diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index c619c3190b22..03632badaa57 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -864,6 +864,7 @@ struct dwc2_hregs_backup { * @hcd_enabled: Host mode sub-driver initialization indicator. * @gadget_enabled: Peripheral mode sub-driver initialization indicator. * @ll_hw_enabled: Status of low-level hardware resources. + * @ll_phy_enabled Status of low-level PHY resources. * @hibernated: True if core is hibernated * @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a * remote wakeup. @@ -1059,6 +1060,7 @@ struct dwc2_hsotg { unsigned int hcd_enabled:1; unsigned int gadget_enabled:1; unsigned int ll_hw_enabled:1; + unsigned int ll_phy_enabled:1; unsigned int hibernated:1; unsigned int reset_phy_on_wake:1; unsigned int need_phy_for_wake:1; @@ -1344,6 +1346,9 @@ extern const struct of_device_id dwc2_of_match_table[]; int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg); int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg); +int dwc2_lowlevel_phy_enable(struct dwc2_hsotg *hsotg); +int dwc2_lowlevel_phy_disable(struct dwc2_hsotg *hsotg); + /* Common polling functions */ int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hs_otg, u32 reg, u32 bit, u32 timeout); diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 4201256ec4e5..14a9935e767f 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -4478,21 +4478,11 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, } if (hsotg->dr_mode == USB_DR_MODE_OTG && dwc2_is_device_mode(hsotg)) { - 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 (!hsotg->ll_phy_enabled) { + ret = dwc2_lowlevel_phy_enable(hsotg); + if (ret) + goto err; } - - if (ret) - goto err; } if (!IS_ERR_OR_NULL(hsotg->uphy)) @@ -4555,16 +4545,8 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) dwc2_lowlevel_hw_disable(hsotg); if (hsotg->dr_mode == USB_DR_MODE_OTG && dwc2_is_device_mode(hsotg)) { - 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 (hsotg->ll_phy_enabled) + dwc2_lowlevel_phy_disable(hsotg); } return 0; diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 70d178966666..eb1357cce876 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -3188,6 +3188,9 @@ static void dwc2_conn_id_status_change(struct work_struct *work) dev_dbg(hsotg->dev, "%s()\n", __func__); + if (!hsotg->ll_phy_enabled && dwc2_is_host_mode(hsotg)) + dwc2_lowlevel_phy_enable(hsotg); + gotgctl = dwc2_readl(hsotg, GOTGCTL); dev_dbg(hsotg->dev, "gotgctl=%0x\n", gotgctl); dev_dbg(hsotg->dev, "gotgctl.b.conidsts=%d\n", diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 403654ec9a5a..c83eaf74f10c 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -128,6 +128,74 @@ static void __dwc2_disable_regulators(void *data) regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); } +static int __dwc2_lowlevel_phy_enable(struct dwc2_hsotg *hsotg) +{ + struct platform_device *pdev = to_platform_device(hsotg->dev); + int ret; + + 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); + } + + return ret; +} + +/** + * dwc2_lowlevel_phy_enable - enable lowlevel PHY resources + * @hsotg: The driver state + * + * A wrapper for platform code responsible for controlling + * low-level PHY resources. + */ +int dwc2_lowlevel_phy_enable(struct dwc2_hsotg *hsotg) +{ + int ret = __dwc2_lowlevel_phy_enable(hsotg); + + if (ret == 0) + hsotg->ll_phy_enabled = true; + return ret; +} + +static int __dwc2_lowlevel_phy_disable(struct dwc2_hsotg *hsotg) +{ + struct platform_device *pdev = to_platform_device(hsotg->dev); + int ret = 0; + + if (hsotg->uphy) { + usb_phy_shutdown(hsotg->uphy); + } else if (hsotg->plat && hsotg->plat->phy_exit) { + ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); + } else { + ret = phy_exit(hsotg->phy); + if (ret == 0) + ret = phy_power_off(hsotg->phy); + } + + return ret; +} + +/** + * dwc2_lowlevel_phy_disable - disable lowlevel PHY resources + * @hsotg: The driver state + * + * A wrapper for platform code responsible for controlling + * low-level PHY platform resources. + */ +int dwc2_lowlevel_phy_disable(struct dwc2_hsotg *hsotg) +{ + int ret = __dwc2_lowlevel_phy_disable(hsotg); + + if (ret == 0) + hsotg->ll_phy_enabled = false; + return ret; +} + static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) { struct platform_device *pdev = to_platform_device(hsotg->dev); @@ -147,15 +215,8 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) if (ret) return ret; - 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 (!hsotg->ll_phy_enabled) + ret = dwc2_lowlevel_phy_enable(hsotg); return ret; } @@ -178,18 +239,11 @@ int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) { - struct platform_device *pdev = to_platform_device(hsotg->dev); int ret = 0; - if (hsotg->uphy) { - usb_phy_shutdown(hsotg->uphy); - } else if (hsotg->plat && hsotg->plat->phy_exit) { - ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); - } else { - ret = phy_exit(hsotg->phy); - if (ret == 0) - ret = phy_power_off(hsotg->phy); - } + if (hsotg->ll_phy_enabled) + ret = dwc2_lowlevel_phy_disable(hsotg); + if (ret) return ret; @@ -608,16 +662,8 @@ static int dwc2_driver_probe(struct platform_device *dev) dwc2_lowlevel_hw_disable(hsotg); if (hsotg->dr_mode == USB_DR_MODE_OTG && dwc2_is_device_mode(hsotg)) { - 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 (hsotg->ll_phy_enabled) + dwc2_lowlevel_phy_disable(hsotg); } #if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \