From: Mehmet Fide <[email protected]>

The driver never enables the vbus-supply of its port, so on boards that
switch VBUS through a regulator, such as the Colibri VF50 and VF61
carriers, the port stays unpowered and no device is found.

Do what ehci-mx6 does: look the regulator up in probe, enable it in
host mode, disable it in device mode, and turn it off on remove. A
missing vbus-supply or a build without DM_REGULATOR is fine; any other
lookup error fails the probe instead of leaving the port dead.

Signed-off-by: Mehmet Fide <[email protected]>
---
Changes in v4:
- enable VBUS in the reset hook only, as ehci-mx6 does: enabling it in
  the shared init as well counted two enables per probe, so "usb stop"
  never switched it off
- the dm core patch it needed is dropped, next claims the regulator
  GPIO at probe time
- reworded the commit message

 drivers/usb/host/ehci-vf.c | 29 ++++++++++++++++++++++++++++-
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/host/ehci-vf.c b/drivers/usb/host/ehci-vf.c
index b1cfad14b09..7b8aeaecf38 100644
--- a/drivers/usb/host/ehci-vf.c
+++ b/drivers/usb/host/ehci-vf.c
@@ -21,6 +21,7 @@
 #include <asm/mach-imx/regs-usbphy.h>
 #include <linux/delay.h>
 #include <usb/ehci-ci.h>
+#include <power/regulator.h>
 #include <linux/libfdt.h>
 
 #include "ehci.h"
@@ -53,6 +54,7 @@ struct ehci_vf_priv_data {
        struct anadig_reg __iomem *anatop_addr;
        void __iomem *phy_addr;
        void __iomem *misc_addr;
+       struct udevice *vbus_supply;
        int portnr;
 };
 
@@ -254,6 +256,13 @@ static int vf_init_after_reset(struct ehci_ctrl *dev)
        if (ret)
                return ret;
 
+       ret = regulator_set_enable_if_allowed(priv->vbus_supply,
+                                             type != USB_INIT_DEVICE);
+       if (ret && ret != -ENOSYS) {
+               printf("Error enabling VBUS supply (ret=%i)\n", ret);
+               return ret;
+       }
+
        if (type == USB_INIT_DEVICE)
                return 0;
 
@@ -279,6 +288,15 @@ static int ehci_usb_probe(struct udevice *dev)
        struct ehci_hcor *hcor;
        int ret;
 
+       ret = device_get_supply_regulator(dev, "vbus-supply",
+                                         &priv->vbus_supply);
+       if (ret == -ENOENT || ret == -ENOSYS) {
+               debug("%s: no vbus supply\n", dev->name);
+       } else if (ret) {
+               printf("Error getting VBUS supply (ret=%i)\n", ret);
+               return ret;
+       }
+
        ret = ehci_vf_common_init(priv);
        if (ret)
                return ret;
@@ -306,12 +324,21 @@ static const struct udevice_id vf_usb_ids[] = {
        { }
 };
 
+static int ehci_usb_remove(struct udevice *dev)
+{
+       struct ehci_vf_priv_data *priv = dev_get_priv(dev);
+
+       regulator_set_enable_if_allowed(priv->vbus_supply, false);
+
+       return ehci_deregister(dev);
+}
+
 U_BOOT_DRIVER(ehci_vf) = {
        .name = "ehci_vf",
        .id = UCLASS_USB,
        .of_match = vf_usb_ids,
        .probe = ehci_usb_probe,
-       .remove = ehci_deregister,
+       .remove = ehci_usb_remove,
        .ops = &ehci_usb_ops,
        .of_to_plat = vf_usb_of_to_plat,
        .plat_auto      = sizeof(struct usb_plat),
-- 
2.55.0

Reply via email to