| 1 | |
| 2 | |
| 3 | * Utils functions to implement the pincontrol driver.
|
| 4 | *
|
| 5 | * Copyright (c) 2013, NVIDIA Corporation.
|
| 6 | *
|
| 7 | * Author: Laxman Dewangan <[email protected]>
|
| 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 int *reserved_maps,
|
| 22 | unsigned int *num_maps, unsigned int reserve)
|
| 23 | {
|
| 24 | unsigned int old_num = *reserved_maps;
|
| 25 | unsigned int 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 int *reserved_maps,
|
| 47 | unsigned int *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 int *reserved_maps,
|
| 64 | unsigned int *num_maps, const char *group,
|
| 65 | unsigned long *configs, unsigned int 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_array(configs, num_configs,
|
| 74 | sizeof(*dup_configs), 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 int *num_configs,
|
| 90 | unsigned long config)
|
| 91 | {
|
| 92 | unsigned int old_num = *num_configs;
|
| 93 | unsigned int 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 int 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);
|