1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> |
4 | * JZ4740 platform PWM support |
5 | * |
6 | * Limitations: |
7 | * - The .apply callback doesn't complete the currently running period before |
8 | * reconfiguring the hardware. |
9 | */ |
10 | |
11 | #include <linux/clk.h> |
12 | #include <linux/err.h> |
13 | #include <linux/gpio.h> |
14 | #include <linux/kernel.h> |
15 | #include <linux/mfd/ingenic-tcu.h> |
16 | #include <linux/mfd/syscon.h> |
17 | #include <linux/module.h> |
18 | #include <linux/of.h> |
19 | #include <linux/platform_device.h> |
20 | #include <linux/pwm.h> |
21 | #include <linux/regmap.h> |
22 | |
23 | struct soc_info { |
24 | unsigned int num_pwms; |
25 | }; |
26 | |
27 | struct jz4740_pwm_chip { |
28 | struct regmap *map; |
29 | struct clk *clk[]; |
30 | }; |
31 | |
32 | static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip) |
33 | { |
34 | return pwmchip_get_drvdata(chip); |
35 | } |
36 | |
37 | static bool jz4740_pwm_can_use_chn(struct pwm_chip *chip, unsigned int channel) |
38 | { |
39 | /* Enable all TCU channels for PWM use by default except channels 0/1 */ |
40 | u32 pwm_channels_mask = GENMASK(chip->npwm - 1, 2); |
41 | |
42 | device_property_read_u32(dev: pwmchip_parent(chip)->parent, |
43 | propname: "ingenic,pwm-channels-mask" , |
44 | val: &pwm_channels_mask); |
45 | |
46 | return !!(pwm_channels_mask & BIT(channel)); |
47 | } |
48 | |
49 | static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) |
50 | { |
51 | struct jz4740_pwm_chip *jz = to_jz4740(chip); |
52 | struct clk *clk; |
53 | char name[16]; |
54 | int err; |
55 | |
56 | if (!jz4740_pwm_can_use_chn(chip, channel: pwm->hwpwm)) |
57 | return -EBUSY; |
58 | |
59 | snprintf(buf: name, size: sizeof(name), fmt: "timer%u" , pwm->hwpwm); |
60 | |
61 | clk = clk_get(dev: pwmchip_parent(chip), id: name); |
62 | if (IS_ERR(ptr: clk)) { |
63 | dev_err(pwmchip_parent(chip), |
64 | "error %pe: Failed to get clock\n" , clk); |
65 | return PTR_ERR(ptr: clk); |
66 | } |
67 | |
68 | err = clk_prepare_enable(clk); |
69 | if (err < 0) { |
70 | clk_put(clk); |
71 | return err; |
72 | } |
73 | |
74 | jz->clk[pwm->hwpwm] = clk; |
75 | |
76 | return 0; |
77 | } |
78 | |
79 | static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) |
80 | { |
81 | struct jz4740_pwm_chip *jz = to_jz4740(chip); |
82 | struct clk *clk = jz->clk[pwm->hwpwm]; |
83 | |
84 | clk_disable_unprepare(clk); |
85 | clk_put(clk); |
86 | } |
87 | |
88 | static int jz4740_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) |
89 | { |
90 | struct jz4740_pwm_chip *jz = to_jz4740(chip); |
91 | |
92 | /* Enable PWM output */ |
93 | regmap_set_bits(map: jz->map, TCU_REG_TCSRc(pwm->hwpwm), TCU_TCSR_PWM_EN); |
94 | |
95 | /* Start counter */ |
96 | regmap_write(map: jz->map, TCU_REG_TESR, BIT(pwm->hwpwm)); |
97 | |
98 | return 0; |
99 | } |
100 | |
101 | static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) |
102 | { |
103 | struct jz4740_pwm_chip *jz = to_jz4740(chip); |
104 | |
105 | /* |
106 | * Set duty > period. This trick allows the TCU channels in TCU2 mode to |
107 | * properly return to their init level. |
108 | */ |
109 | regmap_write(map: jz->map, TCU_REG_TDHRc(pwm->hwpwm), val: 0xffff); |
110 | regmap_write(map: jz->map, TCU_REG_TDFRc(pwm->hwpwm), val: 0x0); |
111 | |
112 | /* |
113 | * Disable PWM output. |
114 | * In TCU2 mode (channel 1/2 on JZ4750+), this must be done before the |
115 | * counter is stopped, while in TCU1 mode the order does not matter. |
116 | */ |
117 | regmap_clear_bits(map: jz->map, TCU_REG_TCSRc(pwm->hwpwm), TCU_TCSR_PWM_EN); |
118 | |
119 | /* Stop counter */ |
120 | regmap_write(map: jz->map, TCU_REG_TECR, BIT(pwm->hwpwm)); |
121 | } |
122 | |
123 | static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, |
124 | const struct pwm_state *state) |
125 | { |
126 | struct jz4740_pwm_chip *jz = to_jz4740(chip); |
127 | unsigned long long tmp = 0xffffull * NSEC_PER_SEC; |
128 | struct clk *clk = jz->clk[pwm->hwpwm]; |
129 | unsigned long period, duty; |
130 | long rate; |
131 | int err; |
132 | |
133 | /* |
134 | * Limit the clock to a maximum rate that still gives us a period value |
135 | * which fits in 16 bits. |
136 | */ |
137 | do_div(tmp, state->period); |
138 | |
139 | /* |
140 | * /!\ IMPORTANT NOTE: |
141 | * ------------------- |
142 | * This code relies on the fact that clk_round_rate() will always round |
143 | * down, which is not a valid assumption given by the clk API, but only |
144 | * happens to be true with the clk drivers used for Ingenic SoCs. |
145 | * |
146 | * Right now, there is no alternative as the clk API does not have a |
147 | * round-down function (and won't have one for a while), but if it ever |
148 | * comes to light, a round-down function should be used instead. |
149 | */ |
150 | rate = clk_round_rate(clk, rate: tmp); |
151 | if (rate < 0) { |
152 | dev_err(pwmchip_parent(chip), "Unable to round rate: %ld\n" , rate); |
153 | return rate; |
154 | } |
155 | |
156 | /* Calculate period value */ |
157 | tmp = (unsigned long long)rate * state->period; |
158 | do_div(tmp, NSEC_PER_SEC); |
159 | period = tmp; |
160 | |
161 | /* Calculate duty value */ |
162 | tmp = (unsigned long long)rate * state->duty_cycle; |
163 | do_div(tmp, NSEC_PER_SEC); |
164 | duty = tmp; |
165 | |
166 | if (duty >= period) |
167 | duty = period - 1; |
168 | |
169 | jz4740_pwm_disable(chip, pwm); |
170 | |
171 | err = clk_set_rate(clk, rate); |
172 | if (err) { |
173 | dev_err(pwmchip_parent(chip), "Unable to set rate: %d\n" , err); |
174 | return err; |
175 | } |
176 | |
177 | /* Reset counter to 0 */ |
178 | regmap_write(map: jz->map, TCU_REG_TCNTc(pwm->hwpwm), val: 0); |
179 | |
180 | /* Set duty */ |
181 | regmap_write(map: jz->map, TCU_REG_TDHRc(pwm->hwpwm), val: duty); |
182 | |
183 | /* Set period */ |
184 | regmap_write(map: jz->map, TCU_REG_TDFRc(pwm->hwpwm), val: period); |
185 | |
186 | /* Set abrupt shutdown */ |
187 | regmap_set_bits(map: jz->map, TCU_REG_TCSRc(pwm->hwpwm), |
188 | TCU_TCSR_PWM_SD); |
189 | |
190 | /* |
191 | * Set polarity. |
192 | * |
193 | * The PWM starts in inactive state until the internal timer reaches the |
194 | * duty value, then becomes active until the timer reaches the period |
195 | * value. In theory, we should then use (period - duty) as the real duty |
196 | * value, as a high duty value would otherwise result in the PWM pin |
197 | * being inactive most of the time. |
198 | * |
199 | * Here, we don't do that, and instead invert the polarity of the PWM |
200 | * when it is active. This trick makes the PWM start with its active |
201 | * state instead of its inactive state. |
202 | */ |
203 | if ((state->polarity == PWM_POLARITY_NORMAL) ^ state->enabled) |
204 | regmap_update_bits(map: jz->map, TCU_REG_TCSRc(pwm->hwpwm), |
205 | TCU_TCSR_PWM_INITL_HIGH, val: 0); |
206 | else |
207 | regmap_update_bits(map: jz->map, TCU_REG_TCSRc(pwm->hwpwm), |
208 | TCU_TCSR_PWM_INITL_HIGH, |
209 | TCU_TCSR_PWM_INITL_HIGH); |
210 | |
211 | if (state->enabled) |
212 | jz4740_pwm_enable(chip, pwm); |
213 | |
214 | return 0; |
215 | } |
216 | |
217 | static const struct pwm_ops jz4740_pwm_ops = { |
218 | .request = jz4740_pwm_request, |
219 | .free = jz4740_pwm_free, |
220 | .apply = jz4740_pwm_apply, |
221 | }; |
222 | |
223 | static int jz4740_pwm_probe(struct platform_device *pdev) |
224 | { |
225 | struct device *dev = &pdev->dev; |
226 | struct pwm_chip *chip; |
227 | struct jz4740_pwm_chip *jz; |
228 | const struct soc_info *info; |
229 | |
230 | info = device_get_match_data(dev); |
231 | if (!info) |
232 | return -EINVAL; |
233 | |
234 | chip = devm_pwmchip_alloc(parent: dev, npwm: info->num_pwms, struct_size(jz, clk, info->num_pwms)); |
235 | if (IS_ERR(ptr: chip)) |
236 | return PTR_ERR(ptr: chip); |
237 | jz = to_jz4740(chip); |
238 | |
239 | jz->map = device_node_to_regmap(np: dev->parent->of_node); |
240 | if (IS_ERR(ptr: jz->map)) { |
241 | dev_err(dev, "regmap not found: %ld\n" , PTR_ERR(jz->map)); |
242 | return PTR_ERR(ptr: jz->map); |
243 | } |
244 | |
245 | chip->ops = &jz4740_pwm_ops; |
246 | |
247 | return devm_pwmchip_add(dev, chip); |
248 | } |
249 | |
250 | static const struct soc_info jz4740_soc_info = { |
251 | .num_pwms = 8, |
252 | }; |
253 | |
254 | static const struct soc_info jz4725b_soc_info = { |
255 | .num_pwms = 6, |
256 | }; |
257 | |
258 | static const struct soc_info x1000_soc_info = { |
259 | .num_pwms = 5, |
260 | }; |
261 | |
262 | static const struct of_device_id jz4740_pwm_dt_ids[] = { |
263 | { .compatible = "ingenic,jz4740-pwm" , .data = &jz4740_soc_info }, |
264 | { .compatible = "ingenic,jz4725b-pwm" , .data = &jz4725b_soc_info }, |
265 | { .compatible = "ingenic,x1000-pwm" , .data = &x1000_soc_info }, |
266 | {}, |
267 | }; |
268 | MODULE_DEVICE_TABLE(of, jz4740_pwm_dt_ids); |
269 | |
270 | static struct platform_driver jz4740_pwm_driver = { |
271 | .driver = { |
272 | .name = "jz4740-pwm" , |
273 | .of_match_table = jz4740_pwm_dt_ids, |
274 | }, |
275 | .probe = jz4740_pwm_probe, |
276 | }; |
277 | module_platform_driver(jz4740_pwm_driver); |
278 | |
279 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>" ); |
280 | MODULE_DESCRIPTION("Ingenic JZ4740 PWM driver" ); |
281 | MODULE_ALIAS("platform:jz4740-pwm" ); |
282 | MODULE_LICENSE("GPL" ); |
283 | |