summaryrefslogtreecommitdiffstats
path: root/drivers/pwm
diff options
context:
space:
mode:
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>2021-07-01 10:27:55 +0200
committerThierry Reding <thierry.reding@gmail.com>2021-07-08 16:09:30 +0200
commitf4a8e31ed84ec646c158824f423cb22d1f362bbf (patch)
tree4685109238d026de25002d42db84791a1feef8f1 /drivers/pwm
parent7d6d4aaf2809f209c7d6bcab2f9ae76797051cfa (diff)
downloadlinux-f4a8e31ed84ec646c158824f423cb22d1f362bbf.tar.bz2
pwm: ep93xx: Ensure configuring period and duty_cycle isn't wrongly skipped
As the last call to ep93xx_pwm_apply() might have exited early if state->enabled was false, the values for period and duty_cycle stored in pwm->state might not have been written to hardware and it must be ensured that they are configured before enabling the PWM. Fixes: 6d45374af539 ("pwm: ep93xx: Implement .apply callback") Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Diffstat (limited to 'drivers/pwm')
-rw-r--r--drivers/pwm/pwm-ep93xx.c85
1 files changed, 40 insertions, 45 deletions
diff --git a/drivers/pwm/pwm-ep93xx.c b/drivers/pwm/pwm-ep93xx.c
index 8a3d781e6514..fc3cb7d669c6 100644
--- a/drivers/pwm/pwm-ep93xx.c
+++ b/drivers/pwm/pwm-ep93xx.c
@@ -64,6 +64,11 @@ static int ep93xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
int ret;
struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip);
bool enabled = state->enabled;
+ void __iomem *base = ep93xx_pwm->base;
+ unsigned long long c;
+ unsigned long period_cycles;
+ unsigned long duty_cycles;
+ unsigned long term;
if (state->polarity != pwm->state.polarity) {
if (enabled) {
@@ -97,57 +102,47 @@ static int ep93xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
- if (state->period != pwm->state.period ||
- state->duty_cycle != pwm->state.duty_cycle) {
- struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip);
- void __iomem *base = ep93xx_pwm->base;
- unsigned long long c;
- unsigned long period_cycles;
- unsigned long duty_cycles;
- unsigned long term;
+ /*
+ * The clock needs to be enabled to access the PWM registers.
+ * Configuration can be changed at any time.
+ */
+ if (!pwm_is_enabled(pwm)) {
+ ret = clk_prepare_enable(ep93xx_pwm->clk);
+ if (ret)
+ return ret;
+ }
- /*
- * The clock needs to be enabled to access the PWM registers.
- * Configuration can be changed at any time.
- */
- if (!pwm_is_enabled(pwm)) {
- ret = clk_prepare_enable(ep93xx_pwm->clk);
- if (ret)
- return ret;
- }
+ c = clk_get_rate(ep93xx_pwm->clk);
+ c *= state->period;
+ do_div(c, 1000000000);
+ period_cycles = c;
+
+ c = period_cycles;
+ c *= state->duty_cycle;
+ do_div(c, state->period);
+ duty_cycles = c;
- c = clk_get_rate(ep93xx_pwm->clk);
- c *= state->period;
- do_div(c, 1000000000);
- period_cycles = c;
-
- c = period_cycles;
- c *= state->duty_cycle;
- do_div(c, state->period);
- duty_cycles = c;
-
- if (period_cycles < 0x10000 && duty_cycles < 0x10000) {
- term = readw(base + EP93XX_PWMx_TERM_COUNT);
-
- /* Order is important if PWM is running */
- if (period_cycles > term) {
- writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT);
- writew(duty_cycles, base + EP93XX_PWMx_DUTY_CYCLE);
- } else {
- writew(duty_cycles, base + EP93XX_PWMx_DUTY_CYCLE);
- writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT);
- }
- ret = 0;
+ if (period_cycles < 0x10000 && duty_cycles < 0x10000) {
+ term = readw(base + EP93XX_PWMx_TERM_COUNT);
+
+ /* Order is important if PWM is running */
+ if (period_cycles > term) {
+ writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT);
+ writew(duty_cycles, base + EP93XX_PWMx_DUTY_CYCLE);
} else {
- ret = -EINVAL;
+ writew(duty_cycles, base + EP93XX_PWMx_DUTY_CYCLE);
+ writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT);
}
+ ret = 0;
+ } else {
+ ret = -EINVAL;
+ }
- if (!pwm_is_enabled(pwm))
- clk_disable_unprepare(ep93xx_pwm->clk);
+ if (!pwm_is_enabled(pwm))
+ clk_disable_unprepare(ep93xx_pwm->clk);
- if (ret)
- return ret;
- }
+ if (ret)
+ return ret;
if (!enabled) {
ret = clk_prepare_enable(ep93xx_pwm->clk);