aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2012-03-15 05:04:35 -0400
committerThierry Reding <thierry.reding@avionic-design.de>2012-07-02 15:39:01 -0400
commit29693248edf10830db2ef82b36806e378ff75c67 (patch)
treee6607ecb7d99b2cba119939d3dbbc438c9ed519e
parent17b2b4780f879a559b8dc96c170dd6df98fe9ab3 (diff)
ARM i.MX: Move i.MX pwm driver to pwm framework
Move the driver to drivers/pwm/ and convert it to use the framework. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> [eric@eukrea.com: set chip.dev to prevent probe failure] [eric@eukrea.com: fix pwmchip_add return code test] Signed-off-by: Eric BĂ©nard <eric@eukrea.com> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
-rw-r--r--arch/arm/plat-mxc/Kconfig6
-rw-r--r--arch/arm/plat-mxc/Makefile1
-rw-r--r--drivers/pwm/Kconfig9
-rw-r--r--drivers/pwm/Makefile1
-rw-r--r--drivers/pwm/pwm-imx.c (renamed from arch/arm/plat-mxc/pwm.c)183
5 files changed, 82 insertions, 118 deletions
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
index c722f9ce6918..baf9064c0844 100644
--- a/arch/arm/plat-mxc/Kconfig
+++ b/arch/arm/plat-mxc/Kconfig
@@ -47,12 +47,6 @@ config MXC_TZIC
47config MXC_AVIC 47config MXC_AVIC
48 bool 48 bool
49 49
50config MXC_PWM
51 tristate "Enable PWM driver"
52 select HAVE_PWM
53 help
54 Enable support for the i.MX PWM controller(s).
55
56config MXC_DEBUG_BOARD 50config MXC_DEBUG_BOARD
57 bool "Enable MXC debug board(for 3-stack)" 51 bool "Enable MXC debug board(for 3-stack)"
58 help 52 help
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
index e81290c27c65..46ba8de2fe4e 100644
--- a/arch/arm/plat-mxc/Makefile
+++ b/arch/arm/plat-mxc/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_MXC_AVIC) += avic.o
11obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o 11obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o
12obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o 12obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
13obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o 13obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o
14obj-$(CONFIG_MXC_PWM) += pwm.o
15obj-$(CONFIG_MXC_ULPI) += ulpi.o 14obj-$(CONFIG_MXC_ULPI) += ulpi.o
16obj-$(CONFIG_MXC_USE_EPIT) += epit.o 15obj-$(CONFIG_MXC_USE_EPIT) += epit.o
17obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o 16obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 0ef4f3037c4a..a9a971581108 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -18,6 +18,15 @@ config PWM_BFIN
18 To compile this driver as a module, choose M here: the module 18 To compile this driver as a module, choose M here: the module
19 will be called pwm-bfin. 19 will be called pwm-bfin.
20 20
21config PWM_IMX
22 tristate "i.MX pwm support"
23 depends on ARCH_MXC
24 help
25 Generic PWM framework driver for i.MX.
26
27 To compile this driver as a module, choose M here: the module
28 will be called pwm-imx.
29
21config PWM_PXA 30config PWM_PXA
22 tristate "PXA PWM support" 31 tristate "PXA PWM support"
23 depends on ARCH_PXA 32 depends on ARCH_PXA
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index e859c513add8..3dd1b8357a0c 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -1,4 +1,5 @@
1obj-$(CONFIG_PWM) += core.o 1obj-$(CONFIG_PWM) += core.o
2obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o 2obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
3obj-$(CONFIG_PWM_IMX) += pwm-imx.o
3obj-$(CONFIG_PWM_PXA) += pwm-pxa.o 4obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
4obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o 5obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
diff --git a/arch/arm/plat-mxc/pwm.c b/drivers/pwm/pwm-imx.c
index c0cab2270dd1..900d14562de8 100644
--- a/arch/arm/plat-mxc/pwm.c
+++ b/drivers/pwm/pwm-imx.c
@@ -39,33 +39,28 @@
39#define MX3_PWMCR_CLKSRC_IPG (1 << 16) 39#define MX3_PWMCR_CLKSRC_IPG (1 << 16)
40#define MX3_PWMCR_EN (1 << 0) 40#define MX3_PWMCR_EN (1 << 0)
41 41
42 42struct imx_chip {
43
44struct pwm_device {
45 struct list_head node;
46 struct platform_device *pdev;
47
48 const char *label;
49 struct clk *clk; 43 struct clk *clk;
50 44
51 int clk_enabled; 45 int clk_enabled;
52 void __iomem *mmio_base; 46 void __iomem *mmio_base;
53 47
54 unsigned int use_count; 48 struct pwm_chip chip;
55 unsigned int pwm_id;
56}; 49};
57 50
58int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) 51#define to_imx_chip(chip) container_of(chip, struct imx_chip, chip)
52
53static int imx_pwm_config(struct pwm_chip *chip,
54 struct pwm_device *pwm, int duty_ns, int period_ns)
59{ 55{
60 if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) 56 struct imx_chip *imx = to_imx_chip(chip);
61 return -EINVAL;
62 57
63 if (!(cpu_is_mx1() || cpu_is_mx21())) { 58 if (!(cpu_is_mx1() || cpu_is_mx21())) {
64 unsigned long long c; 59 unsigned long long c;
65 unsigned long period_cycles, duty_cycles, prescale; 60 unsigned long period_cycles, duty_cycles, prescale;
66 u32 cr; 61 u32 cr;
67 62
68 c = clk_get_rate(pwm->clk); 63 c = clk_get_rate(imx->clk);
69 c = c * period_ns; 64 c = c * period_ns;
70 do_div(c, 1000000000); 65 do_div(c, 1000000000);
71 period_cycles = c; 66 period_cycles = c;
@@ -86,8 +81,8 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
86 else 81 else
87 period_cycles = 0; 82 period_cycles = 0;
88 83
89 writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR); 84 writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
90 writel(period_cycles, pwm->mmio_base + MX3_PWMPR); 85 writel(period_cycles, imx->mmio_base + MX3_PWMPR);
91 86
92 cr = MX3_PWMCR_PRESCALER(prescale) | 87 cr = MX3_PWMCR_PRESCALER(prescale) |
93 MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | 88 MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
@@ -98,7 +93,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
98 else 93 else
99 cr |= MX3_PWMCR_CLKSRC_IPG_HIGH; 94 cr |= MX3_PWMCR_CLKSRC_IPG_HIGH;
100 95
101 writel(cr, pwm->mmio_base + MX3_PWMCR); 96 writel(cr, imx->mmio_base + MX3_PWMCR);
102 } else if (cpu_is_mx1() || cpu_is_mx21()) { 97 } else if (cpu_is_mx1() || cpu_is_mx21()) {
103 /* The PWM subsystem allows for exact frequencies. However, 98 /* The PWM subsystem allows for exact frequencies. However,
104 * I cannot connect a scope on my device to the PWM line and 99 * I cannot connect a scope on my device to the PWM line and
@@ -116,110 +111,73 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
116 * both the prescaler (/1 .. /128) and then by CLKSEL 111 * both the prescaler (/1 .. /128) and then by CLKSEL
117 * (/2 .. /16). 112 * (/2 .. /16).
118 */ 113 */
119 u32 max = readl(pwm->mmio_base + MX1_PWMP); 114 u32 max = readl(imx->mmio_base + MX1_PWMP);
120 u32 p = max * duty_ns / period_ns; 115 u32 p = max * duty_ns / period_ns;
121 writel(max - p, pwm->mmio_base + MX1_PWMS); 116 writel(max - p, imx->mmio_base + MX1_PWMS);
122 } else { 117 } else {
123 BUG(); 118 BUG();
124 } 119 }
125 120
126 return 0; 121 return 0;
127} 122}
128EXPORT_SYMBOL(pwm_config);
129 123
130int pwm_enable(struct pwm_device *pwm) 124static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
131{ 125{
126 struct imx_chip *imx = to_imx_chip(chip);
132 int rc = 0; 127 int rc = 0;
133 128
134 if (!pwm->clk_enabled) { 129 if (!imx->clk_enabled) {
135 rc = clk_prepare_enable(pwm->clk); 130 rc = clk_prepare_enable(imx->clk);
136 if (!rc) 131 if (!rc)
137 pwm->clk_enabled = 1; 132 imx->clk_enabled = 1;
138 } 133 }
139 return rc; 134 return rc;
140} 135}
141EXPORT_SYMBOL(pwm_enable);
142
143void pwm_disable(struct pwm_device *pwm)
144{
145 writel(0, pwm->mmio_base + MX3_PWMCR);
146
147 if (pwm->clk_enabled) {
148 clk_disable_unprepare(pwm->clk);
149 pwm->clk_enabled = 0;
150 }
151}
152EXPORT_SYMBOL(pwm_disable);
153
154static DEFINE_MUTEX(pwm_lock);
155static LIST_HEAD(pwm_list);
156 136
157struct pwm_device *pwm_request(int pwm_id, const char *label) 137static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
158{ 138{
159 struct pwm_device *pwm; 139 struct imx_chip *imx = to_imx_chip(chip);
160 int found = 0;
161 140
162 mutex_lock(&pwm_lock); 141 writel(0, imx->mmio_base + MX3_PWMCR);
163 142
164 list_for_each_entry(pwm, &pwm_list, node) { 143 if (imx->clk_enabled) {
165 if (pwm->pwm_id == pwm_id) { 144 clk_disable_unprepare(imx->clk);
166 found = 1; 145 imx->clk_enabled = 0;
167 break;
168 }
169 } 146 }
170
171 if (found) {
172 if (pwm->use_count == 0) {
173 pwm->use_count++;
174 pwm->label = label;
175 } else
176 pwm = ERR_PTR(-EBUSY);
177 } else
178 pwm = ERR_PTR(-ENOENT);
179
180 mutex_unlock(&pwm_lock);
181 return pwm;
182} 147}
183EXPORT_SYMBOL(pwm_request);
184
185void pwm_free(struct pwm_device *pwm)
186{
187 mutex_lock(&pwm_lock);
188
189 if (pwm->use_count) {
190 pwm->use_count--;
191 pwm->label = NULL;
192 } else
193 pr_warning("PWM device already freed\n");
194 148
195 mutex_unlock(&pwm_lock); 149static struct pwm_ops imx_pwm_ops = {
196} 150 .enable = imx_pwm_enable,
197EXPORT_SYMBOL(pwm_free); 151 .disable = imx_pwm_disable,
152 .config = imx_pwm_config,
153 .owner = THIS_MODULE,
154};
198 155
199static int __devinit mxc_pwm_probe(struct platform_device *pdev) 156static int __devinit imx_pwm_probe(struct platform_device *pdev)
200{ 157{
201 struct pwm_device *pwm; 158 struct imx_chip *imx;
202 struct resource *r; 159 struct resource *r;
203 int ret = 0; 160 int ret = 0;
204 161
205 pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); 162 imx = kzalloc(sizeof(*imx), GFP_KERNEL);
206 if (pwm == NULL) { 163 if (imx == NULL) {
207 dev_err(&pdev->dev, "failed to allocate memory\n"); 164 dev_err(&pdev->dev, "failed to allocate memory\n");
208 return -ENOMEM; 165 return -ENOMEM;
209 } 166 }
210 167
211 pwm->clk = clk_get(&pdev->dev, "pwm"); 168 imx->clk = clk_get(&pdev->dev, "pwm");
212 169
213 if (IS_ERR(pwm->clk)) { 170 if (IS_ERR(imx->clk)) {
214 ret = PTR_ERR(pwm->clk); 171 ret = PTR_ERR(imx->clk);
215 goto err_free; 172 goto err_free;
216 } 173 }
217 174
218 pwm->clk_enabled = 0; 175 imx->chip.ops = &imx_pwm_ops;
176 imx->chip.dev = &pdev->dev;
177 imx->chip.base = -1;
178 imx->chip.npwm = 1;
219 179
220 pwm->use_count = 0; 180 imx->clk_enabled = 0;
221 pwm->pwm_id = pdev->id;
222 pwm->pdev = pdev;
223 181
224 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 182 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
225 if (r == NULL) { 183 if (r == NULL) {
@@ -235,72 +193,75 @@ static int __devinit mxc_pwm_probe(struct platform_device *pdev)
235 goto err_free_clk; 193 goto err_free_clk;
236 } 194 }
237 195
238 pwm->mmio_base = ioremap(r->start, resource_size(r)); 196 imx->mmio_base = ioremap(r->start, resource_size(r));
239 if (pwm->mmio_base == NULL) { 197 if (imx->mmio_base == NULL) {
240 dev_err(&pdev->dev, "failed to ioremap() registers\n"); 198 dev_err(&pdev->dev, "failed to ioremap() registers\n");
241 ret = -ENODEV; 199 ret = -ENODEV;
242 goto err_free_mem; 200 goto err_free_mem;
243 } 201 }
244 202
245 mutex_lock(&pwm_lock); 203 ret = pwmchip_add(&imx->chip);
246 list_add_tail(&pwm->node, &pwm_list); 204 if (ret < 0)
247 mutex_unlock(&pwm_lock); 205 goto err_iounmap;
248 206
249 platform_set_drvdata(pdev, pwm); 207 platform_set_drvdata(pdev, imx);
250 return 0; 208 return 0;
251 209
210err_iounmap:
211 iounmap(imx->mmio_base);
252err_free_mem: 212err_free_mem:
253 release_mem_region(r->start, resource_size(r)); 213 release_mem_region(r->start, resource_size(r));
254err_free_clk: 214err_free_clk:
255 clk_put(pwm->clk); 215 clk_put(imx->clk);
256err_free: 216err_free:
257 kfree(pwm); 217 kfree(imx);
258 return ret; 218 return ret;
259} 219}
260 220
261static int __devexit mxc_pwm_remove(struct platform_device *pdev) 221static int __devexit imx_pwm_remove(struct platform_device *pdev)
262{ 222{
263 struct pwm_device *pwm; 223 struct imx_chip *imx;
264 struct resource *r; 224 struct resource *r;
225 int ret;
265 226
266 pwm = platform_get_drvdata(pdev); 227 imx = platform_get_drvdata(pdev);
267 if (pwm == NULL) 228 if (imx == NULL)
268 return -ENODEV; 229 return -ENODEV;
269 230
270 mutex_lock(&pwm_lock); 231 ret = pwmchip_remove(&imx->chip);
271 list_del(&pwm->node); 232 if (ret)
272 mutex_unlock(&pwm_lock); 233 return ret;
273 234
274 iounmap(pwm->mmio_base); 235 iounmap(imx->mmio_base);
275 236
276 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 237 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
277 release_mem_region(r->start, resource_size(r)); 238 release_mem_region(r->start, resource_size(r));
278 239
279 clk_put(pwm->clk); 240 clk_put(imx->clk);
280 241
281 kfree(pwm); 242 kfree(imx);
282 return 0; 243 return 0;
283} 244}
284 245
285static struct platform_driver mxc_pwm_driver = { 246static struct platform_driver imx_pwm_driver = {
286 .driver = { 247 .driver = {
287 .name = "mxc_pwm", 248 .name = "mxc_pwm",
288 }, 249 },
289 .probe = mxc_pwm_probe, 250 .probe = imx_pwm_probe,
290 .remove = __devexit_p(mxc_pwm_remove), 251 .remove = __devexit_p(imx_pwm_remove),
291}; 252};
292 253
293static int __init mxc_pwm_init(void) 254static int __init imx_pwm_init(void)
294{ 255{
295 return platform_driver_register(&mxc_pwm_driver); 256 return platform_driver_register(&imx_pwm_driver);
296} 257}
297arch_initcall(mxc_pwm_init); 258arch_initcall(imx_pwm_init);
298 259
299static void __exit mxc_pwm_exit(void) 260static void __exit imx_pwm_exit(void)
300{ 261{
301 platform_driver_unregister(&mxc_pwm_driver); 262 platform_driver_unregister(&imx_pwm_driver);
302} 263}
303module_exit(mxc_pwm_exit); 264module_exit(imx_pwm_exit);
304 265
305MODULE_LICENSE("GPL v2"); 266MODULE_LICENSE("GPL v2");
306MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 267MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");