summaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2013-06-17 20:50:03 +0200
committerLinus Walleij <linus.walleij@linaro.org>2013-06-18 10:57:59 +0200
commit12f3ad8df7f58c61ff16ea851541583693d965e1 (patch)
tree8842483822ff6fd4c60b769088452e7d113b47bb /drivers/pinctrl
parentfe1c9a822ce72c6ec8476a2501c412265ee2172c (diff)
sh-pfc: Add pinconf support to DT bindings
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Acked-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r--drivers/pinctrl/sh-pfc/pinctrl.c109
1 files changed, 97 insertions, 12 deletions
diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c
index 7e32bb8c08d..2cf23476adf 100644
--- a/drivers/pinctrl/sh-pfc/pinctrl.c
+++ b/drivers/pinctrl/sh-pfc/pinctrl.c
@@ -74,6 +74,27 @@ static void sh_pfc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
seq_printf(s, "%s", DRV_NAME);
}
+static int sh_pfc_map_add_config(struct pinctrl_map *map,
+ const char *group_or_pin,
+ enum pinctrl_map_type type,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ unsigned long *cfgs;
+
+ cfgs = kmemdup(configs, num_configs * sizeof(*cfgs),
+ GFP_KERNEL);
+ if (cfgs == NULL)
+ return -ENOMEM;
+
+ map->type = type;
+ map->data.configs.group_or_pin = group_or_pin;
+ map->data.configs.configs = cfgs;
+ map->data.configs.num_configs = num_configs;
+
+ return 0;
+}
+
static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
struct pinctrl_map **map,
unsigned int *num_maps, unsigned int *index)
@@ -81,9 +102,14 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
struct pinctrl_map *maps = *map;
unsigned int nmaps = *num_maps;
unsigned int idx = *index;
+ unsigned int num_configs;
const char *function = NULL;
+ unsigned long *configs;
struct property *prop;
+ unsigned int num_groups;
+ unsigned int num_pins;
const char *group;
+ const char *pin;
int ret;
/* Parse the function and configuration properties. At least a function
@@ -95,25 +121,47 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
return ret;
}
- if (!function) {
- dev_err(dev, "DT node must contain at least one function\n");
+ ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs);
+ if (ret < 0)
+ return ret;
+
+ if (!function && num_configs == 0) {
+ dev_err(dev,
+ "DT node must contain at least a function or config\n");
goto done;
}
- /* Count the number of groups and reallocate mappings. */
+ /* Count the number of pins and groups and reallocate mappings. */
+ ret = of_property_count_strings(np, "renesas,pins");
+ if (ret == -EINVAL) {
+ num_pins = 0;
+ } else if (ret < 0) {
+ dev_err(dev, "Invalid pins list in DT\n");
+ goto done;
+ } else {
+ num_pins = ret;
+ }
+
ret = of_property_count_strings(np, "renesas,groups");
- if (ret < 0 && ret != -EINVAL) {
+ if (ret == -EINVAL) {
+ num_groups = 0;
+ } else if (ret < 0) {
dev_err(dev, "Invalid pin groups list in DT\n");
goto done;
+ } else {
+ num_groups = ret;
}
- if (!ret) {
- dev_err(dev, "No group provided in DT node\n");
+ if (!num_pins && !num_groups) {
+ dev_err(dev, "No pin or group provided in DT node\n");
ret = -ENODEV;
goto done;
}
- nmaps += ret;
+ if (function)
+ nmaps += num_groups;
+ if (configs)
+ nmaps += num_pins + num_groups;
maps = krealloc(maps, sizeof(*maps) * nmaps, GFP_KERNEL);
if (maps == NULL) {
@@ -126,22 +174,59 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
/* Iterate over pins and groups and create the mappings. */
of_property_for_each_string(np, "renesas,groups", prop, group) {
- maps[idx].type = PIN_MAP_TYPE_MUX_GROUP;
- maps[idx].data.mux.group = group;
- maps[idx].data.mux.function = function;
- idx++;
+ if (function) {
+ maps[idx].type = PIN_MAP_TYPE_MUX_GROUP;
+ maps[idx].data.mux.group = group;
+ maps[idx].data.mux.function = function;
+ idx++;
+ }
+
+ if (configs) {
+ ret = sh_pfc_map_add_config(&maps[idx], group,
+ PIN_MAP_TYPE_CONFIGS_GROUP,
+ configs, num_configs);
+ if (ret < 0)
+ goto done;
+
+ idx++;
+ }
}
- ret = 0;
+ if (!configs) {
+ ret = 0;
+ goto done;
+ }
+
+ of_property_for_each_string(np, "renesas,pins", prop, pin) {
+ ret = sh_pfc_map_add_config(&maps[idx], pin,
+ PIN_MAP_TYPE_CONFIGS_PIN,
+ configs, num_configs);
+ if (ret < 0)
+ goto done;
+
+ idx++;
+ }
done:
*index = idx;
+ kfree(configs);
return ret;
}
static void sh_pfc_dt_free_map(struct pinctrl_dev *pctldev,
struct pinctrl_map *map, unsigned num_maps)
{
+ unsigned int i;
+
+ if (map == NULL)
+ return;
+
+ for (i = 0; i < num_maps; ++i) {
+ if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP ||
+ map[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
+ kfree(map[i].data.configs.configs);
+ }
+
kfree(map);
}