summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorVenkat Moganty <vmoganty@nvidia.com>2011-09-15 18:27:21 +0530
committerRohan Somvanshi <rsomvanshi@nvidia.com>2011-09-16 06:47:34 -0700
commite796581d9baee3317b65771637ec59b76191391f (patch)
treed4dfe8f94fd53519d03a14e39fea29125591b4f6 /drivers
parentd1800dacc1d106ef81b3b4ef98d6dbc7c8b723b4 (diff)
usb: ehci: tegra: Add remote wakeup support
Adding remote wakeup support. Bug 805906 Change-Id: I4e8637161abd1c5de90b0f856ad5c877e9433e42 Reviewed-on: http://git-master/r/52620 Reviewed-by: Venkat Moganty <vmoganty@nvidia.com> Tested-by: Venkat Moganty <vmoganty@nvidia.com> Reviewed-by: Rakesh Bodla <rbodla@nvidia.com> Tested-by: Rakesh Bodla <rbodla@nvidia.com> Reviewed-by: Rama Kandhala <rkandhala@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/ehci-tegra.c55
1 files changed, 41 insertions, 14 deletions
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 23be171fac0f..a7c0cc1c1a2d 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -48,7 +48,7 @@
#define STS_SRI (1<<7) /* SOF Recieved */
#define TEGRA_HSIC_CONNECTION_MAX_RETRIES 5
-#define HOSTPC_REG_OFFSET 0x1b4
+#define HOSTPC_REG_OFFSET 0x1b4
#define HOSTPC1_DEVLC_STS (1 << 28)
#define HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29)
@@ -102,6 +102,15 @@ static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd)
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
u32 val;
+ if ((tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) &&
+ (tegra->ehci->has_hostpc)) {
+ /* check if there is any remote wake event */
+ if (tegra_usb_phy_is_remotewake_detected(tegra->phy)) {
+ spin_lock (&ehci->lock);
+ usb_hcd_resume_root_hub(hcd);
+ spin_unlock (&ehci->lock);
+ }
+ }
if (tegra->phy->instance == 2) {
spin_lock(&ehci->lock);
val = readl(hcd->regs + TEGRA_USB_SUSP_CTRL_OFFSET);
@@ -178,8 +187,15 @@ static int tegra_ehci_hub_control(
ehci->reset_done[wIndex-1] = 0;
tegra_usb_phy_postresume(tegra->phy, false);
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- ehci->command |= CMD_RUN;
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) {
+ ehci->command |= CMD_RUN;
+ /*
+ * ehci run bit is disabled to avoid SOF.
+ * 2LS WAR is executed by now enable the run bit.
+ */
+ ehci_writel(ehci, ehci->command,
+ &ehci->regs->command);
+ }
#endif
}
} else if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
@@ -394,8 +410,15 @@ static int tegra_usb_suspend(struct usb_hcd *hcd, bool is_dpd)
tegra->port_speed = (readl(&hw->port_status[0]) >> 26) & 0x3;
ehci_halt(tegra->ehci);
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- tegra->ehci->command = ehci_readl(tegra->ehci,
- &tegra->ehci->regs->command);
+ if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) {
+ /*
+ * Ehci run bit is disabled by now read this into command variable
+ * so that bus resume will not enable run bit immedialty.
+ * this is required for 2LS WAR on UTMIP interface.
+ */
+ tegra->ehci->command = ehci_readl(tegra->ehci,
+ &tegra->ehci->regs->command);
+ }
#endif
spin_unlock_irqrestore(&tegra->ehci->lock, flags);
@@ -424,13 +447,16 @@ static int tegra_usb_resume(struct usb_hcd *hcd, bool is_dpd)
/* Force the phy to keep data lines in suspend state */
tegra_ehci_phy_restore_start(tegra->phy, tegra->port_speed);
- if (tegra->ehci->has_hostpc)
+ if ((tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) &&
+ (tegra->ehci->has_hostpc)) {
ehci_reset(ehci);
+ }
/* Enable host mode */
tdi_reset(ehci);
- if (tegra->ehci->has_hostpc) {
+ if ((tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) &&
+ (tegra->ehci->has_hostpc)) {
val = readl(hcd->regs + HOSTPC_REG_OFFSET);
val &= ~HOSTPC1_DEVLC_PTS(~0);
val |= HOSTPC1_DEVLC_STS;
@@ -443,6 +469,12 @@ static int tegra_usb_resume(struct usb_hcd *hcd, bool is_dpd)
writel(val, &hw->port_status[0]);
udelay(10);
+ if ((tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) &&
+ (tegra->ehci->has_hostpc) && (tegra->phy->remote_wakeup)) {
+ ehci->command |= CMD_RUN;
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ }
+
/* Check if the phy resume from LP0. When the phy resume from LP0
* USB register will be reset. */
if (!readl(&hw->async_next)) {
@@ -599,9 +631,7 @@ static int tegra_ehci_setup(struct usb_hcd *hcd)
#ifdef CONFIG_PM
static int tegra_ehci_bus_suspend(struct usb_hcd *hcd)
{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
- u32 port_status;
int error_status = 0;
mutex_lock(&tegra->tegra_ehci_hcd_mutex);
@@ -611,11 +641,8 @@ static int tegra_ehci_bus_suspend(struct usb_hcd *hcd)
tegra_ehci_power_up(hcd, false);
error_status = ehci_bus_suspend(hcd);
if (!error_status && tegra->power_down_on_bus_suspend) {
- port_status = ehci_readl(ehci, &ehci->regs->port_status[0]);
- if (!(port_status & PORT_CONNECT)) {
- tegra_usb_suspend(hcd, false);
- tegra->bus_suspended = 1;
- }
+ tegra_usb_suspend(hcd, false);
+ tegra->bus_suspended = 1;
}
tegra_usb_phy_postsuspend(tegra->phy, false);
mutex_unlock(&tegra->tegra_ehci_hcd_mutex);