Commit 92f69e58 authored by Uwe Kleine-König's avatar Uwe Kleine-König Committed by Thierry Reding
Browse files

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: default avatarUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: default avatarThierry Reding <thierry.reding@gmail.com>
parent 77965c98
Loading
Loading
Loading
Loading
+24 −17
Original line number Diff line number Diff line
@@ -555,8 +555,20 @@ 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) {
	if (!state->enabled) {
		if (pwm->state.enabled)
			chip->ops->disable(chip, pwm);

		return 0;
	}

	/*
	 * 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);
@@ -565,16 +577,11 @@ static int pwm_apply_legacy(struct pwm_chip *chip, struct pwm_device *pwm,

	pwm->state.period = state->period;
	pwm->state.duty_cycle = state->duty_cycle;
	}

	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);
		}
	}

	return 0;