Merge patch series "dm: core: Support same compatible in host/gadget musb drivers"

Markus Schneider-Pargmann (TI.com) <msp@baylibre.com> 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
This commit is contained in:
Tom Rini
2026-01-28 09:21:17 -06:00
4 changed files with 81 additions and 37 deletions

View File

@@ -457,6 +457,10 @@
mux-control-names = "mux0"; mux-control-names = "mux0";
}; };
multimatch-test {
compatible = "sandbox,multimatch-test";
};
phy_provider0: gen_phy@0 { phy_provider0: gen_phy@0 {
compatible = "sandbox,phy"; compatible = "sandbox,phy";
#phy-cells = <1>; #phy-cells = <1>;

View File

@@ -204,10 +204,8 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp,
const struct udevice_id *id; const struct udevice_id *id;
struct driver *entry; struct driver *entry;
struct udevice *dev; struct udevice *dev;
bool found = false;
const char *name, *compat_list, *compat; const char *name, *compat_list, *compat;
int compat_length, i; int compat_length, i;
int result = 0;
int ret = 0; int ret = 0;
if (devp) 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", log_debug(" - attempt to match compatible string '%s'\n",
compat); compat);
id = NULL;
for (entry = driver; entry != driver + n_ents; entry++) { for (entry = driver; entry != driver + n_ents; entry++) {
/* Search for drivers with matching drv or existing of_match */
if (drv) { if (drv) {
if (drv != entry) if (drv != entry)
continue; continue;
if (!entry->of_match) } else if (!entry->of_match) {
break; continue;
} }
ret = driver_check_compatible(entry->of_match, &id,
compat);
if (!ret)
break;
}
if (entry == driver + n_ents)
continue;
if (pre_reloc_only) { id = NULL;
if (!ofnode_pre_reloc(node) && if (entry->of_match) {
!(entry->flags & DM_FLAG_PRE_RELOC)) { ret = driver_check_compatible(entry->of_match, &id,
log_debug("Skipping device pre-relocation\n"); compat);
return 0; 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) if (devp)
*devp = dev; *devp = dev;
return 0;
} }
break;
} }
if (!found && !result && ret != -ENODEV) if (ret != -ENODEV)
log_debug("No match for node '%s'\n", name); log_debug("No match for node '%s'\n", name);
return result; return 0;
} }
#endif #endif

View File

@@ -1410,3 +1410,18 @@ static int dm_test_try_first_device(struct unit_test_state *uts)
return 0; return 0;
} }
DM_TEST(dm_test_try_first_device, 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);

View File

@@ -197,3 +197,29 @@ U_BOOT_DRIVER(test_act_dma_vital_clk_drv) = {
.unbind = test_manual_unbind, .unbind = test_manual_unbind,
.flags = DM_FLAG_VITAL | DM_FLAG_ACTIVE_DMA, .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,
};