summaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-imx.c
diff options
context:
space:
mode:
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>2019-01-07 14:53:52 -0500
committerThierry Reding <thierry.reding@gmail.com>2019-01-16 02:45:33 -0500
commitd80f8206905c1a8c3857d90f12bbfd6293b48a4b (patch)
treea41575aea576d5f2c02c1b979d0ebf2e29ccb872 /drivers/pwm/pwm-imx.c
parentb9a5c60bc2f65561535dc05d0c740aa6e9e3bdf2 (diff)
pwm: imx: Split into two drivers
The two PWM implementations called v1 (for i.MX1 and i.MX21) and v2 (for i.MX27 and later) have nothing in common apart from needing two clocks named "per" and "ipg" and being integrated in a SoC named i.MX. So split the file containing the two disjunct drivers into two files and two complete separate drivers. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> [thierry.reding@gmail.com: fix a modular build issue] Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Diffstat (limited to 'drivers/pwm/pwm-imx.c')
-rw-r--r--drivers/pwm/pwm-imx.c466
1 files changed, 0 insertions, 466 deletions
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
deleted file mode 100644
index 30380fcb5cfb..000000000000
--- a/drivers/pwm/pwm-imx.c
+++ /dev/null
@@ -1,466 +0,0 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * simple driver for PWM (Pulse Width Modulator) controller
4 *
5 * Derived from pxa PWM driver by eric miao <eric.miao@marvell.com>
6 */
7
8#include <linux/bitfield.h>
9#include <linux/bitops.h>
10#include <linux/clk.h>
11#include <linux/delay.h>
12#include <linux/err.h>
13#include <linux/io.h>
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/of.h>
17#include <linux/of_device.h>
18#include <linux/platform_device.h>
19#include <linux/pwm.h>
20#include <linux/slab.h>
21
22/* i.MX1 and i.MX21 share the same PWM function block: */
23
24#define MX1_PWMC 0x00 /* PWM Control Register */
25#define MX1_PWMS 0x04 /* PWM Sample Register */
26#define MX1_PWMP 0x08 /* PWM Period Register */
27
28#define MX1_PWMC_EN BIT(4)
29
30/* i.MX27, i.MX31, i.MX35 share the same PWM function block: */
31
32#define MX3_PWMCR 0x00 /* PWM Control Register */
33#define MX3_PWMSR 0x04 /* PWM Status Register */
34#define MX3_PWMSAR 0x0C /* PWM Sample Register */
35#define MX3_PWMPR 0x10 /* PWM Period Register */
36
37#define MX3_PWMCR_FWM GENMASK(27, 26)
38#define MX3_PWMCR_STOPEN BIT(25)
39#define MX3_PWMCR_DOZEN BIT(24)
40#define MX3_PWMCR_WAITEN BIT(23)
41#define MX3_PWMCR_DBGEN BIT(22)
42#define MX3_PWMCR_BCTR BIT(21)
43#define MX3_PWMCR_HCTR BIT(20)
44
45#define MX3_PWMCR_POUTC GENMASK(19, 18)
46#define MX3_PWMCR_POUTC_NORMAL 0
47#define MX3_PWMCR_POUTC_INVERTED 1
48#define MX3_PWMCR_POUTC_OFF 2
49
50#define MX3_PWMCR_CLKSRC GENMASK(17, 16)
51#define MX3_PWMCR_CLKSRC_OFF 0
52#define MX3_PWMCR_CLKSRC_IPG 1
53#define MX3_PWMCR_CLKSRC_IPG_HIGH 2
54#define MX3_PWMCR_CLKSRC_IPG_32K 3
55
56#define MX3_PWMCR_PRESCALER GENMASK(15, 4)
57
58#define MX3_PWMCR_SWR BIT(3)
59
60#define MX3_PWMCR_REPEAT GENMASK(2, 1)
61#define MX3_PWMCR_REPEAT_1X 0
62#define MX3_PWMCR_REPEAT_2X 1
63#define MX3_PWMCR_REPEAT_4X 2
64#define MX3_PWMCR_REPEAT_8X 3
65
66#define MX3_PWMCR_EN BIT(0)
67
68#define MX3_PWMSR_FWE BIT(6)
69#define MX3_PWMSR_CMP BIT(5)
70#define MX3_PWMSR_ROV BIT(4)
71#define MX3_PWMSR_FE BIT(3)
72
73#define MX3_PWMSR_FIFOAV GENMASK(2, 0)
74#define MX3_PWMSR_FIFOAV_EMPTY 0
75#define MX3_PWMSR_FIFOAV_1WORD 1
76#define MX3_PWMSR_FIFOAV_2WORDS 2
77#define MX3_PWMSR_FIFOAV_3WORDS 3
78#define MX3_PWMSR_FIFOAV_4WORDS 4
79
80#define MX3_PWMCR_PRESCALER_SET(x) FIELD_PREP(MX3_PWMCR_PRESCALER, (x) - 1)
81#define MX3_PWMCR_PRESCALER_GET(x) (FIELD_GET(MX3_PWMCR_PRESCALER, \
82 (x)) + 1)
83
84#define MX3_PWM_SWR_LOOP 5
85
86/* PWMPR register value of 0xffff has the same effect as 0xfffe */
87#define MX3_PWMPR_MAX 0xfffe
88
89struct imx_chip {
90 struct clk *clk_ipg;
91
92 struct clk *clk_per;
93
94 void __iomem *mmio_base;
95
96 struct pwm_chip chip;
97};
98
99#define to_imx_chip(chip) container_of(chip, struct imx_chip, chip)
100
101static int imx_pwm_clk_prepare_enable(struct pwm_chip *chip)
102{
103 struct imx_chip *imx = to_imx_chip(chip);
104 int ret;
105
106 ret = clk_prepare_enable(imx->clk_ipg);
107 if (ret)
108 return ret;
109
110 ret = clk_prepare_enable(imx->clk_per);
111 if (ret) {
112 clk_disable_unprepare(imx->clk_ipg);
113 return ret;
114 }
115
116 return 0;
117}
118
119static void imx_pwm_clk_disable_unprepare(struct pwm_chip *chip)
120{
121 struct imx_chip *imx = to_imx_chip(chip);
122
123 clk_disable_unprepare(imx->clk_per);
124 clk_disable_unprepare(imx->clk_ipg);
125}
126
127static void imx_pwm_get_state(struct pwm_chip *chip,
128 struct pwm_device *pwm, struct pwm_state *state)
129{
130 struct imx_chip *imx = to_imx_chip(chip);
131 u32 period, prescaler, pwm_clk, ret, val;
132 u64 tmp;
133
134 ret = imx_pwm_clk_prepare_enable(chip);
135 if (ret < 0)
136 return;
137
138 val = readl(imx->mmio_base + MX3_PWMCR);
139
140 if (val & MX3_PWMCR_EN) {
141 state->enabled = true;
142 ret = imx_pwm_clk_prepare_enable(chip);
143 if (ret)
144 return;
145 } else {
146 state->enabled = false;
147 }
148
149 switch (FIELD_GET(MX3_PWMCR_POUTC, val)) {
150 case MX3_PWMCR_POUTC_NORMAL:
151 state->polarity = PWM_POLARITY_NORMAL;
152 break;
153 case MX3_PWMCR_POUTC_INVERTED:
154 state->polarity = PWM_POLARITY_INVERSED;
155 break;
156 default:
157 dev_warn(chip->dev, "can't set polarity, output disconnected");
158 }
159
160 prescaler = MX3_PWMCR_PRESCALER_GET(val);
161 pwm_clk = clk_get_rate(imx->clk_per);
162 pwm_clk = DIV_ROUND_CLOSEST_ULL(pwm_clk, prescaler);
163 val = readl(imx->mmio_base + MX3_PWMPR);
164 period = val >= MX3_PWMPR_MAX ? MX3_PWMPR_MAX : val;
165
166 /* PWMOUT (Hz) = PWMCLK / (PWMPR + 2) */
167 tmp = NSEC_PER_SEC * (u64)(period + 2);
168 state->period = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk);
169
170 /* PWMSAR can be read only if PWM is enabled */
171 if (state->enabled) {
172 val = readl(imx->mmio_base + MX3_PWMSAR);
173 tmp = NSEC_PER_SEC * (u64)(val);
174 state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk);
175 } else {
176 state->duty_cycle = 0;
177 }
178
179 imx_pwm_clk_disable_unprepare(chip);
180}
181
182static int imx_pwm_config_v1(struct pwm_chip *chip,
183 struct pwm_device *pwm, int duty_ns, int period_ns)
184{
185 struct imx_chip *imx = to_imx_chip(chip);
186
187 /*
188 * The PWM subsystem allows for exact frequencies. However,
189 * I cannot connect a scope on my device to the PWM line and
190 * thus cannot provide the program the PWM controller
191 * exactly. Instead, I'm relying on the fact that the
192 * Bootloader (u-boot or WinCE+haret) has programmed the PWM
193 * function group already. So I'll just modify the PWM sample
194 * register to follow the ratio of duty_ns vs. period_ns
195 * accordingly.
196 *
197 * This is good enough for programming the brightness of
198 * the LCD backlight.
199 *
200 * The real implementation would divide PERCLK[0] first by
201 * both the prescaler (/1 .. /128) and then by CLKSEL
202 * (/2 .. /16).
203 */
204 u32 max = readl(imx->mmio_base + MX1_PWMP);
205 u32 p = max * duty_ns / period_ns;
206 writel(max - p, imx->mmio_base + MX1_PWMS);
207
208 return 0;
209}
210
211static int imx_pwm_enable_v1(struct pwm_chip *chip, struct pwm_device *pwm)
212{
213 struct imx_chip *imx = to_imx_chip(chip);
214 u32 val;
215 int ret;
216
217 ret = imx_pwm_clk_prepare_enable(chip);
218 if (ret < 0)
219 return ret;
220
221 val = readl(imx->mmio_base + MX1_PWMC);
222 val |= MX1_PWMC_EN;
223 writel(val, imx->mmio_base + MX1_PWMC);
224
225 return 0;
226}
227
228static void imx_pwm_disable_v1(struct pwm_chip *chip, struct pwm_device *pwm)
229{
230 struct imx_chip *imx = to_imx_chip(chip);
231 u32 val;
232
233 val = readl(imx->mmio_base + MX1_PWMC);
234 val &= ~MX1_PWMC_EN;
235 writel(val, imx->mmio_base + MX1_PWMC);
236
237 imx_pwm_clk_disable_unprepare(chip);
238}
239
240static void imx_pwm_sw_reset(struct pwm_chip *chip)
241{
242 struct imx_chip *imx = to_imx_chip(chip);
243 struct device *dev = chip->dev;
244 int wait_count = 0;
245 u32 cr;
246
247 writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR);
248 do {
249 usleep_range(200, 1000);
250 cr = readl(imx->mmio_base + MX3_PWMCR);
251 } while ((cr & MX3_PWMCR_SWR) &&
252 (wait_count++ < MX3_PWM_SWR_LOOP));
253
254 if (cr & MX3_PWMCR_SWR)
255 dev_warn(dev, "software reset timeout\n");
256}
257
258static void imx_pwm_wait_fifo_slot(struct pwm_chip *chip,
259 struct pwm_device *pwm)
260{
261 struct imx_chip *imx = to_imx_chip(chip);
262 struct device *dev = chip->dev;
263 unsigned int period_ms;
264 int fifoav;
265 u32 sr;
266
267 sr = readl(imx->mmio_base + MX3_PWMSR);
268 fifoav = FIELD_GET(MX3_PWMSR_FIFOAV, sr);
269 if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) {
270 period_ms = DIV_ROUND_UP(pwm_get_period(pwm),
271 NSEC_PER_MSEC);
272 msleep(period_ms);
273
274 sr = readl(imx->mmio_base + MX3_PWMSR);
275 if (fifoav == FIELD_GET(MX3_PWMSR_FIFOAV, sr))
276 dev_warn(dev, "there is no free FIFO slot\n");
277 }
278}
279
280static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm,
281 struct pwm_state *state)
282{
283 unsigned long period_cycles, duty_cycles, prescale;
284 struct imx_chip *imx = to_imx_chip(chip);
285 struct pwm_state cstate;
286 unsigned long long c;
287 int ret;
288 u32 cr;
289
290 pwm_get_state(pwm, &cstate);
291
292 if (state->enabled) {
293 c = clk_get_rate(imx->clk_per);
294 c *= state->period;
295
296 do_div(c, 1000000000);
297 period_cycles = c;
298
299 prescale = period_cycles / 0x10000 + 1;
300
301 period_cycles /= prescale;
302 c = (unsigned long long)period_cycles * state->duty_cycle;
303 do_div(c, state->period);
304 duty_cycles = c;
305
306 /*
307 * according to imx pwm RM, the real period value should be
308 * PERIOD value in PWMPR plus 2.
309 */
310 if (period_cycles > 2)
311 period_cycles -= 2;
312 else
313 period_cycles = 0;
314
315 /*
316 * Wait for a free FIFO slot if the PWM is already enabled, and
317 * flush the FIFO if the PWM was disabled and is about to be
318 * enabled.
319 */
320 if (cstate.enabled) {
321 imx_pwm_wait_fifo_slot(chip, pwm);
322 } else {
323 ret = imx_pwm_clk_prepare_enable(chip);
324 if (ret)
325 return ret;
326
327 imx_pwm_sw_reset(chip);
328 }
329
330 writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
331 writel(period_cycles, imx->mmio_base + MX3_PWMPR);
332
333 cr = MX3_PWMCR_PRESCALER_SET(prescale) |
334 MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEN | MX3_PWMCR_WAITEN |
335 FIELD_PREP(MX3_PWMCR_CLKSRC, MX3_PWMCR_CLKSRC_IPG_HIGH) |
336 MX3_PWMCR_DBGEN | MX3_PWMCR_EN;
337
338 if (state->polarity == PWM_POLARITY_INVERSED)
339 cr |= FIELD_PREP(MX3_PWMCR_POUTC,
340 MX3_PWMCR_POUTC_INVERTED);
341
342 writel(cr, imx->mmio_base + MX3_PWMCR);
343 } else if (cstate.enabled) {
344 writel(0, imx->mmio_base + MX3_PWMCR);
345
346 imx_pwm_clk_disable_unprepare(chip);
347 }
348
349 return 0;
350}
351
352static const struct pwm_ops imx_pwm_ops_v1 = {
353 .enable = imx_pwm_enable_v1,
354 .disable = imx_pwm_disable_v1,
355 .config = imx_pwm_config_v1,
356 .owner = THIS_MODULE,
357};
358
359static const struct pwm_ops imx_pwm_ops_v2 = {
360 .apply = imx_pwm_apply_v2,
361 .get_state = imx_pwm_get_state,
362 .owner = THIS_MODULE,
363};
364
365struct imx_pwm_data {
366 bool polarity_supported;
367 const struct pwm_ops *ops;
368};
369
370static struct imx_pwm_data imx_pwm_data_v1 = {
371 .ops = &imx_pwm_ops_v1,
372};
373
374static struct imx_pwm_data imx_pwm_data_v2 = {
375 .polarity_supported = true,
376 .ops = &imx_pwm_ops_v2,
377};
378
379static const struct of_device_id imx_pwm_dt_ids[] = {
380 { .compatible = "fsl,imx1-pwm", .data = &imx_pwm_data_v1, },
381 { .compatible = "fsl,imx27-pwm", .data = &imx_pwm_data_v2, },
382 { /* sentinel */ }
383};
384MODULE_DEVICE_TABLE(of, imx_pwm_dt_ids);
385
386static int imx_pwm_probe(struct platform_device *pdev)
387{
388 const struct of_device_id *of_id =
389 of_match_device(imx_pwm_dt_ids, &pdev->dev);
390 const struct imx_pwm_data *data;
391 struct imx_chip *imx;
392 struct resource *r;
393
394 if (!of_id)
395 return -ENODEV;
396
397 data = of_id->data;
398
399 imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
400 if (imx == NULL)
401 return -ENOMEM;
402
403 platform_set_drvdata(pdev, imx);
404
405 imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
406 if (IS_ERR(imx->clk_ipg)) {
407 dev_err(&pdev->dev, "getting ipg clock failed with %ld\n",
408 PTR_ERR(imx->clk_ipg));
409 return PTR_ERR(imx->clk_ipg);
410 }
411
412 imx->clk_per = devm_clk_get(&pdev->dev, "per");
413 if (IS_ERR(imx->clk_per)) {
414 int ret = PTR_ERR(imx->clk_per);
415
416 if (ret != -EPROBE_DEFER)
417 dev_err(&pdev->dev,
418 "failed to get peripheral clock: %d\n",
419 ret);
420
421 return ret;
422 }
423
424 imx->chip.ops = data->ops;
425 imx->chip.dev = &pdev->dev;
426 imx->chip.base = -1;
427 imx->chip.npwm = 1;
428
429 if (data->polarity_supported) {
430 dev_dbg(&pdev->dev, "PWM supports output inversion\n");
431 imx->chip.of_xlate = of_pwm_xlate_with_flags;
432 imx->chip.of_pwm_n_cells = 3;
433 }
434
435 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
436 imx->mmio_base = devm_ioremap_resource(&pdev->dev, r);
437 if (IS_ERR(imx->mmio_base))
438 return PTR_ERR(imx->mmio_base);
439
440 return pwmchip_add(&imx->chip);
441}
442
443static int imx_pwm_remove(struct platform_device *pdev)
444{
445 struct imx_chip *imx;
446
447 imx = platform_get_drvdata(pdev);
448
449 imx_pwm_clk_disable_unprepare(&imx->chip);
450
451 return pwmchip_remove(&imx->chip);
452}
453
454static struct platform_driver imx_pwm_driver = {
455 .driver = {
456 .name = "imx-pwm",
457 .of_match_table = imx_pwm_dt_ids,
458 },
459 .probe = imx_pwm_probe,
460 .remove = imx_pwm_remove,
461};
462
463module_platform_driver(imx_pwm_driver);
464
465MODULE_LICENSE("GPL v2");
466MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");