diff options
Diffstat (limited to 'drivers/usb/host/ohci-pxa27x.c')
| -rw-r--r-- | drivers/usb/host/ohci-pxa27x.c | 428 | 
1 files changed, 263 insertions, 165 deletions
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index afef7b0a419..e68f3d02cd1 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -19,12 +19,28 @@   * This file is licenced under the GPL.   */ +#include <linux/clk.h>  #include <linux/device.h> -#include <linux/signal.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/of_gpio.h> +#include <linux/platform_data/usb-ohci-pxa27x.h> +#include <linux/platform_data/usb-pxa3xx-ulpi.h>  #include <linux/platform_device.h> -#include <linux/clk.h> -#include <mach/ohci.h> -#include <mach/pxa3xx-u2d.h> +#include <linux/regulator/consumer.h> +#include <linux/signal.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/usb/otg.h> + +#include <mach/hardware.h> + +#include "ohci.h" + +#define DRIVER_DESC "OHCI PXA27x/PXA3x driver"  /*   * UHC: USB Host Controller (OHCI-like) register definitions @@ -98,16 +114,18 @@  #define PXA_UHC_MAX_PORTNUM    3 -struct pxa27x_ohci { -	/* must be 1st member here for hcd_to_ohci() to work */ -	struct ohci_hcd ohci; +static const char hcd_name[] = "ohci-pxa27x"; + +static struct hc_driver __read_mostly ohci_pxa27x_hc_driver; -	struct device	*dev; +struct pxa27x_ohci {  	struct clk	*clk;  	void __iomem	*mmio_base; +	struct regulator *vbus[3]; +	bool		vbus_enabled[3];  }; -#define to_pxa27x_ohci(hcd)	(struct pxa27x_ohci *)hcd_to_ohci(hcd) +#define to_pxa27x_ohci(hcd)	(struct pxa27x_ohci *)(hcd_to_ohci(hcd)->priv)  /*    PMM_NPS_MODE -- PMM Non-power switching mode @@ -119,10 +137,10 @@ struct pxa27x_ohci {    PMM_PERPORT_MODE -- PMM per port switching mode        Ports are powered individually.   */ -static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *ohci, int mode) +static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *pxa_ohci, int mode)  { -	uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA); -	uint32_t uhcrhdb = __raw_readl(ohci->mmio_base + UHCRHDB); +	uint32_t uhcrhda = __raw_readl(pxa_ohci->mmio_base + UHCRHDA); +	uint32_t uhcrhdb = __raw_readl(pxa_ohci->mmio_base + UHCRHDB);  	switch (mode) {  	case PMM_NPS_MODE: @@ -146,20 +164,64 @@ static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *ohci, int mode)  		uhcrhda |= RH_A_NPS;  	} -	__raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA); -	__raw_writel(uhcrhdb, ohci->mmio_base + UHCRHDB); +	__raw_writel(uhcrhda, pxa_ohci->mmio_base + UHCRHDA); +	__raw_writel(uhcrhdb, pxa_ohci->mmio_base + UHCRHDB);  	return 0;  } -extern int usb_disabled(void); +static int pxa27x_ohci_set_vbus_power(struct pxa27x_ohci *pxa_ohci, +				      unsigned int port, bool enable) +{ +	struct regulator *vbus = pxa_ohci->vbus[port]; +	int ret = 0; +	if (IS_ERR_OR_NULL(vbus)) +		return 0; + +	if (enable && !pxa_ohci->vbus_enabled[port]) +		ret = regulator_enable(vbus); +	else if (!enable && pxa_ohci->vbus_enabled[port]) +		ret = regulator_disable(vbus); + +	if (ret < 0) +		return ret; + +	pxa_ohci->vbus_enabled[port] = enable; + +	return 0; +} + +static int pxa27x_ohci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, +				   u16 wIndex, char *buf, u16 wLength) +{ +	struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); +	int ret; + +	switch (typeReq) { +	case SetPortFeature: +	case ClearPortFeature: +		if (!wIndex || wIndex > 3) +			return -EPIPE; + +		if (wValue != USB_PORT_FEAT_POWER) +			break; + +		ret = pxa27x_ohci_set_vbus_power(pxa_ohci, wIndex - 1, +						 typeReq == SetPortFeature); +		if (ret) +			return ret; +		break; +	} + +	return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); +}  /*-------------------------------------------------------------------------*/ -static inline void pxa27x_setup_hc(struct pxa27x_ohci *ohci, +static inline void pxa27x_setup_hc(struct pxa27x_ohci *pxa_ohci,  				   struct pxaohci_platform_data *inf)  { -	uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR); -	uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA); +	uint32_t uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR); +	uint32_t uhcrhda = __raw_readl(pxa_ohci->mmio_base + UHCRHDA);  	if (inf->flags & ENABLE_PORT1)  		uhchr &= ~UHCHR_SSEP1; @@ -191,17 +253,17 @@ static inline void pxa27x_setup_hc(struct pxa27x_ohci *ohci,  		uhcrhda |= UHCRHDA_POTPGT(inf->power_on_delay / 2);  	} -	__raw_writel(uhchr, ohci->mmio_base + UHCHR); -	__raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA); +	__raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR); +	__raw_writel(uhcrhda, pxa_ohci->mmio_base + UHCRHDA);  } -static inline void pxa27x_reset_hc(struct pxa27x_ohci *ohci) +static inline void pxa27x_reset_hc(struct pxa27x_ohci *pxa_ohci)  { -	uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR); +	uint32_t uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR); -	__raw_writel(uhchr | UHCHR_FHR, ohci->mmio_base + UHCHR); +	__raw_writel(uhchr | UHCHR_FHR, pxa_ohci->mmio_base + UHCHR);  	udelay(11); -	__raw_writel(uhchr & ~UHCHR_FHR, ohci->mmio_base + UHCHR); +	__raw_writel(uhchr & ~UHCHR_FHR, pxa_ohci->mmio_base + UHCHR);  }  #ifdef CONFIG_PXA27x @@ -210,25 +272,26 @@ extern void pxa27x_clear_otgph(void);  #define pxa27x_clear_otgph()	do {} while (0)  #endif -static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev) +static int pxa27x_start_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev)  {  	int retval = 0;  	struct pxaohci_platform_data *inf;  	uint32_t uhchr; +	struct usb_hcd *hcd = dev_get_drvdata(dev); -	inf = dev->platform_data; +	inf = dev_get_platdata(dev); -	clk_enable(ohci->clk); +	clk_prepare_enable(pxa_ohci->clk); -	pxa27x_reset_hc(ohci); +	pxa27x_reset_hc(pxa_ohci); -	uhchr = __raw_readl(ohci->mmio_base + UHCHR) | UHCHR_FSBIR; -	__raw_writel(uhchr, ohci->mmio_base + UHCHR); +	uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR) | UHCHR_FSBIR; +	__raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR); -	while (__raw_readl(ohci->mmio_base + UHCHR) & UHCHR_FSBIR) +	while (__raw_readl(pxa_ohci->mmio_base + UHCHR) & UHCHR_FSBIR)  		cpu_relax(); -	pxa27x_setup_hc(ohci, inf); +	pxa27x_setup_hc(pxa_ohci, inf);  	if (inf->init)  		retval = inf->init(dev); @@ -237,40 +300,102 @@ static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev)  		return retval;  	if (cpu_is_pxa3xx()) -		pxa3xx_u2d_start_hc(&ohci_to_hcd(&ohci->ohci)->self); +		pxa3xx_u2d_start_hc(&hcd->self); -	uhchr = __raw_readl(ohci->mmio_base + UHCHR) & ~UHCHR_SSE; -	__raw_writel(uhchr, ohci->mmio_base + UHCHR); -	__raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, ohci->mmio_base + UHCHIE); +	uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR) & ~UHCHR_SSE; +	__raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR); +	__raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, pxa_ohci->mmio_base + UHCHIE);  	/* Clear any OTG Pin Hold */  	pxa27x_clear_otgph();  	return 0;  } -static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev) +static void pxa27x_stop_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev)  {  	struct pxaohci_platform_data *inf; +	struct usb_hcd *hcd = dev_get_drvdata(dev);  	uint32_t uhccoms; -	inf = dev->platform_data; +	inf = dev_get_platdata(dev);  	if (cpu_is_pxa3xx()) -		pxa3xx_u2d_stop_hc(&ohci_to_hcd(&ohci->ohci)->self); +		pxa3xx_u2d_stop_hc(&hcd->self);  	if (inf->exit)  		inf->exit(dev); -	pxa27x_reset_hc(ohci); +	pxa27x_reset_hc(pxa_ohci);  	/* Host Controller Reset */ -	uhccoms = __raw_readl(ohci->mmio_base + UHCCOMS) | 0x01; -	__raw_writel(uhccoms, ohci->mmio_base + UHCCOMS); +	uhccoms = __raw_readl(pxa_ohci->mmio_base + UHCCOMS) | 0x01; +	__raw_writel(uhccoms, pxa_ohci->mmio_base + UHCCOMS);  	udelay(10); -	clk_disable(ohci->clk); +	clk_disable_unprepare(pxa_ohci->clk);  } +#ifdef CONFIG_OF +static const struct of_device_id pxa_ohci_dt_ids[] = { +	{ .compatible = "marvell,pxa-ohci" }, +	{ } +}; + +MODULE_DEVICE_TABLE(of, pxa_ohci_dt_ids); + +static int ohci_pxa_of_init(struct platform_device *pdev) +{ +	struct device_node *np = pdev->dev.of_node; +	struct pxaohci_platform_data *pdata; +	u32 tmp; +	int ret; + +	if (!np) +		return 0; + +	/* Right now device-tree probed devices don't get dma_mask set. +	 * Since shared usb code relies on it, set it here for now. +	 * Once we have dma capability bindings this can go away. +	 */ +	ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +	if (ret) +		return ret; + +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); +	if (!pdata) +		return -ENOMEM; + +	if (of_get_property(np, "marvell,enable-port1", NULL)) +		pdata->flags |= ENABLE_PORT1; +	if (of_get_property(np, "marvell,enable-port2", NULL)) +		pdata->flags |= ENABLE_PORT2; +	if (of_get_property(np, "marvell,enable-port3", NULL)) +		pdata->flags |= ENABLE_PORT3; +	if (of_get_property(np, "marvell,port-sense-low", NULL)) +		pdata->flags |= POWER_SENSE_LOW; +	if (of_get_property(np, "marvell,power-control-low", NULL)) +		pdata->flags |= POWER_CONTROL_LOW; +	if (of_get_property(np, "marvell,no-oc-protection", NULL)) +		pdata->flags |= NO_OC_PROTECTION; +	if (of_get_property(np, "marvell,oc-mode-perport", NULL)) +		pdata->flags |= OC_MODE_PERPORT; +	if (!of_property_read_u32(np, "marvell,power-on-delay", &tmp)) +		pdata->power_on_delay = tmp; +	if (!of_property_read_u32(np, "marvell,port-mode", &tmp)) +		pdata->port_mode = tmp; +	if (!of_property_read_u32(np, "marvell,power-budget", &tmp)) +		pdata->power_budget = tmp; + +	pdev->dev.platform_data = pdata; + +	return 0; +} +#else +static int ohci_pxa_of_init(struct platform_device *pdev) +{ +	return 0; +} +#endif  /*-------------------------------------------------------------------------*/ @@ -292,11 +417,17 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device  	int retval, irq;  	struct usb_hcd *hcd;  	struct pxaohci_platform_data *inf; -	struct pxa27x_ohci *ohci; +	struct pxa27x_ohci *pxa_ohci; +	struct ohci_hcd *ohci;  	struct resource *r;  	struct clk *usb_clk; +	unsigned int i; + +	retval = ohci_pxa_of_init(pdev); +	if (retval) +		return retval; -	inf = pdev->dev.platform_data; +	inf = dev_get_platdata(&pdev->dev);  	if (!inf)  		return -ENODEV; @@ -307,7 +438,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device  		return -ENXIO;  	} -	usb_clk = clk_get(&pdev->dev, NULL); +	usb_clk = devm_clk_get(&pdev->dev, NULL);  	if (IS_ERR(usb_clk))  		return PTR_ERR(usb_clk); @@ -319,56 +450,58 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device  	if (!r) {  		pr_err("no resource of IORESOURCE_MEM");  		retval = -ENXIO; -		goto err1; +		goto err;  	}  	hcd->rsrc_start = r->start;  	hcd->rsrc_len = resource_size(r); -	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { -		pr_debug("request_mem_region failed"); -		retval = -EBUSY; -		goto err1; -	} - -	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); -	if (!hcd->regs) { -		pr_debug("ioremap failed"); -		retval = -ENOMEM; -		goto err2; +	hcd->regs = devm_ioremap_resource(&pdev->dev, r); +	if (IS_ERR(hcd->regs)) { +		retval = PTR_ERR(hcd->regs); +		goto err;  	}  	/* initialize "struct pxa27x_ohci" */ -	ohci = (struct pxa27x_ohci *)hcd_to_ohci(hcd); -	ohci->dev = &pdev->dev; -	ohci->clk = usb_clk; -	ohci->mmio_base = (void __iomem *)hcd->regs; +	pxa_ohci = to_pxa27x_ohci(hcd); +	pxa_ohci->clk = usb_clk; +	pxa_ohci->mmio_base = (void __iomem *)hcd->regs; + +	for (i = 0; i < 3; ++i) { +		char name[6]; + +		if (!(inf->flags & (ENABLE_PORT1 << i))) +			continue; + +		sprintf(name, "vbus%u", i + 1); +		pxa_ohci->vbus[i] = devm_regulator_get(&pdev->dev, name); +	} -	if ((retval = pxa27x_start_hc(ohci, &pdev->dev)) < 0) { +	retval = pxa27x_start_hc(pxa_ohci, &pdev->dev); +	if (retval < 0) {  		pr_debug("pxa27x_start_hc failed"); -		goto err3; +		goto err;  	}  	/* Select Power Management Mode */ -	pxa27x_ohci_select_pmm(ohci, inf->port_mode); +	pxa27x_ohci_select_pmm(pxa_ohci, inf->port_mode);  	if (inf->power_budget)  		hcd->power_budget = inf->power_budget; -	ohci_hcd_init(hcd_to_ohci(hcd)); +	/* The value of NDP in roothub_a is incorrect on this hardware */ +	ohci = hcd_to_ohci(hcd); +	ohci->num_ports = 3; -	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED); -	if (retval == 0) +	retval = usb_add_hcd(hcd, irq, 0); +	if (retval == 0) { +		device_wakeup_enable(hcd->self.controller);  		return retval; +	} -	pxa27x_stop_hc(ohci, &pdev->dev); - err3: -	iounmap(hcd->regs); - err2: -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - err1: +	pxa27x_stop_hc(pxa_ohci, &pdev->dev); + err:  	usb_put_hcd(hcd); -	clk_put(usb_clk);  	return retval;  } @@ -388,87 +521,20 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device   */  void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev)  { -	struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); +	struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); +	unsigned int i;  	usb_remove_hcd(hcd); -	pxa27x_stop_hc(ohci, &pdev->dev); -	iounmap(hcd->regs); -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -	usb_put_hcd(hcd); -	clk_put(ohci->clk); -} - -/*-------------------------------------------------------------------------*/ +	pxa27x_stop_hc(pxa_ohci, &pdev->dev); -static int __devinit -ohci_pxa27x_start (struct usb_hcd *hcd) -{ -	struct ohci_hcd	*ohci = hcd_to_ohci (hcd); -	int		ret; - -	ohci_dbg (ohci, "ohci_pxa27x_start, ohci:%p", ohci); - -	/* The value of NDP in roothub_a is incorrect on this hardware */ -	ohci->num_ports = 3; - -	if ((ret = ohci_init(ohci)) < 0) -		return ret; +	for (i = 0; i < 3; ++i) +		pxa27x_ohci_set_vbus_power(pxa_ohci, i, false); -	if ((ret = ohci_run (ohci)) < 0) { -		err ("can't start %s", hcd->self.bus_name); -		ohci_stop (hcd); -		return ret; -	} - -	return 0; +	usb_put_hcd(hcd);  }  /*-------------------------------------------------------------------------*/ -static const struct hc_driver ohci_pxa27x_hc_driver = { -	.description =		hcd_name, -	.product_desc =		"PXA27x OHCI", -	.hcd_priv_size =	sizeof(struct pxa27x_ohci), - -	/* -	 * generic hardware linkage -	 */ -	.irq =			ohci_irq, -	.flags =		HCD_USB11 | HCD_MEMORY, - -	/* -	 * basic lifecycle operations -	 */ -	.start =		ohci_pxa27x_start, -	.stop =			ohci_stop, -	.shutdown =		ohci_shutdown, - -	/* -	 * managing i/o requests and associated device resources -	 */ -	.urb_enqueue =		ohci_urb_enqueue, -	.urb_dequeue =		ohci_urb_dequeue, -	.endpoint_disable =	ohci_endpoint_disable, - -	/* -	 * scheduling support -	 */ -	.get_frame_number =	ohci_get_frame, - -	/* -	 * root hub support -	 */ -	.hub_status_data =	ohci_hub_status_data, -	.hub_control =		ohci_hub_control, -#ifdef  CONFIG_PM -	.bus_suspend =		ohci_bus_suspend, -	.bus_resume =		ohci_bus_resume, -#endif -	.start_port_reset =	ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ -  static int ohci_hcd_pxa27x_drv_probe(struct platform_device *pdev)  {  	pr_debug ("In ohci_hcd_pxa27x_drv_probe"); @@ -484,7 +550,6 @@ static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev)  	struct usb_hcd *hcd = platform_get_drvdata(pdev);  	usb_hcd_pxa27x_remove(hcd, pdev); -	platform_set_drvdata(pdev, NULL);  	return 0;  } @@ -492,36 +557,44 @@ static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev)  static int ohci_hcd_pxa27x_drv_suspend(struct device *dev)  {  	struct usb_hcd *hcd = dev_get_drvdata(dev); -	struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); +	struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); +	struct ohci_hcd *ohci = hcd_to_ohci(hcd); +	bool do_wakeup = device_may_wakeup(dev); +	int ret; -	if (time_before(jiffies, ohci->ohci.next_statechange)) + +	if (time_before(jiffies, ohci->next_statechange))  		msleep(5); -	ohci->ohci.next_statechange = jiffies; +	ohci->next_statechange = jiffies; -	pxa27x_stop_hc(ohci, dev); -	hcd->state = HC_STATE_SUSPENDED; +	ret = ohci_suspend(hcd, do_wakeup); +	if (ret) +		return ret; -	return 0; +	pxa27x_stop_hc(pxa_ohci, dev); +	return ret;  }  static int ohci_hcd_pxa27x_drv_resume(struct device *dev)  {  	struct usb_hcd *hcd = dev_get_drvdata(dev); -	struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); -	struct pxaohci_platform_data *inf = dev->platform_data; +	struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); +	struct pxaohci_platform_data *inf = dev_get_platdata(dev); +	struct ohci_hcd *ohci = hcd_to_ohci(hcd);  	int status; -	if (time_before(jiffies, ohci->ohci.next_statechange)) +	if (time_before(jiffies, ohci->next_statechange))  		msleep(5); -	ohci->ohci.next_statechange = jiffies; +	ohci->next_statechange = jiffies; -	if ((status = pxa27x_start_hc(ohci, dev)) < 0) +	status = pxa27x_start_hc(pxa_ohci, dev); +	if (status < 0)  		return status;  	/* Select Power Management Mode */ -	pxa27x_ohci_select_pmm(ohci, inf->port_mode); +	pxa27x_ohci_select_pmm(pxa_ohci, inf->port_mode); -	ohci_finish_controller_resume(hcd); +	ohci_resume(hcd, false);  	return 0;  } @@ -531,9 +604,6 @@ static const struct dev_pm_ops ohci_hcd_pxa27x_pm_ops = {  };  #endif -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:pxa27x-ohci"); -  static struct platform_driver ohci_hcd_pxa27x_driver = {  	.probe		= ohci_hcd_pxa27x_drv_probe,  	.remove		= ohci_hcd_pxa27x_drv_remove, @@ -541,9 +611,37 @@ static struct platform_driver ohci_hcd_pxa27x_driver = {  	.driver		= {  		.name	= "pxa27x-ohci",  		.owner	= THIS_MODULE, +		.of_match_table = of_match_ptr(pxa_ohci_dt_ids),  #ifdef CONFIG_PM  		.pm	= &ohci_hcd_pxa27x_pm_ops,  #endif  	},  }; +static const struct ohci_driver_overrides pxa27x_overrides __initconst = { +	.extra_priv_size =      sizeof(struct pxa27x_ohci), +}; + +static int __init ohci_pxa27x_init(void) +{ +	if (usb_disabled()) +		return -ENODEV; + +	pr_info("%s: " DRIVER_DESC "\n", hcd_name); + +	ohci_init_driver(&ohci_pxa27x_hc_driver, &pxa27x_overrides); +	ohci_pxa27x_hc_driver.hub_control = pxa27x_ohci_hub_control; + +	return platform_driver_register(&ohci_hcd_pxa27x_driver); +} +module_init(ohci_pxa27x_init); + +static void __exit ohci_pxa27x_cleanup(void) +{ +	platform_driver_unregister(&ohci_hcd_pxa27x_driver); +} +module_exit(ohci_pxa27x_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa27x-ohci");  | 
