summaryrefslogtreecommitdiff
path: root/drivers/base/core.c
diff options
context:
space:
mode:
authorHerve Codina <herve.codina@bootlin.com>2025-02-24 15:13:51 +0100
committerBjorn Helgaas <bhelgaas@google.com>2025-02-28 15:12:58 -0600
commit3b62449da444502d8b87bf090d8ec4a57d47eda5 (patch)
tree28f825bfea53cc17ffe5df01100e66102c182029 /drivers/base/core.c
parent2014c95afecee3e76ca4a56956a936e23283f05b (diff)
driver core: Introduce device_{add,remove}_of_node()
An of_node can be set to a device using device_set_node(), which does not prevent any of_node and/or fwnode overwrites. When adding an of_node on an already present device, the following operations need to be done: - Attach the of_node only if no of_node is already attached - Attach the of_node as a fwnode if no fwnode were already attached This is the purpose of device_add_of_node(). device_remove_of_node() reverts the operations done by device_add_of_node(). Link: https://lore.kernel.org/r/20250224141356.36325-2-herve.codina@bootlin.com Signed-off-by: Herve Codina <herve.codina@bootlin.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Rob Herring (Arm) <robh@kernel.org> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r--drivers/base/core.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 5a1f05198114..49eb5aaf19cc 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -5171,6 +5171,67 @@ void set_secondary_fwnode(struct device *dev, struct fwnode_handle *fwnode)
EXPORT_SYMBOL_GPL(set_secondary_fwnode);
/**
+ * device_remove_of_node - Remove an of_node from a device
+ * @dev: device whose device tree node is being removed
+ */
+void device_remove_of_node(struct device *dev)
+{
+ dev = get_device(dev);
+ if (!dev)
+ return;
+
+ if (!dev->of_node)
+ goto end;
+
+ if (dev->fwnode == of_fwnode_handle(dev->of_node))
+ dev->fwnode = NULL;
+
+ of_node_put(dev->of_node);
+ dev->of_node = NULL;
+
+end:
+ put_device(dev);
+}
+EXPORT_SYMBOL_GPL(device_remove_of_node);
+
+/**
+ * device_add_of_node - Add an of_node to an existing device
+ * @dev: device whose device tree node is being added
+ * @of_node: of_node to add
+ *
+ * Return: 0 on success or error code on failure.
+ */
+int device_add_of_node(struct device *dev, struct device_node *of_node)
+{
+ int ret;
+
+ if (!of_node)
+ return -EINVAL;
+
+ dev = get_device(dev);
+ if (!dev)
+ return -EINVAL;
+
+ if (dev->of_node) {
+ dev_err(dev, "Cannot replace node %pOF with %pOF\n",
+ dev->of_node, of_node);
+ ret = -EBUSY;
+ goto end;
+ }
+
+ dev->of_node = of_node_get(of_node);
+
+ if (!dev->fwnode)
+ dev->fwnode = of_fwnode_handle(of_node);
+
+ ret = 0;
+end:
+ put_device(dev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(device_add_of_node);
+
+/**
* device_set_of_node_from_dev - reuse device-tree node of another device
* @dev: device whose device-tree node is being set
* @dev2: device whose device-tree node is being reused