From 6e6adab8f735bc4fe27a67bdc3144d8fa89250d4 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 Signed-off-by: Frank Wang --- 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 ad4c94366dad..3cc293a9e3c5 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -4473,6 +4474,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); @@ -4532,6 +4551,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 8cac005b0737..8937a28c31c1 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -599,6 +599,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); + } + } + #if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) /* Postponed adding a new gadget to the udc class driver list */