summaryrefslogtreecommitdiff
path: root/drivers/pwm/core.c
diff options
context:
space:
mode:
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>2021-07-01 09:29:26 +0200
committerThierry Reding <thierry.reding@gmail.com>2021-11-17 17:09:22 +0100
commit92f69e582e15bf281ff1ab3ccc7abdd8392550a3 (patch)
tree763625b54e2b8fe4dde2269972c9754d19e7bfac /drivers/pwm/core.c
parent77965c98cffe41994dce3389c4aae80e2072f098 (diff)
downloadlwn-92f69e582e15bf281ff1ab3ccc7abdd8392550a3.tar.gz
lwn-92f69e582e15bf281ff1ab3ccc7abdd8392550a3.zip
pwm: Prevent a glitch for legacy drivers
If a running PWM is reconfigured to disabled calling the ->config() callback before disabling the hardware might result in a glitch where the (maybe) new period and duty_cycle are visible on the output before disabling the hardware. So handle disabling before calling ->config(). Also exit early in this case which is possible because period and duty_cycle don't matter for disabled PWMs. In return however ->config has to be called even if state->period == pwm->state.period && state->duty_cycle != pwm->state.duty_cycle because setting these might have been skipped in the previous call. 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/core.c')
-rw-r--r--drivers/pwm/core.c41
1 files changed, 24 insertions, 17 deletions
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index c4bbe12cd850..dedf38a81bf9 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -555,26 +555,33 @@ static int pwm_apply_legacy(struct pwm_chip *chip, struct pwm_device *pwm,
pwm->state.polarity = state->polarity;
}
- if (state->period != pwm->state.period ||
- state->duty_cycle != pwm->state.duty_cycle) {
- err = chip->ops->config(pwm->chip, pwm,
- state->duty_cycle,
- state->period);
- if (err)
- return err;
+ if (!state->enabled) {
+ if (pwm->state.enabled)
+ chip->ops->disable(chip, pwm);
- pwm->state.period = state->period;
- pwm->state.duty_cycle = state->duty_cycle;
+ return 0;
}
- if (state->enabled != pwm->state.enabled) {
- if (!pwm->state.enabled) {
- err = chip->ops->enable(chip, pwm);
- if (err)
- return err;
- } else {
- chip->ops->disable(chip, pwm);
- }
+ /*
+ * We cannot skip calling ->config even if state->period ==
+ * pwm->state.period && state->duty_cycle == pwm->state.duty_cycle
+ * because we might have exited early in the last call to
+ * pwm_apply_state because of !state->enabled and so the two values in
+ * pwm->state might not be configured in hardware.
+ */
+ err = chip->ops->config(pwm->chip, pwm,
+ state->duty_cycle,
+ state->period);
+ if (err)
+ return err;
+
+ pwm->state.period = state->period;
+ pwm->state.duty_cycle = state->duty_cycle;
+
+ if (!pwm->state.enabled) {
+ err = chip->ops->enable(chip, pwm);
+ if (err)
+ return err;
}
return 0;