summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/pinctrl/pinconf-generic.c96
-rw-r--r--include/linux/pinctrl/pinconf-generic.h6
2 files changed, 102 insertions, 0 deletions
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 8594f033ac21..d9536caa9c41 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -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)
+{
+ 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 ti,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 ti,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, PIN_MAP_TYPE_CONFIGS_PIN);
+ 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)
+{
+ 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);
+ 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
diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h
index bf7e989abcb5..a472b93292a3 100644
--- a/include/linux/pinctrl/pinconf-generic.h
+++ b/include/linux/pinctrl/pinconf-generic.h
@@ -137,6 +137,12 @@ static inline unsigned long pinconf_to_config_packed(enum pin_config_param param
return PIN_CONF_PACKED(param, argument);
}
+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);
+int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config, struct pinctrl_map **map,
+ unsigned *num_maps);
#endif /* CONFIG_GENERIC_PINCONF */
#endif /* __LINUX_PINCTRL_PINCONF_GENERIC_H */