#include <linux/regulator/consumer.h>
 #include <linux/pm_runtime.h>
 #include <linux/gpio.h>
+#include <linux/clk.h>
 
 /* EHCI Register Set */
 #define EHCI_INSNREG04                                 (0xA0)
 #define        EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT             8
 #define        EHCI_INSNREG05_ULPI_WRDATA_SHIFT                0
 
+/* Errata i693 */
+static struct clk      *utmi_p1_fck;
+static struct clk      *utmi_p2_fck;
+static struct clk      *xclk60mhsp1_ck;
+static struct clk      *xclk60mhsp2_ck;
+static struct clk      *usbhost_p1_fck;
+static struct clk      *usbhost_p2_fck;
+static struct clk      *init_60m_fclk;
+
 /*-------------------------------------------------------------------------*/
 
 static const struct hc_driver ehci_omap_hc_driver;
        return __raw_readl(base + reg);
 }
 
+/* Erratum i693 workaround sequence */
+static void omap_ehci_erratum_i693(struct ehci_hcd *ehci)
+{
+       int ret = 0;
+
+       /* Switch to the internal 60 MHz clock */
+       ret = clk_set_parent(utmi_p1_fck, init_60m_fclk);
+       if (ret != 0)
+               ehci_err(ehci, "init_60m_fclk set parent"
+                       "failed error:%d\n", ret);
+
+       ret = clk_set_parent(utmi_p2_fck, init_60m_fclk);
+       if (ret != 0)
+               ehci_err(ehci, "init_60m_fclk set parent"
+                       "failed error:%d\n", ret);
+
+       clk_enable(usbhost_p1_fck);
+       clk_enable(usbhost_p2_fck);
+
+       /* Wait 1ms and switch back to the external clock */
+       mdelay(1);
+       ret = clk_set_parent(utmi_p1_fck, xclk60mhsp1_ck);
+       if (ret != 0)
+               ehci_err(ehci, "xclk60mhsp1_ck set parent"
+                       "failed error:%d\n", ret);
+
+       ret = clk_set_parent(utmi_p2_fck, xclk60mhsp2_ck);
+       if (ret != 0)
+               ehci_err(ehci, "xclk60mhsp2_ck set parent"
+                       "failed error:%d\n", ret);
+
+       clk_disable(usbhost_p1_fck);
+       clk_disable(usbhost_p2_fck);
+}
+
 static void omap_ehci_soft_phy_reset(struct platform_device *pdev, u8 port)
 {
        struct usb_hcd  *hcd = dev_get_drvdata(&pdev->dev);
        }
 }
 
+static int omap_ehci_hub_control(
+       struct usb_hcd  *hcd,
+       u16             typeReq,
+       u16             wValue,
+       u16             wIndex,
+       char            *buf,
+       u16             wLength
+)
+{
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       u32 __iomem *status_reg = &ehci->regs->port_status[
+                               (wIndex & 0xff) - 1];
+       u32             temp;
+       unsigned long   flags;
+       int             retval = 0;
+
+       spin_lock_irqsave(&ehci->lock, flags);
+
+       if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
+               temp = ehci_readl(ehci, status_reg);
+               if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) {
+                       retval = -EPIPE;
+                       goto done;
+               }
+
+               temp &= ~PORT_WKCONN_E;
+               temp |= PORT_WKDISC_E | PORT_WKOC_E;
+               ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
+
+               omap_ehci_erratum_i693(ehci);
+
+               set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports);
+               goto done;
+       }
+
+       spin_unlock_irqrestore(&ehci->lock, flags);
+
+       /* Handle the hub control events here */
+       return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
+done:
+       spin_unlock_irqrestore(&ehci->lock, flags);
+       return retval;
+}
+
 static void disable_put_regulator(
                struct ehci_hcd_omap_platform_data *pdata)
 {
        /* root ports should always stay powered */
        ehci_port_power(omap_ehci, 1);
 
+       /* get clocks */
+       utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
+       if (IS_ERR(utmi_p1_fck)) {
+               ret = PTR_ERR(utmi_p1_fck);
+               dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
+               goto err_add_hcd;
+       }
+
+       xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
+       if (IS_ERR(xclk60mhsp1_ck)) {
+               ret = PTR_ERR(xclk60mhsp1_ck);
+               dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
+               goto err_utmi_p1_fck;
+       }
+
+       utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
+       if (IS_ERR(utmi_p2_fck)) {
+               ret = PTR_ERR(utmi_p2_fck);
+               dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
+               goto err_xclk60mhsp1_ck;
+       }
+
+       xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
+       if (IS_ERR(xclk60mhsp2_ck)) {
+               ret = PTR_ERR(xclk60mhsp2_ck);
+               dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
+               goto err_utmi_p2_fck;
+       }
+
+       usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
+       if (IS_ERR(usbhost_p1_fck)) {
+               ret = PTR_ERR(usbhost_p1_fck);
+               dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
+               goto err_xclk60mhsp2_ck;
+       }
+
+       usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
+       if (IS_ERR(usbhost_p2_fck)) {
+               ret = PTR_ERR(usbhost_p2_fck);
+               dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
+               goto err_usbhost_p1_fck;
+       }
+
+       init_60m_fclk = clk_get(dev, "init_60m_fclk");
+       if (IS_ERR(init_60m_fclk)) {
+               ret = PTR_ERR(init_60m_fclk);
+               dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
+               goto err_usbhost_p2_fck;
+       }
+
        return 0;
 
+err_usbhost_p2_fck:
+       clk_put(usbhost_p2_fck);
+
+err_usbhost_p1_fck:
+       clk_put(usbhost_p1_fck);
+
+err_xclk60mhsp2_ck:
+       clk_put(xclk60mhsp2_ck);
+
+err_utmi_p2_fck:
+       clk_put(utmi_p2_fck);
+
+err_xclk60mhsp1_ck:
+       clk_put(xclk60mhsp1_ck);
+
+err_utmi_p1_fck:
+       clk_put(utmi_p1_fck);
+
 err_add_hcd:
        disable_put_regulator(pdata);
        pm_runtime_put_sync(dev);
        disable_put_regulator(dev->platform_data);
        iounmap(hcd->regs);
        usb_put_hcd(hcd);
+
+       clk_put(utmi_p1_fck);
+       clk_put(utmi_p2_fck);
+       clk_put(xclk60mhsp1_ck);
+       clk_put(xclk60mhsp2_ck);
+       clk_put(usbhost_p1_fck);
+       clk_put(usbhost_p2_fck);
+       clk_put(init_60m_fclk);
+
        pm_runtime_put_sync(dev);
        pm_runtime_disable(dev);
 
         * root hub support
         */
        .hub_status_data        = ehci_hub_status_data,
-       .hub_control            = ehci_hub_control,
+       .hub_control            = omap_ehci_hub_control,
        .bus_suspend            = ehci_bus_suspend,
        .bus_resume             = ehci_bus_resume,