diff options
author | Rakesh Bodla <rbodla@nvidia.com> | 2012-05-25 18:10:07 +0530 |
---|---|---|
committer | Varun Wadekar <vwadekar@nvidia.com> | 2012-06-07 09:45:42 +0530 |
commit | 7f64d20783f421b594c3f8c5296c0032046b9cd4 (patch) | |
tree | e1026ba73a560fc7f64e11058cf6e36c5b939399 | |
parent | 967f5d0c963976d59f7443460757842498ee0182 (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.c | 64 |
1 files changed, 35 insertions, 29 deletions
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index cfcd6a5b8c9b..d33556815423 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -27,6 +27,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 @@ -168,6 +174,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) { @@ -176,8 +187,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; } @@ -206,33 +215,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: @@ -242,14 +248,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) { @@ -265,7 +269,6 @@ static int tegra_ehci_hub_control( } break; } - spin_unlock_irqrestore(&ehci->lock, flags); } return retval; @@ -331,7 +334,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); @@ -340,6 +343,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; } @@ -348,11 +352,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; } |