xref: /rk3399_rockchip-uboot/drivers/pwm/rk_pwm.c (revision 9424aa84b318a57cb7eb53885893f9b601cf427d)
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