1// SPDX-License-Identifier: GPL-2.0
2/*
3 * MediaTek Pulse Width Modulator driver
4 *
5 * Copyright (C) 2015 John Crispin <blogic@openwrt.org>
6 * Copyright (C) 2017 Zhi Mao <zhi.mao@mediatek.com>
7 *
8 */
9
10#include <linux/bitfield.h>
11#include <linux/err.h>
12#include <linux/io.h>
13#include <linux/ioport.h>
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/clk.h>
17#include <linux/of.h>
18#include <linux/platform_device.h>
19#include <linux/pwm.h>
20#include <linux/slab.h>
21#include <linux/types.h>
22
23/* PWM registers and bits definitions */
24#define PWMCON 0x00
25#define PWMCON_CLKDIV GENMASK(2, 0)
26#define PWMHDUR 0x04
27#define PWMLDUR 0x08
28#define PWMGDUR 0x0c
29#define PWMWAVENUM 0x28
30#define PWMDWIDTH 0x2c
31#define PWMDWIDTH_PERIOD GENMASK(12, 0)
32#define PWM45DWIDTH_FIXUP 0x30
33#define PWMTHRES 0x30
34#define PWMTHRES_DUTY GENMASK(12, 0)
35#define PWM45THRES_FIXUP 0x34
36#define PWM_CK_26M_SEL_V3 0x74
37#define PWM_CK_26M_SEL 0x210
38
39struct pwm_mediatek_of_data {
40 unsigned int num_pwms;
41 bool pwm45_fixup;
42 u16 pwm_ck_26m_sel_reg;
43 unsigned int chanreg_base;
44 unsigned int chanreg_width;
45};
46
47/**
48 * struct pwm_mediatek_chip - struct representing PWM chip
49 * @regs: base address of PWM chip
50 * @clk_top: the top clock generator
51 * @clk_main: the clock used by PWM core
52 * @soc: pointer to chip's platform data
53 * @clk_pwms: the clock and clkrate used by each PWM channel
54 */
55struct pwm_mediatek_chip {
56 void __iomem *regs;
57 struct clk *clk_top;
58 struct clk *clk_main;
59 const struct pwm_mediatek_of_data *soc;
60 struct {
61 struct clk *clk;
62 unsigned long rate;
63 } clk_pwms[];
64};
65
66static inline struct pwm_mediatek_chip *
67to_pwm_mediatek_chip(struct pwm_chip *chip)
68{
69 return pwmchip_get_drvdata(chip);
70}
71
72static int pwm_mediatek_clk_enable(struct pwm_mediatek_chip *pc,
73 unsigned int hwpwm)
74{
75 int ret;
76
77 ret = clk_prepare_enable(clk: pc->clk_top);
78 if (ret < 0)
79 return ret;
80
81 ret = clk_prepare_enable(clk: pc->clk_main);
82 if (ret < 0)
83 goto disable_clk_top;
84
85 ret = clk_prepare_enable(clk: pc->clk_pwms[hwpwm].clk);
86 if (ret < 0)
87 goto disable_clk_main;
88
89 if (!pc->clk_pwms[hwpwm].rate) {
90 pc->clk_pwms[hwpwm].rate = clk_get_rate(clk: pc->clk_pwms[hwpwm].clk);
91
92 /*
93 * With the clk running with not more than 1 GHz the
94 * calculations in .apply() won't overflow.
95 */
96 if (!pc->clk_pwms[hwpwm].rate ||
97 pc->clk_pwms[hwpwm].rate > 1000000000) {
98 ret = -EINVAL;
99 goto disable_clk_hwpwm;
100 }
101 }
102
103 return 0;
104
105disable_clk_hwpwm:
106 clk_disable_unprepare(clk: pc->clk_pwms[hwpwm].clk);
107disable_clk_main:
108 clk_disable_unprepare(clk: pc->clk_main);
109disable_clk_top:
110 clk_disable_unprepare(clk: pc->clk_top);
111
112 return ret;
113}
114
115static void pwm_mediatek_clk_disable(struct pwm_mediatek_chip *pc,
116 unsigned int hwpwm)
117{
118 clk_disable_unprepare(clk: pc->clk_pwms[hwpwm].clk);
119 clk_disable_unprepare(clk: pc->clk_main);
120 clk_disable_unprepare(clk: pc->clk_top);
121}
122
123static inline void pwm_mediatek_writel(struct pwm_mediatek_chip *chip,
124 unsigned int num, unsigned int offset,
125 u32 value)
126{
127 writel(val: value, addr: chip->regs + chip->soc->chanreg_base +
128 num * chip->soc->chanreg_width + offset);
129}
130
131static inline u32 pwm_mediatek_readl(struct pwm_mediatek_chip *chip,
132 unsigned int num, unsigned int offset)
133{
134 return readl(addr: chip->regs + chip->soc->chanreg_base +
135 num * chip->soc->chanreg_width + offset);
136}
137
138struct pwm_mediatek_waveform {
139 u32 enable;
140 u32 con;
141 u32 width;
142 u32 thres;
143};
144
145static int pwm_mediatek_round_waveform_tohw(struct pwm_chip *chip, struct pwm_device *pwm,
146 const struct pwm_waveform *wf, void *_wfhw)
147{
148 struct pwm_mediatek_waveform *wfhw = _wfhw;
149 struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip);
150 u32 clkdiv, enable;
151 u64 cnt_period, cnt_duty;
152 unsigned long clk_rate;
153 int ret = 0;
154
155 if (wf->period_length_ns == 0) {
156 *wfhw = (typeof(*wfhw)){
157 .enable = 0,
158 };
159
160 return 0;
161 }
162
163 if (!pc->clk_pwms[pwm->hwpwm].rate) {
164 struct clk *clk = pc->clk_pwms[pwm->hwpwm].clk;
165
166 ret = clk_prepare_enable(clk);
167 if (ret)
168 return ret;
169
170 pc->clk_pwms[pwm->hwpwm].rate = clk_get_rate(clk);
171
172 clk_disable_unprepare(clk);
173 }
174
175 clk_rate = pc->clk_pwms[pwm->hwpwm].rate;
176 if (clk_rate == 0 || clk_rate > 1000000000)
177 return -EINVAL;
178
179 cnt_period = mul_u64_u64_div_u64(wf->period_length_ns, clk_rate, NSEC_PER_SEC);
180 if (cnt_period == 0) {
181 cnt_period = 1;
182 ret = 1;
183 }
184
185 if (cnt_period > FIELD_MAX(PWMDWIDTH_PERIOD) + 1) {
186 if (cnt_period >= ((FIELD_MAX(PWMDWIDTH_PERIOD) + 1) << FIELD_MAX(PWMCON_CLKDIV))) {
187 clkdiv = FIELD_MAX(PWMCON_CLKDIV);
188 cnt_period = FIELD_MAX(PWMDWIDTH_PERIOD) + 1;
189 } else {
190 clkdiv = ilog2(cnt_period) - ilog2(FIELD_MAX(PWMDWIDTH_PERIOD));
191 cnt_period >>= clkdiv;
192 }
193 } else {
194 clkdiv = 0;
195 }
196
197 cnt_duty = mul_u64_u64_div_u64(wf->duty_length_ns, clk_rate, NSEC_PER_SEC) >> clkdiv;
198 if (cnt_duty > cnt_period)
199 cnt_duty = cnt_period;
200
201 if (cnt_duty) {
202 cnt_duty -= 1;
203 enable = BIT(pwm->hwpwm);
204 } else {
205 enable = 0;
206 }
207
208 cnt_period -= 1;
209
210 dev_dbg(&chip->dev, "pwm#%u: %lld/%lld @%lu -> ENABLE: %x, CON: %x, PERIOD: %llx, DUTY: %llx\n",
211 pwm->hwpwm, wf->duty_length_ns, wf->period_length_ns, clk_rate,
212 enable, clkdiv, cnt_period, cnt_duty);
213
214 *wfhw = (typeof(*wfhw)){
215 .enable = enable,
216 .con = clkdiv,
217 .width = cnt_period,
218 .thres = cnt_duty,
219 };
220
221 return ret;
222}
223
224static int pwm_mediatek_round_waveform_fromhw(struct pwm_chip *chip, struct pwm_device *pwm,
225 const void *_wfhw, struct pwm_waveform *wf)
226{
227 const struct pwm_mediatek_waveform *wfhw = _wfhw;
228 struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip);
229 u32 clkdiv, cnt_period, cnt_duty;
230 unsigned long clk_rate;
231
232 /*
233 * When _wfhw was populated, the clock was on, so .rate is
234 * already set appropriately.
235 */
236 clk_rate = pc->clk_pwms[pwm->hwpwm].rate;
237
238 if (wfhw->enable) {
239 clkdiv = FIELD_GET(PWMCON_CLKDIV, wfhw->con);
240 cnt_period = FIELD_GET(PWMDWIDTH_PERIOD, wfhw->width);
241 cnt_duty = FIELD_GET(PWMTHRES_DUTY, wfhw->thres);
242
243 /*
244 * cnt_period is a 13 bit value, NSEC_PER_SEC is 30 bits wide
245 * and clkdiv is less than 8, so the multiplication doesn't
246 * overflow an u64.
247 */
248 *wf = (typeof(*wf)){
249 .period_length_ns =
250 DIV_ROUND_UP_ULL((u64)(cnt_period + 1) * NSEC_PER_SEC << clkdiv, clk_rate),
251 .duty_length_ns =
252 DIV_ROUND_UP_ULL((u64)(cnt_duty + 1) * NSEC_PER_SEC << clkdiv, clk_rate),
253 };
254 } else {
255 clkdiv = 0;
256 cnt_period = 0;
257 cnt_duty = 0;
258
259 /*
260 * .enable = 0 is also used for too small duty_cycle values, so
261 * report the HW as being enabled to communicate the minimal
262 * period.
263 */
264 *wf = (typeof(*wf)){
265 .period_length_ns =
266 DIV_ROUND_UP_ULL(NSEC_PER_SEC, clk_rate),
267 .duty_length_ns = 0,
268 };
269 }
270
271 dev_dbg(&chip->dev, "pwm#%u: ENABLE: %x, CLKDIV: %x, PERIOD: %x, DUTY: %x @%lu -> %lld/%lld\n",
272 pwm->hwpwm, wfhw->enable, clkdiv, cnt_period, cnt_duty, clk_rate,
273 wf->duty_length_ns, wf->period_length_ns);
274
275 return 0;
276}
277
278static int pwm_mediatek_read_waveform(struct pwm_chip *chip,
279 struct pwm_device *pwm, void *_wfhw)
280{
281 struct pwm_mediatek_waveform *wfhw = _wfhw;
282 struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip);
283 u32 enable, clkdiv, cnt_period, cnt_duty;
284 u32 reg_width = PWMDWIDTH, reg_thres = PWMTHRES;
285 int ret;
286
287 ret = pwm_mediatek_clk_enable(pc, hwpwm: pwm->hwpwm);
288 if (ret < 0)
289 return ret;
290
291 enable = readl(addr: pc->regs) & BIT(pwm->hwpwm);
292
293 if (enable) {
294 if (pc->soc->pwm45_fixup && pwm->hwpwm > 2) {
295 /*
296 * PWM[4,5] has distinct offset for PWMDWIDTH and PWMTHRES
297 * from the other PWMs on MT7623.
298 */
299 reg_width = PWM45DWIDTH_FIXUP;
300 reg_thres = PWM45THRES_FIXUP;
301 }
302
303 clkdiv = FIELD_GET(PWMCON_CLKDIV, pwm_mediatek_readl(pc, pwm->hwpwm, PWMCON));
304 cnt_period = FIELD_GET(PWMDWIDTH_PERIOD, pwm_mediatek_readl(pc, pwm->hwpwm, reg_width));
305 cnt_duty = FIELD_GET(PWMTHRES_DUTY, pwm_mediatek_readl(pc, pwm->hwpwm, reg_thres));
306
307 *wfhw = (typeof(*wfhw)){
308 .enable = enable,
309 .con = BIT(15) | clkdiv,
310 .width = cnt_period,
311 .thres = cnt_duty,
312 };
313 } else {
314 *wfhw = (typeof(*wfhw)){
315 .enable = 0,
316 };
317 }
318
319 pwm_mediatek_clk_disable(pc, hwpwm: pwm->hwpwm);
320
321 return ret;
322}
323
324static int pwm_mediatek_write_waveform(struct pwm_chip *chip,
325 struct pwm_device *pwm, const void *_wfhw)
326{
327 const struct pwm_mediatek_waveform *wfhw = _wfhw;
328 struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip);
329 u32 ctrl;
330 int ret;
331
332 ret = pwm_mediatek_clk_enable(pc, hwpwm: pwm->hwpwm);
333 if (ret < 0)
334 return ret;
335
336 ctrl = readl(addr: pc->regs);
337
338 if (wfhw->enable) {
339 u32 reg_width = PWMDWIDTH, reg_thres = PWMTHRES;
340
341 if (pc->soc->pwm45_fixup && pwm->hwpwm > 2) {
342 /*
343 * PWM[4,5] has distinct offset for PWMDWIDTH and PWMTHRES
344 * from the other PWMs on MT7623.
345 */
346 reg_width = PWM45DWIDTH_FIXUP;
347 reg_thres = PWM45THRES_FIXUP;
348 }
349
350 if (!(ctrl & BIT(pwm->hwpwm))) {
351 /*
352 * The clks are already on, just increasing the usage
353 * counter doesn't fail.
354 */
355 ret = pwm_mediatek_clk_enable(pc, hwpwm: pwm->hwpwm);
356 if (unlikely(ret < 0))
357 goto out;
358
359 ctrl |= BIT(pwm->hwpwm);
360 writel(val: ctrl, addr: pc->regs);
361 }
362
363 /* Make sure we use the bus clock and not the 26MHz clock */
364 if (pc->soc->pwm_ck_26m_sel_reg)
365 writel(val: 0, addr: pc->regs + pc->soc->pwm_ck_26m_sel_reg);
366
367 pwm_mediatek_writel(chip: pc, num: pwm->hwpwm, PWMCON, BIT(15) | wfhw->con);
368 pwm_mediatek_writel(chip: pc, num: pwm->hwpwm, offset: reg_width, value: wfhw->width);
369 pwm_mediatek_writel(chip: pc, num: pwm->hwpwm, offset: reg_thres, value: wfhw->thres);
370 } else {
371 if (ctrl & BIT(pwm->hwpwm)) {
372 ctrl &= ~BIT(pwm->hwpwm);
373 writel(val: ctrl, addr: pc->regs);
374
375 pwm_mediatek_clk_disable(pc, hwpwm: pwm->hwpwm);
376 }
377 }
378
379out:
380 pwm_mediatek_clk_disable(pc, hwpwm: pwm->hwpwm);
381
382 return ret;
383}
384
385static const struct pwm_ops pwm_mediatek_ops = {
386 .sizeof_wfhw = sizeof(struct pwm_mediatek_waveform),
387 .round_waveform_tohw = pwm_mediatek_round_waveform_tohw,
388 .round_waveform_fromhw = pwm_mediatek_round_waveform_fromhw,
389 .read_waveform = pwm_mediatek_read_waveform,
390 .write_waveform = pwm_mediatek_write_waveform,
391};
392
393static int pwm_mediatek_init_used_clks(struct pwm_mediatek_chip *pc)
394{
395 const struct pwm_mediatek_of_data *soc = pc->soc;
396 unsigned int hwpwm;
397 u32 enabled, handled = 0;
398 int ret;
399
400 ret = clk_prepare_enable(clk: pc->clk_top);
401 if (ret)
402 return ret;
403
404 ret = clk_prepare_enable(clk: pc->clk_main);
405 if (ret)
406 goto err_enable_main;
407
408 enabled = readl(addr: pc->regs) & GENMASK(soc->num_pwms - 1, 0);
409
410 while (enabled & ~handled) {
411 hwpwm = ilog2(enabled & ~handled);
412
413 ret = pwm_mediatek_clk_enable(pc, hwpwm);
414 if (ret) {
415 while (handled) {
416 hwpwm = ilog2(handled);
417
418 pwm_mediatek_clk_disable(pc, hwpwm);
419 handled &= ~BIT(hwpwm);
420 }
421
422 break;
423 }
424
425 handled |= BIT(hwpwm);
426 }
427
428 clk_disable_unprepare(clk: pc->clk_main);
429err_enable_main:
430
431 clk_disable_unprepare(clk: pc->clk_top);
432
433 return ret;
434}
435
436static int pwm_mediatek_probe(struct platform_device *pdev)
437{
438 struct pwm_chip *chip;
439 struct pwm_mediatek_chip *pc;
440 const struct pwm_mediatek_of_data *soc;
441 unsigned int i;
442 int ret;
443
444 soc = of_device_get_match_data(dev: &pdev->dev);
445
446 chip = devm_pwmchip_alloc(parent: &pdev->dev, npwm: soc->num_pwms,
447 struct_size(pc, clk_pwms, soc->num_pwms));
448 if (IS_ERR(ptr: chip))
449 return PTR_ERR(ptr: chip);
450 pc = to_pwm_mediatek_chip(chip);
451
452 pc->soc = soc;
453
454 pc->regs = devm_platform_ioremap_resource(pdev, index: 0);
455 if (IS_ERR(ptr: pc->regs))
456 return PTR_ERR(ptr: pc->regs);
457
458 pc->clk_top = devm_clk_get(dev: &pdev->dev, id: "top");
459 if (IS_ERR(ptr: pc->clk_top))
460 return dev_err_probe(dev: &pdev->dev, err: PTR_ERR(ptr: pc->clk_top),
461 fmt: "Failed to get top clock\n");
462
463 pc->clk_main = devm_clk_get(dev: &pdev->dev, id: "main");
464 if (IS_ERR(ptr: pc->clk_main))
465 return dev_err_probe(dev: &pdev->dev, err: PTR_ERR(ptr: pc->clk_main),
466 fmt: "Failed to get main clock\n");
467
468 for (i = 0; i < soc->num_pwms; i++) {
469 char name[8];
470
471 snprintf(buf: name, size: sizeof(name), fmt: "pwm%d", i + 1);
472
473 pc->clk_pwms[i].clk = devm_clk_get(dev: &pdev->dev, id: name);
474 if (IS_ERR(ptr: pc->clk_pwms[i].clk))
475 return dev_err_probe(dev: &pdev->dev, err: PTR_ERR(ptr: pc->clk_pwms[i].clk),
476 fmt: "Failed to get %s clock\n", name);
477
478 ret = devm_clk_rate_exclusive_get(dev: &pdev->dev, clk: pc->clk_pwms[i].clk);
479 if (ret)
480 return dev_err_probe(dev: &pdev->dev, err: ret,
481 fmt: "Failed to lock clock rate for %s\n", name);
482 }
483
484 ret = pwm_mediatek_init_used_clks(pc);
485 if (ret)
486 return dev_err_probe(dev: &pdev->dev, err: ret, fmt: "Failed to initialize used clocks\n");
487
488 chip->ops = &pwm_mediatek_ops;
489
490 ret = devm_pwmchip_add(&pdev->dev, chip);
491 if (ret < 0)
492 return dev_err_probe(dev: &pdev->dev, err: ret, fmt: "pwmchip_add() failed\n");
493
494 return 0;
495}
496
497static const struct pwm_mediatek_of_data mt2712_pwm_data = {
498 .num_pwms = 8,
499 .pwm45_fixup = false,
500 .chanreg_base = 0x10,
501 .chanreg_width = 0x40,
502};
503
504static const struct pwm_mediatek_of_data mt6795_pwm_data = {
505 .num_pwms = 7,
506 .pwm45_fixup = false,
507 .chanreg_base = 0x10,
508 .chanreg_width = 0x40,
509};
510
511static const struct pwm_mediatek_of_data mt7622_pwm_data = {
512 .num_pwms = 6,
513 .pwm45_fixup = false,
514 .pwm_ck_26m_sel_reg = PWM_CK_26M_SEL,
515 .chanreg_base = 0x10,
516 .chanreg_width = 0x40,
517};
518
519static const struct pwm_mediatek_of_data mt7623_pwm_data = {
520 .num_pwms = 5,
521 .pwm45_fixup = true,
522 .chanreg_base = 0x10,
523 .chanreg_width = 0x40,
524};
525
526static const struct pwm_mediatek_of_data mt7628_pwm_data = {
527 .num_pwms = 4,
528 .pwm45_fixup = true,
529 .chanreg_base = 0x10,
530 .chanreg_width = 0x40,
531};
532
533static const struct pwm_mediatek_of_data mt7629_pwm_data = {
534 .num_pwms = 1,
535 .pwm45_fixup = false,
536 .chanreg_base = 0x10,
537 .chanreg_width = 0x40,
538};
539
540static const struct pwm_mediatek_of_data mt7981_pwm_data = {
541 .num_pwms = 3,
542 .pwm45_fixup = false,
543 .pwm_ck_26m_sel_reg = PWM_CK_26M_SEL,
544 .chanreg_base = 0x80,
545 .chanreg_width = 0x40,
546};
547
548static const struct pwm_mediatek_of_data mt7986_pwm_data = {
549 .num_pwms = 2,
550 .pwm45_fixup = false,
551 .pwm_ck_26m_sel_reg = PWM_CK_26M_SEL,
552 .chanreg_base = 0x10,
553 .chanreg_width = 0x40,
554};
555
556static const struct pwm_mediatek_of_data mt7988_pwm_data = {
557 .num_pwms = 8,
558 .pwm45_fixup = false,
559 .chanreg_base = 0x80,
560 .chanreg_width = 0x40,
561};
562
563static const struct pwm_mediatek_of_data mt8183_pwm_data = {
564 .num_pwms = 4,
565 .pwm45_fixup = false,
566 .pwm_ck_26m_sel_reg = PWM_CK_26M_SEL,
567 .chanreg_base = 0x10,
568 .chanreg_width = 0x40,
569};
570
571static const struct pwm_mediatek_of_data mt8365_pwm_data = {
572 .num_pwms = 3,
573 .pwm45_fixup = false,
574 .pwm_ck_26m_sel_reg = PWM_CK_26M_SEL,
575 .chanreg_base = 0x10,
576 .chanreg_width = 0x40,
577};
578
579static const struct pwm_mediatek_of_data mt8516_pwm_data = {
580 .num_pwms = 5,
581 .pwm45_fixup = false,
582 .pwm_ck_26m_sel_reg = PWM_CK_26M_SEL,
583 .chanreg_base = 0x10,
584 .chanreg_width = 0x40,
585};
586
587static const struct pwm_mediatek_of_data mt6991_pwm_data = {
588 .num_pwms = 4,
589 .pwm45_fixup = false,
590 .pwm_ck_26m_sel_reg = PWM_CK_26M_SEL_V3,
591 .chanreg_base = 0x100,
592 .chanreg_width = 0x100,
593};
594
595static const struct of_device_id pwm_mediatek_of_match[] = {
596 { .compatible = "mediatek,mt2712-pwm", .data = &mt2712_pwm_data },
597 { .compatible = "mediatek,mt6795-pwm", .data = &mt6795_pwm_data },
598 { .compatible = "mediatek,mt6991-pwm", .data = &mt6991_pwm_data },
599 { .compatible = "mediatek,mt7622-pwm", .data = &mt7622_pwm_data },
600 { .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data },
601 { .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data },
602 { .compatible = "mediatek,mt7629-pwm", .data = &mt7629_pwm_data },
603 { .compatible = "mediatek,mt7981-pwm", .data = &mt7981_pwm_data },
604 { .compatible = "mediatek,mt7986-pwm", .data = &mt7986_pwm_data },
605 { .compatible = "mediatek,mt7988-pwm", .data = &mt7988_pwm_data },
606 { .compatible = "mediatek,mt8183-pwm", .data = &mt8183_pwm_data },
607 { .compatible = "mediatek,mt8365-pwm", .data = &mt8365_pwm_data },
608 { .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data },
609 { },
610};
611MODULE_DEVICE_TABLE(of, pwm_mediatek_of_match);
612
613static struct platform_driver pwm_mediatek_driver = {
614 .driver = {
615 .name = "pwm-mediatek",
616 .of_match_table = pwm_mediatek_of_match,
617 },
618 .probe = pwm_mediatek_probe,
619};
620module_platform_driver(pwm_mediatek_driver);
621
622MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
623MODULE_DESCRIPTION("MediaTek general purpose Pulse Width Modulator driver");
624MODULE_LICENSE("GPL v2");
625

source code of linux/drivers/pwm/pwm-mediatek.c