]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - drivers/gpio/gpiolib-of.c
Merge tag 'gpio-v4.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux...
[mirror_ubuntu-zesty-kernel.git] / drivers / gpio / gpiolib-of.c
index 4650bf830d6b6306f96e309d4f2782da8a859575..a6c67c6b468045f9325e6249019f0c1080a46398 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/of_gpio.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/slab.h>
+#include <linux/gpio/machine.h>
 
 #include "gpiolib.h"
 
@@ -117,6 +118,114 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
 }
 EXPORT_SYMBOL(of_get_named_gpio_flags);
 
+/**
+ * of_get_gpio_hog() - Get a GPIO hog descriptor, names and flags for GPIO API
+ * @np:                device node to get GPIO from
+ * @name:      GPIO line name
+ * @lflags:    gpio_lookup_flags - returned from of_find_gpio() or
+ *             of_get_gpio_hog()
+ * @dflags:    gpiod_flags - optional GPIO initialization flags
+ *
+ * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno
+ * value on the error condition.
+ */
+static struct gpio_desc *of_get_gpio_hog(struct device_node *np,
+                                 const char **name,
+                                 enum gpio_lookup_flags *lflags,
+                                 enum gpiod_flags *dflags)
+{
+       struct device_node *chip_np;
+       enum of_gpio_flags xlate_flags;
+       struct gpio_desc *desc;
+       struct gg_data gg_data = {
+               .flags = &xlate_flags,
+       };
+       u32 tmp;
+       int i, ret;
+
+       chip_np = np->parent;
+       if (!chip_np)
+               return ERR_PTR(-EINVAL);
+
+       xlate_flags = 0;
+       *lflags = 0;
+       *dflags = 0;
+
+       ret = of_property_read_u32(chip_np, "#gpio-cells", &tmp);
+       if (ret)
+               return ERR_PTR(ret);
+
+       if (tmp > MAX_PHANDLE_ARGS)
+               return ERR_PTR(-EINVAL);
+
+       gg_data.gpiospec.args_count = tmp;
+       gg_data.gpiospec.np = chip_np;
+       for (i = 0; i < tmp; i++) {
+               ret = of_property_read_u32_index(np, "gpios", i,
+                                          &gg_data.gpiospec.args[i]);
+               if (ret)
+                       return ERR_PTR(ret);
+       }
+
+       gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);
+       if (!gg_data.out_gpio) {
+               if (np->parent == np)
+                       return ERR_PTR(-ENXIO);
+               else
+                       return ERR_PTR(-EINVAL);
+       }
+
+       if (xlate_flags & OF_GPIO_ACTIVE_LOW)
+               *lflags |= GPIO_ACTIVE_LOW;
+
+       if (of_property_read_bool(np, "input"))
+               *dflags |= GPIOD_IN;
+       else if (of_property_read_bool(np, "output-low"))
+               *dflags |= GPIOD_OUT_LOW;
+       else if (of_property_read_bool(np, "output-high"))
+               *dflags |= GPIOD_OUT_HIGH;
+       else {
+               pr_warn("GPIO line %d (%s): no hogging state specified, bailing out\n",
+                       desc_to_gpio(gg_data.out_gpio), np->name);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (name && of_property_read_string(np, "line-name", name))
+               *name = np->name;
+
+       desc = gg_data.out_gpio;
+
+       return desc;
+}
+
+/**
+ * of_gpiochip_scan_hogs - Scan gpio-controller and apply GPIO hog as requested
+ * @chip:      gpio chip to act on
+ *
+ * This is only used by of_gpiochip_add to request/set GPIO initial
+ * configuration.
+ */
+static void of_gpiochip_scan_hogs(struct gpio_chip *chip)
+{
+       struct gpio_desc *desc = NULL;
+       struct device_node *np;
+       const char *name;
+       enum gpio_lookup_flags lflags;
+       enum gpiod_flags dflags;
+
+       for_each_child_of_node(chip->of_node, np) {
+               if (!of_property_read_bool(np, "gpio-hog"))
+                       continue;
+
+               desc = of_get_gpio_hog(np, &name, &lflags, &dflags);
+               if (IS_ERR(desc))
+                       continue;
+
+               if (gpiod_hog(desc, name, lflags, dflags))
+                       continue;
+       }
+}
+
 /**
  * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
  * @gc:                pointer to the gpio_chip structure
@@ -326,6 +435,8 @@ void of_gpiochip_add(struct gpio_chip *chip)
 
        of_gpiochip_add_pin_range(chip);
        of_node_get(chip->of_node);
+
+       of_gpiochip_scan_hogs(chip);
 }
 
 void of_gpiochip_remove(struct gpio_chip *chip)