Merge https://gitlab.denx.de/u-boot/custodians/u-boot-fsl-qoriq
[platform/kernel/u-boot.git] / drivers / pwm / pwm-meson.c
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (C) 2020 BayLibre, SAS.
4  * Author: Neil Armstrong <narmstrong@baylibre.com>
5  * Copyright (C) 2014 Amlogic, Inc.
6  *
7  * This PWM is only a set of Gates, Dividers and Counters:
8  * PWM output is achieved by calculating a clock that permits calculating
9  * two periods (low and high). The counter then has to be set to switch after
10  * N cycles for the first half period.
11  * The hardware has no "polarity" setting. This driver reverses the period
12  * cycles (the low length is inverted with the high length) for
13  * PWM_POLARITY_INVERSED.
14  * Setting the polarity will disable and re-enable the PWM output.
15  * Disabling the PWM stops the output immediately (without waiting for the
16  * current period to complete first).
17  */
18
19 #include <common.h>
20 #include <clk.h>
21 #include <div64.h>
22 #include <dm.h>
23 #include <pwm.h>
24 #include <regmap.h>
25 #include <linux/io.h>
26 #include <linux/math64.h>
27 #include <linux/bitfield.h>
28 #include <linux/clk-provider.h>
29
30 #define NSEC_PER_SEC 1000000000L
31
32 #define REG_PWM_A               0x0
33 #define REG_PWM_B               0x4
34 #define PWM_LOW_MASK            GENMASK(15, 0)
35 #define PWM_HIGH_MASK           GENMASK(31, 16)
36
37 #define REG_MISC_AB             0x8
38 #define MISC_B_CLK_EN           BIT(23)
39 #define MISC_A_CLK_EN           BIT(15)
40 #define MISC_CLK_DIV_MASK       0x7f
41 #define MISC_B_CLK_DIV_SHIFT    16
42 #define MISC_A_CLK_DIV_SHIFT    8
43 #define MISC_B_CLK_SEL_SHIFT    6
44 #define MISC_A_CLK_SEL_SHIFT    4
45 #define MISC_CLK_SEL_MASK       0x3
46 #define MISC_B_EN               BIT(1)
47 #define MISC_A_EN               BIT(0)
48
49 #define MESON_NUM_PWMS          2
50
51 static struct meson_pwm_channel_data {
52         u8              reg_offset;
53         u8              clk_sel_shift;
54         u8              clk_div_shift;
55         u32             clk_en_mask;
56         u32             pwm_en_mask;
57 } meson_pwm_per_channel_data[MESON_NUM_PWMS] = {
58         {
59                 .reg_offset     = REG_PWM_A,
60                 .clk_sel_shift  = MISC_A_CLK_SEL_SHIFT,
61                 .clk_div_shift  = MISC_A_CLK_DIV_SHIFT,
62                 .clk_en_mask    = MISC_A_CLK_EN,
63                 .pwm_en_mask    = MISC_A_EN,
64         },
65         {
66                 .reg_offset     = REG_PWM_B,
67                 .clk_sel_shift  = MISC_B_CLK_SEL_SHIFT,
68                 .clk_div_shift  = MISC_B_CLK_DIV_SHIFT,
69                 .clk_en_mask    = MISC_B_CLK_EN,
70                 .pwm_en_mask    = MISC_B_EN,
71         }
72 };
73
74 struct meson_pwm_channel {
75         unsigned int hi;
76         unsigned int lo;
77         u8 pre_div;
78         uint period_ns;
79         uint duty_ns;
80         bool configured;
81         bool enabled;
82         bool polarity;
83         struct clk clk;
84 };
85
86 struct meson_pwm_data {
87         const long *parent_ids;
88         unsigned int num_parents;
89 };
90
91 struct meson_pwm {
92         const struct meson_pwm_data *data;
93         struct meson_pwm_channel channels[MESON_NUM_PWMS];
94         void __iomem *base;
95 };
96
97 static int meson_pwm_set_enable(struct udevice *dev, uint channel, bool enable);
98
99 static int meson_pwm_set_config(struct udevice *dev, uint channeln,
100                                  uint period_ns, uint duty_ns)
101 {
102         struct meson_pwm *priv = dev_get_priv(dev);
103         struct meson_pwm_channel *channel;
104         struct meson_pwm_channel_data *channel_data;
105         unsigned int duty, period, pre_div, cnt, duty_cnt;
106         unsigned long fin_freq;
107
108         if (channeln >= MESON_NUM_PWMS)
109                 return -ENODEV;
110
111         channel = &priv->channels[channeln];
112         channel_data = &meson_pwm_per_channel_data[channeln];
113
114         period = period_ns;
115         if (channel->polarity)
116                 duty = period_ns - duty_ns;
117         else
118                 duty = duty_ns;
119
120         debug("%s%d: polarity %s duty %d period %d\n", __func__, channeln,
121               channel->polarity ? "true" : "false", duty, period);
122
123         fin_freq = clk_get_rate(&channel->clk);
124         if (fin_freq == 0) {
125                 printf("%s%d: invalid source clock frequency\n", __func__, channeln);
126                 return -EINVAL;
127         }
128
129         debug("%s%d: fin_freq: %lu Hz\n", __func__, channeln, fin_freq);
130
131         pre_div = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * 0xffffLL);
132         if (pre_div > MISC_CLK_DIV_MASK) {
133                 printf("%s%d: unable to get period pre_div\n", __func__, channeln);
134                 return -EINVAL;
135         }
136
137         cnt = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * (pre_div + 1));
138         if (cnt > 0xffff) {
139                 printf("%s%d: unable to get period cnt\n", __func__, channeln);
140                 return -EINVAL;
141         }
142
143         debug("%s%d: period=%u pre_div=%u cnt=%u\n", __func__, channeln, period, pre_div, cnt);
144
145         if (duty == period) {
146                 channel->pre_div = pre_div;
147                 channel->hi = cnt;
148                 channel->lo = 0;
149         } else if (duty == 0) {
150                 channel->pre_div = pre_div;
151                 channel->hi = 0;
152                 channel->lo = cnt;
153         } else {
154                 /* Then check is we can have the duty with the same pre_div */
155                 duty_cnt = div64_u64(fin_freq * (u64)duty, NSEC_PER_SEC * (pre_div + 1));
156                 if (duty_cnt > 0xffff) {
157                         printf("%s%d: unable to get duty cycle\n", __func__, channeln);
158                         return -EINVAL;
159                 }
160
161                 debug("%s%d: duty=%u pre_div=%u duty_cnt=%u\n",
162                       __func__, channeln, duty, pre_div, duty_cnt);
163
164                 channel->pre_div = pre_div;
165                 channel->hi = duty_cnt;
166                 channel->lo = cnt - duty_cnt;
167         }
168
169         channel->period_ns = period_ns;
170         channel->duty_ns = duty_ns;
171         channel->configured = true;
172
173         if (channel->enabled) {
174                 meson_pwm_set_enable(dev, channeln, false);
175                 meson_pwm_set_enable(dev, channeln, true);
176         }
177
178         return 0;
179 }
180
181 static int meson_pwm_set_enable(struct udevice *dev, uint channeln, bool enable)
182 {
183         struct meson_pwm *priv = dev_get_priv(dev);
184         struct meson_pwm_channel *channel;
185         struct meson_pwm_channel_data *channel_data;
186         u32 value;
187
188         if (channeln >= MESON_NUM_PWMS)
189                 return -ENODEV;
190
191         channel = &priv->channels[channeln];
192         channel_data = &meson_pwm_per_channel_data[channeln];
193
194         if (!channel->configured)
195                 return -EINVAL;
196
197         if (enable) {
198                 if (channel->enabled)
199                         return 0;
200
201                 value = readl(priv->base + REG_MISC_AB);
202                 value &= ~(MISC_CLK_DIV_MASK << channel_data->clk_div_shift);
203                 value |= channel->pre_div << channel_data->clk_div_shift;
204                 value |= channel_data->clk_en_mask;
205                 writel(value, priv->base + REG_MISC_AB);
206
207                 value = FIELD_PREP(PWM_HIGH_MASK, channel->hi) |
208                         FIELD_PREP(PWM_LOW_MASK, channel->lo);
209                 writel(value, priv->base + channel_data->reg_offset);
210
211                 value = readl(priv->base + REG_MISC_AB);
212                 value |= channel_data->pwm_en_mask;
213                 writel(value, priv->base + REG_MISC_AB);
214
215                 debug("%s%d: enabled\n", __func__, channeln);
216                 channel->enabled = true;
217         } else {
218                 if (!channel->enabled)
219                         return 0;
220
221                 value = readl(priv->base + REG_MISC_AB);
222                 value &= channel_data->pwm_en_mask;
223                 writel(value, priv->base + REG_MISC_AB);
224
225                 debug("%s%d: disabled\n", __func__, channeln);
226                 channel->enabled = false;
227         }
228
229         return 0;
230 }
231
232 static int meson_pwm_set_invert(struct udevice *dev, uint channeln, bool polarity)
233 {
234         struct meson_pwm *priv = dev_get_priv(dev);
235         struct meson_pwm_channel *channel;
236
237         if (channeln >= MESON_NUM_PWMS)
238                 return -ENODEV;
239
240         debug("%s%d: set invert %s\n", __func__, channeln, polarity ? "true" : "false");
241
242         channel = &priv->channels[channeln];
243
244         channel->polarity = polarity;
245
246         if (!channel->configured)
247                 return 0;
248
249         return meson_pwm_set_config(dev, channeln, channel->period_ns, channel->duty_ns);
250 }
251
252 static int meson_pwm_of_to_plat(struct udevice *dev)
253 {
254         struct meson_pwm *priv = dev_get_priv(dev);
255
256         priv->base = dev_read_addr_ptr(dev);
257
258         return 0;
259 }
260
261 static int meson_pwm_probe(struct udevice *dev)
262 {
263         struct meson_pwm *priv = dev_get_priv(dev);
264         struct meson_pwm_data *data;
265         unsigned int i, p;
266         char name[255];
267         int err;
268         u32 reg;
269
270         data = (struct meson_pwm_data *)dev_get_driver_data(dev);
271         if (!data)
272                 return -EINVAL;
273
274         for (i = 0; i < MESON_NUM_PWMS; i++) {
275                 struct meson_pwm_channel *channel = &priv->channels[i];
276                 struct meson_pwm_channel_data *channel_data = &meson_pwm_per_channel_data[i];
277
278                 snprintf(name, sizeof(name), "clkin%u", i);
279
280                 err = clk_get_by_name(dev, name, &channel->clk);
281                 /* If clock is not specified, use the already set clock */
282                 if (err == -ENODATA) {
283                         struct udevice *cdev;
284                         struct uclass *uc;
285
286                         /* Get parent from mux */
287                         p = (readl(priv->base + REG_MISC_AB) >> channel_data->clk_sel_shift) &
288                                 MISC_CLK_SEL_MASK;
289
290                         if (p >= data->num_parents) {
291                                 printf("%s%d: hw parent is invalid\n", __func__, i);
292                                 return -EINVAL;
293                         }
294
295                         if (data->parent_ids[p] == -1) {
296                                 /* Search for xtal clk */
297                                 const char *str;
298
299                                 err = uclass_get(UCLASS_CLK, &uc);
300                                 if (err)
301                                         return err;
302
303                                 uclass_foreach_dev(cdev, uc) {
304                                         if (strcmp(cdev->driver->name, "fixed_rate_clock"))
305                                                 continue;
306
307                                         str = ofnode_read_string(dev_ofnode(cdev),
308                                                                  "clock-output-names");
309                                         if (!str)
310                                                 continue;
311
312                                         if (!strcmp(str, "xtal")) {
313                                                 err = uclass_get_device_by_ofnode(UCLASS_CLK,
314                                                                                   dev_ofnode(cdev),
315                                                                                   &cdev);
316                                                 if (err) {
317                                                         printf("%s%d: Failed to get xtal clk\n", __func__, i);
318                                                         return err;
319                                                 }
320
321                                                 break;
322                                         }
323                                 }
324
325                                 if (!cdev) {
326                                         printf("%s%d: Failed to find xtal clk device\n", __func__, i);
327                                         return -EINVAL;
328                                 }
329
330                                 channel->clk.dev = cdev;
331                                 channel->clk.id = 0;
332                                 channel->clk.data = 0;
333                         } else {
334                                 /* Look for parent clock */
335                                 err = uclass_get(UCLASS_CLK, &uc);
336                                 if (err)
337                                         return err;
338
339                                 uclass_foreach_dev(cdev, uc) {
340                                         if (strstr(cdev->driver->name, "meson_clk"))
341                                                 break;
342                                 }
343
344                                 if (!cdev) {
345                                         printf("%s%d: Failed to find clk device\n", __func__, i);
346                                         return -EINVAL;
347                                 }
348
349                                 err = uclass_get_device_by_ofnode(UCLASS_CLK,
350                                                                   dev_ofnode(cdev),
351                                                                   &cdev);
352                                 if (err) {
353                                         printf("%s%d: Failed to get clk controller\n", __func__, i);
354                                         return err;
355                                 }
356
357                                 channel->clk.dev = cdev;
358                                 channel->clk.id = data->parent_ids[p];
359                                 channel->clk.data = 0;
360                         }
361
362                         /* We have our source clock, do not alter HW clock mux */
363                         continue;
364                 } else
365                         return err;
366
367                 /* Get id in list */
368                 for (p = 0 ; p < data->num_parents ; ++p) {
369                         if (!strcmp(channel->clk.dev->driver->name, "fixed_rate_clock")) {
370                                 if (data->parent_ids[p] == -1)
371                                         break;
372                         } else {
373                                 if (data->parent_ids[p] == channel->clk.id)
374                                         break;
375                         }
376                 }
377
378                 /* Invalid clock ID */
379                 if (p == data->num_parents) {
380                         printf("%s%d: source clock is invalid\n", __func__, i);
381                         return -EINVAL;
382                 }
383
384                 /* switch parent in mux */
385                 reg = readl(priv->base + REG_MISC_AB);
386
387                 debug("%s%d: switching parent %d to %d\n", __func__, i,
388                       (reg >> channel_data->clk_sel_shift) & MISC_CLK_SEL_MASK, p);
389
390                 reg &= MISC_CLK_SEL_MASK << channel_data->clk_sel_shift;
391                 reg |= (p & MISC_CLK_SEL_MASK) << channel_data->clk_sel_shift;
392                 writel(reg, priv->base + REG_MISC_AB);
393         }
394
395         return 0;
396 }
397
398 static const struct pwm_ops meson_pwm_ops = {
399         .set_config     = meson_pwm_set_config,
400         .set_enable     = meson_pwm_set_enable,
401         .set_invert     = meson_pwm_set_invert,
402 };
403
404 #define XTAL                    -1
405
406 /* Local clock ids aliases to avoid define conflicts */
407 #define GXBB_CLKID_HDMI_PLL             2
408 #define GXBB_CLKID_FCLK_DIV3            5
409 #define GXBB_CLKID_FCLK_DIV4            6
410 #define GXBB_CLKID_CLK81                12
411
412 static const long pwm_gxbb_parent_ids[] = {
413         XTAL, GXBB_CLKID_HDMI_PLL, GXBB_CLKID_FCLK_DIV4, GXBB_CLKID_FCLK_DIV3
414 };
415
416 static const struct meson_pwm_data pwm_gxbb_data = {
417         .parent_ids = pwm_gxbb_parent_ids,
418         .num_parents = ARRAY_SIZE(pwm_gxbb_parent_ids),
419 };
420
421 /*
422  * Only the 2 first inputs of the GXBB AO PWMs are valid
423  * The last 2 are grounded
424  */
425 static const long pwm_gxbb_ao_parent_ids[] = {
426         XTAL, GXBB_CLKID_CLK81
427 };
428
429 static const struct meson_pwm_data pwm_gxbb_ao_data = {
430         .parent_ids = pwm_gxbb_ao_parent_ids,
431         .num_parents = ARRAY_SIZE(pwm_gxbb_ao_parent_ids),
432 };
433
434 /* Local clock ids aliases to avoid define conflicts */
435 #define AXG_CLKID_FCLK_DIV3             3
436 #define AXG_CLKID_FCLK_DIV4             4
437 #define AXG_CLKID_FCLK_DIV5             5
438 #define AXG_CLKID_CLK81                 10
439
440 static const long pwm_axg_ee_parent_ids[] = {
441         XTAL, AXG_CLKID_FCLK_DIV5, AXG_CLKID_FCLK_DIV4, AXG_CLKID_FCLK_DIV3
442 };
443
444 static const struct meson_pwm_data pwm_axg_ee_data = {
445         .parent_ids = pwm_axg_ee_parent_ids,
446         .num_parents = ARRAY_SIZE(pwm_axg_ee_parent_ids),
447 };
448
449 static const long pwm_axg_ao_parent_ids[] = {
450         AXG_CLKID_CLK81, XTAL, AXG_CLKID_FCLK_DIV4, AXG_CLKID_FCLK_DIV5
451 };
452
453 static const struct meson_pwm_data pwm_axg_ao_data = {
454         .parent_ids = pwm_axg_ao_parent_ids,
455         .num_parents = ARRAY_SIZE(pwm_axg_ao_parent_ids),
456 };
457
458 /* Local clock ids aliases to avoid define conflicts */
459 #define G12A_CLKID_FCLK_DIV3            3
460 #define G12A_CLKID_FCLK_DIV4            4
461 #define G12A_CLKID_FCLK_DIV5            5
462 #define G12A_CLKID_CLK81                10
463 #define G12A_CLKID_HDMI_PLL             128
464
465 static const long pwm_g12a_ao_ab_parent_ids[] = {
466         XTAL, G12A_CLKID_CLK81, G12A_CLKID_FCLK_DIV4, G12A_CLKID_FCLK_DIV5
467 };
468
469 static const struct meson_pwm_data pwm_g12a_ao_ab_data = {
470         .parent_ids = pwm_g12a_ao_ab_parent_ids,
471         .num_parents = ARRAY_SIZE(pwm_g12a_ao_ab_parent_ids),
472 };
473
474 static const long pwm_g12a_ao_cd_parent_ids[] = {
475         XTAL, G12A_CLKID_CLK81,
476 };
477
478 static const struct meson_pwm_data pwm_g12a_ao_cd_data = {
479         .parent_ids = pwm_g12a_ao_cd_parent_ids,
480         .num_parents = ARRAY_SIZE(pwm_g12a_ao_cd_parent_ids),
481 };
482
483 static const long pwm_g12a_ee_parent_ids[] = {
484         XTAL, G12A_CLKID_HDMI_PLL, G12A_CLKID_FCLK_DIV4, G12A_CLKID_FCLK_DIV3
485 };
486
487 static const struct meson_pwm_data pwm_g12a_ee_data = {
488         .parent_ids = pwm_g12a_ee_parent_ids,
489         .num_parents = ARRAY_SIZE(pwm_g12a_ee_parent_ids),
490 };
491
492 static const struct udevice_id meson_pwm_ids[] = {
493         {
494                 .compatible = "amlogic,meson-gxbb-pwm",
495                 .data = (ulong)&pwm_gxbb_data
496         },
497         {
498                 .compatible = "amlogic,meson-gxbb-ao-pwm",
499                 .data = (ulong)&pwm_gxbb_ao_data
500         },
501         {
502                 .compatible = "amlogic,meson-axg-ee-pwm",
503                 .data = (ulong)&pwm_axg_ee_data
504         },
505         {
506                 .compatible = "amlogic,meson-axg-ao-pwm",
507                 .data = (ulong)&pwm_axg_ao_data
508         },
509         {
510                 .compatible = "amlogic,meson-g12a-ee-pwm",
511                 .data = (ulong)&pwm_g12a_ee_data
512         },
513         {
514                 .compatible = "amlogic,meson-g12a-ao-pwm-ab",
515                 .data = (ulong)&pwm_g12a_ao_ab_data
516         },
517         {
518                 .compatible = "amlogic,meson-g12a-ao-pwm-cd",
519                 .data = (ulong)&pwm_g12a_ao_cd_data
520         },
521 };
522
523 U_BOOT_DRIVER(meson_pwm) = {
524         .name   = "meson_pwm",
525         .id     = UCLASS_PWM,
526         .of_match = meson_pwm_ids,
527         .ops    = &meson_pwm_ops,
528         .of_to_plat = meson_pwm_of_to_plat,
529         .probe   = meson_pwm_probe,
530         .priv_auto      = sizeof(struct meson_pwm),
531 };