Commit c4a5153e authored by Manu Gautam's avatar Manu Gautam Committed by Felipe Balbi

usb: dwc3: core: Power-off core/PHYs on system_suspend in host mode

Commit 689bf72c ("usb: dwc3: Don't reinitialize core during
host bus-suspend/resume") updated suspend/resume routines to not
power_off and reinit PHYs/core for host mode.
It broke platforms that rely on DWC3 core to power_off PHYs to
enter low power state on system suspend.

Perform dwc3_core_exit/init only during host mode system_suspend/
resume to addresses power regression from above mentioned patch
and also allow USB session to stay connected across
runtime_suspend/resume in host mode. While at it also replace
existing checks for HOST only dr_mode with current_dr_role to
have similar core driver behavior for both Host-only and DRD+Host
configurations.

Fixes: 689bf72c ("usb: dwc3: Don't reinitialize core during host bus-suspend/resume")
Reviewed-by: default avatarRoger Quadros <rogerq@ti.com>
Signed-off-by: default avatarManu Gautam <mgautam@codeaurora.org>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 00b42170
...@@ -100,6 +100,8 @@ static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) ...@@ -100,6 +100,8 @@ static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
reg |= DWC3_GCTL_PRTCAPDIR(mode); reg |= DWC3_GCTL_PRTCAPDIR(mode);
dwc3_writel(dwc->regs, DWC3_GCTL, reg); dwc3_writel(dwc->regs, DWC3_GCTL, reg);
dwc->current_dr_role = mode;
} }
static void __dwc3_set_mode(struct work_struct *work) static void __dwc3_set_mode(struct work_struct *work)
...@@ -133,8 +135,6 @@ static void __dwc3_set_mode(struct work_struct *work) ...@@ -133,8 +135,6 @@ static void __dwc3_set_mode(struct work_struct *work)
dwc3_set_prtcap(dwc, dwc->desired_dr_role); dwc3_set_prtcap(dwc, dwc->desired_dr_role);
dwc->current_dr_role = dwc->desired_dr_role;
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
switch (dwc->desired_dr_role) { switch (dwc->desired_dr_role) {
...@@ -219,7 +219,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) ...@@ -219,7 +219,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
* XHCI driver will reset the host block. If dwc3 was configured for * XHCI driver will reset the host block. If dwc3 was configured for
* host-only mode, then we can return early. * host-only mode, then we can return early.
*/ */
if (dwc->dr_mode == USB_DR_MODE_HOST) if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)
return 0; return 0;
reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg = dwc3_readl(dwc->regs, DWC3_DCTL);
...@@ -919,7 +919,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) ...@@ -919,7 +919,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
switch (dwc->dr_mode) { switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL: case USB_DR_MODE_PERIPHERAL:
dwc->current_dr_role = DWC3_GCTL_PRTCAP_DEVICE;
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
if (dwc->usb2_phy) if (dwc->usb2_phy)
...@@ -935,7 +934,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) ...@@ -935,7 +934,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
} }
break; break;
case USB_DR_MODE_HOST: case USB_DR_MODE_HOST:
dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST;
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
if (dwc->usb2_phy) if (dwc->usb2_phy)
...@@ -1287,7 +1285,7 @@ static int dwc3_remove(struct platform_device *pdev) ...@@ -1287,7 +1285,7 @@ static int dwc3_remove(struct platform_device *pdev)
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int dwc3_suspend_common(struct dwc3 *dwc) static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
{ {
unsigned long flags; unsigned long flags;
...@@ -1299,6 +1297,10 @@ static int dwc3_suspend_common(struct dwc3 *dwc) ...@@ -1299,6 +1297,10 @@ static int dwc3_suspend_common(struct dwc3 *dwc)
dwc3_core_exit(dwc); dwc3_core_exit(dwc);
break; break;
case DWC3_GCTL_PRTCAP_HOST: case DWC3_GCTL_PRTCAP_HOST:
/* do nothing during host runtime_suspend */
if (!PMSG_IS_AUTO(msg))
dwc3_core_exit(dwc);
break;
default: default:
/* do nothing */ /* do nothing */
break; break;
...@@ -1307,7 +1309,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc) ...@@ -1307,7 +1309,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc)
return 0; return 0;
} }
static int dwc3_resume_common(struct dwc3 *dwc) static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
{ {
unsigned long flags; unsigned long flags;
int ret; int ret;
...@@ -1323,6 +1325,13 @@ static int dwc3_resume_common(struct dwc3 *dwc) ...@@ -1323,6 +1325,13 @@ static int dwc3_resume_common(struct dwc3 *dwc)
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
break; break;
case DWC3_GCTL_PRTCAP_HOST: 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;
}
break;
default: default:
/* do nothing */ /* do nothing */
break; break;
...@@ -1334,12 +1343,11 @@ static int dwc3_resume_common(struct dwc3 *dwc) ...@@ -1334,12 +1343,11 @@ static int dwc3_resume_common(struct dwc3 *dwc)
static int dwc3_runtime_checks(struct dwc3 *dwc) static int dwc3_runtime_checks(struct dwc3 *dwc)
{ {
switch (dwc->current_dr_role) { switch (dwc->current_dr_role) {
case USB_DR_MODE_PERIPHERAL: case DWC3_GCTL_PRTCAP_DEVICE:
case USB_DR_MODE_OTG:
if (dwc->connected) if (dwc->connected)
return -EBUSY; return -EBUSY;
break; break;
case USB_DR_MODE_HOST: case DWC3_GCTL_PRTCAP_HOST:
default: default:
/* do nothing */ /* do nothing */
break; break;
...@@ -1356,7 +1364,7 @@ static int dwc3_runtime_suspend(struct device *dev) ...@@ -1356,7 +1364,7 @@ static int dwc3_runtime_suspend(struct device *dev)
if (dwc3_runtime_checks(dwc)) if (dwc3_runtime_checks(dwc))
return -EBUSY; return -EBUSY;
ret = dwc3_suspend_common(dwc); ret = dwc3_suspend_common(dwc, PMSG_AUTO_SUSPEND);
if (ret) if (ret)
return ret; return ret;
...@@ -1372,7 +1380,7 @@ static int dwc3_runtime_resume(struct device *dev) ...@@ -1372,7 +1380,7 @@ static int dwc3_runtime_resume(struct device *dev)
device_init_wakeup(dev, false); device_init_wakeup(dev, false);
ret = dwc3_resume_common(dwc); ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);
if (ret) if (ret)
return ret; return ret;
...@@ -1419,7 +1427,7 @@ static int dwc3_suspend(struct device *dev) ...@@ -1419,7 +1427,7 @@ static int dwc3_suspend(struct device *dev)
struct dwc3 *dwc = dev_get_drvdata(dev); struct dwc3 *dwc = dev_get_drvdata(dev);
int ret; int ret;
ret = dwc3_suspend_common(dwc); ret = dwc3_suspend_common(dwc, PMSG_SUSPEND);
if (ret) if (ret)
return ret; return ret;
...@@ -1435,7 +1443,7 @@ static int dwc3_resume(struct device *dev) ...@@ -1435,7 +1443,7 @@ static int dwc3_resume(struct device *dev)
pinctrl_pm_select_default_state(dev); pinctrl_pm_select_default_state(dev);
ret = dwc3_resume_common(dwc); ret = dwc3_resume_common(dwc, PMSG_RESUME);
if (ret) if (ret)
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment