1 // SPDX-License-Identifier: GPL-2.0-only
3 * drivers/pwm/pwm-pxa.c
5 * simple driver for PWM (Pulse Width Modulator) controller
7 * 2008-02-13 initial version
8 * eric miao <eric.miao@marvell.com>
10 * Links to reference manuals for some of the supported PWM chips can be found
11 * in Documentation/arch/arm/marvell.rst.
14 * - When PWM is stopped, the current PWM period stops abruptly at the next
15 * input clock (PWMCR_SD is set) and the output is driven to inactive.
18 #include <linux/mod_devicetable.h>
19 #include <linux/module.h>
20 #include <linux/kernel.h>
21 #include <linux/platform_device.h>
22 #include <linux/slab.h>
23 #include <linux/err.h>
24 #include <linux/clk.h>
26 #include <linux/pwm.h>
29 #include <asm/div64.h>
31 #define HAS_SECONDARY_PWM 0x10
33 static const struct platform_device_id pwm_id_table
[] = {
34 /* PWM has_secondary_pwm? */
36 { "pxa27x-pwm", HAS_SECONDARY_PWM
},
41 MODULE_DEVICE_TABLE(platform
, pwm_id_table
);
43 /* PWM registers and bits definitions */
48 #define PWMCR_SD (1 << 6)
49 #define PWMDCR_FD (1 << 10)
55 void __iomem
*mmio_base
;
58 static inline struct pxa_pwm_chip
*to_pxa_pwm_chip(struct pwm_chip
*chip
)
60 return pwmchip_get_drvdata(chip
);
64 * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
65 * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
67 static int pxa_pwm_config(struct pwm_chip
*chip
, struct pwm_device
*pwm
,
68 u64 duty_ns
, u64 period_ns
)
70 struct pxa_pwm_chip
*pc
= to_pxa_pwm_chip(chip
);
72 unsigned long period_cycles
, prescale
, pv
, dc
;
75 offset
= pwm
->hwpwm
? 0x10 : 0;
77 c
= clk_get_rate(pc
->clk
);
79 do_div(c
, 1000000000);
82 if (period_cycles
< 1)
84 prescale
= (period_cycles
- 1) / 1024;
85 pv
= period_cycles
/ (prescale
+ 1) - 1;
90 if (duty_ns
== period_ns
)
93 dc
= mul_u64_u64_div_u64(pv
+ 1, duty_ns
, period_ns
);
95 writel(prescale
| PWMCR_SD
, pc
->mmio_base
+ offset
+ PWMCR
);
96 writel(dc
, pc
->mmio_base
+ offset
+ PWMDCR
);
97 writel(pv
, pc
->mmio_base
+ offset
+ PWMPCR
);
102 static int pxa_pwm_apply(struct pwm_chip
*chip
, struct pwm_device
*pwm
,
103 const struct pwm_state
*state
)
105 struct pxa_pwm_chip
*pc
= to_pxa_pwm_chip(chip
);
109 if (state
->polarity
!= PWM_POLARITY_NORMAL
)
112 err
= clk_prepare_enable(pc
->clk
);
116 duty_cycle
= state
->enabled
? state
->duty_cycle
: 0;
118 err
= pxa_pwm_config(chip
, pwm
, duty_cycle
, state
->period
);
120 clk_disable_unprepare(pc
->clk
);
124 if (state
->enabled
&& !pwm
->state
.enabled
)
127 clk_disable_unprepare(pc
->clk
);
129 if (!state
->enabled
&& pwm
->state
.enabled
)
130 clk_disable_unprepare(pc
->clk
);
135 static const struct pwm_ops pxa_pwm_ops
= {
136 .apply
= pxa_pwm_apply
,
141 * Device tree users must create one device instance for each PWM channel.
142 * Hence we dispense with the HAS_SECONDARY_PWM and "tell" the original driver
143 * code that this is a single channel pxa25x-pwm. Currently all devices are
144 * supported identically.
146 static const struct of_device_id pwm_of_match
[] = {
147 { .compatible
= "marvell,pxa250-pwm", .data
= &pwm_id_table
[0]},
148 { .compatible
= "marvell,pxa270-pwm", .data
= &pwm_id_table
[0]},
149 { .compatible
= "marvell,pxa168-pwm", .data
= &pwm_id_table
[0]},
150 { .compatible
= "marvell,pxa910-pwm", .data
= &pwm_id_table
[0]},
153 MODULE_DEVICE_TABLE(of
, pwm_of_match
);
155 #define pwm_of_match NULL
158 static int pwm_probe(struct platform_device
*pdev
)
160 const struct platform_device_id
*id
= platform_get_device_id(pdev
);
161 struct pwm_chip
*chip
;
162 struct pxa_pwm_chip
*pc
;
165 if (IS_ENABLED(CONFIG_OF
) && id
== NULL
)
166 id
= of_device_get_match_data(&pdev
->dev
);
171 chip
= devm_pwmchip_alloc(&pdev
->dev
,
172 (id
->driver_data
& HAS_SECONDARY_PWM
) ? 2 : 1,
175 return PTR_ERR(chip
);
176 pc
= to_pxa_pwm_chip(chip
);
178 pc
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
180 return PTR_ERR(pc
->clk
);
182 chip
->ops
= &pxa_pwm_ops
;
184 if (IS_ENABLED(CONFIG_OF
))
185 chip
->of_xlate
= of_pwm_single_xlate
;
187 pc
->mmio_base
= devm_platform_ioremap_resource(pdev
, 0);
188 if (IS_ERR(pc
->mmio_base
))
189 return PTR_ERR(pc
->mmio_base
);
191 ret
= devm_pwmchip_add(&pdev
->dev
, chip
);
193 dev_err(&pdev
->dev
, "pwmchip_add() failed: %d\n", ret
);
200 static struct platform_driver pwm_driver
= {
202 .name
= "pxa25x-pwm",
203 .of_match_table
= pwm_of_match
,
206 .id_table
= pwm_id_table
,
209 module_platform_driver(pwm_driver
);
211 MODULE_DESCRIPTION("PXA Pulse Width Modulator driver");
212 MODULE_LICENSE("GPL v2");