summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRakesh Bodla <rbodla@nvidia.com>2011-08-23 11:19:52 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:48:32 -0800
commit3acee8dd88ec37b2b5dc09e2a70470631a9f2ddd (patch)
treeb956d9085c775af3459d22e7a4504bbb9a17c6eb
parentc0f3ebafb74e967615e8167c285717b8f8168a7b (diff)
usb: ehci: tegra: correct sequence for 2LS bit time
Corrected the sequence for 2LS bit time to all the USB controller for proper suspend and resume. Bug 860452 Original-Change-Id: Ia656893e1e9f54ea149a4039d2933867d95093f3 Reviewed-on: http://git-master/r/48472 Reviewed-by: Rakesh Bodla <rbodla@nvidia.com> Tested-by: Rakesh Bodla <rbodla@nvidia.com> Reviewed-by: Hanumanth Venkateswa Moganty <vmoganty@nvidia.com> Rebase-Id: Ra58611e2110d90601a6b2a051657e3bb4427f76f
-rw-r--r--arch/arm/mach-tegra/usb_phy.c145
-rw-r--r--drivers/usb/host/ehci-tegra.c45
2 files changed, 123 insertions, 67 deletions
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
index 9393cc6822e7..93d330a91227 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -382,6 +382,7 @@
#define UTMIP_WAKE_VAL_P0(x) (((x) & 0xf) << 4)
#define WAKE_VAL_NONE 0xc
#define WAKE_VAL_FSJ 0x2
+#define WAKE_VAL_FSK 0x1
#define PMC_SLEEP_CFG 0x1fc
#define UTMIP_TCTRL_USE_PMC(inst) (1 << ((8*(inst))+3))
@@ -420,6 +421,7 @@
#define UTMIP_CAP_CFG_P2 (1 << 6)
#define UTMIP_CAP_CFG_P1 (1 << 5)
#define UTMIP_CAP_CFG_P0 (1 << 4)
+#define UTMIP_CLR_WAKE_ALARM(inst) (1 << ((inst)+12))
#define UTMIP_CLR_WAKE_ALARM_P2 (1 << 14)
#define PMC_PAD_CFG (0x1f4)
@@ -457,7 +459,10 @@
#define UTMIP_UHSIC_STATUS 0x214
#define UTMIP_WALK_PTR_P2(x) (((x) & 0x3) << 4)
-#define WAKE_ALARM_P2 (1 << 18)
+#define UTMIP_WAKE_ALARM(inst) (1 << ((inst) + 16))
+#define UTMIP_WAKE_ALARM_P2 (1 << 18)
+#define UTMIP_WAKE_ALARM_P1 (1 << 17)
+#define UTMIP_WAKE_ALARM_P0 (1 << 16)
#endif
/* Common registers */
@@ -989,7 +994,9 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd)
#else
if(phy->instance == 2) {
writel(0, base + ICUSB_CTRL);
+ }
+ if (phy->mode == TEGRA_USB_PHY_MODE_HOST) {
val = readl(base + TEGRA_USB_USBMODE_REG_OFFSET);
writel((val | TEGRA_USB_USBMODE_HOST),
(base + TEGRA_USB_USBMODE_REG_OFFSET));
@@ -1009,6 +1016,12 @@ static void utmip_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
unsigned long val, pmc_pad_cfg_val;
void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
unsigned int inst = phy->instance;
+ void __iomem *base = phy->regs;
+ bool port_connected;
+
+ /* check for port connect status */
+ val = readl(base + USB_PORTSC1);
+ port_connected = val & USB_PORTSC1_CCS;
/*Set PMC MASTER bits to do the following
* a. Take over the UTMI drivers
@@ -1126,7 +1139,10 @@ static void utmip_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
/* Turn over pad configuration to PMC */
val = readl(pmc_base + PMC_SLEEP_CFG);
val &= ~UTMIP_WAKE_VAL(inst, ~0);
- val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_FSJ);
+ if (port_connected)
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_FSK);
+ else
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_FSJ);
val |= UTMIP_MASTER_ENABLE(inst) | UTMIP_FSLS_USE_PMC(inst);
writel(val, pmc_base + PMC_SLEEP_CFG);
}
@@ -1138,7 +1154,7 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd)
void __iomem *base = phy->regs;
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- if (phy->instance == 2)
+ if (phy->mode == TEGRA_USB_PHY_MODE_HOST)
utmip_setup_pmc_wake_detect(phy);
#endif
if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
@@ -1208,25 +1224,31 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd)
return 0;
}
-static int utmi_phy_preresume(struct tegra_usb_phy *phy, bool is_dpd)
+static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
{
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
unsigned long val;
- void __iomem *base = phy->regs;
void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
unsigned int inst = phy->instance;
+ /* Disable PMC master mode by clearing MASTER_EN */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) |
+ UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst));
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+#endif
+}
+
+static int utmi_phy_preresume(struct tegra_usb_phy *phy, bool is_dpd)
+{
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ unsigned long val;
+ void __iomem *base = phy->regs;
val = readl(base + UTMIP_TX_CFG0);
val |= UTMIP_HS_DISCON_DISABLE;
writel(val, base + UTMIP_TX_CFG0);
#else
- if (inst == 2) {
- /* Disable PMC master mode by clearing MASTER_EN */
- val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) |
- UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst));
- writel(val, pmc_base + PMC_SLEEP_CFG);
- }
+ utmip_phy_disable_pmc_bus_ctrl(phy);
#endif
return 0;
@@ -1238,27 +1260,25 @@ static int utmi_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd)
void __iomem *base = phy->regs;
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- if (phy->instance == 2) {
- /* Change the UTMIP OBS bus to drive SE0 */
- val = readl(base + UTMIP_MISC_CFG0);
- val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
- val |= UTMIP_DPDM_OBSERVE_SEL_FS_SE0;
- writel(val, base + UTMIP_MISC_CFG0);
-
- /* Wait for 3us(2 LS bit times) */
- udelay (3);
-
- /* Release UTMIP OBS bus */
- val = readl(base + UTMIP_MISC_CFG0);
- val &= ~UTMIP_DPDM_OBSERVE;
- writel(val, base + UTMIP_MISC_CFG0);
-
- /* Release DP/DM pulldown for Host mode */
- val = readl(base + UTMIP_MISC_CFG0);
- val &= ~(FORCE_PULLDN_DM | FORCE_PULLDN_DP |
- COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS);
- writel(val, base + UTMIP_MISC_CFG0);
- }
+ /* Change the UTMIP OBS bus to drive SE0 */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_SE0;
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ /* Wait for 3us(2 LS bit times) */
+ udelay (3);
+
+ /* Release UTMIP OBS bus */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_DPDM_OBSERVE;
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ /* Release DP/DM pulldown for Host mode */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~(FORCE_PULLDN_DM | FORCE_PULLDN_DP |
+ COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS);
+ writel(val, base + UTMIP_MISC_CFG0);
#else
val = readl(base + UTMIP_TX_CFG0);
val &= ~UTMIP_HS_DISCON_DISABLE;
@@ -1327,26 +1347,24 @@ static void utmi_phy_restore_start(struct tegra_usb_phy *phy,
unsigned long val;
void __iomem *base = phy->regs;
- if (phy->instance == 2) {
- /* Force DP/DM pulldown active for Host mode */
- val = readl(base + UTMIP_MISC_CFG0);
- val |= FORCE_PULLDN_DM | FORCE_PULLDN_DP |
- COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS;
- writel(val, base + UTMIP_MISC_CFG0);
- val = readl(base + UTMIP_MISC_CFG0);
- val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
- if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
- val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
- else
- val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
- writel(val, base + UTMIP_MISC_CFG0);
- udelay(1);
+ /* Force DP/DM pulldown active for Host mode */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val |= FORCE_PULLDN_DM | FORCE_PULLDN_DP |
+ COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS;
+ writel(val, base + UTMIP_MISC_CFG0);
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
+ if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
+ else
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(1);
- val = readl(base + UTMIP_MISC_CFG0);
- val |= UTMIP_DPDM_OBSERVE;
- writel(val, base + UTMIP_MISC_CFG0);
- udelay(10);
- }
+ val = readl(base + UTMIP_MISC_CFG0);
+ val |= UTMIP_DPDM_OBSERVE;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(10);
#endif
}
@@ -2198,8 +2216,10 @@ void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy)
void tegra_usb_phy_close(struct tegra_usb_phy *phy)
{
- if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP)
+ if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) {
utmip_pad_close(phy);
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+ }
else if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_LINK_ULPI && phy->clk)
clk_put(phy->clk);
if (phy->mode == TEGRA_USB_PHY_MODE_HOST) {
@@ -2440,22 +2460,23 @@ int __init tegra_usb_phy_init(struct usb_phy_plat_data *pdata, int size)
int tegra_usb_phy_clear_connect_intr(struct tegra_usb_phy *phy)
{
+ u32 ret = -EIO;
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
void __iomem *base = phy->regs;
+ unsigned int inst = phy->instance;
u32 val;
- u32 ret = -EIO;
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
val = readl(pmc_base + UTMIP_UHSIC_STATUS);
- val &= WAKE_ALARM_P2;
+ val &= UTMIP_WAKE_ALARM(inst);
if (val) {
val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~UTMIP_WAKE_VAL_P2(0x0);
- val |= UTMIP_WAKE_VAL_P2(0xc);
+ val &= ~UTMIP_WAKE_VAL(inst, 0x0);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE);
writel(val, pmc_base + PMC_SLEEP_CFG);
val = readl(pmc_base + PMC_TRIGGERS);
- val |= UTMIP_CLR_WAKE_ALARM_P2 | UTMIP_CLR_WALK_PTR_P2;
+ val |= UTMIP_CLR_WAKE_ALARM(inst) | UTMIP_CLR_WALK_PTR(inst);
writel(val, pmc_base + PMC_TRIGGERS);
val = readl(base + UTMIP_PMC_WAKEUP0);
@@ -2463,11 +2484,11 @@ int tegra_usb_phy_clear_connect_intr(struct tegra_usb_phy *phy)
writel(val, base + UTMIP_PMC_WAKEUP0);
val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~(UTMIP_MASTER_ENABLE_P2 |UTMIP_FSLS_USE_PMC_P2 |
- UTMIP_RCTRL_USE_PMC_P2 |UTMIP_TCTRL_USE_PMC_P2);
+ val &= ~(UTMIP_MASTER_ENABLE(inst) |UTMIP_FSLS_USE_PMC(inst) |
+ UTMIP_RCTRL_USE_PMC(inst) |UTMIP_TCTRL_USE_PMC(inst));
writel(val, pmc_base + PMC_SLEEP_CFG);
ret = 0;
}
- return ret;
#endif
+ return ret;
}
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 4b7f9719b673..a63a06f9793f 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -50,6 +50,9 @@
#define TEGRA_HSIC_CONNECTION_MAX_RETRIES 5
#define HOSTPC_REG_OFFSET 0x1b4
+#define HOSTPC1_DEVLC_STS (1 << 28)
+#define HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29)
+
struct tegra_ehci_hcd {
struct ehci_hcd *ehci;
struct tegra_usb_phy *phy;
@@ -164,8 +167,12 @@ static void irq_work(struct work_struct *irq_work)
struct tegra_ehci_hcd *tegra =
container_of(irq_work, struct tegra_ehci_hcd, irq_work);
hcd = ehci_to_hcd(tegra->ehci);
- if (!tegra->host_resumed)
+ if (!tegra->host_resumed) {
+#ifdef CONFIG_USB_HOTPLUG
+ clk_enable(tegra->clk);
+#endif
tegra_ehci_power_up(hcd, false);
+ }
}
static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd)
@@ -219,7 +226,9 @@ static int tegra_ehci_hub_control(
int ports = HCS_N_PORTS(ehci->hcs_params);
u32 temp, status;
u32 __iomem *status_reg;
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
u32 usbsts_reg;
+#endif
unsigned long flags;
int retval = 0;
unsigned selector;
@@ -511,9 +520,19 @@ 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)
+ ehci_reset(ehci);
+
/* Enable host mode */
tdi_reset(ehci);
+ if (tegra->ehci->has_hostpc) {
+ val = readl(hcd->regs + HOSTPC_REG_OFFSET);
+ val &= ~HOSTPC1_DEVLC_PTS(~0);
+ val |= HOSTPC1_DEVLC_STS;
+ writel(val, hcd->regs + HOSTPC_REG_OFFSET);
+ }
+
/* Enable Port Power */
val = readl(&hw->port_status[0]);
val |= PORT_POWER;
@@ -919,9 +938,9 @@ static int tegra_ehci_urb_enqueue (
struct tegra_ehci_hcd *pdata;
int xfertype;
int transfer_buffer_length;
- pdata = dev_get_drvdata(hcd->self.controller);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
unsigned long flags;
+ pdata = dev_get_drvdata(hcd->self.controller);
xfertype = usb_endpoint_type(&urb->ep->desc);
transfer_buffer_length = urb->transfer_buffer_length;
@@ -1157,9 +1176,16 @@ static int tegra_ehci_resume(struct platform_device *pdev)
struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci);
- if ((tegra->bus_suspended) && (tegra->power_down_on_bus_suspend))
+ if ((tegra->bus_suspended) && (tegra->power_down_on_bus_suspend)) {
+#ifdef CONFIG_USB_HOTPLUG
+ clk_enable(tegra->clk);
+#endif
return 0;
+ }
+#ifdef CONFIG_USB_HOTPLUG
+ clk_enable(tegra->clk);
+#endif
return tegra_usb_resume(hcd, true);
}
@@ -1167,14 +1193,23 @@ static int tegra_ehci_suspend(struct platform_device *pdev, pm_message_t state)
{
struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci);
+ int ret;
- if ((tegra->bus_suspended) && (tegra->power_down_on_bus_suspend))
+ if ((tegra->bus_suspended) && (tegra->power_down_on_bus_suspend)) {
+#ifdef CONFIG_USB_HOTPLUG
+ clk_disable(tegra->clk);
+#endif
return 0;
+ }
if (time_before(jiffies, tegra->ehci->next_statechange))
msleep(10);
- return tegra_usb_suspend(hcd, true);
+ ret = tegra_usb_suspend(hcd, true);
+#ifdef CONFIG_USB_HOTPLUG
+ clk_disable(tegra->clk);
+#endif
+ return ret;
}
#endif