mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-08 12:58:12 -04:00
usb: host: Modify PM handling for USB interconnect platforms
Currently the PM handling power collapses the core and issues reset-resume for all the connected devices, both during system suspend-resume and hibernation-restore scenarios. But certain USB interconnect platforms want the connected device to not undergo reset-resume on system resume. Modify the operations to keep the core powered up, PHY resources ON and xhci_resume with hibernated flag as 'false' so that suspend-resume of the connected device is done on resume from system suspend. Keep the hibernation operation as is. Also change the DT flag to 'qcom,ignore-wakeup-src-in-hostmode'. Change-Id: I661494595a3e270890174e0952a67985db58706d Signed-off-by: Ajay Agarwal <ajaya@codeaurora.org> Signed-off-by: Harsh Agarwal <harshq@codeaurora.org>
This commit is contained in:
parent
28255001cf
commit
74b8a97e90
6 changed files with 157 additions and 44 deletions
|
|
@ -2005,7 +2005,8 @@ static int dwc3_resume(struct device *dev)
|
|||
* state as active to reflect actual state of device which
|
||||
* is now out of LPM. This allows runtime_suspend later.
|
||||
*/
|
||||
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)
|
||||
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST &&
|
||||
pm_runtime_status_suspended(dev))
|
||||
pm_runtime_resume(dev);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1387,11 +1387,13 @@ struct dwc3 {
|
|||
/* Indicate if software connect was issued by the usb_gadget_driver */
|
||||
unsigned int softconnect:1;
|
||||
/*
|
||||
* If true, PM suspend allowed irrespective of host runtimePM state
|
||||
* and core will power collapse. This also leads to reset-resume of
|
||||
* connected devices on PM resume.
|
||||
* If true, PM suspend/freeze allowed irrespective of host runtimePM
|
||||
* state. In PM suspend/resume case, core will stay powered and
|
||||
* connected devices will just be suspended/resumed.
|
||||
* In hibernation, core will power collapse and connected devices will
|
||||
* reset-resume on PM restore.
|
||||
*/
|
||||
bool host_poweroff_in_pm_suspend;
|
||||
bool ignore_wakeup_src_in_hostmode;
|
||||
int retries_on_error;
|
||||
u32 gen2_tx_de_emph;
|
||||
u32 gen2_tx_de_emph1;
|
||||
|
|
|
|||
|
|
@ -4446,6 +4446,12 @@ static int dwc3_msm_probe(struct platform_device *pdev)
|
|||
goto put_dwc3;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(node, "qcom,ignore-wakeup-src-in-hostmode")) {
|
||||
dwc->ignore_wakeup_src_in_hostmode = true;
|
||||
dev_dbg(mdwc->dev, "%s: Allow system suspend irrespective of runtime suspend\n",
|
||||
__func__);
|
||||
}
|
||||
|
||||
/*
|
||||
* On platforms with SS PHY that do not support ss_phy_irq for wakeup
|
||||
* events, use pwr_event_irq for wakeup events in superspeed mode.
|
||||
|
|
@ -4474,12 +4480,6 @@ static int dwc3_msm_probe(struct platform_device *pdev)
|
|||
mdwc->pm_qos_latency = 0;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(node, "qcom,host-poweroff-in-pm-suspend")) {
|
||||
dwc->host_poweroff_in_pm_suspend = true;
|
||||
dev_dbg(mdwc->dev, "%s: Core power collapse on host PM suspend\n",
|
||||
__func__);
|
||||
}
|
||||
|
||||
mutex_init(&mdwc->suspend_resume_mutex);
|
||||
|
||||
mdwc->ss_redriver_node = of_parse_phandle(node, "ssusb_redriver", 0);
|
||||
|
|
@ -5302,7 +5302,7 @@ static int dwc3_msm_pm_suspend(struct device *dev)
|
|||
* Check if pm_suspend can proceed irrespective of runtimePM state of
|
||||
* host.
|
||||
*/
|
||||
if (!dwc->host_poweroff_in_pm_suspend || !mdwc->in_host_mode) {
|
||||
if (!dwc->ignore_wakeup_src_in_hostmode || !mdwc->in_host_mode) {
|
||||
if (!atomic_read(&dwc->in_lpm)) {
|
||||
dev_err(mdwc->dev, "Abort PM suspend!! (USB is outside LPM)\n");
|
||||
return -EBUSY;
|
||||
|
|
@ -5313,6 +5313,66 @@ static int dwc3_msm_pm_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
ret = dwc3_msm_suspend(mdwc, false);
|
||||
if (!ret)
|
||||
atomic_set(&mdwc->pm_suspended, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_msm_pm_resume(struct device *dev)
|
||||
{
|
||||
struct dwc3_msm *mdwc = dev_get_drvdata(dev);
|
||||
struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
|
||||
|
||||
dev_dbg(dev, "dwc3-msm PM resume\n");
|
||||
dbg_event(0xFF, "PM Res", 0);
|
||||
|
||||
atomic_set(&mdwc->pm_suspended, 0);
|
||||
|
||||
if (!mdwc->in_host_mode) {
|
||||
/* kick in otg state machine */
|
||||
queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Resume dwc to avoid unclocked access by xhci_plat_resume */
|
||||
if (pm_runtime_status_suspended(dev))
|
||||
pm_runtime_resume(dev);
|
||||
else
|
||||
dwc3_msm_resume(mdwc);
|
||||
|
||||
/* kick in otg state machine */
|
||||
queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_msm_pm_freeze(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dwc3_msm *mdwc = dev_get_drvdata(dev);
|
||||
struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
|
||||
|
||||
dev_dbg(dev, "dwc3-msm PM freeze\n");
|
||||
dbg_event(0xFF, "PM Freeze", 0);
|
||||
|
||||
/*
|
||||
* Check if pm_freeze can proceed irrespective of runtimePM state of
|
||||
* host.
|
||||
*/
|
||||
if (!dwc->ignore_wakeup_src_in_hostmode || !mdwc->in_host_mode) {
|
||||
if (!atomic_read(&dwc->in_lpm)) {
|
||||
dev_err(mdwc->dev, "Abort PM freeze!! (USB is outside LPM)\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
atomic_set(&mdwc->pm_suspended, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* PHYs also need to be power collapsed, so call notify_disconnect
|
||||
* before suspend to ensure it.
|
||||
|
|
@ -5333,13 +5393,13 @@ static int dwc3_msm_pm_suspend(struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_msm_pm_resume(struct device *dev)
|
||||
static int dwc3_msm_pm_restore(struct device *dev)
|
||||
{
|
||||
struct dwc3_msm *mdwc = dev_get_drvdata(dev);
|
||||
struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
|
||||
|
||||
dev_dbg(dev, "dwc3-msm PM resume\n");
|
||||
dbg_event(0xFF, "PM Res", 0);
|
||||
dev_dbg(dev, "dwc3-msm PM restore\n");
|
||||
dbg_event(0xFF, "PM Restore", 0);
|
||||
|
||||
atomic_set(&mdwc->pm_suspended, 0);
|
||||
|
||||
|
|
@ -5352,9 +5412,6 @@ static int dwc3_msm_pm_resume(struct device *dev)
|
|||
|
||||
/* Resume dwc to avoid unclocked access by xhci_plat_resume */
|
||||
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 */
|
||||
mdwc->hs_phy->flags |= PHY_HOST_MODE;
|
||||
|
|
@ -5408,7 +5465,12 @@ static int dwc3_msm_runtime_resume(struct device *dev)
|
|||
#endif
|
||||
|
||||
static const struct dev_pm_ops dwc3_msm_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(dwc3_msm_pm_suspend, dwc3_msm_pm_resume)
|
||||
.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)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -115,9 +115,9 @@ int dwc3_host_init(struct dwc3 *dwc)
|
|||
if (dwc->revision <= DWC3_REVISION_300A)
|
||||
props[prop_idx++] = PROPERTY_ENTRY_BOOL("quirk-broken-port-ped");
|
||||
|
||||
if (dwc->host_poweroff_in_pm_suspend)
|
||||
if (dwc->ignore_wakeup_src_in_hostmode)
|
||||
props[prop_idx++] =
|
||||
PROPERTY_ENTRY_BOOL("host-poweroff-in-pm-suspend");
|
||||
PROPERTY_ENTRY_BOOL("ignore-wakeup-src-in-hostmode");
|
||||
|
||||
if (prop_idx) {
|
||||
ret = platform_device_add_properties(xhci, props);
|
||||
|
|
|
|||
|
|
@ -391,6 +391,67 @@ static int xhci_plat_remove(struct platform_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int xhci_plat_suspend(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 PM suspend\n");
|
||||
|
||||
/* Disable wakeup capability */
|
||||
return xhci_suspend(xhci, false);
|
||||
}
|
||||
|
||||
static int xhci_plat_resume(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 resume\n");
|
||||
|
||||
ret = xhci_priv_resume_quirk(hcd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pm_runtime_status_suspended(dev))
|
||||
ret = pm_runtime_resume(dev);
|
||||
else
|
||||
ret = xhci_resume(xhci, false);
|
||||
|
||||
if (ret)
|
||||
dev_err(dev, "failed to resume xhci-plat (%d)\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xhci_plat_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 PM restore\n");
|
||||
|
||||
ret = xhci_priv_resume_quirk(hcd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* resume from hibernation/power-collapse */
|
||||
ret = xhci_resume(xhci, true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused xhci_plat_runtime_idle(struct device *dev)
|
||||
{
|
||||
/*
|
||||
|
|
@ -421,28 +482,6 @@ static int __maybe_unused xhci_plat_runtime_suspend(struct device *dev)
|
|||
return xhci_suspend(xhci, true);
|
||||
}
|
||||
|
||||
static int xhci_plat_resume(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 resume\n");
|
||||
|
||||
ret = xhci_priv_resume_quirk(hcd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pm_runtime_resume(dev);
|
||||
if (ret)
|
||||
dev_err(dev, "failed to resume xhci-plat (%d)\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused xhci_plat_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
|
|
@ -465,8 +504,12 @@ static int __maybe_unused xhci_plat_runtime_resume(struct device *dev)
|
|||
}
|
||||
|
||||
static const struct dev_pm_ops xhci_plat_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(NULL, xhci_plat_resume)
|
||||
|
||||
.suspend = xhci_plat_suspend,
|
||||
.resume = xhci_plat_resume,
|
||||
.freeze = xhci_plat_suspend,
|
||||
.thaw = xhci_plat_restore,
|
||||
.poweroff = xhci_plat_suspend,
|
||||
.restore = xhci_plat_restore,
|
||||
SET_RUNTIME_PM_OPS(xhci_plat_runtime_suspend,
|
||||
xhci_plat_runtime_resume,
|
||||
xhci_plat_runtime_idle)
|
||||
|
|
|
|||
|
|
@ -1011,6 +1011,11 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
|
|||
xhci->shared_hcd->state != HC_STATE_SUSPENDED)
|
||||
return -EINVAL;
|
||||
|
||||
/* If XHCI is already suspended , then return */
|
||||
if ((!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) ||
|
||||
!test_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags)))
|
||||
return 0;
|
||||
|
||||
xhci_dbc_suspend(xhci);
|
||||
|
||||
/* Clear root port wake on bits if wakeup not allowed. */
|
||||
|
|
|
|||
Loading…
Reference in a new issue