diff options
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 e0a453790a40..84869f28b101 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) { |