• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/staging/dream/
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