In-Reply-To: <20200805061744.20404-1-mike.looijmans@xxxxxxxx> On Wed, 5 Aug 2020 08:17:44 +0200, Mike Looijmans wrote: > Support VBUS power control using regulator framework. Enables the regulator > while the port is in host mode. > > The "vbus-supply" property can be provided using a usb-connector child node > and standard devicetree bindings. > > Signed-off-by: Mike Looijmans <mike.looijmans@xxxxxxxx> > --- > v2: Add missing devm_regulator_get call which got lost during rebase > v3: Remove devicetree binding, use standard usb-connector > Fix probe fail when vbus-supply is not present > v4: Use devm_regulator_get (without "optional") > > drivers/usb/dwc3/core.c | 34 ++++++++++++++++++++++++++-------- > drivers/usb/dwc3/core.h | 4 ++++ > drivers/usb/dwc3/drd.c | 6 ++---- > 3 files changed, 32 insertions(+), 12 deletions(-) > > diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c > index edc17155cb2b..abfd043bae21 100644 > --- a/drivers/usb/dwc3/core.c > +++ b/drivers/usb/dwc3/core.c > @@ -25,6 +25,7 @@ > #include <linux/of.h> > #include <linux/acpi.h> > #include <linux/pinctrl/consumer.h> > +#include <linux/regulator/consumer.h> > #include <linux/reset.h> > > #include <linux/usb/ch9.h> > @@ -112,6 +113,23 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) > dwc->current_dr_role = mode; > } > > +void dwc3_set_vbus(struct dwc3 *dwc, bool enable) > +{ > + int ret; > + > + if (enable != dwc->vbus_reg_enabled) { > + if (enable) > + ret = regulator_enable(dwc->vbus_reg); > + else > + ret = regulator_disable(dwc->vbus_reg); > + if (!ret) > + dwc->vbus_reg_enabled = enable; > + } > + > + if (dwc->usb2_phy) > + otg_set_vbus(dwc->usb2_phy->otg, enable); > +} > + > static void __dwc3_set_mode(struct work_struct *work) > { > struct dwc3 *dwc = work_to_dwc(work); > @@ -164,8 +182,7 @@ static void __dwc3_set_mode(struct work_struct *work) > if (ret) { > dev_err(dwc->dev, "failed to initialize host\n"); > } else { > - if (dwc->usb2_phy) > - otg_set_vbus(dwc->usb2_phy->otg, true); > + dwc3_set_vbus(dwc, true); > phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST); > phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); > } > @@ -173,8 +190,7 @@ static void __dwc3_set_mode(struct work_struct *work) > case DWC3_GCTL_PRTCAP_DEVICE: > dwc3_event_buffers_setup(dwc); > > - if (dwc->usb2_phy) > - otg_set_vbus(dwc->usb2_phy->otg, false); > + dwc3_set_vbus(dwc, false); > phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); > phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); > > @@ -1183,8 +1199,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) > case USB_DR_MODE_PERIPHERAL: > dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); > > - if (dwc->usb2_phy) > - otg_set_vbus(dwc->usb2_phy->otg, false); > + dwc3_set_vbus(dwc, false); > phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); > phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); > > @@ -1198,8 +1213,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) > case USB_DR_MODE_HOST: > dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); > > - if (dwc->usb2_phy) > - otg_set_vbus(dwc->usb2_phy->otg, true); > + dwc3_set_vbus(dwc, true); > phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST); > phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); > > @@ -1470,6 +1484,10 @@ static int dwc3_probe(struct platform_device *pdev) > > dwc3_get_properties(dwc); > > + dwc->vbus_reg = devm_regulator_get(dev, "vbus"); > + if (IS_ERR(dwc->vbus_reg)) > + return PTR_ERR(dwc->vbus_reg); > + > dwc->reset = devm_reset_control_array_get(dev, true, true); > if (IS_ERR(dwc->reset)) > return PTR_ERR(dwc->reset); > diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h > index 4c171a8e215f..cee2574d7bf4 100644 > --- a/drivers/usb/dwc3/core.h > +++ b/drivers/usb/dwc3/core.h > @@ -1085,6 +1085,9 @@ struct dwc3 { > > bool phys_ready; > > + struct regulator *vbus_reg; > + bool vbus_reg_enabled; > + > struct ulpi *ulpi; > bool ulpi_ready; > > @@ -1397,6 +1400,7 @@ struct dwc3_gadget_ep_cmd_params { > > /* prototypes */ > void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode); > +void dwc3_set_vbus(struct dwc3 *dwc, bool enable); > void dwc3_set_mode(struct dwc3 *dwc, u32 mode); > u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type); > > diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c > index 7db1ffc92bbd..45fdec2d128d 100644 > --- a/drivers/usb/dwc3/drd.c > +++ b/drivers/usb/dwc3/drd.c > @@ -384,8 +384,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) > if (ret) { > dev_err(dwc->dev, "failed to initialize host\n"); > } else { > - if (dwc->usb2_phy) > - otg_set_vbus(dwc->usb2_phy->otg, true); > + dwc3_set_vbus(dwc, true); > if (dwc->usb2_generic_phy) > phy_set_mode(dwc->usb2_generic_phy, > PHY_MODE_USB_HOST); > @@ -398,8 +397,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) > dwc3_event_buffers_setup(dwc); > spin_unlock_irqrestore(&dwc->lock, flags); > > - if (dwc->usb2_phy) > - otg_set_vbus(dwc->usb2_phy->otg, false); > + dwc3_set_vbus(dwc, false); > if (dwc->usb2_generic_phy) > phy_set_mode(dwc->usb2_generic_phy, > PHY_MODE_USB_DEVICE); > -- > 2.17.1 Tested after fixing a couple of small conflicts. Tested-by: Yassine Oudjana <y.oudjana@xxxxxxxxxxxxxx>