diff options
author | Manu Gautam <mgautam@codeaurora.org> | 2018-01-18 06:24:30 -0500 |
---|---|---|
committer | Felipe Balbi <felipe.balbi@linux.intel.com> | 2018-02-12 03:50:16 -0500 |
commit | c4a5153e87fdf6805f63ff57556260e2554155a5 (patch) | |
tree | 5ca6f6f3995b3a864f76a11918e8f0f0a5596fde | |
parent | 00b42170c86f90ac9dea83a7dfcd3f0c38098fe2 (diff) |
usb: dwc3: core: Power-off core/PHYs on system_suspend in host mode
Commit 689bf72c6e0d ("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: 689bf72c6e0d ("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>
-rw-r--r-- | drivers/usb/dwc3/core.c | 36 |
1 files changed, 22 insertions, 14 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index bc2467f0e6a7..59511f2cd3ac 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c | |||
@@ -100,6 +100,8 @@ static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) | |||
100 | reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); | 100 | reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); |
101 | reg |= DWC3_GCTL_PRTCAPDIR(mode); | 101 | reg |= DWC3_GCTL_PRTCAPDIR(mode); |
102 | dwc3_writel(dwc->regs, DWC3_GCTL, reg); | 102 | dwc3_writel(dwc->regs, DWC3_GCTL, reg); |
103 | |||
104 | dwc->current_dr_role = mode; | ||
103 | } | 105 | } |
104 | 106 | ||
105 | static void __dwc3_set_mode(struct work_struct *work) | 107 | static void __dwc3_set_mode(struct work_struct *work) |
@@ -133,8 +135,6 @@ static void __dwc3_set_mode(struct work_struct *work) | |||
133 | 135 | ||
134 | dwc3_set_prtcap(dwc, dwc->desired_dr_role); | 136 | dwc3_set_prtcap(dwc, dwc->desired_dr_role); |
135 | 137 | ||
136 | dwc->current_dr_role = dwc->desired_dr_role; | ||
137 | |||
138 | spin_unlock_irqrestore(&dwc->lock, flags); | 138 | spin_unlock_irqrestore(&dwc->lock, flags); |
139 | 139 | ||
140 | switch (dwc->desired_dr_role) { | 140 | switch (dwc->desired_dr_role) { |
@@ -219,7 +219,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) | |||
219 | * XHCI driver will reset the host block. If dwc3 was configured for | 219 | * XHCI driver will reset the host block. If dwc3 was configured for |
220 | * host-only mode, then we can return early. | 220 | * host-only mode, then we can return early. |
221 | */ | 221 | */ |
222 | if (dwc->dr_mode == USB_DR_MODE_HOST) | 222 | if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST) |
223 | return 0; | 223 | return 0; |
224 | 224 | ||
225 | reg = dwc3_readl(dwc->regs, DWC3_DCTL); | 225 | reg = dwc3_readl(dwc->regs, DWC3_DCTL); |
@@ -919,7 +919,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) | |||
919 | 919 | ||
920 | switch (dwc->dr_mode) { | 920 | switch (dwc->dr_mode) { |
921 | case USB_DR_MODE_PERIPHERAL: | 921 | case USB_DR_MODE_PERIPHERAL: |
922 | dwc->current_dr_role = DWC3_GCTL_PRTCAP_DEVICE; | ||
923 | dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); | 922 | dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); |
924 | 923 | ||
925 | if (dwc->usb2_phy) | 924 | if (dwc->usb2_phy) |
@@ -935,7 +934,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) | |||
935 | } | 934 | } |
936 | break; | 935 | break; |
937 | case USB_DR_MODE_HOST: | 936 | case USB_DR_MODE_HOST: |
938 | dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST; | ||
939 | dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); | 937 | dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); |
940 | 938 | ||
941 | if (dwc->usb2_phy) | 939 | if (dwc->usb2_phy) |
@@ -1287,7 +1285,7 @@ static int dwc3_remove(struct platform_device *pdev) | |||
1287 | } | 1285 | } |
1288 | 1286 | ||
1289 | #ifdef CONFIG_PM | 1287 | #ifdef CONFIG_PM |
1290 | static int dwc3_suspend_common(struct dwc3 *dwc) | 1288 | static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) |
1291 | { | 1289 | { |
1292 | unsigned long flags; | 1290 | unsigned long flags; |
1293 | 1291 | ||
@@ -1299,6 +1297,10 @@ static int dwc3_suspend_common(struct dwc3 *dwc) | |||
1299 | dwc3_core_exit(dwc); | 1297 | dwc3_core_exit(dwc); |
1300 | break; | 1298 | break; |
1301 | case DWC3_GCTL_PRTCAP_HOST: | 1299 | case DWC3_GCTL_PRTCAP_HOST: |
1300 | /* do nothing during host runtime_suspend */ | ||
1301 | if (!PMSG_IS_AUTO(msg)) | ||
1302 | dwc3_core_exit(dwc); | ||
1303 | break; | ||
1302 | default: | 1304 | default: |
1303 | /* do nothing */ | 1305 | /* do nothing */ |
1304 | break; | 1306 | break; |
@@ -1307,7 +1309,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc) | |||
1307 | return 0; | 1309 | return 0; |
1308 | } | 1310 | } |
1309 | 1311 | ||
1310 | static int dwc3_resume_common(struct dwc3 *dwc) | 1312 | static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) |
1311 | { | 1313 | { |
1312 | unsigned long flags; | 1314 | unsigned long flags; |
1313 | int ret; | 1315 | int ret; |
@@ -1323,6 +1325,13 @@ static int dwc3_resume_common(struct dwc3 *dwc) | |||
1323 | spin_unlock_irqrestore(&dwc->lock, flags); | 1325 | spin_unlock_irqrestore(&dwc->lock, flags); |
1324 | break; | 1326 | break; |
1325 | case DWC3_GCTL_PRTCAP_HOST: | 1327 | case DWC3_GCTL_PRTCAP_HOST: |
1328 | /* nothing to do on host runtime_resume */ | ||
1329 | if (!PMSG_IS_AUTO(msg)) { | ||
1330 | ret = dwc3_core_init(dwc); | ||
1331 | if (ret) | ||
1332 | return ret; | ||
1333 | } | ||
1334 | break; | ||
1326 | default: | 1335 | default: |
1327 | /* do nothing */ | 1336 | /* do nothing */ |
1328 | break; | 1337 | break; |
@@ -1334,12 +1343,11 @@ static int dwc3_resume_common(struct dwc3 *dwc) | |||
1334 | static int dwc3_runtime_checks(struct dwc3 *dwc) | 1343 | static int dwc3_runtime_checks(struct dwc3 *dwc) |
1335 | { | 1344 | { |
1336 | switch (dwc->current_dr_role) { | 1345 | switch (dwc->current_dr_role) { |
1337 | case USB_DR_MODE_PERIPHERAL: | 1346 | case DWC3_GCTL_PRTCAP_DEVICE: |
1338 | case USB_DR_MODE_OTG: | ||
1339 | if (dwc->connected) | 1347 | if (dwc->connected) |
1340 | return -EBUSY; | 1348 | return -EBUSY; |
1341 | break; | 1349 | break; |
1342 | case USB_DR_MODE_HOST: | 1350 | case DWC3_GCTL_PRTCAP_HOST: |
1343 | default: | 1351 | default: |
1344 | /* do nothing */ | 1352 | /* do nothing */ |
1345 | break; | 1353 | break; |
@@ -1356,7 +1364,7 @@ static int dwc3_runtime_suspend(struct device *dev) | |||
1356 | if (dwc3_runtime_checks(dwc)) | 1364 | if (dwc3_runtime_checks(dwc)) |
1357 | return -EBUSY; | 1365 | return -EBUSY; |
1358 | 1366 | ||
1359 | ret = dwc3_suspend_common(dwc); | 1367 | ret = dwc3_suspend_common(dwc, PMSG_AUTO_SUSPEND); |
1360 | if (ret) | 1368 | if (ret) |
1361 | return ret; | 1369 | return ret; |
1362 | 1370 | ||
@@ -1372,7 +1380,7 @@ static int dwc3_runtime_resume(struct device *dev) | |||
1372 | 1380 | ||
1373 | device_init_wakeup(dev, false); | 1381 | device_init_wakeup(dev, false); |
1374 | 1382 | ||
1375 | ret = dwc3_resume_common(dwc); | 1383 | ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME); |
1376 | if (ret) | 1384 | if (ret) |
1377 | return ret; | 1385 | return ret; |
1378 | 1386 | ||
@@ -1419,7 +1427,7 @@ static int dwc3_suspend(struct device *dev) | |||
1419 | struct dwc3 *dwc = dev_get_drvdata(dev); | 1427 | struct dwc3 *dwc = dev_get_drvdata(dev); |
1420 | int ret; | 1428 | int ret; |
1421 | 1429 | ||
1422 | ret = dwc3_suspend_common(dwc); | 1430 | ret = dwc3_suspend_common(dwc, PMSG_SUSPEND); |
1423 | if (ret) | 1431 | if (ret) |
1424 | return ret; | 1432 | return ret; |
1425 | 1433 | ||
@@ -1435,7 +1443,7 @@ static int dwc3_resume(struct device *dev) | |||
1435 | 1443 | ||
1436 | pinctrl_pm_select_default_state(dev); | 1444 | pinctrl_pm_select_default_state(dev); |
1437 | 1445 | ||
1438 | ret = dwc3_resume_common(dwc); | 1446 | ret = dwc3_resume_common(dwc, PMSG_RESUME); |
1439 | if (ret) | 1447 | if (ret) |
1440 | return ret; | 1448 | return ret; |
1441 | 1449 | ||