* Bus Glue for the EHCI controllers in OMAP3/4
  * Tested on several OMAP3 boards, and OMAP4 Pandaboard
  *
- * Copyright (C) 2007-2011 Texas Instruments, Inc.
+ * Copyright (C) 2007-2013 Texas Instruments, Inc.
  *     Author: Vikram Pandita <vikram.pandita@ti.com>
  *     Author: Anand Gadiyar <gadiyar@ti.com>
  *     Author: Keshava Munegowda <keshava_mgowda@ti.com>
+ *     Author: Roger Quadros <rogerq@ti.com>
  *
  * Copyright (C) 2009 Nokia Corporation
  *     Contact: Felipe Balbi <felipe.balbi@nokia.com>
 
 /*-------------------------------------------------------------------------*/
 
+struct omap_hcd {
+       struct usb_phy *phy[OMAP3_HS_USB_PORTS]; /* one PHY for each port */
+       int nports;
+};
 
 static inline void ehci_write(void __iomem *base, u32 reg, u32 val)
 {
 static struct hc_driver __read_mostly ehci_omap_hc_driver;
 
 static const struct ehci_driver_overrides ehci_omap_overrides __initdata = {
-       .reset =                omap_ehci_init,
+       .reset = omap_ehci_init,
+       .extra_priv_size = sizeof(struct omap_hcd),
 };
 
 /**
  */
 static int ehci_hcd_omap_probe(struct platform_device *pdev)
 {
-       struct device                           *dev = &pdev->dev;
-       struct usbhs_omap_platform_data         *pdata = dev->platform_data;
-       struct resource                         *res;
-       struct usb_hcd                          *hcd;
-       void __iomem                            *regs;
-       int                                     ret = -ENODEV;
-       int                                     irq;
-       int                                     i;
-       char                                    supply[7];
+       struct device *dev = &pdev->dev;
+       struct usbhs_omap_platform_data *pdata = dev->platform_data;
+       struct resource *res;
+       struct usb_hcd  *hcd;
+       void __iomem *regs;
+       int ret = -ENODEV;
+       int irq;
+       int i;
+       char supply[7];
+       struct omap_hcd *omap;
 
        if (usb_disabled())
                return -ENODEV;
        hcd->rsrc_len = resource_size(res);
        hcd->regs = regs;
 
+       omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv;
+       omap->nports = pdata->nports;
+
+       platform_set_drvdata(pdev, hcd);
+
+       /* get the PHY devices if needed */
+       for (i = 0 ; i < omap->nports ; i++) {
+               struct usb_phy *phy;
+
+               if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY)
+                       continue;
+
+               /* get the PHY device */
+               phy = devm_usb_get_phy_dev(dev, i);
+               if (IS_ERR(phy) || !phy) {
+                       ret = IS_ERR(phy) ? PTR_ERR(phy) : -ENODEV;
+                       dev_err(dev, "Can't get PHY device for port %d: %d\n",
+                                       i, ret);
+                       goto err_phy;
+               }
+
+               omap->phy[i] = phy;
+               usb_phy_init(omap->phy[i]);
+               /* bring PHY out of suspend */
+               usb_phy_set_suspend(omap->phy[i], 0);
+       }
+
        /* get ehci regulator and enable */
        for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
                if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) {
 err_pm_runtime:
        disable_put_regulator(pdata);
        pm_runtime_put_sync(dev);
+
+err_phy:
+       for (i = 0; i < omap->nports; i++) {
+               if (omap->phy[i])
+                       usb_phy_shutdown(omap->phy[i]);
+       }
+
        usb_put_hcd(hcd);
 
        return ret;
  */
 static int ehci_hcd_omap_remove(struct platform_device *pdev)
 {
-       struct device *dev                              = &pdev->dev;
-       struct usb_hcd *hcd                             = dev_get_drvdata(dev);
+       struct device *dev = &pdev->dev;
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+       struct omap_hcd *omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv;
+       int i;
 
        usb_remove_hcd(hcd);
        disable_put_regulator(dev->platform_data);
-       usb_put_hcd(hcd);
 
+       for (i = 0; i < omap->nports; i++) {
+               if (omap->phy[i])
+                       usb_phy_shutdown(omap->phy[i]);
+       }
+
+       usb_put_hcd(hcd);
        pm_runtime_put_sync(dev);
        pm_runtime_disable(dev);