blob: cd6be47b5160575bdc733e3397c931d73a158c7c [file] [log] [blame]
Thomas Gleixnerf50a7f32019-05-28 09:57:18 -07001// SPDX-License-Identifier: GPL-2.0-only
Bo Shen32b16d42013-12-13 14:41:49 +08002/*
3 * Driver for Atmel Pulse Width Modulation Controller
4 *
5 * Copyright (C) 2013 Atmel Corporation
6 * Bo Shen <voice.shen@atmel.com>
Uwe Kleine-König3c269ba2019-08-24 02:10:36 +02007 *
8 * Links to reference manuals for the supported PWM chips can be found in
9 * Documentation/arm/microchip.rst.
Bo Shen32b16d42013-12-13 14:41:49 +080010 */
11
12#include <linux/clk.h>
Alexandre Belloni472ac3d2015-05-25 18:11:49 +020013#include <linux/delay.h>
Bo Shen32b16d42013-12-13 14:41:49 +080014#include <linux/err.h>
15#include <linux/io.h>
16#include <linux/module.h>
Alexandre Belloni472ac3d2015-05-25 18:11:49 +020017#include <linux/mutex.h>
Bo Shen32b16d42013-12-13 14:41:49 +080018#include <linux/of.h>
19#include <linux/of_device.h>
20#include <linux/platform_device.h>
21#include <linux/pwm.h>
22#include <linux/slab.h>
23
24/* The following is global registers for PWM controller */
25#define PWM_ENA 0x04
26#define PWM_DIS 0x08
27#define PWM_SR 0x0C
Alexandre Belloni472ac3d2015-05-25 18:11:49 +020028#define PWM_ISR 0x1C
Bo Shen32b16d42013-12-13 14:41:49 +080029/* Bit field in SR */
30#define PWM_SR_ALL_CH_ON 0x0F
31
32/* The following register is PWM channel related registers */
33#define PWM_CH_REG_OFFSET 0x200
34#define PWM_CH_REG_SIZE 0x20
35
36#define PWM_CMR 0x0
37/* Bit field in CMR */
38#define PWM_CMR_CPOL (1 << 9)
39#define PWM_CMR_UPD_CDTY (1 << 10)
Alexandre Belloni8db9e292014-03-14 15:19:08 +010040#define PWM_CMR_CPRE_MSK 0xF
Bo Shen32b16d42013-12-13 14:41:49 +080041
42/* The following registers for PWM v1 */
43#define PWMV1_CDTY 0x04
44#define PWMV1_CPRD 0x08
45#define PWMV1_CUPD 0x10
46
47/* The following registers for PWM v2 */
48#define PWMV2_CDTY 0x04
49#define PWMV2_CDTYUPD 0x08
50#define PWMV2_CPRD 0x0C
51#define PWMV2_CPRDUPD 0x10
52
Claudiu Beznea1a722aa2017-03-22 15:29:34 +020053struct atmel_pwm_registers {
54 u8 period;
55 u8 period_upd;
56 u8 duty;
57 u8 duty_upd;
58};
59
Claudiu Beznea0285827d2019-02-25 16:44:37 +000060struct atmel_pwm_config {
61 u32 max_period;
62 u32 max_pres;
63};
64
Claudiu Beznea53784152019-02-25 16:44:33 +000065struct atmel_pwm_data {
66 struct atmel_pwm_registers regs;
Claudiu Beznea0285827d2019-02-25 16:44:37 +000067 struct atmel_pwm_config cfg;
Claudiu Beznea53784152019-02-25 16:44:33 +000068};
69
Bo Shen32b16d42013-12-13 14:41:49 +080070struct atmel_pwm_chip {
71 struct pwm_chip chip;
72 struct clk *clk;
73 void __iomem *base;
Claudiu Beznea53784152019-02-25 16:44:33 +000074 const struct atmel_pwm_data *data;
Bo Shen32b16d42013-12-13 14:41:49 +080075
Alexandre Belloni472ac3d2015-05-25 18:11:49 +020076 unsigned int updated_pwms;
Thierry Reding313b78e2016-07-11 12:14:34 +020077 /* ISR is cleared when read, ensure only one thread does that */
78 struct mutex isr_lock;
Bo Shen32b16d42013-12-13 14:41:49 +080079};
80
81static inline struct atmel_pwm_chip *to_atmel_pwm_chip(struct pwm_chip *chip)
82{
83 return container_of(chip, struct atmel_pwm_chip, chip);
84}
85
86static inline u32 atmel_pwm_readl(struct atmel_pwm_chip *chip,
87 unsigned long offset)
88{
89 return readl_relaxed(chip->base + offset);
90}
91
92static inline void atmel_pwm_writel(struct atmel_pwm_chip *chip,
93 unsigned long offset, unsigned long val)
94{
95 writel_relaxed(val, chip->base + offset);
96}
97
98static inline u32 atmel_pwm_ch_readl(struct atmel_pwm_chip *chip,
99 unsigned int ch, unsigned long offset)
100{
101 unsigned long base = PWM_CH_REG_OFFSET + ch * PWM_CH_REG_SIZE;
102
103 return readl_relaxed(chip->base + base + offset);
104}
105
106static inline void atmel_pwm_ch_writel(struct atmel_pwm_chip *chip,
107 unsigned int ch, unsigned long offset,
108 unsigned long val)
109{
110 unsigned long base = PWM_CH_REG_OFFSET + ch * PWM_CH_REG_SIZE;
111
112 writel_relaxed(val, chip->base + base + offset);
113}
114
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200115static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
116 const struct pwm_state *state,
117 unsigned long *cprd, u32 *pres)
Bo Shen32b16d42013-12-13 14:41:49 +0800118{
119 struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200120 unsigned long long cycles = state->period;
Bo Shen32b16d42013-12-13 14:41:49 +0800121
Nikolaus Vosse2e08972014-09-23 15:30:21 +0200122 /* Calculate the period cycles and prescale value */
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200123 cycles *= clk_get_rate(atmel_pwm->clk);
124 do_div(cycles, NSEC_PER_SEC);
Bo Shen32b16d42013-12-13 14:41:49 +0800125
Claudiu Beznea0285827d2019-02-25 16:44:37 +0000126 for (*pres = 0; cycles > atmel_pwm->data->cfg.max_period; cycles >>= 1)
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200127 (*pres)++;
Bo Shen32b16d42013-12-13 14:41:49 +0800128
Claudiu Beznea0285827d2019-02-25 16:44:37 +0000129 if (*pres > atmel_pwm->data->cfg.max_pres) {
Nikolaus Vosse2e08972014-09-23 15:30:21 +0200130 dev_err(chip->dev, "pres exceeds the maximum value\n");
131 return -EINVAL;
Bo Shen32b16d42013-12-13 14:41:49 +0800132 }
133
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200134 *cprd = cycles;
Bo Shen32b16d42013-12-13 14:41:49 +0800135
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200136 return 0;
Bo Shen32b16d42013-12-13 14:41:49 +0800137}
138
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200139static void atmel_pwm_calculate_cdty(const struct pwm_state *state,
140 unsigned long cprd, unsigned long *cdty)
Bo Shen32b16d42013-12-13 14:41:49 +0800141{
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200142 unsigned long long cycles = state->duty_cycle;
Bo Shen32b16d42013-12-13 14:41:49 +0800143
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200144 cycles *= cprd;
145 do_div(cycles, state->period);
146 *cdty = cprd - cycles;
Bo Shen32b16d42013-12-13 14:41:49 +0800147}
148
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200149static void atmel_pwm_update_cdty(struct pwm_chip *chip, struct pwm_device *pwm,
150 unsigned long cdty)
Bo Shen32b16d42013-12-13 14:41:49 +0800151{
152 struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
153 u32 val;
Bo Shen32b16d42013-12-13 14:41:49 +0800154
Claudiu Beznea53784152019-02-25 16:44:33 +0000155 if (atmel_pwm->data->regs.duty_upd ==
156 atmel_pwm->data->regs.period_upd) {
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200157 val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR);
158 val &= ~PWM_CMR_UPD_CDTY;
159 atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val);
Bo Shen32b16d42013-12-13 14:41:49 +0800160 }
161
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200162 atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm,
Claudiu Beznea53784152019-02-25 16:44:33 +0000163 atmel_pwm->data->regs.duty_upd, cdty);
Bo Shen32b16d42013-12-13 14:41:49 +0800164}
165
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200166static void atmel_pwm_set_cprd_cdty(struct pwm_chip *chip,
167 struct pwm_device *pwm,
168 unsigned long cprd, unsigned long cdty)
Bo Shen32b16d42013-12-13 14:41:49 +0800169{
170 struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
Bo Shen32b16d42013-12-13 14:41:49 +0800171
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200172 atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm,
Claudiu Beznea53784152019-02-25 16:44:33 +0000173 atmel_pwm->data->regs.duty, cdty);
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200174 atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm,
Claudiu Beznea53784152019-02-25 16:44:33 +0000175 atmel_pwm->data->regs.period, cprd);
Bo Shen32b16d42013-12-13 14:41:49 +0800176}
177
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200178static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm,
179 bool disable_clk)
Bo Shen32b16d42013-12-13 14:41:49 +0800180{
181 struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
Alexandre Belloni472ac3d2015-05-25 18:11:49 +0200182 unsigned long timeout = jiffies + 2 * HZ;
Bo Shen32b16d42013-12-13 14:41:49 +0800183
Alexandre Belloni472ac3d2015-05-25 18:11:49 +0200184 /*
185 * Wait for at least a complete period to have passed before disabling a
186 * channel to be sure that CDTY has been updated
187 */
188 mutex_lock(&atmel_pwm->isr_lock);
189 atmel_pwm->updated_pwms |= atmel_pwm_readl(atmel_pwm, PWM_ISR);
190
191 while (!(atmel_pwm->updated_pwms & (1 << pwm->hwpwm)) &&
192 time_before(jiffies, timeout)) {
193 usleep_range(10, 100);
194 atmel_pwm->updated_pwms |= atmel_pwm_readl(atmel_pwm, PWM_ISR);
195 }
196
197 mutex_unlock(&atmel_pwm->isr_lock);
Bo Shen32b16d42013-12-13 14:41:49 +0800198 atmel_pwm_writel(atmel_pwm, PWM_DIS, 1 << pwm->hwpwm);
199
Guillermo Rodriguezf718c542016-05-13 13:09:37 +0200200 /*
201 * Wait for the PWM channel disable operation to be effective before
202 * stopping the clock.
203 */
204 timeout = jiffies + 2 * HZ;
205
206 while ((atmel_pwm_readl(atmel_pwm, PWM_SR) & (1 << pwm->hwpwm)) &&
207 time_before(jiffies, timeout))
208 usleep_range(10, 100);
209
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200210 if (disable_clk)
211 clk_disable(atmel_pwm->clk);
212}
213
214static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
Uwe Kleine-König71523d12019-08-24 17:37:07 +0200215 const struct pwm_state *state)
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200216{
217 struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
218 struct pwm_state cstate;
219 unsigned long cprd, cdty;
220 u32 pres, val;
221 int ret;
222
223 pwm_get_state(pwm, &cstate);
224
225 if (state->enabled) {
226 if (cstate.enabled &&
227 cstate.polarity == state->polarity &&
228 cstate.period == state->period) {
229 cprd = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm,
Claudiu Beznea53784152019-02-25 16:44:33 +0000230 atmel_pwm->data->regs.period);
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200231 atmel_pwm_calculate_cdty(state, cprd, &cdty);
232 atmel_pwm_update_cdty(chip, pwm, cdty);
233 return 0;
234 }
235
236 ret = atmel_pwm_calculate_cprd_and_pres(chip, state, &cprd,
237 &pres);
238 if (ret) {
239 dev_err(chip->dev,
240 "failed to calculate cprd and prescaler\n");
241 return ret;
242 }
243
244 atmel_pwm_calculate_cdty(state, cprd, &cdty);
245
246 if (cstate.enabled) {
247 atmel_pwm_disable(chip, pwm, false);
248 } else {
249 ret = clk_enable(atmel_pwm->clk);
250 if (ret) {
251 dev_err(chip->dev, "failed to enable clock\n");
252 return ret;
253 }
254 }
255
256 /* It is necessary to preserve CPOL, inside CMR */
257 val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR);
258 val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK);
259 if (state->polarity == PWM_POLARITY_NORMAL)
260 val &= ~PWM_CMR_CPOL;
261 else
262 val |= PWM_CMR_CPOL;
263 atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val);
264 atmel_pwm_set_cprd_cdty(chip, pwm, cprd, cdty);
265 mutex_lock(&atmel_pwm->isr_lock);
266 atmel_pwm->updated_pwms |= atmel_pwm_readl(atmel_pwm, PWM_ISR);
267 atmel_pwm->updated_pwms &= ~(1 << pwm->hwpwm);
268 mutex_unlock(&atmel_pwm->isr_lock);
269 atmel_pwm_writel(atmel_pwm, PWM_ENA, 1 << pwm->hwpwm);
270 } else if (cstate.enabled) {
271 atmel_pwm_disable(chip, pwm, true);
272 }
273
274 return 0;
Bo Shen32b16d42013-12-13 14:41:49 +0800275}
276
277static const struct pwm_ops atmel_pwm_ops = {
Claudiu Beznea1a722aa2017-03-22 15:29:34 +0200278 .apply = atmel_pwm_apply,
Bo Shen32b16d42013-12-13 14:41:49 +0800279 .owner = THIS_MODULE,
280};
281
Claudiu Bezneaabcbe372019-02-25 16:44:41 +0000282static const struct atmel_pwm_data atmel_sam9rl_pwm_data = {
Claudiu Beznea53784152019-02-25 16:44:33 +0000283 .regs = {
284 .period = PWMV1_CPRD,
285 .period_upd = PWMV1_CUPD,
286 .duty = PWMV1_CDTY,
287 .duty_upd = PWMV1_CUPD,
288 },
Claudiu Beznea0285827d2019-02-25 16:44:37 +0000289 .cfg = {
290 /* 16 bits to keep period and duty. */
Thierry Redingd7d96312019-03-04 12:10:29 +0100291 .max_period = 0xffff,
292 .max_pres = 10,
Claudiu Beznea0285827d2019-02-25 16:44:37 +0000293 },
Bo Shen32b16d42013-12-13 14:41:49 +0800294};
295
Claudiu Bezneaabcbe372019-02-25 16:44:41 +0000296static const struct atmel_pwm_data atmel_sama5_pwm_data = {
Claudiu Beznea53784152019-02-25 16:44:33 +0000297 .regs = {
298 .period = PWMV2_CPRD,
299 .period_upd = PWMV2_CPRDUPD,
300 .duty = PWMV2_CDTY,
301 .duty_upd = PWMV2_CDTYUPD,
302 },
Claudiu Beznea0285827d2019-02-25 16:44:37 +0000303 .cfg = {
304 /* 16 bits to keep period and duty. */
Thierry Redingd7d96312019-03-04 12:10:29 +0100305 .max_period = 0xffff,
306 .max_pres = 10,
Claudiu Beznea0285827d2019-02-25 16:44:37 +0000307 },
Bo Shen32b16d42013-12-13 14:41:49 +0800308};
309
Claudiu Beznea74d0c3b2019-02-25 16:44:45 +0000310static const struct atmel_pwm_data mchp_sam9x60_pwm_data = {
311 .regs = {
312 .period = PWMV1_CPRD,
313 .period_upd = PWMV1_CUPD,
314 .duty = PWMV1_CDTY,
315 .duty_upd = PWMV1_CUPD,
316 },
317 .cfg = {
318 /* 32 bits to keep period and duty. */
Thierry Redingd7d96312019-03-04 12:10:29 +0100319 .max_period = 0xffffffff,
320 .max_pres = 10,
Claudiu Beznea74d0c3b2019-02-25 16:44:45 +0000321 },
322};
323
Bo Shen32b16d42013-12-13 14:41:49 +0800324static const struct of_device_id atmel_pwm_dt_ids[] = {
325 {
326 .compatible = "atmel,at91sam9rl-pwm",
Claudiu Bezneaabcbe372019-02-25 16:44:41 +0000327 .data = &atmel_sam9rl_pwm_data,
Bo Shen32b16d42013-12-13 14:41:49 +0800328 }, {
329 .compatible = "atmel,sama5d3-pwm",
Claudiu Bezneaabcbe372019-02-25 16:44:41 +0000330 .data = &atmel_sama5_pwm_data,
Bo Shen32b16d42013-12-13 14:41:49 +0800331 }, {
Claudiu Beznea44521af2017-03-22 15:29:35 +0200332 .compatible = "atmel,sama5d2-pwm",
Claudiu Bezneaabcbe372019-02-25 16:44:41 +0000333 .data = &atmel_sama5_pwm_data,
Claudiu Beznea44521af2017-03-22 15:29:35 +0200334 }, {
Claudiu Beznea74d0c3b2019-02-25 16:44:45 +0000335 .compatible = "microchip,sam9x60-pwm",
336 .data = &mchp_sam9x60_pwm_data,
337 }, {
Bo Shen32b16d42013-12-13 14:41:49 +0800338 /* sentinel */
339 },
340};
341MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids);
342
Bo Shen32b16d42013-12-13 14:41:49 +0800343static int atmel_pwm_probe(struct platform_device *pdev)
344{
Bo Shen32b16d42013-12-13 14:41:49 +0800345 struct atmel_pwm_chip *atmel_pwm;
346 struct resource *res;
347 int ret;
348
Bo Shen32b16d42013-12-13 14:41:49 +0800349 atmel_pwm = devm_kzalloc(&pdev->dev, sizeof(*atmel_pwm), GFP_KERNEL);
350 if (!atmel_pwm)
351 return -ENOMEM;
352
Thierry Reding9193c162019-09-21 01:58:58 +0200353 mutex_init(&atmel_pwm->isr_lock);
Thierry Redingd85b9ce2019-09-21 01:55:48 +0200354 atmel_pwm->data = of_device_get_match_data(&pdev->dev);
Thierry Reding9193c162019-09-21 01:58:58 +0200355 atmel_pwm->updated_pwms = 0;
Thierry Redingd85b9ce2019-09-21 01:55:48 +0200356
Bo Shen32b16d42013-12-13 14:41:49 +0800357 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
358 atmel_pwm->base = devm_ioremap_resource(&pdev->dev, res);
359 if (IS_ERR(atmel_pwm->base))
360 return PTR_ERR(atmel_pwm->base);
361
362 atmel_pwm->clk = devm_clk_get(&pdev->dev, NULL);
363 if (IS_ERR(atmel_pwm->clk))
364 return PTR_ERR(atmel_pwm->clk);
365
366 ret = clk_prepare(atmel_pwm->clk);
367 if (ret) {
368 dev_err(&pdev->dev, "failed to prepare PWM clock\n");
369 return ret;
370 }
371
372 atmel_pwm->chip.dev = &pdev->dev;
373 atmel_pwm->chip.ops = &atmel_pwm_ops;
Kamel Bouhara3d4d8572019-09-18 16:57:16 +0200374 atmel_pwm->chip.of_xlate = of_pwm_xlate_with_flags;
375 atmel_pwm->chip.of_pwm_n_cells = 3;
Bo Shen32b16d42013-12-13 14:41:49 +0800376 atmel_pwm->chip.base = -1;
377 atmel_pwm->chip.npwm = 4;
Bo Shen32b16d42013-12-13 14:41:49 +0800378
379 ret = pwmchip_add(&atmel_pwm->chip);
380 if (ret < 0) {
381 dev_err(&pdev->dev, "failed to add PWM chip %d\n", ret);
382 goto unprepare_clk;
383 }
384
385 platform_set_drvdata(pdev, atmel_pwm);
386
Bo Shen6a683352013-12-19 11:42:22 +0800387 return ret;
388
Bo Shen32b16d42013-12-13 14:41:49 +0800389unprepare_clk:
390 clk_unprepare(atmel_pwm->clk);
391 return ret;
392}
393
394static int atmel_pwm_remove(struct platform_device *pdev)
395{
396 struct atmel_pwm_chip *atmel_pwm = platform_get_drvdata(pdev);
397
398 clk_unprepare(atmel_pwm->clk);
Alexandre Belloni472ac3d2015-05-25 18:11:49 +0200399 mutex_destroy(&atmel_pwm->isr_lock);
Bo Shen32b16d42013-12-13 14:41:49 +0800400
401 return pwmchip_remove(&atmel_pwm->chip);
402}
403
404static struct platform_driver atmel_pwm_driver = {
405 .driver = {
406 .name = "atmel-pwm",
407 .of_match_table = of_match_ptr(atmel_pwm_dt_ids),
408 },
Bo Shen32b16d42013-12-13 14:41:49 +0800409 .probe = atmel_pwm_probe,
410 .remove = atmel_pwm_remove,
411};
412module_platform_driver(atmel_pwm_driver);
413
414MODULE_ALIAS("platform:atmel-pwm");
415MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>");
416MODULE_DESCRIPTION("Atmel PWM driver");
417MODULE_LICENSE("GPL v2");