diff options
author | Stephen Warren <swarren@nvidia.com> | 2012-03-02 20:05:48 (GMT) |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2012-03-05 10:25:11 (GMT) |
commit | 1e2082b520721734c358f776d34a069867214c8e (patch) | |
tree | 4d11e15a4127ad69faf7555864480a6fafe5422c /drivers/pinctrl/pinconf.c | |
parent | 6e5e959dde0d92d177f035652aeaa77f9330c9c6 (diff) | |
download | linux-1e2082b520721734c358f776d34a069867214c8e.tar.xz |
pinctrl: enhance mapping table to support pin config operations
The pinctrl mapping table can now contain entries to:
* Set the mux function of a pin group
* Apply a set of pin config options to a pin or a group
This allows pinctrl_select_state() to apply pin configs settings as well
as mux settings.
v3: Fix find_pinctrl() to iterate over the correct list.
s/_MUX_CONFIGS_/_CONFIGS_/ in mapping table macros.
Fix documentation to use correct mapping table macro.
v2: Added numerous extra PIN_MAP_*() special-case macros.
Fixed kerneldoc typo. Delete pinctrl_get_pin_id() and
replace it with pin_get_from_name(). Various minor fixes.
Updates due to rebase.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Dong Aisheng <dong.aisheng@linaro.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/pinconf.c')
-rw-r--r-- | drivers/pinctrl/pinconf.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index e0a4537..84869f2 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -36,6 +36,24 @@ int pinconf_check_ops(struct pinctrl_dev *pctldev) return 0; } +int pinconf_validate_map(struct pinctrl_map const *map, int i) +{ + if (!map->data.configs.group_or_pin) { + pr_err("failed to register map %s (%d): no group/pin given\n", + map->name, i); + return -EINVAL; + } + + if (map->data.configs.num_configs && + !map->data.configs.configs) { + pr_err("failed to register map %s (%d): no configs ptr given\n", + map->name, i); + return -EINVAL; + } + + return 0; +} + static int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin, unsigned long *config) { @@ -260,8 +278,155 @@ unlock: } EXPORT_SYMBOL(pin_config_group_set); +int pinconf_map_to_setting(struct pinctrl_map const *map, + struct pinctrl_setting *setting) +{ + struct pinctrl_dev *pctldev = setting->pctldev; + + switch (setting->type) { + case PIN_MAP_TYPE_CONFIGS_PIN: + setting->data.configs.group_or_pin = + pin_get_from_name(pctldev, + map->data.configs.group_or_pin); + if (setting->data.configs.group_or_pin < 0) + return setting->data.configs.group_or_pin; + break; + case PIN_MAP_TYPE_CONFIGS_GROUP: + setting->data.configs.group_or_pin = + pinctrl_get_group_selector(pctldev, + map->data.configs.group_or_pin); + if (setting->data.configs.group_or_pin < 0) + return setting->data.configs.group_or_pin; + break; + default: + return -EINVAL; + } + + setting->data.configs.num_configs = map->data.configs.num_configs; + setting->data.configs.configs = map->data.configs.configs; + + return 0; +} + +void pinconf_free_setting(struct pinctrl_setting const *setting) +{ +} + +int pinconf_apply_setting(struct pinctrl_setting const *setting) +{ + struct pinctrl_dev *pctldev = setting->pctldev; + const struct pinconf_ops *ops = pctldev->desc->confops; + int i, ret; + + if (!ops) { + dev_err(pctldev->dev, "missing confops\n"); + return -EINVAL; + } + + switch (setting->type) { + case PIN_MAP_TYPE_CONFIGS_PIN: + if (!ops->pin_config_set) { + dev_err(pctldev->dev, "missing pin_config_set op\n"); + return -EINVAL; + } + for (i = 0; i < setting->data.configs.num_configs; i++) { + ret = ops->pin_config_set(pctldev, + setting->data.configs.group_or_pin, + setting->data.configs.configs[i]); + if (ret < 0) { + dev_err(pctldev->dev, + "pin_config_set op failed for pin %d config %08lx\n", + setting->data.configs.group_or_pin, + setting->data.configs.configs[i]); + return ret; + } + } + break; + case PIN_MAP_TYPE_CONFIGS_GROUP: + if (!ops->pin_config_group_set) { + dev_err(pctldev->dev, + "missing pin_config_group_set op\n"); + return -EINVAL; + } + for (i = 0; i < setting->data.configs.num_configs; i++) { + ret = ops->pin_config_group_set(pctldev, + setting->data.configs.group_or_pin, + setting->data.configs.configs[i]); + if (ret < 0) { + dev_err(pctldev->dev, + "pin_config_group_set op failed for group %d config %08lx\n", + setting->data.configs.group_or_pin, + setting->data.configs.configs[i]); + return ret; + } + } + break; + default: + return -EINVAL; + } + + return 0; +} + #ifdef CONFIG_DEBUG_FS +void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) +{ + int i; + + switch (map->type) { + case PIN_MAP_TYPE_CONFIGS_PIN: + seq_printf(s, "pin "); + break; + case PIN_MAP_TYPE_CONFIGS_GROUP: + seq_printf(s, "group "); + break; + default: + break; + } + + seq_printf(s, "%s\n", map->data.configs.group_or_pin); + + for (i = 0; i < map->data.configs.num_configs; i++) + seq_printf(s, "config %08lx\n", map->data.configs.configs[i]); +} + +void pinconf_show_setting(struct seq_file *s, + struct pinctrl_setting const *setting) +{ + struct pinctrl_dev *pctldev = setting->pctldev; + const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; + struct pin_desc *desc; + int i; + + switch (setting->type) { + case PIN_MAP_TYPE_CONFIGS_PIN: + desc = pin_desc_get(setting->pctldev, + setting->data.configs.group_or_pin); + seq_printf(s, "pin %s (%d)", + desc->name ? desc->name : "unnamed", + setting->data.configs.group_or_pin); + break; + case PIN_MAP_TYPE_CONFIGS_GROUP: + seq_printf(s, "group %s (%d)", + pctlops->get_group_name(pctldev, + setting->data.configs.group_or_pin), + setting->data.configs.group_or_pin); + break; + default: + break; + } + + /* + * FIXME: We should really get the pin controler to dump the config + * values, so they can be decoded to something meaningful. + */ + for (i = 0; i < setting->data.configs.num_configs; i++) + seq_printf(s, " %08lx", setting->data.configs.configs[i]); + + seq_printf(s, "\n"); +} + static void pinconf_dump_pin(struct pinctrl_dev *pctldev, struct seq_file *s, int pin) { |