]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/pwm/pwm-imx.c
c944f15f574c0ea93f9671ec6e0be350b16b4a4f
[karo-tx-linux.git] / drivers / pwm / pwm-imx.c
1 /*
2  * simple driver for PWM (Pulse Width Modulator) controller
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * Derived from pxa PWM driver by eric miao <eric.miao@marvell.com>
9  */
10
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/platform_device.h>
14 #include <linux/slab.h>
15 #include <linux/err.h>
16 #include <linux/clk.h>
17 #include <linux/delay.h>
18 #include <linux/io.h>
19 #include <linux/pwm.h>
20 #include <linux/of.h>
21 #include <linux/of_device.h>
22
23 /* i.MX1 and i.MX21 share the same PWM function block: */
24
25 #define MX1_PWMC                        0x00   /* PWM Control Register */
26 #define MX1_PWMS                        0x04   /* PWM Sample Register */
27 #define MX1_PWMP                        0x08   /* PWM Period Register */
28
29 #define MX1_PWMC_EN                     (1 << 4)
30
31 /* i.MX27, i.MX31, i.MX35 share the same PWM function block: */
32
33 #define MX3_PWMCR                       0x00    /* PWM Control Register */
34 #define MX3_PWMSR                       0x04    /* PWM Status Register */
35 #define MX3_PWMSAR                      0x0C    /* PWM Sample Register */
36 #define MX3_PWMPR                       0x10    /* PWM Period Register */
37 #define MX3_PWMCR_PRESCALER(x)          ((((x) - 1) & 0xFFF) << 4)
38 #define MX3_PWMCR_DOZEEN                (1 << 24)
39 #define MX3_PWMCR_WAITEN                (1 << 23)
40 #define MX3_PWMCR_DBGEN                 (1 << 22)
41 #define MX3_PWMCR_CLKSRC_IPG_HIGH       (2 << 16)
42 #define MX3_PWMCR_CLKSRC_IPG            (1 << 16)
43 #define MX3_PWMCR_SWR                   (1 << 3)
44 #define MX3_PWMCR_EN                    (1 << 0)
45 #define MX3_PWMSR_FIFOAV_4WORDS         0x4
46 #define MX3_PWMSR_FIFOAV_MASK           0x7
47
48 #define MX3_PWM_SWR_LOOP                5
49
50 struct imx_chip {
51         struct clk      *clk_per;
52
53         void __iomem    *mmio_base;
54
55         struct pwm_chip chip;
56
57         int (*config)(struct pwm_chip *chip,
58                 struct pwm_device *pwm, int duty_ns, int period_ns);
59         void (*set_enable)(struct pwm_chip *chip, bool enable);
60 };
61
62 #define to_imx_chip(chip)       container_of(chip, struct imx_chip, chip)
63
64 static int imx_pwm_config_v1(struct pwm_chip *chip,
65                 struct pwm_device *pwm, int duty_ns, int period_ns)
66 {
67         struct imx_chip *imx = to_imx_chip(chip);
68
69         /*
70          * The PWM subsystem allows for exact frequencies. However,
71          * I cannot connect a scope on my device to the PWM line and
72          * thus cannot provide the program the PWM controller
73          * exactly. Instead, I'm relying on the fact that the
74          * Bootloader (u-boot or WinCE+haret) has programmed the PWM
75          * function group already. So I'll just modify the PWM sample
76          * register to follow the ratio of duty_ns vs. period_ns
77          * accordingly.
78          *
79          * This is good enough for programming the brightness of
80          * the LCD backlight.
81          *
82          * The real implementation would divide PERCLK[0] first by
83          * both the prescaler (/1 .. /128) and then by CLKSEL
84          * (/2 .. /16).
85          */
86         u32 max = readl(imx->mmio_base + MX1_PWMP);
87         u32 p = max * duty_ns / period_ns;
88         writel(max - p, imx->mmio_base + MX1_PWMS);
89
90         return 0;
91 }
92
93 static int imx_pwm_enable_v1(struct pwm_chip *chip, struct pwm_device *pwm)
94 {
95         struct imx_chip *imx = to_imx_chip(chip);
96         u32 val;
97         int ret;
98
99         ret = clk_prepare_enable(imx->clk_per);
100         if (ret < 0)
101                 return ret;
102
103         val = readl(imx->mmio_base + MX1_PWMC);
104         val |= MX1_PWMC_EN;
105         writel(val, imx->mmio_base + MX1_PWMC);
106
107         return 0;
108 }
109
110 static void imx_pwm_disable_v1(struct pwm_chip *chip, struct pwm_device *pwm)
111 {
112         struct imx_chip *imx = to_imx_chip(chip);
113         u32 val;
114
115         val = readl(imx->mmio_base + MX1_PWMC);
116         val &= ~MX1_PWMC_EN;
117         writel(val, imx->mmio_base + MX1_PWMC);
118
119         clk_disable_unprepare(imx->clk_per);
120 }
121
122 static void imx_pwm_sw_reset(struct pwm_chip *chip)
123 {
124         struct imx_chip *imx = to_imx_chip(chip);
125         struct device *dev = chip->dev;
126         int wait_count = 0;
127         u32 cr;
128
129         writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR);
130         do {
131                 usleep_range(200, 1000);
132                 cr = readl(imx->mmio_base + MX3_PWMCR);
133         } while ((cr & MX3_PWMCR_SWR) &&
134                  (wait_count++ < MX3_PWM_SWR_LOOP));
135
136         if (cr & MX3_PWMCR_SWR)
137                 dev_warn(dev, "software reset timeout\n");
138 }
139
140
141 static int imx_pwm_config_v2(struct pwm_chip *chip,
142                 struct pwm_device *pwm, int duty_ns, int period_ns)
143 {
144         struct imx_chip *imx = to_imx_chip(chip);
145         struct device *dev = chip->dev;
146         unsigned long long c;
147         unsigned long period_cycles, duty_cycles, prescale;
148         unsigned int period_ms;
149         bool enable = pwm_is_enabled(pwm);
150         int fifoav;
151         u32 cr, sr;
152
153         /*
154          * i.MX PWMv2 has a 4-word sample FIFO.
155          * In order to avoid FIFO overflow issue, we do software reset
156          * to clear all sample FIFO if the controller is disabled or
157          * wait for a full PWM cycle to get a relinquished FIFO slot
158          * when the controller is enabled and the FIFO is fully loaded.
159          */
160         if (enable) {
161                 sr = readl(imx->mmio_base + MX3_PWMSR);
162                 fifoav = sr & MX3_PWMSR_FIFOAV_MASK;
163                 if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) {
164                         period_ms = DIV_ROUND_UP(pwm_get_period(pwm),
165                                                  NSEC_PER_MSEC);
166                         msleep(period_ms);
167
168                         sr = readl(imx->mmio_base + MX3_PWMSR);
169                         if (fifoav == (sr & MX3_PWMSR_FIFOAV_MASK))
170                                 dev_warn(dev, "there is no free FIFO slot\n");
171                 }
172         } else {
173                 imx_pwm_sw_reset(chip);
174         }
175
176         c = clk_get_rate(imx->clk_per);
177         c = c * period_ns;
178         do_div(c, 1000000000);
179         period_cycles = c;
180
181         prescale = period_cycles / 0x10000 + 1;
182
183         period_cycles /= prescale;
184         c = (unsigned long long)period_cycles * duty_ns;
185         do_div(c, period_ns);
186         duty_cycles = c;
187
188         /*
189          * according to imx pwm RM, the real period value should be
190          * PERIOD value in PWMPR plus 2.
191          */
192         if (period_cycles > 2)
193                 period_cycles -= 2;
194         else
195                 period_cycles = 0;
196
197         writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
198         writel(period_cycles, imx->mmio_base + MX3_PWMPR);
199
200         cr = MX3_PWMCR_PRESCALER(prescale) |
201                 MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
202                 MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH;
203
204         if (enable)
205                 cr |= MX3_PWMCR_EN;
206
207         writel(cr, imx->mmio_base + MX3_PWMCR);
208
209         return 0;
210 }
211
212 static void imx_pwm_set_enable_v2(struct pwm_chip *chip, bool enable)
213 {
214         struct imx_chip *imx = to_imx_chip(chip);
215         u32 val;
216
217         val = readl(imx->mmio_base + MX3_PWMCR);
218
219         if (enable)
220                 val |= MX3_PWMCR_EN;
221         else
222                 val &= ~MX3_PWMCR_EN;
223
224         writel(val, imx->mmio_base + MX3_PWMCR);
225 }
226
227 static int imx_pwm_config(struct pwm_chip *chip,
228                 struct pwm_device *pwm, int duty_ns, int period_ns)
229 {
230         struct imx_chip *imx = to_imx_chip(chip);
231         int ret;
232
233         ret = clk_prepare_enable(imx->clk_per);
234         if (ret)
235                 return ret;
236
237         ret = imx->config(chip, pwm, duty_ns, period_ns);
238
239         clk_disable_unprepare(imx->clk_per);
240
241         return ret;
242 }
243
244 static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
245 {
246         struct imx_chip *imx = to_imx_chip(chip);
247         int ret;
248
249         ret = clk_prepare_enable(imx->clk_per);
250         if (ret)
251                 return ret;
252
253         imx->set_enable(chip, true);
254
255         return 0;
256 }
257
258 static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
259 {
260         struct imx_chip *imx = to_imx_chip(chip);
261
262         imx->set_enable(chip, false);
263
264         clk_disable_unprepare(imx->clk_per);
265 }
266
267 static const struct pwm_ops imx_pwm_ops_v1 = {
268         .enable = imx_pwm_enable_v1,
269         .disable = imx_pwm_disable_v1,
270         .config = imx_pwm_config_v1,
271         .owner = THIS_MODULE,
272 };
273
274 static const struct pwm_ops imx_pwm_ops_v2 = {
275         .enable = imx_pwm_enable,
276         .disable = imx_pwm_disable,
277         .config = imx_pwm_config,
278         .owner = THIS_MODULE,
279 };
280
281 struct imx_pwm_data {
282         int (*config)(struct pwm_chip *chip,
283                 struct pwm_device *pwm, int duty_ns, int period_ns);
284         void (*set_enable)(struct pwm_chip *chip, bool enable);
285         const struct pwm_ops *ops;
286 };
287
288 static struct imx_pwm_data imx_pwm_data_v1 = {
289         .ops = &imx_pwm_ops_v1,
290 };
291
292 static struct imx_pwm_data imx_pwm_data_v2 = {
293         .config = imx_pwm_config_v2,
294         .set_enable = imx_pwm_set_enable_v2,
295         .ops = &imx_pwm_ops_v2,
296 };
297
298 static const struct of_device_id imx_pwm_dt_ids[] = {
299         { .compatible = "fsl,imx1-pwm", .data = &imx_pwm_data_v1, },
300         { .compatible = "fsl,imx27-pwm", .data = &imx_pwm_data_v2, },
301         { /* sentinel */ }
302 };
303 MODULE_DEVICE_TABLE(of, imx_pwm_dt_ids);
304
305 static int imx_pwm_probe(struct platform_device *pdev)
306 {
307         const struct of_device_id *of_id =
308                         of_match_device(imx_pwm_dt_ids, &pdev->dev);
309         const struct imx_pwm_data *data;
310         struct imx_chip *imx;
311         struct resource *r;
312         int ret = 0;
313
314         if (!of_id)
315                 return -ENODEV;
316
317         data = of_id->data;
318
319         imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
320         if (imx == NULL)
321                 return -ENOMEM;
322
323         imx->clk_per = devm_clk_get(&pdev->dev, "per");
324         if (IS_ERR(imx->clk_per)) {
325                 dev_err(&pdev->dev, "getting per clock failed with %ld\n",
326                                 PTR_ERR(imx->clk_per));
327                 return PTR_ERR(imx->clk_per);
328         }
329
330         imx->chip.ops = data->ops;
331         imx->chip.dev = &pdev->dev;
332         imx->chip.base = -1;
333         imx->chip.npwm = 1;
334         imx->chip.can_sleep = true;
335
336         r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
337         imx->mmio_base = devm_ioremap_resource(&pdev->dev, r);
338         if (IS_ERR(imx->mmio_base))
339                 return PTR_ERR(imx->mmio_base);
340
341         imx->config = data->config;
342         imx->set_enable = data->set_enable;
343
344         ret = pwmchip_add(&imx->chip);
345         if (ret < 0)
346                 return ret;
347
348         platform_set_drvdata(pdev, imx);
349         return 0;
350 }
351
352 static int imx_pwm_remove(struct platform_device *pdev)
353 {
354         struct imx_chip *imx;
355
356         imx = platform_get_drvdata(pdev);
357         if (imx == NULL)
358                 return -ENODEV;
359
360         return pwmchip_remove(&imx->chip);
361 }
362
363 static struct platform_driver imx_pwm_driver = {
364         .driver         = {
365                 .name   = "imx-pwm",
366                 .of_match_table = imx_pwm_dt_ids,
367         },
368         .probe          = imx_pwm_probe,
369         .remove         = imx_pwm_remove,
370 };
371
372 module_platform_driver(imx_pwm_driver);
373
374 MODULE_LICENSE("GPL v2");
375 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");