1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2014 Free Electrons
4 * Copyright (C) 2014 Atmel
6 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
10 #include <linux/delay.h>
11 #include <linux/mfd/atmel-hlcdc.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/pwm.h>
15 #include <linux/regmap.h>
17 #define ATMEL_HLCDC_PWMCVAL_MASK GENMASK(15, 8)
18 #define ATMEL_HLCDC_PWMCVAL(x) (((x) << 8) & ATMEL_HLCDC_PWMCVAL_MASK)
19 #define ATMEL_HLCDC_PWMPOL BIT(4)
20 #define ATMEL_HLCDC_PWMPS_MASK GENMASK(2, 0)
21 #define ATMEL_HLCDC_PWMPS_MAX 0x6
22 #define ATMEL_HLCDC_PWMPS(x) ((x) & ATMEL_HLCDC_PWMPS_MASK)
24 struct atmel_hlcdc_pwm_errata
{
25 bool slow_clk_erratum
;
26 bool div1_clk_erratum
;
29 struct atmel_hlcdc_pwm
{
31 struct atmel_hlcdc
*hlcdc
;
33 const struct atmel_hlcdc_pwm_errata
*errata
;
36 static inline struct atmel_hlcdc_pwm
*to_atmel_hlcdc_pwm(struct pwm_chip
*chip
)
38 return container_of(chip
, struct atmel_hlcdc_pwm
, chip
);
41 static int atmel_hlcdc_pwm_apply(struct pwm_chip
*c
, struct pwm_device
*pwm
,
42 const struct pwm_state
*state
)
44 struct atmel_hlcdc_pwm
*chip
= to_atmel_hlcdc_pwm(c
);
45 struct atmel_hlcdc
*hlcdc
= chip
->hlcdc
;
50 struct clk
*new_clk
= hlcdc
->slow_clk
;
51 u64 pwmcval
= state
->duty_cycle
* 256;
52 unsigned long clk_freq
;
57 if (!chip
->errata
|| !chip
->errata
->slow_clk_erratum
) {
58 clk_freq
= clk_get_rate(new_clk
);
62 clk_period_ns
= (u64
)NSEC_PER_SEC
* 256;
63 do_div(clk_period_ns
, clk_freq
);
66 /* Errata: cannot use slow clk on some IP revisions */
67 if ((chip
->errata
&& chip
->errata
->slow_clk_erratum
) ||
68 clk_period_ns
> state
->period
) {
69 new_clk
= hlcdc
->sys_clk
;
70 clk_freq
= clk_get_rate(new_clk
);
74 clk_period_ns
= (u64
)NSEC_PER_SEC
* 256;
75 do_div(clk_period_ns
, clk_freq
);
78 for (pres
= 0; pres
<= ATMEL_HLCDC_PWMPS_MAX
; pres
++) {
79 /* Errata: cannot divide by 1 on some IP revisions */
80 if (!pres
&& chip
->errata
&&
81 chip
->errata
->div1_clk_erratum
)
84 if ((clk_period_ns
<< pres
) >= state
->period
)
88 if (pres
> ATMEL_HLCDC_PWMPS_MAX
)
91 pwmcfg
= ATMEL_HLCDC_PWMPS(pres
);
93 if (new_clk
!= chip
->cur_clk
) {
97 ret
= clk_prepare_enable(new_clk
);
101 clk_disable_unprepare(chip
->cur_clk
);
102 chip
->cur_clk
= new_clk
;
104 if (new_clk
== hlcdc
->sys_clk
)
105 gencfg
= ATMEL_HLCDC_CLKPWMSEL
;
107 ret
= regmap_update_bits(hlcdc
->regmap
,
109 ATMEL_HLCDC_CLKPWMSEL
,
115 do_div(pwmcval
, state
->period
);
118 * The PWM duty cycle is configurable from 0/256 to 255/256 of
119 * the period cycle. Hence we can't set a duty cycle occupying
120 * the whole period cycle if we're asked to.
121 * Set it to 255 if pwmcval is greater than 256.
126 pwmcfg
|= ATMEL_HLCDC_PWMCVAL(pwmcval
);
128 if (state
->polarity
== PWM_POLARITY_NORMAL
)
129 pwmcfg
|= ATMEL_HLCDC_PWMPOL
;
131 ret
= regmap_update_bits(hlcdc
->regmap
, ATMEL_HLCDC_CFG(6),
132 ATMEL_HLCDC_PWMCVAL_MASK
|
133 ATMEL_HLCDC_PWMPS_MASK
|
139 ret
= regmap_write(hlcdc
->regmap
, ATMEL_HLCDC_EN
,
144 ret
= regmap_read_poll_timeout(hlcdc
->regmap
, ATMEL_HLCDC_SR
,
146 status
& ATMEL_HLCDC_PWM
,
151 ret
= regmap_write(hlcdc
->regmap
, ATMEL_HLCDC_DIS
,
156 ret
= regmap_read_poll_timeout(hlcdc
->regmap
, ATMEL_HLCDC_SR
,
158 !(status
& ATMEL_HLCDC_PWM
),
163 clk_disable_unprepare(chip
->cur_clk
);
164 chip
->cur_clk
= NULL
;
170 static const struct pwm_ops atmel_hlcdc_pwm_ops
= {
171 .apply
= atmel_hlcdc_pwm_apply
,
172 .owner
= THIS_MODULE
,
175 static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_at91sam9x5_errata
= {
176 .slow_clk_erratum
= true,
179 static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata
= {
180 .div1_clk_erratum
= true,
183 #ifdef CONFIG_PM_SLEEP
184 static int atmel_hlcdc_pwm_suspend(struct device
*dev
)
186 struct atmel_hlcdc_pwm
*chip
= dev_get_drvdata(dev
);
188 /* Keep the periph clock enabled if the PWM is still running. */
189 if (pwm_is_enabled(&chip
->chip
.pwms
[0]))
190 clk_disable_unprepare(chip
->hlcdc
->periph_clk
);
195 static int atmel_hlcdc_pwm_resume(struct device
*dev
)
197 struct atmel_hlcdc_pwm
*chip
= dev_get_drvdata(dev
);
198 struct pwm_state state
;
201 pwm_get_state(&chip
->chip
.pwms
[0], &state
);
203 /* Re-enable the periph clock it was stopped during suspend. */
204 if (!state
.enabled
) {
205 ret
= clk_prepare_enable(chip
->hlcdc
->periph_clk
);
210 return atmel_hlcdc_pwm_apply(&chip
->chip
, &chip
->chip
.pwms
[0], &state
);
214 static SIMPLE_DEV_PM_OPS(atmel_hlcdc_pwm_pm_ops
,
215 atmel_hlcdc_pwm_suspend
, atmel_hlcdc_pwm_resume
);
217 static const struct of_device_id atmel_hlcdc_dt_ids
[] = {
219 .compatible
= "atmel,at91sam9n12-hlcdc",
220 /* 9n12 has same errata as 9x5 HLCDC PWM */
221 .data
= &atmel_hlcdc_pwm_at91sam9x5_errata
,
224 .compatible
= "atmel,at91sam9x5-hlcdc",
225 .data
= &atmel_hlcdc_pwm_at91sam9x5_errata
,
228 .compatible
= "atmel,sama5d2-hlcdc",
231 .compatible
= "atmel,sama5d3-hlcdc",
232 .data
= &atmel_hlcdc_pwm_sama5d3_errata
,
235 .compatible
= "atmel,sama5d4-hlcdc",
236 .data
= &atmel_hlcdc_pwm_sama5d3_errata
,
238 { .compatible
= "microchip,sam9x60-hlcdc", },
241 MODULE_DEVICE_TABLE(of
, atmel_hlcdc_dt_ids
);
243 static int atmel_hlcdc_pwm_probe(struct platform_device
*pdev
)
245 const struct of_device_id
*match
;
246 struct device
*dev
= &pdev
->dev
;
247 struct atmel_hlcdc_pwm
*chip
;
248 struct atmel_hlcdc
*hlcdc
;
251 hlcdc
= dev_get_drvdata(dev
->parent
);
253 chip
= devm_kzalloc(dev
, sizeof(*chip
), GFP_KERNEL
);
257 ret
= clk_prepare_enable(hlcdc
->periph_clk
);
261 match
= of_match_node(atmel_hlcdc_dt_ids
, dev
->parent
->of_node
);
263 chip
->errata
= match
->data
;
266 chip
->chip
.ops
= &atmel_hlcdc_pwm_ops
;
267 chip
->chip
.dev
= dev
;
268 chip
->chip
.base
= -1;
270 chip
->chip
.of_xlate
= of_pwm_xlate_with_flags
;
271 chip
->chip
.of_pwm_n_cells
= 3;
273 ret
= pwmchip_add_with_polarity(&chip
->chip
, PWM_POLARITY_INVERSED
);
275 clk_disable_unprepare(hlcdc
->periph_clk
);
279 platform_set_drvdata(pdev
, chip
);
284 static int atmel_hlcdc_pwm_remove(struct platform_device
*pdev
)
286 struct atmel_hlcdc_pwm
*chip
= platform_get_drvdata(pdev
);
289 ret
= pwmchip_remove(&chip
->chip
);
293 clk_disable_unprepare(chip
->hlcdc
->periph_clk
);
298 static const struct of_device_id atmel_hlcdc_pwm_dt_ids
[] = {
299 { .compatible
= "atmel,hlcdc-pwm" },
303 static struct platform_driver atmel_hlcdc_pwm_driver
= {
305 .name
= "atmel-hlcdc-pwm",
306 .of_match_table
= atmel_hlcdc_pwm_dt_ids
,
307 .pm
= &atmel_hlcdc_pwm_pm_ops
,
309 .probe
= atmel_hlcdc_pwm_probe
,
310 .remove
= atmel_hlcdc_pwm_remove
,
312 module_platform_driver(atmel_hlcdc_pwm_driver
);
314 MODULE_ALIAS("platform:atmel-hlcdc-pwm");
315 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
316 MODULE_DESCRIPTION("Atmel HLCDC PWM driver");
317 MODULE_LICENSE("GPL v2");