Commit 888a623d authored by Jitao Shi's avatar Jitao Shi Committed by Thierry Reding

pwm: mtk-disp: Implement atomic API .apply()

Switch the driver to support the .apply() method.
Signed-off-by: default avatarJitao Shi <jitao.shi@mediatek.com>
Signed-off-by: default avatarThierry Reding <thierry.reding@gmail.com>
parent d7a4e582
...@@ -47,6 +47,7 @@ struct mtk_disp_pwm { ...@@ -47,6 +47,7 @@ struct mtk_disp_pwm {
struct clk *clk_main; struct clk *clk_main;
struct clk *clk_mm; struct clk *clk_mm;
void __iomem *base; void __iomem *base;
bool enabled;
}; };
static inline struct mtk_disp_pwm *to_mtk_disp_pwm(struct pwm_chip *chip) static inline struct mtk_disp_pwm *to_mtk_disp_pwm(struct pwm_chip *chip)
...@@ -66,25 +67,45 @@ static void mtk_disp_pwm_update_bits(struct mtk_disp_pwm *mdp, u32 offset, ...@@ -66,25 +67,45 @@ static void mtk_disp_pwm_update_bits(struct mtk_disp_pwm *mdp, u32 offset,
writel(value, address); writel(value, address);
} }
static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, static int mtk_disp_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns) const struct pwm_state *state)
{ {
struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
u32 clk_div, period, high_width, value; u32 clk_div, period, high_width, value;
u64 div, rate; u64 div, rate;
int err; int err;
err = clk_prepare_enable(mdp->clk_main); if (state->polarity != PWM_POLARITY_NORMAL)
if (err < 0) { return -EINVAL;
dev_err(chip->dev, "Can't enable mdp->clk_main: %pe\n", ERR_PTR(err));
return err; if (!state->enabled) {
mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
0x0);
if (mdp->enabled) {
clk_disable_unprepare(mdp->clk_mm);
clk_disable_unprepare(mdp->clk_main);
}
mdp->enabled = false;
return 0;
} }
err = clk_prepare_enable(mdp->clk_mm); if (!mdp->enabled) {
if (err < 0) { err = clk_prepare_enable(mdp->clk_main);
dev_err(chip->dev, "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(err)); if (err < 0) {
clk_disable_unprepare(mdp->clk_main); dev_err(chip->dev, "Can't enable mdp->clk_main: %pe\n",
return err; ERR_PTR(err));
return err;
}
err = clk_prepare_enable(mdp->clk_mm);
if (err < 0) {
dev_err(chip->dev, "Can't enable mdp->clk_mm: %pe\n",
ERR_PTR(err));
clk_disable_unprepare(mdp->clk_main);
return err;
}
} }
/* /*
...@@ -98,20 +119,22 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -98,20 +119,22 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
* high_width = (PWM_CLK_RATE * duty_ns) / (10^9 * (clk_div + 1)) * high_width = (PWM_CLK_RATE * duty_ns) / (10^9 * (clk_div + 1))
*/ */
rate = clk_get_rate(mdp->clk_main); rate = clk_get_rate(mdp->clk_main);
clk_div = div_u64(rate * period_ns, NSEC_PER_SEC) >> clk_div = div_u64(rate * state->period, NSEC_PER_SEC) >>
PWM_PERIOD_BIT_WIDTH; PWM_PERIOD_BIT_WIDTH;
if (clk_div > PWM_CLKDIV_MAX) { if (clk_div > PWM_CLKDIV_MAX) {
clk_disable_unprepare(mdp->clk_mm); if (!mdp->enabled) {
clk_disable_unprepare(mdp->clk_main); clk_disable_unprepare(mdp->clk_mm);
clk_disable_unprepare(mdp->clk_main);
}
return -EINVAL; return -EINVAL;
} }
div = NSEC_PER_SEC * (clk_div + 1); div = NSEC_PER_SEC * (clk_div + 1);
period = div64_u64(rate * period_ns, div); period = div64_u64(rate * state->period, div);
if (period > 0) if (period > 0)
period--; period--;
high_width = div64_u64(rate * duty_ns, div); high_width = div64_u64(rate * state->duty_cycle, div);
value = period | (high_width << PWM_HIGH_WIDTH_SHIFT); value = period | (high_width << PWM_HIGH_WIDTH_SHIFT);
mtk_disp_pwm_update_bits(mdp, mdp->data->con0, mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
...@@ -141,51 +164,15 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -141,51 +164,15 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
mdp->data->con0_sel); mdp->data->con0_sel);
} }
clk_disable_unprepare(mdp->clk_mm);
clk_disable_unprepare(mdp->clk_main);
return 0;
}
static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
int err;
err = clk_prepare_enable(mdp->clk_main);
if (err < 0) {
dev_err(chip->dev, "Can't enable mdp->clk_main: %pe\n", ERR_PTR(err));
return err;
}
err = clk_prepare_enable(mdp->clk_mm);
if (err < 0) {
dev_err(chip->dev, "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(err));
clk_disable_unprepare(mdp->clk_main);
return err;
}
mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask, mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
mdp->data->enable_mask); mdp->data->enable_mask);
mdp->enabled = true;
return 0; return 0;
} }
static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
0x0);
clk_disable_unprepare(mdp->clk_mm);
clk_disable_unprepare(mdp->clk_main);
}
static const struct pwm_ops mtk_disp_pwm_ops = { static const struct pwm_ops mtk_disp_pwm_ops = {
.config = mtk_disp_pwm_config, .apply = mtk_disp_pwm_apply,
.enable = mtk_disp_pwm_enable,
.disable = mtk_disp_pwm_disable,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment