aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Anderson <dianders@chromium.org>2019-05-20 13:56:04 -0400
committerFelipe Balbi <felipe.balbi@linux.intel.com>2019-06-18 04:58:28 -0400
commitc846b03ff767149d75d4d8dca6d3d4945a21074a (patch)
treeeb0e2dcdb7b697427ee610c252268fe08efd7b01
parent1d390437f605db28596ad4c4bfeca2fed052c025 (diff)
USB: dwc2: Don't turn off the usbphy in suspend if wakeup is enabled
If the 'snps,need-phy-for-wake' is set in the device tree then: - We know that we can wakeup, so call device_set_wakeup_capable(). The USB core will use this knowledge to enable wakeup by default. - We know that we should keep the PHY on during suspend if something on our root hub needs remote wakeup. This requires the patch (USB: Export usb_wakeup_enabled_descendants()). Note that we don't keep the PHY on at suspend time if it's not needed because it would be a power draw. If we later find some users of dwc2 that can support wakeup without keeping the PHY on we may want to add a way to call device_set_wakeup_capable() without keeping the PHY on at suspend time. Signed-off-by: Douglas Anderson <dianders@chromium.org> Signed-off-by: Chris Zhong <zyw@rock-chips.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
-rw-r--r--drivers/usb/dwc2/core.h8
-rw-r--r--drivers/usb/dwc2/hcd.c19
-rw-r--r--drivers/usb/dwc2/platform.c23
3 files changed, 47 insertions, 3 deletions
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 152ac41dfb2d..d08d070a0fb6 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -861,6 +861,9 @@ struct dwc2_hregs_backup {
861 * @hibernated: True if core is hibernated 861 * @hibernated: True if core is hibernated
862 * @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a 862 * @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a
863 * remote wakeup. 863 * remote wakeup.
864 * @phy_off_for_suspend: Status of whether we turned the PHY off at suspend.
865 * @need_phy_for_wake: Quirk saying that we should keep the PHY on at
866 * suspend if we need USB to wake us up.
864 * @frame_number: Frame number read from the core. For both device 867 * @frame_number: Frame number read from the core. For both device
865 * and host modes. The value ranges are from 0 868 * and host modes. The value ranges are from 0
866 * to HFNUM_MAX_FRNUM. 869 * to HFNUM_MAX_FRNUM.
@@ -1049,6 +1052,8 @@ struct dwc2_hsotg {
1049 unsigned int ll_hw_enabled:1; 1052 unsigned int ll_hw_enabled:1;
1050 unsigned int hibernated:1; 1053 unsigned int hibernated:1;
1051 unsigned int reset_phy_on_wake:1; 1054 unsigned int reset_phy_on_wake:1;
1055 unsigned int need_phy_for_wake:1;
1056 unsigned int phy_off_for_suspend:1;
1052 u16 frame_number; 1057 u16 frame_number;
1053 1058
1054 struct phy *phy; 1059 struct phy *phy;
@@ -1438,6 +1443,7 @@ int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
1438int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg); 1443int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg);
1439int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, 1444int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
1440 int rem_wakeup, int reset); 1445 int rem_wakeup, int reset);
1446bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2);
1441static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) 1447static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg)
1442{ schedule_work(&hsotg->phy_reset_work); } 1448{ schedule_work(&hsotg->phy_reset_work); }
1443#else 1449#else
@@ -1463,6 +1469,8 @@ static inline int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
1463static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, 1469static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
1464 int rem_wakeup, int reset) 1470 int rem_wakeup, int reset)
1465{ return 0; } 1471{ return 0; }
1472static inline bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
1473{ return false; }
1466static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) {} 1474static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) {}
1467 1475
1468#endif 1476#endif
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 2192a2873c7c..4c78a390c958 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -5587,3 +5587,22 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
5587 dev_dbg(hsotg->dev, "Host hibernation restore complete\n"); 5587 dev_dbg(hsotg->dev, "Host hibernation restore complete\n");
5588 return ret; 5588 return ret;
5589} 5589}
5590
5591bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
5592{
5593 struct usb_device *root_hub = dwc2_hsotg_to_hcd(dwc2)->self.root_hub;
5594
5595 /* If the controller isn't allowed to wakeup then we can power off. */
5596 if (!device_may_wakeup(dwc2->dev))
5597 return true;
5598
5599 /*
5600 * We don't want to power off the PHY if something under the
5601 * root hub has wakeup enabled.
5602 */
5603 if (usb_wakeup_enabled_descendants(root_hub))
5604 return false;
5605
5606 /* No reason to keep the PHY powered, so allow poweroff */
5607 return true;
5608}
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index d10a7f8daec3..3e6c3c8a32ff 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -447,6 +447,10 @@ static int dwc2_driver_probe(struct platform_device *dev)
447 if (retval) 447 if (retval)
448 goto error; 448 goto error;
449 449
450 hsotg->need_phy_for_wake =
451 of_property_read_bool(dev->dev.of_node,
452 "snps,need-phy-for-wake");
453
450 /* 454 /*
451 * Reset before dwc2_get_hwparams() then it could get power-on real 455 * Reset before dwc2_get_hwparams() then it could get power-on real
452 * reset value form registers. 456 * reset value form registers.
@@ -478,6 +482,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
478 hsotg->gadget_enabled = 1; 482 hsotg->gadget_enabled = 1;
479 } 483 }
480 484
485 /*
486 * If we need PHY for wakeup we must be wakeup capable.
487 * When we have a device that can wake without the PHY we
488 * can adjust this condition.
489 */
490 if (hsotg->need_phy_for_wake)
491 device_set_wakeup_capable(&dev->dev, true);
492
481 hsotg->reset_phy_on_wake = 493 hsotg->reset_phy_on_wake =
482 of_property_read_bool(dev->dev.of_node, 494 of_property_read_bool(dev->dev.of_node,
483 "snps,reset-phy-on-wake"); 495 "snps,reset-phy-on-wake");
@@ -516,13 +528,17 @@ error:
516static int __maybe_unused dwc2_suspend(struct device *dev) 528static int __maybe_unused dwc2_suspend(struct device *dev)
517{ 529{
518 struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); 530 struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
531 bool is_device_mode = dwc2_is_device_mode(dwc2);
519 int ret = 0; 532 int ret = 0;
520 533
521 if (dwc2_is_device_mode(dwc2)) 534 if (is_device_mode)
522 dwc2_hsotg_suspend(dwc2); 535 dwc2_hsotg_suspend(dwc2);
523 536
524 if (dwc2->ll_hw_enabled) 537 if (dwc2->ll_hw_enabled &&
538 (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) {
525 ret = __dwc2_lowlevel_hw_disable(dwc2); 539 ret = __dwc2_lowlevel_hw_disable(dwc2);
540 dwc2->phy_off_for_suspend = true;
541 }
526 542
527 return ret; 543 return ret;
528} 544}
@@ -532,11 +548,12 @@ static int __maybe_unused dwc2_resume(struct device *dev)
532 struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); 548 struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
533 int ret = 0; 549 int ret = 0;
534 550
535 if (dwc2->ll_hw_enabled) { 551 if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) {
536 ret = __dwc2_lowlevel_hw_enable(dwc2); 552 ret = __dwc2_lowlevel_hw_enable(dwc2);
537 if (ret) 553 if (ret)
538 return ret; 554 return ret;
539 } 555 }
556 dwc2->phy_off_for_suspend = false;
540 557
541 if (dwc2_is_device_mode(dwc2)) 558 if (dwc2_is_device_mode(dwc2))
542 ret = dwc2_hsotg_resume(dwc2); 559 ret = dwc2_hsotg_resume(dwc2);