linux/drivers/staging/dream/generic_gpio.c
<<
>>
Prefs
   1/* arch/arm/mach-msm/generic_gpio.c
   2 *
   3 * Copyright (C) 2007 Google, Inc.
   4 *
   5 * This software is licensed under the terms of the GNU General Public
   6 * License version 2, as published by the Free Software Foundation, and
   7 * may be copied, distributed, and modified under those terms.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 */
  15
  16#include <linux/kernel.h>
  17#include <linux/module.h>
  18#include <linux/errno.h>
  19#include <linux/slab.h>
  20#include <linux/spinlock.h>
  21#include <asm/gpio.h>
  22#include "gpio_chip.h"
  23
  24#define GPIO_NUM_TO_CHIP_INDEX(gpio) ((gpio)>>5)
  25
  26struct gpio_state {
  27        unsigned long flags;
  28        int refcount;
  29};
  30
  31static DEFINE_SPINLOCK(gpio_chips_lock);
  32static LIST_HEAD(gpio_chip_list);
  33static struct gpio_chip **gpio_chip_array;
  34static unsigned long gpio_chip_array_size;
  35
  36int register_gpio_chip(struct gpio_chip *new_gpio_chip)
  37{
  38        int err = 0;
  39        struct gpio_chip *gpio_chip;
  40        int i;
  41        unsigned long irq_flags;
  42        unsigned int chip_array_start_index, chip_array_end_index;
  43
  44        new_gpio_chip->state = kzalloc((new_gpio_chip->end + 1 - new_gpio_chip->start) * sizeof(new_gpio_chip->state[0]), GFP_KERNEL);
  45        if (new_gpio_chip->state == NULL) {
  46                printk(KERN_ERR "register_gpio_chip: failed to allocate state\n");
  47                return -ENOMEM;
  48        }
  49
  50        spin_lock_irqsave(&gpio_chips_lock, irq_flags);
  51        chip_array_start_index = GPIO_NUM_TO_CHIP_INDEX(new_gpio_chip->start);
  52        chip_array_end_index = GPIO_NUM_TO_CHIP_INDEX(new_gpio_chip->end);
  53        if (chip_array_end_index >= gpio_chip_array_size) {
  54                struct gpio_chip **new_gpio_chip_array;
  55                unsigned long new_gpio_chip_array_size = chip_array_end_index + 1;
  56
  57                new_gpio_chip_array = kmalloc(new_gpio_chip_array_size * sizeof(new_gpio_chip_array[0]), GFP_ATOMIC);
  58                if (new_gpio_chip_array == NULL) {
  59                        printk(KERN_ERR "register_gpio_chip: failed to allocate array\n");
  60                        err = -ENOMEM;
  61                        goto failed;
  62                }
  63                for (i = 0; i < gpio_chip_array_size; i++)
  64                        new_gpio_chip_array[i] = gpio_chip_array[i];
  65                for (i = gpio_chip_array_size; i < new_gpio_chip_array_size; i++)
  66                        new_gpio_chip_array[i] = NULL;
  67                gpio_chip_array = new_gpio_chip_array;
  68                gpio_chip_array_size = new_gpio_chip_array_size;
  69        }
  70        list_for_each_entry(gpio_chip, &gpio_chip_list, list) {
  71                if (gpio_chip->start > new_gpio_chip->end) {
  72                        list_add_tail(&new_gpio_chip->list, &gpio_chip->list);
  73                        goto added;
  74                }
  75                if (gpio_chip->end >= new_gpio_chip->start) {
  76                        printk(KERN_ERR "register_gpio_source %u-%u overlaps with %u-%u\n",
  77                               new_gpio_chip->start, new_gpio_chip->end,
  78                               gpio_chip->start, gpio_chip->end);
  79                        err = -EBUSY;
  80                        goto failed;
  81                }
  82        }
  83        list_add_tail(&new_gpio_chip->list, &gpio_chip_list);
  84added:
  85        for (i = chip_array_start_index; i <= chip_array_end_index; i++) {
  86                if (gpio_chip_array[i] == NULL || gpio_chip_array[i]->start > new_gpio_chip->start)
  87                        gpio_chip_array[i] = new_gpio_chip;
  88        }
  89failed:
  90        spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
  91        if (err)
  92                kfree(new_gpio_chip->state);
  93        return err;
  94}
  95
  96static struct gpio_chip *get_gpio_chip_locked(unsigned int gpio)
  97{
  98        unsigned long i;
  99        struct gpio_chip *chip;
 100
 101        i = GPIO_NUM_TO_CHIP_INDEX(gpio);
 102        if (i >= gpio_chip_array_size)
 103                return NULL;
 104        chip = gpio_chip_array[i];
 105        if (chip == NULL)
 106                return NULL;
 107        list_for_each_entry_from(chip, &gpio_chip_list, list) {
 108                if (gpio < chip->start)
 109                        return NULL;
 110                if (gpio <= chip->end)
 111                        return chip;
 112        }
 113        return NULL;
 114}
 115
 116static int request_gpio(unsigned int gpio, unsigned long flags)
 117{
 118        int err = 0;
 119        struct gpio_chip *chip;
 120        unsigned long irq_flags;
 121        unsigned long chip_index;
 122
 123        spin_lock_irqsave(&gpio_chips_lock, irq_flags);
 124        chip = get_gpio_chip_locked(gpio);
 125        if (chip == NULL) {
 126                err = -EINVAL;
 127                goto err;
 128        }
 129        chip_index = gpio - chip->start;
 130        if (chip->state[chip_index].refcount == 0) {
 131                chip->configure(chip, gpio, flags);
 132                chip->state[chip_index].flags = flags;
 133                chip->state[chip_index].refcount++;
 134        } else if ((flags & IRQF_SHARED) && (chip->state[chip_index].flags & IRQF_SHARED))
 135                chip->state[chip_index].refcount++;
 136        else
 137                err = -EBUSY;
 138err:
 139        spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
 140        return err;
 141}
 142
 143int gpio_request(unsigned gpio, const char *label)
 144{
 145        return request_gpio(gpio, 0);
 146}
 147EXPORT_SYMBOL(gpio_request);
 148
 149void gpio_free(unsigned gpio)
 150{
 151        struct gpio_chip *chip;
 152        unsigned long irq_flags;
 153        unsigned long chip_index;
 154
 155        spin_lock_irqsave(&gpio_chips_lock, irq_flags);
 156        chip = get_gpio_chip_locked(gpio);
 157        if (chip) {
 158                chip_index = gpio - chip->start;
 159                chip->state[chip_index].refcount--;
 160        }
 161        spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
 162}
 163EXPORT_SYMBOL(gpio_free);
 164
 165static int gpio_get_irq_num(unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp)
 166{
 167        int ret = -ENOTSUPP;
 168        struct gpio_chip *chip;
 169        unsigned long irq_flags;
 170
 171        spin_lock_irqsave(&gpio_chips_lock, irq_flags);
 172        chip = get_gpio_chip_locked(gpio);
 173        if (chip && chip->get_irq_num)
 174                ret = chip->get_irq_num(chip, gpio, irqp, irqnumflagsp);
 175        spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
 176        return ret;
 177}
 178
 179int gpio_to_irq(unsigned gpio)
 180{
 181        int ret, irq;
 182        ret = gpio_get_irq_num(gpio, &irq, NULL);
 183        if (ret)
 184                return ret;
 185        return irq;
 186}
 187EXPORT_SYMBOL(gpio_to_irq);
 188
 189int gpio_configure(unsigned int gpio, unsigned long flags)
 190{
 191        int ret = -ENOTSUPP;
 192        struct gpio_chip *chip;
 193        unsigned long irq_flags;
 194
 195        spin_lock_irqsave(&gpio_chips_lock, irq_flags);
 196        chip = get_gpio_chip_locked(gpio);
 197        if (chip)
 198                ret = chip->configure(chip, gpio, flags);
 199        spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
 200        return ret;
 201}
 202EXPORT_SYMBOL(gpio_configure);
 203
 204int gpio_direction_input(unsigned gpio)
 205{
 206        return gpio_configure(gpio, GPIOF_INPUT);
 207}
 208EXPORT_SYMBOL(gpio_direction_input);
 209
 210int gpio_direction_output(unsigned gpio, int value)
 211{
 212        gpio_set_value(gpio, value);
 213        return gpio_configure(gpio, GPIOF_DRIVE_OUTPUT);
 214}
 215EXPORT_SYMBOL(gpio_direction_output);
 216
 217int gpio_get_value(unsigned gpio)
 218{
 219        int ret = -ENOTSUPP;
 220        struct gpio_chip *chip;
 221        unsigned long irq_flags;
 222
 223        spin_lock_irqsave(&gpio_chips_lock, irq_flags);
 224        chip = get_gpio_chip_locked(gpio);
 225        if (chip && chip->read)
 226                ret = chip->read(chip, gpio);
 227        spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
 228        return ret;
 229}
 230EXPORT_SYMBOL(gpio_get_value);
 231
 232void gpio_set_value(unsigned gpio, int on)
 233{
 234        int ret = -ENOTSUPP;
 235        struct gpio_chip *chip;
 236        unsigned long irq_flags;
 237
 238        spin_lock_irqsave(&gpio_chips_lock, irq_flags);
 239        chip = get_gpio_chip_locked(gpio);
 240        if (chip && chip->write)
 241                ret = chip->write(chip, gpio, on);
 242        spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
 243}
 244EXPORT_SYMBOL(gpio_set_value);
 245
 246int gpio_read_detect_status(unsigned int gpio)
 247{
 248        int ret = -ENOTSUPP;
 249        struct gpio_chip *chip;
 250        unsigned long irq_flags;
 251
 252        spin_lock_irqsave(&gpio_chips_lock, irq_flags);
 253        chip = get_gpio_chip_locked(gpio);
 254        if (chip && chip->read_detect_status)
 255                ret = chip->read_detect_status(chip, gpio);
 256        spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
 257        return ret;
 258}
 259EXPORT_SYMBOL(gpio_read_detect_status);
 260
 261int gpio_clear_detect_status(unsigned int gpio)
 262{
 263        int ret = -ENOTSUPP;
 264        struct gpio_chip *chip;
 265        unsigned long irq_flags;
 266
 267        spin_lock_irqsave(&gpio_chips_lock, irq_flags);
 268        chip = get_gpio_chip_locked(gpio);
 269        if (chip && chip->clear_detect_status)
 270                ret = chip->clear_detect_status(chip, gpio);
 271        spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
 272        return ret;
 273}
 274EXPORT_SYMBOL(gpio_clear_detect_status);
 275
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.