[PATCH v4 06/29] bus: Introduce simple-platorm-bus

Herve Codina
2025-10-15T07:17:23Z

The simple-pm-bus driver handles several simple busses. When it is used
with busses other than a compatible "simple-pm-bus", it doesn't populate
its child devices during its probe.

This confuses fw_devlink and results in wrong or missing devlinks.

Once a driver is bound to a device and the probe() has been called,
device_links_driver_bound() is called.

This function performs operation based on the following assumption:
If a child firmware node of the bound device is not added as a
device, it will never be added.

Among operations done on fw_devlinks of those "never be added" devices,
device_links_driver_bound() changes their supplier.

With devices attached to a simple-bus compatible device, this change
leads to wrong devlinks where supplier of devices points to the device
parent (i.e. simple-bus compatible device) instead of the device itself
(i.e. simple-bus child).

When the device attached to the simple-bus is removed, because devlinks
are not correct, its consumers are not removed first.

In order to have correct devlinks created, make the simple-bus driver
compliant with the devlink assumption and create its child devices
during its probe.

Doing that leads to other issues due to the fact that simple-bus is
closely related to of_platform_populate().

Indeed, of_platform_populate() can probe child devices if a simple-bus
compatible node is detected. This behavior is expected by some drivers
such as some MFD drivers. Those drivers perform some operations in their
probe() but rely on the core (simple-mfd, simple-bus compatible) to
populate child devices [1].

Avoiding recursive probing in of_platform_populate() and let the
simple-bus driver probe its child devices will break some system.

For this reason, keep the current behavior of the simple-bus driver and
of_platform_populate() as they are and introduce simple-platform-bus
driver.

This driver doesn't interfere with of_platform_populate() and populates
child devices during its probe() as expected by fw_devlink.

[1] https://lore.kernel.org/all/20250715095201.1bcb4ab7@bootlin.com/

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
drivers/bus/simple-pm-bus.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)

diff --git a/drivers/bus/simple-pm-bus.c b/drivers/bus/simple-pm-bus.c
index d8e029e7e53f..e975685d2b07 100644
--- a/drivers/bus/simple-pm-bus.c
+++ b/drivers/bus/simple-pm-bus.c
@@ -158,5 +158,42 @@ static struct platform_driver simple_pm_bus_driver = {

module_platform_driver(simple_pm_bus_driver);

+static int simple_platform_bus_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+
+ if (np)
+ of_platform_populate(np, NULL, NULL, dev);
+
+ return 0;
+}
+
+static void simple_platform_bus_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+
+ if (np)
+ of_platform_depopulate(dev);
+}
+
+static const struct of_device_id simple_platform_bus_of_match[] = {
+ { .compatible = "simple-platform-bus", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, simple_platform_bus_of_match);
+
+static struct platform_driver simple_platform_bus_driver = {
+ .probe = simple_platform_bus_probe,
+ .remove = simple_platform_bus_remove,
+ .driver = {
+ .name = "simple-platform-bus",
+ .of_match_table = simple_platform_bus_of_match,
+ },
+};
+
+module_platform_driver(simple_platform_bus_driver);
+
MODULE_DESCRIPTION("Simple Power-Managed Bus Driver");
MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
--
2.51.0