From 6101daf11fb99307e2b7491eea2b1bf39c8ff5d1 Mon Sep 17 00:00:00 2001 From: Rakesh Bodla Date: Fri, 25 May 2012 18:10:07 +0530 Subject: 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 Reviewed-on: http://git-master/r/104746 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Venkat Moganty --- drivers/usb/host/ehci-tegra.c | 64 +++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 29 deletions(-) (limited to 'drivers') 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 #include +#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; } -- cgit v1.2.3