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