diff options
author | Richard Purdie <rpurdie@rpsys.net> | 2005-11-12 09:22:11 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-01-04 16:48:28 -0500 |
commit | 81f280e22f14d6d976620acaa1b346a90f4e1adc (patch) | |
tree | 298db1ef614489451fecdd35439c630c8086a368 | |
parent | 88026842b0a760145aa71d69e74fbc9ec118ca44 (diff) |
[PATCH] USB: pxa27x OHCI - Separate platform code from main driver
To allow multiple platforms to use the PXA27x OHCI driver, the platform
code needs to be moved into the board specific files in
arch/arm/mach-pxa. This patch does this for mainstone and adds
preliminary hooks to allow other boards to use the driver.
This has been compile tested for mainstone and successfully run on Spitz
(Sharp Zaurus SL-C3000) with the addition of an appropriate board
support file.
Signed-off-by: Richard Purdie <rpurdie@rpsys.net>
Signed-off-by: Nicolas Pitre <nico@cam.org>
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | arch/arm/mach-pxa/mainstone.c | 21 | ||||
-rw-r--r-- | arch/arm/mach-pxa/pxa27x.c | 6 | ||||
-rw-r--r-- | drivers/usb/host/ohci-pxa27x.c | 85 | ||||
-rw-r--r-- | include/asm-arm/arch-pxa/ohci.h | 18 |
4 files changed, 88 insertions, 42 deletions
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 07892f4012d8..277498ae5b6c 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <asm/arch/pxafb.h> | 43 | #include <asm/arch/pxafb.h> |
44 | #include <asm/arch/mmc.h> | 44 | #include <asm/arch/mmc.h> |
45 | #include <asm/arch/irda.h> | 45 | #include <asm/arch/irda.h> |
46 | #include <asm/arch/ohci.h> | ||
46 | 47 | ||
47 | #include "generic.h" | 48 | #include "generic.h" |
48 | 49 | ||
@@ -393,6 +394,25 @@ static struct platform_device *platform_devices[] __initdata = { | |||
393 | &mst_flash_device[1], | 394 | &mst_flash_device[1], |
394 | }; | 395 | }; |
395 | 396 | ||
397 | static int mainstone_ohci_init(struct device *dev) | ||
398 | { | ||
399 | /* setup Port1 GPIO pin. */ | ||
400 | pxa_gpio_mode( 88 | GPIO_ALT_FN_1_IN); /* USBHPWR1 */ | ||
401 | pxa_gpio_mode( 89 | GPIO_ALT_FN_2_OUT); /* USBHPEN1 */ | ||
402 | |||
403 | /* Set the Power Control Polarity Low and Power Sense | ||
404 | Polarity Low to active low. */ | ||
405 | UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) & | ||
406 | ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE); | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static struct pxaohci_platform_data mainstone_ohci_platform_data = { | ||
412 | .port_mode = PMM_PERPORT_MODE, | ||
413 | .init = mainstone_ohci_init, | ||
414 | }; | ||
415 | |||
396 | static void __init mainstone_init(void) | 416 | static void __init mainstone_init(void) |
397 | { | 417 | { |
398 | int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */ | 418 | int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */ |
@@ -424,6 +444,7 @@ static void __init mainstone_init(void) | |||
424 | 444 | ||
425 | pxa_set_mci_info(&mainstone_mci_platform_data); | 445 | pxa_set_mci_info(&mainstone_mci_platform_data); |
426 | pxa_set_ficp_info(&mainstone_ficp_platform_data); | 446 | pxa_set_ficp_info(&mainstone_ficp_platform_data); |
447 | pxa_set_ohci_info(&mainstone_ohci_platform_data); | ||
427 | } | 448 | } |
428 | 449 | ||
429 | 450 | ||
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index c722a9a91fcc..b41b1efaa2cf 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <asm/hardware.h> | 21 | #include <asm/hardware.h> |
22 | #include <asm/irq.h> | 22 | #include <asm/irq.h> |
23 | #include <asm/arch/pxa-regs.h> | 23 | #include <asm/arch/pxa-regs.h> |
24 | #include <asm/arch/ohci.h> | ||
24 | 25 | ||
25 | #include "generic.h" | 26 | #include "generic.h" |
26 | 27 | ||
@@ -194,6 +195,11 @@ static struct platform_device ohci_device = { | |||
194 | .resource = pxa27x_ohci_resources, | 195 | .resource = pxa27x_ohci_resources, |
195 | }; | 196 | }; |
196 | 197 | ||
198 | void __init pxa_set_ohci_info(struct pxaohci_platform_data *info) | ||
199 | { | ||
200 | ohci_device.dev.platform_data = info; | ||
201 | } | ||
202 | |||
197 | static struct platform_device *devices[] __initdata = { | 203 | static struct platform_device *devices[] __initdata = { |
198 | &ohci_device, | 204 | &ohci_device, |
199 | }; | 205 | }; |
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 9d65ec307990..c165d1ebed5c 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c | |||
@@ -26,18 +26,12 @@ | |||
26 | #include <asm/mach-types.h> | 26 | #include <asm/mach-types.h> |
27 | #include <asm/hardware.h> | 27 | #include <asm/hardware.h> |
28 | #include <asm/arch/pxa-regs.h> | 28 | #include <asm/arch/pxa-regs.h> |
29 | 29 | #include <asm/arch/ohci.h> | |
30 | |||
31 | #define PMM_NPS_MODE 1 | ||
32 | #define PMM_GLOBAL_MODE 2 | ||
33 | #define PMM_PERPORT_MODE 3 | ||
34 | 30 | ||
35 | #define PXA_UHC_MAX_PORTNUM 3 | 31 | #define PXA_UHC_MAX_PORTNUM 3 |
36 | 32 | ||
37 | #define UHCRHPS(x) __REG2( 0x4C000050, (x)<<2 ) | 33 | #define UHCRHPS(x) __REG2( 0x4C000050, (x)<<2 ) |
38 | 34 | ||
39 | static int pxa27x_ohci_pmm_state; | ||
40 | |||
41 | /* | 35 | /* |
42 | PMM_NPS_MODE -- PMM Non-power switching mode | 36 | PMM_NPS_MODE -- PMM Non-power switching mode |
43 | Ports are powered continuously. | 37 | Ports are powered continuously. |
@@ -50,8 +44,6 @@ static int pxa27x_ohci_pmm_state; | |||
50 | */ | 44 | */ |
51 | static int pxa27x_ohci_select_pmm( int mode ) | 45 | static int pxa27x_ohci_select_pmm( int mode ) |
52 | { | 46 | { |
53 | pxa27x_ohci_pmm_state = mode; | ||
54 | |||
55 | switch ( mode ) { | 47 | switch ( mode ) { |
56 | case PMM_NPS_MODE: | 48 | case PMM_NPS_MODE: |
57 | UHCRHDA |= RH_A_NPS; | 49 | UHCRHDA |= RH_A_NPS; |
@@ -71,7 +63,6 @@ static int pxa27x_ohci_select_pmm( int mode ) | |||
71 | "Invalid mode %d, set to non-power switch mode.\n", | 63 | "Invalid mode %d, set to non-power switch mode.\n", |
72 | mode ); | 64 | mode ); |
73 | 65 | ||
74 | pxa27x_ohci_pmm_state = PMM_NPS_MODE; | ||
75 | UHCRHDA |= RH_A_NPS; | 66 | UHCRHDA |= RH_A_NPS; |
76 | } | 67 | } |
77 | 68 | ||
@@ -82,8 +73,13 @@ extern int usb_disabled(void); | |||
82 | 73 | ||
83 | /*-------------------------------------------------------------------------*/ | 74 | /*-------------------------------------------------------------------------*/ |
84 | 75 | ||
85 | static void pxa27x_start_hc(struct platform_device *dev) | 76 | static int pxa27x_start_hc(struct device *dev) |
86 | { | 77 | { |
78 | int retval = 0; | ||
79 | struct pxaohci_platform_data *inf; | ||
80 | |||
81 | inf = dev->platform_data; | ||
82 | |||
87 | pxa_set_cken(CKEN10_USBHOST, 1); | 83 | pxa_set_cken(CKEN10_USBHOST, 1); |
88 | 84 | ||
89 | UHCHR |= UHCHR_FHR; | 85 | UHCHR |= UHCHR_FHR; |
@@ -94,21 +90,11 @@ static void pxa27x_start_hc(struct platform_device *dev) | |||
94 | while (UHCHR & UHCHR_FSBIR) | 90 | while (UHCHR & UHCHR_FSBIR) |
95 | cpu_relax(); | 91 | cpu_relax(); |
96 | 92 | ||
97 | /* This could be properly abstracted away through the | 93 | if (inf->init) |
98 | device data the day more machines are supported and | 94 | retval = inf->init(dev); |
99 | their differences can be figured out correctly. */ | ||
100 | if (machine_is_mainstone()) { | ||
101 | /* setup Port1 GPIO pin. */ | ||
102 | pxa_gpio_mode( 88 | GPIO_ALT_FN_1_IN); /* USBHPWR1 */ | ||
103 | pxa_gpio_mode( 89 | GPIO_ALT_FN_2_OUT); /* USBHPEN1 */ | ||
104 | |||
105 | /* Set the Power Control Polarity Low and Power Sense | ||
106 | Polarity Low to active low. Supply power to USB ports. */ | ||
107 | UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) & | ||
108 | ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE); | ||
109 | 95 | ||
110 | pxa27x_ohci_pmm_state = PMM_PERPORT_MODE; | 96 | if (retval < 0) |
111 | } | 97 | return retval; |
112 | 98 | ||
113 | UHCHR &= ~UHCHR_SSE; | 99 | UHCHR &= ~UHCHR_SSE; |
114 | 100 | ||
@@ -117,10 +103,19 @@ static void pxa27x_start_hc(struct platform_device *dev) | |||
117 | /* Clear any OTG Pin Hold */ | 103 | /* Clear any OTG Pin Hold */ |
118 | if (PSSR & PSSR_OTGPH) | 104 | if (PSSR & PSSR_OTGPH) |
119 | PSSR |= PSSR_OTGPH; | 105 | PSSR |= PSSR_OTGPH; |
106 | |||
107 | return 0; | ||
120 | } | 108 | } |
121 | 109 | ||
122 | static void pxa27x_stop_hc(struct platform_device *dev) | 110 | static void pxa27x_stop_hc(struct device *dev) |
123 | { | 111 | { |
112 | struct pxaohci_platform_data *inf; | ||
113 | |||
114 | inf = dev->platform_data; | ||
115 | |||
116 | if (inf->exit) | ||
117 | inf->exit(dev); | ||
118 | |||
124 | UHCHR |= UHCHR_FHR; | 119 | UHCHR |= UHCHR_FHR; |
125 | udelay(11); | 120 | udelay(11); |
126 | UHCHR &= ~UHCHR_FHR; | 121 | UHCHR &= ~UHCHR_FHR; |
@@ -147,22 +142,27 @@ static void pxa27x_stop_hc(struct platform_device *dev) | |||
147 | * through the hotplug entry's driver_data. | 142 | * through the hotplug entry's driver_data. |
148 | * | 143 | * |
149 | */ | 144 | */ |
150 | int usb_hcd_pxa27x_probe (const struct hc_driver *driver, | 145 | int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device *pdev) |
151 | struct platform_device *dev) | ||
152 | { | 146 | { |
153 | int retval; | 147 | int retval; |
154 | struct usb_hcd *hcd; | 148 | struct usb_hcd *hcd; |
149 | struct pxaohci_platform_data *inf; | ||
150 | |||
151 | inf = pdev->dev.platform_data; | ||
155 | 152 | ||
156 | if (dev->resource[1].flags != IORESOURCE_IRQ) { | 153 | if (!inf) |
154 | return -ENODEV; | ||
155 | |||
156 | if (pdev->resource[1].flags != IORESOURCE_IRQ) { | ||
157 | pr_debug ("resource[1] is not IORESOURCE_IRQ"); | 157 | pr_debug ("resource[1] is not IORESOURCE_IRQ"); |
158 | return -ENOMEM; | 158 | return -ENOMEM; |
159 | } | 159 | } |
160 | 160 | ||
161 | hcd = usb_create_hcd (driver, &dev->dev, "pxa27x"); | 161 | hcd = usb_create_hcd (driver, &pdev->dev, "pxa27x"); |
162 | if (!hcd) | 162 | if (!hcd) |
163 | return -ENOMEM; | 163 | return -ENOMEM; |
164 | hcd->rsrc_start = dev->resource[0].start; | 164 | hcd->rsrc_start = pdev->resource[0].start; |
165 | hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1; | 165 | hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; |
166 | 166 | ||
167 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { | 167 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { |
168 | pr_debug("request_mem_region failed"); | 168 | pr_debug("request_mem_region failed"); |
@@ -177,18 +177,22 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, | |||
177 | goto err2; | 177 | goto err2; |
178 | } | 178 | } |
179 | 179 | ||
180 | pxa27x_start_hc(dev); | 180 | if ((retval = pxa27x_start_hc(&pdev->dev)) < 0) { |
181 | pr_debug("pxa27x_start_hc failed"); | ||
182 | goto err3; | ||
183 | } | ||
181 | 184 | ||
182 | /* Select Power Management Mode */ | 185 | /* Select Power Management Mode */ |
183 | pxa27x_ohci_select_pmm(pxa27x_ohci_pmm_state); | 186 | pxa27x_ohci_select_pmm(inf->port_mode); |
184 | 187 | ||
185 | ohci_hcd_init(hcd_to_ohci(hcd)); | 188 | ohci_hcd_init(hcd_to_ohci(hcd)); |
186 | 189 | ||
187 | retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT); | 190 | retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT); |
188 | if (retval == 0) | 191 | if (retval == 0) |
189 | return retval; | 192 | return retval; |
190 | 193 | ||
191 | pxa27x_stop_hc(dev); | 194 | pxa27x_stop_hc(&pdev->dev); |
195 | err3: | ||
192 | iounmap(hcd->regs); | 196 | iounmap(hcd->regs); |
193 | err2: | 197 | err2: |
194 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 198 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
@@ -211,10 +215,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, | |||
211 | * context, normally "rmmod", "apmd", or something similar. | 215 | * context, normally "rmmod", "apmd", or something similar. |
212 | * | 216 | * |
213 | */ | 217 | */ |
214 | void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *dev) | 218 | void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev) |
215 | { | 219 | { |
216 | usb_remove_hcd(hcd); | 220 | usb_remove_hcd(hcd); |
217 | pxa27x_stop_hc(dev); | 221 | pxa27x_stop_hc(&pdev->dev); |
218 | iounmap(hcd->regs); | 222 | iounmap(hcd->regs); |
219 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 223 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
220 | usb_put_hcd(hcd); | 224 | usb_put_hcd(hcd); |
@@ -292,15 +296,12 @@ static const struct hc_driver ohci_pxa27x_hc_driver = { | |||
292 | 296 | ||
293 | static int ohci_hcd_pxa27x_drv_probe(struct platform_device *pdev) | 297 | static int ohci_hcd_pxa27x_drv_probe(struct platform_device *pdev) |
294 | { | 298 | { |
295 | int ret; | ||
296 | |||
297 | pr_debug ("In ohci_hcd_pxa27x_drv_probe"); | 299 | pr_debug ("In ohci_hcd_pxa27x_drv_probe"); |
298 | 300 | ||
299 | if (usb_disabled()) | 301 | if (usb_disabled()) |
300 | return -ENODEV; | 302 | return -ENODEV; |
301 | 303 | ||
302 | ret = usb_hcd_pxa27x_probe(&ohci_pxa27x_hc_driver, pdev); | 304 | return usb_hcd_pxa27x_probe(&ohci_pxa27x_hc_driver, pdev); |
303 | return ret; | ||
304 | } | 305 | } |
305 | 306 | ||
306 | static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev) | 307 | static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev) |
diff --git a/include/asm-arm/arch-pxa/ohci.h b/include/asm-arm/arch-pxa/ohci.h new file mode 100644 index 000000000000..7da89569061e --- /dev/null +++ b/include/asm-arm/arch-pxa/ohci.h | |||
@@ -0,0 +1,18 @@ | |||
1 | #ifndef ASMARM_ARCH_OHCI_H | ||
2 | #define ASMARM_ARCH_OHCI_H | ||
3 | |||
4 | struct device; | ||
5 | |||
6 | struct pxaohci_platform_data { | ||
7 | int (*init)(struct device *); | ||
8 | void (*exit)(struct device *); | ||
9 | |||
10 | int port_mode; | ||
11 | #define PMM_NPS_MODE 1 | ||
12 | #define PMM_GLOBAL_MODE 2 | ||
13 | #define PMM_PERPORT_MODE 3 | ||
14 | }; | ||
15 | |||
16 | extern void pxa_set_ohci_info(struct pxaohci_platform_data *info); | ||
17 | |||
18 | #endif | ||