Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[sfrench/cifs-2.6.git] / drivers / pwm / pwm-brcmstb.c
1 /*
2  * Broadcom BCM7038 PWM driver
3  * Author: Florian Fainelli
4  *
5  * Copyright (C) 2015 Broadcom Corporation
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  */
17
18 #define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
19
20 #include <linux/clk.h>
21 #include <linux/export.h>
22 #include <linux/init.h>
23 #include <linux/io.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/of.h>
27 #include <linux/platform_device.h>
28 #include <linux/pwm.h>
29 #include <linux/spinlock.h>
30
31 #define PWM_CTRL                0x00
32 #define  CTRL_START             BIT(0)
33 #define  CTRL_OEB               BIT(1)
34 #define  CTRL_FORCE_HIGH        BIT(2)
35 #define  CTRL_OPENDRAIN         BIT(3)
36 #define  CTRL_CHAN_OFFS         4
37
38 #define PWM_CTRL2               0x04
39 #define  CTRL2_OUT_SELECT       BIT(0)
40
41 #define PWM_CH_SIZE             0x8
42
43 #define PWM_CWORD_MSB(ch)       (0x08 + ((ch) * PWM_CH_SIZE))
44 #define PWM_CWORD_LSB(ch)       (0x0c + ((ch) * PWM_CH_SIZE))
45
46 /* Number of bits for the CWORD value */
47 #define CWORD_BIT_SIZE          16
48
49 /*
50  * Maximum control word value allowed when variable-frequency PWM is used as a
51  * clock for the constant-frequency PMW.
52  */
53 #define CONST_VAR_F_MAX         32768
54 #define CONST_VAR_F_MIN         1
55
56 #define PWM_ON(ch)              (0x18 + ((ch) * PWM_CH_SIZE))
57 #define  PWM_ON_MIN             1
58 #define PWM_PERIOD(ch)          (0x1c + ((ch) * PWM_CH_SIZE))
59 #define  PWM_PERIOD_MIN         0
60
61 #define PWM_ON_PERIOD_MAX       0xff
62
63 struct brcmstb_pwm {
64         void __iomem *base;
65         spinlock_t lock;
66         struct clk *clk;
67         struct pwm_chip chip;
68 };
69
70 static inline u32 brcmstb_pwm_readl(struct brcmstb_pwm *p,
71                                     unsigned int offset)
72 {
73         if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
74                 return __raw_readl(p->base + offset);
75         else
76                 return readl_relaxed(p->base + offset);
77 }
78
79 static inline void brcmstb_pwm_writel(struct brcmstb_pwm *p, u32 value,
80                                       unsigned int offset)
81 {
82         if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
83                 __raw_writel(value, p->base + offset);
84         else
85                 writel_relaxed(value, p->base + offset);
86 }
87
88 static inline struct brcmstb_pwm *to_brcmstb_pwm(struct pwm_chip *chip)
89 {
90         return container_of(chip, struct brcmstb_pwm, chip);
91 }
92
93 /*
94  * Fv is derived from the variable frequency output. The variable frequency
95  * output is configured using this formula:
96  *
97  * W = cword, if cword < 2 ^ 15 else 16-bit 2's complement of cword
98  *
99  * Fv = W x 2 ^ -16 x 27Mhz (reference clock)
100  *
101  * The period is: (period + 1) / Fv and "on" time is on / (period + 1)
102  *
103  * The PWM core framework specifies that the "duty_ns" parameter is in fact the
104  * "on" time, so this translates directly into our HW programming here.
105  */
106 static int brcmstb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
107                               int duty_ns, int period_ns)
108 {
109         struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
110         unsigned long pc, dc, cword = CONST_VAR_F_MAX;
111         unsigned int channel = pwm->hwpwm;
112         u32 value;
113
114         /*
115          * If asking for a duty_ns equal to period_ns, we need to substract
116          * the period value by 1 to make it shorter than the "on" time and
117          * produce a flat 100% duty cycle signal, and max out the "on" time
118          */
119         if (duty_ns == period_ns) {
120                 dc = PWM_ON_PERIOD_MAX;
121                 pc = PWM_ON_PERIOD_MAX - 1;
122                 goto done;
123         }
124
125         while (1) {
126                 u64 rate, tmp;
127
128                 /*
129                  * Calculate the base rate from base frequency and current
130                  * cword
131                  */
132                 rate = (u64)clk_get_rate(p->clk) * (u64)cword;
133                 do_div(rate, 1 << CWORD_BIT_SIZE);
134
135                 tmp = period_ns * rate;
136                 do_div(tmp, NSEC_PER_SEC);
137                 pc = tmp;
138
139                 tmp = (duty_ns + 1) * rate;
140                 do_div(tmp, NSEC_PER_SEC);
141                 dc = tmp;
142
143                 /*
144                  * We can be called with separate duty and period updates,
145                  * so do not reject dc == 0 right away
146                  */
147                 if (pc == PWM_PERIOD_MIN || (dc < PWM_ON_MIN && duty_ns))
148                         return -EINVAL;
149
150                 /* We converged on a calculation */
151                 if (pc <= PWM_ON_PERIOD_MAX && dc <= PWM_ON_PERIOD_MAX)
152                         break;
153
154                 /*
155                  * The cword needs to be a power of 2 for the variable
156                  * frequency generator to output a 50% duty cycle variable
157                  * frequency which is used as input clock to the fixed
158                  * frequency generator.
159                  */
160                 cword >>= 1;
161
162                 /*
163                  * Desired periods are too large, we do not have a divider
164                  * for them
165                  */
166                 if (cword < CONST_VAR_F_MIN)
167                         return -EINVAL;
168         }
169
170 done:
171         /*
172          * Configure the defined "cword" value to have the variable frequency
173          * generator output a base frequency for the constant frequency
174          * generator to derive from.
175          */
176         spin_lock(&p->lock);
177         brcmstb_pwm_writel(p, cword >> 8, PWM_CWORD_MSB(channel));
178         brcmstb_pwm_writel(p, cword & 0xff, PWM_CWORD_LSB(channel));
179
180         /* Select constant frequency signal output */
181         value = brcmstb_pwm_readl(p, PWM_CTRL2);
182         value |= CTRL2_OUT_SELECT << (channel * CTRL_CHAN_OFFS);
183         brcmstb_pwm_writel(p, value, PWM_CTRL2);
184
185         /* Configure on and period value */
186         brcmstb_pwm_writel(p, pc, PWM_PERIOD(channel));
187         brcmstb_pwm_writel(p, dc, PWM_ON(channel));
188         spin_unlock(&p->lock);
189
190         return 0;
191 }
192
193 static inline void brcmstb_pwm_enable_set(struct brcmstb_pwm *p,
194                                           unsigned int channel, bool enable)
195 {
196         unsigned int shift = channel * CTRL_CHAN_OFFS;
197         u32 value;
198
199         spin_lock(&p->lock);
200         value = brcmstb_pwm_readl(p, PWM_CTRL);
201
202         if (enable) {
203                 value &= ~(CTRL_OEB << shift);
204                 value |= (CTRL_START | CTRL_OPENDRAIN) << shift;
205         } else {
206                 value &= ~((CTRL_START | CTRL_OPENDRAIN) << shift);
207                 value |= CTRL_OEB << shift;
208         }
209
210         brcmstb_pwm_writel(p, value, PWM_CTRL);
211         spin_unlock(&p->lock);
212 }
213
214 static int brcmstb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
215 {
216         struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
217
218         brcmstb_pwm_enable_set(p, pwm->hwpwm, true);
219
220         return 0;
221 }
222
223 static void brcmstb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
224 {
225         struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
226
227         brcmstb_pwm_enable_set(p, pwm->hwpwm, false);
228 }
229
230 static const struct pwm_ops brcmstb_pwm_ops = {
231         .config = brcmstb_pwm_config,
232         .enable = brcmstb_pwm_enable,
233         .disable = brcmstb_pwm_disable,
234         .owner = THIS_MODULE,
235 };
236
237 static const struct of_device_id brcmstb_pwm_of_match[] = {
238         { .compatible = "brcm,bcm7038-pwm", },
239         { /* sentinel */ }
240 };
241 MODULE_DEVICE_TABLE(of, brcmstb_pwm_of_match);
242
243 static int brcmstb_pwm_probe(struct platform_device *pdev)
244 {
245         struct brcmstb_pwm *p;
246         struct resource *res;
247         int ret;
248
249         p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
250         if (!p)
251                 return -ENOMEM;
252
253         spin_lock_init(&p->lock);
254
255         p->clk = devm_clk_get(&pdev->dev, NULL);
256         if (IS_ERR(p->clk)) {
257                 dev_err(&pdev->dev, "failed to obtain clock\n");
258                 return PTR_ERR(p->clk);
259         }
260
261         ret = clk_prepare_enable(p->clk);
262         if (ret < 0) {
263                 dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
264                 return ret;
265         }
266
267         platform_set_drvdata(pdev, p);
268
269         p->chip.dev = &pdev->dev;
270         p->chip.ops = &brcmstb_pwm_ops;
271         p->chip.base = -1;
272         p->chip.npwm = 2;
273
274         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
275         p->base = devm_ioremap_resource(&pdev->dev, res);
276         if (IS_ERR(p->base)) {
277                 ret = PTR_ERR(p->base);
278                 goto out_clk;
279         }
280
281         ret = pwmchip_add(&p->chip);
282         if (ret) {
283                 dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
284                 goto out_clk;
285         }
286
287         return 0;
288
289 out_clk:
290         clk_disable_unprepare(p->clk);
291         return ret;
292 }
293
294 static int brcmstb_pwm_remove(struct platform_device *pdev)
295 {
296         struct brcmstb_pwm *p = platform_get_drvdata(pdev);
297         int ret;
298
299         ret = pwmchip_remove(&p->chip);
300         clk_disable_unprepare(p->clk);
301
302         return ret;
303 }
304
305 #ifdef CONFIG_PM_SLEEP
306 static int brcmstb_pwm_suspend(struct device *dev)
307 {
308         struct brcmstb_pwm *p = dev_get_drvdata(dev);
309
310         clk_disable(p->clk);
311
312         return 0;
313 }
314
315 static int brcmstb_pwm_resume(struct device *dev)
316 {
317         struct brcmstb_pwm *p = dev_get_drvdata(dev);
318
319         clk_enable(p->clk);
320
321         return 0;
322 }
323 #endif
324
325 static SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend,
326                          brcmstb_pwm_resume);
327
328 static struct platform_driver brcmstb_pwm_driver = {
329         .probe = brcmstb_pwm_probe,
330         .remove = brcmstb_pwm_remove,
331         .driver = {
332                 .name = "pwm-brcmstb",
333                 .of_match_table = brcmstb_pwm_of_match,
334                 .pm = &brcmstb_pwm_pm_ops,
335         },
336 };
337 module_platform_driver(brcmstb_pwm_driver);
338
339 MODULE_AUTHOR("Florian Fainelli <f.fainelli@gmail.com>");
340 MODULE_DESCRIPTION("Broadcom STB PWM driver");
341 MODULE_ALIAS("platform:pwm-brcmstb");
342 MODULE_LICENSE("GPL");