From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EEFE945561A; Sat, 12 Sep 2026 10:47:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789210039; cv=none; b=fXPP2+b9oYiMHFNbDvmV1N2uq3rfcoj0uvLKjaAUjmgT38CEM34koVOhTLAicwmbzmUv1Z90Fvv4wwFykqsdzJciHhmfPQaRkDpyAPTzXYjuwJPXZj/m2CoXl8vIFTFgcpr0UmgycAqn3/11zXPPNIMUeE5HUaoL2uCsS2B6bTA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789210039; c=relaxed/simple; bh=6dGZ+30/UcJICQYnGzdpJ8jwG+aYIqvFj2/3ccPL+4g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=smvsbJpRa5uWHdSqPCJO4XkJvSPUxfsWfkHLL3Mv+/FzzkFvIFEftSD4aET8z8z7Vbuo5oUBs8zv0gAI8btOc3IseqDv/p2bM7b8rt9L3h3zJev5BYXjjoGZvxdNwUHN4kqhUMiWnTIquY8Dz+fd9djKLg6oofrEyrzJ8AwT+FM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=sax102nB; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="sax102nB" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 057351F000FF; Sat, 12 Sep 2026 10:47:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1789210035; bh=3NUdedWD8ukulON8bp2fTA04/v31N13NoHsffpCvp7E=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=sax102nBnIn2a+lRjodxC0y+RtivhrmzBfmDWoQKMxaOaRXfrUeJWWyggAd50S5WR nwGDWCkY2wxnl/4PvncuxRT86mI6qXNenRSAI7gyq605DOT3Ax6LZlQYOSG8y4fcfP sS5hrSLS8H3eed6eyVCrdNnwtgekMVtd0RncXW2A= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Tommaso Merciai , Vinod Koul , Sasha Levin Subject: [PATCH 6.18 0944/1518] phy: renesas: rcar-gen3-usb2: Add regulator for OTG VBUS control Date: Sat, 12 Sep 2026 08:51:53 +0200 Message-ID: <20260912065644.808891404@linuxfoundation.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260912065623.398859879@linuxfoundation.org> References: <20260912065623.398859879@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.18-stable review patch. If anyone has any objections, please let me know. ------------------ From: Tommaso Merciai [ Upstream commit b6d7dd157763e0c8937f60241fb4af9eb546a7fb ] Enable OTG VBUS control on R-Car Gen3 USB2 PHY by registering a regulator driver that manages the VBOUT line. This change allows the controller to handle VBUS output for OTG ports using the regulator framework when the platform requires hardware-based VBUS control. Without this, some platforms cannot properly manage VBUS power on OTG- capable ports, leading to potential USB functionality issues. Signed-off-by: Tommaso Merciai Link: https://patch.msgid.link/6c1aebf60b4d8ff0c51a8243c68b397c1a384867.1766405010.git.tommaso.merciai.xr@bp.renesas.com Signed-off-by: Vinod Koul Stable-dep-of: 49c9b71b4508 ("phy: renesas: phy-rcar-gen3-usb2: Fix devm action registration for disabled VBUS regulator") Signed-off-by: Sasha Levin --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 142 ++++++++++++++++++++++- 1 file changed, 137 insertions(+), 5 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index d4588a936f92d..03ea292bbfd4c 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -140,6 +141,7 @@ struct rcar_gen3_chan { bool extcon_host; bool is_otg_channel; bool uses_otg_pins; + bool otg_internal_reg; }; struct rcar_gen3_phy_drv_data { @@ -224,6 +226,11 @@ static void rcar_gen3_phy_usb2_set_vbus(struct rcar_gen3_chan *ch, static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) { + if (ch->otg_internal_reg) { + regulator_hardware_enable(ch->vbus, vbus); + return; + } + if (ch->phy_data->no_adp_ctrl || ch->phy_data->vblvl_ctrl) { if (ch->vbus) regulator_hardware_enable(ch->vbus, vbus); @@ -592,7 +599,7 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p) u32 val; int ret = 0; - if (channel->vbus) { + if (channel->vbus && !channel->otg_internal_reg) { ret = regulator_enable(channel->vbus); if (ret) return ret; @@ -633,7 +640,7 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p) } } - if (channel->vbus) + if (channel->vbus && !channel->otg_internal_reg) ret = regulator_disable(channel->vbus); return ret; @@ -819,6 +826,128 @@ static int rcar_gen3_phy_usb2_init_bus(struct rcar_gen3_chan *channel) return ret; } +static int rcar_gen3_phy_usb2_regulator_endisable(struct regulator_dev *rdev, + bool enable) +{ + struct rcar_gen3_chan *channel = rdev_get_drvdata(rdev); + struct device *dev = channel->dev; + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) { + dev_warn(dev, "pm_runtime_get failed: %i\n", ret); + return ret; + } + + rcar_gen3_phy_usb2_set_vbus(channel, USB2_VBCTRL, + USB2_VBCTRL_VBOUT, enable); + pm_runtime_put_noidle(dev); + + return ret; +} + +static int rcar_gen3_phy_usb2_regulator_enable(struct regulator_dev *rdev) +{ + return rcar_gen3_phy_usb2_regulator_endisable(rdev, true); +} + +static int rcar_gen3_phy_usb2_regulator_disable(struct regulator_dev *rdev) +{ + return rcar_gen3_phy_usb2_regulator_endisable(rdev, false); +} + +static int rcar_gen3_phy_usb2_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct rcar_gen3_chan *channel = rdev_get_drvdata(rdev); + void __iomem *usb2_base = channel->base; + struct device *dev = channel->dev; + u32 vbus_ctrl_reg = USB2_VBCTRL; + u32 val; + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) { + dev_warn(dev, "pm_runtime_get failed: %i\n", ret); + return ret; + } + + val = readl(usb2_base + vbus_ctrl_reg); + + pm_runtime_put_noidle(dev); + dev_dbg(channel->dev, "%s: %08x\n", __func__, val); + + return (val & USB2_VBCTRL_VBOUT) ? 1 : 0; +} + +static const struct regulator_ops rcar_gen3_phy_usb2_regulator_ops = { + .enable = rcar_gen3_phy_usb2_regulator_enable, + .disable = rcar_gen3_phy_usb2_regulator_disable, + .is_enabled = rcar_gen3_phy_usb2_regulator_is_enabled, +}; + +static const struct regulator_desc rcar_gen3_phy_usb2_regulator = { + .name = "otg-vbus-regulator", + .of_match = of_match_ptr("vbus-regulator"), + .ops = &rcar_gen3_phy_usb2_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .fixed_uV = 5000000, + .n_voltages = 1, +}; + +static void rcar_gen3_phy_usb2_vbus_disable_action(void *data) +{ + struct regulator *vbus = data; + + regulator_disable(vbus); +} + +static int rcar_gen3_phy_usb2_vbus_regulator_get_exclusive_enable(struct rcar_gen3_chan *channel, + bool enable) +{ + struct device *dev = channel->dev; + int ret; + + channel->vbus = devm_regulator_get_exclusive(dev, "vbus"); + if (IS_ERR(channel->vbus)) + return PTR_ERR(channel->vbus); + + if (!enable) + return 0; + + ret = regulator_enable(channel->vbus); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, rcar_gen3_phy_usb2_vbus_disable_action, + channel->vbus); +} + +static int rcar_gen3_phy_usb2_vbus_regulator_register(struct rcar_gen3_chan *channel) +{ + 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"); + if (rcfg.of_node) { + rcfg.driver_data = channel; + rdev = devm_regulator_register(dev, &rcar_gen3_phy_usb2_regulator, + &rcfg); + of_node_put(rcfg.of_node); + if (IS_ERR(rdev)) + return dev_err_probe(dev, PTR_ERR(rdev), + "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); +} + static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -891,10 +1020,13 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) phy_set_drvdata(channel->rphys[i].phy, &channel->rphys[i]); } - if (channel->phy_data->no_adp_ctrl && channel->is_otg_channel) - channel->vbus = devm_regulator_get_exclusive(dev, "vbus"); - else + if (channel->phy_data->no_adp_ctrl && channel->is_otg_channel) { + ret = rcar_gen3_phy_usb2_vbus_regulator_register(channel); + if (ret) + return ret; + } else { channel->vbus = devm_regulator_get_optional(dev, "vbus"); + } if (IS_ERR(channel->vbus)) { if (PTR_ERR(channel->vbus) == -EPROBE_DEFER) { ret = PTR_ERR(channel->vbus); -- 2.53.0