This patch adds device connection parsing in of_platform_populate().

TODO:
 - How to free the devcon memories?
 - How to remove the devcon instances?

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda...@renesas.com>
---
 drivers/of/platform.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/of.h    |  1 +
 2 files changed, 67 insertions(+)

diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index c00d81d..41c018d 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/of_graph.h>
 #include <linux/of_iommu.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
@@ -326,6 +327,63 @@ static const struct of_dev_auxdata *of_dev_lookup(const 
struct of_dev_auxdata *l
        return NULL;
 }
 
+static int of_parse_device_connection(struct device_node *np)
+{
+       struct device_node *child_ep, *parent, *remote_parent;
+       struct platform_device *pdev, *remote_pdev;
+       struct device_connection *devcon = NULL;
+       const char *id;
+
+       if (of_node_check_flag(np, OF_DEVICE_CONNECTED)) {
+               pr_debug("%s() - skipping %pOF, already device connected\n",
+                       __func__, np);
+               return 0;
+       }
+
+       of_node_set_flag(np, OF_DEVICE_CONNECTED);
+
+       for_each_endpoint_of_node(np, child_ep) {
+               if (of_property_read_string(child_ep, "device-connection-id",
+                                           &id) < 0)
+                       continue;
+
+               remote_parent = of_graph_get_remote_port_parent(child_ep);
+               if (!remote_parent)
+                       return 0;
+
+               parent = of_graph_get_port_parent(child_ep);
+               if (!parent)
+                       return 0;
+
+               pdev = of_find_device_by_node(parent);
+               if (!pdev)
+                       return 0;
+
+               /*
+                * WARN_ON in really_probe() may happen if devm_kzalloc is
+                * used. TODO: How to free this?
+                */
+               devcon = kzalloc(sizeof(*devcon), GFP_KERNEL);
+               if (!devcon)
+                       return -ENOMEM;
+
+               devcon->id = id;
+               remote_pdev = of_find_device_by_node(remote_parent);
+               if (!remote_pdev) {
+                       kfree(devcon);
+                       return 0;
+               }
+
+               devcon->endpoint[0] = dev_name(&pdev->dev);
+               devcon->endpoint[1] = dev_name(&remote_pdev->dev);
+
+               /* TODO: How to remove the connection? */
+               device_connection_add(devcon);
+       }
+
+       return 0;
+}
+
 /**
  * of_platform_bus_create() - Create a device for a node and its children.
  * @bus: device node of the bus to instantiate
@@ -477,6 +535,14 @@ int of_platform_populate(struct device_node *root,
        }
        of_node_set_flag(root, OF_POPULATED_BUS);
 
+       for_each_child_of_node(root, child) {
+               rc = of_parse_device_connection(child);
+               if (rc) {
+                       of_node_put(child);
+                       break;
+               }
+       }
+
        of_node_put(root);
        return rc;
 }
diff --git a/include/linux/of.h b/include/linux/of.h
index 4d25e4f..30aa103 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -143,6 +143,7 @@ static inline void of_node_put(struct device_node *node) { }
 #define OF_DETACHED    2 /* node has been detached from the device tree */
 #define OF_POPULATED   3 /* device already created for the node */
 #define OF_POPULATED_BUS       4 /* of_platform_populate recursed to children 
of this node */
+#define OF_DEVICE_CONNECTED    5 /* checked devcon on of_platform_populate */
 
 #define OF_BAD_ADDR    ((u64)-1)
 
-- 
1.9.1

Reply via email to