1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Core driver for the generic pin config portions of the pin control subsystem
4 *
5 * Copyright (C) 2011 ST-Ericsson SA
6 * Written on behalf of Linaro for ST-Ericsson
7 *
8 * Author: Linus Walleij <linus.walleij@linaro.org>
9 */
10
11 #define pr_fmt(fmt) "generic pinconfig core: " fmt
12
13 #include <linux/array_size.h>
14 #include <linux/debugfs.h>
15 #include <linux/device.h>
16 #include <linux/init.h>
17 #include <linux/module.h>
18 #include <linux/of.h>
19 #include <linux/slab.h>
20 #include <linux/seq_file.h>
21
22 #include <linux/pinctrl/pinconf-generic.h>
23 #include <linux/pinctrl/pinconf.h>
24 #include <linux/pinctrl/pinctrl.h>
25
26 #include "core.h"
27 #include "pinconf.h"
28 #include "pinctrl-utils.h"
29
30 #ifdef CONFIG_DEBUG_FS
31 static const struct pin_config_item conf_items[] = {
32 PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL, false),
33 PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL, false),
34 PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL, false),
35 PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", "ohms", true),
36 PCONFDUMP(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT,
37 "input bias pull to pin specific state", "ohms", true),
38 PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", "ohms", true),
39 PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL, false),
40 PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL, false),
41 PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL, false),
42 PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA", true),
43 PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH_UA, "output drive strength", "uA", true),
44 PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec", true),
45 PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL, false),
46 PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL, false),
47 PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_UV, "input schmitt threshold", "uV", true),
48 PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL, false),
49 PCONFDUMP(PIN_CONFIG_MODE_LOW_POWER, "pin low power", "mode", true),
50 PCONFDUMP(PIN_CONFIG_OUTPUT_ENABLE, "output enabled", NULL, false),
51 PCONFDUMP(PIN_CONFIG_LEVEL, "pin output", "level", true),
52 PCONFDUMP(PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS, "output impedance", "ohms", true),
53 PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector", true),
54 PCONFDUMP(PIN_CONFIG_SLEEP_HARDWARE_STATE, "sleep hardware state", NULL, false),
55 PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL, true),
56 PCONFDUMP(PIN_CONFIG_SKEW_DELAY, "skew delay", NULL, true),
57 PCONFDUMP(PIN_CONFIG_SKEW_DELAY_INPUT_PS, "input skew delay", "ps", true),
58 PCONFDUMP(PIN_CONFIG_SKEW_DELAY_OUTPUT_PS, "output skew delay", "ps", true),
59 };
60
pinconf_generic_dump_one(struct pinctrl_dev * pctldev,struct seq_file * s,const char * gname,unsigned int pin,const struct pin_config_item * items,int nitems,int * print_sep)61 static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev,
62 struct seq_file *s, const char *gname,
63 unsigned int pin,
64 const struct pin_config_item *items,
65 int nitems, int *print_sep)
66 {
67 int i;
68
69 for (i = 0; i < nitems; i++) {
70 const struct pin_config_item *item = &items[i];
71 unsigned long config;
72 int ret;
73
74 /* We want to check out this parameter */
75 config = pinconf_to_config_packed(item->param, 0);
76 if (gname)
77 ret = pin_config_group_get(dev_name(pctldev->dev),
78 gname, &config);
79 else
80 ret = pin_config_get_for_pin(pctldev, pin, &config);
81 /* These are legal errors */
82 if (ret == -EINVAL || ret == -ENOTSUPP)
83 continue;
84 if (ret) {
85 seq_printf(s, "ERROR READING CONFIG SETTING %d ", i);
86 continue;
87 }
88 /* comma between multiple configs */
89 if (*print_sep)
90 seq_puts(s, ", ");
91 *print_sep = 1;
92 seq_puts(s, item->display);
93 /* Print unit if available */
94 if (item->has_arg) {
95 u32 val = pinconf_to_config_argument(config);
96
97 if (item->format)
98 seq_printf(s, " (%u %s)", val, item->format);
99 else
100 seq_printf(s, " (0x%x)", val);
101
102 if (item->values && item->num_values) {
103 if (val < item->num_values)
104 seq_printf(s, " \"%s\"", item->values[val]);
105 else
106 seq_puts(s, " \"(unknown)\"");
107 }
108 }
109 }
110 }
111
112 /**
113 * pinconf_generic_dump_pins - Print information about pin or group of pins
114 * @pctldev: Pincontrol device
115 * @s: File to print to
116 * @gname: Group name specifying pins
117 * @pin: Pin number specifying pin
118 *
119 * Print the pinconf configuration for the requested pin(s) to @s. Pins can be
120 * specified either by pin using @pin or by group using @gname. Only one needs
121 * to be specified the other can be NULL/0.
122 */
pinconf_generic_dump_pins(struct pinctrl_dev * pctldev,struct seq_file * s,const char * gname,unsigned int pin)123 void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, struct seq_file *s,
124 const char *gname, unsigned int pin)
125 {
126 const struct pinconf_ops *ops = pctldev->desc->confops;
127 int print_sep = 0;
128
129 if (!ops->is_generic)
130 return;
131
132 /* generic parameters */
133 pinconf_generic_dump_one(pctldev, s, gname, pin, conf_items,
134 ARRAY_SIZE(conf_items), &print_sep);
135 /* driver-specific parameters */
136 if (pctldev->desc->num_custom_params &&
137 pctldev->desc->custom_conf_items)
138 pinconf_generic_dump_one(pctldev, s, gname, pin,
139 pctldev->desc->custom_conf_items,
140 pctldev->desc->num_custom_params,
141 &print_sep);
142 }
143
pinconf_generic_dump_config(struct pinctrl_dev * pctldev,struct seq_file * s,unsigned long config)144 void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
145 struct seq_file *s, unsigned long config)
146 {
147 int i;
148
149 for (i = 0; i < ARRAY_SIZE(conf_items); i++) {
150 if (pinconf_to_config_param(config) != conf_items[i].param)
151 continue;
152 seq_printf(s, "%s: 0x%x", conf_items[i].display,
153 pinconf_to_config_argument(config));
154 }
155
156 if (!pctldev->desc->num_custom_params ||
157 !pctldev->desc->custom_conf_items)
158 return;
159
160 for (i = 0; i < pctldev->desc->num_custom_params; i++) {
161 if (pinconf_to_config_param(config) !=
162 pctldev->desc->custom_conf_items[i].param)
163 continue;
164 seq_printf(s, "%s: 0x%x",
165 pctldev->desc->custom_conf_items[i].display,
166 pinconf_to_config_argument(config));
167 }
168 }
169 EXPORT_SYMBOL_GPL(pinconf_generic_dump_config);
170 #endif
171
172 #ifdef CONFIG_OF
173 static const struct pinconf_generic_params dt_params[] = {
174 { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
175 { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
176 { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
177 { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
178 { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
179 { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
180 { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
181 { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
182 { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 },
183 { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
184 { "drive-strength-microamp", PIN_CONFIG_DRIVE_STRENGTH_UA, 0 },
185 { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
186 { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
187 { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
188 { "input-schmitt", PIN_CONFIG_INPUT_SCHMITT, 0 },
189 { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
190 { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
191 { "input-schmitt-microvolts", PIN_CONFIG_INPUT_SCHMITT_UV, 0 },
192 { "low-power-disable", PIN_CONFIG_MODE_LOW_POWER, 0 },
193 { "low-power-enable", PIN_CONFIG_MODE_LOW_POWER, 1 },
194 { "output-disable", PIN_CONFIG_OUTPUT_ENABLE, 0 },
195 { "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 },
196 { "output-high", PIN_CONFIG_LEVEL, 1, },
197 { "output-impedance-ohms", PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS, 0 },
198 { "output-low", PIN_CONFIG_LEVEL, 0, },
199 { "power-source", PIN_CONFIG_POWER_SOURCE, 0 },
200 { "sleep-hardware-state", PIN_CONFIG_SLEEP_HARDWARE_STATE, 0 },
201 { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 },
202 { "skew-delay", PIN_CONFIG_SKEW_DELAY, 0 },
203 { "skew-delay-input-ps", PIN_CONFIG_SKEW_DELAY_INPUT_PS, 0 },
204 { "skew-delay-output-ps", PIN_CONFIG_SKEW_DELAY_OUTPUT_PS, 0 },
205 };
206
207 /**
208 * parse_dt_cfg() - Parse DT pinconf parameters
209 * @np: DT node
210 * @params: Array of describing generic parameters
211 * @count: Number of entries in @params
212 * @cfg: Array of parsed config options
213 * @ncfg: Number of entries in @cfg
214 *
215 * Parse the config options described in @params from @np and puts the result
216 * in @cfg. @cfg does not need to be empty, entries are added beginning at
217 * @ncfg. @ncfg is updated to reflect the number of entries after parsing. @cfg
218 * needs to have enough memory allocated to hold all possible entries.
219 */
parse_dt_cfg(struct device_node * np,const struct pinconf_generic_params * params,unsigned int count,unsigned long * cfg,unsigned int * ncfg)220 static int parse_dt_cfg(struct device_node *np,
221 const struct pinconf_generic_params *params,
222 unsigned int count, unsigned long *cfg,
223 unsigned int *ncfg)
224 {
225 int i;
226
227 for (i = 0; i < count; i++) {
228 u32 val;
229 int ret;
230 const struct pinconf_generic_params *par = ¶ms[i];
231
232 if (par->values && par->num_values) {
233 ret = fwnode_property_match_property_string(of_fwnode_handle(np),
234 par->property,
235 par->values, par->num_values);
236 if (ret == -ENOENT)
237 return ret;
238 if (ret >= 0) {
239 val = ret;
240 ret = 0;
241 }
242 } else {
243 ret = of_property_read_u32(np, par->property, &val);
244 }
245
246 /* property not found */
247 if (ret == -EINVAL)
248 continue;
249
250 /* use default value, when no value is specified */
251 if (ret)
252 val = par->default_value;
253
254 pr_debug("found %s with value %u\n", par->property, val);
255 cfg[*ncfg] = pinconf_to_config_packed(par->param, val);
256 (*ncfg)++;
257 }
258
259 return 0;
260 }
261
262 /**
263 * pinconf_generic_parse_dt_pinmux()
264 * parse the pinmux properties into generic pin mux values.
265 * @np: node containing the pinmux properties
266 * @dev: pincontrol core device
267 * @pid: array with pin identity entries
268 * @pmux: array with pin mux value entries
269 * @npins: number of pins
270 *
271 * pinmux property: mux value [0,7]bits and pin identity [8,31]bits.
272 */
pinconf_generic_parse_dt_pinmux(struct device_node * np,struct device * dev,unsigned int ** pid,unsigned int ** pmux,unsigned int * npins)273 int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev,
274 unsigned int **pid, unsigned int **pmux,
275 unsigned int *npins)
276 {
277 unsigned int *pid_t;
278 unsigned int *pmux_t;
279 struct property *prop;
280 unsigned int npins_t, i;
281 u32 value;
282 int ret;
283
284 prop = of_find_property(np, "pinmux", NULL);
285 if (!prop) {
286 dev_info(dev, "Missing pinmux property\n");
287 return -ENOENT;
288 }
289
290 if (!pid || !pmux || !npins) {
291 dev_err(dev, "parameters error\n");
292 return -EINVAL;
293 }
294
295 npins_t = prop->length / sizeof(u32);
296 pid_t = devm_kcalloc(dev, npins_t, sizeof(*pid_t), GFP_KERNEL);
297 pmux_t = devm_kcalloc(dev, npins_t, sizeof(*pmux_t), GFP_KERNEL);
298 if (!pid_t || !pmux_t) {
299 dev_err(dev, "kalloc memory fail\n");
300 return -ENOMEM;
301 }
302 for (i = 0; i < npins_t; i++) {
303 ret = of_property_read_u32_index(np, "pinmux", i, &value);
304 if (ret) {
305 dev_err(dev, "get pinmux value fail\n");
306 goto exit;
307 }
308 pmux_t[i] = value & 0xff;
309 pid_t[i] = (value >> 8) & 0xffffff;
310 }
311 *pid = pid_t;
312 *pmux = pmux_t;
313 *npins = npins_t;
314
315 return 0;
316 exit:
317 devm_kfree(dev, pid_t);
318 devm_kfree(dev, pmux_t);
319 return ret;
320 }
321 EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_pinmux);
322
323 /**
324 * pinconf_generic_parse_dt_config()
325 * parse the config properties into generic pinconfig values.
326 * @np: node containing the pinconfig properties
327 * @pctldev: pincontrol device
328 * @configs: array with nconfigs entries containing the generic pinconf values
329 * must be freed when no longer necessary.
330 * @nconfigs: number of configurations
331 */
pinconf_generic_parse_dt_config(struct device_node * np,struct pinctrl_dev * pctldev,unsigned long ** configs,unsigned int * nconfigs)332 int pinconf_generic_parse_dt_config(struct device_node *np,
333 struct pinctrl_dev *pctldev,
334 unsigned long **configs,
335 unsigned int *nconfigs)
336 {
337 unsigned long *cfg;
338 unsigned int max_cfg, ncfg = 0;
339 int ret;
340
341 if (!np)
342 return -EINVAL;
343
344 /* allocate a temporary array big enough to hold one of each option */
345 max_cfg = ARRAY_SIZE(dt_params);
346 if (pctldev)
347 max_cfg += pctldev->desc->num_custom_params;
348 cfg = kcalloc(max_cfg, sizeof(*cfg), GFP_KERNEL);
349 if (!cfg)
350 return -ENOMEM;
351
352 ret = parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg);
353 if (ret)
354 return ret;
355 if (pctldev && pctldev->desc->num_custom_params &&
356 pctldev->desc->custom_params) {
357 ret = parse_dt_cfg(np, pctldev->desc->custom_params,
358 pctldev->desc->num_custom_params, cfg, &ncfg);
359 if (ret)
360 return ret;
361 }
362
363 /* no configs found at all */
364 if (ncfg == 0) {
365 *configs = NULL;
366 *nconfigs = 0;
367 goto out;
368 }
369
370 /*
371 * Now limit the number of configs to the real number of
372 * found properties.
373 */
374 *configs = kmemdup(cfg, ncfg * sizeof(unsigned long), GFP_KERNEL);
375 if (!*configs) {
376 ret = -ENOMEM;
377 goto out;
378 }
379
380 *nconfigs = ncfg;
381
382 out:
383 kfree(cfg);
384 return ret;
385 }
386 EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_config);
387
pinconf_generic_dt_node_to_map_pinmux(struct pinctrl_dev * pctldev,struct device_node * np,struct pinctrl_map ** map,unsigned int * num_maps)388 int pinconf_generic_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev,
389 struct device_node *np,
390 struct pinctrl_map **map,
391 unsigned int *num_maps)
392 {
393 struct device *dev = pctldev->dev;
394 struct device_node *pnode;
395 unsigned long *configs = NULL;
396 unsigned int num_configs = 0;
397 struct property *prop;
398 unsigned int reserved_maps;
399 int reserve;
400 int ret;
401
402 prop = of_find_property(np, "pinmux", NULL);
403 if (!prop) {
404 dev_info(dev, "Missing pinmux property\n");
405 return -ENOENT;
406 }
407
408 pnode = of_get_parent(np);
409 if (!pnode) {
410 dev_info(dev, "Missing function node\n");
411 return -EINVAL;
412 }
413
414 reserved_maps = 0;
415 *map = NULL;
416 *num_maps = 0;
417
418 ret = pinconf_generic_parse_dt_config(np, pctldev, &configs,
419 &num_configs);
420 if (ret < 0) {
421 dev_err(dev, "%pOF: could not parse node property\n", np);
422 return ret;
423 }
424
425 reserve = 1;
426 if (num_configs)
427 reserve++;
428
429 ret = pinctrl_utils_reserve_map(pctldev, map, &reserved_maps,
430 num_maps, reserve);
431 if (ret < 0)
432 goto exit;
433
434 ret = pinctrl_utils_add_map_mux(pctldev, map,
435 &reserved_maps, num_maps, np->name,
436 pnode->name);
437 if (ret < 0)
438 goto exit;
439
440 if (num_configs) {
441 ret = pinctrl_utils_add_map_configs(pctldev, map, &reserved_maps,
442 num_maps, np->name, configs,
443 num_configs, PIN_MAP_TYPE_CONFIGS_GROUP);
444 if (ret < 0)
445 goto exit;
446 }
447
448 exit:
449 kfree(configs);
450 if (ret)
451 pinctrl_utils_free_map(pctldev, *map, *num_maps);
452
453 return ret;
454 }
455 EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map_pinmux);
456
pinconf_generic_dt_subnode_to_map(struct pinctrl_dev * pctldev,struct device_node * np,struct pinctrl_map ** map,unsigned int * reserved_maps,unsigned int * num_maps,enum pinctrl_map_type type)457 int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
458 struct device_node *np, struct pinctrl_map **map,
459 unsigned int *reserved_maps, unsigned int *num_maps,
460 enum pinctrl_map_type type)
461 {
462 int ret;
463 const char *function;
464 struct device *dev = pctldev->dev;
465 unsigned long *configs = NULL;
466 unsigned int num_configs = 0;
467 unsigned int reserve, strings_count;
468 struct property *prop;
469 const char *group;
470 const char *subnode_target_type = "pins";
471
472 ret = of_property_count_strings(np, "pins");
473 if (ret < 0) {
474 ret = of_property_count_strings(np, "groups");
475 if (ret < 0)
476 /* skip this node; may contain config child nodes */
477 return 0;
478 if (type == PIN_MAP_TYPE_INVALID)
479 type = PIN_MAP_TYPE_CONFIGS_GROUP;
480 subnode_target_type = "groups";
481 } else {
482 if (type == PIN_MAP_TYPE_INVALID)
483 type = PIN_MAP_TYPE_CONFIGS_PIN;
484 }
485 strings_count = ret;
486
487 ret = of_property_read_string(np, "function", &function);
488 if (ret < 0) {
489 /* EINVAL=missing, which is fine since it's optional */
490 if (ret != -EINVAL)
491 dev_err(dev, "%pOF: could not parse property function\n",
492 np);
493 function = NULL;
494 }
495
496 ret = pinconf_generic_parse_dt_config(np, pctldev, &configs,
497 &num_configs);
498 if (ret < 0) {
499 dev_err(dev, "%pOF: could not parse node property\n", np);
500 return ret;
501 }
502
503 reserve = 0;
504 if (function != NULL)
505 reserve++;
506 if (num_configs)
507 reserve++;
508
509 reserve *= strings_count;
510
511 ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps,
512 num_maps, reserve);
513 if (ret < 0)
514 goto exit;
515
516 of_property_for_each_string(np, subnode_target_type, prop, group) {
517 if (function) {
518 ret = pinctrl_utils_add_map_mux(pctldev, map,
519 reserved_maps, num_maps, group,
520 function);
521 if (ret < 0)
522 goto exit;
523 }
524
525 if (num_configs) {
526 ret = pinctrl_utils_add_map_configs(pctldev, map,
527 reserved_maps, num_maps, group, configs,
528 num_configs, type);
529 if (ret < 0)
530 goto exit;
531 }
532 }
533 ret = 0;
534
535 exit:
536 kfree(configs);
537 return ret;
538 }
539 EXPORT_SYMBOL_GPL(pinconf_generic_dt_subnode_to_map);
540
pinconf_generic_dt_node_to_map(struct pinctrl_dev * pctldev,struct device_node * np_config,struct pinctrl_map ** map,unsigned int * num_maps,enum pinctrl_map_type type)541 int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev,
542 struct device_node *np_config, struct pinctrl_map **map,
543 unsigned int *num_maps, enum pinctrl_map_type type)
544 {
545 unsigned int reserved_maps;
546 int ret;
547
548 reserved_maps = 0;
549 *map = NULL;
550 *num_maps = 0;
551
552 ret = pinconf_generic_dt_subnode_to_map(pctldev, np_config, map,
553 &reserved_maps, num_maps, type);
554 if (ret < 0)
555 goto exit;
556
557 for_each_available_child_of_node_scoped(np_config, np) {
558 ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map,
559 &reserved_maps, num_maps, type);
560 if (ret < 0)
561 goto exit;
562 }
563 return 0;
564
565 exit:
566 pinctrl_utils_free_map(pctldev, *map, *num_maps);
567 return ret;
568 }
569 EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map);
570
pinconf_generic_dt_free_map(struct pinctrl_dev * pctldev,struct pinctrl_map * map,unsigned int num_maps)571 void pinconf_generic_dt_free_map(struct pinctrl_dev *pctldev,
572 struct pinctrl_map *map,
573 unsigned int num_maps)
574 {
575 pinctrl_utils_free_map(pctldev, map, num_maps);
576 }
577 EXPORT_SYMBOL_GPL(pinconf_generic_dt_free_map);
578
579 #endif
580