Message ID | 1363094444-5035-1-git-send-email-manjunath.goudar@linaro.org |
---|---|
State | New |
Headers | show |
On 12 March 2013 18:50, Manjunath Goudar <manjunath.goudar@linaro.org>wrote: > Separate the Tegra on-chip host controller driver from > ehci-hcd host code so that it can be built as a separate driver module. > This work is part of enabling multi-platform kernels on ARM; > however, note that other changes are still needed before Tegra > can be booted with a multi-platform kernel. > > Signed-off-by: Manjunath Goudar <manjunath.goudar@linaro.org> > Cc: Greg KH <greg@kroah.com> > Cc: Alan Stern <stern@rowland.harvard.edu> > Cc: Grant Likely <grant.likely@secretlab.ca> > Cc: Rob Herring <rob.herring@calxeda.com> > Cc: Stephen Warren <swarren@wwwdotorg.org> > Cc: Russell King <linux@arm.linux.org.uk> > CC: Felipe Balbi <balbi@ti.com> > Cc: linux-arm-kernel@lists.infradead.org > Cc: linux-usb@vger.kernel.org > Cc: linux-tegra@vger.kernel.org > --- > drivers/usb/host/Kconfig | 2 +- > drivers/usb/host/Makefile | 1 + > drivers/usb/host/ehci-hcd.c | 27 +++++---- > drivers/usb/host/ehci-hub.c | 5 +- > drivers/usb/host/ehci-tegra.c | 115 > +++++++++++++++++++-------------------- > drivers/usb/host/ehci.h | 23 ++++++++ > drivers/usb/otg/ulpi_viewport.c | 2 + > 7 files changed, 104 insertions(+), 71 deletions(-) > > diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig > index 1c516c6..2d15cca 100644 > --- a/drivers/usb/host/Kconfig > +++ b/drivers/usb/host/Kconfig > @@ -210,7 +210,7 @@ config USB_EHCI_MSM > has an external PHY. > > config USB_EHCI_TEGRA > - boolean "NVIDIA Tegra HCD support" > + tristate "NVIDIA Tegra HCD support" > depends on USB_EHCI_HCD && ARCH_TEGRA > select USB_EHCI_ROOT_HUB_TT > help > diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile > index 1550a0e..67bea25 100644 > --- a/drivers/usb/host/Makefile > +++ b/drivers/usb/host/Makefile > @@ -35,6 +35,7 @@ obj-$(CONFIG_USB_EHCI_HCD_VT8500) += ehci-vt8500.o > obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o > obj-$(CONFIG_USB_W90X900_EHCI) += ehci-w90x900.o > obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o > +obj-$(CONFIG_USB_EHCI_TEGRA) +=ehci-tegra.o > > > obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o > diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c > index a077323..0030520 100644 > --- a/drivers/usb/host/ehci-hcd.c > +++ b/drivers/usb/host/ehci-hcd.c > @@ -155,7 +155,7 @@ static inline unsigned ehci_read_frame_index(struct > ehci_hcd *ehci) > * before driver shutdown. But it also seems to be caused by bugs in > cardbus > * bridge shutdown: shutting down the bridge before the devices using it. > */ > -static int handshake (struct ehci_hcd *ehci, void __iomem *ptr, > +int handshake (struct ehci_hcd *ehci, void __iomem *ptr, > u32 mask, u32 done, int usec) > { > u32 result; > @@ -172,6 +172,7 @@ static int handshake (struct ehci_hcd *ehci, void > __iomem *ptr, > } while (usec > 0); > return -ETIMEDOUT; > } > +EXPORT_SYMBOL_GPL(handshake); > Hi Arnd this one I will change ehci_handshake. > /* check TDI/ARC silicon is in host mode */ > static int tdi_in_host_mode (struct ehci_hcd *ehci) > @@ -186,7 +187,7 @@ static int tdi_in_host_mode (struct ehci_hcd *ehci) > * Force HC to halt state from unknown (EHCI spec section 2.3). > * Must be called with interrupts enabled and the lock not held. > */ > -static int ehci_halt (struct ehci_hcd *ehci) > +int ehci_halt (struct ehci_hcd *ehci) > { > u32 temp; > > @@ -215,9 +216,10 @@ static int ehci_halt (struct ehci_hcd *ehci) > return handshake(ehci, &ehci->regs->status, > STS_HALT, STS_HALT, 16 * 125); > } > +EXPORT_SYMBOL_GPL(ehci_halt); > > /* put TDI/ARC silicon into EHCI mode */ > -static void tdi_reset (struct ehci_hcd *ehci) > +void tdi_reset (struct ehci_hcd *ehci) > { > u32 tmp; > > @@ -231,12 +233,13 @@ static void tdi_reset (struct ehci_hcd *ehci) > tmp |= USBMODE_BE; > ehci_writel(ehci, tmp, &ehci->regs->usbmode); > } > +EXPORT_SYMBOL_GPL(tdi_reset); > > /* > * Reset a non-running (STS_HALT == 1) controller. > * Must be called with interrupts enabled and the lock not held. > */ > -static int ehci_reset (struct ehci_hcd *ehci) > +int ehci_reset (struct ehci_hcd *ehci) > { > int retval; > u32 command = ehci_readl(ehci, &ehci->regs->command); > @@ -272,6 +275,7 @@ static int ehci_reset (struct ehci_hcd *ehci) > ehci->resuming_ports = 0; > return retval; > } > +EXPORT_SYMBOL_GPL(ehci_reset); > > /* > * Idle the controller (turn off the schedules). > @@ -1233,7 +1237,14 @@ void ehci_init_driver(struct hc_driver *drv, > drv->hcd_priv_size += over->extra_priv_size; > if (over->reset) > drv->reset = over->reset; > - } > Look this below code for tegra pacth this my approach > + if (over->map_urb_for_dma && over->unmap_urb_for_dma) > + { > + drv->map_urb_for_dma = > over->map_urb_for_dma; > + drv->unmap_urb_for_dma = > over->unmap_urb_for_dma; > + } > + if (over->hub_control) > + drv->hub_control = over->hub_control; > + } > } > EXPORT_SYMBOL_GPL(ehci_init_driver); > > @@ -1288,11 +1299,6 @@ MODULE_LICENSE ("GPL"); > #define PLATFORM_DRIVER ehci_hcd_msp_driver > #endif > > -#ifdef CONFIG_USB_EHCI_TEGRA > -#include "ehci-tegra.c" > -#define PLATFORM_DRIVER tegra_ehci_driver > -#endif > - > #ifdef CONFIG_SPARC_LEON > #include "ehci-grlib.c" > #define PLATFORM_DRIVER ehci_grlib_driver > @@ -1315,6 +1321,7 @@ MODULE_LICENSE ("GPL"); > !IS_ENABLED(CONFIG_USB_EHCI_MSM) && \ > !IS_ENABLED(CONFIG_USB_W90X900_EHCI) && \ > !IS_ENABLED(CONFIG_PLAT_ORION) && \ > + !IS_ENABLED(CONFIG_USB_EHCI_TEGRA) && \ > !defined(PLATFORM_DRIVER) && \ > !defined(PS3_SYSTEM_BUS_DRIVER) && \ > !defined(OF_PLATFORM_DRIVER) && \ > diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c > index 4d3b294..dba88fa 100644 > --- a/drivers/usb/host/ehci-hub.c > +++ b/drivers/usb/host/ehci-hub.c > @@ -33,7 +33,7 @@ > > #ifdef CONFIG_PM > > -static int ehci_hub_control( > +int ehci_hub_control( > struct usb_hcd *hcd, > u16 typeReq, > u16 wValue, > @@ -695,7 +695,7 @@ ehci_hub_descriptor ( > > > /*-------------------------------------------------------------------------*/ > > -static int ehci_hub_control ( > +int ehci_hub_control ( > struct usb_hcd *hcd, > u16 typeReq, > u16 wValue, > @@ -1115,6 +1115,7 @@ error_exit: > spin_unlock_irqrestore (&ehci->lock, flags); > return retval; > } > +EXPORT_SYMBOL_GPL(ehci_hub_control); > > static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum) > { > diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c > index 568aecc..6670d93 100644 > --- a/drivers/usb/host/ehci-tegra.c > +++ b/drivers/usb/host/ehci-tegra.c > @@ -17,18 +17,27 @@ > */ > > #include <linux/clk.h> > +#include <linux/dma-mapping.h> > #include <linux/err.h> > -#include <linux/platform_device.h> > -#include <linux/platform_data/tegra_usb.h> > -#include <linux/irq.h> > -#include <linux/usb/otg.h> > #include <linux/gpio.h> > +#include <linux/io.h> > +#include <linux/irq.h> > +#include <linux/kernel.h> > +#include <linux/module.h> > #include <linux/of.h> > #include <linux/of_gpio.h> > +#include <linux/platform_device.h> > +#include <linux/platform_data/tegra_usb.h> > #include <linux/pm_runtime.h> > +#include <linux/slab.h> > +#include <linux/usb/otg.h> > #include <linux/usb/ehci_def.h> > +#include <linux/usb.h> > +#include <linux/usb/hcd.h> > #include <linux/usb/tegra_usb_phy.h> > > +#include "ehci.h" > + > #define TEGRA_USB_BASE 0xC5000000 > #define TEGRA_USB2_BASE 0xC5004000 > #define TEGRA_USB3_BASE 0xC5008000 > @@ -37,9 +46,14 @@ > #define TEGRA_USB_PORTSC1 0x184 > #define TEGRA_USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) > #define TEGRA_USB_PORTSC1_PHCD (1 << 23) > +#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) > > #define TEGRA_USB_DMA_ALIGN 32 > > +#define DRIVER_DESC "EHCI Tegra driver" > + > +static const char hcd_name[] = "tegra-ehci"; > + > struct tegra_ehci_hcd { > struct ehci_hcd *ehci; > struct tegra_usb_phy *phy; > @@ -268,31 +282,6 @@ static void tegra_ehci_restart(struct usb_hcd *hcd) > up_write(&ehci_cf_port_reset_rwsem); > } > > -static void tegra_ehci_shutdown(struct usb_hcd *hcd) > -{ > - struct tegra_ehci_hcd *tegra = > dev_get_drvdata(hcd->self.controller); > - > - /* ehci_shutdown touches the USB controller registers, make sure > - * controller has clocks to it */ > - if (!tegra->host_resumed) > - tegra_ehci_power_up(hcd); > - > - ehci_shutdown(hcd); > -} > - > -static int tegra_ehci_setup(struct usb_hcd *hcd) > -{ > - struct ehci_hcd *ehci = hcd_to_ehci(hcd); > - > - /* EHCI registers start at offset 0x100 */ > - ehci->caps = hcd->regs + 0x100; > - > - /* switch to host mode */ > - hcd->has_tt = 1; > - > - return ehci_setup(hcd); > -} > - > struct dma_aligned_buffer { > void *kmalloc_ptr; > void *old_xfer_buffer; > @@ -372,36 +361,14 @@ static void tegra_ehci_unmap_urb_for_dma(struct > usb_hcd *hcd, struct urb *urb) > free_dma_aligned_buffer(urb); > } > > -static const struct hc_driver tegra_ehci_hc_driver = { > - .description = hcd_name, > - .product_desc = "Tegra EHCI Host Controller", > - .hcd_priv_size = sizeof(struct ehci_hcd), > - .flags = HCD_USB2 | HCD_MEMORY, > - > - /* standard ehci functions */ > - .irq = ehci_irq, > - .start = ehci_run, > - .stop = ehci_stop, > - .urb_enqueue = ehci_urb_enqueue, > - .urb_dequeue = ehci_urb_dequeue, > - .endpoint_disable = ehci_endpoint_disable, > - .endpoint_reset = ehci_endpoint_reset, > - .get_frame_number = ehci_get_frame, > - .hub_status_data = ehci_hub_status_data, > - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, > - .relinquish_port = ehci_relinquish_port, > - .port_handed_over = ehci_port_handed_over, > - > - /* modified ehci functions for tegra */ > - .reset = tegra_ehci_setup, > - .shutdown = tegra_ehci_shutdown, > +static struct hc_driver __read_mostly tegra_ehci_hc_driver; > + > +static struct ehci_driver_overrides tegra_overrides __initdata = { > + .extra_priv_size = sizeof(struct tegra_ehci_hcd), > .map_urb_for_dma = tegra_ehci_map_urb_for_dma, > .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma, > - .hub_control = tegra_ehci_hub_control, > -#ifdef CONFIG_PM > - .bus_suspend = ehci_bus_suspend, > - .bus_resume = ehci_bus_resume, > -#endif > + .hub_control = tegra_ehci_hub_control, > + > }; > > static int setup_vbus_gpio(struct platform_device *pdev, > @@ -757,8 +724,14 @@ static int tegra_ehci_probe(struct platform_device > *pdev) > dev_err(&pdev->dev, "Failed to power on the phy\n"); > goto fail; > } > + > + /* EHCI registers start at offset 0x100 */ > + tegra->ehci->caps = hcd->regs + 0x100; > > tegra->host_resumed = 1; > + > + /* switch to host mode */ > + hcd->has_tt = 1; > tegra->ehci = hcd_to_ehci(hcd); > > irq = platform_get_irq(pdev, 0); > @@ -833,7 +806,11 @@ static void tegra_ehci_hcd_shutdown(struct > platform_device *pdev) > { > struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev); > struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci); > - > + > + /* ehci_shutdown touches the USB controller registers, make sure > + * controller has clocks to it */ > + if (!tegra->host_resumed) > + tegra_ehci_power_up(hcd); > if (hcd->driver->shutdown) > hcd->driver->shutdown(hcd); > } > @@ -855,3 +832,25 @@ static struct platform_driver tegra_ehci_driver = { > #endif > } > }; > + > +static int __init ehci_tegra_init(void) > +{ > + if (usb_disabled()) > + return -ENODEV; > + > + pr_info("%s: " DRIVER_DESC "\n", hcd_name); > + > + ehci_init_driver(&tegra_ehci_hc_driver, &tegra_overrides); > + return platform_driver_register(&tegra_ehci_driver); > +} > +module_init(ehci_tegra_init); > + > +static void __exit ehci_tegra_cleanup(void) > +{ > + platform_driver_unregister(&tegra_ehci_driver); > +} > +module_exit(ehci_tegra_cleanup); > + > +MODULE_DESCRIPTION(DRIVER_DESC); > +MODULE_ALIAS("platform:tegra-ehci"); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h > index 139c932..adad882 100644 > --- a/drivers/usb/host/ehci.h > +++ b/drivers/usb/host/ehci.h > @@ -793,12 +793,35 @@ static inline u32 hc32_to_cpup (const struct > ehci_hcd *ehci, const __hc32 *x) > struct ehci_driver_overrides { > size_t extra_priv_size; > int (*reset)(struct usb_hcd *hcd); > + /* > + * (optional) these hooks allow an HCD to override the default DMA > + * mapping and unmapping routines. In general, they shouldn't be > + * necessary unless the host controller has special DMA > requirements, > + * such as alignment contraints. If these are not specified, the > + * general usb_hcd_(un)?map_urb_for_dma functions will be used > instead > + * (and it may be a good idea to call these functions in your HCD > + * implementation) > + */ > + int (*map_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb, > + gfp_t mem_flags); > + void (*unmap_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb); > + /* root hub support */ > + int (*hub_control)(struct usb_hcd *hcd, u16 typeReq, u16 > wValue, > + u16 wIndex, char *buf, u16 wLength); > }; > > extern void ehci_init_driver(struct hc_driver *drv, > const struct ehci_driver_overrides *over); > extern int ehci_setup(struct usb_hcd *hcd); > extern void ehci_shutdown(struct usb_hcd *hcd); > +extern int handshake(struct ehci_hcd *ehci, void __iomem *ptr, > + u32 mask, u32 done, int usec); > +extern int ehci_hub_control(struct usb_hcd *hcd, u16 typeReq, > + u16 wValue, u16 wIndex, char *buf, > + u16 wLength); > +extern int ehci_reset(struct ehci_hcd *ehci); > +extern int ehci_halt(struct ehci_hcd *ehci); > +extern void tdi_reset(struct ehci_hcd *ehci); > > #ifdef CONFIG_PM > extern int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup); > diff --git a/drivers/usb/otg/ulpi_viewport.c > b/drivers/usb/otg/ulpi_viewport.c > index c5ba7e5..4442425 100644 > --- a/drivers/usb/otg/ulpi_viewport.c > +++ b/drivers/usb/otg/ulpi_viewport.c > @@ -13,6 +13,7 @@ > */ > > #include <linux/kernel.h> > +#include <linux/module.h> > #include <linux/usb.h> > #include <linux/io.h> > #include <linux/usb/otg.h> > @@ -78,3 +79,4 @@ struct usb_phy_io_ops ulpi_viewport_access_ops = { > .read = ulpi_viewport_read, > .write = ulpi_viewport_write, > }; > +EXPORT_SYMBOL_GPL(ulpi_viewport_access_ops); > -- > 1.7.9.5 > >
On Tuesday 12 March 2013, Manjunath Goudar wrote: > On 12 March 2013 18:50, Manjunath Goudar <manjunath.goudar@linaro.org>wrote: > > > Separate the Tegra on-chip host controller driver from > > ehci-hcd host code so that it can be built as a separate driver module. > > This work is part of enabling multi-platform kernels on ARM; > > however, note that other changes are still needed before Tegra > > can be booted with a multi-platform kernel. As I mentioned before, when you reply to an email, please remove all the quoted text you are not referring to directly. > > > + if (over->map_urb_for_dma && over->unmap_urb_for_dma) > > + { > > + drv->map_urb_for_dma = over->map_urb_for_dma; > > + drv->unmap_urb_for_dma = over->unmap_urb_for_dma; > > + } > > + if (over->hub_control) > > + drv->hub_control = over->hub_control; > > + } > > } Please do this properly with the right coding style, I'm sure you can do better than the above. Note also how using separate if() clauses for each member would make this code more readable and actually smaller. Arnd
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 1c516c6..2d15cca 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -210,7 +210,7 @@ config USB_EHCI_MSM has an external PHY. config USB_EHCI_TEGRA - boolean "NVIDIA Tegra HCD support" + tristate "NVIDIA Tegra HCD support" depends on USB_EHCI_HCD && ARCH_TEGRA select USB_EHCI_ROOT_HUB_TT help diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 1550a0e..67bea25 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_USB_EHCI_HCD_VT8500) += ehci-vt8500.o obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o obj-$(CONFIG_USB_W90X900_EHCI) += ehci-w90x900.o obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o +obj-$(CONFIG_USB_EHCI_TEGRA) +=ehci-tegra.o obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index a077323..0030520 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -155,7 +155,7 @@ static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci) * before driver shutdown. But it also seems to be caused by bugs in cardbus * bridge shutdown: shutting down the bridge before the devices using it. */ -static int handshake (struct ehci_hcd *ehci, void __iomem *ptr, +int handshake (struct ehci_hcd *ehci, void __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; @@ -172,6 +172,7 @@ static int handshake (struct ehci_hcd *ehci, void __iomem *ptr, } while (usec > 0); return -ETIMEDOUT; } +EXPORT_SYMBOL_GPL(handshake); /* check TDI/ARC silicon is in host mode */ static int tdi_in_host_mode (struct ehci_hcd *ehci) @@ -186,7 +187,7 @@ static int tdi_in_host_mode (struct ehci_hcd *ehci) * Force HC to halt state from unknown (EHCI spec section 2.3). * Must be called with interrupts enabled and the lock not held. */ -static int ehci_halt (struct ehci_hcd *ehci) +int ehci_halt (struct ehci_hcd *ehci) { u32 temp; @@ -215,9 +216,10 @@ static int ehci_halt (struct ehci_hcd *ehci) return handshake(ehci, &ehci->regs->status, STS_HALT, STS_HALT, 16 * 125); } +EXPORT_SYMBOL_GPL(ehci_halt); /* put TDI/ARC silicon into EHCI mode */ -static void tdi_reset (struct ehci_hcd *ehci) +void tdi_reset (struct ehci_hcd *ehci) { u32 tmp; @@ -231,12 +233,13 @@ static void tdi_reset (struct ehci_hcd *ehci) tmp |= USBMODE_BE; ehci_writel(ehci, tmp, &ehci->regs->usbmode); } +EXPORT_SYMBOL_GPL(tdi_reset); /* * Reset a non-running (STS_HALT == 1) controller. * Must be called with interrupts enabled and the lock not held. */ -static int ehci_reset (struct ehci_hcd *ehci) +int ehci_reset (struct ehci_hcd *ehci) { int retval; u32 command = ehci_readl(ehci, &ehci->regs->command); @@ -272,6 +275,7 @@ static int ehci_reset (struct ehci_hcd *ehci) ehci->resuming_ports = 0; return retval; } +EXPORT_SYMBOL_GPL(ehci_reset); /* * Idle the controller (turn off the schedules). @@ -1233,7 +1237,14 @@ void ehci_init_driver(struct hc_driver *drv, drv->hcd_priv_size += over->extra_priv_size; if (over->reset) drv->reset = over->reset; - } + if (over->map_urb_for_dma && over->unmap_urb_for_dma) + { + drv->map_urb_for_dma = over->map_urb_for_dma; + drv->unmap_urb_for_dma = over->unmap_urb_for_dma; + } + if (over->hub_control) + drv->hub_control = over->hub_control; + } } EXPORT_SYMBOL_GPL(ehci_init_driver); @@ -1288,11 +1299,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_hcd_msp_driver #endif -#ifdef CONFIG_USB_EHCI_TEGRA -#include "ehci-tegra.c" -#define PLATFORM_DRIVER tegra_ehci_driver -#endif - #ifdef CONFIG_SPARC_LEON #include "ehci-grlib.c" #define PLATFORM_DRIVER ehci_grlib_driver @@ -1315,6 +1321,7 @@ MODULE_LICENSE ("GPL"); !IS_ENABLED(CONFIG_USB_EHCI_MSM) && \ !IS_ENABLED(CONFIG_USB_W90X900_EHCI) && \ !IS_ENABLED(CONFIG_PLAT_ORION) && \ + !IS_ENABLED(CONFIG_USB_EHCI_TEGRA) && \ !defined(PLATFORM_DRIVER) && \ !defined(PS3_SYSTEM_BUS_DRIVER) && \ !defined(OF_PLATFORM_DRIVER) && \ diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 4d3b294..dba88fa 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -33,7 +33,7 @@ #ifdef CONFIG_PM -static int ehci_hub_control( +int ehci_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, @@ -695,7 +695,7 @@ ehci_hub_descriptor ( /*-------------------------------------------------------------------------*/ -static int ehci_hub_control ( +int ehci_hub_control ( struct usb_hcd *hcd, u16 typeReq, u16 wValue, @@ -1115,6 +1115,7 @@ error_exit: spin_unlock_irqrestore (&ehci->lock, flags); return retval; } +EXPORT_SYMBOL_GPL(ehci_hub_control); static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum) { diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 568aecc..6670d93 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -17,18 +17,27 @@ */ #include <linux/clk.h> +#include <linux/dma-mapping.h> #include <linux/err.h> -#include <linux/platform_device.h> -#include <linux/platform_data/tegra_usb.h> -#include <linux/irq.h> -#include <linux/usb/otg.h> #include <linux/gpio.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/of.h> #include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include <linux/platform_data/tegra_usb.h> #include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <linux/usb/otg.h> #include <linux/usb/ehci_def.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> #include <linux/usb/tegra_usb_phy.h> +#include "ehci.h" + #define TEGRA_USB_BASE 0xC5000000 #define TEGRA_USB2_BASE 0xC5004000 #define TEGRA_USB3_BASE 0xC5008000 @@ -37,9 +46,14 @@ #define TEGRA_USB_PORTSC1 0x184 #define TEGRA_USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) #define TEGRA_USB_PORTSC1_PHCD (1 << 23) +#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) #define TEGRA_USB_DMA_ALIGN 32 +#define DRIVER_DESC "EHCI Tegra driver" + +static const char hcd_name[] = "tegra-ehci"; + struct tegra_ehci_hcd { struct ehci_hcd *ehci; struct tegra_usb_phy *phy; @@ -268,31 +282,6 @@ static void tegra_ehci_restart(struct usb_hcd *hcd) up_write(&ehci_cf_port_reset_rwsem); } -static void tegra_ehci_shutdown(struct usb_hcd *hcd) -{ - struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); - - /* ehci_shutdown touches the USB controller registers, make sure - * controller has clocks to it */ - if (!tegra->host_resumed) - tegra_ehci_power_up(hcd); - - ehci_shutdown(hcd); -} - -static int tegra_ehci_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - /* EHCI registers start at offset 0x100 */ - ehci->caps = hcd->regs + 0x100; - - /* switch to host mode */ - hcd->has_tt = 1; - - return ehci_setup(hcd); -} - struct dma_aligned_buffer { void *kmalloc_ptr; void *old_xfer_buffer; @@ -372,36 +361,14 @@ static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) free_dma_aligned_buffer(urb); } -static const struct hc_driver tegra_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "Tegra EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - .flags = HCD_USB2 | HCD_MEMORY, - - /* standard ehci functions */ - .irq = ehci_irq, - .start = ehci_run, - .stop = ehci_stop, - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - .get_frame_number = ehci_get_frame, - .hub_status_data = ehci_hub_status_data, - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - /* modified ehci functions for tegra */ - .reset = tegra_ehci_setup, - .shutdown = tegra_ehci_shutdown, +static struct hc_driver __read_mostly tegra_ehci_hc_driver; + +static struct ehci_driver_overrides tegra_overrides __initdata = { + .extra_priv_size = sizeof(struct tegra_ehci_hcd), .map_urb_for_dma = tegra_ehci_map_urb_for_dma, .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma, - .hub_control = tegra_ehci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif + .hub_control = tegra_ehci_hub_control, + }; static int setup_vbus_gpio(struct platform_device *pdev, @@ -757,8 +724,14 @@ static int tegra_ehci_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to power on the phy\n"); goto fail; } + + /* EHCI registers start at offset 0x100 */ + tegra->ehci->caps = hcd->regs + 0x100; tegra->host_resumed = 1; + + /* switch to host mode */ + hcd->has_tt = 1; tegra->ehci = hcd_to_ehci(hcd); irq = platform_get_irq(pdev, 0); @@ -833,7 +806,11 @@ static void tegra_ehci_hcd_shutdown(struct platform_device *pdev) { struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev); struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci); - + + /* ehci_shutdown touches the USB controller registers, make sure + * controller has clocks to it */ + if (!tegra->host_resumed) + tegra_ehci_power_up(hcd); if (hcd->driver->shutdown) hcd->driver->shutdown(hcd); } @@ -855,3 +832,25 @@ static struct platform_driver tegra_ehci_driver = { #endif } }; + +static int __init ehci_tegra_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ehci_init_driver(&tegra_ehci_hc_driver, &tegra_overrides); + return platform_driver_register(&tegra_ehci_driver); +} +module_init(ehci_tegra_init); + +static void __exit ehci_tegra_cleanup(void) +{ + platform_driver_unregister(&tegra_ehci_driver); +} +module_exit(ehci_tegra_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_ALIAS("platform:tegra-ehci"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 139c932..adad882 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -793,12 +793,35 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x) struct ehci_driver_overrides { size_t extra_priv_size; int (*reset)(struct usb_hcd *hcd); + /* + * (optional) these hooks allow an HCD to override the default DMA + * mapping and unmapping routines. In general, they shouldn't be + * necessary unless the host controller has special DMA requirements, + * such as alignment contraints. If these are not specified, the + * general usb_hcd_(un)?map_urb_for_dma functions will be used instead + * (and it may be a good idea to call these functions in your HCD + * implementation) + */ + int (*map_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags); + void (*unmap_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb); + /* root hub support */ + int (*hub_control)(struct usb_hcd *hcd, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength); }; extern void ehci_init_driver(struct hc_driver *drv, const struct ehci_driver_overrides *over); extern int ehci_setup(struct usb_hcd *hcd); extern void ehci_shutdown(struct usb_hcd *hcd); +extern int handshake(struct ehci_hcd *ehci, void __iomem *ptr, + u32 mask, u32 done, int usec); +extern int ehci_hub_control(struct usb_hcd *hcd, u16 typeReq, + u16 wValue, u16 wIndex, char *buf, + u16 wLength); +extern int ehci_reset(struct ehci_hcd *ehci); +extern int ehci_halt(struct ehci_hcd *ehci); +extern void tdi_reset(struct ehci_hcd *ehci); #ifdef CONFIG_PM extern int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup); diff --git a/drivers/usb/otg/ulpi_viewport.c b/drivers/usb/otg/ulpi_viewport.c index c5ba7e5..4442425 100644 --- a/drivers/usb/otg/ulpi_viewport.c +++ b/drivers/usb/otg/ulpi_viewport.c @@ -13,6 +13,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/usb.h> #include <linux/io.h> #include <linux/usb/otg.h> @@ -78,3 +79,4 @@ struct usb_phy_io_ops ulpi_viewport_access_ops = { .read = ulpi_viewport_read, .write = ulpi_viewport_write, }; +EXPORT_SYMBOL_GPL(ulpi_viewport_access_ops);
Separate the Tegra on-chip host controller driver from ehci-hcd host code so that it can be built as a separate driver module. This work is part of enabling multi-platform kernels on ARM; however, note that other changes are still needed before Tegra can be booted with a multi-platform kernel. Signed-off-by: Manjunath Goudar <manjunath.goudar@linaro.org> Cc: Greg KH <greg@kroah.com> Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Grant Likely <grant.likely@secretlab.ca> Cc: Rob Herring <rob.herring@calxeda.com> Cc: Stephen Warren <swarren@wwwdotorg.org> Cc: Russell King <linux@arm.linux.org.uk> CC: Felipe Balbi <balbi@ti.com> Cc: linux-arm-kernel@lists.infradead.org Cc: linux-usb@vger.kernel.org Cc: linux-tegra@vger.kernel.org --- drivers/usb/host/Kconfig | 2 +- drivers/usb/host/Makefile | 1 + drivers/usb/host/ehci-hcd.c | 27 +++++---- drivers/usb/host/ehci-hub.c | 5 +- drivers/usb/host/ehci-tegra.c | 115 +++++++++++++++++++-------------------- drivers/usb/host/ehci.h | 23 ++++++++ drivers/usb/otg/ulpi_viewport.c | 2 + 7 files changed, 104 insertions(+), 71 deletions(-)