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
to_rockchip_pwm_chip(struct pwm_chip * chip)56 static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *chip)
57 {
58 return pwmchip_get_drvdata(chip);
59 }
60
rockchip_pwm_get_state(struct pwm_chip * chip,struct pwm_device * pwm,struct pwm_state * state)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
rockchip_pwm_config(struct pwm_chip * chip,struct pwm_device * pwm,const struct pwm_state * state)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
rockchip_pwm_enable(struct pwm_chip * chip,struct pwm_device * pwm,bool enable)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
rockchip_pwm_apply(struct pwm_chip * chip,struct pwm_device * pwm,const struct pwm_state * state)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
rockchip_pwm_probe(struct platform_device * pdev)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
rockchip_pwm_remove(struct platform_device * pdev)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