usb: dwc3: core: Power-off core/PHYs on system_suspend in host mode
Commit689bf72c6e
("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:689bf72c6e
("usb: dwc3: Don't reinitialize core during host bus-suspend/resume") Reviewed-by: Roger Quadros <rogerq@ti.com> Signed-off-by: Manu Gautam <mgautam@codeaurora.org> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
This commit is contained in:
parent
00b42170c8
commit
c4a5153e87
1 changed files with 22 additions and 14 deletions
|
@ -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)
|
||||||
|
|
||||||
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)
|
||||||
* 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)
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
#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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue