diff options
author | Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> | 2019-01-09 03:19:05 -0500 |
---|---|---|
committer | Thierry Reding <thierry.reding@gmail.com> | 2019-03-04 06:14:05 -0500 |
commit | 7f68ce8287d3b25a70455aec18ff678a908d49ee (patch) | |
tree | 0cb52f72f3a27a736137a0b8578f0bd05b793d01 | |
parent | 74d0c3b2050927f364e3320091f234c108bd845d (diff) |
pwm: rcar: Add support "atomic" API
This patch adds support for "atomic" API. This behavior differs with
legacy APIs a little.
Legacy APIs:
The PWMCNT register will be updated in rcar_pwm_config() even if
the PWM state is disabled.
Atomic API:
The PWMCNT register will be updated in rcar_pwm_apply() only if
the PWM state is enabled. Otherwize, if a PWM runs with 30% duty
cycles and the pwm_apply_state() is called with state->enabled = 0,
->duty_cycle = 60 and ->period = 100, this is possible to output
a 60% duty cycle.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
-rw-r--r-- | drivers/pwm/pwm-rcar.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c index a41812fc6f95..e3ab663ff3a7 100644 --- a/drivers/pwm/pwm-rcar.c +++ b/drivers/pwm/pwm-rcar.c | |||
@@ -192,12 +192,49 @@ static void rcar_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
192 | rcar_pwm_update(rp, RCAR_PWMCR_EN0, 0, RCAR_PWMCR); | 192 | rcar_pwm_update(rp, RCAR_PWMCR_EN0, 0, RCAR_PWMCR); |
193 | } | 193 | } |
194 | 194 | ||
195 | static int rcar_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, | ||
196 | struct pwm_state *state) | ||
197 | { | ||
198 | struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip); | ||
199 | struct pwm_state cur_state; | ||
200 | int div, ret; | ||
201 | |||
202 | /* This HW/driver only supports normal polarity */ | ||
203 | pwm_get_state(pwm, &cur_state); | ||
204 | if (state->polarity != PWM_POLARITY_NORMAL) | ||
205 | return -ENOTSUPP; | ||
206 | |||
207 | if (!state->enabled) { | ||
208 | rcar_pwm_disable(chip, pwm); | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | div = rcar_pwm_get_clock_division(rp, state->period); | ||
213 | if (div < 0) | ||
214 | return div; | ||
215 | |||
216 | rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR); | ||
217 | |||
218 | ret = rcar_pwm_set_counter(rp, div, state->duty_cycle, state->period); | ||
219 | if (!ret) | ||
220 | rcar_pwm_set_clock_control(rp, div); | ||
221 | |||
222 | /* The SYNC should be set to 0 even if rcar_pwm_set_counter failed */ | ||
223 | rcar_pwm_update(rp, RCAR_PWMCR_SYNC, 0, RCAR_PWMCR); | ||
224 | |||
225 | if (!ret && state->enabled) | ||
226 | ret = rcar_pwm_enable(chip, pwm); | ||
227 | |||
228 | return ret; | ||
229 | } | ||
230 | |||
195 | static const struct pwm_ops rcar_pwm_ops = { | 231 | static const struct pwm_ops rcar_pwm_ops = { |
196 | .request = rcar_pwm_request, | 232 | .request = rcar_pwm_request, |
197 | .free = rcar_pwm_free, | 233 | .free = rcar_pwm_free, |
198 | .config = rcar_pwm_config, | 234 | .config = rcar_pwm_config, |
199 | .enable = rcar_pwm_enable, | 235 | .enable = rcar_pwm_enable, |
200 | .disable = rcar_pwm_disable, | 236 | .disable = rcar_pwm_disable, |
237 | .apply = rcar_pwm_apply, | ||
201 | .owner = THIS_MODULE, | 238 | .owner = THIS_MODULE, |
202 | }; | 239 | }; |
203 | 240 | ||