Merge tag 'hsi-for-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi
[linux-2.6-microblaze.git] / drivers / pinctrl / pinctrl-utils.c
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 *reserved_maps,
22                 unsigned *num_maps, unsigned reserve)
23 {
24         unsigned old_num = *reserved_maps;
25         unsigned 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 *reserved_maps,
47                 unsigned *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 *reserved_maps,
64                 unsigned *num_maps, const char *group,
65                 unsigned long *configs, unsigned 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(configs, num_configs * sizeof(*dup_configs),
74                               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 *num_configs,
90                 unsigned long config)
91 {
92         unsigned old_num = *num_configs;
93         unsigned 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 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);