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>
static int dwc3_rockchip_suspend(struct device *dev)
{
struct dwc3_rockchip *rockchip = dev_get_drvdata(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);
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);
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);
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);
+ }
+