From 2c596cbe2ed008c047a695e77aa687564c8cf74d Mon Sep 17 00:00:00 2001 From: Rakesh Bodla Date: Thu, 31 May 2012 21:32:23 +0530 Subject: arm: tegra: usb: fix UTMIP auto suspend issues Fixing the UTMIP auto suspend issues. Bug 992463 Bug 989400 Change-Id: Ia0d536cd66081b263f7f2bde5debcc600dcef22a Signed-off-by: Rakesh Bodla Reviewed-on: http://git-master/r/105692 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Venkat Moganty --- arch/arm/mach-tegra/tegra3_usb_phy.c | 28 ++++++++++++++++++++++------ drivers/usb/host/ehci-tegra.c | 13 ++++++++++++- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-tegra/tegra3_usb_phy.c b/arch/arm/mach-tegra/tegra3_usb_phy.c index 432dd5509664..b151eb61d5e9 100644 --- a/arch/arm/mach-tegra/tegra3_usb_phy.c +++ b/arch/arm/mach-tegra/tegra3_usb_phy.c @@ -1341,16 +1341,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); @@ -1388,6 +1392,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); } @@ -1409,9 +1428,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 diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index c5fa8160bffe..98f3d5106a38 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -224,7 +224,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; @@ -241,6 +241,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; } @@ -264,6 +269,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; } } -- cgit v1.2.3