1e634cf4eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21eb207a9SLaxman Dewangan /* 31eb207a9SLaxman Dewangan * Utils functions to implement the pincontrol driver. 41eb207a9SLaxman Dewangan * 51eb207a9SLaxman Dewangan * Copyright (c) 2013, NVIDIA Corporation. 61eb207a9SLaxman Dewangan * 71eb207a9SLaxman Dewangan * Author: Laxman Dewangan <ldewangan@nvidia.com> 81eb207a9SLaxman Dewangan */ 982cc14c9SAndy Shevchenko #include <linux/array_size.h> 101eb207a9SLaxman Dewangan #include <linux/device.h> 112f62eb9dSLaxman Dewangan #include <linux/export.h> 121eb207a9SLaxman Dewangan #include <linux/of.h> 131eb207a9SLaxman Dewangan #include <linux/slab.h> 1482cc14c9SAndy Shevchenko 1582cc14c9SAndy Shevchenko #include <linux/pinctrl/pinctrl.h> 1682cc14c9SAndy Shevchenko 171eb207a9SLaxman Dewangan #include "core.h" 181eb207a9SLaxman Dewangan #include "pinctrl-utils.h" 191eb207a9SLaxman Dewangan 201eb207a9SLaxman Dewangan int pinctrl_utils_reserve_map(struct pinctrl_dev *pctldev, 217cc4e6b0SAndy Shevchenko struct pinctrl_map **map, unsigned int *reserved_maps, 227cc4e6b0SAndy Shevchenko unsigned int *num_maps, unsigned int reserve) 231eb207a9SLaxman Dewangan { 247cc4e6b0SAndy Shevchenko unsigned int old_num = *reserved_maps; 257cc4e6b0SAndy Shevchenko unsigned int new_num = *num_maps + reserve; 261eb207a9SLaxman Dewangan struct pinctrl_map *new_map; 271eb207a9SLaxman Dewangan 281eb207a9SLaxman Dewangan if (old_num >= new_num) 291eb207a9SLaxman Dewangan return 0; 301eb207a9SLaxman Dewangan 312207994dSBartosz Golaszewski new_map = krealloc_array(*map, new_num, sizeof(*new_map), GFP_KERNEL); 321eb207a9SLaxman Dewangan if (!new_map) { 331eb207a9SLaxman Dewangan dev_err(pctldev->dev, "krealloc(map) failed\n"); 341eb207a9SLaxman Dewangan return -ENOMEM; 351eb207a9SLaxman Dewangan } 361eb207a9SLaxman Dewangan 371eb207a9SLaxman Dewangan memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map)); 381eb207a9SLaxman Dewangan 391eb207a9SLaxman Dewangan *map = new_map; 401eb207a9SLaxman Dewangan *reserved_maps = new_num; 411eb207a9SLaxman Dewangan return 0; 421eb207a9SLaxman Dewangan } 431eb207a9SLaxman Dewangan EXPORT_SYMBOL_GPL(pinctrl_utils_reserve_map); 441eb207a9SLaxman Dewangan 451eb207a9SLaxman Dewangan int pinctrl_utils_add_map_mux(struct pinctrl_dev *pctldev, 467cc4e6b0SAndy Shevchenko struct pinctrl_map **map, unsigned int *reserved_maps, 477cc4e6b0SAndy Shevchenko unsigned int *num_maps, const char *group, 481eb207a9SLaxman Dewangan const char *function) 491eb207a9SLaxman Dewangan { 501eb207a9SLaxman Dewangan if (WARN_ON(*num_maps == *reserved_maps)) 511eb207a9SLaxman Dewangan return -ENOSPC; 521eb207a9SLaxman Dewangan 531eb207a9SLaxman Dewangan (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; 541eb207a9SLaxman Dewangan (*map)[*num_maps].data.mux.group = group; 551eb207a9SLaxman Dewangan (*map)[*num_maps].data.mux.function = function; 561eb207a9SLaxman Dewangan (*num_maps)++; 571eb207a9SLaxman Dewangan 581eb207a9SLaxman Dewangan return 0; 591eb207a9SLaxman Dewangan } 601eb207a9SLaxman Dewangan EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_mux); 611eb207a9SLaxman Dewangan 621eb207a9SLaxman Dewangan int pinctrl_utils_add_map_configs(struct pinctrl_dev *pctldev, 637cc4e6b0SAndy Shevchenko struct pinctrl_map **map, unsigned int *reserved_maps, 647cc4e6b0SAndy Shevchenko unsigned int *num_maps, const char *group, 657cc4e6b0SAndy Shevchenko unsigned long *configs, unsigned int num_configs, 661eb207a9SLaxman Dewangan enum pinctrl_map_type type) 671eb207a9SLaxman Dewangan { 681eb207a9SLaxman Dewangan unsigned long *dup_configs; 691eb207a9SLaxman Dewangan 701eb207a9SLaxman Dewangan if (WARN_ON(*num_maps == *reserved_maps)) 711eb207a9SLaxman Dewangan return -ENOSPC; 721eb207a9SLaxman Dewangan 73*ca428f12SShen Lichuan dup_configs = kmemdup_array(configs, num_configs, 74*ca428f12SShen Lichuan sizeof(*dup_configs), GFP_KERNEL); 7586f75c65SMarkus Elfring if (!dup_configs) 761eb207a9SLaxman Dewangan return -ENOMEM; 771eb207a9SLaxman Dewangan 781eb207a9SLaxman Dewangan (*map)[*num_maps].type = type; 791eb207a9SLaxman Dewangan (*map)[*num_maps].data.configs.group_or_pin = group; 801eb207a9SLaxman Dewangan (*map)[*num_maps].data.configs.configs = dup_configs; 811eb207a9SLaxman Dewangan (*map)[*num_maps].data.configs.num_configs = num_configs; 821eb207a9SLaxman Dewangan (*num_maps)++; 831eb207a9SLaxman Dewangan 841eb207a9SLaxman Dewangan return 0; 851eb207a9SLaxman Dewangan } 861eb207a9SLaxman Dewangan EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_configs); 871eb207a9SLaxman Dewangan 881eb207a9SLaxman Dewangan int pinctrl_utils_add_config(struct pinctrl_dev *pctldev, 897cc4e6b0SAndy Shevchenko unsigned long **configs, unsigned int *num_configs, 901eb207a9SLaxman Dewangan unsigned long config) 911eb207a9SLaxman Dewangan { 927cc4e6b0SAndy Shevchenko unsigned int old_num = *num_configs; 937cc4e6b0SAndy Shevchenko unsigned int new_num = old_num + 1; 941eb207a9SLaxman Dewangan unsigned long *new_configs; 951eb207a9SLaxman Dewangan 961eb207a9SLaxman Dewangan new_configs = krealloc(*configs, sizeof(*new_configs) * new_num, 971eb207a9SLaxman Dewangan GFP_KERNEL); 981eb207a9SLaxman Dewangan if (!new_configs) { 991eb207a9SLaxman Dewangan dev_err(pctldev->dev, "krealloc(configs) failed\n"); 1001eb207a9SLaxman Dewangan return -ENOMEM; 1011eb207a9SLaxman Dewangan } 1021eb207a9SLaxman Dewangan 1031eb207a9SLaxman Dewangan new_configs[old_num] = config; 1041eb207a9SLaxman Dewangan 1051eb207a9SLaxman Dewangan *configs = new_configs; 1061eb207a9SLaxman Dewangan *num_configs = new_num; 1071eb207a9SLaxman Dewangan 1081eb207a9SLaxman Dewangan return 0; 1091eb207a9SLaxman Dewangan } 1101eb207a9SLaxman Dewangan EXPORT_SYMBOL_GPL(pinctrl_utils_add_config); 1111eb207a9SLaxman Dewangan 112d32f7fd3SIrina Tirdea void pinctrl_utils_free_map(struct pinctrl_dev *pctldev, 1137cc4e6b0SAndy Shevchenko struct pinctrl_map *map, unsigned int num_maps) 1141eb207a9SLaxman Dewangan { 1151eb207a9SLaxman Dewangan int i; 1161eb207a9SLaxman Dewangan 1173287c240SLaxman Dewangan for (i = 0; i < num_maps; i++) { 1183287c240SLaxman Dewangan switch (map[i].type) { 1193287c240SLaxman Dewangan case PIN_MAP_TYPE_CONFIGS_GROUP: 1203287c240SLaxman Dewangan case PIN_MAP_TYPE_CONFIGS_PIN: 1211eb207a9SLaxman Dewangan kfree(map[i].data.configs.configs); 1223287c240SLaxman Dewangan break; 1233287c240SLaxman Dewangan default: 1243287c240SLaxman Dewangan break; 1253287c240SLaxman Dewangan } 1263287c240SLaxman Dewangan } 1271eb207a9SLaxman Dewangan kfree(map); 1281eb207a9SLaxman Dewangan } 129d32f7fd3SIrina Tirdea EXPORT_SYMBOL_GPL(pinctrl_utils_free_map); 130