Commit | Line | Data |
---|---|---|
738a1cfe AH |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright 2018-2019 NXP. | |
4 | * | |
5 | * Limitations: | |
6 | * - The TPM counter and period counter are shared between | |
7 | * multiple channels, so all channels should use same period | |
8 | * settings. | |
9 | * - Changes to polarity cannot be latched at the time of the | |
10 | * next period start. | |
11 | * - Changing period and duty cycle together isn't atomic, | |
12 | * with the wrong timing it might happen that a period is | |
13 | * produced with old duty cycle but new period settings. | |
14 | */ | |
15 | ||
16 | #include <linux/bitfield.h> | |
17 | #include <linux/bitops.h> | |
18 | #include <linux/clk.h> | |
19 | #include <linux/err.h> | |
20 | #include <linux/io.h> | |
21 | #include <linux/log2.h> | |
22 | #include <linux/module.h> | |
23 | #include <linux/of.h> | |
24 | #include <linux/of_address.h> | |
25 | #include <linux/platform_device.h> | |
26 | #include <linux/pwm.h> | |
27 | #include <linux/slab.h> | |
28 | ||
29 | #define PWM_IMX_TPM_PARAM 0x4 | |
30 | #define PWM_IMX_TPM_GLOBAL 0x8 | |
31 | #define PWM_IMX_TPM_SC 0x10 | |
32 | #define PWM_IMX_TPM_CNT 0x14 | |
33 | #define PWM_IMX_TPM_MOD 0x18 | |
34 | #define PWM_IMX_TPM_CnSC(n) (0x20 + (n) * 0x8) | |
35 | #define PWM_IMX_TPM_CnV(n) (0x24 + (n) * 0x8) | |
36 | ||
37 | #define PWM_IMX_TPM_PARAM_CHAN GENMASK(7, 0) | |
38 | ||
39 | #define PWM_IMX_TPM_SC_PS GENMASK(2, 0) | |
40 | #define PWM_IMX_TPM_SC_CMOD GENMASK(4, 3) | |
41 | #define PWM_IMX_TPM_SC_CMOD_INC_EVERY_CLK FIELD_PREP(PWM_IMX_TPM_SC_CMOD, 1) | |
42 | #define PWM_IMX_TPM_SC_CPWMS BIT(5) | |
43 | ||
44 | #define PWM_IMX_TPM_CnSC_CHF BIT(7) | |
45 | #define PWM_IMX_TPM_CnSC_MSB BIT(5) | |
46 | #define PWM_IMX_TPM_CnSC_MSA BIT(4) | |
47 | ||
48 | /* | |
49 | * The reference manual describes this field as two separate bits. The | |
50 | * semantic of the two bits isn't orthogonal though, so they are treated | |
51 | * together as a 2-bit field here. | |
52 | */ | |
53 | #define PWM_IMX_TPM_CnSC_ELS GENMASK(3, 2) | |
54 | #define PWM_IMX_TPM_CnSC_ELS_INVERSED FIELD_PREP(PWM_IMX_TPM_CnSC_ELS, 1) | |
55 | #define PWM_IMX_TPM_CnSC_ELS_NORMAL FIELD_PREP(PWM_IMX_TPM_CnSC_ELS, 2) | |
56 | ||
57 | ||
58 | #define PWM_IMX_TPM_MOD_WIDTH 16 | |
59 | #define PWM_IMX_TPM_MOD_MOD GENMASK(PWM_IMX_TPM_MOD_WIDTH - 1, 0) | |
60 | ||
61 | struct imx_tpm_pwm_chip { | |
62 | struct pwm_chip chip; | |
63 | struct clk *clk; | |
64 | void __iomem *base; | |
65 | struct mutex lock; | |
66 | u32 user_count; | |
67 | u32 enable_count; | |
68 | u32 real_period; | |
69 | }; | |
70 | ||
71 | struct imx_tpm_pwm_param { | |
72 | u8 prescale; | |
73 | u32 mod; | |
74 | u32 val; | |
75 | }; | |
76 | ||
77 | static inline struct imx_tpm_pwm_chip * | |
78 | to_imx_tpm_pwm_chip(struct pwm_chip *chip) | |
79 | { | |
80 | return container_of(chip, struct imx_tpm_pwm_chip, chip); | |
81 | } | |
82 | ||
83 | /* | |
84 | * This function determines for a given pwm_state *state that a consumer | |
85 | * might request the pwm_state *real_state that eventually is implemented | |
86 | * by the hardware and the necessary register values (in *p) to achieve | |
87 | * this. | |
88 | */ | |
89 | static int pwm_imx_tpm_round_state(struct pwm_chip *chip, | |
90 | struct imx_tpm_pwm_param *p, | |
91 | struct pwm_state *real_state, | |
71523d18 | 92 | const struct pwm_state *state) |
738a1cfe AH |
93 | { |
94 | struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); | |
95 | u32 rate, prescale, period_count, clock_unit; | |
96 | u64 tmp; | |
97 | ||
98 | rate = clk_get_rate(tpm->clk); | |
99 | tmp = (u64)state->period * rate; | |
100 | clock_unit = DIV_ROUND_CLOSEST_ULL(tmp, NSEC_PER_SEC); | |
101 | if (clock_unit <= PWM_IMX_TPM_MOD_MOD) | |
102 | prescale = 0; | |
103 | else | |
104 | prescale = ilog2(clock_unit) + 1 - PWM_IMX_TPM_MOD_WIDTH; | |
105 | ||
106 | if ((!FIELD_FIT(PWM_IMX_TPM_SC_PS, prescale))) | |
107 | return -ERANGE; | |
108 | p->prescale = prescale; | |
109 | ||
110 | period_count = (clock_unit + ((1 << prescale) >> 1)) >> prescale; | |
111 | p->mod = period_count; | |
112 | ||
113 | /* calculate real period HW can support */ | |
114 | tmp = (u64)period_count << prescale; | |
115 | tmp *= NSEC_PER_SEC; | |
116 | real_state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate); | |
117 | ||
118 | /* | |
119 | * if eventually the PWM output is inactive, either | |
120 | * duty cycle is 0 or status is disabled, need to | |
121 | * make sure the output pin is inactive. | |
122 | */ | |
123 | if (!state->enabled) | |
124 | real_state->duty_cycle = 0; | |
125 | else | |
126 | real_state->duty_cycle = state->duty_cycle; | |
127 | ||
128 | tmp = (u64)p->mod * real_state->duty_cycle; | |
129 | p->val = DIV_ROUND_CLOSEST_ULL(tmp, real_state->period); | |
130 | ||
131 | real_state->polarity = state->polarity; | |
132 | real_state->enabled = state->enabled; | |
133 | ||
134 | return 0; | |
135 | } | |
136 | ||
137 | static void pwm_imx_tpm_get_state(struct pwm_chip *chip, | |
138 | struct pwm_device *pwm, | |
139 | struct pwm_state *state) | |
140 | { | |
141 | struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); | |
142 | u32 rate, val, prescale; | |
143 | u64 tmp; | |
144 | ||
145 | /* get period */ | |
146 | state->period = tpm->real_period; | |
147 | ||
148 | /* get duty cycle */ | |
149 | rate = clk_get_rate(tpm->clk); | |
150 | val = readl(tpm->base + PWM_IMX_TPM_SC); | |
151 | prescale = FIELD_GET(PWM_IMX_TPM_SC_PS, val); | |
152 | tmp = readl(tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm)); | |
153 | tmp = (tmp << prescale) * NSEC_PER_SEC; | |
154 | state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate); | |
155 | ||
156 | /* get polarity */ | |
157 | val = readl(tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm)); | |
158 | if ((val & PWM_IMX_TPM_CnSC_ELS) == PWM_IMX_TPM_CnSC_ELS_INVERSED) | |
159 | state->polarity = PWM_POLARITY_INVERSED; | |
160 | else | |
161 | /* | |
162 | * Assume reserved values (2b00 and 2b11) to yield | |
163 | * normal polarity. | |
164 | */ | |
165 | state->polarity = PWM_POLARITY_NORMAL; | |
166 | ||
167 | /* get channel status */ | |
168 | state->enabled = FIELD_GET(PWM_IMX_TPM_CnSC_ELS, val) ? true : false; | |
169 | } | |
170 | ||
171 | /* this function is supposed to be called with mutex hold */ | |
172 | static int pwm_imx_tpm_apply_hw(struct pwm_chip *chip, | |
173 | struct imx_tpm_pwm_param *p, | |
174 | struct pwm_state *state, | |
175 | struct pwm_device *pwm) | |
176 | { | |
177 | struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); | |
178 | bool period_update = false; | |
179 | bool duty_update = false; | |
180 | u32 val, cmod, cur_prescale; | |
181 | unsigned long timeout; | |
182 | struct pwm_state c; | |
183 | ||
184 | if (state->period != tpm->real_period) { | |
185 | /* | |
186 | * TPM counter is shared by multiple channels, so | |
187 | * prescale and period can NOT be modified when | |
188 | * there are multiple channels in use with different | |
189 | * period settings. | |
190 | */ | |
191 | if (tpm->user_count > 1) | |
192 | return -EBUSY; | |
193 | ||
194 | val = readl(tpm->base + PWM_IMX_TPM_SC); | |
195 | cmod = FIELD_GET(PWM_IMX_TPM_SC_CMOD, val); | |
196 | cur_prescale = FIELD_GET(PWM_IMX_TPM_SC_PS, val); | |
197 | if (cmod && cur_prescale != p->prescale) | |
198 | return -EBUSY; | |
199 | ||
200 | /* set TPM counter prescale */ | |
201 | val &= ~PWM_IMX_TPM_SC_PS; | |
202 | val |= FIELD_PREP(PWM_IMX_TPM_SC_PS, p->prescale); | |
203 | writel(val, tpm->base + PWM_IMX_TPM_SC); | |
204 | ||
205 | /* | |
206 | * set period count: | |
207 | * if the PWM is disabled (CMOD[1:0] = 2b00), then MOD register | |
208 | * is updated when MOD register is written. | |
209 | * | |
210 | * if the PWM is enabled (CMOD[1:0] ≠ 2b00), the period length | |
211 | * is latched into hardware when the next period starts. | |
212 | */ | |
213 | writel(p->mod, tpm->base + PWM_IMX_TPM_MOD); | |
214 | tpm->real_period = state->period; | |
215 | period_update = true; | |
216 | } | |
217 | ||
218 | pwm_imx_tpm_get_state(chip, pwm, &c); | |
219 | ||
220 | /* polarity is NOT allowed to be changed if PWM is active */ | |
221 | if (c.enabled && c.polarity != state->polarity) | |
222 | return -EBUSY; | |
223 | ||
224 | if (state->duty_cycle != c.duty_cycle) { | |
225 | /* | |
226 | * set channel value: | |
227 | * if the PWM is disabled (CMOD[1:0] = 2b00), then CnV register | |
228 | * is updated when CnV register is written. | |
229 | * | |
230 | * if the PWM is enabled (CMOD[1:0] ≠ 2b00), the duty length | |
231 | * is latched into hardware when the next period starts. | |
232 | */ | |
233 | writel(p->val, tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm)); | |
234 | duty_update = true; | |
235 | } | |
236 | ||
237 | /* make sure MOD & CnV registers are updated */ | |
238 | if (period_update || duty_update) { | |
239 | timeout = jiffies + msecs_to_jiffies(tpm->real_period / | |
240 | NSEC_PER_MSEC + 1); | |
241 | while (readl(tpm->base + PWM_IMX_TPM_MOD) != p->mod | |
242 | || readl(tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm)) | |
243 | != p->val) { | |
244 | if (time_after(jiffies, timeout)) | |
245 | return -ETIME; | |
246 | cpu_relax(); | |
247 | } | |
248 | } | |
249 | ||
250 | /* | |
251 | * polarity settings will enabled/disable output status | |
252 | * immediately, so if the channel is disabled, need to | |
253 | * make sure MSA/MSB/ELS are set to 0 which means channel | |
254 | * disabled. | |
255 | */ | |
256 | val = readl(tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm)); | |
257 | val &= ~(PWM_IMX_TPM_CnSC_ELS | PWM_IMX_TPM_CnSC_MSA | | |
258 | PWM_IMX_TPM_CnSC_MSB); | |
259 | if (state->enabled) { | |
260 | /* | |
261 | * set polarity (for edge-aligned PWM modes) | |
262 | * | |
263 | * ELS[1:0] = 2b10 yields normal polarity behaviour, | |
264 | * ELS[1:0] = 2b01 yields inversed polarity. | |
265 | * The other values are reserved. | |
266 | */ | |
267 | val |= PWM_IMX_TPM_CnSC_MSB; | |
268 | val |= (state->polarity == PWM_POLARITY_NORMAL) ? | |
269 | PWM_IMX_TPM_CnSC_ELS_NORMAL : | |
270 | PWM_IMX_TPM_CnSC_ELS_INVERSED; | |
271 | } | |
272 | writel(val, tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm)); | |
273 | ||
274 | /* control the counter status */ | |
275 | if (state->enabled != c.enabled) { | |
276 | val = readl(tpm->base + PWM_IMX_TPM_SC); | |
277 | if (state->enabled) { | |
278 | if (++tpm->enable_count == 1) | |
279 | val |= PWM_IMX_TPM_SC_CMOD_INC_EVERY_CLK; | |
280 | } else { | |
281 | if (--tpm->enable_count == 0) | |
282 | val &= ~PWM_IMX_TPM_SC_CMOD; | |
283 | } | |
284 | writel(val, tpm->base + PWM_IMX_TPM_SC); | |
285 | } | |
286 | ||
287 | return 0; | |
288 | } | |
289 | ||
290 | static int pwm_imx_tpm_apply(struct pwm_chip *chip, | |
291 | struct pwm_device *pwm, | |
71523d18 | 292 | const struct pwm_state *state) |
738a1cfe AH |
293 | { |
294 | struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); | |
295 | struct imx_tpm_pwm_param param; | |
296 | struct pwm_state real_state; | |
297 | int ret; | |
298 | ||
299 | ret = pwm_imx_tpm_round_state(chip, ¶m, &real_state, state); | |
300 | if (ret) | |
301 | return ret; | |
302 | ||
303 | mutex_lock(&tpm->lock); | |
304 | ret = pwm_imx_tpm_apply_hw(chip, ¶m, &real_state, pwm); | |
305 | mutex_unlock(&tpm->lock); | |
306 | ||
307 | return ret; | |
308 | } | |
309 | ||
310 | static int pwm_imx_tpm_request(struct pwm_chip *chip, struct pwm_device *pwm) | |
311 | { | |
312 | struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); | |
313 | ||
314 | mutex_lock(&tpm->lock); | |
315 | tpm->user_count++; | |
316 | mutex_unlock(&tpm->lock); | |
317 | ||
318 | return 0; | |
319 | } | |
320 | ||
321 | static void pwm_imx_tpm_free(struct pwm_chip *chip, struct pwm_device *pwm) | |
322 | { | |
323 | struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); | |
324 | ||
325 | mutex_lock(&tpm->lock); | |
326 | tpm->user_count--; | |
327 | mutex_unlock(&tpm->lock); | |
328 | } | |
329 | ||
330 | static const struct pwm_ops imx_tpm_pwm_ops = { | |
331 | .request = pwm_imx_tpm_request, | |
332 | .free = pwm_imx_tpm_free, | |
333 | .get_state = pwm_imx_tpm_get_state, | |
334 | .apply = pwm_imx_tpm_apply, | |
335 | .owner = THIS_MODULE, | |
336 | }; | |
337 | ||
338 | static int pwm_imx_tpm_probe(struct platform_device *pdev) | |
339 | { | |
340 | struct imx_tpm_pwm_chip *tpm; | |
341 | int ret; | |
342 | u32 val; | |
343 | ||
344 | tpm = devm_kzalloc(&pdev->dev, sizeof(*tpm), GFP_KERNEL); | |
345 | if (!tpm) | |
346 | return -ENOMEM; | |
347 | ||
348 | platform_set_drvdata(pdev, tpm); | |
349 | ||
350 | tpm->base = devm_platform_ioremap_resource(pdev, 0); | |
351 | if (IS_ERR(tpm->base)) | |
352 | return PTR_ERR(tpm->base); | |
353 | ||
354 | tpm->clk = devm_clk_get(&pdev->dev, NULL); | |
355 | if (IS_ERR(tpm->clk)) { | |
356 | ret = PTR_ERR(tpm->clk); | |
357 | if (ret != -EPROBE_DEFER) | |
358 | dev_err(&pdev->dev, | |
359 | "failed to get PWM clock: %d\n", ret); | |
360 | return ret; | |
361 | } | |
362 | ||
363 | ret = clk_prepare_enable(tpm->clk); | |
364 | if (ret) { | |
365 | dev_err(&pdev->dev, | |
366 | "failed to prepare or enable clock: %d\n", ret); | |
367 | return ret; | |
368 | } | |
369 | ||
370 | tpm->chip.dev = &pdev->dev; | |
371 | tpm->chip.ops = &imx_tpm_pwm_ops; | |
372 | tpm->chip.base = -1; | |
373 | tpm->chip.of_xlate = of_pwm_xlate_with_flags; | |
374 | tpm->chip.of_pwm_n_cells = 3; | |
375 | ||
376 | /* get number of channels */ | |
377 | val = readl(tpm->base + PWM_IMX_TPM_PARAM); | |
378 | tpm->chip.npwm = FIELD_GET(PWM_IMX_TPM_PARAM_CHAN, val); | |
379 | ||
380 | mutex_init(&tpm->lock); | |
381 | ||
382 | ret = pwmchip_add(&tpm->chip); | |
383 | if (ret) { | |
384 | dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); | |
385 | clk_disable_unprepare(tpm->clk); | |
386 | } | |
387 | ||
388 | return ret; | |
389 | } | |
390 | ||
391 | static int pwm_imx_tpm_remove(struct platform_device *pdev) | |
392 | { | |
393 | struct imx_tpm_pwm_chip *tpm = platform_get_drvdata(pdev); | |
394 | int ret = pwmchip_remove(&tpm->chip); | |
395 | ||
396 | clk_disable_unprepare(tpm->clk); | |
397 | ||
398 | return ret; | |
399 | } | |
400 | ||
401 | static int __maybe_unused pwm_imx_tpm_suspend(struct device *dev) | |
402 | { | |
403 | struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev); | |
404 | ||
405 | if (tpm->enable_count > 0) | |
406 | return -EBUSY; | |
407 | ||
408 | clk_disable_unprepare(tpm->clk); | |
409 | ||
410 | return 0; | |
411 | } | |
412 | ||
413 | static int __maybe_unused pwm_imx_tpm_resume(struct device *dev) | |
414 | { | |
415 | struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev); | |
416 | int ret = 0; | |
417 | ||
418 | ret = clk_prepare_enable(tpm->clk); | |
419 | if (ret) | |
420 | dev_err(dev, | |
421 | "failed to prepare or enable clock: %d\n", | |
422 | ret); | |
423 | ||
424 | return ret; | |
425 | } | |
426 | ||
427 | static SIMPLE_DEV_PM_OPS(imx_tpm_pwm_pm, | |
428 | pwm_imx_tpm_suspend, pwm_imx_tpm_resume); | |
429 | ||
430 | static const struct of_device_id imx_tpm_pwm_dt_ids[] = { | |
431 | { .compatible = "fsl,imx7ulp-pwm", }, | |
432 | { /* sentinel */ } | |
433 | }; | |
434 | MODULE_DEVICE_TABLE(of, imx_tpm_pwm_dt_ids); | |
435 | ||
436 | static struct platform_driver imx_tpm_pwm_driver = { | |
437 | .driver = { | |
438 | .name = "imx7ulp-tpm-pwm", | |
439 | .of_match_table = imx_tpm_pwm_dt_ids, | |
440 | .pm = &imx_tpm_pwm_pm, | |
441 | }, | |
442 | .probe = pwm_imx_tpm_probe, | |
443 | .remove = pwm_imx_tpm_remove, | |
444 | }; | |
445 | module_platform_driver(imx_tpm_pwm_driver); | |
446 | ||
447 | MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>"); | |
448 | MODULE_DESCRIPTION("i.MX TPM PWM Driver"); | |
449 | MODULE_LICENSE("GPL v2"); |