[PATCH v3 2/2] usb: ehci-vf: enable the vbus supply of the port

Mehmet Fide <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <[email protected]>
From: Mehmet Fide <[email protected]>

The driver never looks at the vbus-supply of its port, so on a board
where VBUS is switched by a regulator, as it is on the Colibri VF50 and
VF61 carriers, the port stays unpowered and no device is ever found.

Take the regulator the way ehci-mx6 does: look it up in probe, enable it
in host mode and disable it in device mode when the controller comes up,
and turn it off again when the controller is removed.

A port with no vbus-supply, and a build without DM_REGULATOR, are both
fine and are the common case here: of the five boards that select
ARCH_VF610 only the Colibri has DM_REGULATOR at all. Anything else the
lookup reports is a supply that is described but unusable, and the
driver gives up on the port instead of leaving it silently unpowered.

Signed-off-by: Mehmet Fide <[email protected]>
---
 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 6c9866bfa5f..39baceaa820 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;
 };
 
@@ -143,6 +145,13 @@ static int ehci_vf_common_init(struct ehci_vf_priv_data *priv)
 	usb_internal_phy_clock_gate(priv->phy_addr);
 	usb_phy_enable(priv->phy_addr, priv->ehci);
 
+	ret = regulator_set_enable_if_allowed(priv->vbus_supply,
+					      priv->init_type != USB_INIT_DEVICE);
+	if (ret && ret != -ENOSYS) {
+		printf("Error enabling VBUS supply (ret=%i)\n", ret);
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -284,6 +293,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;
@@ -311,12 +329,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.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.