summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2026-01-28 09:21:17 -0600
committerTom Rini <[email protected]>2026-01-28 09:21:17 -0600
commite8ec8d980a31c4a1d665e4aa9089d6aa27cb0d0b (patch)
tree629a81743f41c1ab97ddc1ce75f6a192ab7ab788
parentcd4f4f74213aa02df1a0f2c533cd2cabfac6aa2e (diff)
parentc7e0e3fd33ca9809605a6de0a58809daf1224bff (diff)
Merge patch series "dm: core: Support same compatible in host/gadget musb drivers"
Markus Schneider-Pargmann (TI.com) <[email protected]> says: musb currently uses a wrapper driver that binds on the parent device of the actual musb devices to manage the differentiation between gadget and host modes. However in the upstream devicetree this parent devicetree node can not be used to match the wrapper driver. To be able to probe the musb devices in host/gadget mode directly, this series introduces support for returning -ENODEV in bind functions resulting in iterating the remaining drivers potentially binding to other drivers that match the compatible. Link: https://lore.kernel.org/r/20260127-topic-musb-probing-v2026-01-v4-0-ea3201e0f809@baylibre.com
-rw-r--r--arch/sandbox/dts/test.dts4
-rw-r--r--drivers/core/lists.c75
-rw-r--r--test/dm/core.c15
-rw-r--r--test/dm/test-driver.c26
4 files changed, 82 insertions, 38 deletions
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index cd53c170171..b7402d7042a 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -457,6 +457,10 @@
mux-control-names = "mux0";
};
+ multimatch-test {
+ compatible = "sandbox,multimatch-test";
+ };
+
phy_provider0: gen_phy@0 {
compatible = "sandbox,phy";
#phy-cells = <1>;
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index c7be504b6fc..2545dc142f6 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -204,10 +204,8 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp,
const struct udevice_id *id;
struct driver *entry;
struct udevice *dev;
- bool found = false;
const char *name, *compat_list, *compat;
int compat_length, i;
- int result = 0;
int ret = 0;
if (devp)
@@ -237,55 +235,56 @@ 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++) {
+ /* Search for drivers with matching drv or existing of_match */
if (drv) {
if (drv != entry)
continue;
- if (!entry->of_match)
- break;
+ } else if (!entry->of_match) {
+ continue;
}
- ret = driver_check_compatible(entry->of_match, &id,
- compat);
- if (!ret)
- 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;
+
+ id = NULL;
+ if (entry->of_match) {
+ ret = driver_check_compatible(entry->of_match, &id,
+ compat);
+ if (ret)
+ continue;
+ log_debug(" - found match at driver '%s' for '%s'\n",
+ entry->name, id->compatible);
+ }
+
+ if (pre_reloc_only) {
+ if (!ofnode_pre_reloc(node) &&
+ !(entry->flags & DM_FLAG_PRE_RELOC)) {
+ log_debug("Skipping device pre-relocation\n");
+ return 0;
+ }
+ }
+
+ ret = device_bind_with_driver_data(parent, entry, name,
+ id ? id->data : 0, node,
+ &dev);
+ if (!drv && 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);
}
- }
- 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;
+
+ return 0;
}
- break;
}
- if (!found && !result && ret != -ENODEV)
+ if (ret != -ENODEV)
log_debug("No match for node '%s'\n", name);
- return result;
+ return 0;
}
#endif
diff --git a/test/dm/core.c b/test/dm/core.c
index 53693f4f7ed..78ee14af228 100644
--- a/test/dm/core.c
+++ b/test/dm/core.c
@@ -1410,3 +1410,18 @@ static int dm_test_try_first_device(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_try_first_device, 0);
+
+/* Test that all drivers are iterated when bind returns -ENODEV */
+static int dm_test_multimatch(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+
+ ut_assertok(uclass_find_device_by_name(UCLASS_TEST, "multimatch-test",
+ &dev));
+ ut_assertnonnull(dev);
+ ut_asserteq_str("test_multimatch_second", dev->driver->name);
+ ut_asserteq(2, dm_testdrv_op_count[DM_TEST_OP_BIND]);
+
+ return 0;
+}
+DM_TEST(dm_test_multimatch, UTF_SCAN_FDT);
diff --git a/test/dm/test-driver.c b/test/dm/test-driver.c
index 759de3a5f77..d628a6d766f 100644
--- a/test/dm/test-driver.c
+++ b/test/dm/test-driver.c
@@ -197,3 +197,29 @@ U_BOOT_DRIVER(test_act_dma_vital_clk_drv) = {
.unbind = test_manual_unbind,
.flags = DM_FLAG_VITAL | DM_FLAG_ACTIVE_DMA,
};
+
+static int test_multimatch_first_bind(struct udevice *dev)
+{
+ dm_testdrv_op_count[DM_TEST_OP_BIND]++;
+
+ return -ENODEV;
+}
+
+static const struct udevice_id test_multimatch_ids[] = {
+ { .compatible = "sandbox,multimatch-test" },
+ { }
+};
+
+U_BOOT_DRIVER(test_multimatch_first) = {
+ .name = "test_multimatch_first",
+ .id = UCLASS_TEST,
+ .of_match = test_multimatch_ids,
+ .bind = test_multimatch_first_bind,
+};
+
+U_BOOT_DRIVER(test_multimatch_second) = {
+ .name = "test_multimatch_second",
+ .id = UCLASS_TEST,
+ .of_match = test_multimatch_ids,
+ .bind = test_manual_bind,
+};