Commit 81f280e2 authored by Richard Purdie's avatar Richard Purdie Committed by Greg Kroah-Hartman

[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: default avatarRichard Purdie <rpurdie@rpsys.net>
Signed-off-by: default avatarNicolas Pitre <nico@cam.org>
Acked-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 88026842
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include <asm/arch/pxafb.h> #include <asm/arch/pxafb.h>
#include <asm/arch/mmc.h> #include <asm/arch/mmc.h>
#include <asm/arch/irda.h> #include <asm/arch/irda.h>
#include <asm/arch/ohci.h>
#include "generic.h" #include "generic.h"
...@@ -393,6 +394,25 @@ static struct platform_device *platform_devices[] __initdata = { ...@@ -393,6 +394,25 @@ static struct platform_device *platform_devices[] __initdata = {
&mst_flash_device[1], &mst_flash_device[1],
}; };
static int mainstone_ohci_init(struct device *dev)
{
/* setup Port1 GPIO pin. */
pxa_gpio_mode( 88 | GPIO_ALT_FN_1_IN); /* USBHPWR1 */
pxa_gpio_mode( 89 | GPIO_ALT_FN_2_OUT); /* USBHPEN1 */
/* Set the Power Control Polarity Low and Power Sense
Polarity Low to active low. */
UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) &
~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE);
return 0;
}
static struct pxaohci_platform_data mainstone_ohci_platform_data = {
.port_mode = PMM_PERPORT_MODE,
.init = mainstone_ohci_init,
};
static void __init mainstone_init(void) static void __init mainstone_init(void)
{ {
int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */ 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,6 +444,7 @@ static void __init mainstone_init(void)
pxa_set_mci_info(&mainstone_mci_platform_data); pxa_set_mci_info(&mainstone_mci_platform_data);
pxa_set_ficp_info(&mainstone_ficp_platform_data); pxa_set_ficp_info(&mainstone_ficp_platform_data);
pxa_set_ohci_info(&mainstone_ohci_platform_data);
} }
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pxa-regs.h> #include <asm/arch/pxa-regs.h>
#include <asm/arch/ohci.h>
#include "generic.h" #include "generic.h"
...@@ -194,6 +195,11 @@ static struct platform_device ohci_device = { ...@@ -194,6 +195,11 @@ static struct platform_device ohci_device = {
.resource = pxa27x_ohci_resources, .resource = pxa27x_ohci_resources,
}; };
void __init pxa_set_ohci_info(struct pxaohci_platform_data *info)
{
ohci_device.dev.platform_data = info;
}
static struct platform_device *devices[] __initdata = { static struct platform_device *devices[] __initdata = {
&ohci_device, &ohci_device,
}; };
......
...@@ -26,18 +26,12 @@ ...@@ -26,18 +26,12 @@
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/arch/pxa-regs.h> #include <asm/arch/pxa-regs.h>
#include <asm/arch/ohci.h>
#define PMM_NPS_MODE 1
#define PMM_GLOBAL_MODE 2
#define PMM_PERPORT_MODE 3
#define PXA_UHC_MAX_PORTNUM 3 #define PXA_UHC_MAX_PORTNUM 3
#define UHCRHPS(x) __REG2( 0x4C000050, (x)<<2 ) #define UHCRHPS(x) __REG2( 0x4C000050, (x)<<2 )
static int pxa27x_ohci_pmm_state;
/* /*
PMM_NPS_MODE -- PMM Non-power switching mode PMM_NPS_MODE -- PMM Non-power switching mode
Ports are powered continuously. Ports are powered continuously.
...@@ -50,8 +44,6 @@ static int pxa27x_ohci_pmm_state; ...@@ -50,8 +44,6 @@ static int pxa27x_ohci_pmm_state;
*/ */
static int pxa27x_ohci_select_pmm( int mode ) static int pxa27x_ohci_select_pmm( int mode )
{ {
pxa27x_ohci_pmm_state = mode;
switch ( mode ) { switch ( mode ) {
case PMM_NPS_MODE: case PMM_NPS_MODE:
UHCRHDA |= RH_A_NPS; UHCRHDA |= RH_A_NPS;
...@@ -71,7 +63,6 @@ static int pxa27x_ohci_select_pmm( int mode ) ...@@ -71,7 +63,6 @@ static int pxa27x_ohci_select_pmm( int mode )
"Invalid mode %d, set to non-power switch mode.\n", "Invalid mode %d, set to non-power switch mode.\n",
mode ); mode );
pxa27x_ohci_pmm_state = PMM_NPS_MODE;
UHCRHDA |= RH_A_NPS; UHCRHDA |= RH_A_NPS;
} }
...@@ -82,8 +73,13 @@ extern int usb_disabled(void); ...@@ -82,8 +73,13 @@ extern int usb_disabled(void);
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static void pxa27x_start_hc(struct platform_device *dev) static int pxa27x_start_hc(struct device *dev)
{ {
int retval = 0;
struct pxaohci_platform_data *inf;
inf = dev->platform_data;
pxa_set_cken(CKEN10_USBHOST, 1); pxa_set_cken(CKEN10_USBHOST, 1);
UHCHR |= UHCHR_FHR; UHCHR |= UHCHR_FHR;
...@@ -94,21 +90,11 @@ static void pxa27x_start_hc(struct platform_device *dev) ...@@ -94,21 +90,11 @@ static void pxa27x_start_hc(struct platform_device *dev)
while (UHCHR & UHCHR_FSBIR) while (UHCHR & UHCHR_FSBIR)
cpu_relax(); cpu_relax();
/* This could be properly abstracted away through the if (inf->init)
device data the day more machines are supported and retval = inf->init(dev);
their differences can be figured out correctly. */
if (machine_is_mainstone()) {
/* setup Port1 GPIO pin. */
pxa_gpio_mode( 88 | GPIO_ALT_FN_1_IN); /* USBHPWR1 */
pxa_gpio_mode( 89 | GPIO_ALT_FN_2_OUT); /* USBHPEN1 */
/* Set the Power Control Polarity Low and Power Sense
Polarity Low to active low. Supply power to USB ports. */
UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) &
~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE);
pxa27x_ohci_pmm_state = PMM_PERPORT_MODE; if (retval < 0)
} return retval;
UHCHR &= ~UHCHR_SSE; UHCHR &= ~UHCHR_SSE;
...@@ -117,10 +103,19 @@ static void pxa27x_start_hc(struct platform_device *dev) ...@@ -117,10 +103,19 @@ static void pxa27x_start_hc(struct platform_device *dev)
/* Clear any OTG Pin Hold */ /* Clear any OTG Pin Hold */
if (PSSR & PSSR_OTGPH) if (PSSR & PSSR_OTGPH)
PSSR |= PSSR_OTGPH; PSSR |= PSSR_OTGPH;
return 0;
} }
static void pxa27x_stop_hc(struct platform_device *dev) static void pxa27x_stop_hc(struct device *dev)
{ {
struct pxaohci_platform_data *inf;
inf = dev->platform_data;
if (inf->exit)
inf->exit(dev);
UHCHR |= UHCHR_FHR; UHCHR |= UHCHR_FHR;
udelay(11); udelay(11);
UHCHR &= ~UHCHR_FHR; UHCHR &= ~UHCHR_FHR;
...@@ -147,22 +142,27 @@ static void pxa27x_stop_hc(struct platform_device *dev) ...@@ -147,22 +142,27 @@ static void pxa27x_stop_hc(struct platform_device *dev)
* through the hotplug entry's driver_data. * through the hotplug entry's driver_data.
* *
*/ */
int usb_hcd_pxa27x_probe (const struct hc_driver *driver, int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device *pdev)
struct platform_device *dev)
{ {
int retval; int retval;
struct usb_hcd *hcd; struct usb_hcd *hcd;
struct pxaohci_platform_data *inf;
inf = pdev->dev.platform_data;
if (dev->resource[1].flags != IORESOURCE_IRQ) { if (!inf)
return -ENODEV;
if (pdev->resource[1].flags != IORESOURCE_IRQ) {
pr_debug ("resource[1] is not IORESOURCE_IRQ"); pr_debug ("resource[1] is not IORESOURCE_IRQ");
return -ENOMEM; return -ENOMEM;
} }
hcd = usb_create_hcd (driver, &dev->dev, "pxa27x"); hcd = usb_create_hcd (driver, &pdev->dev, "pxa27x");
if (!hcd) if (!hcd)
return -ENOMEM; return -ENOMEM;
hcd->rsrc_start = dev->resource[0].start; hcd->rsrc_start = pdev->resource[0].start;
hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1; hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
pr_debug("request_mem_region failed"); pr_debug("request_mem_region failed");
...@@ -177,18 +177,22 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, ...@@ -177,18 +177,22 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver,
goto err2; goto err2;
} }
pxa27x_start_hc(dev); if ((retval = pxa27x_start_hc(&pdev->dev)) < 0) {
pr_debug("pxa27x_start_hc failed");
goto err3;
}
/* Select Power Management Mode */ /* Select Power Management Mode */
pxa27x_ohci_select_pmm(pxa27x_ohci_pmm_state); pxa27x_ohci_select_pmm(inf->port_mode);
ohci_hcd_init(hcd_to_ohci(hcd)); ohci_hcd_init(hcd_to_ohci(hcd));
retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT); retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT);
if (retval == 0) if (retval == 0)
return retval; return retval;
pxa27x_stop_hc(dev); pxa27x_stop_hc(&pdev->dev);
err3:
iounmap(hcd->regs); iounmap(hcd->regs);
err2: err2:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len); release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
...@@ -211,10 +215,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, ...@@ -211,10 +215,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver,
* context, normally "rmmod", "apmd", or something similar. * context, normally "rmmod", "apmd", or something similar.
* *
*/ */
void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *dev) void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev)
{ {
usb_remove_hcd(hcd); usb_remove_hcd(hcd);
pxa27x_stop_hc(dev); pxa27x_stop_hc(&pdev->dev);
iounmap(hcd->regs); iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len); release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd); usb_put_hcd(hcd);
...@@ -292,15 +296,12 @@ static const struct hc_driver ohci_pxa27x_hc_driver = { ...@@ -292,15 +296,12 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
static int ohci_hcd_pxa27x_drv_probe(struct platform_device *pdev) static int ohci_hcd_pxa27x_drv_probe(struct platform_device *pdev)
{ {
int ret;
pr_debug ("In ohci_hcd_pxa27x_drv_probe"); pr_debug ("In ohci_hcd_pxa27x_drv_probe");
if (usb_disabled()) if (usb_disabled())
return -ENODEV; return -ENODEV;
ret = usb_hcd_pxa27x_probe(&ohci_pxa27x_hc_driver, pdev); return usb_hcd_pxa27x_probe(&ohci_pxa27x_hc_driver, pdev);
return ret;
} }
static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev) static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev)
......
#ifndef ASMARM_ARCH_OHCI_H
#define ASMARM_ARCH_OHCI_H
struct device;
struct pxaohci_platform_data {
int (*init)(struct device *);
void (*exit)(struct device *);
int port_mode;
#define PMM_NPS_MODE 1
#define PMM_GLOBAL_MODE 2
#define PMM_PERPORT_MODE 3
};
extern void pxa_set_ohci_info(struct pxaohci_platform_data *info);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment