1 /*
2 * Copyright (c) 2016 Google, Inc
3 * Written by Simon Glass <sjg@chromium.org>
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8 #include <common.h>
9 #include <clk.h>
10 #include <div64.h>
11 #include <dm.h>
12 #include <dm/pinctrl.h>
13 #include <pwm.h>
14 #include <regmap.h>
15 #include <syscon.h>
16 #include <asm/io.h>
17 #include <asm/arch/pwm.h>
18 #include <power/regulator.h>
19
20 DECLARE_GLOBAL_DATA_PTR;
21
22 /*
23 * regs for pwm v4
24 */
25 #define HIWORD_UPDATE(v, l, h) (((v) << (l)) | (GENMASK(h, l) << 16))
26
27 /* VERSION_ID */
28 #define VERSION_ID 0x0
29 #define CHANNEL_NUM_SUPPORT_SHIFT 0
30 #define CHANNEL_NUM_SUPPORT_MASK (0xf << CHANNEL_NUM_SUPPORT_SHIFT)
31 #define CHANNLE_INDEX_SHIFT 4
32 #define CHANNLE_INDEX_MASK (0xf << CHANNLE_INDEX_SHIFT)
33 /* ENABLE */
34 #define ENABLE 0x4
35 #define PWM_ENABLE_V4 (0x3 << 0)
36 #define PWM_CLK_EN(v) HIWORD_UPDATE(v, 0, 0)
37 #define PWM_EN(v) HIWORD_UPDATE(v, 1, 1)
38 #define PWM_CTRL_UPDATE_EN(v) HIWORD_UPDATE(v, 2, 2)
39 #define PWM_GLOBAL_JOIN_EN(v) HIWORD_UPDATE(v, 4, 4)
40 /* CLK_CTRL */
41 #define CLK_CTRL 0x8
42 #define CLK_PRESCALE(v) HIWORD_UPDATE(v, 0, 2)
43 #define CLK_SCALE(v) HIWORD_UPDATE(v, 4, 12)
44 #define CLK_SRC_SEL(v) HIWORD_UPDATE(v, 13, 14)
45 #define CLK_GLOBAL_SEL(v) HIWORD_UPDATE(v, 15, 15)
46 /* CTRL */
47 #define CTRL_V4 0xc
48 #define PWM_MODE(v) HIWORD_UPDATE(v, 0, 1)
49 #define ONESHOT_MODE 0
50 #define CONTINUOUS_MODE 1
51 #define CAPTURE_MODE 2
52 #define PWM_POLARITY(v) HIWORD_UPDATE(v, 2, 3)
53 #define DUTY_NEGATIVE (0 << 0)
54 #define DUTY_POSITIVE (1 << 0)
55 #define INACTIVE_NEGATIVE (0 << 1)
56 #define INACTIVE_POSITIVE (1 << 1)
57 #define PWM_ALIGNED_INVALID(v) HIWORD_UPDATE(v, 5, 5)
58 #define PWM_IN_SEL(v) HIWORD_UPDATE(v, 6, 8)
59 /* PERIOD */
60 #define PERIOD 0x10
61 /* DUTY */
62 #define DUTY 0x14
63
64 struct rk_pwm_priv {
65 fdt_addr_t base;
66 ulong freq;
67 u32 conf_polarity;
68 bool vop_pwm_en; /* indicate voppwm mirror register state */
69 const struct rockchip_pwm_data *data;
70 };
71
72 struct rockchip_pwm_funcs {
73 int (*set_invert)(struct udevice *dev, uint channel, bool polarity);
74 int (*set_config)(struct udevice *dev, uint channel,
75 uint period_ns, uint duty_ns);
76 int (*set_enable)(struct udevice *dev, uint channel, bool enable);
77 };
78
79 struct rockchip_pwm_data {
80 struct rockchip_pwm_regs regs;
81 struct rockchip_pwm_funcs funcs;
82 unsigned int prescaler;
83 bool supports_polarity;
84 bool supports_lock;
85 bool vop_pwm;
86 u8 main_version;
87 u32 enable_conf;
88 u32 enable_conf_mask;
89 };
90
rk_pwm_set_invert_v4(struct udevice * dev,uint channel,bool polarity)91 static int rk_pwm_set_invert_v4(struct udevice *dev, uint channel, bool polarity)
92 {
93 struct rk_pwm_priv *priv = dev_get_priv(dev);
94
95 debug("%s: polarity=%u\n", __func__, polarity);
96 if (polarity)
97 priv->conf_polarity = DUTY_NEGATIVE | INACTIVE_POSITIVE;
98 else
99 priv->conf_polarity = DUTY_POSITIVE | INACTIVE_NEGATIVE;
100
101 return 0;
102 }
103
rk_pwm_set_invert_v1(struct udevice * dev,uint channel,bool polarity)104 static int rk_pwm_set_invert_v1(struct udevice *dev, uint channel, bool polarity)
105 {
106 struct rk_pwm_priv *priv = dev_get_priv(dev);
107
108 debug("%s: polarity=%u\n", __func__, polarity);
109 if (polarity)
110 priv->conf_polarity = PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE;
111 else
112 priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE;
113
114 return 0;
115 }
116
rk_pwm_set_invert(struct udevice * dev,uint channel,bool polarity)117 static int rk_pwm_set_invert(struct udevice *dev, uint channel, bool polarity)
118 {
119 struct rk_pwm_priv *priv = dev_get_priv(dev);
120
121 if (!priv->data->supports_polarity) {
122 debug("%s: Do not support polarity\n", __func__);
123 return 0;
124 }
125
126 return priv->data->funcs.set_invert(dev, channel, polarity);
127 }
128
rk_pwm_set_config_v4(struct udevice * dev,uint channel,uint period_ns,uint duty_ns)129 static int rk_pwm_set_config_v4(struct udevice *dev, uint channel,
130 uint period_ns, uint duty_ns)
131 {
132 struct rk_pwm_priv *priv = dev_get_priv(dev);
133 unsigned long period, duty;
134
135 period = lldiv((uint64_t)(priv->freq / 1000) * period_ns,
136 priv->data->prescaler * 1000000);
137 duty = lldiv((uint64_t)(priv->freq / 1000) * duty_ns,
138 priv->data->prescaler * 1000000);
139
140 writel(period, priv->base + PERIOD);
141 writel(duty, priv->base + DUTY);
142
143 if (priv->data->supports_polarity)
144 writel(PWM_POLARITY(priv->conf_polarity), priv->base + CTRL_V4);
145
146 writel(PWM_MODE(CONTINUOUS_MODE) | PWM_ALIGNED_INVALID(false),
147 priv->base + CTRL_V4);
148
149 writel(PWM_CTRL_UPDATE_EN(true), priv->base + ENABLE);
150
151 debug("%s: period=%lu, duty=%lu\n", __func__, period, duty);
152
153 return 0;
154 }
155
rk_pwm_set_config_v1(struct udevice * dev,uint channel,uint period_ns,uint duty_ns)156 static int rk_pwm_set_config_v1(struct udevice *dev, uint channel,
157 uint period_ns, uint duty_ns)
158 {
159 struct rk_pwm_priv *priv = dev_get_priv(dev);
160 const struct rockchip_pwm_regs *regs = &priv->data->regs;
161 unsigned long period, duty;
162 u32 ctrl;
163
164 debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns);
165
166 ctrl = readl(priv->base + regs->ctrl);
167 if (priv->data->vop_pwm) {
168 if (priv->vop_pwm_en)
169 ctrl |= RK_PWM_ENABLE;
170 else
171 ctrl &= ~RK_PWM_ENABLE;
172 }
173
174 /*
175 * Lock the period and duty of previous configuration, then
176 * change the duty and period, that would not be effective.
177 */
178 if (priv->data->supports_lock) {
179 ctrl |= PWM_LOCK;
180 writel(ctrl, priv->base + regs->ctrl);
181 }
182
183 period = lldiv((uint64_t)(priv->freq / 1000) * period_ns,
184 priv->data->prescaler * 1000000);
185 duty = lldiv((uint64_t)(priv->freq / 1000) * duty_ns,
186 priv->data->prescaler * 1000000);
187
188 writel(period, priv->base + regs->period);
189 writel(duty, priv->base + regs->duty);
190
191 if (priv->data->supports_polarity) {
192 ctrl &= ~(PWM_DUTY_MASK | PWM_INACTIVE_MASK);
193 ctrl |= priv->conf_polarity;
194 }
195
196 /*
197 * Unlock and set polarity at the same time,
198 * the configuration of duty, period and polarity
199 * would be effective together at next period.
200 */
201 if (priv->data->supports_lock)
202 ctrl &= ~PWM_LOCK;
203 writel(ctrl, priv->base + regs->ctrl);
204
205 debug("%s: period=%lu, duty=%lu\n", __func__, period, duty);
206
207 return 0;
208 }
209
rk_pwm_set_config(struct udevice * dev,uint channel,uint period_ns,uint duty_ns)210 static int rk_pwm_set_config(struct udevice *dev, uint channel,
211 uint period_ns, uint duty_ns)
212 {
213 struct rk_pwm_priv *priv = dev_get_priv(dev);
214
215 return priv->data->funcs.set_config(dev, channel, period_ns, duty_ns);
216 }
217
rk_pwm_set_enable_v4(struct udevice * dev,uint channel,bool enable)218 static int rk_pwm_set_enable_v4(struct udevice *dev, uint channel, bool enable)
219 {
220 struct rk_pwm_priv *priv = dev_get_priv(dev);
221
222 debug("%s: Enable '%s'\n", __func__, dev->name);
223
224 writel(PWM_EN(enable) | PWM_CLK_EN(enable), priv->base + ENABLE);
225
226 if (enable)
227 pinctrl_select_state(dev, "active");
228
229 return 0;
230 }
231
rk_pwm_set_enable_v1(struct udevice * dev,uint channel,bool enable)232 static int rk_pwm_set_enable_v1(struct udevice *dev, uint channel, bool enable)
233 {
234 struct rk_pwm_priv *priv = dev_get_priv(dev);
235 const struct rockchip_pwm_regs *regs = &priv->data->regs;
236 u32 ctrl;
237
238 debug("%s: Enable '%s'\n", __func__, dev->name);
239
240 ctrl = readl(priv->base + regs->ctrl);
241 ctrl &= ~priv->data->enable_conf_mask;
242
243 if (enable)
244 ctrl |= priv->data->enable_conf;
245 else
246 ctrl &= ~priv->data->enable_conf;
247
248 writel(ctrl, priv->base + regs->ctrl);
249 if (priv->data->vop_pwm)
250 priv->vop_pwm_en = enable;
251
252 if (enable)
253 pinctrl_select_state(dev, "active");
254
255 return 0;
256 }
257
rk_pwm_set_enable(struct udevice * dev,uint channel,bool enable)258 static int rk_pwm_set_enable(struct udevice *dev, uint channel, bool enable)
259 {
260 struct rk_pwm_priv *priv = dev_get_priv(dev);
261
262 return priv->data->funcs.set_enable(dev, channel, enable);
263 }
264
rk_pwm_ofdata_to_platdata(struct udevice * dev)265 static int rk_pwm_ofdata_to_platdata(struct udevice *dev)
266 {
267 struct rk_pwm_priv *priv = dev_get_priv(dev);
268
269 priv->base = dev_read_addr(dev);
270
271 return 0;
272 }
273
274 #if defined(CONFIG_MOS_SUPPORT) && !defined(CONFIG_SPL_BUILD)
rk_pwm_clk_init(struct udevice * dev)275 static int rk_pwm_clk_init(struct udevice *dev)
276 {
277 struct clk_bulk clks = { 0 };
278 int ret = 0;
279
280 ret = clk_get_bulk(dev, &clks);
281 if (ret == -ENOSYS || ret == -ENOENT)
282 return 0;
283 if (ret) {
284 dev_err(dev, "failed to get clk: %d\n", ret);
285 return ret;
286 }
287
288 ret = clk_enable_bulk(&clks);
289 if (ret) {
290 dev_err(dev, "failed to enable clk: %d\n", ret);
291 clk_release_bulk(&clks);
292 return ret;
293 }
294
295 return 0;
296 }
297 #endif
298
rk_pwm_probe(struct udevice * dev)299 static int rk_pwm_probe(struct udevice *dev)
300 {
301 struct rk_pwm_priv *priv = dev_get_priv(dev);
302 struct clk clk;
303 int ret = 0;
304
305 ret = clk_get_by_index(dev, 0, &clk);
306 if (ret < 0) {
307 debug("%s get clock fail!\n", __func__);
308 return -EINVAL;
309 }
310
311 ret = clk_get_rate(&clk);
312 if (ret < 0) {
313 debug("%s pwm get clock rate fail!\n", __func__);
314 return -EINVAL;
315 }
316 priv->freq = ret;
317 priv->data = (struct rockchip_pwm_data *)dev_get_driver_data(dev);
318
319 if (priv->data->supports_polarity) {
320 if (priv->data->main_version >= 4) {
321 priv->conf_polarity = DUTY_POSITIVE | INACTIVE_NEGATIVE;
322 } else {
323 priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE;
324 }
325 }
326
327 #if defined(CONFIG_MOS_SUPPORT) && !defined(CONFIG_SPL_BUILD)
328 ret = rk_pwm_clk_init(dev);
329 if (ret)
330 return ret;
331 #endif
332
333 return 0;
334 }
335
336 static const struct pwm_ops rk_pwm_ops = {
337 .set_invert = rk_pwm_set_invert,
338 .set_config = rk_pwm_set_config,
339 .set_enable = rk_pwm_set_enable,
340 };
341
342 static const struct rockchip_pwm_data pwm_data_v1 = {
343 .main_version = 0x01,
344 .regs = {
345 .version = 0x5c,
346 .duty = 0x04,
347 .period = 0x08,
348 .ctrl = 0x0c,
349 },
350 .prescaler = 2,
351 .supports_polarity = false,
352 .supports_lock = false,
353 .vop_pwm = false,
354 .enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN,
355 .enable_conf_mask = BIT(1) | BIT(3),
356 .funcs = {
357 .set_invert = rk_pwm_set_invert_v1,
358 .set_config = rk_pwm_set_config_v1,
359 .set_enable = rk_pwm_set_enable_v1,
360 },
361 };
362
363 static const struct rockchip_pwm_data pwm_data_v2 = {
364 .main_version = 0x02,
365 .regs = {
366 .version = 0x5c,
367 .duty = 0x08,
368 .period = 0x04,
369 .ctrl = 0x0c,
370 },
371 .prescaler = 1,
372 .supports_polarity = true,
373 .supports_lock = false,
374 .vop_pwm = false,
375 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
376 PWM_CONTINUOUS,
377 .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
378 .funcs = {
379 .set_invert = rk_pwm_set_invert_v1,
380 .set_config = rk_pwm_set_config_v1,
381 .set_enable = rk_pwm_set_enable_v1,
382 },
383 };
384
385 static const struct rockchip_pwm_data pwm_data_vop = {
386 .main_version = 0x02,
387 .regs = {
388 .version = 0x5c,
389 .duty = 0x08,
390 .period = 0x04,
391 .ctrl = 0x00,
392 },
393 .prescaler = 1,
394 .supports_polarity = true,
395 .supports_lock = false,
396 .vop_pwm = true,
397 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
398 PWM_CONTINUOUS,
399 .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
400 .funcs = {
401 .set_invert = rk_pwm_set_invert_v1,
402 .set_config = rk_pwm_set_config_v1,
403 .set_enable = rk_pwm_set_enable_v1,
404 },
405 };
406
407 static const struct rockchip_pwm_data pwm_data_v3 = {
408 .main_version = 0x03,
409 .regs = {
410 .version = 0x5c,
411 .duty = 0x08,
412 .period = 0x04,
413 .ctrl = 0x0c,
414 },
415 .prescaler = 1,
416 .supports_polarity = true,
417 .supports_lock = true,
418 .vop_pwm = false,
419 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
420 PWM_CONTINUOUS,
421 .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
422 .funcs = {
423 .set_invert = rk_pwm_set_invert_v1,
424 .set_config = rk_pwm_set_config_v1,
425 .set_enable = rk_pwm_set_enable_v1,
426 },
427 };
428
429 static const struct rockchip_pwm_data pwm_data_v4 = {
430 .main_version = 0x04,
431 .regs = {
432 .version = 0x0,
433 .enable = 0x4,
434 .ctrl = 0xc,
435 .period = 0x10,
436 .duty = 0x14,
437 },
438 .prescaler = 1,
439 .supports_polarity = true,
440 .supports_lock = true,
441 .vop_pwm = false,
442 .enable_conf = PWM_ENABLE_V4,
443 .funcs = {
444 .set_invert = rk_pwm_set_invert_v4,
445 .set_config = rk_pwm_set_config_v4,
446 .set_enable = rk_pwm_set_enable_v4,
447 },
448 };
449
450 static const struct udevice_id rk_pwm_ids[] = {
451 { .compatible = "rockchip,rk2928-pwm", .data = (ulong)&pwm_data_v1},
452 { .compatible = "rockchip,rk3288-pwm", .data = (ulong)&pwm_data_v2},
453 { .compatible = "rockchip,rk3328-pwm", .data = (ulong)&pwm_data_v3},
454 { .compatible = "rockchip,vop-pwm", .data = (ulong)&pwm_data_vop},
455 { .compatible = "rockchip,rk3399-pwm", .data = (ulong)&pwm_data_v2},
456 { .compatible = "rockchip,rk3576-pwm", .data = (ulong)&pwm_data_v4},
457 { }
458 };
459
460 U_BOOT_DRIVER(rk_pwm) = {
461 .name = "rk_pwm",
462 .id = UCLASS_PWM,
463 .of_match = rk_pwm_ids,
464 .ops = &rk_pwm_ops,
465 .ofdata_to_platdata = rk_pwm_ofdata_to_platdata,
466 .probe = rk_pwm_probe,
467 .priv_auto_alloc_size = sizeof(struct rk_pwm_priv),
468 };
469