lkml.org 
[lkml]   [2012]   [Mar]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH V2 6/6] pinctrl: tegra: Add complete device tree support
    Date
    Implement pinctrl_ops dt_node_to_map() and dt_free_map(). These allow
    complete specification of the desired pinmux configuration using device
    tree.

    Signed-off-by: Stephen Warren <swarren@wwwdotorg.org>
    ---
    v2: Rebase on of_property_for_each_string() API changes.
    ---
    drivers/pinctrl/pinctrl-tegra.c | 181 +++++++++++++++++++++++++++++++++++++++
    1 files changed, 181 insertions(+), 0 deletions(-)

    diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
    index 9b32968..304788f 100644
    --- a/drivers/pinctrl/pinctrl-tegra.c
    +++ b/drivers/pinctrl/pinctrl-tegra.c
    @@ -23,9 +23,12 @@
    #include <linux/io.h>
    #include <linux/module.h>
    #include <linux/of_device.h>
    +#include <linux/of_iter_prop.h>
    +#include <linux/pinctrl/machine.h>
    #include <linux/pinctrl/pinctrl.h>
    #include <linux/pinctrl/pinmux.h>
    #include <linux/pinctrl/pinconf.h>
    +#include <linux/slab.h>

    #include <mach/pinconf-tegra.h>

    @@ -98,11 +101,189 @@ static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
    seq_printf(s, " " DRIVER_NAME);
    }

    +static int add_map(struct pinctrl_map **map, unsigned *num_maps)
    +{
    + unsigned old_num = *num_maps;
    + unsigned new_num = old_num + 1;
    + struct pinctrl_map *new_map;
    +
    + new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
    + if (!new_map)
    + return -ENOMEM;
    +
    + memset(new_map + old_num, 0, sizeof(*new_map));
    +
    + *map = new_map;
    + *num_maps = new_num;
    +
    + return 0;
    +}
    +
    +static int add_map_mux(struct pinctrl_map **map, unsigned *num_maps,
    + const char *group, const char *function)
    +{
    + unsigned i = *num_maps;
    + int ret;
    +
    + ret = add_map(map, num_maps);
    + if (ret < 0)
    + return ret;
    +
    + (*map)[i].type = PIN_MAP_TYPE_MUX_GROUP;
    + (*map)[i].data.mux.group = group;
    + (*map)[i].data.mux.function = function;
    +
    + return 0;
    +}
    +
    +static int add_map_configs(struct pinctrl_map **map, unsigned *num_maps,
    + const char *group, unsigned long *configs,
    + unsigned num_configs)
    +{
    + unsigned i = *num_maps;
    + unsigned long *dup_configs;
    + int ret;
    +
    + dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
    + GFP_KERNEL);
    + if (!dup_configs)
    + return -ENOMEM;
    +
    + ret = add_map(map, num_maps);
    + if (ret < 0)
    + return ret;
    +
    + (*map)[i].type = PIN_MAP_TYPE_CONFIGS_GROUP;
    + (*map)[i].data.configs.group_or_pin = group;
    + (*map)[i].data.configs.configs = dup_configs;
    + (*map)[i].data.configs.num_configs = num_configs;
    +
    + return 0;
    +}
    +
    +static int add_config(unsigned long **configs, unsigned *num_configs,
    + unsigned long config)
    +{
    + unsigned old_num = *num_configs;
    + unsigned new_num = old_num + 1;
    + unsigned long *new_configs;
    +
    + new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
    + GFP_KERNEL);
    + if (!new_configs)
    + return -ENOMEM;
    +
    + new_configs[old_num] = config;
    +
    + *configs = new_configs;
    + *num_configs = new_num;
    +
    + return 0;
    +}
    +
    +void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
    + struct pinctrl_map *map, unsigned num_maps)
    +{
    + int i;
    +
    + for (i = 0; i < num_maps; i++)
    + if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
    + kfree(map[i].data.configs.configs);
    +
    + kfree(map);
    +}
    +
    +static const struct cfg_param {
    + const char *property;
    + enum tegra_pinconf_param param;
    +} cfg_params[] = {
    + {"nvidia,pull", TEGRA_PINCONF_PARAM_PULL},
    + {"nvidia,tristate", TEGRA_PINCONF_PARAM_TRISTATE},
    + {"nvidia,enable-input", TEGRA_PINCONF_PARAM_ENABLE_INPUT},
    + {"nvidia,open-drain", TEGRA_PINCONF_PARAM_OPEN_DRAIN},
    + {"nvidia,lock", TEGRA_PINCONF_PARAM_LOCK},
    + {"nvidia,io-reset", TEGRA_PINCONF_PARAM_IORESET},
    + {"nvidia,high-speed-mode", TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE},
    + {"nvidia,schmitt", TEGRA_PINCONF_PARAM_SCHMITT},
    + {"nvidia,low-power-mode", TEGRA_PINCONF_PARAM_LOW_POWER_MODE},
    + {"nvidia,pull-down-strength", TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH},
    + {"nvidia,pull-up-strength", TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH},
    + {"nvidia,slew-rate-falling", TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING},
    + {"nvidia,slew-rate-rising", TEGRA_PINCONF_PARAM_SLEW_RATE_RISING},
    +};
    +
    +int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
    + struct device_node *np_config,
    + struct pinctrl_map **map, unsigned *num_maps)
    +{
    + struct device_node *np;
    + unsigned long config;
    + const char *function;
    + unsigned long *configs = NULL;
    + unsigned num_configs = 0;
    + u32 val;
    + int ret, i;
    + struct property *prop;
    + const char *group;
    +
    + *map = NULL;
    + *num_maps = 0;
    +
    + for_each_child_of_node(np_config, np) {
    + ret = of_property_read_string(np, "nvidia,function", &function);
    + if (ret < 0)
    + function = NULL;
    +
    + for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
    + ret = of_property_read_u32(np, cfg_params[i].property,
    + &val);
    + if (!ret) {
    + config = TEGRA_PINCONF_PACK(
    + cfg_params[i].param, val);
    + ret = add_config(&configs, &num_configs,
    + config);
    + if (ret < 0)
    + goto error;
    + }
    + }
    +
    + of_property_for_each_string(np, "nvidia,pins", prop, group) {
    + if (function) {
    + ret = add_map_mux(map, num_maps, group,
    + function);
    + if (ret < 0)
    + goto error;
    + }
    +
    + if (num_configs) {
    + ret = add_map_configs(map, num_maps, group,
    + configs, num_configs);
    + if (ret < 0)
    + goto error;
    + }
    + }
    +
    + kfree(configs);
    + configs = NULL;
    + num_configs = 0;
    + }
    +
    + return 0;
    +
    +error:
    + kfree(configs);
    + tegra_pinctrl_dt_free_map(pctldev, *map, *num_maps);
    +
    + return ret;
    +}
    +
    static struct pinctrl_ops tegra_pinctrl_ops = {
    .list_groups = tegra_pinctrl_list_groups,
    .get_group_name = tegra_pinctrl_get_group_name,
    .get_group_pins = tegra_pinctrl_get_group_pins,
    .pin_dbg_show = tegra_pinctrl_pin_dbg_show,
    + .dt_node_to_map = tegra_pinctrl_dt_node_to_map,
    + .dt_free_map = tegra_pinctrl_dt_free_map,
    };

    static int tegra_pinctrl_list_funcs(struct pinctrl_dev *pctldev,
    --
    1.7.0.4


    \
     
     \ /
      Last update: 2012-03-20 18:47    [W:7.193 / U:0.056 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site