diff options
author | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2013-06-17 20:50:03 +0200 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2013-06-18 10:57:59 +0200 |
commit | 12f3ad8df7f58c61ff16ea851541583693d965e1 (patch) | |
tree | 8842483822ff6fd4c60b769088452e7d113b47bb | |
parent | fe1c9a822ce72c6ec8476a2501c412265ee2172c (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>
-rw-r--r-- | Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt | 36 | ||||
-rw-r--r-- | drivers/pinctrl/sh-pfc/pinctrl.c | 109 |
2 files changed, 124 insertions, 21 deletions
diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt index 8264cbcdd41..d5dac7b843a 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt @@ -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 configuration node" and for the common pinctrl bindings used by client devices. -Each pin configuration node represents desired functions to select on a pin -group or a list of pin groups. The functions and pin groups can be specified -directly in the pin configuration node, or grouped in child subnodes. Several -functions can thus be referenced as a single pin configuration node by client -devices. +Each pin configuration node represents a desired configuration for a pin, a +pin group, or a list of pins or pin groups. The configuration can include the +function to select on those pin(s) and pin configuration parameters (such as +pull-up and pull-down). -A configuration node or subnode must contain a function and reference at least -one pin group. +Pin configuration nodes contain pin configuration properties, either directly +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 are parsed through phandles and processed purely based on their content. 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 group. @@ -54,6 +61,10 @@ Pin Configuration Node Properties: function arrays of the PFC data file corresponding to the SoC (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 ---- @@ -113,8 +124,15 @@ Example 3: KZM-A9-GT (SH-Mobile AG5) default pin state hog and pin control maps pinctrl-names = "default"; mmcif_pins: mmcif { - renesas,groups = "mmc0_data8_0", "mmc0_ctrl_0"; - renesas,function = "mmc0"; + mux { + 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 { 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); } |