xref: /rk3399_rockchip-uboot/drivers/pwm/rk_pwm.c (revision d50ae2019e8c020d508dcfe7bf68a933dbd70e9e)
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 
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 = PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE;
98 	else
99 		priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE;
100 
101 	return 0;
102 }
103 
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 
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 
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 
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 
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 
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 
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 
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 
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 static int rk_pwm_probe(struct udevice *dev)
275 {
276 	struct rk_pwm_priv *priv = dev_get_priv(dev);
277 	struct clk clk;
278 	int ret = 0;
279 
280 	ret = clk_get_by_index(dev, 0, &clk);
281 	if (ret < 0) {
282 		debug("%s get clock fail!\n", __func__);
283 		return -EINVAL;
284 	}
285 
286 	ret = clk_get_rate(&clk);
287 	if (ret < 0) {
288 		debug("%s pwm get clock rate fail!\n", __func__);
289 		return -EINVAL;
290 	}
291 	priv->freq = ret;
292 	priv->data = (struct rockchip_pwm_data *)dev_get_driver_data(dev);
293 
294 	if (priv->data->supports_polarity)
295 		priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE;
296 
297 	return 0;
298 }
299 
300 static const struct pwm_ops rk_pwm_ops = {
301 	.set_invert	= rk_pwm_set_invert,
302 	.set_config	= rk_pwm_set_config,
303 	.set_enable	= rk_pwm_set_enable,
304 };
305 
306 static const struct rockchip_pwm_data pwm_data_v1 = {
307 	.main_version = 0x01,
308 	.regs = {
309 		.version = 0x5c,
310 		.duty = 0x04,
311 		.period = 0x08,
312 		.ctrl = 0x0c,
313 	},
314 	.prescaler = 2,
315 	.supports_polarity = false,
316 	.supports_lock = false,
317 	.vop_pwm = false,
318 	.enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN,
319 	.enable_conf_mask = BIT(1) | BIT(3),
320 	.funcs = {
321 		.set_invert = rk_pwm_set_invert_v1,
322 		.set_config = rk_pwm_set_config_v1,
323 		.set_enable = rk_pwm_set_enable_v1,
324 	},
325 };
326 
327 static const struct rockchip_pwm_data pwm_data_v2 = {
328 	.main_version = 0x02,
329 	.regs = {
330 		.version = 0x5c,
331 		.duty = 0x08,
332 		.period = 0x04,
333 		.ctrl = 0x0c,
334 	},
335 	.prescaler = 1,
336 	.supports_polarity = true,
337 	.supports_lock = false,
338 	.vop_pwm = false,
339 	.enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
340 		       PWM_CONTINUOUS,
341 	.enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
342 	.funcs = {
343 		.set_invert = rk_pwm_set_invert_v1,
344 		.set_config = rk_pwm_set_config_v1,
345 		.set_enable = rk_pwm_set_enable_v1,
346 	},
347 };
348 
349 static const struct rockchip_pwm_data pwm_data_vop = {
350 	.main_version = 0x02,
351 	.regs = {
352 		.version = 0x5c,
353 		.duty = 0x08,
354 		.period = 0x04,
355 		.ctrl = 0x00,
356 	},
357 	.prescaler = 1,
358 	.supports_polarity = true,
359 	.supports_lock = false,
360 	.vop_pwm = true,
361 	.enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
362 		       PWM_CONTINUOUS,
363 	.enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
364 	.funcs = {
365 		.set_invert = rk_pwm_set_invert_v1,
366 		.set_config = rk_pwm_set_config_v1,
367 		.set_enable = rk_pwm_set_enable_v1,
368 	},
369 };
370 
371 static const struct rockchip_pwm_data pwm_data_v3 = {
372 	.main_version = 0x03,
373 	.regs = {
374 		.version = 0x5c,
375 		.duty = 0x08,
376 		.period = 0x04,
377 		.ctrl = 0x0c,
378 	},
379 	.prescaler = 1,
380 	.supports_polarity = true,
381 	.supports_lock = true,
382 	.vop_pwm = false,
383 	.enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
384 		       PWM_CONTINUOUS,
385 	.enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
386 	.funcs = {
387 		.set_invert = rk_pwm_set_invert_v1,
388 		.set_config = rk_pwm_set_config_v1,
389 		.set_enable = rk_pwm_set_enable_v1,
390 	},
391 };
392 
393 static const struct rockchip_pwm_data pwm_data_v4 = {
394 	.main_version = 0x04,
395 	.regs = {
396 		.version = 0x0,
397 		.enable = 0x4,
398 		.ctrl = 0xc,
399 		.period = 0x10,
400 		.duty = 0x14,
401 	},
402 	.prescaler = 1,
403 	.supports_polarity = true,
404 	.supports_lock = true,
405 	.vop_pwm = false,
406 	.enable_conf = PWM_ENABLE_V4,
407 	.funcs = {
408 		.set_invert = rk_pwm_set_invert_v4,
409 		.set_config = rk_pwm_set_config_v4,
410 		.set_enable = rk_pwm_set_enable_v4,
411 	},
412 };
413 
414 static const struct udevice_id rk_pwm_ids[] = {
415 	{ .compatible = "rockchip,rk2928-pwm", .data = (ulong)&pwm_data_v1},
416 	{ .compatible = "rockchip,rk3288-pwm", .data = (ulong)&pwm_data_v2},
417 	{ .compatible = "rockchip,rk3328-pwm", .data = (ulong)&pwm_data_v3},
418 	{ .compatible = "rockchip,vop-pwm", .data = (ulong)&pwm_data_vop},
419 	{ .compatible = "rockchip,rk3399-pwm", .data = (ulong)&pwm_data_v2},
420 	{ .compatible = "rockchip,rk3576-pwm", .data = (ulong)&pwm_data_v4},
421 	{ }
422 };
423 
424 U_BOOT_DRIVER(rk_pwm) = {
425 	.name	= "rk_pwm",
426 	.id	= UCLASS_PWM,
427 	.of_match = rk_pwm_ids,
428 	.ops	= &rk_pwm_ops,
429 	.ofdata_to_platdata	= rk_pwm_ofdata_to_platdata,
430 	.probe		= rk_pwm_probe,
431 	.priv_auto_alloc_size	= sizeof(struct rk_pwm_priv),
432 };
433