Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Manu Gautam and committed by
Felipe Balbi
bcb12877 a4333c3a

+33 -3
+33 -3
drivers/usb/dwc3/core.c
··· 1394 1394 static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) 1395 1395 { 1396 1396 unsigned long flags; 1397 + u32 reg; 1397 1398 1398 1399 switch (dwc->current_dr_role) { 1399 1400 case DWC3_GCTL_PRTCAP_DEVICE: ··· 1404 1403 dwc3_core_exit(dwc); 1405 1404 break; 1406 1405 case DWC3_GCTL_PRTCAP_HOST: 1407 - /* do nothing during host runtime_suspend */ 1408 - if (!PMSG_IS_AUTO(msg)) 1406 + if (!PMSG_IS_AUTO(msg)) { 1409 1407 dwc3_core_exit(dwc); 1408 + break; 1409 + } 1410 + 1411 + /* Let controller to suspend HSPHY before PHY driver suspends */ 1412 + if (dwc->dis_u2_susphy_quirk || 1413 + dwc->dis_enblslpm_quirk) { 1414 + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 1415 + reg |= DWC3_GUSB2PHYCFG_ENBLSLPM | 1416 + DWC3_GUSB2PHYCFG_SUSPHY; 1417 + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 1418 + 1419 + /* Give some time for USB2 PHY to suspend */ 1420 + usleep_range(5000, 6000); 1421 + } 1422 + 1423 + phy_pm_runtime_put_sync(dwc->usb2_generic_phy); 1424 + phy_pm_runtime_put_sync(dwc->usb3_generic_phy); 1410 1425 break; 1411 1426 case DWC3_GCTL_PRTCAP_OTG: 1412 1427 /* do nothing during runtime_suspend */ ··· 1450 1433 { 1451 1434 unsigned long flags; 1452 1435 int ret; 1436 + u32 reg; 1453 1437 1454 1438 switch (dwc->current_dr_role) { 1455 1439 case DWC3_GCTL_PRTCAP_DEVICE: ··· 1464 1446 spin_unlock_irqrestore(&dwc->lock, flags); 1465 1447 break; 1466 1448 case DWC3_GCTL_PRTCAP_HOST: 1467 - /* nothing to do on host runtime_resume */ 1468 1449 if (!PMSG_IS_AUTO(msg)) { 1469 1450 ret = dwc3_core_init(dwc); 1470 1451 if (ret) 1471 1452 return ret; 1472 1453 dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); 1454 + break; 1473 1455 } 1456 + /* Restore GUSB2PHYCFG bits that were modified in suspend */ 1457 + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 1458 + if (dwc->dis_u2_susphy_quirk) 1459 + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; 1460 + 1461 + if (dwc->dis_enblslpm_quirk) 1462 + reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; 1463 + 1464 + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 1465 + 1466 + phy_pm_runtime_get_sync(dwc->usb2_generic_phy); 1467 + phy_pm_runtime_get_sync(dwc->usb3_generic_phy); 1474 1468 break; 1475 1469 case DWC3_GCTL_PRTCAP_OTG: 1476 1470 /* nothing to do on runtime_resume */