forked from Minki/linux
pwm: sifive: Reduce time the controller lock is held
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>
This commit is contained in:
parent
61180f68ad
commit
0f02f491b7
@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
struct pwm_sifive_ddata {
|
struct pwm_sifive_ddata {
|
||||||
struct pwm_chip chip;
|
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 notifier_block notifier;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
@ -76,6 +76,7 @@ static void pwm_sifive_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
|||||||
mutex_unlock(&ddata->lock);
|
mutex_unlock(&ddata->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Called holding ddata->lock */
|
||||||
static void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata,
|
static void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata,
|
||||||
unsigned long rate)
|
unsigned long rate)
|
||||||
{
|
{
|
||||||
@ -144,7 +145,6 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&ddata->lock);
|
|
||||||
cur_state = pwm->state;
|
cur_state = pwm->state;
|
||||||
enabled = cur_state.enabled;
|
enabled = cur_state.enabled;
|
||||||
|
|
||||||
@ -163,14 +163,17 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||||||
/* The hardware cannot generate a 100% duty cycle */
|
/* The hardware cannot generate a 100% duty cycle */
|
||||||
frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1);
|
frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1);
|
||||||
|
|
||||||
|
mutex_lock(&ddata->lock);
|
||||||
if (state->period != ddata->approx_period) {
|
if (state->period != ddata->approx_period) {
|
||||||
if (ddata->user_count != 1) {
|
if (ddata->user_count != 1) {
|
||||||
|
mutex_unlock(&ddata->lock);
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
ddata->approx_period = state->period;
|
ddata->approx_period = state->period;
|
||||||
pwm_sifive_update_clock(ddata, clk_get_rate(ddata->clk));
|
pwm_sifive_update_clock(ddata, clk_get_rate(ddata->clk));
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&ddata->lock);
|
||||||
|
|
||||||
writel(frac, ddata->regs + PWM_SIFIVE_PWMCMP(pwm->hwpwm));
|
writel(frac, ddata->regs + PWM_SIFIVE_PWMCMP(pwm->hwpwm));
|
||||||
|
|
||||||
@ -185,7 +188,6 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||||||
|
|
||||||
exit:
|
exit:
|
||||||
clk_disable(ddata->clk);
|
clk_disable(ddata->clk);
|
||||||
mutex_unlock(&ddata->lock);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user