]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/staging/dream/generic_gpio.c
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel...
[net-next-2.6.git] / drivers / staging / dream / generic_gpio.c
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
26 struct gpio_state {
27         unsigned long flags;
28         int refcount;
29 };
30
31 static DEFINE_SPINLOCK(gpio_chips_lock);
32 static LIST_HEAD(gpio_chip_list);
33 static struct gpio_chip **gpio_chip_array;
34 static unsigned long gpio_chip_array_size;
35
36 int 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);
84 added:
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         }
89 failed:
90         spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
91         if (err)
92                 kfree(new_gpio_chip->state);
93         return err;
94 }
95
96 static 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
116 static 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;
138 err:
139         spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
140         return err;
141 }
142
143 int gpio_request(unsigned gpio, const char *label)
144 {
145         return request_gpio(gpio, 0);
146 }
147 EXPORT_SYMBOL(gpio_request);
148
149 void 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 }
163 EXPORT_SYMBOL(gpio_free);
164
165 static 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
179 int 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 }
187 EXPORT_SYMBOL(gpio_to_irq);
188
189 int 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 }
202 EXPORT_SYMBOL(gpio_configure);
203
204 int gpio_direction_input(unsigned gpio)
205 {
206         return gpio_configure(gpio, GPIOF_INPUT);
207 }
208 EXPORT_SYMBOL(gpio_direction_input);
209
210 int gpio_direction_output(unsigned gpio, int value)
211 {
212         gpio_set_value(gpio, value);
213         return gpio_configure(gpio, GPIOF_DRIVE_OUTPUT);
214 }
215 EXPORT_SYMBOL(gpio_direction_output);
216
217 int 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 }
230 EXPORT_SYMBOL(gpio_get_value);
231
232 void 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 }
244 EXPORT_SYMBOL(gpio_set_value);
245
246 int 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 }
259 EXPORT_SYMBOL(gpio_read_detect_status);
260
261 int 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 }
274 EXPORT_SYMBOL(gpio_clear_detect_status);