So the GPIO subsystem can be queried about the dependencies of nodes
that consume GPIOs, as specified in bindings/gpio/gpio.txt.

Signed-off-by: Tomeu Vizoso <[email protected]>
---
 drivers/gpio/gpiolib-sysfs.c | 81 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index b57ed8e..d0a7fb1 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -7,6 +7,7 @@
 #include <linux/interrupt.h>
 #include <linux/kdev_t.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 
 #include "gpiolib.h"
 
@@ -515,6 +516,85 @@ done:
        return status ? : len;
 }
 
+static bool strends(const char *str, const char *postfix)
+{
+       if (strlen(str) < strlen(postfix))
+               return false;
+
+       return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
+}
+
+static void add_dependency(struct fwnode_handle *fwnode,
+                          struct list_head *list)
+{
+       struct fwnode_dependency *dep;
+
+       dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+       if (!dep)
+               return;
+
+       INIT_LIST_HEAD(&dep->dependency);
+       dep->fwnode = fwnode;
+
+       list_add_tail(&dep->dependency, list);
+}
+
+struct list_head *gpio_get_dependencies(struct fwnode_handle *fwnode)
+{
+       struct device_node *np = of_node(fwnode);
+       struct list_head *list = NULL;
+       struct property *pp;
+       struct of_phandle_args pspec;
+       int count, i, ret;
+
+       if (!is_of_node(fwnode))
+               return NULL;
+
+       np = of_node(fwnode);
+       if (!np)
+               return NULL;
+
+       list = kzalloc(sizeof(*list), GFP_KERNEL);
+       if (!list)
+               return NULL;
+
+       INIT_LIST_HEAD(list);
+
+       for_each_property_of_node(np, pp) {
+               if (strcmp(pp->name, "gpio") &&
+                   !strends(pp->name, "-gpios") &&
+                   !strends(pp->name, "-gpio"))
+                       continue;
+
+               count = of_count_phandle_with_args(np, pp->name,
+                                                  "#gpio-cells");
+               for (i = 0; i < count; i++) {
+                       ret = of_parse_phandle_with_args(np, pp->name,
+                                                        "#gpio-cells", i,
+                                                        &pspec);
+                       if (ret || !pspec.np)
+                               continue;
+
+                       add_dependency(&pspec.np->fwnode, list);
+
+                       of_node_put(pspec.np);
+               }
+       }
+
+       for (i = 0;; i++) {
+               ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,
+                                                      i, &pspec);
+               if (ret)
+                       break;
+
+               add_dependency(&pspec.np->fwnode, list);
+
+               of_node_put(pspec.np);
+       }
+
+       return list;
+}
+
 static struct class_attribute gpio_class_attrs[] = {
        __ATTR(export, 0200, NULL, export_store),
        __ATTR(unexport, 0200, NULL, unexport_store),
@@ -526,6 +606,7 @@ static struct class gpio_class = {
        .owner =        THIS_MODULE,
 
        .class_attrs =  gpio_class_attrs,
+       .get_dependencies = gpio_get_dependencies,
 };
 
 
-- 
2.4.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to