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