xref: /linux/drivers/pinctrl/pinctrl-utils.c (revision 962ad08780a5bfb3240bc793e565181eacfceafb)
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