aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-pxa
diff options
context:
space:
mode:
authorIgor Grinberg <grinberg@compulab.co.il>2010-07-27 08:06:58 -0400
committerEric Miao <eric.y.miao@gmail.com>2010-10-08 04:21:17 -0400
commit69f22be7b10684ade3808de22db87c536ed135f3 (patch)
tree4b32340fcd5f616d905008917574a195345a8848 /arch/arm/mach-pxa
parentcb655d0f3d57c23db51b981648e452988c0223f9 (diff)
ARM: pxa: add U2D controller and ULPI driver for pxa3xx
USB2.0 Device Controller (U2DC) which is found in Marvell PXA3xx. U2DC supports both High and Full speed modes. PXA320 and PXA300 U2DC supports only UTMI interface. PXA310 U2DC supports only ULPI interface and has the OTG capability. U2D Controller ULPI driver introduced in this patch supports only the PXA310 USB Host via the ULPI. Signed-off-by: Igor Grinberg <grinberg@compulab.co.il> Signed-off-by: Mike Rapoport <mike@compulab.co.il> Signed-off-by: Eric Miao <eric.y.miao@gmail.com>
Diffstat (limited to 'arch/arm/mach-pxa')
-rw-r--r--arch/arm/mach-pxa/Kconfig4
-rw-r--r--arch/arm/mach-pxa/Makefile2
-rw-r--r--arch/arm/mach-pxa/devices.c28
-rw-r--r--arch/arm/mach-pxa/devices.h1
-rw-r--r--arch/arm/mach-pxa/include/mach/pxa3xx-u2d.h35
-rw-r--r--arch/arm/mach-pxa/pxa3xx-ulpi.c392
-rw-r--r--arch/arm/mach-pxa/pxa3xx.c2
7 files changed, 462 insertions, 2 deletions
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 7aefb9074852..3d4926edb675 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -643,6 +643,7 @@ config CPU_PXA300
643config CPU_PXA310 643config CPU_PXA310
644 bool 644 bool
645 select CPU_PXA300 645 select CPU_PXA300
646 select PXA310_ULPI if USB_ULPI
646 help 647 help
647 PXA310 (codename Monahans-LV) 648 PXA310 (codename Monahans-LV)
648 649
@@ -698,4 +699,7 @@ config PXA_HAVE_BOARD_IRQS
698config PXA_HAVE_ISA_IRQS 699config PXA_HAVE_ISA_IRQS
699 bool 700 bool
700 701
702config PXA310_ULPI
703 bool
704
701endif 705endif
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 85c7fb324dbb..a1db59b124f9 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -18,7 +18,7 @@ endif
18# SoC-specific code 18# SoC-specific code
19obj-$(CONFIG_PXA25x) += mfp-pxa2xx.o pxa2xx.o pxa25x.o 19obj-$(CONFIG_PXA25x) += mfp-pxa2xx.o pxa2xx.o pxa25x.o
20obj-$(CONFIG_PXA27x) += mfp-pxa2xx.o pxa2xx.o pxa27x.o 20obj-$(CONFIG_PXA27x) += mfp-pxa2xx.o pxa2xx.o pxa27x.o
21obj-$(CONFIG_PXA3xx) += mfp-pxa3xx.o pxa3xx.o smemc.o 21obj-$(CONFIG_PXA3xx) += mfp-pxa3xx.o pxa3xx.o smemc.o pxa3xx-ulpi.o
22obj-$(CONFIG_CPU_PXA300) += pxa300.o 22obj-$(CONFIG_CPU_PXA300) += pxa300.o
23obj-$(CONFIG_CPU_PXA320) += pxa320.o 23obj-$(CONFIG_CPU_PXA320) += pxa320.o
24obj-$(CONFIG_CPU_PXA930) += pxa930.o 24obj-$(CONFIG_CPU_PXA930) += pxa930.o
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index 65447dc736c2..a2fc859251da 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -6,6 +6,7 @@
6 6
7#include <asm/pmu.h> 7#include <asm/pmu.h>
8#include <mach/udc.h> 8#include <mach/udc.h>
9#include <mach/pxa3xx-u2d.h>
9#include <mach/pxafb.h> 10#include <mach/pxafb.h>
10#include <mach/mmc.h> 11#include <mach/mmc.h>
11#include <mach/irda.h> 12#include <mach/irda.h>
@@ -134,6 +135,33 @@ struct platform_device pxa27x_device_udc = {
134 } 135 }
135}; 136};
136 137
138#ifdef CONFIG_PXA3xx
139static struct resource pxa3xx_u2d_resources[] = {
140 [0] = {
141 .start = 0x54100000,
142 .end = 0x54100fff,
143 .flags = IORESOURCE_MEM,
144 },
145 [1] = {
146 .start = IRQ_USB2,
147 .end = IRQ_USB2,
148 .flags = IORESOURCE_IRQ,
149 },
150};
151
152struct platform_device pxa3xx_device_u2d = {
153 .name = "pxa3xx-u2d",
154 .id = -1,
155 .resource = pxa3xx_u2d_resources,
156 .num_resources = ARRAY_SIZE(pxa3xx_u2d_resources),
157};
158
159void __init pxa3xx_set_u2d_info(struct pxa3xx_u2d_platform_data *info)
160{
161 pxa_register_device(&pxa3xx_device_u2d, info);
162}
163#endif /* CONFIG_PXA3xx */
164
137static struct resource pxafb_resources[] = { 165static struct resource pxafb_resources[] = {
138 [0] = { 166 [0] = {
139 .start = 0x44000000, 167 .start = 0x44000000,
diff --git a/arch/arm/mach-pxa/devices.h b/arch/arm/mach-pxa/devices.h
index 50353ea49ba4..715e8bd02e24 100644
--- a/arch/arm/mach-pxa/devices.h
+++ b/arch/arm/mach-pxa/devices.h
@@ -4,6 +4,7 @@ extern struct platform_device pxa3xx_device_mci2;
4extern struct platform_device pxa3xx_device_mci3; 4extern struct platform_device pxa3xx_device_mci3;
5extern struct platform_device pxa25x_device_udc; 5extern struct platform_device pxa25x_device_udc;
6extern struct platform_device pxa27x_device_udc; 6extern struct platform_device pxa27x_device_udc;
7extern struct platform_device pxa3xx_device_u2d;
7extern struct platform_device pxa_device_fb; 8extern struct platform_device pxa_device_fb;
8extern struct platform_device pxa_device_ffuart; 9extern struct platform_device pxa_device_ffuart;
9extern struct platform_device pxa_device_btuart; 10extern struct platform_device pxa_device_btuart;
diff --git a/arch/arm/mach-pxa/include/mach/pxa3xx-u2d.h b/arch/arm/mach-pxa/include/mach/pxa3xx-u2d.h
new file mode 100644
index 000000000000..9d82cb65ea56
--- /dev/null
+++ b/arch/arm/mach-pxa/include/mach/pxa3xx-u2d.h
@@ -0,0 +1,35 @@
1/*
2 * PXA3xx U2D header
3 *
4 * Copyright (C) 2010 CompuLab Ltd.
5 *
6 * Igor Grinberg <grinberg@compulab.co.il>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __PXA310_U2D__
13#define __PXA310_U2D__
14
15#include <linux/usb/ulpi.h>
16
17struct pxa3xx_u2d_platform_data {
18
19#define ULPI_SER_6PIN (1 << 0)
20#define ULPI_SER_3PIN (1 << 1)
21 unsigned int ulpi_mode;
22
23 int (*init)(struct device *);
24 void (*exit)(struct device *);
25};
26
27
28/* Start PXA3xx U2D host */
29int pxa3xx_u2d_start_hc(struct usb_bus *host);
30/* Stop PXA3xx U2D host */
31void pxa3xx_u2d_stop_hc(struct usb_bus *host);
32
33extern void pxa3xx_set_u2d_info(struct pxa3xx_u2d_platform_data *info);
34
35#endif /* __PXA310_U2D__ */
diff --git a/arch/arm/mach-pxa/pxa3xx-ulpi.c b/arch/arm/mach-pxa/pxa3xx-ulpi.c
new file mode 100644
index 000000000000..e57439e01171
--- /dev/null
+++ b/arch/arm/mach-pxa/pxa3xx-ulpi.c
@@ -0,0 +1,392 @@
1/*
2 * linux/arch/arm/mach-pxa/pxa3xx-ulpi.c
3 *
4 * code specific to pxa3xx aka Monahans
5 *
6 * Copyright (C) 2010 CompuLab Ltd.
7 *
8 * 2010-13-07: Igor Grinberg <grinberg@compulab.co.il>
9 * initial version: pxa310 USB Host mode support
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
15
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/slab.h>
19#include <linux/device.h>
20#include <linux/platform_device.h>
21#include <linux/err.h>
22#include <linux/io.h>
23#include <linux/delay.h>
24#include <linux/clk.h>
25#include <linux/usb.h>
26#include <linux/usb/otg.h>
27
28#include <mach/hardware.h>
29#include <mach/regs-u2d.h>
30#include <mach/pxa3xx-u2d.h>
31
32struct pxa3xx_u2d_ulpi {
33 struct clk *clk;
34 void __iomem *mmio_base;
35
36 struct otg_transceiver *otg;
37 unsigned int ulpi_mode;
38};
39
40static struct pxa3xx_u2d_ulpi *u2d;
41
42static inline u32 u2d_readl(u32 reg)
43{
44 return __raw_readl(u2d->mmio_base + reg);
45}
46
47static inline void u2d_writel(u32 reg, u32 val)
48{
49 __raw_writel(val, u2d->mmio_base + reg);
50}
51
52#if defined(CONFIG_PXA310_ULPI)
53enum u2d_ulpi_phy_mode {
54 SYNCH = 0,
55 CARKIT = (1 << 0),
56 SER_3PIN = (1 << 1),
57 SER_6PIN = (1 << 2),
58 LOWPOWER = (1 << 3),
59};
60
61static inline enum u2d_ulpi_phy_mode pxa310_ulpi_get_phymode(void)
62{
63 return (u2d_readl(U2DOTGUSR) >> 28) & 0xF;
64}
65
66static int pxa310_ulpi_poll(void)
67{
68 int timeout = 50000;
69
70 while (timeout--) {
71 if (!(u2d_readl(U2DOTGUCR) & U2DOTGUCR_RUN))
72 return 0;
73
74 cpu_relax();
75 }
76
77 pr_warning("%s: ULPI access timed out!\n", __func__);
78
79 return -ETIMEDOUT;
80}
81
82static int pxa310_ulpi_read(struct otg_transceiver *otg, u32 reg)
83{
84 int err;
85
86 if (pxa310_ulpi_get_phymode() != SYNCH) {
87 pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
88 return -EBUSY;
89 }
90
91 u2d_writel(U2DOTGUCR, U2DOTGUCR_RUN | U2DOTGUCR_RNW | (reg << 16));
92 msleep(5);
93
94 err = pxa310_ulpi_poll();
95 if (err)
96 return err;
97
98 return u2d_readl(U2DOTGUCR) & U2DOTGUCR_RDATA;
99}
100
101static int pxa310_ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
102{
103 if (pxa310_ulpi_get_phymode() != SYNCH) {
104 pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
105 return -EBUSY;
106 }
107
108 u2d_writel(U2DOTGUCR, U2DOTGUCR_RUN | (reg << 16) | (val << 8));
109 msleep(5);
110
111 return pxa310_ulpi_poll();
112}
113
114struct otg_io_access_ops pxa310_ulpi_access_ops = {
115 .read = pxa310_ulpi_read,
116 .write = pxa310_ulpi_write,
117};
118
119static void pxa310_otg_transceiver_rtsm(void)
120{
121 u32 u2dotgcr;
122
123 /* put PHY to sync mode */
124 u2dotgcr = u2d_readl(U2DOTGCR);
125 u2dotgcr |= U2DOTGCR_RTSM | U2DOTGCR_UTMID;
126 u2d_writel(U2DOTGCR, u2dotgcr);
127 msleep(10);
128
129 /* setup OTG sync mode */
130 u2dotgcr = u2d_readl(U2DOTGCR);
131 u2dotgcr |= U2DOTGCR_ULAF;
132 u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
133 u2d_writel(U2DOTGCR, u2dotgcr);
134}
135
136static int pxa310_start_otg_host_transcvr(struct usb_bus *host)
137{
138 int err;
139
140 pxa310_otg_transceiver_rtsm();
141
142 err = otg_init(u2d->otg);
143 if (err) {
144 pr_err("OTG transceiver init failed");
145 return err;
146 }
147
148 err = otg_set_vbus(u2d->otg, 1);
149 if (err) {
150 pr_err("OTG transceiver VBUS set failed");
151 return err;
152 }
153
154 err = otg_set_host(u2d->otg, host);
155 if (err)
156 pr_err("OTG transceiver Host mode set failed");
157
158 return err;
159}
160
161static int pxa310_start_otg_hc(struct usb_bus *host)
162{
163 u32 u2dotgcr;
164 int err;
165
166 /* disable USB device controller */
167 u2d_writel(U2DCR, u2d_readl(U2DCR) & ~U2DCR_UDE);
168 u2d_writel(U2DOTGCR, u2d_readl(U2DOTGCR) | U2DOTGCR_UTMID);
169 u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~0x37F7F);
170
171 err = pxa310_start_otg_host_transcvr(host);
172 if (err)
173 return err;
174
175 /* set xceiver mode */
176 if (u2d->ulpi_mode & ULPI_IC_6PIN_SERIAL)
177 u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) & ~U2DP3CR_P2SS);
178 else if (u2d->ulpi_mode & ULPI_IC_3PIN_SERIAL)
179 u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) | U2DP3CR_P2SS);
180
181 /* start OTG host controller */
182 u2dotgcr = u2d_readl(U2DOTGCR) | U2DOTGCR_SMAF;
183 u2d_writel(U2DOTGCR, u2dotgcr & ~(U2DOTGCR_ULAF | U2DOTGCR_CKAF));
184
185 return 0;
186}
187
188static void pxa310_stop_otg_hc(void)
189{
190 pxa310_otg_transceiver_rtsm();
191
192 otg_set_host(u2d->otg, NULL);
193 otg_set_vbus(u2d->otg, 0);
194 otg_shutdown(u2d->otg);
195}
196
197static void pxa310_u2d_setup_otg_hc(void)
198{
199 u32 u2dotgcr;
200
201 u2dotgcr = u2d_readl(U2DOTGCR);
202 u2dotgcr |= U2DOTGCR_ULAF | U2DOTGCR_UTMID;
203 u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
204 u2d_writel(U2DOTGCR, u2dotgcr);
205 msleep(5);
206 u2d_writel(U2DOTGCR, u2dotgcr | U2DOTGCR_ULE);
207 msleep(5);
208 u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~0x37F7F);
209}
210
211static int pxa310_otg_init(struct pxa3xx_u2d_platform_data *pdata)
212{
213 unsigned int ulpi_mode = ULPI_OTG_DRVVBUS;
214
215 if (pdata) {
216 if (pdata->ulpi_mode & ULPI_SER_6PIN)
217 ulpi_mode |= ULPI_IC_6PIN_SERIAL;
218 else if (pdata->ulpi_mode & ULPI_SER_3PIN)
219 ulpi_mode |= ULPI_IC_3PIN_SERIAL;
220 }
221
222 u2d->ulpi_mode = ulpi_mode;
223
224 u2d->otg = otg_ulpi_create(&pxa310_ulpi_access_ops, ulpi_mode);
225 if (!u2d->otg)
226 return -ENOMEM;
227
228 u2d->otg->io_priv = u2d->mmio_base;
229
230 return 0;
231}
232
233static void pxa310_otg_exit(void)
234{
235 kfree(u2d->otg);
236}
237#else
238static inline void pxa310_u2d_setup_otg_hc(void) {}
239static inline int pxa310_start_otg_hc(struct usb_bus *host)
240{
241 return 0;
242}
243static inline void pxa310_stop_otg_hc(void) {}
244static inline int pxa310_otg_init(struct pxa3xx_u2d_platform_data *pdata)
245{
246 return 0;
247}
248static inline void pxa310_otg_exit(void) {}
249#endif /* CONFIG_PXA310_ULPI */
250
251int pxa3xx_u2d_start_hc(struct usb_bus *host)
252{
253 int err = 0;
254
255 clk_enable(u2d->clk);
256
257 if (cpu_is_pxa310()) {
258 pxa310_u2d_setup_otg_hc();
259 err = pxa310_start_otg_hc(host);
260 }
261
262 return err;
263}
264
265void pxa3xx_u2d_stop_hc(struct usb_bus *host)
266{
267 if (cpu_is_pxa310())
268 pxa310_stop_otg_hc();
269
270 clk_disable(u2d->clk);
271}
272
273static int pxa3xx_u2d_probe(struct platform_device *pdev)
274{
275 struct pxa3xx_u2d_platform_data *pdata = pdev->dev.platform_data;
276 struct resource *r;
277 int err;
278
279 u2d = kzalloc(sizeof(struct pxa3xx_u2d_ulpi), GFP_KERNEL);
280 if (!u2d) {
281 dev_err(&pdev->dev, "failed to allocate memory\n");
282 return -ENOMEM;
283 }
284
285 u2d->clk = clk_get(&pdev->dev, NULL);
286 if (IS_ERR(u2d->clk)) {
287 dev_err(&pdev->dev, "failed to get u2d clock\n");
288 err = PTR_ERR(u2d->clk);
289 goto err_free_mem;
290 }
291
292 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
293 if (!r) {
294 dev_err(&pdev->dev, "no IO memory resource defined\n");
295 err = -ENODEV;
296 goto err_put_clk;
297 }
298
299 r = request_mem_region(r->start, resource_size(r), pdev->name);
300 if (!r) {
301 dev_err(&pdev->dev, "failed to request memory resource\n");
302 err = -EBUSY;
303 goto err_put_clk;
304 }
305
306 u2d->mmio_base = ioremap(r->start, resource_size(r));
307 if (!u2d->mmio_base) {
308 dev_err(&pdev->dev, "ioremap() failed\n");
309 err = -ENODEV;
310 goto err_free_res;
311 }
312
313 if (pdata->init) {
314 err = pdata->init(&pdev->dev);
315 if (err)
316 goto err_free_io;
317 }
318
319 /* Only PXA310 U2D has OTG functionality */
320 if (cpu_is_pxa310()) {
321 err = pxa310_otg_init(pdata);
322 if (err)
323 goto err_free_plat;
324 }
325
326 platform_set_drvdata(pdev, &u2d);
327
328 return 0;
329
330err_free_plat:
331 if (pdata->exit)
332 pdata->exit(&pdev->dev);
333err_free_io:
334 iounmap(u2d->mmio_base);
335err_free_res:
336 release_mem_region(r->start, resource_size(r));
337err_put_clk:
338 clk_put(u2d->clk);
339err_free_mem:
340 kfree(u2d);
341 return err;
342}
343
344static int pxa3xx_u2d_remove(struct platform_device *pdev)
345{
346 struct pxa3xx_u2d_platform_data *pdata = pdev->dev.platform_data;
347 struct resource *r;
348
349 if (cpu_is_pxa310()) {
350 pxa310_stop_otg_hc();
351 pxa310_otg_exit();
352 }
353
354 if (pdata->exit)
355 pdata->exit(&pdev->dev);
356
357 platform_set_drvdata(pdev, NULL);
358 iounmap(u2d->mmio_base);
359 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
360 release_mem_region(r->start, resource_size(r));
361
362 clk_put(u2d->clk);
363
364 kfree(u2d);
365
366 return 0;
367}
368
369static struct platform_driver pxa3xx_u2d_ulpi_driver = {
370 .driver = {
371 .name = "pxa3xx-u2d",
372 .owner = THIS_MODULE,
373 },
374 .probe = pxa3xx_u2d_probe,
375 .remove = pxa3xx_u2d_remove,
376};
377
378static int pxa3xx_u2d_ulpi_init(void)
379{
380 return platform_driver_register(&pxa3xx_u2d_ulpi_driver);
381}
382module_init(pxa3xx_u2d_ulpi_init);
383
384static void __exit pxa3xx_u2d_ulpi_exit(void)
385{
386 platform_driver_unregister(&pxa3xx_u2d_ulpi_driver);
387}
388module_exit(pxa3xx_u2d_ulpi_exit);
389
390MODULE_DESCRIPTION("PXA3xx U2D ULPI driver");
391MODULE_AUTHOR("Igor Grinberg");
392MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index fa0014847c71..cf2bd26dcbab 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -265,7 +265,7 @@ static struct clk_lookup pxa3xx_clkregs[] = {
265 INIT_CLKREG(&clk_pxa3xx_i2c, "pxa2xx-i2c.0", NULL), 265 INIT_CLKREG(&clk_pxa3xx_i2c, "pxa2xx-i2c.0", NULL),
266 INIT_CLKREG(&clk_pxa3xx_udc, "pxa27x-udc", NULL), 266 INIT_CLKREG(&clk_pxa3xx_udc, "pxa27x-udc", NULL),
267 INIT_CLKREG(&clk_pxa3xx_usbh, "pxa27x-ohci", NULL), 267 INIT_CLKREG(&clk_pxa3xx_usbh, "pxa27x-ohci", NULL),
268 INIT_CLKREG(&clk_pxa3xx_u2d, NULL, "U2DCLK"), 268 INIT_CLKREG(&clk_pxa3xx_u2d, "pxa3xx-u2d", NULL),
269 INIT_CLKREG(&clk_pxa3xx_keypad, "pxa27x-keypad", NULL), 269 INIT_CLKREG(&clk_pxa3xx_keypad, "pxa27x-keypad", NULL),
270 INIT_CLKREG(&clk_pxa3xx_ssp1, "pxa27x-ssp.0", NULL), 270 INIT_CLKREG(&clk_pxa3xx_ssp1, "pxa27x-ssp.0", NULL),
271 INIT_CLKREG(&clk_pxa3xx_ssp2, "pxa27x-ssp.1", NULL), 271 INIT_CLKREG(&clk_pxa3xx_ssp2, "pxa27x-ssp.1", NULL),