linux/drivers/pinctrl/pinctrl-utils.c
<<
>>
Prefs
   1/*
   2 * Utils functions to implement the pincontrol driver.
   3 *
   4 * Copyright (c) 2013, NVIDIA Corporation.
   5 *
   6 * Author: Laxman Dewangan <ldewangan@nvidia.com>
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License as
  10 * published by the Free Software Foundation version 2.
  11 *
  12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
  13 * whether express or implied; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  20 * 02111-1307, USA
  21 */
  22#include <linux/device.h>
  23#include <linux/export.h>
  24#include <linux/kernel.h>
  25#include <linux/pinctrl/pinctrl.h>
  26#include <linux/of.h>
  27#include <linux/slab.h>
  28#include "core.h"
  29#include "pinctrl-utils.h"
  30
  31int pinctrl_utils_reserve_map(struct pinctrl_dev *pctldev,
  32                struct pinctrl_map **map, unsigned *reserved_maps,
  33                unsigned *num_maps, unsigned reserve)
  34{
  35        unsigned old_num = *reserved_maps;
  36        unsigned new_num = *num_maps + reserve;
  37        struct pinctrl_map *new_map;
  38
  39        if (old_num >= new_num)
  40                return 0;
  41
  42        new_map = krealloc_array(*map, new_num, sizeof(*new_map), GFP_KERNEL);
  43        if (!new_map) {
  44                dev_err(pctldev->dev, "krealloc(map) failed\n");
  45                return -ENOMEM;
  46        }
  47
  48        memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
  49
  50        *map = new_map;
  51        *reserved_maps = new_num;
  52        return 0;
  53}
  54EXPORT_SYMBOL_GPL(pinctrl_utils_reserve_map);
  55
  56int pinctrl_utils_add_map_mux(struct pinctrl_dev *pctldev,
  57                struct pinctrl_map **map, unsigned *reserved_maps,
  58                unsigned *num_maps, const char *group,
  59                const char *function)
  60{
  61        if (WARN_ON(*num_maps == *reserved_maps))
  62                return -ENOSPC;
  63
  64        (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
  65        (*map)[*num_maps].data.mux.group = group;
  66        (*map)[*num_maps].data.mux.function = function;
  67        (*num_maps)++;
  68
  69        return 0;
  70}
  71EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_mux);
  72
  73int pinctrl_utils_add_map_configs(struct pinctrl_dev *pctldev,
  74                struct pinctrl_map **map, unsigned *reserved_maps,
  75                unsigned *num_maps, const char *group,
  76                unsigned long *configs, unsigned num_configs,
  77                enum pinctrl_map_type type)
  78{
  79        unsigned long *dup_configs;
  80
  81        if (WARN_ON(*num_maps == *reserved_maps))
  82                return -ENOSPC;
  83
  84        dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
  85                              GFP_KERNEL);
  86        if (!dup_configs)
  87                return -ENOMEM;
  88
  89        (*map)[*num_maps].type = type;
  90        (*map)[*num_maps].data.configs.group_or_pin = group;
  91        (*map)[*num_maps].data.configs.configs = dup_configs;
  92        (*map)[*num_maps].data.configs.num_configs = num_configs;
  93        (*num_maps)++;
  94
  95        return 0;
  96}
  97EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_configs);
  98
  99int pinctrl_utils_add_config(struct pinctrl_dev *pctldev,
 100                unsigned long **configs, unsigned *num_configs,
 101                unsigned long config)
 102{
 103        unsigned old_num = *num_configs;
 104        unsigned new_num = old_num + 1;
 105        unsigned long *new_configs;
 106
 107        new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
 108                               GFP_KERNEL);
 109        if (!new_configs) {
 110                dev_err(pctldev->dev, "krealloc(configs) failed\n");
 111                return -ENOMEM;
 112        }
 113
 114        new_configs[old_num] = config;
 115
 116        *configs = new_configs;
 117        *num_configs = new_num;
 118
 119        return 0;
 120}
 121EXPORT_SYMBOL_GPL(pinctrl_utils_add_config);
 122
 123void pinctrl_utils_free_map(struct pinctrl_dev *pctldev,
 124              struct pinctrl_map *map, unsigned num_maps)
 125{
 126        int i;
 127
 128        for (i = 0; i < num_maps; i++) {
 129                switch (map[i].type) {
 130                case PIN_MAP_TYPE_CONFIGS_GROUP:
 131                case PIN_MAP_TYPE_CONFIGS_PIN:
 132                        kfree(map[i].data.configs.configs);
 133                        break;
 134                default:
 135                        break;
 136                }
 137        }
 138        kfree(map);
 139}
 140EXPORT_SYMBOL_GPL(pinctrl_utils_free_map);
 141