[PATCH 1/4] dm: core: Support multiple drivers with same compatibles

Markus Schneider-Pargmann (TI.com)
2025-11-26T22:50:31Z

Currently once a driver matched the compatible string of a device, other
drivers are ignored. If the first matching driver returns -ENODEV, no
other possibly matching drivers are iterated with that compatible of the
device. Instead the next compatible in the list of compatibles is
selected, assuming only one driver matches one compatible at a time.

To be able to use the bind function to return -ENODEV and continue
matching other drivers with the same compatible, move the for loop a bit
to continue the for loop after -ENODEV was returned.

This is required for ti-musb-host and ti-musb-peripheral which both
match on the same device but differ based on the dr_mode DT property.
Depending on this property, the driver is either UCLASS_USB or
UCLASS_USB_GADGET_GENERIc. By checking the DT property in the bind
function and returning -ENODEV the other driver can probe instead.

Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
---
drivers/core/lists.c | 62 +++++++++++++++++++++++++++-------------------------
1 file changed, 32 insertions(+), 30 deletions(-)

diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index c7be504b6fc69ec2870a6766eed35cb9eba46a97..144e31286b3bb53a90b4f8bb0d3fba6e25a47f9e 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -237,8 +237,9 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp,
log_debug(" - attempt to match compatible string '%s'\n",
compat);

- id = NULL;
for (entry = driver; entry != driver + n_ents; entry++) {
+ id = NULL;
+
if (drv) {
if (drv != entry)
continue;
@@ -247,39 +248,40 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp,
}
ret = driver_check_compatible(entry->of_match, &id,
compat);
- if (!ret)
- break;
+ if (ret)
+ continue;
+ if (pre_reloc_only) {
+ if (!ofnode_pre_reloc(node) &&
+ !(entry->flags & DM_FLAG_PRE_RELOC)) {
+ log_debug("Skipping device pre-relocation\n");
+ return 0;
+ }
+ }
+
+ if (entry->of_match)
+ log_debug(" - found match at driver '%s' for '%s'\n",
+ entry->name, id->compatible);
+ ret = device_bind_with_driver_data(parent, entry, name,
+ id ? id->data : 0, node,
+ &dev);
+ if (ret == -ENODEV) {
+ log_debug("Driver '%s' refuses to bind\n", entry->name);
+ continue;
+ }
+ if (ret) {
+ dm_warn("Error binding driver '%s': %d\n", entry->name,
+ ret);
+ return log_msg_ret("bind", ret);
+ }
+
+ found = true;
+ if (devp)
+ *devp = dev;
+ break;
}
if (entry == driver + n_ents)
continue;

- if (pre_reloc_only) {
- if (!ofnode_pre_reloc(node) &&
- !(entry->flags & DM_FLAG_PRE_RELOC)) {
- log_debug("Skipping device pre-relocation\n");
- return 0;
- }
- }
-
- if (entry->of_match)
- log_debug(" - found match at driver '%s' for '%s'\n",
- entry->name, id->compatible);
- ret = device_bind_with_driver_data(parent, entry, name,
- id ? id->data : 0, node,
- &dev);
- if (ret == -ENODEV) {
- log_debug("Driver '%s' refuses to bind\n", entry->name);
- continue;
- }
- if (ret) {
- dm_warn("Error binding driver '%s': %d\n", entry->name,
- ret);
- return log_msg_ret("bind", ret);
- } else {
- found = true;
- if (devp)
- *devp = dev;
- }
break;
}

--
2.51.0