130 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 20int 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}43EXPORT_SYMBOL_GPL(pinctrl_utils_reserve_map);44 45int 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}60EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_mux);61 62int 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}86EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_configs);87 88int 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}110EXPORT_SYMBOL_GPL(pinctrl_utils_add_config);111 112void 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}129EXPORT_SYMBOL_GPL(pinctrl_utils_free_map);130