From e6f2f6d63e3b0c4e75011f09ecbdbe093d5f2eb1 Mon Sep 17 00:00:00 2001 From: William Wu Date: Wed, 7 Mar 2018 18:13:37 +0800 Subject: [PATCH] usb: dwc2: power on/off phy for otg mode The commit dc71e5194420 ("usb: dwc2: make otg manage lowlevel hw on its own") aimed to control the clk and phy power for otg mode, but it also introduced lost of new problems, so we revert it. This patch only controls phy power for otg mode, it can fix the dwc2 udc start fail issue with the following error log: dwc2_hsotg_init_fifo: timeout flushing fifos (GRSTCTL=80000430) dwc2_core_reset() HANG! Soft Reset GRSTCTL=80000001 bound driver configfs-gadget dwc2_core_reset() HANG! Soft Reset GRSTCTL=80000001 Change-Id: Id6996aecab7f0aaaf12530b7a377144e23ef1667 Signed-off-by: William Wu --- drivers/usb/dwc2/gadget.c | 32 ++++++++++++++++++++++++++++++++ drivers/usb/dwc2/platform.c | 13 +++++++++++++ 2 files changed, 45 insertions(+) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 1330ab8e29c2..0c4fa75a1f72 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -3465,6 +3466,24 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, goto err; } + if (hsotg->dr_mode == USB_DR_MODE_OTG) { + struct platform_device *pdev = to_platform_device(hsotg->dev); + + if (hsotg->uphy) { + ret = usb_phy_init(hsotg->uphy); + } else if (hsotg->plat && hsotg->plat->phy_init) { + ret = hsotg->plat->phy_init(pdev, + hsotg->plat->phy_type); + } else { + ret = phy_power_on(hsotg->phy); + if (ret == 0) + ret = phy_init(hsotg->phy); + } + + if (ret) + goto err; + } + if (!IS_ERR_OR_NULL(hsotg->uphy)) otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget); @@ -3524,6 +3543,19 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) dwc2_lowlevel_hw_disable(hsotg); + if (hsotg->dr_mode == USB_DR_MODE_OTG) { + struct platform_device *pdev = to_platform_device(hsotg->dev); + + if (hsotg->uphy) { + usb_phy_shutdown(hsotg->uphy); + } else if (hsotg->plat && hsotg->plat->phy_exit) { + hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); + } else { + phy_exit(hsotg->phy); + phy_power_off(hsotg->phy); + } + } + return 0; } diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index cada275a5f5f..47a1b6dd3a18 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -654,6 +654,19 @@ static int dwc2_driver_probe(struct platform_device *dev) if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) dwc2_lowlevel_hw_disable(hsotg); + if (hsotg->dr_mode == USB_DR_MODE_OTG) { + struct platform_device *pdev = to_platform_device(hsotg->dev); + + if (hsotg->uphy) { + usb_phy_shutdown(hsotg->uphy); + } else if (hsotg->plat && hsotg->plat->phy_exit) { + hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); + } else { + phy_exit(hsotg->phy); + phy_power_off(hsotg->phy); + } + } + return 0; error: