Commit ae52f797 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'pwm/for-6.3-rc6' of...

Merge tag 'pwm/for-6.3-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm

Pull pwm fixes from Thierry Reding:
 "These are some fixes to make sure the PWM state structure is always
  initialized to a known state.

  Prior to this it could happen in some situations that random data from
  the stack would leak into the data structure and cause subtle bugs"

* tag 'pwm/for-6.3-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm:
  pwm: Zero-initialize the pwm_state passed to driver's .get_state()
  pwm: meson: Explicitly set .polarity in .get_state()
  pwm: sprd: Explicitly set .polarity in .get_state()
  pwm: iqs620a: Explicitly set .polarity in .get_state()
  pwm: cros-ec: Explicitly set .polarity in .get_state()
  pwm: hibvt: Explicitly set .polarity in .get_state()
parents ac6c0433 1271a7b9
...@@ -115,7 +115,14 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) ...@@ -115,7 +115,14 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
} }
if (pwm->chip->ops->get_state) { if (pwm->chip->ops->get_state) {
struct pwm_state state; /*
* Zero-initialize state because most drivers are unaware of
* .usage_power. The other members of state are supposed to be
* set by lowlevel drivers. We still initialize the whole
* structure for simplicity even though this might paper over
* faulty implementations of .get_state().
*/
struct pwm_state state = { 0, };
err = pwm->chip->ops->get_state(pwm->chip, pwm, &state); err = pwm->chip->ops->get_state(pwm->chip, pwm, &state);
trace_pwm_get(pwm, &state, err); trace_pwm_get(pwm, &state, err);
...@@ -448,7 +455,7 @@ static void pwm_apply_state_debug(struct pwm_device *pwm, ...@@ -448,7 +455,7 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,
{ {
struct pwm_state *last = &pwm->last; struct pwm_state *last = &pwm->last;
struct pwm_chip *chip = pwm->chip; struct pwm_chip *chip = pwm->chip;
struct pwm_state s1, s2; struct pwm_state s1 = { 0 }, s2 = { 0 };
int err; int err;
if (!IS_ENABLED(CONFIG_PWM_DEBUG)) if (!IS_ENABLED(CONFIG_PWM_DEBUG))
...@@ -530,6 +537,7 @@ static void pwm_apply_state_debug(struct pwm_device *pwm, ...@@ -530,6 +537,7 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,
return; return;
} }
*last = (struct pwm_state){ 0 };
err = chip->ops->get_state(chip, pwm, last); err = chip->ops->get_state(chip, pwm, last);
trace_pwm_get(pwm, last, err); trace_pwm_get(pwm, last, err);
if (err) if (err)
......
...@@ -198,6 +198,7 @@ static int cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -198,6 +198,7 @@ static int cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
state->enabled = (ret > 0); state->enabled = (ret > 0);
state->period = EC_PWM_MAX_DUTY; state->period = EC_PWM_MAX_DUTY;
state->polarity = PWM_POLARITY_NORMAL;
/* /*
* Note that "disabled" and "duty cycle == 0" are treated the same. If * Note that "disabled" and "duty cycle == 0" are treated the same. If
......
...@@ -146,6 +146,7 @@ static int hibvt_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -146,6 +146,7 @@ static int hibvt_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
value = readl(base + PWM_CTRL_ADDR(pwm->hwpwm)); value = readl(base + PWM_CTRL_ADDR(pwm->hwpwm));
state->enabled = (PWM_ENABLE_MASK & value); state->enabled = (PWM_ENABLE_MASK & value);
state->polarity = (PWM_POLARITY_MASK & value) ? PWM_POLARITY_INVERSED : PWM_POLARITY_NORMAL;
return 0; return 0;
} }
......
...@@ -126,6 +126,7 @@ static int iqs620_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -126,6 +126,7 @@ static int iqs620_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
mutex_unlock(&iqs620_pwm->lock); mutex_unlock(&iqs620_pwm->lock);
state->period = IQS620_PWM_PERIOD_NS; state->period = IQS620_PWM_PERIOD_NS;
state->polarity = PWM_POLARITY_NORMAL;
return 0; return 0;
} }
......
...@@ -162,6 +162,12 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm, ...@@ -162,6 +162,12 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
duty = state->duty_cycle; duty = state->duty_cycle;
period = state->period; period = state->period;
/*
* Note this is wrong. The result is an output wave that isn't really
* inverted and so is wrongly identified by .get_state as normal.
* Fixing this needs some care however as some machines might rely on
* this.
*/
if (state->polarity == PWM_POLARITY_INVERSED) if (state->polarity == PWM_POLARITY_INVERSED)
duty = period - duty; duty = period - duty;
...@@ -358,6 +364,8 @@ static int meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -358,6 +364,8 @@ static int meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
state->duty_cycle = 0; state->duty_cycle = 0;
} }
state->polarity = PWM_POLARITY_NORMAL;
return 0; return 0;
} }
......
...@@ -109,6 +109,7 @@ static int sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -109,6 +109,7 @@ static int sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
duty = val & SPRD_PWM_DUTY_MSK; duty = val & SPRD_PWM_DUTY_MSK;
tmp = (prescale + 1) * NSEC_PER_SEC * duty; tmp = (prescale + 1) * NSEC_PER_SEC * duty;
state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, chn->clk_rate); state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, chn->clk_rate);
state->polarity = PWM_POLARITY_NORMAL;
/* Disable PWM clocks if the PWM channel is not in enable state. */ /* Disable PWM clocks if the PWM channel is not in enable state. */
if (!state->enabled) if (!state->enabled)
......
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