usb: dwc3: core: Suspend PHYs on runtime suspend in host mode

Some PHY drivers (e.g. for Qualcomm QUSB2 and QMP PHYs) support
runtime PM to reduce PHY power consumption during bus_suspend.
Add changes to let core auto-suspend PHYs on host bus-suspend
using GUSB2PHYCFG register if needed for a platform. Also perform
PHYs runtime suspend/resume and let platform glue drivers e.g.
dwc3-qcom handle remote wakeup during bus suspend by waking up
devices on receiving wakeup event from PHY.

Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
This commit is contained in:
Manu Gautam 2018-05-09 23:09:21 +05:30 committed by Felipe Balbi
parent a4333c3a6b
commit bcb128777a
1 changed files with 33 additions and 3 deletions

View File

@ -1394,6 +1394,7 @@ static int dwc3_remove(struct platform_device *pdev)
static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
{
unsigned long flags;
u32 reg;
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
@ -1403,9 +1404,25 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
dwc3_core_exit(dwc);
break;
case DWC3_GCTL_PRTCAP_HOST:
/* do nothing during host runtime_suspend */
if (!PMSG_IS_AUTO(msg))
if (!PMSG_IS_AUTO(msg)) {
dwc3_core_exit(dwc);
break;
}
/* Let controller to suspend HSPHY before PHY driver suspends */
if (dwc->dis_u2_susphy_quirk ||
dwc->dis_enblslpm_quirk) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg |= DWC3_GUSB2PHYCFG_ENBLSLPM |
DWC3_GUSB2PHYCFG_SUSPHY;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
/* Give some time for USB2 PHY to suspend */
usleep_range(5000, 6000);
}
phy_pm_runtime_put_sync(dwc->usb2_generic_phy);
phy_pm_runtime_put_sync(dwc->usb3_generic_phy);
break;
case DWC3_GCTL_PRTCAP_OTG:
/* do nothing during runtime_suspend */
@ -1433,6 +1450,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
{
unsigned long flags;
int ret;
u32 reg;
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
@ -1446,13 +1464,25 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
spin_unlock_irqrestore(&dwc->lock, flags);
break;
case DWC3_GCTL_PRTCAP_HOST:
/* nothing to do on host runtime_resume */
if (!PMSG_IS_AUTO(msg)) {
ret = dwc3_core_init(dwc);
if (ret)
return ret;
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
break;
}
/* Restore GUSB2PHYCFG bits that were modified in suspend */
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
if (dwc->dis_u2_susphy_quirk)
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
if (dwc->dis_enblslpm_quirk)
reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
phy_pm_runtime_get_sync(dwc->usb2_generic_phy);
phy_pm_runtime_get_sync(dwc->usb3_generic_phy);
break;
case DWC3_GCTL_PRTCAP_OTG:
/* nothing to do on runtime_resume */