diff mbox

USB: EHCI: make ehci-tegra a separate driver

Message ID 1363094444-5035-1-git-send-email-manjunath.goudar@linaro.org
State New
Headers show

Commit Message

manjunath.goudar@linaro.org March 12, 2013, 1:20 p.m. UTC
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(-)

Comments

manjunath.goudar@linaro.org March 12, 2013, 1:25 p.m. UTC | #1
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
>
>
Arnd Bergmann March 12, 2013, 2:22 p.m. UTC | #2
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 mbox

Patch

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);