.. | .. |
---|
41 | 41 | |
---|
42 | 42 | struct pwm_sifive_ddata { |
---|
43 | 43 | 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 */ |
---|
45 | 45 | struct notifier_block notifier; |
---|
46 | 46 | struct clk *clk; |
---|
47 | 47 | void __iomem *regs; |
---|
.. | .. |
---|
76 | 76 | mutex_unlock(&ddata->lock); |
---|
77 | 77 | } |
---|
78 | 78 | |
---|
| 79 | +/* Called holding ddata->lock */ |
---|
79 | 80 | static void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata, |
---|
80 | 81 | unsigned long rate) |
---|
81 | 82 | { |
---|
.. | .. |
---|
163 | 164 | return ret; |
---|
164 | 165 | } |
---|
165 | 166 | |
---|
166 | | - mutex_lock(&ddata->lock); |
---|
167 | 167 | cur_state = pwm->state; |
---|
168 | 168 | enabled = cur_state.enabled; |
---|
169 | 169 | |
---|
.. | .. |
---|
182 | 182 | /* The hardware cannot generate a 100% duty cycle */ |
---|
183 | 183 | frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1); |
---|
184 | 184 | |
---|
| 185 | + mutex_lock(&ddata->lock); |
---|
185 | 186 | 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); |
---|
187 | 195 | ret = -EBUSY; |
---|
188 | 196 | goto exit; |
---|
189 | 197 | } |
---|
190 | 198 | ddata->approx_period = state->period; |
---|
191 | 199 | pwm_sifive_update_clock(ddata, clk_get_rate(ddata->clk)); |
---|
192 | 200 | } |
---|
| 201 | + mutex_unlock(&ddata->lock); |
---|
193 | 202 | |
---|
194 | 203 | writel(frac, ddata->regs + PWM_SIFIVE_PWMCMP(pwm->hwpwm)); |
---|
195 | 204 | |
---|
.. | .. |
---|
198 | 207 | |
---|
199 | 208 | exit: |
---|
200 | 209 | clk_disable(ddata->clk); |
---|
201 | | - mutex_unlock(&ddata->lock); |
---|
202 | 210 | return ret; |
---|
203 | 211 | } |
---|
204 | 212 | |
---|
.. | .. |
---|
217 | 225 | struct pwm_sifive_ddata *ddata = |
---|
218 | 226 | container_of(nb, struct pwm_sifive_ddata, notifier); |
---|
219 | 227 | |
---|
220 | | - if (event == POST_RATE_CHANGE) |
---|
| 228 | + if (event == POST_RATE_CHANGE) { |
---|
| 229 | + mutex_lock(&ddata->lock); |
---|
221 | 230 | pwm_sifive_update_clock(ddata, ndata->new_rate); |
---|
| 231 | + mutex_unlock(&ddata->lock); |
---|
| 232 | + } |
---|
222 | 233 | |
---|
223 | 234 | return NOTIFY_OK; |
---|
224 | 235 | } |
---|