Commit f4a8e31e authored by Uwe Kleine-König's avatar Uwe Kleine-König Committed by Thierry Reding

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: 6d45374a ("pwm: ep93xx: Implement .apply callback")
Signed-off-by: default avatarUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: default avatarThierry Reding <thierry.reding@gmail.com>
parent 7d6d4aaf
...@@ -64,6 +64,11 @@ static int ep93xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -64,6 +64,11 @@ static int ep93xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
int ret; int ret;
struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip); struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip);
bool enabled = state->enabled; 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 (state->polarity != pwm->state.polarity) {
if (enabled) { if (enabled) {
...@@ -97,57 +102,47 @@ static int ep93xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -97,57 +102,47 @@ static int ep93xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0; return 0;
} }
if (state->period != pwm->state.period || /*
state->duty_cycle != pwm->state.duty_cycle) { * The clock needs to be enabled to access the PWM registers.
struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip); * Configuration can be changed at any time.
void __iomem *base = ep93xx_pwm->base; */
unsigned long long c; if (!pwm_is_enabled(pwm)) {
unsigned long period_cycles; ret = clk_prepare_enable(ep93xx_pwm->clk);
unsigned long duty_cycles; if (ret)
unsigned long term; return ret;
}
/* c = clk_get_rate(ep93xx_pwm->clk);
* The clock needs to be enabled to access the PWM registers. c *= state->period;
* Configuration can be changed at any time. do_div(c, 1000000000);
*/ period_cycles = c;
if (!pwm_is_enabled(pwm)) {
ret = clk_prepare_enable(ep93xx_pwm->clk); c = period_cycles;
if (ret) c *= state->duty_cycle;
return ret; do_div(c, state->period);
} duty_cycles = c;
c = clk_get_rate(ep93xx_pwm->clk); if (period_cycles < 0x10000 && duty_cycles < 0x10000) {
c *= state->period; term = readw(base + EP93XX_PWMx_TERM_COUNT);
do_div(c, 1000000000);
period_cycles = c; /* Order is important if PWM is running */
if (period_cycles > term) {
c = period_cycles; writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT);
c *= state->duty_cycle; writew(duty_cycles, base + EP93XX_PWMx_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;
} else { } 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)) if (!pwm_is_enabled(pwm))
clk_disable_unprepare(ep93xx_pwm->clk); clk_disable_unprepare(ep93xx_pwm->clk);
if (ret) if (ret)
return ret; return ret;
}
if (!enabled) { if (!enabled) {
ret = clk_prepare_enable(ep93xx_pwm->clk); ret = clk_prepare_enable(ep93xx_pwm->clk);
......
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