usb: dwc3: rockchip: power off usb2 phy in suspend
authorWilliam Wu <wulf@rock-chips.com>
Thu, 15 Dec 2016 06:46:53 +0000 (14:46 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Wed, 21 Dec 2016 03:06:11 +0000 (11:06 +0800)
DWC3 use extcon notifier to manage USB cable detection
and mode switch. For host mode, if USB device connected,
it requires to reset the whole DWC3 controller to make
sure that pipe power state in P2 before power on USB3 PHY,
after do DWC3 reset we will do phy power on in extcon evt
work, however, the DWC3 core will do phy power on again
in runtime resume process (dwc3_runtime_resume() ->
dwc3_core_init() -> phy_power_on()). This will cause PHY
power off failure during suspend because we just do once
phy power off in suspend(dwc3_suspend() -> dwc3_core_exit()
-> phy_power_off()).

This patch does phy power off in suspend to make sure that
USB2 PHY enter suspend in HOST mode. And because USB3 PHY
power on operation need to be done while the pipe is in P2
state, but after resume the pipe is in P0 state, so we just
put USB3 PHY in power on state.

Change-Id: I643ba0abeb015be9285fd29d59fa0e006131c39b
Signed-off-by: William Wu <wulf@rock-chips.com>
drivers/usb/dwc3/dwc3-rockchip.c

index b9f4d6f532794c71c705e5a3286d4aefbfaf5d93..a7444d17c66ca96f7206ec518cc02598182313dc 100644 (file)
@@ -595,22 +595,45 @@ static int dwc3_rockchip_runtime_resume(struct device *dev)
 static int dwc3_rockchip_suspend(struct device *dev)
 {
        struct dwc3_rockchip *rockchip = dev_get_drvdata(dev);
+       struct dwc3 *dwc = rockchip->dwc;
 
        rockchip->suspended = true;
        cancel_work_sync(&rockchip->otg_work);
 
+       if (rockchip->edev && dwc->dr_mode != USB_DR_MODE_PERIPHERAL) {
+               /*
+                * If USB HOST connected, we will do phy power
+                * on in extcon evt work, so need to do phy
+                * power off in suspend. And we just power off
+                * USB2 PHY here because USB3 PHY power on operation
+                * need to be done while DWC3 controller is in P2
+                * state, but after resume DWC3 controller is in
+                * P0 state. So we put USB3 PHY in power on state.
+                */
+               if (extcon_get_cable_state_(rockchip->edev,
+                                           EXTCON_USB_HOST) > 0)
+                       phy_power_off(dwc->usb2_generic_phy);
+       }
+
        return 0;
 }
 
 static int dwc3_rockchip_resume(struct device *dev)
 {
        struct dwc3_rockchip *rockchip = dev_get_drvdata(dev);
+       struct dwc3 *dwc = rockchip->dwc;
 
        rockchip->suspended = false;
 
        if (rockchip->edev)
                schedule_work(&rockchip->otg_work);
 
+       if (rockchip->edev && dwc->dr_mode != USB_DR_MODE_PERIPHERAL) {
+               if (extcon_get_cable_state_(rockchip->edev,
+                                           EXTCON_USB_HOST) > 0)
+                       phy_power_on(dwc->usb2_generic_phy);
+       }
+
        return 0;
 }