File Index
Files and directories
Sign in
FILE

pwm-fsl-ftm.c

File preview with syntax highlighting.

linux-6.19.14/drivers/pwm/pwm-fsl-ftm.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *  Freescale FlexTimer Module (FTM) PWM Driver
  4 *
  5 *  Copyright 2012-2013 Freescale Semiconductor, Inc.
  6 *  Copyright 2020-2025 NXP
  7 */
  8
  9#include <linux/clk.h>
 10#include <linux/err.h>
 11#include <linux/io.h>
 12#include <linux/kernel.h>
 13#include <linux/module.h>
 14#include <linux/of.h>
 15#include <linux/platform_device.h>
 16#include <linux/pm.h>
 17#include <linux/pwm.h>
 18#include <linux/regmap.h>
 19#include <linux/slab.h>
 20#include <linux/fsl/ftm.h>
 21
 22#define FTM_SC_CLK(c)	(((c) + 1) << FTM_SC_CLK_MASK_SHIFT)
 23
 24enum fsl_pwm_clk {
 25	FSL_PWM_CLK_SYS,
 26	FSL_PWM_CLK_FIX,
 27	FSL_PWM_CLK_EXT,
 28	FSL_PWM_CLK_CNTEN,
 29	FSL_PWM_CLK_MAX
 30};
 31
 32struct fsl_ftm_soc {
 33	bool has_enable_bits;
 34	bool has_flt_reg;
 35	unsigned int npwm;
 36};
 37
 38struct fsl_pwm_periodcfg {
 39	enum fsl_pwm_clk clk_select;
 40	unsigned int clk_ps;
 41	unsigned int mod_period;
 42};
 43
 44struct fsl_pwm_chip {
 45	struct regmap *regmap;
 46
 47	/* This value is valid iff a pwm is running */
 48	struct fsl_pwm_periodcfg period;
 49
 50	struct clk *ipg_clk;
 51	struct clk *clk[FSL_PWM_CLK_MAX];
 52
 53	const struct fsl_ftm_soc *soc;
 54};
 55
 56static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip)
 57{
 58	return pwmchip_get_drvdata(chip);
 59}
 60
 61static void ftm_clear_write_protection(struct fsl_pwm_chip *fpc)
 62{
 63	u32 val;
 64
 65	regmap_read(fpc->regmap, FTM_FMS, &val);
 66	if (val & FTM_FMS_WPEN)
 67		regmap_set_bits(fpc->regmap, FTM_MODE, FTM_MODE_WPDIS);
 68}
 69
 70static void ftm_set_write_protection(struct fsl_pwm_chip *fpc)
 71{
 72	regmap_set_bits(fpc->regmap, FTM_FMS, FTM_FMS_WPEN);
 73}
 74
 75static bool fsl_pwm_periodcfg_are_equal(const struct fsl_pwm_periodcfg *a,
 76					const struct fsl_pwm_periodcfg *b)
 77{
 78	if (a->clk_select != b->clk_select)
 79		return false;
 80	if (a->clk_ps != b->clk_ps)
 81		return false;
 82	if (a->mod_period != b->mod_period)
 83		return false;
 84	return true;
 85}
 86
 87static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 88{
 89	int ret;
 90	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
 91
 92	ret = clk_prepare_enable(fpc->ipg_clk);
 93	if (!ret && fpc->soc->has_enable_bits)
 94		regmap_set_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16));
 95
 96	return ret;
 97}
 98
 99static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
100{
101	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
102
103	if (fpc->soc->has_enable_bits)
104		regmap_clear_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16));
105
106	clk_disable_unprepare(fpc->ipg_clk);
107}
108
109static unsigned int fsl_pwm_ticks_to_ns(struct fsl_pwm_chip *fpc,
110					  unsigned int ticks)
111{
112	unsigned long rate;
113	unsigned long long exval;
114
115	rate = clk_get_rate(fpc->clk[fpc->period.clk_select]);
116	if (rate >> fpc->period.clk_ps == 0)
117		return 0;
118
119	exval = ticks;
120	exval *= 1000000000UL;
121	do_div(exval, rate >> fpc->period.clk_ps);
122	return exval;
123}
124
125static bool fsl_pwm_calculate_period_clk(struct fsl_pwm_chip *fpc,
126					 unsigned int period_ns,
127					 enum fsl_pwm_clk index,
128					 struct fsl_pwm_periodcfg *periodcfg
129					 )
130{
131	unsigned long long c;
132	unsigned int ps;
133
134	c = clk_get_rate(fpc->clk[index]);
135	c = c * period_ns;
136	do_div(c, 1000000000UL);
137
138	if (c == 0)
139		return false;
140
141	for (ps = 0; ps < 8 ; ++ps, c >>= 1) {
142		if (c <= 0x10000) {
143			periodcfg->clk_select = index;
144			periodcfg->clk_ps = ps;
145			periodcfg->mod_period = c - 1;
146			return true;
147		}
148	}
149	return false;
150}
151
152static bool fsl_pwm_calculate_period(struct fsl_pwm_chip *fpc,
153				     unsigned int period_ns,
154				     struct fsl_pwm_periodcfg *periodcfg)
155{
156	enum fsl_pwm_clk m0, m1;
157	unsigned long fix_rate, ext_rate;
158	bool ret;
159
160	ret = fsl_pwm_calculate_period_clk(fpc, period_ns, FSL_PWM_CLK_SYS,
161					   periodcfg);
162	if (ret)
163		return true;
164
165	fix_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_FIX]);
166	ext_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_EXT]);
167
168	if (fix_rate > ext_rate) {
169		m0 = FSL_PWM_CLK_FIX;
170		m1 = FSL_PWM_CLK_EXT;
171	} else {
172		m0 = FSL_PWM_CLK_EXT;
173		m1 = FSL_PWM_CLK_FIX;
174	}
175
176	ret = fsl_pwm_calculate_period_clk(fpc, period_ns, m0, periodcfg);
177	if (ret)
178		return true;
179
180	return fsl_pwm_calculate_period_clk(fpc, period_ns, m1, periodcfg);
181}
182
183static unsigned int fsl_pwm_calculate_duty(struct fsl_pwm_chip *fpc,
184					   unsigned int duty_ns)
185{
186	unsigned long long duty;
187
188	unsigned int period = fpc->period.mod_period + 1;
189	unsigned int period_ns = fsl_pwm_ticks_to_ns(fpc, period);
190
191	if (!period_ns)
192		return 0;
193
194	duty = (unsigned long long)duty_ns * period;
195	do_div(duty, period_ns);
196
197	return (unsigned int)duty;
198}
199
200static bool fsl_pwm_is_any_pwm_enabled(struct fsl_pwm_chip *fpc,
201				       struct pwm_device *pwm)
202{
203	u32 val;
204
205	regmap_read(fpc->regmap, FTM_OUTMASK, &val);
206	if (~val & 0xFF)
207		return true;
208	else
209		return false;
210}
211
212static bool fsl_pwm_is_other_pwm_enabled(struct fsl_pwm_chip *fpc,
213					 struct pwm_device *pwm)
214{
215	u32 val;
216
217	regmap_read(fpc->regmap, FTM_OUTMASK, &val);
218	if (~(val | BIT(pwm->hwpwm)) & 0xFF)
219		return true;
220	else
221		return false;
222}
223
224static int fsl_pwm_apply_config(struct pwm_chip *chip,
225				struct pwm_device *pwm,
226				const struct pwm_state *newstate)
227{
228	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
229	unsigned int duty;
230	u32 reg_polarity;
231
232	struct fsl_pwm_periodcfg periodcfg;
233	bool do_write_period = false;
234
235	if (!fsl_pwm_calculate_period(fpc, newstate->period, &periodcfg)) {
236		dev_err(pwmchip_parent(chip), "failed to calculate new period\n");
237		return -EINVAL;
238	}
239
240	if (!fsl_pwm_is_any_pwm_enabled(fpc, pwm))
241		do_write_period = true;
242	/*
243	 * The Freescale FTM controller supports only a single period for
244	 * all PWM channels, therefore verify if the newly computed period
245	 * is different than the current period being used. In such case
246	 * we allow to change the period only if no other pwm is running.
247	 */
248	else if (!fsl_pwm_periodcfg_are_equal(&fpc->period, &periodcfg)) {
249		if (fsl_pwm_is_other_pwm_enabled(fpc, pwm)) {
250			dev_err(pwmchip_parent(chip),
251				"Cannot change period for PWM %u, disable other PWMs first\n",
252				pwm->hwpwm);
253			return -EBUSY;
254		}
255		if (fpc->period.clk_select != periodcfg.clk_select) {
256			int ret;
257			enum fsl_pwm_clk oldclk = fpc->period.clk_select;
258			enum fsl_pwm_clk newclk = periodcfg.clk_select;
259
260			ret = clk_prepare_enable(fpc->clk[newclk]);
261			if (ret)
262				return ret;
263			clk_disable_unprepare(fpc->clk[oldclk]);
264		}
265		do_write_period = true;
266	}
267
268	ftm_clear_write_protection(fpc);
269
270	if (do_write_period) {
271		regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK,
272				   FTM_SC_CLK(periodcfg.clk_select));
273		regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_PS_MASK,
274				   periodcfg.clk_ps);
275		regmap_write(fpc->regmap, FTM_MOD, periodcfg.mod_period);
276
277		fpc->period = periodcfg;
278	}
279
280	duty = fsl_pwm_calculate_duty(fpc, newstate->duty_cycle);
281
282	regmap_write(fpc->regmap, FTM_CSC(pwm->hwpwm),
283		     FTM_CSC_MSB | FTM_CSC_ELSB);
284	regmap_write(fpc->regmap, FTM_CV(pwm->hwpwm), duty);
285
286	reg_polarity = 0;
287	if (newstate->polarity == PWM_POLARITY_INVERSED)
288		reg_polarity = BIT(pwm->hwpwm);
289
290	regmap_update_bits(fpc->regmap, FTM_POL, BIT(pwm->hwpwm), reg_polarity);
291
292	ftm_set_write_protection(fpc);
293
294	return 0;
295}
296
297static int fsl_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
298			 const struct pwm_state *newstate)
299{
300	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
301	struct pwm_state *oldstate = &pwm->state;
302	int ret;
303
304	/*
305	 * oldstate to newstate : action
306	 *
307	 * disabled to disabled : ignore
308	 * enabled to disabled : disable
309	 * enabled to enabled : update settings
310	 * disabled to enabled : update settings + enable
311	 */
312
313	if (!newstate->enabled) {
314		if (oldstate->enabled) {
315			regmap_set_bits(fpc->regmap, FTM_OUTMASK,
316					BIT(pwm->hwpwm));
317			clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
318			clk_disable_unprepare(fpc->clk[fpc->period.clk_select]);
319		}
320
321		return 0;
322	}
323
324	ret = fsl_pwm_apply_config(chip, pwm, newstate);
325	if (ret)
326		return ret;
327
328	/* check if need to enable */
329	if (!oldstate->enabled) {
330		ret = clk_prepare_enable(fpc->clk[fpc->period.clk_select]);
331		if (ret)
332			return ret;
333
334		ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);
335		if (ret) {
336			clk_disable_unprepare(fpc->clk[fpc->period.clk_select]);
337			return ret;
338		}
339
340		regmap_clear_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm));
341	}
342
343	return ret;
344}
345
346static const struct pwm_ops fsl_pwm_ops = {
347	.request = fsl_pwm_request,
348	.free = fsl_pwm_free,
349	.apply = fsl_pwm_apply,
350};
351
352static int fsl_pwm_init(struct fsl_pwm_chip *fpc)
353{
354	int ret;
355
356	ret = clk_prepare_enable(fpc->ipg_clk);
357	if (ret)
358		return ret;
359
360	regmap_write(fpc->regmap, FTM_CNTIN, 0x00);
361	regmap_write(fpc->regmap, FTM_OUTINIT, 0x00);
362	regmap_write(fpc->regmap, FTM_OUTMASK, 0xFF);
363
364	clk_disable_unprepare(fpc->ipg_clk);
365
366	return 0;
367}
368
369static bool fsl_pwm_volatile_reg(struct device *dev, unsigned int reg)
370{
371	switch (reg) {
372	case FTM_FMS:
373	case FTM_MODE:
374	case FTM_CNT:
375		return true;
376	}
377	return false;
378}
379
380static bool fsl_pwm_is_reg(struct device *dev, unsigned int reg)
381{
382	struct pwm_chip *chip = dev_get_drvdata(dev);
383	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
384
385	if (reg >= FTM_CSC(fpc->soc->npwm) && reg < FTM_CNTIN)
386		return false;
387
388	if ((reg == FTM_FLTCTRL || reg == FTM_FLTPOL) && !fpc->soc->has_flt_reg)
389		return false;
390
391	return true;
392}
393
394static const struct regmap_config fsl_pwm_regmap_config = {
395	.reg_bits = 32,
396	.reg_stride = 4,
397	.val_bits = 32,
398
399	.max_register = FTM_PWMLOAD,
400	.volatile_reg = fsl_pwm_volatile_reg,
401	.cache_type = REGCACHE_FLAT,
402	.writeable_reg = fsl_pwm_is_reg,
403	.readable_reg = fsl_pwm_is_reg,
404};
405
406static int fsl_pwm_probe(struct platform_device *pdev)
407{
408	const struct fsl_ftm_soc *soc = of_device_get_match_data(&pdev->dev);
409	struct pwm_chip *chip;
410	struct fsl_pwm_chip *fpc;
411	void __iomem *base;
412	int ret;
413
414	chip = devm_pwmchip_alloc(&pdev->dev, soc->npwm, sizeof(*fpc));
415	if (IS_ERR(chip))
416		return PTR_ERR(chip);
417	fpc = to_fsl_chip(chip);
418
419	fpc->soc = soc;
420
421	base = devm_platform_ioremap_resource(pdev, 0);
422	if (IS_ERR(base))
423		return PTR_ERR(base);
424
425	fpc->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "ftm_sys", base,
426						&fsl_pwm_regmap_config);
427	if (IS_ERR(fpc->regmap)) {
428		dev_err(&pdev->dev, "regmap init failed\n");
429		return PTR_ERR(fpc->regmap);
430	}
431
432	fpc->clk[FSL_PWM_CLK_SYS] = devm_clk_get(&pdev->dev, "ftm_sys");
433	if (IS_ERR(fpc->clk[FSL_PWM_CLK_SYS])) {
434		dev_err(&pdev->dev, "failed to get \"ftm_sys\" clock\n");
435		return PTR_ERR(fpc->clk[FSL_PWM_CLK_SYS]);
436	}
437
438	fpc->clk[FSL_PWM_CLK_FIX] = devm_clk_get(&pdev->dev, "ftm_fix");
439	if (IS_ERR(fpc->clk[FSL_PWM_CLK_FIX]))
440		return PTR_ERR(fpc->clk[FSL_PWM_CLK_FIX]);
441
442	fpc->clk[FSL_PWM_CLK_EXT] = devm_clk_get(&pdev->dev, "ftm_ext");
443	if (IS_ERR(fpc->clk[FSL_PWM_CLK_EXT]))
444		return PTR_ERR(fpc->clk[FSL_PWM_CLK_EXT]);
445
446	fpc->clk[FSL_PWM_CLK_CNTEN] =
447				devm_clk_get(&pdev->dev, "ftm_cnt_clk_en");
448	if (IS_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]))
449		return PTR_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]);
450
451	/*
452	 * ipg_clk is the interface clock for the IP. If not provided, use the
453	 * ftm_sys clock as the default.
454	 */
455	fpc->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
456	if (IS_ERR(fpc->ipg_clk))
457		fpc->ipg_clk = fpc->clk[FSL_PWM_CLK_SYS];
458
459	chip->ops = &fsl_pwm_ops;
460
461	ret = devm_pwmchip_add(&pdev->dev, chip);
462	if (ret < 0) {
463		dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
464		return ret;
465	}
466
467	platform_set_drvdata(pdev, chip);
468
469	return fsl_pwm_init(fpc);
470}
471
472#ifdef CONFIG_PM_SLEEP
473static int fsl_pwm_suspend(struct device *dev)
474{
475	struct pwm_chip *chip = dev_get_drvdata(dev);
476	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
477	int i;
478
479	regcache_cache_only(fpc->regmap, true);
480	regcache_mark_dirty(fpc->regmap);
481
482	for (i = 0; i < chip->npwm; i++) {
483		struct pwm_device *pwm = &chip->pwms[i];
484
485		if (!test_bit(PWMF_REQUESTED, &pwm->flags))
486			continue;
487
488		clk_disable_unprepare(fpc->ipg_clk);
489
490		if (!pwm_is_enabled(pwm))
491			continue;
492
493		clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
494		clk_disable_unprepare(fpc->clk[fpc->period.clk_select]);
495	}
496
497	return 0;
498}
499
500static int fsl_pwm_resume(struct device *dev)
501{
502	struct pwm_chip *chip = dev_get_drvdata(dev);
503	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
504	int i;
505
506	for (i = 0; i < chip->npwm; i++) {
507		struct pwm_device *pwm = &chip->pwms[i];
508
509		if (!test_bit(PWMF_REQUESTED, &pwm->flags))
510			continue;
511
512		clk_prepare_enable(fpc->ipg_clk);
513
514		if (!pwm_is_enabled(pwm))
515			continue;
516
517		clk_prepare_enable(fpc->clk[fpc->period.clk_select]);
518		clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);
519	}
520
521	/* restore all registers from cache */
522	regcache_cache_only(fpc->regmap, false);
523	regcache_sync(fpc->regmap);
524
525	return 0;
526}
527#endif
528
529static const struct dev_pm_ops fsl_pwm_pm_ops = {
530	SET_SYSTEM_SLEEP_PM_OPS(fsl_pwm_suspend, fsl_pwm_resume)
531};
532
533static const struct fsl_ftm_soc vf610_ftm_pwm = {
534	.has_enable_bits = false,
535	.has_flt_reg = true,
536	.npwm = 8,
537};
538
539static const struct fsl_ftm_soc imx8qm_ftm_pwm = {
540	.has_enable_bits = true,
541	.has_flt_reg = true,
542	.npwm = 8,
543};
544
545static const struct fsl_ftm_soc s32g2_ftm_pwm = {
546	.has_enable_bits = true,
547	.has_flt_reg = false,
548	.npwm = 6,
549};
550
551static const struct of_device_id fsl_pwm_dt_ids[] = {
552	{ .compatible = "fsl,vf610-ftm-pwm", .data = &vf610_ftm_pwm },
553	{ .compatible = "fsl,imx8qm-ftm-pwm", .data = &imx8qm_ftm_pwm },
554	{ .compatible = "nxp,s32g2-ftm-pwm", .data = &s32g2_ftm_pwm },
555	{ /* sentinel */ }
556};
557MODULE_DEVICE_TABLE(of, fsl_pwm_dt_ids);
558
559static struct platform_driver fsl_pwm_driver = {
560	.driver = {
561		.name = "fsl-ftm-pwm",
562		.of_match_table = fsl_pwm_dt_ids,
563		.pm = &fsl_pwm_pm_ops,
564	},
565	.probe = fsl_pwm_probe,
566};
567module_platform_driver(fsl_pwm_driver);
568
569MODULE_DESCRIPTION("Freescale FlexTimer Module PWM Driver");
570MODULE_AUTHOR("Xiubo Li <Li.Xiubo@freescale.com>");
571MODULE_ALIAS("platform:fsl-ftm-pwm");
572MODULE_LICENSE("GPL");
~/ Read-only file preview.