aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-imx.c
diff options
context:
space:
mode:
authorLukasz Majewski <lukma@denx.de>2017-01-29 16:54:11 -0500
committerThierry Reding <thierry.reding@gmail.com>2017-01-30 03:12:52 -0500
commit0ca1a11a1d816c8fb0bb29b985666cef912958c1 (patch)
tree176d7786ae196e5d17198923bd50ac2d98245e06 /drivers/pwm/pwm-imx.c
parent73b1ff1f3e5ccc22b31fa44c98460ef05393181c (diff)
pwm: imx: Provide atomic PWM support for i.MX PWMv2
This commit provides apply() callback implementation for i.MX's PWMv2. Suggested-by: Stefan Agner <stefan@agner.ch> Suggested-by: Boris Brezillon <boris.brezillon@free-electrons.com> Signed-off-by: Lukasz Majewski <l.majewski@majess.pl> Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Diffstat (limited to 'drivers/pwm/pwm-imx.c')
-rw-r--r--drivers/pwm/pwm-imx.c67
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
251static 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
251static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 317static 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
281static const struct pwm_ops imx_pwm_ops_v2 = { 347static 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,