Commit 79c11b6fa0b225ac165e79e821d50e70f563645f
1 parent
5384e27317
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
pwm: Move PUV3 PWM driver to PWM framework
This commit moves the driver to drivers/pwm and converts it to the new PWM framework. Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de> Tested-by: Qin Rui <qinrui@mprc.pku.edu.cn> Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
Showing 6 changed files with 174 additions and 231 deletions Side-by-side Diff
arch/unicore32/Kconfig
... | ... | @@ -20,9 +20,6 @@ |
20 | 20 | designs licensed by PKUnity Ltd. |
21 | 21 | Please see web page at <http://www.pkunity.com/>. |
22 | 22 | |
23 | -config HAVE_PWM | |
24 | - bool | |
25 | - | |
26 | 23 | config GENERIC_GPIO |
27 | 24 | def_bool y |
28 | 25 | |
... | ... | @@ -105,7 +102,8 @@ |
105 | 102 | |
106 | 103 | config PUV3_NB0916 |
107 | 104 | bool "NetBook board (0916)" |
108 | - select HAVE_PWM | |
105 | + select PWM | |
106 | + select PWM_PUV3 | |
109 | 107 | |
110 | 108 | config PUV3_SMW0919 |
111 | 109 | bool "Security Mini-Workstation board (0919)" |
... | ... | @@ -218,12 +216,6 @@ |
218 | 216 | select GENERIC_GPIO |
219 | 217 | select GPIO_SYSFS if EXPERIMENTAL |
220 | 218 | default y |
221 | - | |
222 | -config PUV3_PWM | |
223 | - tristate | |
224 | - default BACKLIGHT_PWM | |
225 | - help | |
226 | - Enable support for NB0916 PWM controllers | |
227 | 219 | |
228 | 220 | if PUV3_NB0916 |
229 | 221 |
arch/unicore32/kernel/Makefile
arch/unicore32/kernel/pwm.c
1 | -/* | |
2 | - * linux/arch/unicore32/kernel/pwm.c | |
3 | - * | |
4 | - * Code specific to PKUnity SoC and UniCore ISA | |
5 | - * | |
6 | - * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> | |
7 | - * Copyright (C) 2001-2010 Guan Xuetao | |
8 | - * | |
9 | - * This program is free software; you can redistribute it and/or modify | |
10 | - * it under the terms of the GNU General Public License version 2 as | |
11 | - * published by the Free Software Foundation. | |
12 | - */ | |
13 | - | |
14 | -#include <linux/module.h> | |
15 | -#include <linux/kernel.h> | |
16 | -#include <linux/platform_device.h> | |
17 | -#include <linux/slab.h> | |
18 | -#include <linux/err.h> | |
19 | -#include <linux/clk.h> | |
20 | -#include <linux/io.h> | |
21 | -#include <linux/pwm.h> | |
22 | - | |
23 | -#include <asm/div64.h> | |
24 | -#include <mach/hardware.h> | |
25 | - | |
26 | -struct pwm_device { | |
27 | - struct list_head node; | |
28 | - struct platform_device *pdev; | |
29 | - | |
30 | - void __iomem *base; | |
31 | - | |
32 | - const char *label; | |
33 | - struct clk *clk; | |
34 | - int clk_enabled; | |
35 | - | |
36 | - unsigned int use_count; | |
37 | - unsigned int pwm_id; | |
38 | -}; | |
39 | - | |
40 | -/* | |
41 | - * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE | |
42 | - * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE | |
43 | - */ | |
44 | -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | |
45 | -{ | |
46 | - unsigned long long c; | |
47 | - unsigned long period_cycles, prescale, pv, dc; | |
48 | - | |
49 | - if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) | |
50 | - return -EINVAL; | |
51 | - | |
52 | - c = clk_get_rate(pwm->clk); | |
53 | - c = c * period_ns; | |
54 | - do_div(c, 1000000000); | |
55 | - period_cycles = c; | |
56 | - | |
57 | - if (period_cycles < 1) | |
58 | - period_cycles = 1; | |
59 | - prescale = (period_cycles - 1) / 1024; | |
60 | - pv = period_cycles / (prescale + 1) - 1; | |
61 | - | |
62 | - if (prescale > 63) | |
63 | - return -EINVAL; | |
64 | - | |
65 | - if (duty_ns == period_ns) | |
66 | - dc = OST_PWMDCCR_FDCYCLE; | |
67 | - else | |
68 | - dc = (pv + 1) * duty_ns / period_ns; | |
69 | - | |
70 | - /* NOTE: the clock to PWM has to be enabled first | |
71 | - * before writing to the registers | |
72 | - */ | |
73 | - clk_enable(pwm->clk); | |
74 | - | |
75 | - writel(prescale, pwm->base + OST_PWM_PWCR); | |
76 | - writel(pv - dc, pwm->base + OST_PWM_DCCR); | |
77 | - writel(pv, pwm->base + OST_PWM_PCR); | |
78 | - | |
79 | - clk_disable(pwm->clk); | |
80 | - | |
81 | - return 0; | |
82 | -} | |
83 | -EXPORT_SYMBOL(pwm_config); | |
84 | - | |
85 | -int pwm_enable(struct pwm_device *pwm) | |
86 | -{ | |
87 | - int rc = 0; | |
88 | - | |
89 | - if (!pwm->clk_enabled) { | |
90 | - rc = clk_enable(pwm->clk); | |
91 | - if (!rc) | |
92 | - pwm->clk_enabled = 1; | |
93 | - } | |
94 | - return rc; | |
95 | -} | |
96 | -EXPORT_SYMBOL(pwm_enable); | |
97 | - | |
98 | -void pwm_disable(struct pwm_device *pwm) | |
99 | -{ | |
100 | - if (pwm->clk_enabled) { | |
101 | - clk_disable(pwm->clk); | |
102 | - pwm->clk_enabled = 0; | |
103 | - } | |
104 | -} | |
105 | -EXPORT_SYMBOL(pwm_disable); | |
106 | - | |
107 | -static DEFINE_MUTEX(pwm_lock); | |
108 | -static LIST_HEAD(pwm_list); | |
109 | - | |
110 | -struct pwm_device *pwm_request(int pwm_id, const char *label) | |
111 | -{ | |
112 | - struct pwm_device *pwm; | |
113 | - int found = 0; | |
114 | - | |
115 | - mutex_lock(&pwm_lock); | |
116 | - | |
117 | - list_for_each_entry(pwm, &pwm_list, node) { | |
118 | - if (pwm->pwm_id == pwm_id) { | |
119 | - found = 1; | |
120 | - break; | |
121 | - } | |
122 | - } | |
123 | - | |
124 | - if (found) { | |
125 | - if (pwm->use_count == 0) { | |
126 | - pwm->use_count++; | |
127 | - pwm->label = label; | |
128 | - } else | |
129 | - pwm = ERR_PTR(-EBUSY); | |
130 | - } else | |
131 | - pwm = ERR_PTR(-ENOENT); | |
132 | - | |
133 | - mutex_unlock(&pwm_lock); | |
134 | - return pwm; | |
135 | -} | |
136 | -EXPORT_SYMBOL(pwm_request); | |
137 | - | |
138 | -void pwm_free(struct pwm_device *pwm) | |
139 | -{ | |
140 | - mutex_lock(&pwm_lock); | |
141 | - | |
142 | - if (pwm->use_count) { | |
143 | - pwm->use_count--; | |
144 | - pwm->label = NULL; | |
145 | - } else | |
146 | - pr_warning("PWM device already freed\n"); | |
147 | - | |
148 | - mutex_unlock(&pwm_lock); | |
149 | -} | |
150 | -EXPORT_SYMBOL(pwm_free); | |
151 | - | |
152 | -static inline void __add_pwm(struct pwm_device *pwm) | |
153 | -{ | |
154 | - mutex_lock(&pwm_lock); | |
155 | - list_add_tail(&pwm->node, &pwm_list); | |
156 | - mutex_unlock(&pwm_lock); | |
157 | -} | |
158 | - | |
159 | -static int __devinit pwm_probe(struct platform_device *pdev) | |
160 | -{ | |
161 | - struct pwm_device *pwm; | |
162 | - struct resource *r; | |
163 | - | |
164 | - pwm = devm_kzalloc(&pdev->dev, sizeof(struct pwm_device), GFP_KERNEL); | |
165 | - if (pwm == NULL) { | |
166 | - dev_err(&pdev->dev, "failed to allocate memory\n"); | |
167 | - return -ENOMEM; | |
168 | - } | |
169 | - | |
170 | - pwm->clk = devm_clk_get(&pdev->dev, "OST_CLK"); | |
171 | - if (IS_ERR(pwm->clk)) | |
172 | - return PTR_ERR(pwm->clk); | |
173 | - | |
174 | - pwm->clk_enabled = 0; | |
175 | - | |
176 | - pwm->use_count = 0; | |
177 | - pwm->pwm_id = pdev->id; | |
178 | - pwm->pdev = pdev; | |
179 | - | |
180 | - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
181 | - if (r == NULL) { | |
182 | - dev_err(&pdev->dev, "no memory resource defined\n"); | |
183 | - return -ENODEV; | |
184 | - } | |
185 | - | |
186 | - pwm->base = devm_request_and_ioremap(&pdev->dev, r); | |
187 | - if (pwm->base == NULL) | |
188 | - return -EADDRNOTAVAIL; | |
189 | - | |
190 | - __add_pwm(pwm); | |
191 | - platform_set_drvdata(pdev, pwm); | |
192 | - return 0; | |
193 | -} | |
194 | - | |
195 | -static int __devexit pwm_remove(struct platform_device *pdev) | |
196 | -{ | |
197 | - struct pwm_device *pwm; | |
198 | - | |
199 | - pwm = platform_get_drvdata(pdev); | |
200 | - if (pwm == NULL) | |
201 | - return -ENODEV; | |
202 | - | |
203 | - mutex_lock(&pwm_lock); | |
204 | - list_del(&pwm->node); | |
205 | - mutex_unlock(&pwm_lock); | |
206 | - | |
207 | - return 0; | |
208 | -} | |
209 | - | |
210 | -static struct platform_driver puv3_pwm_driver = { | |
211 | - .driver = { | |
212 | - .name = "PKUnity-v3-PWM", | |
213 | - }, | |
214 | - .probe = pwm_probe, | |
215 | - .remove = __devexit_p(pwm_remove), | |
216 | -}; | |
217 | -module_platform_driver(puv3_pwm_driver); | |
218 | - | |
219 | -MODULE_LICENSE("GPL v2"); |
drivers/pwm/Kconfig
1 | 1 | menuconfig PWM |
2 | 2 | bool "Pulse-Width Modulation (PWM) Support" |
3 | - depends on !MACH_JZ4740 && !PUV3_PWM | |
3 | + depends on !MACH_JZ4740 | |
4 | 4 | help |
5 | 5 | Generic Pulse-Width Modulation (PWM) support. |
6 | 6 | |
... | ... | @@ -75,6 +75,15 @@ |
75 | 75 | |
76 | 76 | To compile this driver as a module, choose M here: the module |
77 | 77 | will be called pwm-mxs. |
78 | + | |
79 | +config PWM_PUV3 | |
80 | + tristate "PKUnity NetBook-0916 PWM support" | |
81 | + depends on ARCH_PUV3 | |
82 | + help | |
83 | + Generic PWM framework driver for PKUnity NetBook-0916. | |
84 | + | |
85 | + To compile this driver as a module, choose M here: the module | |
86 | + will be called pwm-puv3. | |
78 | 87 | |
79 | 88 | config PWM_PXA |
80 | 89 | tristate "PXA PWM support" |
drivers/pwm/Makefile
... | ... | @@ -4,6 +4,7 @@ |
4 | 4 | obj-$(CONFIG_PWM_IMX) += pwm-imx.o |
5 | 5 | obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o |
6 | 6 | obj-$(CONFIG_PWM_MXS) += pwm-mxs.o |
7 | +obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o | |
7 | 8 | obj-$(CONFIG_PWM_PXA) += pwm-pxa.o |
8 | 9 | obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o |
9 | 10 | obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o |
drivers/pwm/pwm-puv3.c
1 | +/* | |
2 | + * linux/arch/unicore32/kernel/pwm.c | |
3 | + * | |
4 | + * Code specific to PKUnity SoC and UniCore ISA | |
5 | + * | |
6 | + * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> | |
7 | + * Copyright (C) 2001-2010 Guan Xuetao | |
8 | + * | |
9 | + * This program is free software; you can redistribute it and/or modify | |
10 | + * it under the terms of the GNU General Public License version 2 as | |
11 | + * published by the Free Software Foundation. | |
12 | + */ | |
13 | + | |
14 | +#include <linux/module.h> | |
15 | +#include <linux/kernel.h> | |
16 | +#include <linux/platform_device.h> | |
17 | +#include <linux/slab.h> | |
18 | +#include <linux/err.h> | |
19 | +#include <linux/clk.h> | |
20 | +#include <linux/io.h> | |
21 | +#include <linux/pwm.h> | |
22 | + | |
23 | +#include <asm/div64.h> | |
24 | +#include <mach/hardware.h> | |
25 | + | |
26 | +struct puv3_pwm_chip { | |
27 | + struct pwm_chip chip; | |
28 | + void __iomem *base; | |
29 | + struct clk *clk; | |
30 | + bool enabled; | |
31 | +}; | |
32 | + | |
33 | +static inline struct puv3_pwm_chip *to_puv3(struct pwm_chip *chip) | |
34 | +{ | |
35 | + return container_of(chip, struct puv3_pwm_chip, chip); | |
36 | +} | |
37 | + | |
38 | +/* | |
39 | + * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE | |
40 | + * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE | |
41 | + */ | |
42 | +static int puv3_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |
43 | + int duty_ns, int period_ns) | |
44 | +{ | |
45 | + unsigned long period_cycles, prescale, pv, dc; | |
46 | + struct puv3_pwm_chip *puv3 = to_puv3(chip); | |
47 | + unsigned long long c; | |
48 | + | |
49 | + c = clk_get_rate(puv3->clk); | |
50 | + c = c * period_ns; | |
51 | + do_div(c, 1000000000); | |
52 | + period_cycles = c; | |
53 | + | |
54 | + if (period_cycles < 1) | |
55 | + period_cycles = 1; | |
56 | + | |
57 | + prescale = (period_cycles - 1) / 1024; | |
58 | + pv = period_cycles / (prescale + 1) - 1; | |
59 | + | |
60 | + if (prescale > 63) | |
61 | + return -EINVAL; | |
62 | + | |
63 | + if (duty_ns == period_ns) | |
64 | + dc = OST_PWMDCCR_FDCYCLE; | |
65 | + else | |
66 | + dc = (pv + 1) * duty_ns / period_ns; | |
67 | + | |
68 | + /* | |
69 | + * NOTE: the clock to PWM has to be enabled first | |
70 | + * before writing to the registers | |
71 | + */ | |
72 | + clk_prepare_enable(puv3->clk); | |
73 | + | |
74 | + writel(prescale, puv3->base + OST_PWM_PWCR); | |
75 | + writel(pv - dc, puv3->base + OST_PWM_DCCR); | |
76 | + writel(pv, puv3->base + OST_PWM_PCR); | |
77 | + | |
78 | + clk_disable_unprepare(puv3->clk); | |
79 | + | |
80 | + return 0; | |
81 | +} | |
82 | + | |
83 | +static int puv3_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | |
84 | +{ | |
85 | + struct puv3_pwm_chip *puv3 = to_puv3(chip); | |
86 | + | |
87 | + return clk_prepare_enable(puv3->clk); | |
88 | +} | |
89 | + | |
90 | +static void puv3_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |
91 | +{ | |
92 | + struct puv3_pwm_chip *puv3 = to_puv3(chip); | |
93 | + | |
94 | + clk_disable_unprepare(puv3->clk); | |
95 | +} | |
96 | + | |
97 | +static const struct pwm_ops puv3_pwm_ops = { | |
98 | + .config = puv3_pwm_config, | |
99 | + .enable = puv3_pwm_enable, | |
100 | + .disable = puv3_pwm_disable, | |
101 | + .owner = THIS_MODULE, | |
102 | +}; | |
103 | + | |
104 | +static int __devinit pwm_probe(struct platform_device *pdev) | |
105 | +{ | |
106 | + struct puv3_pwm_chip *puv3; | |
107 | + struct resource *r; | |
108 | + int ret; | |
109 | + | |
110 | + puv3 = devm_kzalloc(&pdev->dev, sizeof(*puv3), GFP_KERNEL); | |
111 | + if (puv3 == NULL) { | |
112 | + dev_err(&pdev->dev, "failed to allocate memory\n"); | |
113 | + return -ENOMEM; | |
114 | + } | |
115 | + | |
116 | + puv3->clk = devm_clk_get(&pdev->dev, "OST_CLK"); | |
117 | + if (IS_ERR(puv3->clk)) | |
118 | + return PTR_ERR(puv3->clk); | |
119 | + | |
120 | + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
121 | + if (r == NULL) { | |
122 | + dev_err(&pdev->dev, "no memory resource defined\n"); | |
123 | + return -ENODEV; | |
124 | + } | |
125 | + | |
126 | + puv3->base = devm_request_and_ioremap(&pdev->dev, r); | |
127 | + if (puv3->base == NULL) | |
128 | + return -EADDRNOTAVAIL; | |
129 | + | |
130 | + puv3->chip.dev = &pdev->dev; | |
131 | + puv3->chip.ops = &puv3_pwm_ops; | |
132 | + puv3->chip.base = -1; | |
133 | + puv3->chip.npwm = 1; | |
134 | + | |
135 | + ret = pwmchip_add(&puv3->chip); | |
136 | + if (ret < 0) { | |
137 | + dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); | |
138 | + return ret; | |
139 | + } | |
140 | + | |
141 | + platform_set_drvdata(pdev, puv3); | |
142 | + return 0; | |
143 | +} | |
144 | + | |
145 | +static int __devexit pwm_remove(struct platform_device *pdev) | |
146 | +{ | |
147 | + struct puv3_pwm_chip *puv3 = platform_get_drvdata(pdev); | |
148 | + | |
149 | + return pwmchip_remove(&puv3->chip); | |
150 | +} | |
151 | + | |
152 | +static struct platform_driver puv3_pwm_driver = { | |
153 | + .driver = { | |
154 | + .name = "PKUnity-v3-PWM", | |
155 | + }, | |
156 | + .probe = pwm_probe, | |
157 | + .remove = __devexit_p(pwm_remove), | |
158 | +}; | |
159 | +module_platform_driver(puv3_pwm_driver); | |
160 | + | |
161 | +MODULE_LICENSE("GPL v2"); |