Merge branch 'master' of https://source.denx.de/u-boot/custodians/u-boot-riscv
[platform/kernel/u-boot.git] / drivers / pwm / pwm-cadence-ttc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * (C) Copyright 2021 Xilinx, Inc. Michal Simek
4  */
5
6 #define LOG_CATEGORY UCLASS_PWM
7
8 #include <clk.h>
9 #include <common.h>
10 #include <div64.h>
11 #include <dm.h>
12 #include <log.h>
13 #include <pwm.h>
14 #include <asm/io.h>
15 #include <log.h>
16 #include <div64.h>
17 #include <linux/bitfield.h>
18 #include <linux/math64.h>
19 #include <linux/log2.h>
20 #include <dm/device_compat.h>
21
22 #define CLOCK_CONTROL           0
23 #define COUNTER_CONTROL         0xc
24 #define INTERVAL_COUNTER        0x24
25 #define MATCH_1_COUNTER         0x30
26
27 #define CLK_FALLING_EDGE        BIT(6)
28 #define CLK_SRC_EXTERNAL        BIT(5)
29 #define CLK_PRESCALE_MASK       GENMASK(4, 1)
30 #define CLK_PRESCALE_ENABLE     BIT(0)
31
32 #define COUNTER_WAVE_POL                BIT(6)
33 #define COUNTER_WAVE_DISABLE            BIT(5)
34 #define COUNTER_RESET                   BIT(4)
35 #define COUNTER_MATCH_ENABLE            BIT(3)
36 #define COUNTER_DECREMENT_ENABLE        BIT(2)
37 #define COUNTER_INTERVAL_ENABLE         BIT(1)
38 #define COUNTER_COUNTING_DISABLE        BIT(0)
39
40 #define NSEC_PER_SEC    1000000000L
41
42 #define TTC_REG(reg, channel) ((reg) + (channel) * sizeof(u32))
43 #define TTC_CLOCK_CONTROL(reg, channel) \
44         TTC_REG((reg) + CLOCK_CONTROL, (channel))
45 #define TTC_COUNTER_CONTROL(reg, channel) \
46         TTC_REG((reg) + COUNTER_CONTROL, (channel))
47 #define TTC_INTERVAL_COUNTER(reg, channel) \
48         TTC_REG((reg) + INTERVAL_COUNTER, (channel))
49 #define TTC_MATCH_1_COUNTER(reg, channel) \
50         TTC_REG((reg) + MATCH_1_COUNTER, (channel))
51
52 struct cadence_ttc_pwm_plat {
53         u8 *regs;
54         u32 timer_width;
55 };
56
57 struct cadence_ttc_pwm_priv {
58         u8 *regs;
59         u32 timer_width;
60         u32 timer_mask;
61         unsigned long frequency;
62         bool invert[2];
63 };
64
65 static int cadence_ttc_pwm_set_invert(struct udevice *dev, uint channel,
66                                       bool polarity)
67 {
68         struct cadence_ttc_pwm_priv *priv = dev_get_priv(dev);
69
70         if (channel > 2) {
71                 dev_err(dev, "Unsupported channel number %d(max 2)\n", channel);
72                 return -EINVAL;
73         }
74
75         priv->invert[channel] = polarity;
76
77         dev_dbg(dev, "polarity=%u. Please config PWM again\n", polarity);
78
79         return 0;
80 }
81
82 static int cadence_ttc_pwm_set_config(struct udevice *dev, uint channel,
83                                       uint period_ns, uint duty_ns)
84 {
85         struct cadence_ttc_pwm_priv *priv = dev_get_priv(dev);
86         u32 counter_ctrl, clock_ctrl;
87         int period_clocks, duty_clocks, prescaler;
88
89         dev_dbg(dev, "channel %d, duty %d/period %d ns\n", channel,
90                 duty_ns, period_ns);
91
92         if (channel > 2) {
93                 dev_err(dev, "Unsupported channel number %d(max 2)\n", channel);
94                 return -EINVAL;
95         }
96
97         /* Make sure counter is stopped */
98         counter_ctrl = readl(TTC_COUNTER_CONTROL(priv->regs, channel));
99         setbits_le32(TTC_COUNTER_CONTROL(priv->regs, channel),
100                      COUNTER_COUNTING_DISABLE | COUNTER_WAVE_DISABLE);
101
102         /* Calculate period, prescaler and set clock control register */
103         period_clocks = div64_u64(((int64_t)period_ns * priv->frequency),
104                                   NSEC_PER_SEC);
105
106         prescaler = ilog2(period_clocks) + 1 - priv->timer_width;
107         if (prescaler < 0)
108                 prescaler = 0;
109
110         clock_ctrl = readl(TTC_CLOCK_CONTROL(priv->regs, channel));
111
112         if (!prescaler) {
113                 clock_ctrl &= ~(CLK_PRESCALE_ENABLE | CLK_PRESCALE_MASK);
114         } else {
115                 clock_ctrl &= ~CLK_PRESCALE_MASK;
116                 clock_ctrl |= CLK_PRESCALE_ENABLE;
117                 clock_ctrl |= FIELD_PREP(CLK_PRESCALE_MASK, prescaler - 1);
118         };
119
120         /* External source is not handled by this driver now */
121         clock_ctrl &= ~CLK_SRC_EXTERNAL;
122
123         writel(clock_ctrl, TTC_CLOCK_CONTROL(priv->regs, channel));
124
125         /* Calculate interval and set counter control value */
126         duty_clocks = div64_u64(((int64_t)duty_ns * priv->frequency),
127                                 NSEC_PER_SEC);
128
129         writel((period_clocks >> prescaler) & priv->timer_mask,
130                TTC_INTERVAL_COUNTER(priv->regs, channel));
131         writel((duty_clocks >> prescaler) & priv->timer_mask,
132                TTC_MATCH_1_COUNTER(priv->regs, channel));
133
134         /* Restore/reset counter */
135         counter_ctrl &= ~COUNTER_DECREMENT_ENABLE;
136         counter_ctrl |= COUNTER_INTERVAL_ENABLE |
137                         COUNTER_RESET |
138                         COUNTER_MATCH_ENABLE;
139
140         if (priv->invert[channel])
141                 counter_ctrl |= COUNTER_WAVE_POL;
142         else
143                 counter_ctrl &= ~COUNTER_WAVE_POL;
144
145         writel(counter_ctrl, TTC_COUNTER_CONTROL(priv->regs, channel));
146
147         dev_dbg(dev, "%d/%d clocks, prescaler 2^%d\n", duty_clocks,
148                 period_clocks, prescaler);
149
150         return 0;
151 };
152
153 static int cadence_ttc_pwm_set_enable(struct udevice *dev, uint channel,
154                                       bool enable)
155 {
156         struct cadence_ttc_pwm_priv *priv = dev_get_priv(dev);
157
158         if (channel > 2) {
159                 dev_err(dev, "Unsupported channel number %d(max 2)\n", channel);
160                 return -EINVAL;
161         }
162
163         dev_dbg(dev, "Enable: %d, channel %d\n", enable, channel);
164
165         if (enable) {
166                 clrbits_le32(TTC_COUNTER_CONTROL(priv->regs, channel),
167                              COUNTER_COUNTING_DISABLE |
168                              COUNTER_WAVE_DISABLE);
169                 setbits_le32(TTC_COUNTER_CONTROL(priv->regs, channel),
170                              COUNTER_RESET);
171         } else {
172                 setbits_le32(TTC_COUNTER_CONTROL(priv->regs, channel),
173                              COUNTER_COUNTING_DISABLE |
174                              COUNTER_WAVE_DISABLE);
175         }
176
177         return 0;
178 };
179
180 static int cadence_ttc_pwm_probe(struct udevice *dev)
181 {
182         struct cadence_ttc_pwm_priv *priv = dev_get_priv(dev);
183         struct cadence_ttc_pwm_plat *plat = dev_get_plat(dev);
184         struct clk clk;
185         int ret;
186
187         priv->regs = plat->regs;
188         priv->timer_width = plat->timer_width;
189         priv->timer_mask = GENMASK(priv->timer_width - 1, 0);
190
191         ret = clk_get_by_index(dev, 0, &clk);
192         if (ret < 0) {
193                 dev_err(dev, "failed to get clock\n");
194                 return ret;
195         }
196
197         priv->frequency = clk_get_rate(&clk);
198         if (IS_ERR_VALUE(priv->frequency)) {
199                 dev_err(dev, "failed to get rate\n");
200                 return priv->frequency;
201         }
202         dev_dbg(dev, "Clk frequency: %ld\n", priv->frequency);
203
204         ret = clk_enable(&clk);
205         if (ret) {
206                 dev_err(dev, "failed to enable clock\n");
207                 return ret;
208         }
209
210         return 0;
211 }
212
213 static int cadence_ttc_pwm_of_to_plat(struct udevice *dev)
214 {
215         struct cadence_ttc_pwm_plat *plat = dev_get_plat(dev);
216         const char *cells;
217
218         cells = dev_read_prop(dev, "#pwm-cells", NULL);
219         if (!cells)
220                 return -EINVAL;
221
222         plat->regs = dev_read_addr_ptr(dev);
223
224         plat->timer_width = dev_read_u32_default(dev, "timer-width", 16);
225
226         return 0;
227 }
228
229 static int cadence_ttc_pwm_bind(struct udevice *dev)
230 {
231         const char *cells;
232
233         cells = dev_read_prop(dev, "#pwm-cells", NULL);
234         if (!cells)
235                 return -ENODEV;
236
237         return 0;
238 }
239
240 static const struct pwm_ops cadence_ttc_pwm_ops = {
241         .set_invert = cadence_ttc_pwm_set_invert,
242         .set_config = cadence_ttc_pwm_set_config,
243         .set_enable = cadence_ttc_pwm_set_enable,
244 };
245
246 static const struct udevice_id cadence_ttc_pwm_ids[] = {
247         { .compatible = "cdns,ttc" },
248         { }
249 };
250
251 U_BOOT_DRIVER(cadence_ttc_pwm) = {
252         .name = "cadence_ttc_pwm",
253         .id = UCLASS_PWM,
254         .of_match = cadence_ttc_pwm_ids,
255         .ops = &cadence_ttc_pwm_ops,
256         .bind = cadence_ttc_pwm_bind,
257         .of_to_plat = cadence_ttc_pwm_of_to_plat,
258         .probe = cadence_ttc_pwm_probe,
259         .priv_auto = sizeof(struct cadence_ttc_pwm_priv),
260         .plat_auto = sizeof(struct cadence_ttc_pwm_plat),
261 };