diff options
author | Douglas Anderson <dianders@chromium.org> | 2019-05-20 19:56:04 +0200 |
---|---|---|
committer | Felipe Balbi <felipe.balbi@linux.intel.com> | 2019-06-18 10:58:28 +0200 |
commit | c846b03ff767149d75d4d8dca6d3d4945a21074a (patch) | |
tree | eb0e2dcdb7b697427ee610c252268fe08efd7b01 /drivers/usb/dwc2/platform.c | |
parent | ARM: dts: rockchip: Allow wakeup from rk3288-veyron's dwc2 USB ports (diff) | |
download | linux-c846b03ff767149d75d4d8dca6d3d4945a21074a.tar.xz linux-c846b03ff767149d75d4d8dca6d3d4945a21074a.zip |
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>
Diffstat (limited to 'drivers/usb/dwc2/platform.c')
-rw-r--r-- | drivers/usb/dwc2/platform.c | 23 |
1 files changed, 20 insertions, 3 deletions
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) if (retval) goto error; + hsotg->need_phy_for_wake = + of_property_read_bool(dev->dev.of_node, + "snps,need-phy-for-wake"); + /* * Reset before dwc2_get_hwparams() then it could get power-on real * reset value form registers. @@ -478,6 +482,14 @@ static int dwc2_driver_probe(struct platform_device *dev) hsotg->gadget_enabled = 1; } + /* + * If we need PHY for wakeup we must be wakeup capable. + * When we have a device that can wake without the PHY we + * can adjust this condition. + */ + if (hsotg->need_phy_for_wake) + device_set_wakeup_capable(&dev->dev, true); + hsotg->reset_phy_on_wake = of_property_read_bool(dev->dev.of_node, "snps,reset-phy-on-wake"); @@ -516,13 +528,17 @@ error: static int __maybe_unused dwc2_suspend(struct device *dev) { struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); + bool is_device_mode = dwc2_is_device_mode(dwc2); int ret = 0; - if (dwc2_is_device_mode(dwc2)) + if (is_device_mode) dwc2_hsotg_suspend(dwc2); - if (dwc2->ll_hw_enabled) + if (dwc2->ll_hw_enabled && + (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) { ret = __dwc2_lowlevel_hw_disable(dwc2); + dwc2->phy_off_for_suspend = true; + } return ret; } @@ -532,11 +548,12 @@ static int __maybe_unused dwc2_resume(struct device *dev) struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); int ret = 0; - if (dwc2->ll_hw_enabled) { + if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) { ret = __dwc2_lowlevel_hw_enable(dwc2); if (ret) return ret; } + dwc2->phy_off_for_suspend = false; if (dwc2_is_device_mode(dwc2)) ret = dwc2_hsotg_resume(dwc2); |