hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/drivers/pwm/pwm-sifive.c
....@@ -41,7 +41,7 @@
4141
4242 struct pwm_sifive_ddata {
4343 struct pwm_chip chip;
44
- struct mutex lock; /* lock to protect user_count */
44
+ struct mutex lock; /* lock to protect user_count and approx_period */
4545 struct notifier_block notifier;
4646 struct clk *clk;
4747 void __iomem *regs;
....@@ -76,6 +76,7 @@
7676 mutex_unlock(&ddata->lock);
7777 }
7878
79
+/* Called holding ddata->lock */
7980 static void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata,
8081 unsigned long rate)
8182 {
....@@ -163,7 +164,6 @@
163164 return ret;
164165 }
165166
166
- mutex_lock(&ddata->lock);
167167 cur_state = pwm->state;
168168 enabled = cur_state.enabled;
169169
....@@ -182,14 +182,23 @@
182182 /* The hardware cannot generate a 100% duty cycle */
183183 frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1);
184184
185
+ mutex_lock(&ddata->lock);
185186 if (state->period != ddata->approx_period) {
186
- if (ddata->user_count != 1) {
187
+ /*
188
+ * Don't let a 2nd user change the period underneath the 1st user.
189
+ * However if ddate->approx_period == 0 this is the first time we set
190
+ * any period, so let whoever gets here first set the period so other
191
+ * users who agree on the period won't fail.
192
+ */
193
+ if (ddata->user_count != 1 && ddata->approx_period) {
194
+ mutex_unlock(&ddata->lock);
187195 ret = -EBUSY;
188196 goto exit;
189197 }
190198 ddata->approx_period = state->period;
191199 pwm_sifive_update_clock(ddata, clk_get_rate(ddata->clk));
192200 }
201
+ mutex_unlock(&ddata->lock);
193202
194203 writel(frac, ddata->regs + PWM_SIFIVE_PWMCMP(pwm->hwpwm));
195204
....@@ -198,7 +207,6 @@
198207
199208 exit:
200209 clk_disable(ddata->clk);
201
- mutex_unlock(&ddata->lock);
202210 return ret;
203211 }
204212
....@@ -217,8 +225,11 @@
217225 struct pwm_sifive_ddata *ddata =
218226 container_of(nb, struct pwm_sifive_ddata, notifier);
219227
220
- if (event == POST_RATE_CHANGE)
228
+ if (event == POST_RATE_CHANGE) {
229
+ mutex_lock(&ddata->lock);
221230 pwm_sifive_update_clock(ddata, ndata->new_rate);
231
+ mutex_unlock(&ddata->lock);
232
+ }
222233
223234 return NOTIFY_OK;
224235 }