Merge "usb: core: Resume the devices on pm restore"
This commit is contained in:
commit
9e63500269
4 changed files with 145 additions and 19 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue