Merge tag 'sunxi-clk-for-3.13' of https://github.com/mripard/linux into clk-next...
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / pinctrl / pinconf-generic.c
index 8594f03..55a0ebe 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/of.h>
 #include "core.h"
 #include "pinconf.h"
+#include "pinctrl-utils.h"
 
 #ifdef CONFIG_DEBUG_FS
 
@@ -236,4 +237,99 @@ out:
        kfree(cfg);
        return ret;
 }
+
+int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+               struct device_node *np, struct pinctrl_map **map,
+               unsigned *reserved_maps, unsigned *num_maps,
+               enum pinctrl_map_type type)
+{
+       int ret;
+       const char *function;
+       struct device *dev = pctldev->dev;
+       unsigned long *configs = NULL;
+       unsigned num_configs = 0;
+       unsigned reserve;
+       struct property *prop;
+       const char *group;
+
+       ret = of_property_read_string(np, "function", &function);
+       if (ret < 0) {
+               /* EINVAL=missing, which is fine since it's optional */
+               if (ret != -EINVAL)
+                       dev_err(dev, "could not parse property function\n");
+               function = NULL;
+       }
+
+       ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs);
+       if (ret < 0) {
+               dev_err(dev, "could not parse node property\n");
+               return ret;
+       }
+
+       reserve = 0;
+       if (function != NULL)
+               reserve++;
+       if (num_configs)
+               reserve++;
+       ret = of_property_count_strings(np, "pins");
+       if (ret < 0) {
+               dev_err(dev, "could not parse property pins\n");
+               goto exit;
+       }
+       reserve *= ret;
+
+       ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps,
+                       num_maps, reserve);
+       if (ret < 0)
+               goto exit;
+
+       of_property_for_each_string(np, "pins", prop, group) {
+               if (function) {
+                       ret = pinctrl_utils_add_map_mux(pctldev, map,
+                                       reserved_maps, num_maps, group,
+                                       function);
+                       if (ret < 0)
+                               goto exit;
+               }
+
+               if (num_configs) {
+                       ret = pinctrl_utils_add_map_configs(pctldev, map,
+                                       reserved_maps, num_maps, group, configs,
+                                       num_configs, type);
+                       if (ret < 0)
+                               goto exit;
+               }
+       }
+       ret = 0;
+
+exit:
+       kfree(configs);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pinconf_generic_dt_subnode_to_map);
+
+int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev,
+               struct device_node *np_config, struct pinctrl_map **map,
+               unsigned *num_maps, enum pinctrl_map_type type)
+{
+       unsigned reserved_maps;
+       struct device_node *np;
+       int ret;
+
+       reserved_maps = 0;
+       *map = NULL;
+       *num_maps = 0;
+
+       for_each_child_of_node(np_config, np) {
+               ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map,
+                                       &reserved_maps, num_maps, type);
+               if (ret < 0) {
+                       pinctrl_utils_dt_free_map(pctldev, *map, *num_maps);
+                       return ret;
+               }
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map);
+
 #endif