mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
sh-pfc: Add pinconf support to DT bindings
Signed-off-by: Laurent Pinchart <[email protected]> Acked-by: Heiko Stuebner <[email protected]> Signed-off-by: Linus Walleij <[email protected]>
This commit is contained in:
parent
fe1c9a822c
commit
12f3ad8df7
2 changed files with 124 additions and 21 deletions
|
|
@ -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;
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue