From: Rosen Penev <rosenp@gmail.com>
To: devicetree@vger.kernel.org
Cc: "Florian Fainelli" <florian.fainelli@broadcom.com>,
"Hauke Mehrtens" <hauke@hauke-m.de>,
"Rafał Miłecki" <zajec5@gmail.com>,
"Broadcom internal kernel review list"
<bcm-kernel-feedback-list@broadcom.com>,
"Rob Herring" <robh@kernel.org>,
"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
"Conor Dooley" <conor+dt@kernel.org>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
linux-arm-kernel@lists.infradead.org (moderated list:BROADCOM
BCM5301X ARM ARCHITECTURE),
linux-kernel@vger.kernel.org (open list),
linux-usb@vger.kernel.org (open list:USB SUBSYSTEM)
Subject: [PATCHv2 1/2] usb: bcma: add regulator support
Date: Mon, 21 Sep 2026 14:41:32 -0700 [thread overview]
Message-ID: <20260921214133.16519-2-rosenp@gmail.com> (raw)
In-Reply-To: <20260921214133.16519-1-rosenp@gmail.com>
bcma-hcd drives the USB power line by grabbing the undocumented
"vcc-gpio" from the controller node and poking it through gpiolib.
Besides relying on a non-standard binding, this cannot work on boards
such as the NETGEAR R7000 and R8000 where one chipcommon GPIO powers
both the USB2 and USB3 cores: the two controllers each request that
GPIO exclusively, so the second one fails with -EBUSY and its port
stays dead.
Add support for the standard regulator interface. Each core obtains its
(shared) VBUS supply through devm_regulator_get() and the regulator core
reference-counts the enable/disable requests, allowing both controllers to
drive one GPIO without conflicts.
Assisted-by: LLM
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/usb/host/bcma-hcd.c | 54 +++++++++++++++++++++++++++++--------
1 file changed, 43 insertions(+), 11 deletions(-)
diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c
index 519386255886..0d5a220b6988 100644
--- a/drivers/usb/host/bcma-hcd.c
+++ b/drivers/usb/host/bcma-hcd.c
@@ -26,6 +26,7 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/regulator/consumer.h>
#include <linux/usb/ehci_pdriver.h>
#include <linux/usb/ohci_pdriver.h>
@@ -41,6 +42,7 @@ struct bcma_hcd_device {
struct platform_device *ehci_dev;
struct platform_device *ohci_dev;
struct gpio_desc *gpio_desc;
+ struct regulator *regulator;
};
/* Wait for bitmask in a register to get set or cleared.
@@ -280,14 +282,23 @@ static int bcma_hcd_usb20_ns_init(struct bcma_hcd_device *bcma_hcd)
return 0;
}
-static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val)
+static int bcma_hci_platform_power(struct bcma_device *dev, bool on)
{
struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
+ int err;
+
+ if (usb_dev->gpio_desc)
+ return gpiod_set_value(usb_dev->gpio_desc, on);
- if (!usb_dev->gpio_desc)
- return;
+ if (!usb_dev->regulator)
+ return 0;
- gpiod_set_value(usb_dev->gpio_desc, val);
+ if (on)
+ err = regulator_enable(usb_dev->regulator);
+ else
+ err = regulator_disable(usb_dev->regulator);
+
+ return err;
}
static const struct usb_ehci_pdata ehci_pdata = {
@@ -395,12 +406,12 @@ static int bcma_hcd_usb30_init(struct bcma_hcd_device *bcma_hcd)
static int bcma_hcd_probe(struct bcma_device *core)
{
int err;
+ struct device *dev = &core->dev;
struct bcma_hcd_device *usb_dev;
/* TODO: Probably need checks here; is the core connected? */
- usb_dev = devm_kzalloc(&core->dev, sizeof(struct bcma_hcd_device),
- GFP_KERNEL);
+ usb_dev = devm_kzalloc(dev, sizeof(*usb_dev), GFP_KERNEL);
if (!usb_dev)
return -ENOMEM;
usb_dev->core = core;
@@ -411,6 +422,14 @@ static int bcma_hcd_probe(struct bcma_device *core)
return dev_err_probe(&core->dev, PTR_ERR(usb_dev->gpio_desc),
"error obtaining VCC GPIO");
+ usb_dev->regulator = devm_regulator_get(dev, "vbus");
+ if (IS_ERR(usb_dev->regulator))
+ return dev_err_probe(dev, PTR_ERR(usb_dev->regulator), "error obtaining VBUS regulator");
+
+ err = regulator_enable(usb_dev->regulator);
+ if (err)
+ return dev_err_probe(dev, err, "error enabling VCC regulator");
+
switch (core->id.id) {
case BCMA_CORE_USB20_HOST:
if (IS_ENABLED(CONFIG_ARM))
@@ -427,13 +446,16 @@ static int bcma_hcd_probe(struct bcma_device *core)
err = bcma_hcd_usb30_init(usb_dev);
break;
default:
- return -ENODEV;
+ err = -ENODEV;
}
if (err)
- return err;
+ goto error;
bcma_set_drvdata(core, usb_dev);
return 0;
+error:
+ regulator_disable(usb_dev->regulator);
+ return err;
}
static void bcma_hcd_remove(struct bcma_device *dev)
@@ -442,6 +464,8 @@ static void bcma_hcd_remove(struct bcma_device *dev)
struct platform_device *ohci_dev = usb_dev->ohci_dev;
struct platform_device *ehci_dev = usb_dev->ehci_dev;
+ regulator_disable(usb_dev->regulator);
+
if (ohci_dev)
platform_device_unregister(ohci_dev);
if (ehci_dev)
@@ -452,7 +476,7 @@ static void bcma_hcd_remove(struct bcma_device *dev)
static void bcma_hcd_shutdown(struct bcma_device *dev)
{
- bcma_hci_platform_power_gpio(dev, false);
+ bcma_hci_platform_power(dev, false);
bcma_core_disable(dev, 0);
}
@@ -460,7 +484,11 @@ static void bcma_hcd_shutdown(struct bcma_device *dev)
static int bcma_hcd_suspend(struct bcma_device *dev)
{
- bcma_hci_platform_power_gpio(dev, false);
+ int err;
+
+ err = bcma_hci_platform_power(dev, false);
+ if (err)
+ return err;
bcma_core_disable(dev, 0);
return 0;
@@ -468,7 +496,11 @@ static int bcma_hcd_suspend(struct bcma_device *dev)
static int bcma_hcd_resume(struct bcma_device *dev)
{
- bcma_hci_platform_power_gpio(dev, true);
+ int err;
+
+ err = bcma_hci_platform_power(dev, true);
+ if (err)
+ return err;
bcma_core_enable(dev, 0);
return 0;
--
2.55.0
next prev parent reply other threads:[~2026-09-21 21:41 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-21 21:41 [PATCHv2 0/2] usb: bcma: control VBUS via a regulator Rosen Penev
2026-09-21 21:41 ` Rosen Penev [this message]
2026-09-21 21:51 ` [PATCHv2 1/2] usb: bcma: add regulator support sashiko-bot
2026-09-21 21:59 ` Rafał Miłecki
2026-09-21 22:06 ` Rosen Penev
2026-09-21 21:41 ` [PATCHv2 2/2] ARM: dts: broadcom: model USB VBUS power with regulator-fixed Rosen Penev
2026-09-21 21:56 ` sashiko-bot
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=20260921214133.16519-2-rosenp@gmail.com \
--to=rosenp@gmail.com \
--cc=bcm-kernel-feedback-list@broadcom.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=florian.fainelli@broadcom.com \
--cc=gregkh@linuxfoundation.org \
--cc=hauke@hauke-m.de \
--cc=krzk+dt@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=robh@kernel.org \
--cc=zajec5@gmail.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.