diff options
Diffstat (limited to 'drivers/usb/host/ohci-pxa27x.c')
| -rw-r--r-- | drivers/usb/host/ohci-pxa27x.c | 121 |
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 | ||
| 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; | ||
| 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 | */ |
| 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) |
| @@ -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 | ||
| 314 | static int ohci_hcd_pxa27x_drv_suspend(struct platform_device *dev, pm_message_t state) | 316 | #ifdef CONFIG_PM |
| 317 | static 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 | ||
| 322 | static int ohci_hcd_pxa27x_drv_resume(struct platform_device *dev) | 333 | static 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 | ||
| 331 | static struct platform_driver ohci_hcd_pxa27x_driver = { | 354 | static 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 | }, |
