Commit 12f3ad8d authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Linus Walleij

sh-pfc: Add pinconf support to DT bindings

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Acked-by: default avatarHeiko Stuebner <heiko@sntech.de>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent fe1c9a82
...@@ -30,20 +30,27 @@ The PFC node also acts as a container for pin configuration nodes. Please refer ...@@ -30,20 +30,27 @@ The PFC node also acts as a container for pin configuration nodes. Please refer
to pinctrl-bindings.txt in this directory for the definition of the term "pin to pinctrl-bindings.txt in this directory for the definition of the term "pin
configuration node" and for the common pinctrl bindings used by client devices. configuration node" and for the common pinctrl bindings used by client devices.
Each pin configuration node represents desired functions to select on a pin Each pin configuration node represents a desired configuration for a pin, a
group or a list of pin groups. The functions and pin groups can be specified pin group, or a list of pins or pin groups. The configuration can include the
directly in the pin configuration node, or grouped in child subnodes. Several function to select on those pin(s) and pin configuration parameters (such as
functions can thus be referenced as a single pin configuration node by client pull-up and pull-down).
devices.
A configuration node or subnode must contain a function and reference at least Pin configuration nodes contain pin configuration properties, either directly
one pin group. or grouped in child subnodes. Both pin muxing and configuration parameters can
be grouped in that way and referenced as a single pin configuration node by
client devices.
A configuration node or subnode must reference at least one pin (through the
pins or pin groups properties) and contain at least a function or one
configuration parameter. When the function is present only pin groups can be
used to reference pins.
All pin configuration nodes and subnodes names are ignored. All of those nodes All pin configuration nodes and subnodes names are ignored. All of those nodes
are parsed through phandles and processed purely based on their content. are parsed through phandles and processed purely based on their content.
Pin Configuration Node Properties: Pin Configuration Node Properties:
- renesas,pins : An array of strings, each string containing the name of a pin.
- renesas,groups : An array of strings, each string containing the name of a pin - renesas,groups : An array of strings, each string containing the name of a pin
group. group.
...@@ -54,6 +61,10 @@ Pin Configuration Node Properties: ...@@ -54,6 +61,10 @@ Pin Configuration Node Properties:
function arrays of the PFC data file corresponding to the SoC function arrays of the PFC data file corresponding to the SoC
(drivers/pinctrl/sh-pfc/pfc-*.c) (drivers/pinctrl/sh-pfc/pfc-*.c)
The pin configuration parameters use the generic pinconf bindings defined in
pinctrl-bindings.txt in this directory. The supported parameters are
bias-disable, bias-pull-up and bias-pull-down.
GPIO GPIO
---- ----
...@@ -113,9 +124,16 @@ Example 3: KZM-A9-GT (SH-Mobile AG5) default pin state hog and pin control maps ...@@ -113,9 +124,16 @@ Example 3: KZM-A9-GT (SH-Mobile AG5) default pin state hog and pin control maps
pinctrl-names = "default"; pinctrl-names = "default";
mmcif_pins: mmcif { mmcif_pins: mmcif {
mux {
renesas,groups = "mmc0_data8_0", "mmc0_ctrl_0"; renesas,groups = "mmc0_data8_0", "mmc0_ctrl_0";
renesas,function = "mmc0"; renesas,function = "mmc0";
}; };
cfg {
renesas,groups = "mmc0_data8_0";
renesas,pins = "PORT279";
bias-pull-up;
};
};
scifa4_pins: scifa4 { scifa4_pins: scifa4 {
renesas,groups = "scifa4_data", "scifa4_ctrl"; renesas,groups = "scifa4_data", "scifa4_ctrl";
......
...@@ -74,6 +74,27 @@ static void sh_pfc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, ...@@ -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); 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, static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
struct pinctrl_map **map, struct pinctrl_map **map,
unsigned int *num_maps, unsigned int *index) 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, ...@@ -81,9 +102,14 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
struct pinctrl_map *maps = *map; struct pinctrl_map *maps = *map;
unsigned int nmaps = *num_maps; unsigned int nmaps = *num_maps;
unsigned int idx = *index; unsigned int idx = *index;
unsigned int num_configs;
const char *function = NULL; const char *function = NULL;
unsigned long *configs;
struct property *prop; struct property *prop;
unsigned int num_groups;
unsigned int num_pins;
const char *group; const char *group;
const char *pin;
int ret; int ret;
/* Parse the function and configuration properties. At least a function /* 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, ...@@ -95,25 +121,47 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
return ret; return ret;
} }
if (!function) { ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs);
dev_err(dev, "DT node must contain at least one function\n"); 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 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; goto done;
} else {
num_pins = ret;
} }
/* Count the number of groups and reallocate mappings. */
ret = of_property_count_strings(np, "renesas,groups"); 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"); dev_err(dev, "Invalid pin groups list in DT\n");
goto done; goto done;
} else {
num_groups = ret;
} }
if (!ret) { if (!num_pins && !num_groups) {
dev_err(dev, "No group provided in DT node\n"); dev_err(dev, "No pin or group provided in DT node\n");
ret = -ENODEV; ret = -ENODEV;
goto done; goto done;
} }
nmaps += ret; if (function)
nmaps += num_groups;
if (configs)
nmaps += num_pins + num_groups;
maps = krealloc(maps, sizeof(*maps) * nmaps, GFP_KERNEL); maps = krealloc(maps, sizeof(*maps) * nmaps, GFP_KERNEL);
if (maps == NULL) { if (maps == NULL) {
...@@ -126,22 +174,59 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, ...@@ -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. */ /* Iterate over pins and groups and create the mappings. */
of_property_for_each_string(np, "renesas,groups", prop, group) { of_property_for_each_string(np, "renesas,groups", prop, group) {
if (function) {
maps[idx].type = PIN_MAP_TYPE_MUX_GROUP; maps[idx].type = PIN_MAP_TYPE_MUX_GROUP;
maps[idx].data.mux.group = group; maps[idx].data.mux.group = group;
maps[idx].data.mux.function = function; maps[idx].data.mux.function = function;
idx++; 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; 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: done:
*index = idx; *index = idx;
kfree(configs);
return ret; return ret;
} }
static void sh_pfc_dt_free_map(struct pinctrl_dev *pctldev, static void sh_pfc_dt_free_map(struct pinctrl_dev *pctldev,
struct pinctrl_map *map, unsigned num_maps) 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); kfree(map);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment