diff mbox series

phy: phy-imx8mq-usb: add vbus regulator support

Message ID 20230609012949.3250445-1-tharvey@gateworks.com
State Superseded
Delegated to: Stefano Babic
Headers show
Series phy: phy-imx8mq-usb: add vbus regulator support | expand

Commit Message

Tim Harvey June 9, 2023, 1:29 a.m. UTC
Add support for enabling and disabling vbus-supply regulator found
on several imx8mp boards in the usb3_phy0 and usb3_phy1 nodes.

Without this I suspect U-Boot usb does not work on the following:
 - imx8mp-beacon-kit
 - imx8mp-msc-sm2s
 - imx8mp-verdin-wifi-dev

Signed-off-by: Tim Harvey <tharvey@gateworks.com>
---
 drivers/phy/phy-imx8mq-usb.c | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

Comments

Adam Ford June 9, 2023, 3:11 a.m. UTC | #1
On Thu, Jun 8, 2023 at 8:29 PM Tim Harvey <tharvey@gateworks.com> wrote:
>
> Add support for enabling and disabling vbus-supply regulator found
> on several imx8mp boards in the usb3_phy0 and usb3_phy1 nodes.
>
> Without this I suspect U-Boot usb does not work on the following:
>  - imx8mp-beacon-kit

The Host-only port works on the Beacon board, but the dual-role, usb
type-c port doesn't appear to have been impacted.  I am guessing it's
due to the lack of a proper type-c driver. Despite that,  I think it's
the right thing to do for this platform, and I'll give some feedback
below.

>  - imx8mp-msc-sm2s
>  - imx8mp-verdin-wifi-dev
>

Reviewed-by: Adam Ford <aford173@gmail.com>

> Signed-off-by: Tim Harvey <tharvey@gateworks.com>
> ---
>  drivers/phy/phy-imx8mq-usb.c | 24 ++++++++++++++++++++++--
>  1 file changed, 22 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/phy/phy-imx8mq-usb.c b/drivers/phy/phy-imx8mq-usb.c
> index 69f01de55538..eed9c07848f4 100644
> --- a/drivers/phy/phy-imx8mq-usb.c
> +++ b/drivers/phy/phy-imx8mq-usb.c
> @@ -14,6 +14,7 @@
>  #include <linux/delay.h>
>  #include <linux/err.h>
>  #include <clk.h>
> +#include <power/regulator.h>
>
>  #define PHY_CTRL0                      0x0
>  #define PHY_CTRL0_REF_SSP_EN           BIT(2)
> @@ -81,6 +82,7 @@ struct imx8mq_usb_phy {
>  #endif
>         void __iomem *base;
>         enum imx8mpq_phy_type type;
> +       struct udevice *vbus_supply;
>  };
>
>  static const struct udevice_id imx8mq_usb_phy_of_match[] = {
> @@ -173,9 +175,9 @@ static int imx8mq_usb_phy_power_on(struct phy *usb_phy)
>         struct udevice *dev = usb_phy->dev;
>         struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
>         u32 value;
> +       int ret;

In the unlikely event that neither CONFIG_CLK nor CONFIG_DM_REGULATOR
is configured, will defining ret here throw a compiler warning that
it's unused? I wonder if __maybe_unused attribute would be permissible
here or if this should be inside an #if statement.

>
>  #if CONFIG_IS_ENABLED(CLK)
> -       int ret;
>         ret = clk_enable(&imx_phy->phy_clk);
>         if (ret) {
>                 printf("Failed to enable usb phy clock\n");
> @@ -183,6 +185,12 @@ static int imx8mq_usb_phy_power_on(struct phy *usb_phy)
>         }
>  #endif
>
> +       if (CONFIG_IS_ENABLED(DM_REGULATOR) && imx_phy->vbus_supply) {
> +               ret = regulator_set_enable(imx_phy->vbus_supply, true);
> +               if (ret)

I am personally a fan of error messages.  There is an error message if
the clock fails, so unless there is an objection, can we have one here
too?  One was also added to the probe function.

> +                       return ret;
> +       }
> +
>         /* Disable rx term override */
>         value = readl(imx_phy->base + PHY_CTRL6);
>         value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
> @@ -206,6 +214,9 @@ static int imx8mq_usb_phy_power_off(struct phy *usb_phy)
>         clk_disable(&imx_phy->phy_clk);
>  #endif
>
> +       if (CONFIG_IS_ENABLED(DM_REGULATOR) && imx_phy->vbus_supply)
> +               return regulator_set_enable(imx_phy->vbus_supply, false);
> +
>         return 0;
>  }
>
> @@ -224,6 +235,7 @@ struct phy_ops imx8mq_usb_phy_ops = {
>  int imx8mq_usb_phy_probe(struct udevice *dev)
>  {
>         struct imx8mq_usb_phy *priv = dev_get_priv(dev);
> +       int ret;

Same comment as above regarding whether or not this might be unused.
>
>         priv->type = dev_get_driver_data(dev);
>         priv->base = dev_read_addr_ptr(dev);
> @@ -232,7 +244,6 @@ int imx8mq_usb_phy_probe(struct udevice *dev)
>                 return -EINVAL;
>
>  #if CONFIG_IS_ENABLED(CLK)
> -       int ret;
>
>         /* Assigned clock already set clock */
>         ret = clk_get_by_name(dev, "phy", &priv->phy_clk);
> @@ -242,6 +253,15 @@ int imx8mq_usb_phy_probe(struct udevice *dev)
>         }
>  #endif
>
> +       if (CONFIG_IS_ENABLED(DM_REGULATOR)) {
> +               ret = device_get_supply_regulator(dev, "vbus-supply",
> +                                                 &priv->vbus_supply);
> +               if (ret && ret != -ENOENT) {
> +                       pr_err("Failed to get PHY regulator\n");
> +                       return ret;
> +               }
> +       }
> +
>         return 0;
>  }
>
> --
> 2.25.1
>
Tim Harvey June 9, 2023, 4:17 p.m. UTC | #2
On Thu, Jun 8, 2023 at 8:12 PM Adam Ford <aford173@gmail.com> wrote:
>
> On Thu, Jun 8, 2023 at 8:29 PM Tim Harvey <tharvey@gateworks.com> wrote:
> >
> > Add support for enabling and disabling vbus-supply regulator found
> > on several imx8mp boards in the usb3_phy0 and usb3_phy1 nodes.
> >
> > Without this I suspect U-Boot usb does not work on the following:
> >  - imx8mp-beacon-kit
>
> The Host-only port works on the Beacon board, but the dual-role, usb
> type-c port doesn't appear to have been impacted.  I am guessing it's
> due to the lack of a proper type-c driver. Despite that,  I think it's
> the right thing to do for this platform, and I'll give some feedback
> below.

Adam,

Is perhaps the pca6416 gpio0 pulled up externally or defaults to
driving high? If you put a print in regulator_set_enable() you'll see
that reg_usb1_host_vbus never gets called without this patch so I
don't see how a device on that host would work.

Right - the type-c doesn't work because there is no driver for the
ptn5110. Even if there were I'm not clear what the right mechanism is
for calling out from the dwc3 driver to see what role the usb
controller should be. I don't believe U-Boot already has any common
method for usb host controllers to ask for role other than reading the
dr_mode prop. Perhaps there needs to be a usb connector uclass added
with a global function to check the role that various typec controller
drivers could use. I have some imx8mp boards that have OTG connectors
where I need to check the USB_ID gpio for the role which can be
handled that way as well.

If you did want to default your type-c to host mode until such support
exists you can add 'dr_mode = "host"' to the usb_dwc3_0 node in your
imx8mp-beacon-kit-u-boot.dtsi:

>
> >  - imx8mp-msc-sm2s
> >  - imx8mp-verdin-wifi-dev
> >
>
> Reviewed-by: Adam Ford <aford173@gmail.com>
>
> > Signed-off-by: Tim Harvey <tharvey@gateworks.com>
> > ---
> >  drivers/phy/phy-imx8mq-usb.c | 24 ++++++++++++++++++++++--
> >  1 file changed, 22 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/phy/phy-imx8mq-usb.c b/drivers/phy/phy-imx8mq-usb.c
> > index 69f01de55538..eed9c07848f4 100644
> > --- a/drivers/phy/phy-imx8mq-usb.c
> > +++ b/drivers/phy/phy-imx8mq-usb.c
> > @@ -14,6 +14,7 @@
> >  #include <linux/delay.h>
> >  #include <linux/err.h>
> >  #include <clk.h>
> > +#include <power/regulator.h>
> >
> >  #define PHY_CTRL0                      0x0
> >  #define PHY_CTRL0_REF_SSP_EN           BIT(2)
> > @@ -81,6 +82,7 @@ struct imx8mq_usb_phy {
> >  #endif
> >         void __iomem *base;
> >         enum imx8mpq_phy_type type;
> > +       struct udevice *vbus_supply;
> >  };
> >
> >  static const struct udevice_id imx8mq_usb_phy_of_match[] = {
> > @@ -173,9 +175,9 @@ static int imx8mq_usb_phy_power_on(struct phy *usb_phy)
> >         struct udevice *dev = usb_phy->dev;
> >         struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
> >         u32 value;
> > +       int ret;
>
> In the unlikely event that neither CONFIG_CLK nor CONFIG_DM_REGULATOR
> is configured, will defining ret here throw a compiler warning that
> it's unused? I wonder if __maybe_unused attribute would be permissible
> here or if this should be inside an #if statement.
>

good point, I'll add for v2

> >
> >  #if CONFIG_IS_ENABLED(CLK)
> > -       int ret;
> >         ret = clk_enable(&imx_phy->phy_clk);
> >         if (ret) {
> >                 printf("Failed to enable usb phy clock\n");
> > @@ -183,6 +185,12 @@ static int imx8mq_usb_phy_power_on(struct phy *usb_phy)
> >         }
> >  #endif
> >
> > +       if (CONFIG_IS_ENABLED(DM_REGULATOR) && imx_phy->vbus_supply) {
> > +               ret = regulator_set_enable(imx_phy->vbus_supply, true);
> > +               if (ret)
>
> I am personally a fan of error messages.  There is an error message if
> the clock fails, so unless there is an objection, can we have one here
> too?  One was also added to the probe function.

ok, I'll add this for v2

>
> > +                       return ret;
> > +       }
> > +
> >         /* Disable rx term override */
> >         value = readl(imx_phy->base + PHY_CTRL6);
> >         value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
> > @@ -206,6 +214,9 @@ static int imx8mq_usb_phy_power_off(struct phy *usb_phy)
> >         clk_disable(&imx_phy->phy_clk);
> >  #endif
> >
> > +       if (CONFIG_IS_ENABLED(DM_REGULATOR) && imx_phy->vbus_supply)
> > +               return regulator_set_enable(imx_phy->vbus_supply, false);
> > +
> >         return 0;
> >  }
> >
> > @@ -224,6 +235,7 @@ struct phy_ops imx8mq_usb_phy_ops = {
> >  int imx8mq_usb_phy_probe(struct udevice *dev)
> >  {
> >         struct imx8mq_usb_phy *priv = dev_get_priv(dev);
> > +       int ret;
>
> Same comment as above regarding whether or not this might be unused.

yep - will address.

Thanks for the review!

Tim
diff mbox series

Patch

diff --git a/drivers/phy/phy-imx8mq-usb.c b/drivers/phy/phy-imx8mq-usb.c
index 69f01de55538..eed9c07848f4 100644
--- a/drivers/phy/phy-imx8mq-usb.c
+++ b/drivers/phy/phy-imx8mq-usb.c
@@ -14,6 +14,7 @@ 
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <clk.h>
+#include <power/regulator.h>
 
 #define PHY_CTRL0			0x0
 #define PHY_CTRL0_REF_SSP_EN		BIT(2)
@@ -81,6 +82,7 @@  struct imx8mq_usb_phy {
 #endif
 	void __iomem *base;
 	enum imx8mpq_phy_type type;
+	struct udevice *vbus_supply;
 };
 
 static const struct udevice_id imx8mq_usb_phy_of_match[] = {
@@ -173,9 +175,9 @@  static int imx8mq_usb_phy_power_on(struct phy *usb_phy)
 	struct udevice *dev = usb_phy->dev;
 	struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
 	u32 value;
+	int ret;
 
 #if CONFIG_IS_ENABLED(CLK)
-	int ret;
 	ret = clk_enable(&imx_phy->phy_clk);
 	if (ret) {
 		printf("Failed to enable usb phy clock\n");
@@ -183,6 +185,12 @@  static int imx8mq_usb_phy_power_on(struct phy *usb_phy)
 	}
 #endif
 
+	if (CONFIG_IS_ENABLED(DM_REGULATOR) && imx_phy->vbus_supply) {
+		ret = regulator_set_enable(imx_phy->vbus_supply, true);
+		if (ret)
+			return ret;
+	}
+
 	/* Disable rx term override */
 	value = readl(imx_phy->base + PHY_CTRL6);
 	value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
@@ -206,6 +214,9 @@  static int imx8mq_usb_phy_power_off(struct phy *usb_phy)
 	clk_disable(&imx_phy->phy_clk);
 #endif
 
+	if (CONFIG_IS_ENABLED(DM_REGULATOR) && imx_phy->vbus_supply)
+		return regulator_set_enable(imx_phy->vbus_supply, false);
+
 	return 0;
 }
 
@@ -224,6 +235,7 @@  struct phy_ops imx8mq_usb_phy_ops = {
 int imx8mq_usb_phy_probe(struct udevice *dev)
 {
 	struct imx8mq_usb_phy *priv = dev_get_priv(dev);
+	int ret;
 
 	priv->type = dev_get_driver_data(dev);
 	priv->base = dev_read_addr_ptr(dev);
@@ -232,7 +244,6 @@  int imx8mq_usb_phy_probe(struct udevice *dev)
 		return -EINVAL;
 
 #if CONFIG_IS_ENABLED(CLK)
-	int ret;
 
 	/* Assigned clock already set clock */
 	ret = clk_get_by_name(dev, "phy", &priv->phy_clk);
@@ -242,6 +253,15 @@  int imx8mq_usb_phy_probe(struct udevice *dev)
 	}
 #endif
 
+	if (CONFIG_IS_ENABLED(DM_REGULATOR)) {
+		ret = device_get_supply_regulator(dev, "vbus-supply",
+						  &priv->vbus_supply);
+		if (ret && ret != -ENOENT) {
+			pr_err("Failed to get PHY regulator\n");
+			return ret;
+		}
+	}
+
 	return 0;
 }