]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/pwm/pwm-sun4i.c
pwm: sun4i: Improve hardware read out
[mirror_ubuntu-bionic-kernel.git] / drivers / pwm / pwm-sun4i.c
CommitLineData
09853ce7
AB
1/*
2 * Driver for Allwinner sun4i Pulse Width Modulation Controller
3 *
4 * Copyright (C) 2014 Alexandre Belloni <alexandre.belloni@free-electrons.com>
5 *
6 * Licensed under GPLv2.
7 */
8
9#include <linux/bitops.h>
10#include <linux/clk.h>
11#include <linux/err.h>
12#include <linux/io.h>
13#include <linux/module.h>
14#include <linux/of.h>
15#include <linux/of_device.h>
16#include <linux/platform_device.h>
17#include <linux/pwm.h>
18#include <linux/slab.h>
19#include <linux/spinlock.h>
20#include <linux/time.h>
21
22#define PWM_CTRL_REG 0x0
23
24#define PWM_CH_PRD_BASE 0x4
25#define PWM_CH_PRD_OFFSET 0x4
26#define PWM_CH_PRD(ch) (PWM_CH_PRD_BASE + PWM_CH_PRD_OFFSET * (ch))
27
28#define PWMCH_OFFSET 15
29#define PWM_PRESCAL_MASK GENMASK(3, 0)
30#define PWM_PRESCAL_OFF 0
31#define PWM_EN BIT(4)
32#define PWM_ACT_STATE BIT(5)
33#define PWM_CLK_GATING BIT(6)
34#define PWM_MODE BIT(7)
35#define PWM_PULSE BIT(8)
36#define PWM_BYPASS BIT(9)
37
38#define PWM_RDY_BASE 28
39#define PWM_RDY_OFFSET 1
40#define PWM_RDY(ch) BIT(PWM_RDY_BASE + PWM_RDY_OFFSET * (ch))
41
42#define PWM_PRD(prd) (((prd) - 1) << 16)
43#define PWM_PRD_MASK GENMASK(15, 0)
44
45#define PWM_DTY_MASK GENMASK(15, 0)
46
93e0dfb2
AB
47#define PWM_REG_PRD(reg) ((((reg) >> 16) & PWM_PRD_MASK) + 1)
48#define PWM_REG_DTY(reg) ((reg) & PWM_DTY_MASK)
49#define PWM_REG_PRESCAL(reg, chan) (((reg) >> ((chan) * PWMCH_OFFSET)) & PWM_PRESCAL_MASK)
50
09853ce7
AB
51#define BIT_CH(bit, chan) ((bit) << ((chan) * PWMCH_OFFSET))
52
53static const u32 prescaler_table[] = {
54 120,
55 180,
56 240,
57 360,
58 480,
59 0,
60 0,
61 0,
62 12000,
63 24000,
64 36000,
65 48000,
66 72000,
67 0,
68 0,
69 0, /* Actually 1 but tested separately */
70};
71
72struct sun4i_pwm_data {
73 bool has_prescaler_bypass;
74 bool has_rdy;
f6649f7a 75 unsigned int npwm;
09853ce7
AB
76};
77
78struct sun4i_pwm_chip {
79 struct pwm_chip chip;
80 struct clk *clk;
81 void __iomem *base;
82 spinlock_t ctrl_lock;
83 const struct sun4i_pwm_data *data;
84};
85
86static inline struct sun4i_pwm_chip *to_sun4i_pwm_chip(struct pwm_chip *chip)
87{
88 return container_of(chip, struct sun4i_pwm_chip, chip);
89}
90
91static inline u32 sun4i_pwm_readl(struct sun4i_pwm_chip *chip,
92 unsigned long offset)
93{
94 return readl(chip->base + offset);
95}
96
97static inline void sun4i_pwm_writel(struct sun4i_pwm_chip *chip,
98 u32 val, unsigned long offset)
99{
100 writel(val, chip->base + offset);
101}
102
93e0dfb2
AB
103static void sun4i_pwm_get_state(struct pwm_chip *chip,
104 struct pwm_device *pwm,
105 struct pwm_state *state)
106{
107 struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
108 u64 clk_rate, tmp;
109 u32 val;
110 unsigned int prescaler;
111
112 clk_rate = clk_get_rate(sun4i_pwm->clk);
113
114 val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
115
116 if ((val == PWM_PRESCAL_MASK) && sun4i_pwm->data->has_prescaler_bypass)
117 prescaler = 1;
118 else
119 prescaler = prescaler_table[PWM_REG_PRESCAL(val, pwm->hwpwm)];
120
121 if (prescaler == 0)
122 return;
123
124 if (val & BIT_CH(PWM_ACT_STATE, pwm->hwpwm))
125 state->polarity = PWM_POLARITY_NORMAL;
126 else
127 state->polarity = PWM_POLARITY_INVERSED;
128
129 if (val & BIT_CH(PWM_CLK_GATING | PWM_EN, pwm->hwpwm))
130 state->enabled = true;
131 else
132 state->enabled = false;
133
134 val = sun4i_pwm_readl(sun4i_pwm, PWM_CH_PRD(pwm->hwpwm));
135
136 tmp = prescaler * NSEC_PER_SEC * PWM_REG_DTY(val);
137 state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
138
139 tmp = prescaler * NSEC_PER_SEC * PWM_REG_PRD(val);
140 state->period = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
141}
142
09853ce7
AB
143static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
144 int duty_ns, int period_ns)
145{
146 struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
147 u32 prd, dty, val, clk_gate;
148 u64 clk_rate, div = 0;
149 unsigned int prescaler = 0;
150 int err;
151
152 clk_rate = clk_get_rate(sun4i_pwm->clk);
153
154 if (sun4i_pwm->data->has_prescaler_bypass) {
155 /* First, test without any prescaler when available */
156 prescaler = PWM_PRESCAL_MASK;
157 /*
158 * When not using any prescaler, the clock period in nanoseconds
159 * is not an integer so round it half up instead of
160 * truncating to get less surprising values.
161 */
5dcd7b42 162 div = clk_rate * period_ns + NSEC_PER_SEC / 2;
09853ce7
AB
163 do_div(div, NSEC_PER_SEC);
164 if (div - 1 > PWM_PRD_MASK)
165 prescaler = 0;
166 }
167
168 if (prescaler == 0) {
169 /* Go up from the first divider */
170 for (prescaler = 0; prescaler < PWM_PRESCAL_MASK; prescaler++) {
171 if (!prescaler_table[prescaler])
172 continue;
173 div = clk_rate;
174 do_div(div, prescaler_table[prescaler]);
175 div = div * period_ns;
176 do_div(div, NSEC_PER_SEC);
177 if (div - 1 <= PWM_PRD_MASK)
178 break;
179 }
180
181 if (div - 1 > PWM_PRD_MASK) {
182 dev_err(chip->dev, "period exceeds the maximum value\n");
183 return -EINVAL;
184 }
185 }
186
187 prd = div;
188 div *= duty_ns;
189 do_div(div, period_ns);
190 dty = div;
191
192 err = clk_prepare_enable(sun4i_pwm->clk);
193 if (err) {
194 dev_err(chip->dev, "failed to enable PWM clock\n");
195 return err;
196 }
197
198 spin_lock(&sun4i_pwm->ctrl_lock);
199 val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
200
201 if (sun4i_pwm->data->has_rdy && (val & PWM_RDY(pwm->hwpwm))) {
202 spin_unlock(&sun4i_pwm->ctrl_lock);
203 clk_disable_unprepare(sun4i_pwm->clk);
204 return -EBUSY;
205 }
206
207 clk_gate = val & BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
208 if (clk_gate) {
209 val &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
210 sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
211 }
212
213 val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
214 val &= ~BIT_CH(PWM_PRESCAL_MASK, pwm->hwpwm);
215 val |= BIT_CH(prescaler, pwm->hwpwm);
216 sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
217
218 val = (dty & PWM_DTY_MASK) | PWM_PRD(prd);
219 sun4i_pwm_writel(sun4i_pwm, val, PWM_CH_PRD(pwm->hwpwm));
220
221 if (clk_gate) {
222 val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
223 val |= clk_gate;
224 sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
225 }
226
227 spin_unlock(&sun4i_pwm->ctrl_lock);
228 clk_disable_unprepare(sun4i_pwm->clk);
229
230 return 0;
231}
232
233static int sun4i_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
234 enum pwm_polarity polarity)
235{
236 struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
237 u32 val;
238 int ret;
239
240 ret = clk_prepare_enable(sun4i_pwm->clk);
241 if (ret) {
242 dev_err(chip->dev, "failed to enable PWM clock\n");
243 return ret;
244 }
245
246 spin_lock(&sun4i_pwm->ctrl_lock);
247 val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
248
249 if (polarity != PWM_POLARITY_NORMAL)
250 val &= ~BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
251 else
252 val |= BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
253
254 sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
255
256 spin_unlock(&sun4i_pwm->ctrl_lock);
257 clk_disable_unprepare(sun4i_pwm->clk);
258
259 return 0;
260}
261
262static int sun4i_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
263{
264 struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
265 u32 val;
266 int ret;
267
268 ret = clk_prepare_enable(sun4i_pwm->clk);
269 if (ret) {
270 dev_err(chip->dev, "failed to enable PWM clock\n");
271 return ret;
272 }
273
274 spin_lock(&sun4i_pwm->ctrl_lock);
275 val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
276 val |= BIT_CH(PWM_EN, pwm->hwpwm);
277 val |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
278 sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
279 spin_unlock(&sun4i_pwm->ctrl_lock);
280
281 return 0;
282}
283
284static void sun4i_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
285{
286 struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
287 u32 val;
288
289 spin_lock(&sun4i_pwm->ctrl_lock);
290 val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
291 val &= ~BIT_CH(PWM_EN, pwm->hwpwm);
292 val &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
293 sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
294 spin_unlock(&sun4i_pwm->ctrl_lock);
295
296 clk_disable_unprepare(sun4i_pwm->clk);
297}
298
299static const struct pwm_ops sun4i_pwm_ops = {
300 .config = sun4i_pwm_config,
301 .set_polarity = sun4i_pwm_set_polarity,
302 .enable = sun4i_pwm_enable,
303 .disable = sun4i_pwm_disable,
93e0dfb2 304 .get_state = sun4i_pwm_get_state,
09853ce7
AB
305 .owner = THIS_MODULE,
306};
307
308static const struct sun4i_pwm_data sun4i_pwm_data_a10 = {
309 .has_prescaler_bypass = false,
310 .has_rdy = false,
f6649f7a
HG
311 .npwm = 2,
312};
313
314static const struct sun4i_pwm_data sun4i_pwm_data_a10s = {
315 .has_prescaler_bypass = true,
316 .has_rdy = true,
317 .npwm = 2,
318};
319
320static const struct sun4i_pwm_data sun4i_pwm_data_a13 = {
321 .has_prescaler_bypass = true,
322 .has_rdy = true,
323 .npwm = 1,
09853ce7
AB
324};
325
326static const struct sun4i_pwm_data sun4i_pwm_data_a20 = {
327 .has_prescaler_bypass = true,
328 .has_rdy = true,
f6649f7a 329 .npwm = 2,
09853ce7
AB
330};
331
42ddcf4f
MK
332static const struct sun4i_pwm_data sun4i_pwm_data_h3 = {
333 .has_prescaler_bypass = true,
334 .has_rdy = true,
335 .npwm = 1,
336};
337
09853ce7
AB
338static const struct of_device_id sun4i_pwm_dt_ids[] = {
339 {
340 .compatible = "allwinner,sun4i-a10-pwm",
341 .data = &sun4i_pwm_data_a10,
f6649f7a
HG
342 }, {
343 .compatible = "allwinner,sun5i-a10s-pwm",
344 .data = &sun4i_pwm_data_a10s,
345 }, {
346 .compatible = "allwinner,sun5i-a13-pwm",
347 .data = &sun4i_pwm_data_a13,
09853ce7
AB
348 }, {
349 .compatible = "allwinner,sun7i-a20-pwm",
350 .data = &sun4i_pwm_data_a20,
42ddcf4f
MK
351 }, {
352 .compatible = "allwinner,sun8i-h3-pwm",
353 .data = &sun4i_pwm_data_h3,
09853ce7
AB
354 }, {
355 /* sentinel */
356 },
357};
358MODULE_DEVICE_TABLE(of, sun4i_pwm_dt_ids);
359
360static int sun4i_pwm_probe(struct platform_device *pdev)
361{
362 struct sun4i_pwm_chip *pwm;
363 struct resource *res;
93e0dfb2 364 int ret;
09853ce7
AB
365 const struct of_device_id *match;
366
367 match = of_match_device(sun4i_pwm_dt_ids, &pdev->dev);
368
369 pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
370 if (!pwm)
371 return -ENOMEM;
372
373 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
374 pwm->base = devm_ioremap_resource(&pdev->dev, res);
375 if (IS_ERR(pwm->base))
376 return PTR_ERR(pwm->base);
377
378 pwm->clk = devm_clk_get(&pdev->dev, NULL);
379 if (IS_ERR(pwm->clk))
380 return PTR_ERR(pwm->clk);
381
f6649f7a 382 pwm->data = match->data;
09853ce7
AB
383 pwm->chip.dev = &pdev->dev;
384 pwm->chip.ops = &sun4i_pwm_ops;
385 pwm->chip.base = -1;
f6649f7a 386 pwm->chip.npwm = pwm->data->npwm;
09853ce7
AB
387 pwm->chip.of_xlate = of_pwm_xlate_with_flags;
388 pwm->chip.of_pwm_n_cells = 3;
09853ce7
AB
389
390 spin_lock_init(&pwm->ctrl_lock);
391
392 ret = pwmchip_add(&pwm->chip);
393 if (ret < 0) {
394 dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
395 return ret;
396 }
397
398 platform_set_drvdata(pdev, pwm);
399
09853ce7 400 return 0;
09853ce7
AB
401}
402
403static int sun4i_pwm_remove(struct platform_device *pdev)
404{
405 struct sun4i_pwm_chip *pwm = platform_get_drvdata(pdev);
406
407 return pwmchip_remove(&pwm->chip);
408}
409
410static struct platform_driver sun4i_pwm_driver = {
411 .driver = {
412 .name = "sun4i-pwm",
413 .of_match_table = sun4i_pwm_dt_ids,
414 },
415 .probe = sun4i_pwm_probe,
416 .remove = sun4i_pwm_remove,
417};
418module_platform_driver(sun4i_pwm_driver);
419
420MODULE_ALIAS("platform:sun4i-pwm");
421MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
422MODULE_DESCRIPTION("Allwinner sun4i PWM driver");
423MODULE_LICENSE("GPL v2");