aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ohci-pxa27x.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ohci-pxa27x.c')
-rw-r--r--drivers/usb/host/ohci-pxa27x.c121
1 files changed, 73 insertions, 48 deletions
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 9d65ec307990..acde8868da21 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
39static 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 */
51static int pxa27x_ohci_select_pmm( int mode ) 45static 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
85static void pxa27x_start_hc(struct platform_device *dev) 76static 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
122static void pxa27x_stop_hc(struct platform_device *dev) 110static 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 */
150int usb_hcd_pxa27x_probe (const struct hc_driver *driver, 145int 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;
155 150
156 if (dev->resource[1].flags != IORESOURCE_IRQ) { 151 inf = pdev->dev.platform_data;
152
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 */
214void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *dev) 218void 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
293static int ohci_hcd_pxa27x_drv_probe(struct platform_device *pdev) 297static 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
306static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev) 307static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev)
@@ -308,31 +309,55 @@ static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev)
308 struct usb_hcd *hcd = platform_get_drvdata(pdev); 309 struct usb_hcd *hcd = platform_get_drvdata(pdev);
309 310
310 usb_hcd_pxa27x_remove(hcd, pdev); 311 usb_hcd_pxa27x_remove(hcd, pdev);
312 platform_set_drvdata(pdev, NULL);
311 return 0; 313 return 0;
312} 314}
313 315
314static int ohci_hcd_pxa27x_drv_suspend(struct platform_device *dev, pm_message_t state) 316#ifdef CONFIG_PM
317static int ohci_hcd_pxa27x_drv_suspend(struct platform_device *pdev, pm_message_t state)
315{ 318{
316// struct usb_hcd *hcd = platform_get_drvdata(dev); 319 struct usb_hcd *hcd = platform_get_drvdata(pdev);
317 printk("%s: not implemented yet\n", __FUNCTION__); 320 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
321
322 if (time_before(jiffies, ohci->next_statechange))
323 msleep(5);
324 ohci->next_statechange = jiffies;
325
326 pxa27x_stop_hc(&pdev->dev);
327 hcd->state = HC_STATE_SUSPENDED;
328 pdev->dev.power.power_state = PMSG_SUSPEND;
318 329
319 return 0; 330 return 0;
320} 331}
321 332
322static int ohci_hcd_pxa27x_drv_resume(struct platform_device *dev) 333static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev)
323{ 334{
324// struct usb_hcd *hcd = platform_get_drvdata(dev); 335 struct usb_hcd *hcd = platform_get_drvdata(pdev);
325 printk("%s: not implemented yet\n", __FUNCTION__); 336 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
337 int status;
338
339 if (time_before(jiffies, ohci->next_statechange))
340 msleep(5);
341 ohci->next_statechange = jiffies;
342
343 if ((status = pxa27x_start_hc(&pdev->dev)) < 0)
344 return status;
345
346 pdev->dev.power.power_state = PMSG_ON;
347 usb_hcd_resume_root_hub(hcd);
326 348
327 return 0; 349 return 0;
328} 350}
351#endif
329 352
330 353
331static struct platform_driver ohci_hcd_pxa27x_driver = { 354static struct platform_driver ohci_hcd_pxa27x_driver = {
332 .probe = ohci_hcd_pxa27x_drv_probe, 355 .probe = ohci_hcd_pxa27x_drv_probe,
333 .remove = ohci_hcd_pxa27x_drv_remove, 356 .remove = ohci_hcd_pxa27x_drv_remove,
357#ifdef CONFIG_PM
334 .suspend = ohci_hcd_pxa27x_drv_suspend, 358 .suspend = ohci_hcd_pxa27x_drv_suspend,
335 .resume = ohci_hcd_pxa27x_drv_resume, 359 .resume = ohci_hcd_pxa27x_drv_resume,
360#endif
336 .driver = { 361 .driver = {
337 .name = "pxa27x-ohci", 362 .name = "pxa27x-ohci",
338 }, 363 },