USB: bcma: add regulator support
PATCH v4 1/1 USB: bcma: add regulator support
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. VBUS is fetched with devm_regulator_get() so existing boards keep working. Those with "vcc-gpio" are unchanged. A dummy regulator warning is now emitted to encourage migration to the new regulator setup.
Both mechanisms now start with VBUS off and enable it only after the host controller has been set up, so a SuperSpeed device no longer falls back to high-speed because EHCI started with VBUS already on. VBUS is dropped again on suspend, shutdown and remove.
---
v4: split into own patch as it's not dependent on dts changes.
v3: don't drop GPIO.
v2: fixup dts and keep GPIO working.
drivers/usb/host/bcma-hcd.c | 38 ++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-)
drivers/usb/host/bcma-hcd.c +31 -7
@@ -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,18 @@ 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 =0 ; -if (!usb_dev->gpio_desc) -return ; +if (usb_dev->gpio_desc) + err =gpiod_set_value (usb_dev->gpio_desc, on); +if (err) +return err; -gpiod_set_value (usb_dev->gpio_desc, val); +return on ?regulator_enable (usb_dev->regulator) : +regulator_disable (usb_dev->regulator); }static const struct usb_ehci_pdata ehci_pdata = {
@@ -416,6 +422,11 @@ 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 (&core->dev,"vbus" ); +if (IS_ERR (usb_dev->regulator)) +return dev_err_probe (&core->dev,PTR_ERR (usb_dev->regulator), +"error obtaining VBUS regulator" ); +switch (core->id.id) {case BCMA_CORE_USB20_HOST :if (IS_ENABLED (CONFIG_ARM ))
@@ -437,6 +448,10 @@ static int bcma_hcd_probe(struct bcma_device *core)if (err)return err; + err =regulator_enable (usb_dev->regulator); +if (err) +return dev_err_probe (&core->dev, err,"error enabling VBUS" ); +bcma_set_drvdata (core, usb_dev);return 0 ; }
@@ -452,12 +467,13 @@ static void bcma_hcd_remove(struct bcma_device *dev)if (ehci_dev)platform_device_unregister (ehci_dev); +bcma_hci_platform_power (dev, false);bcma_core_disable (dev,0 ); }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 ); }
@@ -465,7 +481,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 ;
@@ -473,7 +493,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 ;
Signature · 1 line
2.55.0