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]> --- Notes: Changes in v6: - dev_err() and dev_dbg() for the two messages; the reset hook reaches the device through the private data Changes in v5: - none 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 | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/ehci-vf.c b/drivers/usb/host/ehci-vf.c index b145424006d..d56ce1abc2b 100644 --- a/drivers/usb/host/ehci-vf.c +++ b/drivers/usb/host/ehci-vf.c @@ -20,7 +20,9 @@ #include <asm/mach-imx/regs-usbphy.h> #include <linux/delay.h> #include <usb/ehci-ci.h> +#include <power/regulator.h> #include <linux/usb/otg.h> +#include <dm/device_compat.h> #include "ehci.h" @@ -41,6 +43,8 @@ struct ehci_vf_priv_data { struct anadig_reg __iomem *anatop_addr; void __iomem *phy_addr; void __iomem *misc_addr; + struct udevice *vbus_supply; + struct udevice *dev; int portnr; }; @@ -209,9 +213,9 @@ static int vf_usb_of_to_plat(struct udevice *dev) return 0; } -static int vf_init_after_reset(struct ehci_ctrl *dev) +static int vf_init_after_reset(struct ehci_ctrl *ctrl) { - struct ehci_vf_priv_data *priv = dev->priv; + struct ehci_vf_priv_data *priv = ctrl->priv; enum usb_init_type type = priv->init_type; struct usb_ehci *ehci = priv->ehci; int ret; @@ -220,6 +224,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) { + dev_err(priv->dev, "cannot enable the VBUS supply: %d\n", ret); + return ret; + } + if (type == USB_INIT_DEVICE) return 0; @@ -245,6 +256,16 @@ static int ehci_usb_probe(struct udevice *dev) struct ehci_hcor *hcor; int ret; + priv->dev = dev; + ret = device_get_supply_regulator(dev, "vbus-supply", + &priv->vbus_supply); + if (ret == -ENOENT || ret == -ENOSYS) { + dev_dbg(dev, "no VBUS supply\n"); + } else if (ret) { + dev_err(dev, "cannot get the VBUS supply: %d\n", ret); + return ret; + } + ret = ehci_vf_common_init(priv); if (ret) return ret; @@ -272,12 +293,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
