1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Freescale FlexTimer Module (FTM) PWM Driver
5 * Copyright 2012-2013 Freescale Semiconductor, Inc.
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/mutex.h>
14 #include <linux/of_address.h>
15 #include <linux/of_device.h>
16 #include <linux/platform_device.h>
18 #include <linux/pwm.h>
19 #include <linux/regmap.h>
20 #include <linux/slab.h>
21 #include <linux/fsl/ftm.h>
23 #define FTM_SC_CLK(c) (((c) + 1) << FTM_SC_CLK_MASK_SHIFT)
37 struct fsl_pwm_periodcfg
{
38 enum fsl_pwm_clk clk_select
;
40 unsigned int mod_period
;
46 struct regmap
*regmap
;
48 /* This value is valid iff a pwm is running */
49 struct fsl_pwm_periodcfg period
;
52 struct clk
*clk
[FSL_PWM_CLK_MAX
];
54 const struct fsl_ftm_soc
*soc
;
57 static inline struct fsl_pwm_chip
*to_fsl_chip(struct pwm_chip
*chip
)
59 return container_of(chip
, struct fsl_pwm_chip
, chip
);
62 static void ftm_clear_write_protection(struct fsl_pwm_chip
*fpc
)
66 regmap_read(fpc
->regmap
, FTM_FMS
, &val
);
67 if (val
& FTM_FMS_WPEN
)
68 regmap_update_bits(fpc
->regmap
, FTM_MODE
, FTM_MODE_WPDIS
,
72 static void ftm_set_write_protection(struct fsl_pwm_chip
*fpc
)
74 regmap_update_bits(fpc
->regmap
, FTM_FMS
, FTM_FMS_WPEN
, FTM_FMS_WPEN
);
77 static bool fsl_pwm_periodcfg_are_equal(const struct fsl_pwm_periodcfg
*a
,
78 const struct fsl_pwm_periodcfg
*b
)
80 if (a
->clk_select
!= b
->clk_select
)
82 if (a
->clk_ps
!= b
->clk_ps
)
84 if (a
->mod_period
!= b
->mod_period
)
89 static int fsl_pwm_request(struct pwm_chip
*chip
, struct pwm_device
*pwm
)
92 struct fsl_pwm_chip
*fpc
= to_fsl_chip(chip
);
94 ret
= clk_prepare_enable(fpc
->ipg_clk
);
95 if (!ret
&& fpc
->soc
->has_enable_bits
) {
96 mutex_lock(&fpc
->lock
);
97 regmap_update_bits(fpc
->regmap
, FTM_SC
, BIT(pwm
->hwpwm
+ 16),
98 BIT(pwm
->hwpwm
+ 16));
99 mutex_unlock(&fpc
->lock
);
105 static void fsl_pwm_free(struct pwm_chip
*chip
, struct pwm_device
*pwm
)
107 struct fsl_pwm_chip
*fpc
= to_fsl_chip(chip
);
109 if (fpc
->soc
->has_enable_bits
) {
110 mutex_lock(&fpc
->lock
);
111 regmap_update_bits(fpc
->regmap
, FTM_SC
, BIT(pwm
->hwpwm
+ 16),
113 mutex_unlock(&fpc
->lock
);
116 clk_disable_unprepare(fpc
->ipg_clk
);
119 static unsigned int fsl_pwm_ticks_to_ns(struct fsl_pwm_chip
*fpc
,
123 unsigned long long exval
;
125 rate
= clk_get_rate(fpc
->clk
[fpc
->period
.clk_select
]);
127 exval
*= 1000000000UL;
128 do_div(exval
, rate
>> fpc
->period
.clk_ps
);
132 static bool fsl_pwm_calculate_period_clk(struct fsl_pwm_chip
*fpc
,
133 unsigned int period_ns
,
134 enum fsl_pwm_clk index
,
135 struct fsl_pwm_periodcfg
*periodcfg
138 unsigned long long c
;
141 c
= clk_get_rate(fpc
->clk
[index
]);
143 do_div(c
, 1000000000UL);
148 for (ps
= 0; ps
< 8 ; ++ps
, c
>>= 1) {
150 periodcfg
->clk_select
= index
;
151 periodcfg
->clk_ps
= ps
;
152 periodcfg
->mod_period
= c
- 1;
159 static bool fsl_pwm_calculate_period(struct fsl_pwm_chip
*fpc
,
160 unsigned int period_ns
,
161 struct fsl_pwm_periodcfg
*periodcfg
)
163 enum fsl_pwm_clk m0
, m1
;
164 unsigned long fix_rate
, ext_rate
;
167 ret
= fsl_pwm_calculate_period_clk(fpc
, period_ns
, FSL_PWM_CLK_SYS
,
172 fix_rate
= clk_get_rate(fpc
->clk
[FSL_PWM_CLK_FIX
]);
173 ext_rate
= clk_get_rate(fpc
->clk
[FSL_PWM_CLK_EXT
]);
175 if (fix_rate
> ext_rate
) {
176 m0
= FSL_PWM_CLK_FIX
;
177 m1
= FSL_PWM_CLK_EXT
;
179 m0
= FSL_PWM_CLK_EXT
;
180 m1
= FSL_PWM_CLK_FIX
;
183 ret
= fsl_pwm_calculate_period_clk(fpc
, period_ns
, m0
, periodcfg
);
187 return fsl_pwm_calculate_period_clk(fpc
, period_ns
, m1
, periodcfg
);
190 static unsigned int fsl_pwm_calculate_duty(struct fsl_pwm_chip
*fpc
,
191 unsigned int duty_ns
)
193 unsigned long long duty
;
195 unsigned int period
= fpc
->period
.mod_period
+ 1;
196 unsigned int period_ns
= fsl_pwm_ticks_to_ns(fpc
, period
);
198 duty
= (unsigned long long)duty_ns
* period
;
199 do_div(duty
, period_ns
);
201 return (unsigned int)duty
;
204 static bool fsl_pwm_is_any_pwm_enabled(struct fsl_pwm_chip
*fpc
,
205 struct pwm_device
*pwm
)
209 regmap_read(fpc
->regmap
, FTM_OUTMASK
, &val
);
216 static bool fsl_pwm_is_other_pwm_enabled(struct fsl_pwm_chip
*fpc
,
217 struct pwm_device
*pwm
)
221 regmap_read(fpc
->regmap
, FTM_OUTMASK
, &val
);
222 if (~(val
| BIT(pwm
->hwpwm
)) & 0xFF)
228 static int fsl_pwm_apply_config(struct fsl_pwm_chip
*fpc
,
229 struct pwm_device
*pwm
,
230 const struct pwm_state
*newstate
)
235 struct fsl_pwm_periodcfg periodcfg
;
236 bool do_write_period
= false;
238 if (!fsl_pwm_calculate_period(fpc
, newstate
->period
, &periodcfg
)) {
239 dev_err(fpc
->chip
.dev
, "failed to calculate new period\n");
243 if (!fsl_pwm_is_any_pwm_enabled(fpc
, pwm
))
244 do_write_period
= true;
246 * The Freescale FTM controller supports only a single period for
247 * all PWM channels, therefore verify if the newly computed period
248 * is different than the current period being used. In such case
249 * we allow to change the period only if no other pwm is running.
251 else if (!fsl_pwm_periodcfg_are_equal(&fpc
->period
, &periodcfg
)) {
252 if (fsl_pwm_is_other_pwm_enabled(fpc
, pwm
)) {
253 dev_err(fpc
->chip
.dev
,
254 "Cannot change period for PWM %u, disable other PWMs first\n",
258 if (fpc
->period
.clk_select
!= periodcfg
.clk_select
) {
260 enum fsl_pwm_clk oldclk
= fpc
->period
.clk_select
;
261 enum fsl_pwm_clk newclk
= periodcfg
.clk_select
;
263 ret
= clk_prepare_enable(fpc
->clk
[newclk
]);
266 clk_disable_unprepare(fpc
->clk
[oldclk
]);
268 do_write_period
= true;
271 ftm_clear_write_protection(fpc
);
273 if (do_write_period
) {
274 regmap_update_bits(fpc
->regmap
, FTM_SC
, FTM_SC_CLK_MASK
,
275 FTM_SC_CLK(periodcfg
.clk_select
));
276 regmap_update_bits(fpc
->regmap
, FTM_SC
, FTM_SC_PS_MASK
,
278 regmap_write(fpc
->regmap
, FTM_MOD
, periodcfg
.mod_period
);
280 fpc
->period
= periodcfg
;
283 duty
= fsl_pwm_calculate_duty(fpc
, newstate
->duty_cycle
);
285 regmap_write(fpc
->regmap
, FTM_CSC(pwm
->hwpwm
),
286 FTM_CSC_MSB
| FTM_CSC_ELSB
);
287 regmap_write(fpc
->regmap
, FTM_CV(pwm
->hwpwm
), duty
);
290 if (newstate
->polarity
== PWM_POLARITY_INVERSED
)
291 reg_polarity
= BIT(pwm
->hwpwm
);
293 regmap_update_bits(fpc
->regmap
, FTM_POL
, BIT(pwm
->hwpwm
), reg_polarity
);
295 ftm_set_write_protection(fpc
);
300 static int fsl_pwm_apply(struct pwm_chip
*chip
, struct pwm_device
*pwm
,
301 const struct pwm_state
*newstate
)
303 struct fsl_pwm_chip
*fpc
= to_fsl_chip(chip
);
304 struct pwm_state
*oldstate
= &pwm
->state
;
308 * oldstate to newstate : action
310 * disabled to disabled : ignore
311 * enabled to disabled : disable
312 * enabled to enabled : update settings
313 * disabled to enabled : update settings + enable
316 mutex_lock(&fpc
->lock
);
318 if (!newstate
->enabled
) {
319 if (oldstate
->enabled
) {
320 regmap_update_bits(fpc
->regmap
, FTM_OUTMASK
,
321 BIT(pwm
->hwpwm
), BIT(pwm
->hwpwm
));
322 clk_disable_unprepare(fpc
->clk
[FSL_PWM_CLK_CNTEN
]);
323 clk_disable_unprepare(fpc
->clk
[fpc
->period
.clk_select
]);
329 ret
= fsl_pwm_apply_config(fpc
, pwm
, newstate
);
333 /* check if need to enable */
334 if (!oldstate
->enabled
) {
335 ret
= clk_prepare_enable(fpc
->clk
[fpc
->period
.clk_select
]);
339 ret
= clk_prepare_enable(fpc
->clk
[FSL_PWM_CLK_CNTEN
]);
341 clk_disable_unprepare(fpc
->clk
[fpc
->period
.clk_select
]);
345 regmap_update_bits(fpc
->regmap
, FTM_OUTMASK
, BIT(pwm
->hwpwm
),
350 mutex_unlock(&fpc
->lock
);
354 static const struct pwm_ops fsl_pwm_ops
= {
355 .request
= fsl_pwm_request
,
356 .free
= fsl_pwm_free
,
357 .apply
= fsl_pwm_apply
,
358 .owner
= THIS_MODULE
,
361 static int fsl_pwm_init(struct fsl_pwm_chip
*fpc
)
365 ret
= clk_prepare_enable(fpc
->ipg_clk
);
369 regmap_write(fpc
->regmap
, FTM_CNTIN
, 0x00);
370 regmap_write(fpc
->regmap
, FTM_OUTINIT
, 0x00);
371 regmap_write(fpc
->regmap
, FTM_OUTMASK
, 0xFF);
373 clk_disable_unprepare(fpc
->ipg_clk
);
378 static bool fsl_pwm_volatile_reg(struct device
*dev
, unsigned int reg
)
389 static const struct regmap_config fsl_pwm_regmap_config
= {
394 .max_register
= FTM_PWMLOAD
,
395 .volatile_reg
= fsl_pwm_volatile_reg
,
396 .cache_type
= REGCACHE_FLAT
,
399 static int fsl_pwm_probe(struct platform_device
*pdev
)
401 struct fsl_pwm_chip
*fpc
;
405 fpc
= devm_kzalloc(&pdev
->dev
, sizeof(*fpc
), GFP_KERNEL
);
409 mutex_init(&fpc
->lock
);
411 fpc
->soc
= of_device_get_match_data(&pdev
->dev
);
412 fpc
->chip
.dev
= &pdev
->dev
;
414 base
= devm_platform_ioremap_resource(pdev
, 0);
416 return PTR_ERR(base
);
418 fpc
->regmap
= devm_regmap_init_mmio_clk(&pdev
->dev
, "ftm_sys", base
,
419 &fsl_pwm_regmap_config
);
420 if (IS_ERR(fpc
->regmap
)) {
421 dev_err(&pdev
->dev
, "regmap init failed\n");
422 return PTR_ERR(fpc
->regmap
);
425 fpc
->clk
[FSL_PWM_CLK_SYS
] = devm_clk_get(&pdev
->dev
, "ftm_sys");
426 if (IS_ERR(fpc
->clk
[FSL_PWM_CLK_SYS
])) {
427 dev_err(&pdev
->dev
, "failed to get \"ftm_sys\" clock\n");
428 return PTR_ERR(fpc
->clk
[FSL_PWM_CLK_SYS
]);
431 fpc
->clk
[FSL_PWM_CLK_FIX
] = devm_clk_get(fpc
->chip
.dev
, "ftm_fix");
432 if (IS_ERR(fpc
->clk
[FSL_PWM_CLK_FIX
]))
433 return PTR_ERR(fpc
->clk
[FSL_PWM_CLK_FIX
]);
435 fpc
->clk
[FSL_PWM_CLK_EXT
] = devm_clk_get(fpc
->chip
.dev
, "ftm_ext");
436 if (IS_ERR(fpc
->clk
[FSL_PWM_CLK_EXT
]))
437 return PTR_ERR(fpc
->clk
[FSL_PWM_CLK_EXT
]);
439 fpc
->clk
[FSL_PWM_CLK_CNTEN
] =
440 devm_clk_get(fpc
->chip
.dev
, "ftm_cnt_clk_en");
441 if (IS_ERR(fpc
->clk
[FSL_PWM_CLK_CNTEN
]))
442 return PTR_ERR(fpc
->clk
[FSL_PWM_CLK_CNTEN
]);
445 * ipg_clk is the interface clock for the IP. If not provided, use the
446 * ftm_sys clock as the default.
448 fpc
->ipg_clk
= devm_clk_get(&pdev
->dev
, "ipg");
449 if (IS_ERR(fpc
->ipg_clk
))
450 fpc
->ipg_clk
= fpc
->clk
[FSL_PWM_CLK_SYS
];
453 fpc
->chip
.ops
= &fsl_pwm_ops
;
454 fpc
->chip
.of_xlate
= of_pwm_xlate_with_flags
;
455 fpc
->chip
.of_pwm_n_cells
= 3;
459 ret
= pwmchip_add(&fpc
->chip
);
461 dev_err(&pdev
->dev
, "failed to add PWM chip: %d\n", ret
);
465 platform_set_drvdata(pdev
, fpc
);
467 return fsl_pwm_init(fpc
);
470 static int fsl_pwm_remove(struct platform_device
*pdev
)
472 struct fsl_pwm_chip
*fpc
= platform_get_drvdata(pdev
);
474 return pwmchip_remove(&fpc
->chip
);
477 #ifdef CONFIG_PM_SLEEP
478 static int fsl_pwm_suspend(struct device
*dev
)
480 struct fsl_pwm_chip
*fpc
= dev_get_drvdata(dev
);
483 regcache_cache_only(fpc
->regmap
, true);
484 regcache_mark_dirty(fpc
->regmap
);
486 for (i
= 0; i
< fpc
->chip
.npwm
; i
++) {
487 struct pwm_device
*pwm
= &fpc
->chip
.pwms
[i
];
489 if (!test_bit(PWMF_REQUESTED
, &pwm
->flags
))
492 clk_disable_unprepare(fpc
->ipg_clk
);
494 if (!pwm_is_enabled(pwm
))
497 clk_disable_unprepare(fpc
->clk
[FSL_PWM_CLK_CNTEN
]);
498 clk_disable_unprepare(fpc
->clk
[fpc
->period
.clk_select
]);
504 static int fsl_pwm_resume(struct device
*dev
)
506 struct fsl_pwm_chip
*fpc
= dev_get_drvdata(dev
);
509 for (i
= 0; i
< fpc
->chip
.npwm
; i
++) {
510 struct pwm_device
*pwm
= &fpc
->chip
.pwms
[i
];
512 if (!test_bit(PWMF_REQUESTED
, &pwm
->flags
))
515 clk_prepare_enable(fpc
->ipg_clk
);
517 if (!pwm_is_enabled(pwm
))
520 clk_prepare_enable(fpc
->clk
[fpc
->period
.clk_select
]);
521 clk_prepare_enable(fpc
->clk
[FSL_PWM_CLK_CNTEN
]);
524 /* restore all registers from cache */
525 regcache_cache_only(fpc
->regmap
, false);
526 regcache_sync(fpc
->regmap
);
532 static const struct dev_pm_ops fsl_pwm_pm_ops
= {
533 SET_SYSTEM_SLEEP_PM_OPS(fsl_pwm_suspend
, fsl_pwm_resume
)
536 static const struct fsl_ftm_soc vf610_ftm_pwm
= {
537 .has_enable_bits
= false,
540 static const struct fsl_ftm_soc imx8qm_ftm_pwm
= {
541 .has_enable_bits
= true,
544 static const struct of_device_id fsl_pwm_dt_ids
[] = {
545 { .compatible
= "fsl,vf610-ftm-pwm", .data
= &vf610_ftm_pwm
},
546 { .compatible
= "fsl,imx8qm-ftm-pwm", .data
= &imx8qm_ftm_pwm
},
549 MODULE_DEVICE_TABLE(of
, fsl_pwm_dt_ids
);
551 static struct platform_driver fsl_pwm_driver
= {
553 .name
= "fsl-ftm-pwm",
554 .of_match_table
= fsl_pwm_dt_ids
,
555 .pm
= &fsl_pwm_pm_ops
,
557 .probe
= fsl_pwm_probe
,
558 .remove
= fsl_pwm_remove
,
560 module_platform_driver(fsl_pwm_driver
);
562 MODULE_DESCRIPTION("Freescale FlexTimer Module PWM Driver");
563 MODULE_AUTHOR("Xiubo Li <Li.Xiubo@freescale.com>");
564 MODULE_ALIAS("platform:fsl-ftm-pwm");
565 MODULE_LICENSE("GPL");