From: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
To: Prabhakar <prabhakar.csengg@gmail.com>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>,
Vinod Koul <vkoul@kernel.org>,
Neil Armstrong <neil.armstrong@linaro.org>,
Manivannan Sadhasivam <mani@kernel.org>,
Geert Uytterhoeven <geert+renesas@glider.be>,
Magnus Damm <magnus.damm@gmail.com>,
linux-renesas-soc@vger.kernel.org, linux-phy@lists.infradead.org,
linux-kernel@vger.kernel.org,
Prabhakar <prabhakar.csengg+renesas@gmail.com>,
Biju Das <biju.das.jz@bp.renesas.com>,
Fabrizio Castro <fabrizio.castro.jz@renesas.com>,
Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Subject: Re: [PATCH v2] phy: renesas: rcar-gen3-usb2: Keep OTG VBUS disabled until role is known
Date: Fri, 9 Oct 2026 16:59:15 +0200 [thread overview]
Message-ID: <askBQzpjiQX0CY0e@tom-desktop> (raw)
In-Reply-To: <20261007190654.452376-1-prabhakar.mahadev-lad.rj@bp.renesas.com>
Hi Prabhakar,
Thanks for your patch.
On Wed, Oct 07, 2026 at 08:06:54PM +0100, Prabhakar wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> On OTG channels of SoCs without ADP control, the VBUS regulator is
> acquired with devm_regulator_get_exclusive() and its output is switched
> by rcar_gen3_enable_vbus_ctrl() using regulator_hardware_enable() once
> the port role is known.
>
> The helper acquiring the regulator has the following problems:
>
> - The internal regulator is unconditionally enabled at probe, so VBUS
> is driven before the port role is known. If the port is connected to
> an external host this can back-power it.
>
> - regulator_get_exclusive() hands the consumer an enable reference if
> the regulator is already enabled, for example by the bootloader. The
> unconditional regulator_enable() then takes a second reference while
> only one is released on unbind, leaving the regulator enabled and
> triggering the WARN_ON() in _regulator_put().
>
> Fix this by making sure the driver always holds exactly one reference
> to the regulator: reuse the reference handed over by the exclusive get
> if the regulator is already enabled, and call regulator_enable()
> otherwise. Register the disable action in both cases, then turn off the
> physical VBUS output with regulator_hardware_enable() until the port
> role is established. Enabling a disabled regulator to take the
> reference may briefly drive VBUS during probe; this cannot be avoided
> with the regulator API.
>
> Rename the regulator helper to reflect that it acquires the regulator
> without directly enabling its physical VBUS output.
>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Tested on RZ/G3E.
Tested-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
Kind regards,
Tommaso
> ---
> v1->v2:
> - regulator_enable() is only called if the regulator is not already enabled,
> ensuring exactly one reference is held.
> - Dropped enable parameter from the function
> - Renamed function rcar_gen3_phy_usb2_vbus_regulator_get_exclusive_enable()
> to rcar_gen3_phy_usb2_vbus_regulator_get_exclusive()
> - Updated commit message
> ---
> drivers/phy/renesas/phy-rcar-gen3-usb2.c | 35 +++++++++++++++++-------
> 1 file changed, 25 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
> index b5ba751805aa..3481505dea2e 100644
> --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
> +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
> @@ -1114,8 +1114,7 @@ static void rcar_gen3_phy_usb2_vbus_disable_action(void *data)
> regulator_disable(vbus);
> }
>
> -static int rcar_gen3_phy_usb2_vbus_regulator_get_exclusive_enable(struct rcar_gen3_chan *channel,
> - bool enable)
> +static int rcar_gen3_phy_usb2_vbus_regulator_get_exclusive(struct rcar_gen3_chan *channel)
> {
> struct device *dev = channel->dev;
> int ret;
> @@ -1133,17 +1132,35 @@ static int rcar_gen3_phy_usb2_vbus_regulator_get_exclusive_enable(struct rcar_ge
> return 0;
> }
>
> - if (enable) {
> + ret = regulator_is_enabled(channel->vbus);
> + if (ret < 0)
> + return ret;
> +
> + if (!ret) {
> ret = regulator_enable(channel->vbus);
> if (ret)
> return ret;
> }
>
> - if (regulator_is_enabled(channel->vbus))
> - return devm_add_action_or_reset(dev, rcar_gen3_phy_usb2_vbus_disable_action,
> - channel->vbus);
> + /*
> + * An exclusive get of an enabled regulator already holds a reference, so
> + * add a cleanup action to disable it when the device is released.
> + */
> + ret = devm_add_action_or_reset(dev, rcar_gen3_phy_usb2_vbus_disable_action,
> + channel->vbus);
> + if (ret)
> + return ret;
>
> - return 0;
> + /*
> + * The regulator is enabled only so that the regulator core holds a
> + * reference to it. Do not drive VBUS until the port's role is known;
> + * rcar_gen3_enable_vbus_ctrl() switches it from then on.
> + *
> + * The VBUS regulator used on these SoCs implement the .enable/.disable
> + * ops, so regulator_hardware_enable() cannot fail with -EOPNOTSUPP here
> + * and no special handling for it is needed.
> + */
> + return regulator_hardware_enable(channel->vbus, false);
> }
>
> static int rcar_gen3_phy_usb2_vbus_regulator_register(struct rcar_gen3_chan *channel)
> @@ -1151,7 +1168,6 @@ static int rcar_gen3_phy_usb2_vbus_regulator_register(struct rcar_gen3_chan *cha
> struct device *dev = channel->dev;
> struct regulator_config rcfg = { .dev = dev, };
> struct regulator_dev *rdev;
> - bool enable = false;
>
> rcfg.of_node = of_get_available_child_by_name(dev->of_node,
> "vbus-regulator");
> @@ -1165,10 +1181,9 @@ static int rcar_gen3_phy_usb2_vbus_regulator_register(struct rcar_gen3_chan *cha
> "Failed to create vbus-regulator\n");
>
> channel->otg_internal_reg = true;
> - enable = true;
> }
>
> - return rcar_gen3_phy_usb2_vbus_regulator_get_exclusive_enable(channel, enable);
> + return rcar_gen3_phy_usb2_vbus_regulator_get_exclusive(channel);
> }
>
> static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
> --
> 2.55.0
>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
WARNING: multiple messages have this Message-ID (diff)
From: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
To: Prabhakar <prabhakar.csengg@gmail.com>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>,
Vinod Koul <vkoul@kernel.org>,
Neil Armstrong <neil.armstrong@linaro.org>,
Manivannan Sadhasivam <mani@kernel.org>,
Geert Uytterhoeven <geert+renesas@glider.be>,
Magnus Damm <magnus.damm@gmail.com>,
linux-renesas-soc@vger.kernel.org, linux-phy@lists.infradead.org,
linux-kernel@vger.kernel.org,
Prabhakar <prabhakar.csengg+renesas@gmail.com>,
Biju Das <biju.das.jz@bp.renesas.com>,
Fabrizio Castro <fabrizio.castro.jz@renesas.com>,
Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Subject: Re: [PATCH v2] phy: renesas: rcar-gen3-usb2: Keep OTG VBUS disabled until role is known
Date: Fri, 9 Oct 2026 16:59:15 +0200 [thread overview]
Message-ID: <askBQzpjiQX0CY0e@tom-desktop> (raw)
In-Reply-To: <20261007190654.452376-1-prabhakar.mahadev-lad.rj@bp.renesas.com>
Hi Prabhakar,
Thanks for your patch.
On Wed, Oct 07, 2026 at 08:06:54PM +0100, Prabhakar wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> On OTG channels of SoCs without ADP control, the VBUS regulator is
> acquired with devm_regulator_get_exclusive() and its output is switched
> by rcar_gen3_enable_vbus_ctrl() using regulator_hardware_enable() once
> the port role is known.
>
> The helper acquiring the regulator has the following problems:
>
> - The internal regulator is unconditionally enabled at probe, so VBUS
> is driven before the port role is known. If the port is connected to
> an external host this can back-power it.
>
> - regulator_get_exclusive() hands the consumer an enable reference if
> the regulator is already enabled, for example by the bootloader. The
> unconditional regulator_enable() then takes a second reference while
> only one is released on unbind, leaving the regulator enabled and
> triggering the WARN_ON() in _regulator_put().
>
> Fix this by making sure the driver always holds exactly one reference
> to the regulator: reuse the reference handed over by the exclusive get
> if the regulator is already enabled, and call regulator_enable()
> otherwise. Register the disable action in both cases, then turn off the
> physical VBUS output with regulator_hardware_enable() until the port
> role is established. Enabling a disabled regulator to take the
> reference may briefly drive VBUS during probe; this cannot be avoided
> with the regulator API.
>
> Rename the regulator helper to reflect that it acquires the regulator
> without directly enabling its physical VBUS output.
>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Tested on RZ/G3E.
Tested-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
Kind regards,
Tommaso
> ---
> v1->v2:
> - regulator_enable() is only called if the regulator is not already enabled,
> ensuring exactly one reference is held.
> - Dropped enable parameter from the function
> - Renamed function rcar_gen3_phy_usb2_vbus_regulator_get_exclusive_enable()
> to rcar_gen3_phy_usb2_vbus_regulator_get_exclusive()
> - Updated commit message
> ---
> drivers/phy/renesas/phy-rcar-gen3-usb2.c | 35 +++++++++++++++++-------
> 1 file changed, 25 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
> index b5ba751805aa..3481505dea2e 100644
> --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
> +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
> @@ -1114,8 +1114,7 @@ static void rcar_gen3_phy_usb2_vbus_disable_action(void *data)
> regulator_disable(vbus);
> }
>
> -static int rcar_gen3_phy_usb2_vbus_regulator_get_exclusive_enable(struct rcar_gen3_chan *channel,
> - bool enable)
> +static int rcar_gen3_phy_usb2_vbus_regulator_get_exclusive(struct rcar_gen3_chan *channel)
> {
> struct device *dev = channel->dev;
> int ret;
> @@ -1133,17 +1132,35 @@ static int rcar_gen3_phy_usb2_vbus_regulator_get_exclusive_enable(struct rcar_ge
> return 0;
> }
>
> - if (enable) {
> + ret = regulator_is_enabled(channel->vbus);
> + if (ret < 0)
> + return ret;
> +
> + if (!ret) {
> ret = regulator_enable(channel->vbus);
> if (ret)
> return ret;
> }
>
> - if (regulator_is_enabled(channel->vbus))
> - return devm_add_action_or_reset(dev, rcar_gen3_phy_usb2_vbus_disable_action,
> - channel->vbus);
> + /*
> + * An exclusive get of an enabled regulator already holds a reference, so
> + * add a cleanup action to disable it when the device is released.
> + */
> + ret = devm_add_action_or_reset(dev, rcar_gen3_phy_usb2_vbus_disable_action,
> + channel->vbus);
> + if (ret)
> + return ret;
>
> - return 0;
> + /*
> + * The regulator is enabled only so that the regulator core holds a
> + * reference to it. Do not drive VBUS until the port's role is known;
> + * rcar_gen3_enable_vbus_ctrl() switches it from then on.
> + *
> + * The VBUS regulator used on these SoCs implement the .enable/.disable
> + * ops, so regulator_hardware_enable() cannot fail with -EOPNOTSUPP here
> + * and no special handling for it is needed.
> + */
> + return regulator_hardware_enable(channel->vbus, false);
> }
>
> static int rcar_gen3_phy_usb2_vbus_regulator_register(struct rcar_gen3_chan *channel)
> @@ -1151,7 +1168,6 @@ static int rcar_gen3_phy_usb2_vbus_regulator_register(struct rcar_gen3_chan *cha
> struct device *dev = channel->dev;
> struct regulator_config rcfg = { .dev = dev, };
> struct regulator_dev *rdev;
> - bool enable = false;
>
> rcfg.of_node = of_get_available_child_by_name(dev->of_node,
> "vbus-regulator");
> @@ -1165,10 +1181,9 @@ static int rcar_gen3_phy_usb2_vbus_regulator_register(struct rcar_gen3_chan *cha
> "Failed to create vbus-regulator\n");
>
> channel->otg_internal_reg = true;
> - enable = true;
> }
>
> - return rcar_gen3_phy_usb2_vbus_regulator_get_exclusive_enable(channel, enable);
> + return rcar_gen3_phy_usb2_vbus_regulator_get_exclusive(channel);
> }
>
> static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
> --
> 2.55.0
>
next prev parent reply other threads:[~2026-10-09 14:59 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-07 19:06 [PATCH v2] phy: renesas: rcar-gen3-usb2: Keep OTG VBUS disabled until role is known Prabhakar
2026-10-07 19:06 ` Prabhakar
2026-10-07 19:20 ` sashiko-bot
2026-10-07 20:17 ` Lad, Prabhakar
2026-10-09 14:59 ` Tommaso Merciai [this message]
2026-10-09 14:59 ` Tommaso Merciai
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=askBQzpjiQX0CY0e@tom-desktop \
--to=tommaso.merciai.xr@bp.renesas.com \
--cc=biju.das.jz@bp.renesas.com \
--cc=fabrizio.castro.jz@renesas.com \
--cc=geert+renesas@glider.be \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-phy@lists.infradead.org \
--cc=linux-renesas-soc@vger.kernel.org \
--cc=magnus.damm@gmail.com \
--cc=mani@kernel.org \
--cc=neil.armstrong@linaro.org \
--cc=prabhakar.csengg+renesas@gmail.com \
--cc=prabhakar.csengg@gmail.com \
--cc=prabhakar.mahadev-lad.rj@bp.renesas.com \
--cc=vkoul@kernel.org \
--cc=yoshihiro.shimoda.uh@renesas.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.