arm: tegra: usb: fix UTMIP auto suspend issues
Rakesh Bodla [Thu, 31 May 2012 16:02:23 +0000 (21:02 +0530)]
Fixing the UTMIP auto suspend issues.

Bug 992463
Bug 989400

Change-Id: Ia0d536cd66081b263f7f2bde5debcc600dcef22a
Signed-off-by: Rakesh Bodla <rbodla@nvidia.com>
Reviewed-on: http://git-master/r/105692
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>

arch/arm/mach-tegra/tegra3_usb_phy.c
drivers/usb/host/ehci-tegra.c

index 7a48d41..3715f26 100644 (file)
@@ -1342,16 +1342,20 @@ static int utmi_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
        unsigned  int inst = phy->inst;
 
        DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
-
-       val = (readl(base + HOSTPC1_DEVLC) >> 25) &
+       phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
                        HOSTPC1_DEVLC_PSPD_MASK;
-       if (val == USB_PHY_PORT_SPEED_HIGH) {
+
+       if (phy->port_speed == USB_PHY_PORT_SPEED_HIGH) {
                /* Disable interrupts */
                writel(0, base + USB_USBINTR);
                /* Clear the run bit to stop SOFs - 2LS WAR */
                val = readl(base + USB_USBCMD);
                val &= ~USB_USBCMD_RS;
                writel(val, base + USB_USBCMD);
+               if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH,
+                                                        USB_USBSTS_HCH, 2000)) {
+                       pr_err("%s: timeout waiting for USB_USBSTS_HCH\n", __func__);
+               }
        }
 
        val = readl(pmc_base + PMC_SLEEP_CFG);
@@ -1389,6 +1393,21 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy)
                val |= UTMIP_PD_CHRG;
                writel(val, base + UTMIP_BAT_CHRG_CFG0);
        } else {
+               phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
+                               HOSTPC1_DEVLC_PSPD_MASK;
+
+               /* Disable interrupts */
+               writel(0, base + USB_USBINTR);
+
+               /* Clear the run bit to stop SOFs - 2LS WAR */
+               val = readl(base + USB_USBCMD);
+               val &= ~USB_USBCMD_RS;
+               writel(val, base + USB_USBCMD);
+
+               if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH,
+                                                        USB_USBSTS_HCH, 2000)) {
+                       pr_err("%s: timeout waiting for USB_USBSTS_HCH\n", __func__);
+               }
                utmip_setup_pmc_wake_detect(phy);
        }
 
@@ -1410,9 +1429,6 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy)
 
        utmi_phy_pad_power_off(phy);
 
-       phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
-                       HOSTPC1_DEVLC_PSPD_MASK;
-
        if (phy->pdata->u_data.host.hot_plug) {
                bool enable_hotplug = true;
                /* if it is OTG port then make sure to enable hot-plug feature
index d335568..ab2bdb3 100644 (file)
@@ -228,7 +228,7 @@ static int tegra_ehci_hub_control(
                        status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1];
                        /* Ensure the port PORT_SUSPEND and PORT_RESUME has cleared */
                        if (handshake(ehci, status_reg, (PORT_SUSPEND | PORT_RESUME), 0, 25000)) {
-                               pr_err("%s: timeout waiting for SUSPEND to clear\n", __func__);
+                               EHCI_DBG("%s: timeout waiting for SUSPEND to clear\n", __func__);
                        }
                        tegra_usb_phy_post_resume(tegra->phy);
                        tegra->port_resuming = 0;
@@ -245,6 +245,11 @@ static int tegra_ehci_hub_control(
                if (wValue == USB_PORT_FEAT_SUSPEND) {
                        tegra_usb_phy_pre_resume(tegra->phy, false);
                        tegra->port_resuming = 1;
+               } else if (wValue == USB_PORT_FEAT_ENABLE) {
+                       u32 temp;
+                       temp = ehci_readl(ehci, &ehci->regs->port_status[0]) & ~PORT_RWC_BITS;
+                       ehci_writel(ehci, temp & ~PORT_PE, &ehci->regs->port_status[0]);
+                       return retval;
                }
                break;
        }
@@ -268,6 +273,12 @@ static int tegra_ehci_hub_control(
                                        tegra_usb_phy_port_power(tegra->phy);
                        }
                        break;
+               case ClearPortFeature:
+                       if (wValue == USB_PORT_FEAT_SUSPEND) {
+                               /* tegra USB controller needs 25 ms to resume the port */
+                               ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25);
+                       }
+                       break;
                }
        }