summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRakesh Bodla <rbodla@nvidia.com>2012-05-25 18:10:07 +0530
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-05-29 07:01:38 -0700
commit6101daf11fb99307e2b7491eea2b1bf39c8ff5d1 (patch)
tree9227d52aee169da2624ac74bd179914d987e1de4
parent819931a20214284ae55d8bc67c458c6790035a93 (diff)
usb: ehci: tegra: fix remote wakeup issues
This change fixes remote wakeup issues when usb line is in suspend state. Bug 989441 Bug 989400 Change-Id: I97982943d5521470b83ed87b83ab8703c4e9c260 Signed-off-by: Rakesh Bodla <rbodla@nvidia.com> Reviewed-on: http://git-master/r/104746 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>
-rw-r--r--drivers/usb/host/ehci-tegra.c64
1 files changed, 35 insertions, 29 deletions
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 82523bd200a6..c5fa8160bffe 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -23,6 +23,12 @@
#include <mach/usb_phy.h>
#include <mach/iomap.h>
+#if 0
+#define EHCI_DBG(stuff...) pr_info("ehci-tegra: " stuff)
+#else
+#define EHCI_DBG(stuff...) do {} while (0)
+#endif
+
static const char driver_name[] = "tegra-ehci";
#define TEGRA_USB_DMA_ALIGN 32
@@ -164,6 +170,11 @@ static irqreturn_t tegra_ehci_irq(struct usb_hcd *hcd)
}
spin_unlock(&ehci->lock);
+ EHCI_DBG("%s() cmd = 0x%x, int_sts = 0x%x, portsc = 0x%x\n", __func__,
+ ehci_readl(ehci, &ehci->regs->command),
+ ehci_readl(ehci, &ehci->regs->status),
+ ehci_readl(ehci, &ehci->regs->port_status[0]));
+
irq_status = ehci_irq(hcd);
if (pmc_remote_wakeup) {
@@ -172,8 +183,6 @@ static irqreturn_t tegra_ehci_irq(struct usb_hcd *hcd)
if (ehci->controller_remote_wakeup) {
ehci->controller_remote_wakeup = false;
- /* disable interrupts */
- ehci_writel(ehci, 0, &ehci->regs->intr_enable);
tegra_usb_phy_pre_resume(tegra->phy, true);
tegra->port_resuming = 1;
}
@@ -202,33 +211,30 @@ static int tegra_ehci_hub_control(
return retval;
}
- status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1];
-
- spin_lock_irqsave(&ehci->lock, flags);
/* Do tegra phy specific actions based on the type request */
switch (typeReq) {
case GetPortStatus:
- if (time_after_eq(jiffies, ehci->reset_done[wIndex - 1])) {
- if (tegra->port_resuming) {
- int delay = ehci->reset_done[wIndex-1] - jiffies;
- /* Sometimes it seems we get called too soon... In that case, wait.*/
- if (delay > 0) {
- ehci_dbg(ehci, "GetPortStatus called too soon, waiting %dms...\n", delay);
- mdelay(jiffies_to_msecs(delay));
- }
- /* 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__);
- }
- tegra_usb_phy_post_resume(tegra->phy);
- tegra->port_resuming = 0;
- /* If run bit is not set by now enable it */
- if (ehci->command & CMD_RUN) {
- ehci->command |= CMD_RUN;
- ehci_writel(ehci, ehci->command,
- &ehci->regs->command);
- }
+ if (tegra->port_resuming) {
+ int delay = ehci->reset_done[wIndex-1] - jiffies;
+ /* Sometimes it seems we get called too soon... In that case, wait.*/
+ if (delay > 0) {
+ ehci_dbg(ehci, "GetPortStatus called too soon, waiting %dms...\n", delay);
+ mdelay(jiffies_to_msecs(delay));
}
+ 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__);
+ }
+ tegra_usb_phy_post_resume(tegra->phy);
+ tegra->port_resuming = 0;
+ /* If run bit is not set by now enable it */
+ if (ehci->command & CMD_RUN) {
+ ehci->command |= CMD_RUN;
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ }
+ /* Now we can safely re-enable irqs */
+ ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
}
break;
case ClearPortFeature:
@@ -238,14 +244,12 @@ static int tegra_ehci_hub_control(
}
break;
}
- spin_unlock_irqrestore(&ehci->lock, flags);
/* handle ehci hub control request */
retval = ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
/* do tegra phy specific actions based on the type request */
if (!retval) {
- spin_lock_irqsave(&ehci->lock, flags);
switch (typeReq) {
case SetPortFeature:
if (wValue == USB_PORT_FEAT_SUSPEND) {
@@ -261,7 +265,6 @@ static int tegra_ehci_hub_control(
}
break;
}
- spin_unlock_irqrestore(&ehci->lock, flags);
}
return retval;
@@ -327,7 +330,7 @@ static int tegra_ehci_bus_suspend(struct usb_hcd *hcd)
{
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
int err = 0;
-
+ EHCI_DBG("%s() BEGIN\n", __func__);
mutex_lock(&tegra->sync_lock);
tegra->bus_suspended_fail = false;
err = ehci_bus_suspend(hcd);
@@ -336,6 +339,7 @@ static int tegra_ehci_bus_suspend(struct usb_hcd *hcd)
else
tegra_usb_phy_suspend(tegra->phy);
mutex_unlock(&tegra->sync_lock);
+ EHCI_DBG("%s() END\n", __func__);
return err;
}
@@ -344,11 +348,13 @@ static int tegra_ehci_bus_resume(struct usb_hcd *hcd)
{
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
int err = 0;
+ EHCI_DBG("%s() BEGIN\n", __func__);
mutex_lock(&tegra->sync_lock);
tegra_usb_phy_resume(tegra->phy);
err = ehci_bus_resume(hcd);
mutex_unlock(&tegra->sync_lock);
+ EHCI_DBG("%s() END\n", __func__);
return err;
}