xref: /linux/drivers/pwm/pwm-rockchip.c (revision 22c55fb9eb92395d999b8404d73e58540d11bdd8)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * PWM driver for Rockchip SoCs
4  *
5  * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
6  * Copyright (C) 2014 ROCKCHIP, Inc.
7  */
8 
9 #include <linux/clk.h>
10 #include <linux/io.h>
11 #include <linux/limits.h>
12 #include <linux/math64.h>
13 #include <linux/module.h>
14 #include <linux/of.h>
15 #include <linux/platform_device.h>
16 #include <linux/property.h>
17 #include <linux/pwm.h>
18 #include <linux/time.h>
19 
20 #define PWM_CTRL_TIMER_EN	(1 << 0)
21 #define PWM_CTRL_OUTPUT_EN	(1 << 3)
22 
23 #define PWM_ENABLE		(1 << 0)
24 #define PWM_CONTINUOUS		(1 << 1)
25 #define PWM_DUTY_POSITIVE	(1 << 3)
26 #define PWM_DUTY_NEGATIVE	(0 << 3)
27 #define PWM_INACTIVE_NEGATIVE	(0 << 4)
28 #define PWM_INACTIVE_POSITIVE	(1 << 4)
29 #define PWM_POLARITY_MASK	(PWM_DUTY_POSITIVE | PWM_INACTIVE_POSITIVE)
30 #define PWM_OUTPUT_LEFT		(0 << 5)
31 #define PWM_LOCK_EN		(1 << 6)
32 #define PWM_LP_DISABLE		(0 << 8)
33 
34 struct rockchip_pwm_chip {
35 	struct clk *clk;
36 	struct clk *pclk;
37 	const struct rockchip_pwm_data *data;
38 	void __iomem *base;
39 };
40 
41 struct rockchip_pwm_regs {
42 	unsigned long duty;
43 	unsigned long period;
44 	unsigned long cntr;
45 	unsigned long ctrl;
46 };
47 
48 struct rockchip_pwm_data {
49 	struct rockchip_pwm_regs regs;
50 	unsigned int prescaler;
51 	bool supports_polarity;
52 	bool supports_lock;
53 	u32 enable_conf;
54 };
55 
56 static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *chip)
57 {
58 	return pwmchip_get_drvdata(chip);
59 }
60 
61 static int rockchip_pwm_get_state(struct pwm_chip *chip,
62 				  struct pwm_device *pwm,
63 				  struct pwm_state *state)
64 {
65 	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
66 	u64 prescaled_ns = (u64)pc->data->prescaler * NSEC_PER_SEC;
67 	u32 enable_conf = pc->data->enable_conf;
68 	unsigned long clk_rate;
69 	u64 tmp;
70 	u32 val;
71 	int ret;
72 
73 	ret = clk_enable(pc->pclk);
74 	if (ret)
75 		return ret;
76 
77 	ret = clk_enable(pc->clk);
78 	if (ret)
79 		return ret;
80 
81 	clk_rate = clk_get_rate(pc->clk);
82 
83 	tmp = readl_relaxed(pc->base + pc->data->regs.period);
84 	tmp *= prescaled_ns;
85 	state->period = DIV_U64_ROUND_UP(tmp, clk_rate);
86 
87 	tmp = readl_relaxed(pc->base + pc->data->regs.duty);
88 	tmp *= prescaled_ns;
89 	state->duty_cycle =  DIV_U64_ROUND_UP(tmp, clk_rate);
90 
91 	val = readl_relaxed(pc->base + pc->data->regs.ctrl);
92 	state->enabled = (val & enable_conf) == enable_conf;
93 
94 	if (pc->data->supports_polarity && !(val & PWM_DUTY_POSITIVE))
95 		state->polarity = PWM_POLARITY_INVERSED;
96 	else
97 		state->polarity = PWM_POLARITY_NORMAL;
98 
99 	clk_disable(pc->clk);
100 	clk_disable(pc->pclk);
101 
102 	return 0;
103 }
104 
105 static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
106 			       const struct pwm_state *state)
107 {
108 	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
109 	u64 prescaled_ns = (u64)pc->data->prescaler * NSEC_PER_SEC;
110 	u64 clk_rate, tmp;
111 	u32 period_ticks, duty_ticks;
112 	u32 ctrl;
113 
114 	clk_rate = clk_get_rate(pc->clk);
115 
116 	/*
117 	 * Since period and duty cycle registers have a width of 32
118 	 * bits, every possible input period can be obtained using the
119 	 * default prescaler value for all practical clock rate values.
120 	 */
121 	tmp = mul_u64_u64_div_u64(clk_rate, state->period, prescaled_ns);
122 	if (tmp > U32_MAX)
123 		tmp = U32_MAX;
124 	period_ticks = tmp;
125 
126 	tmp = mul_u64_u64_div_u64(clk_rate, state->duty_cycle, prescaled_ns);
127 	if (tmp > U32_MAX)
128 		tmp = U32_MAX;
129 	duty_ticks = tmp;
130 
131 	/*
132 	 * Lock the period and duty of previous configuration, then
133 	 * change the duty and period, that would not be effective.
134 	 */
135 	ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl);
136 	if (pc->data->supports_lock) {
137 		ctrl |= PWM_LOCK_EN;
138 		writel_relaxed(ctrl, pc->base + pc->data->regs.ctrl);
139 	}
140 
141 	writel(period_ticks, pc->base + pc->data->regs.period);
142 	writel(duty_ticks, pc->base + pc->data->regs.duty);
143 
144 	if (pc->data->supports_polarity) {
145 		ctrl &= ~PWM_POLARITY_MASK;
146 		if (state->polarity == PWM_POLARITY_INVERSED)
147 			ctrl |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE;
148 		else
149 			ctrl |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;
150 	}
151 
152 	/*
153 	 * Unlock and set polarity at the same time,
154 	 * the configuration of duty, period and polarity
155 	 * would be effective together at next period.
156 	 */
157 	if (pc->data->supports_lock)
158 		ctrl &= ~PWM_LOCK_EN;
159 
160 	writel(ctrl, pc->base + pc->data->regs.ctrl);
161 }
162 
163 static int rockchip_pwm_enable(struct pwm_chip *chip,
164 			       struct pwm_device *pwm,
165 			       bool enable)
166 {
167 	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
168 	u32 enable_conf = pc->data->enable_conf;
169 	int ret;
170 	u32 val;
171 
172 	if (enable) {
173 		ret = clk_enable(pc->clk);
174 		if (ret)
175 			return ret;
176 	}
177 
178 	val = readl_relaxed(pc->base + pc->data->regs.ctrl);
179 
180 	if (enable)
181 		val |= enable_conf;
182 	else
183 		val &= ~enable_conf;
184 
185 	writel_relaxed(val, pc->base + pc->data->regs.ctrl);
186 
187 	if (!enable)
188 		clk_disable(pc->clk);
189 
190 	return 0;
191 }
192 
193 static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
194 			      const struct pwm_state *state)
195 {
196 	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
197 	struct pwm_state curstate;
198 	bool enabled;
199 	int ret = 0;
200 
201 	ret = clk_enable(pc->pclk);
202 	if (ret)
203 		return ret;
204 
205 	ret = clk_enable(pc->clk);
206 	if (ret)
207 		return ret;
208 
209 	pwm_get_state(pwm, &curstate);
210 	enabled = curstate.enabled;
211 
212 	if (state->polarity != curstate.polarity && enabled &&
213 	    !pc->data->supports_lock) {
214 		ret = rockchip_pwm_enable(chip, pwm, false);
215 		if (ret)
216 			goto out;
217 		enabled = false;
218 	}
219 
220 	rockchip_pwm_config(chip, pwm, state);
221 	if (state->enabled != enabled) {
222 		ret = rockchip_pwm_enable(chip, pwm, state->enabled);
223 		if (ret)
224 			goto out;
225 	}
226 
227 out:
228 	clk_disable(pc->clk);
229 	clk_disable(pc->pclk);
230 
231 	return ret;
232 }
233 
234 static const struct pwm_ops rockchip_pwm_ops = {
235 	.get_state = rockchip_pwm_get_state,
236 	.apply = rockchip_pwm_apply,
237 };
238 
239 static const struct rockchip_pwm_data pwm_data_v1 = {
240 	.regs = {
241 		.duty = 0x04,
242 		.period = 0x08,
243 		.cntr = 0x00,
244 		.ctrl = 0x0c,
245 	},
246 	.prescaler = 2,
247 	.supports_polarity = false,
248 	.supports_lock = false,
249 	.enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN,
250 };
251 
252 static const struct rockchip_pwm_data pwm_data_v2 = {
253 	.regs = {
254 		.duty = 0x08,
255 		.period = 0x04,
256 		.cntr = 0x00,
257 		.ctrl = 0x0c,
258 	},
259 	.prescaler = 1,
260 	.supports_polarity = true,
261 	.supports_lock = false,
262 	.enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
263 		       PWM_CONTINUOUS,
264 };
265 
266 static const struct rockchip_pwm_data pwm_data_vop = {
267 	.regs = {
268 		.duty = 0x08,
269 		.period = 0x04,
270 		.cntr = 0x0c,
271 		.ctrl = 0x00,
272 	},
273 	.prescaler = 1,
274 	.supports_polarity = true,
275 	.supports_lock = false,
276 	.enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
277 		       PWM_CONTINUOUS,
278 };
279 
280 static const struct rockchip_pwm_data pwm_data_v3 = {
281 	.regs = {
282 		.duty = 0x08,
283 		.period = 0x04,
284 		.cntr = 0x00,
285 		.ctrl = 0x0c,
286 	},
287 	.prescaler = 1,
288 	.supports_polarity = true,
289 	.supports_lock = true,
290 	.enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
291 		       PWM_CONTINUOUS,
292 };
293 
294 static const struct of_device_id rockchip_pwm_dt_ids[] = {
295 	{ .compatible = "rockchip,rk2928-pwm", .data = &pwm_data_v1},
296 	{ .compatible = "rockchip,rk3288-pwm", .data = &pwm_data_v2},
297 	{ .compatible = "rockchip,vop-pwm", .data = &pwm_data_vop},
298 	{ .compatible = "rockchip,rk3328-pwm", .data = &pwm_data_v3},
299 	{ /* sentinel */ }
300 };
301 MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);
302 
303 static int rockchip_pwm_probe(struct platform_device *pdev)
304 {
305 	struct pwm_chip *chip;
306 	struct rockchip_pwm_chip *pc;
307 	u32 enable_conf, ctrl;
308 	bool enabled;
309 	int ret, count;
310 
311 	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*pc));
312 	if (IS_ERR(chip))
313 		return PTR_ERR(chip);
314 	pc = to_rockchip_pwm_chip(chip);
315 
316 	pc->base = devm_platform_ioremap_resource(pdev, 0);
317 	if (IS_ERR(pc->base))
318 		return PTR_ERR(pc->base);
319 
320 	pc->clk = devm_clk_get(&pdev->dev, "pwm");
321 	if (IS_ERR(pc->clk)) {
322 		pc->clk = devm_clk_get(&pdev->dev, NULL);
323 		if (IS_ERR(pc->clk))
324 			return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk),
325 					     "Can't get PWM clk\n");
326 	}
327 
328 	count = of_count_phandle_with_args(pdev->dev.of_node,
329 					   "clocks", "#clock-cells");
330 	if (count == 2)
331 		pc->pclk = devm_clk_get(&pdev->dev, "pclk");
332 	else
333 		pc->pclk = pc->clk;
334 
335 	if (IS_ERR(pc->pclk))
336 		return dev_err_probe(&pdev->dev, PTR_ERR(pc->pclk), "Can't get APB clk\n");
337 
338 	ret = clk_prepare_enable(pc->clk);
339 	if (ret)
340 		return dev_err_probe(&pdev->dev, ret, "Can't prepare enable PWM clk\n");
341 
342 	ret = clk_prepare_enable(pc->pclk);
343 	if (ret) {
344 		dev_err_probe(&pdev->dev, ret, "Can't prepare enable APB clk\n");
345 		goto err_clk;
346 	}
347 
348 	platform_set_drvdata(pdev, chip);
349 
350 	pc->data = device_get_match_data(&pdev->dev);
351 	chip->ops = &rockchip_pwm_ops;
352 
353 	enable_conf = pc->data->enable_conf;
354 	ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl);
355 	enabled = (ctrl & enable_conf) == enable_conf;
356 
357 	ret = pwmchip_add(chip);
358 	if (ret < 0) {
359 		dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n");
360 		goto err_pclk;
361 	}
362 
363 	/* Keep the PWM clk enabled if the PWM appears to be up and running. */
364 	if (!enabled)
365 		clk_disable(pc->clk);
366 
367 	clk_disable(pc->pclk);
368 
369 	return 0;
370 
371 err_pclk:
372 	clk_disable_unprepare(pc->pclk);
373 err_clk:
374 	clk_disable_unprepare(pc->clk);
375 
376 	return ret;
377 }
378 
379 static void rockchip_pwm_remove(struct platform_device *pdev)
380 {
381 	struct pwm_chip *chip = platform_get_drvdata(pdev);
382 	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
383 
384 	pwmchip_remove(chip);
385 
386 	clk_unprepare(pc->pclk);
387 	clk_unprepare(pc->clk);
388 }
389 
390 static struct platform_driver rockchip_pwm_driver = {
391 	.driver = {
392 		.name = "rockchip-pwm",
393 		.of_match_table = rockchip_pwm_dt_ids,
394 	},
395 	.probe = rockchip_pwm_probe,
396 	.remove = rockchip_pwm_remove,
397 };
398 module_platform_driver(rockchip_pwm_driver);
399 
400 MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
401 MODULE_DESCRIPTION("Rockchip SoC PWM driver");
402 MODULE_LICENSE("GPL v2");
403