Loading drivers/usb/phy/phy-msm-usb.c +64 −18 Original line number Original line Diff line number Diff line Loading @@ -1191,9 +1191,12 @@ static irqreturn_t msm_otg_phy_irq_handler(int irq, void *data) return IRQ_HANDLED; return IRQ_HANDLED; } } #define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000) #define PHY_SUSPEND_TIMEOUT_USEC (5 * 1000) #define PHY_DEVICE_BUS_SUSPEND_TIMEOUT_USEC 100 #define PHY_RESUME_TIMEOUT_USEC (100 * 1000) #define PHY_RESUME_TIMEOUT_USEC (100 * 1000) #define PHY_SUSPEND_RETRIES_MAX 3 #ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP static int msm_otg_suspend(struct msm_otg *motg) static int msm_otg_suspend(struct msm_otg *motg) { { Loading @@ -1206,9 +1209,9 @@ static int msm_otg_suspend(struct msm_otg *motg) u32 cmd_val; u32 cmd_val; u32 portsc, config2; u32 portsc, config2; u32 func_ctrl; u32 func_ctrl; int phcd_retry_cnt = 0; int phcd_retry_cnt = 0, ret; unsigned phy_suspend_timeout; phcd_retry: cnt = 0; cnt = 0; if (atomic_read(&motg->in_lpm)) if (atomic_read(&motg->in_lpm)) Loading @@ -1226,6 +1229,7 @@ phcd_retry: motg->ui_enabled = 0; motg->ui_enabled = 0; disable_irq(motg->irq); disable_irq(motg->irq); lpm_start: host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host && host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host && !test_bit(ID, &motg->inputs); !test_bit(ID, &motg->inputs); device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) && device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) && Loading Loading @@ -1277,16 +1281,39 @@ phcd_retry: ULPI_CLR(ULPI_IFC_CTRL)); ULPI_CLR(ULPI_IFC_CTRL)); } } /* Set the PHCD bit, only if it is not set by the controller. /* * PHY may take some time or even fail to enter into low power * PHY suspend sequence as mentioned in the databook. * mode (LPM). Hence poll for 500 msec and reset the PHY and link * * in failure case. * Device bus suspend: The controller may abort PHY suspend if * there is an incoming reset or resume from the host. If PHCD * is not set within 100 usec. Abort the LPM sequence. * * Host bus suspend: If the peripheral is attached, PHY is already * put into suspend along with the peripheral bus suspend. poll for * PHCD upto 5 msec. If the peripheral is not attached i.e entering * LPM with Micro-A cable, set the PHCD and poll for it for 5 msec. * * No cable connected: Set the PHCD to suspend the PHY. Poll for PHCD * upto 5 msec. * * The controller aborts PHY suspend only in device bus suspend case. * In other cases, it is observed that PHCD may not get set within * the timeout. If so, set the PHCD again and poll for it before * reset recovery. */ */ phcd_retry: if (device_bus_suspend) phy_suspend_timeout = PHY_DEVICE_BUS_SUSPEND_TIMEOUT_USEC; else phy_suspend_timeout = PHY_SUSPEND_TIMEOUT_USEC; cnt = 0; portsc = readl_relaxed(USB_PORTSC); portsc = readl_relaxed(USB_PORTSC); if (!(portsc & PORTSC_PHCD)) { if (!(portsc & PORTSC_PHCD)) { writel_relaxed(portsc | PORTSC_PHCD, writel_relaxed(portsc | PORTSC_PHCD, USB_PORTSC); USB_PORTSC); while (cnt < PHY_SUSPEND_TIMEOUT_USEC) { while (cnt < phy_suspend_timeout) { if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD) if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD) break; break; udelay(1); udelay(1); Loading @@ -1294,16 +1321,29 @@ phcd_retry: } } } } if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) { if (cnt >= phy_suspend_timeout) { dev_err(phy->dev, "Unable to suspend PHY\n"); if (phcd_retry_cnt > PHY_SUSPEND_RETRIES_MAX) { dev_err(phy->dev, "PHY suspend failed\n"); ret = -EBUSY; goto phy_suspend_fail; } if (device_bus_suspend) { dev_dbg(phy->dev, "PHY suspend aborted\n"); ret = -EBUSY; goto phy_suspend_fail; } else { if (phcd_retry_cnt++ < PHY_SUSPEND_RETRIES_MAX) { dev_dbg(phy->dev, "PHY suspend retry\n"); goto phcd_retry; } else { dev_err(phy->dev, "reset attempt during PHY suspend\n"); phcd_retry_cnt++; motg->reset_counter = 0; motg->reset_counter = 0; msm_otg_reset(phy); msm_otg_reset(phy); motg->ui_enabled = 1; goto lpm_start; enable_irq(motg->irq); } if (phcd_retry_cnt++ < 3) } goto phcd_retry; else return -EBUSY; } } /* /* Loading Loading @@ -1484,6 +1524,11 @@ phcd_retry: dev_info(phy->dev, "USB in low power mode\n"); dev_info(phy->dev, "USB in low power mode\n"); return 0; return 0; phy_suspend_fail: motg->ui_enabled = 1; enable_irq(motg->irq); return ret; } } static int msm_otg_resume(struct msm_otg *motg) static int msm_otg_resume(struct msm_otg *motg) Loading Loading @@ -3258,6 +3303,7 @@ static void msm_otg_sm_work(struct work_struct *w) if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) { if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) { pm_runtime_put_noidle(otg->phy->dev); pm_runtime_put_noidle(otg->phy->dev); pm_runtime_suspend(otg->phy->dev); pm_runtime_suspend(otg->phy->dev); motg->pm_done = 1; } } } else if (test_bit(ID_C, &motg->inputs)) { } else if (test_bit(ID_C, &motg->inputs)) { msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX); msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX); Loading Loading
drivers/usb/phy/phy-msm-usb.c +64 −18 Original line number Original line Diff line number Diff line Loading @@ -1191,9 +1191,12 @@ static irqreturn_t msm_otg_phy_irq_handler(int irq, void *data) return IRQ_HANDLED; return IRQ_HANDLED; } } #define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000) #define PHY_SUSPEND_TIMEOUT_USEC (5 * 1000) #define PHY_DEVICE_BUS_SUSPEND_TIMEOUT_USEC 100 #define PHY_RESUME_TIMEOUT_USEC (100 * 1000) #define PHY_RESUME_TIMEOUT_USEC (100 * 1000) #define PHY_SUSPEND_RETRIES_MAX 3 #ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP static int msm_otg_suspend(struct msm_otg *motg) static int msm_otg_suspend(struct msm_otg *motg) { { Loading @@ -1206,9 +1209,9 @@ static int msm_otg_suspend(struct msm_otg *motg) u32 cmd_val; u32 cmd_val; u32 portsc, config2; u32 portsc, config2; u32 func_ctrl; u32 func_ctrl; int phcd_retry_cnt = 0; int phcd_retry_cnt = 0, ret; unsigned phy_suspend_timeout; phcd_retry: cnt = 0; cnt = 0; if (atomic_read(&motg->in_lpm)) if (atomic_read(&motg->in_lpm)) Loading @@ -1226,6 +1229,7 @@ phcd_retry: motg->ui_enabled = 0; motg->ui_enabled = 0; disable_irq(motg->irq); disable_irq(motg->irq); lpm_start: host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host && host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host && !test_bit(ID, &motg->inputs); !test_bit(ID, &motg->inputs); device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) && device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) && Loading Loading @@ -1277,16 +1281,39 @@ phcd_retry: ULPI_CLR(ULPI_IFC_CTRL)); ULPI_CLR(ULPI_IFC_CTRL)); } } /* Set the PHCD bit, only if it is not set by the controller. /* * PHY may take some time or even fail to enter into low power * PHY suspend sequence as mentioned in the databook. * mode (LPM). Hence poll for 500 msec and reset the PHY and link * * in failure case. * Device bus suspend: The controller may abort PHY suspend if * there is an incoming reset or resume from the host. If PHCD * is not set within 100 usec. Abort the LPM sequence. * * Host bus suspend: If the peripheral is attached, PHY is already * put into suspend along with the peripheral bus suspend. poll for * PHCD upto 5 msec. If the peripheral is not attached i.e entering * LPM with Micro-A cable, set the PHCD and poll for it for 5 msec. * * No cable connected: Set the PHCD to suspend the PHY. Poll for PHCD * upto 5 msec. * * The controller aborts PHY suspend only in device bus suspend case. * In other cases, it is observed that PHCD may not get set within * the timeout. If so, set the PHCD again and poll for it before * reset recovery. */ */ phcd_retry: if (device_bus_suspend) phy_suspend_timeout = PHY_DEVICE_BUS_SUSPEND_TIMEOUT_USEC; else phy_suspend_timeout = PHY_SUSPEND_TIMEOUT_USEC; cnt = 0; portsc = readl_relaxed(USB_PORTSC); portsc = readl_relaxed(USB_PORTSC); if (!(portsc & PORTSC_PHCD)) { if (!(portsc & PORTSC_PHCD)) { writel_relaxed(portsc | PORTSC_PHCD, writel_relaxed(portsc | PORTSC_PHCD, USB_PORTSC); USB_PORTSC); while (cnt < PHY_SUSPEND_TIMEOUT_USEC) { while (cnt < phy_suspend_timeout) { if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD) if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD) break; break; udelay(1); udelay(1); Loading @@ -1294,16 +1321,29 @@ phcd_retry: } } } } if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) { if (cnt >= phy_suspend_timeout) { dev_err(phy->dev, "Unable to suspend PHY\n"); if (phcd_retry_cnt > PHY_SUSPEND_RETRIES_MAX) { dev_err(phy->dev, "PHY suspend failed\n"); ret = -EBUSY; goto phy_suspend_fail; } if (device_bus_suspend) { dev_dbg(phy->dev, "PHY suspend aborted\n"); ret = -EBUSY; goto phy_suspend_fail; } else { if (phcd_retry_cnt++ < PHY_SUSPEND_RETRIES_MAX) { dev_dbg(phy->dev, "PHY suspend retry\n"); goto phcd_retry; } else { dev_err(phy->dev, "reset attempt during PHY suspend\n"); phcd_retry_cnt++; motg->reset_counter = 0; motg->reset_counter = 0; msm_otg_reset(phy); msm_otg_reset(phy); motg->ui_enabled = 1; goto lpm_start; enable_irq(motg->irq); } if (phcd_retry_cnt++ < 3) } goto phcd_retry; else return -EBUSY; } } /* /* Loading Loading @@ -1484,6 +1524,11 @@ phcd_retry: dev_info(phy->dev, "USB in low power mode\n"); dev_info(phy->dev, "USB in low power mode\n"); return 0; return 0; phy_suspend_fail: motg->ui_enabled = 1; enable_irq(motg->irq); return ret; } } static int msm_otg_resume(struct msm_otg *motg) static int msm_otg_resume(struct msm_otg *motg) Loading Loading @@ -3258,6 +3303,7 @@ static void msm_otg_sm_work(struct work_struct *w) if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) { if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) { pm_runtime_put_noidle(otg->phy->dev); pm_runtime_put_noidle(otg->phy->dev); pm_runtime_suspend(otg->phy->dev); pm_runtime_suspend(otg->phy->dev); motg->pm_done = 1; } } } else if (test_bit(ID_C, &motg->inputs)) { } else if (test_bit(ID_C, &motg->inputs)) { msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX); msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX); Loading