blob: dc23e32e835c1aeb86837b1f8f9ac36bcf99c620 [file] [log] [blame]
junyi.zhao0cbb4ed2023-02-08 17:32:25 +08001// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2/*
3 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
4 */
5
6#include <common.h>
7#include <dm.h>
8#include <pwm.h>
9#include <regmap.h>
10#include <linux/err.h>
11#include <linux/io.h>
12#include <linux/sizes.h>
13#include <linux/printk.h>
14#include <div64.h>
15
16#include "pwm-meson.h"
17
18struct meson_pwm_priv {
19 struct meson_pwm_reg *regs;
20 struct meson_pwm_state *pwm_state;
21 struct meson_pwm_data *pwm_data;
Qianggui Song0de08922023-07-10 16:10:38 +080022 fdt_addr_t extern_clk_addr;
junyi.zhao0cbb4ed2023-02-08 17:32:25 +080023};
24
25static u64 meson_pwm_clock_get_rate(void)
26{
27 return 24000000;
28}
29
30static int pwm_meson_get_polarity(struct udevice *dev, uint channel)
31{
32 struct meson_pwm_priv *priv = dev_get_priv(dev);
33#ifdef PWM_REG_POLAR
34 struct meson_pwm_reg *regs = priv->regs;
35
36 unsigned int tmp, val;
37
38 switch (channel) {
39 case MESON_PWM0:
40 case MESON_PWM2:
41 val = 0x1 << 26;
42 break;
43
44 case MESON_PWM1:
45 case MESON_PWM3:
46 val = 0x1 << 27;
47 break;
48
49 default:
50 pr_err("Id is invalid\n");
51 return 0;
52 }
53
54 tmp = readl(&regs->miscr);
55 tmp = tmp & val;
56 if (tmp == 0)
57 return 0;
58 else
59 return 1;
60#else
61 struct meson_pwm_state *pwm_state = priv->pwm_state;
62
63 return pwm_state[channel].polarity;
64#endif
65}
66
67static void pwm_constant_enable(struct udevice *dev, uint channel)
68{
69 struct meson_pwm_priv *priv = dev_get_priv(dev);
70 struct meson_pwm_reg *regs = priv->regs;
71
72 switch (channel) {
73 case MESON_PWM0:
74 case MESON_PWM2:
75 setbits_le32(&regs->miscr, 1 << 28);
76 break;
77
78 case MESON_PWM1:
79 case MESON_PWM3:
80 setbits_le32(&regs->miscr, 1 << 29);
81 break;
82
83 default:
84 pr_err("Id is invalid\n");
85 break;
86 }
87}
88
89static void pwm_constant_disable(struct udevice *dev, uint channel)
90{
91 struct meson_pwm_priv *priv = dev_get_priv(dev);
92 struct meson_pwm_reg *regs = priv->regs;
93
94 switch (channel) {
95 case MESON_PWM0:
96 case MESON_PWM2:
97 clrbits_le32(&regs->miscr, 1 << 28);
98 break;
99
100 case MESON_PWM1:
101 case MESON_PWM3:
102 clrbits_le32(&regs->miscr, 1 << 29);
103 break;
104
105 default:
106 pr_err("Id is invalid\n");
107 break;
108 }
109}
110
111static void pwm_meson_config(struct udevice *dev, unsigned int channel)
112{
113 struct meson_pwm_priv *priv = dev_get_priv(dev);
114 struct meson_pwm_reg *regs = priv->regs;
115 struct meson_pwm_state *pwm_state = priv->pwm_state;
116 fdt_addr_t clk_addr = priv->extern_clk_addr;
117
118 switch (channel) {
119 case MESON_PWM0:
120 /*set div and clock enable*/
121 if (priv->pwm_data->extern_clk)
122 clrsetbits_le32(clk_addr,
123 (0xff << 0) | (3 << 9), (pwm_state[channel].pre_div << 0 | 1 << 8));
124 else
125 setbits_le32(&regs->miscr,
126 (pwm_state[channel].pre_div << 8 | 1 << 15));
127 /*set duty*/
128 writel((pwm_state[channel].hi << 16 | pwm_state[channel].lo), &regs->dar);
129 break;
130 case MESON_PWM1:
131 /*set div and clock enable*/
132 if (priv->pwm_data->extern_clk)
133 clrsetbits_le32(clk_addr, (0xff << 16) | (3 << 25),
134 (pwm_state[channel].pre_div << 16 | 1 << 24));
135 else
136 setbits_le32(&regs->miscr,
137 (pwm_state[channel].pre_div << 16 | 1 << 23));
138 /*set duty*/
139 writel((pwm_state[channel].hi << 16 | pwm_state[channel].lo), &regs->dbr);
140 break;
141
142 default:
143 break;
144 }
145}
146
147static void pwm_meson_config_ext(struct udevice *dev, unsigned int channel)
148{
149 struct meson_pwm_priv *priv = dev_get_priv(dev);
150 struct meson_pwm_reg *regs = priv->regs;
151 struct meson_pwm_state *pwm_state = priv->pwm_state;
152
153 switch (channel) {
154 case MESON_PWM2:
155 /*set div and clock enable*/
156 /*setbits_le32(&regs->miscr, (pwm_state[channel].pre_div << 8 | 1 << 15));*/
157 /*set duty*/
158 writel((pwm_state[channel].hi << 16 | pwm_state[channel].lo), &regs->da2r);
159 break;
160
161 case MESON_PWM3:
162 /*set div and clock enable*/
163 /*setbits_le32(&regs->miscr,
164 *(pwm_state[channel].pre_div << 16 | 1 << 23));
165 */
166 /*set duty*/
167 writel((pwm_state[channel].hi << 16 | pwm_state[channel].lo), &regs->db2r);
168 break;
169
170 default:
171 break;
172 }
173}
174
175static int meson_pwm_cacl(struct udevice *dev, uint channel, uint period,
176 uint duty)
177{
178 struct meson_pwm_priv *priv = dev_get_priv(dev);
179 struct meson_pwm_state *pwm_state = priv->pwm_state;
180 unsigned int pre_div, cnt, duty_cnt, inv;
181 unsigned long fin_freq = -1;
182 u64 fin_ps;
183
184 inv = pwm_meson_get_polarity(dev, channel);
185 if (inv)
186 duty = period - duty;
187
188 fin_freq = meson_pwm_clock_get_rate();
189 fin_ps = (u64)NSEC_PER_SEC * 1000;
190 do_div(fin_ps, fin_freq);
191
192 for (pre_div = 0; pre_div < 0x7f; pre_div++) {
193 cnt = DIV_ROUND_CLOSEST_ULL((u64)period * 1000,
194 fin_ps * (pre_div + 1));
195 if (cnt <= 0xffff)
196 break;
197 }
198
199 if (pre_div >= 0x7f) {
200 pr_err("unable to get period pre_div\n");
201 return -EINVAL;
202 }
203
204 if (duty == period) {
205 pwm_state[channel].pre_div = pre_div;
206 pwm_state[channel].hi = cnt;
207 pwm_state[channel].lo = 0;
208 } else if (duty == 0) {
209 pwm_state[channel].pre_div = pre_div;
210 pwm_state[channel].hi = 0;
211 pwm_state[channel].lo = cnt;
212 } else {
213 /* Then check is we can have the duty with the same pre_div */
214 duty_cnt = DIV_ROUND_CLOSEST_ULL((u64)duty * 1000,
215 fin_ps * (pre_div + 1));
216 if (duty_cnt > 0xffff) {
217 pr_err("unable to get duty cycle\n");
218 return -EINVAL;
219 }
220
221 if (duty_cnt == 0)
222 duty_cnt = 1;
223
224 if (cnt == duty_cnt)
225 duty_cnt -= 1;
226
227 pwm_state[channel].pre_div = pre_div;
228 pwm_state[channel].hi = duty_cnt - 1;
229 pwm_state[channel].lo = cnt - duty_cnt - 1;
230 }
231
232 if (duty == period || duty == 0)
233 pwm_constant_enable(dev, channel);
234 else
235 pwm_constant_disable(dev, channel);
236
237 return 0;
238}
239
240static int meson_pwm_set_config(struct udevice *dev, uint channel, uint period_ns,
241 uint duty_ns)
242{
243 struct meson_pwm_priv *priv = dev_get_priv(dev);
244 struct meson_pwm_state *pwm_state = priv->pwm_state;
245
Qianggui Song0de08922023-07-10 16:10:38 +0800246 if (period_ns == 0) {
247 pr_err("period_ns can not be zero\n");
junyi.zhao0cbb4ed2023-02-08 17:32:25 +0800248 return -1;
249 }
250
251 if (duty_ns > period_ns) {
252 pr_err("Not available duty_ns period_ns error\n");
253 return -1;
254 }
255
256 if (pwm_state[channel].period != period_ns ||
257 pwm_state[channel].duty_cycle != duty_ns) {
258 meson_pwm_cacl(dev, channel, period_ns, duty_ns);
259 switch (channel) {
260 case MESON_PWM0:
261 case MESON_PWM1:
262 pwm_meson_config(dev, channel);
263 break;
264
265 case MESON_PWM2:
266 case MESON_PWM3:
267 pwm_meson_config_ext(dev, channel);
268 break;
269
270 default:
271 break;
272 }
273 }
274
275 pwm_state[channel].period = period_ns;
276 pwm_state[channel].duty_cycle = duty_ns;
277
278 return 0;
279};
280
281static void meson_pwm_meson_enable(struct udevice *dev, unsigned int channel)
282{
283 struct meson_pwm_priv *priv = dev_get_priv(dev);
284 struct meson_pwm_reg *regs = priv->regs;
285 struct meson_pwm_state *pwm_state = priv->pwm_state;
286 fdt_addr_t clk_addr = priv->extern_clk_addr;
287 unsigned int val, val_clk, orig;
288
289 switch (channel) {
290 case MESON_PWM0:
291 val = 1 << 0;
292 val_clk = 1 << 8;
293 break;
294 case MESON_PWM1:
295 val = 1 << 1;
296 val_clk = 1 << 24;
297 break;
298 case MESON_PWM2:
299 val = 1 << 25;
300 val_clk = 1 << 8;
301 break;
302 case MESON_PWM3:
303 val = 1 << 24;
304 val_clk = 1 << 24;
305 break;
306 default:
307 pr_err("channel is not legal\n");
308 return;
309 }
310
311 orig = readl(&regs->miscr);
312 orig |= val;
313 writel(orig, &regs->miscr);
314 if (priv->pwm_data->extern_clk) {
315 orig = readl(clk_addr);
316 orig |= val_clk;
317 writel(orig, clk_addr);
318 }
319 pwm_state[channel].enabled = 1;
320}
321
322static void meson_pwm_meson_disable(struct udevice *dev, unsigned int channel)
323{
324 struct meson_pwm_priv *priv = dev_get_priv(dev);
325 struct meson_pwm_reg *regs = priv->regs;
326 struct meson_pwm_state *pwm_state = priv->pwm_state;
327 fdt_addr_t clk_addr = priv->extern_clk_addr;
328 unsigned int val, val_clk, orig;
329
330 switch (channel) {
331 case MESON_PWM0:
332 val = 1 << 0;
333 val_clk = 1 << 8;
334 break;
335 case MESON_PWM1:
336 val = 1 << 1;
337 val_clk = 1 << 24;
338 break;
339 case MESON_PWM2:
340 val = 1 << 25;
341 val_clk = 1 << 8;
342 break;
343 case MESON_PWM3:
344 val = 1 << 24;
345 val_clk = 1 << 24;
346 break;
347 default:
348 pr_err("channel is not legal\n");
349 return;
350 }
351
352 orig = readl(&regs->miscr);
353 orig &= ~val;
354 writel(orig, &regs->miscr);
355 if (priv->pwm_data->extern_clk) {
356 orig = readl(clk_addr);
357 orig &= ~val_clk;
358 writel(orig, clk_addr);
359 }
360 pwm_state[channel].enabled = 0;
361}
362
363static int meson_pwm_set_enable(struct udevice *dev, uint channel, bool enable)
364{
365 struct meson_pwm_priv *priv = dev_get_priv(dev);
366 struct meson_pwm_state *pwm_state = priv->pwm_state;
367
368 if (pwm_state[channel].enabled != enable) {
369 if (enable)
370 meson_pwm_meson_enable(dev, channel);
371 else
372 meson_pwm_meson_disable(dev, channel);
373 }
374
375 return 0;
376}
377
378static int meson_pwm_set_invert(struct udevice *dev, uint channel, bool polarity)
379{
380 struct meson_pwm_priv *priv = dev_get_priv(dev);
381 struct meson_pwm_state *pwm_state = priv->pwm_state;
382#ifdef PWM_REG_INVERT
383 struct meson_pwm_reg *regs = priv->regs;
384
385 switch (channel) {
386 case MESON_PWM0:
387 if (polarity)
388 setbits_le32(&regs->miscr, 0x01 << 26);
389 else
390 clrbits_le32(&regs->miscr, 0x01 << 26);
391 break;
392
393 case MESON_PWM1:
394 if (polarity)
395 setbits_le32(&regs->miscr, 0x01 << 27);
396 else
397 clrbits_le32(&regs->miscr, 0x01 << 27);
398 break;
399
400 default:
401 pr_err("Id is invalid\n");
402 break;
403 }
404#endif
405 if (polarity)
406 pwm_state[channel].polarity = 1;
407 else
408 pwm_state[channel].polarity = 0;
409 return 0;
410};
411
412static int meson_pwm_set_times(struct udevice *dev, uint channel, uint times)
413{
414 struct meson_pwm_priv *priv = dev_get_priv(dev);
415 struct meson_pwm_reg *regs = priv->regs;
416
417 if (times > 256 || times <= 0) {
418 pr_err("Not available times error\n");
419 return -1;
420 }
421
422 switch (channel) {
423 case MESON_PWM0:
424 clrbits_le32(&regs->tr, 0xff << 24);
425 setbits_le32(&regs->tr, (times - 1) << 24);
426 break;
427
428 case MESON_PWM1:
429 clrbits_le32(&regs->tr, 0xff << 8);
430 setbits_le32(&regs->tr, (times - 1) << 8);
431 break;
432
433 case MESON_PWM2:
434 clrbits_le32(&regs->tr, 0xff << 16);
435 setbits_le32(&regs->tr, (times - 1) << 16);
436 break;
437
438 case MESON_PWM3:
439 clrbits_le32(&regs->tr, 0xff << 0);
440 setbits_le32(&regs->tr, (times - 1) << 0);
441 break;
442
443 default:
444 pr_err("Id is invalid\n");
445 break;
446 }
447
448 return 0;
449};
450
451static int meson_pwm_set_blink_times(struct udevice *dev, uint channel, uint times)
452{
453 struct meson_pwm_priv *priv = dev_get_priv(dev);
454 struct meson_pwm_reg *regs = priv->regs;
455
456 if (times > 16 || times <= 0) {
457 pr_err("Not available times error\n");
458 return -1;
459 }
460
461 switch (channel) {
462 case MESON_PWM0:
463 case MESON_PWM2:
464 clrbits_le32(&regs->br, 0xf);
465 setbits_le32(&regs->br, times - 1);
466 break;
467
468 case MESON_PWM1:
469 case MESON_PWM3:
470 clrbits_le32(&regs->br, 0xf << 4);
471 setbits_le32(&regs->br, (times - 1) << 4);
472 break;
473
474 default:
475 pr_err("Id is invalid\n");
476 break;
477 }
478
479 return 0;
480};
481
482static int meson_pwm_blink_enable(struct udevice *dev, uint channel, bool enable)
483{
484 struct meson_pwm_priv *priv = dev_get_priv(dev);
485 struct meson_pwm_reg *regs = priv->regs;
486
487 switch (channel) {
488 case MESON_PWM0:
489 case MESON_PWM2:
490 if (enable)
491 setbits_le32(&regs->br, 1 << 8);
492 else
493 clrbits_le32(&regs->br, 1 << 8);
494 break;
495
496 case MESON_PWM1:
497 case MESON_PWM3:
498 if (enable)
499 setbits_le32(&regs->br, 1 << 9);
500 else
501 clrbits_le32(&regs->br, 1 << 9);
502 break;
503
504 default:
505 pr_err("Id is invalid\n");
506 break;
507 }
508
509 return 0;
510};
511
512static int meson_pwm_probe(struct udevice *dev)
513{
514 struct meson_pwm_priv *priv = dev_get_priv(dev);
515
516 priv->pwm_data = (struct meson_pwm_data *)dev_get_driver_data(dev);
517 priv->regs = (struct meson_pwm_reg *)dev_read_addr_index(dev, 0);
518 if (priv->regs == (void *)FDT_ADDR_T_NONE) {
519 pr_err("Coun't get pwm base regs addr\n");
520 return -1;
521 }
522
523 /* If you use external clk, get clk regs addr */
524 if (priv->pwm_data->extern_clk) {
525 priv->extern_clk_addr = dev_read_addr_index(dev, 1);
526 if (priv->extern_clk_addr == FDT_ADDR_T_NONE) {
527 pr_err("Coun't get pwm clk regs addr\n");
528 return -1;
529 }
530 }
531
532 priv->pwm_state = (struct meson_pwm_state *)calloc(4, sizeof(struct meson_pwm_state));
533
534 return 0;
535}
536
537int meson_pwm_remove(struct udevice *dev)
538{
539 struct meson_pwm_priv *priv = dev_get_priv(dev);
540
541 free(priv->pwm_state);
542
543 return 0;
544}
545
546static const struct meson_pwm_data pwm_meson_g12a_data = {
547 .extern_clk = 0,
548};
549
550static const struct meson_pwm_data pwm_meson_v2_data = {
551 .extern_clk = 1,
552};
553
554static const struct pwm_ops meson_pwm_ops = {
555 .set_config = meson_pwm_set_config,
556 .set_enable = meson_pwm_set_enable,
557 .set_invert = meson_pwm_set_invert,
558 .set_times = meson_pwm_set_times,
559 .set_blink_times = meson_pwm_set_blink_times,
560 .set_blink_enable = meson_pwm_blink_enable,
561};
562
563static const struct udevice_id meson_pwm_ids[] = {
564 {.compatible = "amlogic,g12a-ee-pwm", .data = (long)&pwm_meson_g12a_data},
565 {.compatible = "amlogic,g12a-ao-pwm", .data = (long)&pwm_meson_g12a_data},
566 {.compatible = "amlogic,meson-v2-pwm", .data = (long)&pwm_meson_v2_data},
567 {}
568};
569
570U_BOOT_DRIVER(meson_pwm) = {
571 .name = "meson_pwm",
572 .id = UCLASS_PWM,
573 .of_match = meson_pwm_ids,
574 .ops = &meson_pwm_ops,
575 .probe = meson_pwm_probe,
576 .remove = meson_pwm_remove,
577 .priv_auto = sizeof(struct meson_pwm_priv),
578};