Merge tag 'kvmarm-fixes-6.0-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmar...
[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/device.h>
10 #include <linux/export.h>
11 #include <linux/kernel.h>
12 #include <linux/pinctrl/pinctrl.h>
13 #include <linux/of.h>
14 #include <linux/slab.h>
15 #include "core.h"
16 #include "pinctrl-utils.h"
17
18 int pinctrl_utils_reserve_map(struct pinctrl_dev *pctldev,
19                 struct pinctrl_map **map, unsigned *reserved_maps,
20                 unsigned *num_maps, unsigned reserve)
21 {
22         unsigned old_num = *reserved_maps;
23         unsigned new_num = *num_maps + reserve;
24         struct pinctrl_map *new_map;
25
26         if (old_num >= new_num)
27                 return 0;
28
29         new_map = krealloc_array(*map, new_num, sizeof(*new_map), GFP_KERNEL);
30         if (!new_map) {
31                 dev_err(pctldev->dev, "krealloc(map) failed\n");
32                 return -ENOMEM;
33         }
34
35         memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
36
37         *map = new_map;
38         *reserved_maps = new_num;
39         return 0;
40 }
41 EXPORT_SYMBOL_GPL(pinctrl_utils_reserve_map);
42
43 int pinctrl_utils_add_map_mux(struct pinctrl_dev *pctldev,
44                 struct pinctrl_map **map, unsigned *reserved_maps,
45                 unsigned *num_maps, const char *group,
46                 const char *function)
47 {
48         if (WARN_ON(*num_maps == *reserved_maps))
49                 return -ENOSPC;
50
51         (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
52         (*map)[*num_maps].data.mux.group = group;
53         (*map)[*num_maps].data.mux.function = function;
54         (*num_maps)++;
55
56         return 0;
57 }
58 EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_mux);
59
60 int pinctrl_utils_add_map_configs(struct pinctrl_dev *pctldev,
61                 struct pinctrl_map **map, unsigned *reserved_maps,
62                 unsigned *num_maps, const char *group,
63                 unsigned long *configs, unsigned num_configs,
64                 enum pinctrl_map_type type)
65 {
66         unsigned long *dup_configs;
67
68         if (WARN_ON(*num_maps == *reserved_maps))
69                 return -ENOSPC;
70
71         dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
72                               GFP_KERNEL);
73         if (!dup_configs)
74                 return -ENOMEM;
75
76         (*map)[*num_maps].type = type;
77         (*map)[*num_maps].data.configs.group_or_pin = group;
78         (*map)[*num_maps].data.configs.configs = dup_configs;
79         (*map)[*num_maps].data.configs.num_configs = num_configs;
80         (*num_maps)++;
81
82         return 0;
83 }
84 EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_configs);
85
86 int pinctrl_utils_add_config(struct pinctrl_dev *pctldev,
87                 unsigned long **configs, unsigned *num_configs,
88                 unsigned long config)
89 {
90         unsigned old_num = *num_configs;
91         unsigned new_num = old_num + 1;
92         unsigned long *new_configs;
93
94         new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
95                                GFP_KERNEL);
96         if (!new_configs) {
97                 dev_err(pctldev->dev, "krealloc(configs) failed\n");
98                 return -ENOMEM;
99         }
100
101         new_configs[old_num] = config;
102
103         *configs = new_configs;
104         *num_configs = new_num;
105
106         return 0;
107 }
108 EXPORT_SYMBOL_GPL(pinctrl_utils_add_config);
109
110 void pinctrl_utils_free_map(struct pinctrl_dev *pctldev,
111               struct pinctrl_map *map, unsigned num_maps)
112 {
113         int i;
114
115         for (i = 0; i < num_maps; i++) {
116                 switch (map[i].type) {
117                 case PIN_MAP_TYPE_CONFIGS_GROUP:
118                 case PIN_MAP_TYPE_CONFIGS_PIN:
119                         kfree(map[i].data.configs.configs);
120                         break;
121                 default:
122                         break;
123                 }
124         }
125         kfree(map);
126 }
127 EXPORT_SYMBOL_GPL(pinctrl_utils_free_map);