diff options
Diffstat (limited to 'arch/arm/mach-tegra/tegra3_usb_phy.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra3_usb_phy.c | 346 |
1 files changed, 259 insertions, 87 deletions
diff --git a/arch/arm/mach-tegra/tegra3_usb_phy.c b/arch/arm/mach-tegra/tegra3_usb_phy.c index 3a831c59a750..66637f29b19c 100644 --- a/arch/arm/mach-tegra/tegra3_usb_phy.c +++ b/arch/arm/mach-tegra/tegra3_usb_phy.c @@ -473,6 +473,11 @@ #define PHY_DBG(stuff...) do {} while (0) #endif +/* define HSIC phy params */ +#define HSIC_SYNC_START_DELAY 9 +#define HSIC_IDLE_WAIT_DELAY 17 +#define HSIC_ELASTIC_UNDERRUN_LIMIT 16 +#define HSIC_ELASTIC_OVERRUN_LIMIT 16 static u32 utmip_rctrl_val, utmip_tctrl_val; static DEFINE_SPINLOCK(utmip_pad_lock); @@ -632,12 +637,6 @@ static void utmip_setup_pmc_wake_detect(struct tegra_usb_phy *phy) writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE); /* Enable which type of event can trigger a walk, - in this case usb_line_wake */ - val = readl(pmc_base + PMC_SLEEPWALK_CFG); - val |= UTMIP_LINEVAL_WALK_EN(inst); - writel(val, pmc_base + PMC_SLEEPWALK_CFG); - - /* Enable which type of event can trigger a walk, * in this case usb_line_wake */ val = readl(pmc_base + PMC_SLEEPWALK_CFG); val |= UTMIP_LINEVAL_WALK_EN(inst); @@ -721,10 +720,6 @@ static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy) 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(inst) | UTMIP_CLR_WALK_PTR(inst); - writel(val, pmc_base + PMC_TRIGGERS); - val = readl(base + UTMIP_PMC_WAKEUP0); val &= ~EVENT_INT_ENB; writel(val, base + UTMIP_PMC_WAKEUP0); @@ -744,6 +739,11 @@ static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy) val |= (USBOP_VAL_PD(inst) | USBON_VAL_PD(inst)); writel(val, pmc_base + PMC_USB_AO); + val = readl(pmc_base + PMC_TRIGGERS); + val |= UTMIP_CLR_WALK_PTR(inst); + val |= UTMIP_CLR_WAKE_ALARM(inst); + writel(val, pmc_base + PMC_TRIGGERS); + phy->remote_wakeup = false; PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, inst); } @@ -766,8 +766,7 @@ bool utmi_phy_remotewake_detected(struct tegra_usb_phy *phy) writel(val, pmc_base + PMC_SLEEP_CFG); val = readl(pmc_base + PMC_TRIGGERS); - val |= UTMIP_CLR_WAKE_ALARM(inst) | - UTMIP_CLR_WALK_PTR(inst); + val |= UTMIP_CLR_WAKE_ALARM(inst); writel(val, pmc_base + PMC_TRIGGERS); val = readl(base + UTMIP_PMC_WAKEUP0); @@ -989,7 +988,8 @@ static int usb_phy_bringup_host_controller(struct tegra_usb_phy *phy) /* Program the field PTC based on the saved speed mode */ val = readl(base + USB_PORTSC); val &= ~USB_PORTSC_PTC(~0); - if (phy->port_speed == USB_PHY_PORT_SPEED_HIGH) + if ((phy->port_speed == USB_PHY_PORT_SPEED_HIGH) || + (phy->pdata->phy_intf == TEGRA_USB_PHY_INTF_HSIC)) val |= USB_PORTSC_PTC(5); else if (phy->port_speed == USB_PHY_PORT_SPEED_FULL) val |= USB_PORTSC_PTC(6); @@ -1222,19 +1222,23 @@ static int utmi_phy_irq(struct tegra_usb_phy *phy) { void __iomem *base = phy->regs; unsigned long val = 0; + bool remote_wakeup = false; + int irq_status = IRQ_HANDLED; if (phy->phy_clk_on) { DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n", - readl(base + USB_USBSTS), readl(base + USB_PORTSC)); + readl(base + USB_USBSTS), readl(base + USB_PORTSC)); DBG("USB_USBMODE[0x%x] USB_USBCMD[0x%x]\n", - readl(base + USB_USBMODE), readl(base + USB_USBCMD)); + readl(base + USB_USBMODE), readl(base + USB_USBCMD)); } usb_phy_fence_read(phy); /* check if there is any remote wake event */ - if (utmi_phy_remotewake_detected(phy)) + if (utmi_phy_remotewake_detected(phy)) { pr_info("%s: utmip remote wake detected\n", __func__); + remote_wakeup = true; + } if (phy->pdata->u_data.host.hot_plug) { val = readl(base + USB_SUSP_CTRL); @@ -1242,19 +1246,36 @@ static int utmi_phy_irq(struct tegra_usb_phy *phy) val &= ~USB_PHY_CLK_VALID_INT_ENB | USB_PHY_CLK_VALID_INT_STS; writel(val , (base + USB_SUSP_CTRL)); - pr_info("%s: usb device plugged-in\n", __func__); - val = readl(base + USB_USBSTS); - if (!(val & USB_USBSTS_PCI)) - return IRQ_NONE; - val = readl(base + USB_PORTSC); - val &= ~(USB_PORTSC_WKCN | USB_PORTSC_RWC_BITS); - writel(val , (base + USB_PORTSC)); + + /* In case of remote wakeup PHY clock will not up + immediately, so should not access any controller + register but normal plug-in/plug-out should be + executed */ + if (!remote_wakeup) { + val = readl(base + USB_USBSTS); + if (!(val & USB_USBSTS_PCI)) { + irq_status = IRQ_NONE; + goto exit; + } + + val = readl(base + USB_PORTSC); + if (val & USB_PORTSC_CCS) + val &= ~USB_PORTSC_WKCN; + else + val &= ~USB_PORTSC_WKDS; + val &= ~USB_PORTSC_RWC_BITS; + writel(val , (base + USB_PORTSC)); + } } else if (!phy->phy_clk_on) { - return IRQ_NONE; + if (remote_wakeup) + irq_status = IRQ_HANDLED; + else + irq_status = IRQ_NONE; + goto exit; } } - - return IRQ_HANDLED; +exit: + return irq_status; } static void utmi_phy_enable_obs_bus(struct tegra_usb_phy *phy) @@ -1466,8 +1487,12 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy) enable_hotplug = (val & USB_ID_STATUS) ? false : true; } if (enable_hotplug) { + /* Enable wakeup event of device plug-in/plug-out */ val = readl(base + USB_PORTSC); - val |= USB_PORTSC_WKCN; + if (val & USB_PORTSC_CCS) + val |= USB_PORTSC_WKDS; + else + val |= USB_PORTSC_WKCN; writel(val, base + USB_PORTSC); val = readl(base + USB_SUSP_CTRL); @@ -1481,6 +1506,7 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy) } } + /* Disable PHY clock */ val = readl(base + HOSTPC1_DEVLC); val |= HOSTPC1_DEVLC_PHCD; writel(val, base + HOSTPC1_DEVLC); @@ -1647,11 +1673,11 @@ static void utmi_phy_restore_start(struct tegra_usb_phy *phy) if (UTMIP_WALK_PTR_VAL(inst) & val) { phy->remote_wakeup = true; } else if(!phy->remote_wakeup) { - if (!((UTMIP_USBON_VAL(phy->inst) | - UTMIP_USBOP_VAL(phy->inst)) & val)) { - utmip_phy_disable_pmc_bus_ctrl(phy); - } + val = readl(pmc_base + PMC_SLEEP_CFG); + if (val & UTMIP_MASTER_ENABLE(inst)) + utmip_phy_disable_pmc_bus_ctrl(phy); } + utmi_phy_enable_obs_bus(phy); } @@ -1669,7 +1695,9 @@ static void utmi_phy_restore_end(struct tegra_usb_phy *phy) val = readl(base + USB_PORTSC); udelay(1); if (wait_time_us == 0) { - PHY_DBG("%s PMC REMOTE WAKEUP FPR timeout val = 0x%x instance = %d\n", __func__, val, phy->inst); + PHY_DBG("%s PMC REMOTE WAKEUP FPR timeout" + "val = 0x%lx instance = %d\n", + __func__, val, phy->inst); utmip_phy_disable_pmc_bus_ctrl(phy); utmi_phy_post_resume(phy); return; @@ -1810,6 +1838,31 @@ static void uhsic_powerup_pmc_wake_detect(struct tegra_usb_phy *phy) mdelay(1); } +static void uhsic_powerdown_pmc_wake_detect(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); + + DBG("%s:%d\n", __func__, __LINE__); + + /* turn off pad detectors for HSIC*/ + val = readl(pmc_base + PMC_USB_AO); + val |= (HSIC_RESERVED_P0 | STROBE_VAL_PD_P0 | DATA_VAL_PD_P0); + writel(val, pmc_base + PMC_USB_AO); + + /* enable pull downs on HSIC PMC */ + val = UHSIC_STROBE_RPD_A | UHSIC_DATA_RPD_A | UHSIC_STROBE_RPD_B | + UHSIC_DATA_RPD_B | UHSIC_STROBE_RPD_C | UHSIC_DATA_RPD_C | + UHSIC_STROBE_RPD_D | UHSIC_DATA_RPD_D; + writel(val, pmc_base + PMC_SLEEPWALK_UHSIC); + + /* Turn over pad configuration to PMC */ + val = readl(pmc_base + PMC_SLEEP_CFG); + val &= ~UHSIC_WAKE_VAL_P0(~0); + val |= UHSIC_WAKE_VAL_P0(WAKE_VAL_NONE) | UHSIC_MASTER_ENABLE_P0; + writel(val, pmc_base + PMC_SLEEP_CFG); +} + static void uhsic_setup_pmc_wake_detect(struct tegra_usb_phy *phy) { unsigned long val; @@ -1844,6 +1897,30 @@ static void uhsic_setup_pmc_wake_detect(struct tegra_usb_phy *phy) val |= UHSIC_PWR; writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG); + /* Make sure nothing is happening on the line with respect to PMC */ + val = readl(pmc_base + PMC_UTMIP_UHSIC_FAKE); + val &= ~UHSIC_STROBE_VAL; + val &= ~UHSIC_DATA_VAL; + writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE); + + /* Clear walk enable */ + val = readl(pmc_base + PMC_SLEEPWALK_CFG); + val &= ~UHSIC_LINEVAL_WALK_EN; + writel(val, pmc_base + PMC_SLEEPWALK_CFG); + + /* Make sure wake value for line is none */ + val = readl(pmc_base + PMC_SLEEP_CFG); + val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY); + val |= UHSIC_WAKE_VAL(WAKE_VAL_NONE); + writel(val, pmc_base + PMC_SLEEP_CFG); + + /* turn on pad detectors */ + val = readl(pmc_base + PMC_USB_AO); + val &= ~(STROBE_VAL_PD_P0 | DATA_VAL_PD_P0); + writel(val, pmc_base + PMC_USB_AO); + + /* Add small delay before usb detectors provide stable line values */ + udelay(1); /* Enable which type of event can trigger a walk, * in this case usb_line_wake */ @@ -1860,19 +1937,16 @@ static void uhsic_setup_pmc_wake_detect(struct tegra_usb_phy *phy) val |= UHSIC_DATA_RPD_A; val &= ~UHSIC_STROBE_RPD_A; val |= UHSIC_STROBE_RPU_A; - writel(val, pmc_base + PMC_SLEEPWALK_UHSIC); val &= ~UHSIC_DATA_RPD_B; val |= UHSIC_DATA_RPU_B; val &= ~UHSIC_STROBE_RPU_B; val |= UHSIC_STROBE_RPD_B; - writel(val, pmc_base + PMC_SLEEPWALK_UHSIC); val &= ~UHSIC_DATA_RPD_C; val |= UHSIC_DATA_RPU_C; val &= ~UHSIC_STROBE_RPU_C; val |= UHSIC_STROBE_RPD_C; - writel(val, pmc_base + PMC_SLEEPWALK_UHSIC); val &= ~UHSIC_DATA_RPD_D; val |= UHSIC_DATA_RPU_D; @@ -1880,19 +1954,21 @@ static void uhsic_setup_pmc_wake_detect(struct tegra_usb_phy *phy) val |= UHSIC_STROBE_RPD_D; writel(val, pmc_base + PMC_SLEEPWALK_UHSIC); - /* turn on pad detectors */ - val = readl(pmc_base + PMC_USB_AO); - val &= ~(STROBE_VAL_PD_P0 | DATA_VAL_PD_P0); - writel(val, pmc_base + PMC_USB_AO); - /* Add small delay before usb detectors provide stable line values */ - udelay(1); - phy->remote_wakeup = false; - /* Turn over pad configuration to PMC for line wake events*/ + /* Setting Wake event*/ val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~UHSIC_WAKE_VAL(~0); + val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY); val |= UHSIC_WAKE_VAL(WAKE_VAL_SD10); + writel(val, pmc_base + PMC_SLEEP_CFG); + + /* Clear the walk pointers and wake alarm */ + val = readl(pmc_base + PMC_TRIGGERS); + val |= UHSIC_CLR_WAKE_ALARM_P0 | UHSIC_CLR_WALK_PTR_P0; + writel(val, pmc_base + PMC_TRIGGERS); + + /* Turn over pad configuration to PMC for line wake events*/ + val = readl(pmc_base + PMC_SLEEP_CFG); val |= UHSIC_MASTER_ENABLE; writel(val, pmc_base + PMC_SLEEP_CFG); @@ -1911,14 +1987,10 @@ static void uhsic_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy) DBG("%s (%d)\n", __func__, __LINE__); val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~UHSIC_WAKE_VAL(0x0); + val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY); val |= UHSIC_WAKE_VAL(WAKE_VAL_NONE); writel(val, pmc_base + PMC_SLEEP_CFG); - val = readl(pmc_base + PMC_TRIGGERS); - val |= UHSIC_CLR_WAKE_ALARM_P0 | UHSIC_CLR_WALK_PTR_P0; - writel(val, pmc_base + PMC_TRIGGERS); - val = readl(base + UHSIC_PMC_WAKEUP0); val &= ~EVENT_INT_ENB; writel(val, base + UHSIC_PMC_WAKEUP0); @@ -1933,6 +2005,10 @@ static void uhsic_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy) val |= (STROBE_VAL_PD_P0 | DATA_VAL_PD_P0); writel(val, pmc_base + PMC_USB_AO); + val = readl(pmc_base + PMC_TRIGGERS); + val |= (UHSIC_CLR_WALK_PTR_P0 | UHSIC_CLR_WAKE_ALARM_P0); + writel(val, pmc_base + PMC_TRIGGERS); + phy->remote_wakeup = false; } @@ -1947,12 +2023,12 @@ static bool uhsic_phy_remotewake_detected(struct tegra_usb_phy *phy) val = readl(pmc_base + UTMIP_UHSIC_STATUS); if (UHSIC_WAKE_ALARM & val) { val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~UHSIC_WAKE_VAL(0x0); + val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY); val |= UHSIC_WAKE_VAL(WAKE_VAL_NONE); writel(val, pmc_base + PMC_SLEEP_CFG); val = readl(pmc_base + PMC_TRIGGERS); - val |= UHSIC_CLR_WAKE_ALARM_P0 | UHSIC_CLR_WALK_PTR_P0; + val |= UHSIC_CLR_WAKE_ALARM_P0; writel(val, pmc_base + PMC_TRIGGERS); val = readl(base + UHSIC_PMC_WAKEUP0); @@ -2003,14 +2079,10 @@ static void uhsic_phy_restore_start(struct tegra_usb_phy *phy) if (UHSIC_WALK_PTR_VAL & val) { phy->remote_wakeup = true; } else { - if (!((UHSIC_STROBE_VAL_P0 | UHSIC_DATA_VAL_P0) & val)) { - uhsic_phy_disable_pmc_bus_ctrl(phy); - } else { - DBG("%s(%d): setting pretend connect\n", __func__, __LINE__); - val = readl(base + UHSIC_CMD_CFG0); - val |= UHSIC_PRETEND_CONNECT_DETECT; - writel(val, base + UHSIC_CMD_CFG0); - } + DBG("%s(%d): setting pretend connect\n", __func__, __LINE__); + val = readl(base + UHSIC_CMD_CFG0); + val |= UHSIC_PRETEND_CONNECT_DETECT; + writel(val, base + UHSIC_CMD_CFG0); } } @@ -2019,7 +2091,7 @@ static void uhsic_phy_restore_end(struct tegra_usb_phy *phy) unsigned long val; void __iomem *base = phy->regs; - int wait_time_us = 3000; /* FPR should be set by this time */ + int wait_time_us = 25000; /* FPR should be set by this time */ DBG("%s(%d)\n", __func__, __LINE__); @@ -2035,9 +2107,8 @@ static void uhsic_phy_restore_end(struct tegra_usb_phy *phy) return; } wait_time_us--; - } while (!(val & USB_PORTSC_RESUME)); - /* wait for 25 ms to port resume complete */ - msleep(25); + } while (val & (USB_PORTSC_RESUME | USB_PORTSC_SUSP)); + /* disable PMC master control */ uhsic_phy_disable_pmc_bus_ctrl(phy); @@ -2050,25 +2121,73 @@ static void uhsic_phy_restore_end(struct tegra_usb_phy *phy) pr_warn("%s: timeout waiting for SOF\n", __func__); } uhsic_phy_post_resume(phy); + + /* Set RUN bit */ + val = readl(base + USB_USBCMD); + val |= USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS, + USB_USBCMD_RS, 2000)) { + pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__); + return; + } } else { uhsic_phy_disable_pmc_bus_ctrl(phy); } +} - /* Set RUN bit */ - val = readl(base + USB_USBCMD); - val |= USB_USBCMD_RS; - writel(val, base + USB_USBCMD); - if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS, - USB_USBCMD_RS, 2000)) { - pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__); - return; +static int hsic_rail_enable(struct tegra_usb_phy *phy) +{ + int ret; + + if (phy->hsic_reg == NULL) { + phy->hsic_reg = regulator_get(NULL, "avdd_hsic"); + if (IS_ERR_OR_NULL(phy->hsic_reg)) { + pr_err("HSIC: Could not get regulator avdd_hsic\n"); + phy->hsic_reg = NULL; + return PTR_ERR(phy->hsic_reg); + } } + + ret = regulator_enable(phy->hsic_reg); + if (ret < 0) { + pr_err("%s avdd_hsic could not be enabled\n", __func__); + return ret; + } + + return 0; +} + +static int hsic_rail_disable(struct tegra_usb_phy *phy) +{ + int ret; + + if (phy->hsic_reg == NULL) { + pr_warn("%s: unbalanced disable\n", __func__); + return -EIO; + } + + ret = regulator_disable(phy->hsic_reg); + if (ret < 0) { + pr_err("HSIC regulator avdd_hsic cannot be disabled\n"); + return ret; + } + + return 0; } static int uhsic_phy_open(struct tegra_usb_phy *phy) { unsigned long parent_rate; int i; + int ret; + + phy->hsic_reg = NULL; + ret = hsic_rail_enable(phy); + if (ret < 0) { + pr_err("%s avdd_hsic could not be enabled\n", __func__); + return ret; + } DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk)); @@ -2088,6 +2207,18 @@ static int uhsic_phy_open(struct tegra_usb_phy *phy) return 0; } +static void uhsic_phy_close(struct tegra_usb_phy *phy) +{ + int ret; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + uhsic_powerdown_pmc_wake_detect(phy); + + ret = hsic_rail_disable(phy); + if (ret < 0) + pr_err("%s avdd_hsic could not be disabled\n", __func__); +} + static int uhsic_phy_irq(struct tegra_usb_phy *phy) { usb_phy_fence_read(phy); @@ -2101,7 +2232,6 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy) { unsigned long val; void __iomem *base = phy->regs; - struct tegra_hsic_config *config = &phy->pdata->u_cfg.hsic; DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); @@ -2127,13 +2257,13 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy) writel(val, base + USB_SUSP_CTRL); val = readl(base + UHSIC_HSRX_CFG0); - val |= UHSIC_IDLE_WAIT(config->idle_wait_delay); - val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(config->elastic_underrun_limit); - val |= UHSIC_ELASTIC_OVERRUN_LIMIT(config->elastic_overrun_limit); + val |= UHSIC_IDLE_WAIT(HSIC_IDLE_WAIT_DELAY); + val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(HSIC_ELASTIC_UNDERRUN_LIMIT); + val |= UHSIC_ELASTIC_OVERRUN_LIMIT(HSIC_ELASTIC_OVERRUN_LIMIT); writel(val, base + UHSIC_HSRX_CFG0); val = readl(base + UHSIC_HSRX_CFG1); - val |= UHSIC_HS_SYNC_START_DLY(config->sync_start_delay); + val |= UHSIC_HS_SYNC_START_DLY(HSIC_SYNC_START_DELAY); writel(val, base + UHSIC_HSRX_CFG1); /* WAR HSIC TX */ @@ -2173,8 +2303,6 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy) val = readl(base + HOSTPC1_DEVLC); val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK); val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC); - val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK); - val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED); val &= ~HOSTPC1_DEVLC_STS; writel(val, base + HOSTPC1_DEVLC); @@ -2203,6 +2331,15 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy) phy->phy_clk_on = true; phy->hw_accessible = true; + if (phy->pmc_sleepwalk) { + DBG("%s(%d) inst:[%d] restore phy\n", __func__, __LINE__, + phy->inst); + uhsic_phy_restore_start(phy); + usb_phy_bringup_host_controller(phy); + uhsic_phy_restore_end(phy); + phy->pmc_sleepwalk = false; + } + return 0; } @@ -2224,12 +2361,20 @@ static int uhsic_phy_power_off(struct tegra_usb_phy *phy) /* Disable interrupts */ writel(0, base + USB_USBINTR); - uhsic_setup_pmc_wake_detect(phy); + if (phy->pmc_sleepwalk == false) { + uhsic_setup_pmc_wake_detect(phy); + phy->pmc_sleepwalk = true; + } val = readl(base + HOSTPC1_DEVLC); val |= HOSTPC1_DEVLC_PHCD; writel(val, base + HOSTPC1_DEVLC); + /* Remove power downs for HSIC from PADS CFG1 register */ + val = readl(base + UHSIC_PADS_CFG1); + val |= (UHSIC_PD_BG |UHSIC_PD_TRK | UHSIC_PD_RX | + UHSIC_PD_ZI | UHSIC_PD_TX); + writel(val, base + UHSIC_PADS_CFG1); phy->phy_clk_on = false; phy->hw_accessible = false; @@ -2251,8 +2396,6 @@ int uhsic_phy_bus_port_power(struct tegra_usb_phy *phy) val = readl(base + HOSTPC1_DEVLC); val &= ~(HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK)); val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC); - val &= ~(HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK)); - val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED); writel(val, base + HOSTPC1_DEVLC); val = readl(base + UHSIC_MISC_CFG0); @@ -2292,8 +2435,6 @@ static int uhsic_phy_bus_reset(struct tegra_usb_phy *phy) val = readl(base + HOSTPC1_DEVLC); val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK); val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC); - val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK); - val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED); val &= ~HOSTPC1_DEVLC_STS; writel(val, base + HOSTPC1_DEVLC); /* wait here, otherwise HOSTPC1_DEVLC_PSPD will timeout */ @@ -2373,10 +2514,6 @@ int uhsic_phy_resume(struct tegra_usb_phy *phy) { DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); - uhsic_phy_restore_start(phy); - usb_phy_bringup_host_controller(phy); - uhsic_phy_restore_end(phy); - return 0; } @@ -2528,6 +2665,9 @@ static void ulpi_null_phy_close(struct tegra_usb_phy *phy) static int ulpi_null_phy_power_off(struct tegra_usb_phy *phy) { + unsigned int val; + void __iomem *base = phy->regs; + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); if (!phy->phy_clk_on) { @@ -2539,6 +2679,9 @@ static int ulpi_null_phy_power_off(struct tegra_usb_phy *phy) phy->phy_clk_on = false; phy->hw_accessible = false; ulpi_null_phy_set_tristate(true); + val = readl(base + ULPIS2S_CTRL); + val &= ~ULPIS2S_PLLU_MASTER_BLASTER60; + writel(val, base + ULPIS2S_CTRL); return 0; } @@ -2563,7 +2706,16 @@ static int ulpi_null_phy_init(struct tegra_usb_phy *phy) static int ulpi_null_phy_irq(struct tegra_usb_phy *phy) { + unsigned long val; + void __iomem *base = phy->regs; + usb_phy_fence_read(phy); + if (phy->bus_reseting){ + val = readl(base + USB_USBCMD); + val |= USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + phy->bus_reseting = false; + } return IRQ_HANDLED; } @@ -2589,6 +2741,23 @@ static int ulpi_null_phy_cmd_reset(struct tegra_usb_phy *phy) return 0; } +static int ulpi_phy_bus_reset(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + /*DISABLE RUN BIT */ + + val = readl(base + USB_USBCMD); + val &= ~USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + phy->bus_reseting = true; + + return 0; +} + static int ulpi_null_phy_restore(struct tegra_usb_phy *phy) { struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi; @@ -2761,6 +2930,7 @@ static int ulpi_null_phy_power_on(struct tegra_usb_phy *phy) } udelay(10); + phy->bus_reseting = false; phy->phy_clk_on = true; phy->hw_accessible = true; @@ -2823,6 +2993,7 @@ static struct tegra_usb_phy_ops utmi_phy_ops = { static struct tegra_usb_phy_ops uhsic_phy_ops = { .open = uhsic_phy_open, + .close = uhsic_phy_close, .irq = uhsic_phy_irq, .power_on = uhsic_phy_power_on, .power_off = uhsic_phy_power_off, @@ -2844,6 +3015,7 @@ static struct tegra_usb_phy_ops ulpi_null_phy_ops = { .resume = ulpi_null_phy_resume, .post_resume = ulpi_null_phy_post_resume, .reset = ulpi_null_phy_cmd_reset, + .bus_reset = ulpi_phy_bus_reset, }; static struct tegra_usb_phy_ops ulpi_link_phy_ops; |