[PATCH v1 3/6] usb: skip host-only devices when picking the ehci gadget controller
Stefan Eichenberger <[email protected]>
| Newsgroups | org.u-boot-project.lists.u-boot |
|---|---|
| Message-ID | <[email protected]> |
From: Stefan Eichenberger <[email protected]> The i.MX95 SoC has two USB controllers, a DWC3 host-only controller and a ChipIdea OTG controller. The latter is the one that can be used for USB gadget functionality. However, U-Boot incorrectly selects the host-only controller when attempting to set up a USB gadget, leading to failures in gadget mode. Iterate over usb devices and skipping any that are host-only when selecting the controller for gadget mode. This ensures that a device only or otg controller is used for USB gadget functionality. Verified on Verdin iMX95 hardware: "ums 0 mmc 0" now correctly flips the ChipIdea OTG controller into device mode and enumerates on the host PC. Fixes: 821ca608d816 ("usb: Use the first available device for ehci_gadget") Signed-off-by: Stefan Eichenberger <[email protected]> --- drivers/usb/host/usb-uclass.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index 1c74d6fd39a..b9e9ef7e86a 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -18,6 +18,7 @@ #include <dm/device-internal.h> #include <dm/lists.h> #include <dm/uclass-internal.h> +#include <linux/usb/otg.h> #include <time.h> static bool asynch_allowed; @@ -484,10 +485,23 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp) struct udevice *dev; int ret; - /* Find the old device and remove it */ + /* + * Find the first UCLASS_USB device that isn't host-only. SoCs can + * have more than one UCLASS_USB controller (e.g. i.MX95, where a + * host-only DWC3 port and the ChipIdea OTG port both register under + * UCLASS_USB); taking whichever device happens to be first could + * pick the host-only controller instead of the OTG-capable one this + * is actually meant to flip into device mode. + */ ret = uclass_find_first_device(UCLASS_USB, &dev); if (ret) return ret; + while (dev && usb_get_dr_mode(dev_ofnode(dev)) == USB_DR_MODE_HOST) + uclass_find_next_device(&dev); + if (!dev) + return -ENODEV; + + /* Remove the old device */ ret = device_remove(dev, DM_REMOVE_NORMAL); if (ret) return ret; @@ -507,10 +521,15 @@ int usb_remove_ehci_gadget(struct ehci_ctrl **ctlrp) struct udevice *dev; int ret; - /* Find the old device and remove it */ + /* Find the same non-host-only device usb_setup_ehci_gadget() used */ ret = uclass_find_first_device(UCLASS_USB, &dev); if (ret) return ret; + while (dev && usb_get_dr_mode(dev_ofnode(dev)) == USB_DR_MODE_HOST) + uclass_find_next_device(&dev); + if (!dev) + return -ENODEV; + ret = device_remove(dev, DM_REMOVE_NORMAL); if (ret) return ret; -- 2.55.0