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(p: *map, new_n: new_num, new_size: 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(p: configs, size: 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(objp: *configs, new_size: 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(objp: map[i].data.configs.configs); |
122 | break; |
123 | default: |
124 | break; |
125 | } |
126 | } |
127 | kfree(objp: map); |
128 | } |
129 | EXPORT_SYMBOL_GPL(pinctrl_utils_free_map); |
130 | |