From: Uwe Kleine-König u.kleine-koenig@pengutronix.de
[ Upstream commit 0f02f491b786143f08eb19840f1cf4f12aec6dee ]
The lock is only to serialize access and update to user_count and approx_period between different PWMs served by the same pwm_chip. So the lock needs only to be taken during the check if the (chip global) period can and/or needs to be changed.
Signed-off-by: Uwe Kleine-König u.kleine-koenig@pengutronix.de Tested-by: Emil Renner Berthing emil.renner.berthing@canonical.com Signed-off-by: Thierry Reding thierry.reding@gmail.com Stable-dep-of: 334c7b13d383 ("pwm: sifive: Always let the first pwm_apply_state succeed") Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/pwm/pwm-sifive.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c index 538297ef82558..980ddcdd52953 100644 --- a/drivers/pwm/pwm-sifive.c +++ b/drivers/pwm/pwm-sifive.c @@ -43,7 +43,7 @@
struct pwm_sifive_ddata { struct pwm_chip chip; - struct mutex lock; /* lock to protect user_count */ + struct mutex lock; /* lock to protect user_count and approx_period */ struct notifier_block notifier; struct clk *clk; void __iomem *regs; @@ -78,6 +78,7 @@ static void pwm_sifive_free(struct pwm_chip *chip, struct pwm_device *pwm) mutex_unlock(&ddata->lock); }
+/* Called holding ddata->lock */ static void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata, unsigned long rate) { @@ -166,7 +167,6 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm, return ret; }
- mutex_lock(&ddata->lock); cur_state = pwm->state; enabled = cur_state.enabled;
@@ -185,14 +185,17 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm, /* The hardware cannot generate a 100% duty cycle */ frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1);
+ mutex_lock(&ddata->lock); if (state->period != ddata->approx_period) { if (ddata->user_count != 1) { + mutex_unlock(&ddata->lock); ret = -EBUSY; goto exit; } ddata->approx_period = state->period; pwm_sifive_update_clock(ddata, clk_get_rate(ddata->clk)); } + mutex_unlock(&ddata->lock);
writel(frac, ddata->regs + PWM_SIFIVE_PWMCMP0 + pwm->hwpwm * PWM_SIFIVE_SIZE_PWMCMP); @@ -202,7 +205,6 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
exit: clk_disable(ddata->clk); - mutex_unlock(&ddata->lock); return ret; }