forked from Minki/linux
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>
This commit is contained in:
parent
fe1c9a822c
commit
12f3ad8df7
@ -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:
|
|||||||
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,8 +124,15 @@ 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 {
|
||||||
renesas,groups = "mmc0_data8_0", "mmc0_ctrl_0";
|
mux {
|
||||||
renesas,function = "mmc0";
|
renesas,groups = "mmc0_data8_0", "mmc0_ctrl_0";
|
||||||
|
renesas,function = "mmc0";
|
||||||
|
};
|
||||||
|
cfg {
|
||||||
|
renesas,groups = "mmc0_data8_0";
|
||||||
|
renesas,pins = "PORT279";
|
||||||
|
bias-pull-up;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
scifa4_pins: scifa4 {
|
scifa4_pins: scifa4 {
|
||||||
|
@ -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,
|
|||||||
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,
|
|||||||
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;
|
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");
|
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,
|
|||||||
|
|
||||||
/* 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) {
|
||||||
maps[idx].type = PIN_MAP_TYPE_MUX_GROUP;
|
if (function) {
|
||||||
maps[idx].data.mux.group = group;
|
maps[idx].type = PIN_MAP_TYPE_MUX_GROUP;
|
||||||
maps[idx].data.mux.function = function;
|
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++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user