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(*map, sizeof(*new_map) * new_num, 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                dev_err(pctldev->dev, "kmemdup(configs) failed\n");
  88                return -ENOMEM;
  89        }
  90
  91        (*map)[*num_maps].type = type;
  92        (*map)[*num_maps].data.configs.group_or_pin = group;
  93        (*map)[*num_maps].data.configs.configs = dup_configs;
  94        (*map)[*num_maps].data.configs.num_configs = num_configs;
  95        (*num_maps)++;
  96
  97        return 0;
  98}
  99EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_configs);
 100
 101int pinctrl_utils_add_config(struct pinctrl_dev *pctldev,
 102                unsigned long **configs, unsigned *num_configs,
 103                unsigned long config)
 104{
 105        unsigned old_num = *num_configs;
 106        unsigned new_num = old_num + 1;
 107        unsigned long *new_configs;
 108
 109        new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
 110                               GFP_KERNEL);
 111        if (!new_configs) {
 112                dev_err(pctldev->dev, "krealloc(configs) failed\n");
 113                return -ENOMEM;
 114        }
 115
 116        new_configs[old_num] = config;
 117
 118        *configs = new_configs;
 119        *num_configs = new_num;
 120
 121        return 0;
 122}
 123EXPORT_SYMBOL_GPL(pinctrl_utils_add_config);
 124
 125void pinctrl_utils_dt_free_map(struct pinctrl_dev *pctldev,
 126              struct pinctrl_map *map, unsigned num_maps)
 127{
 128        int i;
 129
 130        for (i = 0; i < num_maps; i++) {
 131                switch (map[i].type) {
 132                case PIN_MAP_TYPE_CONFIGS_GROUP:
 133                case PIN_MAP_TYPE_CONFIGS_PIN:
 134                        kfree(map[i].data.configs.configs);
 135                        break;
 136                default:
 137                        break;
 138                }
 139        }
 140        kfree(map);
 141}
 142EXPORT_SYMBOL_GPL(pinctrl_utils_dt_free_map);
 143