[PATCH 1/2] usb: bcma: control VBUS via a regulator instead of a GPIO
COOLING11d
From: Rosen Penev <hidden>
Date: 2026-09-20 21:14:17
Also in:
linux-arm-kernel, linux-usb, lkml
Subsystem:
the rest, usb subsystem · Maintainers:
Linus Torvalds, Greg Kroah-Hartman
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. Use the standard regulator interface instead. Each core obtains its (shared) VBUS supply through devm_regulator_get_optional() 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 <redacted> --- drivers/usb/host/bcma-hcd.c | 45 +++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 14 deletions(-)
diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c
index 519386255886..394ba9e5a7f7 100644
--- a/drivers/usb/host/bcma-hcd.c
+++ b/drivers/usb/host/bcma-hcd.c@@ -20,12 +20,12 @@ */ #include <linux/bcma/bcma.h> #include <linux/delay.h> -#include <linux/gpio/consumer.h> #include <linux/platform_device.h> #include <linux/module.h> #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>
@@ -40,7 +40,7 @@ struct bcma_hcd_device { struct bcma_device *core; 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 +280,20 @@ 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->regulator) + return 0; - if (!usb_dev->gpio_desc) - return; + if (on) + err = regulator_enable(usb_dev->regulator); + else + err = regulator_disable(usb_dev->regulator); - gpiod_set_value(usb_dev->gpio_desc, val); + return err; } static const struct usb_ehci_pdata ehci_pdata = {
@@ -405,11 +411,14 @@ static int bcma_hcd_probe(struct bcma_device *core) return -ENOMEM; usb_dev->core = core; - usb_dev->gpio_desc = devm_gpiod_get_optional(&core->dev, "vcc", - GPIOD_OUT_HIGH); - if (IS_ERR(usb_dev->gpio_desc)) - return dev_err_probe(&core->dev, PTR_ERR(usb_dev->gpio_desc), - "error obtaining VCC GPIO"); + usb_dev->regulator = devm_regulator_get_optional(&core->dev, "vbus"); + if (IS_ERR(usb_dev->regulator)) { + return PTR_ERR(usb_dev->regulator); + + err = regulator_enable(usb_dev->regulator); + if (err) + return dev_err_probe(&core->dev, err, + "error enabling VCC regulator"); switch (core->id.id) { case BCMA_CORE_USB20_HOST:
@@ -452,7 +461,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 +469,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 +481,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