diff options
Diffstat (limited to 'drivers/pwm/pwm-imx.c')
-rw-r--r-- | drivers/pwm/pwm-imx.c | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index d557279446ed..34f3031d5c40 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c | |||
@@ -248,6 +248,72 @@ static int imx_pwm_config(struct pwm_chip *chip, | |||
248 | return ret; | 248 | return ret; |
249 | } | 249 | } |
250 | 250 | ||
251 | static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm, | ||
252 | struct pwm_state *state) | ||
253 | { | ||
254 | unsigned long period_cycles, duty_cycles, prescale; | ||
255 | struct imx_chip *imx = to_imx_chip(chip); | ||
256 | struct pwm_state cstate; | ||
257 | unsigned long long c; | ||
258 | int ret; | ||
259 | |||
260 | pwm_get_state(pwm, &cstate); | ||
261 | |||
262 | if (state->enabled) { | ||
263 | c = clk_get_rate(imx->clk_per); | ||
264 | c *= state->period; | ||
265 | |||
266 | do_div(c, 1000000000); | ||
267 | period_cycles = c; | ||
268 | |||
269 | prescale = period_cycles / 0x10000 + 1; | ||
270 | |||
271 | period_cycles /= prescale; | ||
272 | c = (unsigned long long)period_cycles * state->duty_cycle; | ||
273 | do_div(c, state->period); | ||
274 | duty_cycles = c; | ||
275 | |||
276 | /* | ||
277 | * according to imx pwm RM, the real period value should be | ||
278 | * PERIOD value in PWMPR plus 2. | ||
279 | */ | ||
280 | if (period_cycles > 2) | ||
281 | period_cycles -= 2; | ||
282 | else | ||
283 | period_cycles = 0; | ||
284 | |||
285 | /* | ||
286 | * Wait for a free FIFO slot if the PWM is already enabled, and | ||
287 | * flush the FIFO if the PWM was disabled and is about to be | ||
288 | * enabled. | ||
289 | */ | ||
290 | if (cstate.enabled) { | ||
291 | imx_pwm_wait_fifo_slot(chip, pwm); | ||
292 | } else { | ||
293 | ret = clk_prepare_enable(imx->clk_per); | ||
294 | if (ret) | ||
295 | return ret; | ||
296 | |||
297 | imx_pwm_sw_reset(chip); | ||
298 | } | ||
299 | |||
300 | writel(duty_cycles, imx->mmio_base + MX3_PWMSAR); | ||
301 | writel(period_cycles, imx->mmio_base + MX3_PWMPR); | ||
302 | |||
303 | writel(MX3_PWMCR_PRESCALER(prescale) | | ||
304 | MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | | ||
305 | MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH | | ||
306 | MX3_PWMCR_EN, | ||
307 | imx->mmio_base + MX3_PWMCR); | ||
308 | } else if (cstate.enabled) { | ||
309 | writel(0, imx->mmio_base + MX3_PWMCR); | ||
310 | |||
311 | clk_disable_unprepare(imx->clk_per); | ||
312 | } | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
251 | static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | 317 | static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) |
252 | { | 318 | { |
253 | struct imx_chip *imx = to_imx_chip(chip); | 319 | struct imx_chip *imx = to_imx_chip(chip); |
@@ -279,6 +345,7 @@ static const struct pwm_ops imx_pwm_ops_v1 = { | |||
279 | }; | 345 | }; |
280 | 346 | ||
281 | static const struct pwm_ops imx_pwm_ops_v2 = { | 347 | static const struct pwm_ops imx_pwm_ops_v2 = { |
348 | .apply = imx_pwm_apply_v2, | ||
282 | .enable = imx_pwm_enable, | 349 | .enable = imx_pwm_enable, |
283 | .disable = imx_pwm_disable, | 350 | .disable = imx_pwm_disable, |
284 | .config = imx_pwm_config, | 351 | .config = imx_pwm_config, |