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:
committed by
Felipe Balbi
parent
a4333c3a6b
commit
bcb128777a
+33
-3
@@ -1394,6 +1394,7 @@ static int dwc3_remove(struct platform_device *pdev)
|
|||||||
static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
switch (dwc->current_dr_role) {
|
switch (dwc->current_dr_role) {
|
||||||
case DWC3_GCTL_PRTCAP_DEVICE:
|
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);
|
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)) {
|
||||||
if (!PMSG_IS_AUTO(msg))
|
|
||||||
dwc3_core_exit(dwc);
|
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;
|
break;
|
||||||
case DWC3_GCTL_PRTCAP_OTG:
|
case DWC3_GCTL_PRTCAP_OTG:
|
||||||
/* do nothing during runtime_suspend */
|
/* do nothing during runtime_suspend */
|
||||||
@@ -1433,6 +1450,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
|||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret;
|
int ret;
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
switch (dwc->current_dr_role) {
|
switch (dwc->current_dr_role) {
|
||||||
case DWC3_GCTL_PRTCAP_DEVICE:
|
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);
|
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)) {
|
if (!PMSG_IS_AUTO(msg)) {
|
||||||
ret = dwc3_core_init(dwc);
|
ret = dwc3_core_init(dwc);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
|
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;
|
break;
|
||||||
case DWC3_GCTL_PRTCAP_OTG:
|
case DWC3_GCTL_PRTCAP_OTG:
|
||||||
/* nothing to do on runtime_resume */
|
/* nothing to do on runtime_resume */
|
||||||
|
|||||||
Reference in New Issue
Block a user