[RFC PATCH 4/6] of: Extract alloc/add functions from of_platform_device_create_pdata()

Stephen Boyd
2025-01-08T01:28:55Z

Allow drivers to modify the 'struct device' for a device node by
splitting of_platform_device_create_pdata() into two functions. The
first function, of_platform_device_alloc(), allocates the platform
device and the second function, of_platform_device_add(), adds the
platform device to the platform bus. SoC power management drivers can
use these APIs to allocate a platform device for a node underneath the
soc node, attach pmdomains and/or set the device as runtime PM active,
and finally add the platform device to the platform bus.

Cc: Rob Herring <robh@kernel.org>
Cc: Saravana Kannan <saravanak@google.com>
Cc: <devicetree@vger.kernel.org>
Cc: Bjorn Andersson <andersson@kernel.org>
Cc: Konrad Dybcio <konradybcio@kernel.org>
Cc: <linux-arm-msm@vger.kernel.org>
Signed-off-by: Stephen Boyd <swboyd@chromium.org>
---
drivers/of/platform.c | 80 ++++++++++++++++++++++++++++++-------
include/linux/of_platform.h | 14 +++++++
2 files changed, 79 insertions(+), 15 deletions(-)

diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 63a80c30d515..d8ee2d38a382 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -138,6 +138,66 @@ struct platform_device *of_device_alloc(struct device_node *np,
}
EXPORT_SYMBOL(of_device_alloc);

+/**
+ * of_platform_device_alloc - Alloc and initialize an of_device
+ * @np: pointer to node to create device for
+ * @bus_id: name to assign device
+ * @parent: Linux device model parent device.
+ *
+ * Return: Pointer to created platform device, or NULL if a device was not
+ * allocated. Unavailable devices will not get allocated.
+ */
+struct platform_device *
+of_platform_device_alloc(struct device_node *np, const char *bus_id,
+ struct device *parent)
+{
+ struct platform_device *ofdev;
+
+ pr_debug("alloc platform device: %pOF\n", np);
+
+ if (!of_device_is_available(np) ||
+ of_node_test_and_set_flag(np, OF_POPULATED))
+ return NULL;
+
+ ofdev = of_device_alloc(np, bus_id, parent);
+ if (!ofdev) {
+ of_node_clear_flag(np, OF_POPULATED);
+ return ofdev;
+ }
+
+ ofdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+ if (!ofdev->dev.dma_mask)
+ ofdev->dev.dma_mask = &ofdev->dev.coherent_dma_mask;
+ ofdev->dev.bus = &platform_bus_type;
+ of_msi_configure(&ofdev->dev, ofdev->dev.of_node);
+
+ return ofdev;
+}
+EXPORT_SYMBOL(of_platform_device_alloc);
+
+/**
+ * of_platform_device_add - Add an of_device to the platform bus
+ * @ofdev: of_device to add
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int of_platform_device_add(struct platform_device *ofdev)
+{
+ struct device_node *np = ofdev->dev.of_node;
+ int ret;
+
+ pr_debug("adding platform device: %pOF\n", np);
+
+ ret = of_device_add(ofdev);
+ if (ret) {
+ platform_device_put(ofdev);
+ of_node_clear_flag(np, OF_POPULATED);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(of_platform_device_add);
+
/**
* of_platform_device_create_pdata - Alloc, initialize and register an of_device
* @np: pointer to node to create device for
@@ -154,29 +214,19 @@ static struct platform_device *of_platform_device_create_pdata(
void *platform_data,
struct device *parent)
{
+ int ret;
struct platform_device *dev;

pr_debug("create platform device: %pOF\n", np);

- if (!of_device_is_available(np) ||
- of_node_test_and_set_flag(np, OF_POPULATED))
+ dev = of_platform_device_alloc(np, bus_id, parent);
+ if (!dev)
return NULL;

- dev = of_device_alloc(np, bus_id, parent);
- if (!dev)
- goto err_clear_flag;
-
- dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
- if (!dev->dev.dma_mask)
- dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
- dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;
- of_msi_configure(&dev->dev, dev->dev.of_node);
-
- if (of_device_add(dev) != 0) {
- platform_device_put(dev);
+ ret = of_platform_device_add(dev);
+ if (ret)
goto err_clear_flag;
- }

return dev;

diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index 17471ef8e092..e55c1371b560 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -71,6 +71,10 @@ extern int of_platform_bus_probe(struct device_node *root,

#ifdef CONFIG_OF_ADDRESS
/* Platform devices and busses creation */
+extern struct platform_device *of_platform_device_alloc(struct device_node *np,
+ const char *bus_id,
+ struct device *parent);
+extern int of_platform_device_add(struct platform_device *ofdev);
extern struct platform_device *of_platform_device_create(struct device_node *np,
const char *bus_id,
struct device *parent);
@@ -91,6 +95,16 @@ extern int devm_of_platform_populate(struct device *dev);
extern void devm_of_platform_depopulate(struct device *dev);
#else
/* Platform devices and busses creation */
+static inline struct platform_device *of_platform_device_alloc(struct device_node *np,
+ const char *bus_id,
+ struct device *parent)
+{
+ return NULL;
+}
+static inline int of_platform_device_add(struct platform_device *ofdev)
+{
+ return -ENODEV;
+}
static inline struct platform_device *of_platform_device_create(struct device_node *np,
const char *bus_id,
struct device *parent)
--