1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Utils functions to implement the pincontrol driver. 4 * 5 * Copyright (c) 2013, NVIDIA Corporation. 6 * 7 * Author: Laxman Dewangan <ldewangan@nvidia.com> 8 */ 9 #include <linux/array_size.h> 10 #include <linux/device.h> 11 #include <linux/export.h> 12 #include <linux/of.h> 13 #include <linux/slab.h> 14 15 #include <linux/pinctrl/pinctrl.h> 16 17 #include "core.h" 18 #include "pinctrl-utils.h" 19 20 int pinctrl_utils_reserve_map(struct pinctrl_dev *pctldev, 21 struct pinctrl_map **map, unsigned int *reserved_maps, 22 unsigned int *num_maps, unsigned int reserve) 23 { 24 unsigned int old_num = *reserved_maps; 25 unsigned int new_num = *num_maps + reserve; 26 struct pinctrl_map *new_map; 27 28 if (old_num >= new_num) 29 return 0; 30 31 new_map = krealloc_array(*map, new_num, sizeof(*new_map), GFP_KERNEL); 32 if (!new_map) { 33 dev_err(pctldev->dev, "krealloc(map) failed\n"); 34 return -ENOMEM; 35 } 36 37 memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map)); 38 39 *map = new_map; 40 *reserved_maps = new_num; 41 return 0; 42 } 43 EXPORT_SYMBOL_GPL(pinctrl_utils_reserve_map); 44 45 int pinctrl_utils_add_map_mux(struct pinctrl_dev *pctldev, 46 struct pinctrl_map **map, unsigned int *reserved_maps, 47 unsigned int *num_maps, const char *group, 48 const char *function) 49 { 50 if (WARN_ON(*num_maps == *reserved_maps)) 51 return -ENOSPC; 52 53 (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; 54 (*map)[*num_maps].data.mux.group = group; 55 (*map)[*num_maps].data.mux.function = function; 56 (*num_maps)++; 57 58 return 0; 59 } 60 EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_mux); 61 62 int pinctrl_utils_add_map_configs(struct pinctrl_dev *pctldev, 63 struct pinctrl_map **map, unsigned int *reserved_maps, 64 unsigned int *num_maps, const char *group, 65 unsigned long *configs, unsigned int num_configs, 66 enum pinctrl_map_type type) 67 { 68 unsigned long *dup_configs; 69 70 if (WARN_ON(*num_maps == *reserved_maps)) 71 return -ENOSPC; 72 73 dup_configs = kmemdup_array(configs, num_configs, 74 sizeof(*dup_configs), GFP_KERNEL); 75 if (!dup_configs) 76 return -ENOMEM; 77 78 (*map)[*num_maps].type = type; 79 (*map)[*num_maps].data.configs.group_or_pin = group; 80 (*map)[*num_maps].data.configs.configs = dup_configs; 81 (*map)[*num_maps].data.configs.num_configs = num_configs; 82 (*num_maps)++; 83 84 return 0; 85 } 86 EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_configs); 87 88 int pinctrl_utils_add_config(struct pinctrl_dev *pctldev, 89 unsigned long **configs, unsigned int *num_configs, 90 unsigned long config) 91 { 92 unsigned int old_num = *num_configs; 93 unsigned int new_num = old_num + 1; 94 unsigned long *new_configs; 95 96 new_configs = krealloc(*configs, sizeof(*new_configs) * new_num, 97 GFP_KERNEL); 98 if (!new_configs) { 99 dev_err(pctldev->dev, "krealloc(configs) failed\n"); 100 return -ENOMEM; 101 } 102 103 new_configs[old_num] = config; 104 105 *configs = new_configs; 106 *num_configs = new_num; 107 108 return 0; 109 } 110 EXPORT_SYMBOL_GPL(pinctrl_utils_add_config); 111 112 void pinctrl_utils_free_map(struct pinctrl_dev *pctldev, 113 struct pinctrl_map *map, unsigned int num_maps) 114 { 115 int i; 116 117 for (i = 0; i < num_maps; i++) { 118 switch (map[i].type) { 119 case PIN_MAP_TYPE_CONFIGS_GROUP: 120 case PIN_MAP_TYPE_CONFIGS_PIN: 121 kfree(map[i].data.configs.configs); 122 break; 123 default: 124 break; 125 } 126 } 127 kfree(map); 128 } 129 EXPORT_SYMBOL_GPL(pinctrl_utils_free_map); 130