From 1bc26ade8ade41d293702be3bc2267b318d74160 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Tue, 11 Sep 2018 12:11:48 +0530 Subject: [PATCH] usb: dwc3: Add support for PM suspend and hibernation in host mode DWC3 driver uses wakeup_source and allows pm_suspend only after entering low power mode as part of runtime suspend. This prevents PM suspend in host mode if connected device's driver doesn't support runtime or selective suspend. For platforms such as automotive, add support in driver where user can specify using dtsi attribute to not use wakeup source in host mode. It will allow system to enter deep sleep or pm_suspend irrespective of runtime PM state of XHCI. The connected devices are also reset-resumed on PM resume. On high level below are the changes in default behavior: -Do not use wakeup_source for DWC3 when operating in host mode. -For host mode, devices will suspend upon PM suspend and reset-resumed on PM resume. Change-Id: I8a3d744a1d9d714f17a0cfe4ff5b69b04d9f763f Signed-off-by: Ajay Agarwal Signed-off-by: Jack Pham --- drivers/usb/dwc3/core.c | 13 ++++++++++++- drivers/usb/dwc3/core.h | 6 ++++++ drivers/usb/dwc3/host.c | 5 ++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index c2c71532d358..f9a1103c7ff2 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1949,8 +1949,18 @@ static int dwc3_resume(struct device *dev) int ret; /* Check if platform glue driver handling PM, if not then handle here */ - if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0)) + if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0)) { + /* + * If the core was in host mode during suspend, then set the + * runtime PM 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 && + dwc->host_poweroff_in_pm_suspend) + goto runtime_set_active; + return 0; + } pinctrl_pm_select_default_state(dev); @@ -1958,6 +1968,7 @@ static int dwc3_resume(struct device *dev) if (ret) return ret; +runtime_set_active: pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index e709da4cc67b..c08682fc63d1 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1345,6 +1345,12 @@ struct dwc3 { unsigned int vbus_active:1; /* 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. + */ + bool host_poweroff_in_pm_suspend; }; #define INCRX_BURST_MODE 0 diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index f748cd49abbf..70732c21ca4c 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -43,7 +43,7 @@ out: int dwc3_host_init(struct dwc3 *dwc) { - struct property_entry props[5]; + struct property_entry props[6]; struct platform_device *xhci; int ret, irq; struct resource *res; @@ -115,6 +115,9 @@ int dwc3_host_init(struct dwc3 *dwc) if (dwc->revision <= DWC3_REVISION_300A) props[prop_idx++].name = "quirk-broken-port-ped"; + if (dwc->host_poweroff_in_pm_suspend) + props[prop_idx++].name = "host-poweroff-in-pm-suspend"; + if (prop_idx) { ret = platform_device_add_properties(xhci, props); if (ret) {