diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2018-06-04 13:49:04 -0700 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2018-06-04 13:49:04 -0700 |
| commit | 9e635002691bf62690f22529c5ecc059408664b4 (patch) | |
| tree | bf02e18562668d540356417c15edfeeee1a4238e | |
| parent | 5ae645ca395cea144eb07445e304dcfe9769bd2e (diff) | |
| parent | 6c16439a24013225ad0ce2e433954021c353bdc0 (diff) | |
Merge "usb: core: Resume the devices on pm restore"
| -rw-r--r-- | drivers/usb/core/driver.c | 5 | ||||
| -rw-r--r-- | drivers/usb/dwc3/core.c | 20 | ||||
| -rw-r--r-- | drivers/usb/dwc3/dwc3-msm.c | 100 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-plat.c | 39 |
4 files changed, 145 insertions, 19 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ee33c0d796b5..55322469084d 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1495,9 +1495,10 @@ int usb_resume(struct device *dev, pm_message_t msg) * Some buses would like to keep their devices in suspend * state after system resume. Their resume happen when * a remote wakeup is detected or interface driver start - * I/O. + * I/O. And in the case when the system is restoring from + * hibernation, make sure all the devices are resumed. */ - if (udev->bus->skip_resume) + if (udev->bus->skip_resume && msg.event != PM_EVENT_RESTORE) return 0; /* For all calls, take the device back to full power and diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 0744b14e120b..3191825710af 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1435,8 +1435,26 @@ err_usb2phy_init: return ret; } +static int dwc3_pm_restore(struct device *dev) +{ + /* + * Set the core as runtime active to prevent the runtime + * PM ops being called before the PM restore is completed. + */ + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; +} + static const struct dev_pm_ops dwc3_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume) + .suspend = dwc3_suspend, + .resume = dwc3_resume, + .freeze = dwc3_suspend, + .thaw = dwc3_pm_restore, + .poweroff = dwc3_suspend, + .restore = dwc3_pm_restore, }; #define DWC3_PM_OPS &(dwc3_dev_pm_ops) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 3f59a2f8b84f..f94d0ba2f966 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -1908,6 +1908,18 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc) dwc3_core_init(dwc); /* Re-configure event buffers */ dwc3_event_buffers_setup(dwc); + + /* Get initial P3 status and enable IN_P3 event */ + val = dwc3_msm_read_reg_field(mdwc->base, + DWC3_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK); + atomic_set(&mdwc->in_p3, val == DWC3_LINK_STATE_U3); + dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, + PWR_EVNT_POWERDOWN_IN_P3_MASK, 1); + if (mdwc->otg_state == OTG_STATE_A_HOST) { + dev_dbg(mdwc->dev, "%s: set the core in host mode\n", + __func__); + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); + } } static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc) @@ -1993,7 +2005,7 @@ static void dwc3_set_phy_speed_flags(struct dwc3_msm *mdwc) static void msm_dwc3_perf_vote_update(struct dwc3_msm *mdwc, bool perf_mode); -static int dwc3_msm_suspend(struct dwc3_msm *mdwc) +static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation) { int ret, i; struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); @@ -2115,7 +2127,8 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) clk_disable_unprepare(mdwc->xo_clk); /* Perform controller power collapse */ - if (!mdwc->in_host_mode && (!mdwc->vbus_active || mdwc->in_restart)) { + if ((!mdwc->in_host_mode && (!mdwc->vbus_active || mdwc->in_restart)) || + hibernation) { mdwc->lpm_flags |= MDWC3_POWER_COLLAPSE; dev_dbg(mdwc->dev, "%s: power collapse\n", __func__); dwc3_msm_config_gdsc(mdwc, 0); @@ -2254,19 +2267,10 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) /* Recover from controller power collapse */ if (mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) { - u32 tmp; - dev_dbg(mdwc->dev, "%s: exit power collapse\n", __func__); dwc3_msm_power_collapse_por(mdwc); - /* Get initial P3 status and enable IN_P3 event */ - tmp = dwc3_msm_read_reg_field(mdwc->base, - DWC3_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK); - atomic_set(&mdwc->in_p3, tmp == DWC3_LINK_STATE_U3); - dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, - PWR_EVNT_POWERDOWN_IN_P3_MASK, 1); - mdwc->lpm_flags &= ~MDWC3_POWER_COLLAPSE; } @@ -4014,7 +4018,39 @@ static int dwc3_msm_pm_suspend(struct device *dev) return -EBUSY; } - ret = dwc3_msm_suspend(mdwc); + ret = dwc3_msm_suspend(mdwc, false); + if (!ret) + atomic_set(&mdwc->pm_suspended, 1); + + return ret; +} + +static int dwc3_msm_pm_freeze(struct device *dev) +{ + int ret = 0; + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + + dev_dbg(dev, "dwc3-msm PM freeze\n"); + dbg_event(0xFF, "PM Freeze", 0); + + flush_workqueue(mdwc->dwc3_wq); + + /* Resume the core to make sure we can power collapse it */ + ret = dwc3_msm_resume(mdwc); + + /* + * PHYs also need to be power collapsed, so call the notify_disconnect + * before suspend to ensure it. + */ + usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH); + if (mdwc->ss_phy->flags & PHY_HOST_MODE) { + usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER); + mdwc->ss_phy->flags &= ~PHY_HOST_MODE; + } + + mdwc->hs_phy->flags &= ~PHY_HOST_MODE; + + ret = dwc3_msm_suspend(mdwc, true); if (!ret) atomic_set(&mdwc->pm_suspended, 1); @@ -4043,6 +4079,35 @@ static int dwc3_msm_pm_resume(struct device *dev) return 0; } + +static int dwc3_msm_pm_restore(struct device *dev) +{ + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + + dev_dbg(dev, "dwc3-msm PM restore\n"); + dbg_event(0xFF, "PM Restore", 0); + + atomic_set(&mdwc->pm_suspended, 0); + + dwc3_msm_resume(mdwc); + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + /* Restore PHY flags if hibernated in host mode */ + if (mdwc->otg_state == OTG_STATE_A_HOST) { + mdwc->hs_phy->flags |= PHY_HOST_MODE; + if (mdwc->ss_phy) { + mdwc->ss_phy->flags |= PHY_HOST_MODE; + usb_phy_notify_connect(mdwc->ss_phy, + USB_SPEED_SUPER); + } + + usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH); + } + + return 0; +} #endif #ifdef CONFIG_PM @@ -4061,7 +4126,7 @@ static int dwc3_msm_runtime_suspend(struct device *dev) dev_dbg(dev, "DWC3-msm runtime suspend\n"); dbg_event(0xFF, "RT Sus", 0); - return dwc3_msm_suspend(mdwc); + return dwc3_msm_suspend(mdwc, false); } static int dwc3_msm_runtime_resume(struct device *dev) @@ -4076,8 +4141,13 @@ static int dwc3_msm_runtime_resume(struct device *dev) #endif static const struct dev_pm_ops dwc3_msm_dev_pm_ops = { - .prepare = dwc3_msm_pm_prepare, - SET_SYSTEM_SLEEP_PM_OPS(dwc3_msm_pm_suspend, dwc3_msm_pm_resume) + .prepare = dwc3_msm_pm_prepare, + .suspend = dwc3_msm_pm_suspend, + .resume = dwc3_msm_pm_resume, + .freeze = dwc3_msm_pm_freeze, + .thaw = dwc3_msm_pm_restore, + .poweroff = dwc3_msm_pm_suspend, + .restore = dwc3_msm_pm_restore, SET_RUNTIME_PM_OPS(dwc3_msm_runtime_suspend, dwc3_msm_runtime_resume, dwc3_msm_runtime_idle) }; diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index b8ff368e4464..efe1924e0875 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -370,6 +370,39 @@ static int xhci_plat_runtime_idle(struct device *dev) return -EBUSY; } +static int xhci_plat_pm_freeze(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + if (!xhci) + return 0; + + dev_dbg(dev, "xhci-plat freeze\n"); + + return xhci_suspend(xhci, false); +} + +static int xhci_plat_pm_restore(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ret; + + if (!xhci) + return 0; + + dev_dbg(dev, "xhci-plat restore\n"); + + ret = xhci_resume(xhci, true); + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_mark_last_busy(dev); + + return ret; +} + static int xhci_plat_runtime_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); @@ -401,7 +434,11 @@ static int xhci_plat_runtime_resume(struct device *dev) } static const struct dev_pm_ops xhci_plat_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume) + .suspend = xhci_plat_suspend, + .resume = xhci_plat_resume, + .freeze = xhci_plat_pm_freeze, + .restore = xhci_plat_pm_restore, + .thaw = xhci_plat_pm_restore, SET_RUNTIME_PM_OPS(xhci_plat_runtime_suspend, xhci_plat_runtime_resume, xhci_plat_runtime_idle) }; |
