Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt...
[pandora-kernel.git] / drivers / gpio / pl061.c
1 /*
2  *  linux/drivers/gpio/pl061.c
3  *
4  *  Copyright (C) 2008, 2009 Provigent Ltd.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * Driver for the ARM PrimeCell(tm) General Purpose Input/Output (PL061)
11  *
12  * Data sheet: ARM DDI 0190B, September 2000
13  */
14 #include <linux/spinlock.h>
15 #include <linux/errno.h>
16 #include <linux/module.h>
17 #include <linux/list.h>
18 #include <linux/io.h>
19 #include <linux/ioport.h>
20 #include <linux/irq.h>
21 #include <linux/bitops.h>
22 #include <linux/workqueue.h>
23 #include <linux/gpio.h>
24 #include <linux/device.h>
25 #include <linux/amba/bus.h>
26 #include <linux/amba/pl061.h>
27 #include <linux/slab.h>
28
29 #define GPIODIR 0x400
30 #define GPIOIS  0x404
31 #define GPIOIBE 0x408
32 #define GPIOIEV 0x40C
33 #define GPIOIE  0x410
34 #define GPIORIS 0x414
35 #define GPIOMIS 0x418
36 #define GPIOIC  0x41C
37
38 #define PL061_GPIO_NR   8
39
40 struct pl061_gpio {
41         /* We use a list of pl061_gpio structs for each trigger IRQ in the main
42          * interrupts controller of the system. We need this to support systems
43          * in which more that one PL061s are connected to the same IRQ. The ISR
44          * interates through this list to find the source of the interrupt.
45          */
46         struct list_head        list;
47
48         /* Each of the two spinlocks protects a different set of hardware
49          * regiters and data structurs. This decouples the code of the IRQ from
50          * the GPIO code. This also makes the case of a GPIO routine call from
51          * the IRQ code simpler.
52          */
53         spinlock_t              lock;           /* GPIO registers */
54         spinlock_t              irq_lock;       /* IRQ registers */
55
56         void __iomem            *base;
57         unsigned                irq_base;
58         struct gpio_chip        gc;
59 };
60
61 static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
62 {
63         struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
64         unsigned long flags;
65         unsigned char gpiodir;
66
67         if (offset >= gc->ngpio)
68                 return -EINVAL;
69
70         spin_lock_irqsave(&chip->lock, flags);
71         gpiodir = readb(chip->base + GPIODIR);
72         gpiodir &= ~(1 << offset);
73         writeb(gpiodir, chip->base + GPIODIR);
74         spin_unlock_irqrestore(&chip->lock, flags);
75
76         return 0;
77 }
78
79 static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
80                 int value)
81 {
82         struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
83         unsigned long flags;
84         unsigned char gpiodir;
85
86         if (offset >= gc->ngpio)
87                 return -EINVAL;
88
89         spin_lock_irqsave(&chip->lock, flags);
90         writeb(!!value << offset, chip->base + (1 << (offset + 2)));
91         gpiodir = readb(chip->base + GPIODIR);
92         gpiodir |= 1 << offset;
93         writeb(gpiodir, chip->base + GPIODIR);
94         spin_unlock_irqrestore(&chip->lock, flags);
95
96         return 0;
97 }
98
99 static int pl061_get_value(struct gpio_chip *gc, unsigned offset)
100 {
101         struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
102
103         return !!readb(chip->base + (1 << (offset + 2)));
104 }
105
106 static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value)
107 {
108         struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
109
110         writeb(!!value << offset, chip->base + (1 << (offset + 2)));
111 }
112
113 static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
114 {
115         struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
116
117         if (chip->irq_base == (unsigned) -1)
118                 return -EINVAL;
119
120         return chip->irq_base + offset;
121 }
122
123 /*
124  * PL061 GPIO IRQ
125  */
126 static void pl061_irq_disable(unsigned irq)
127 {
128         struct pl061_gpio *chip = get_irq_chip_data(irq);
129         int offset = irq - chip->irq_base;
130         unsigned long flags;
131         u8 gpioie;
132
133         spin_lock_irqsave(&chip->irq_lock, flags);
134         gpioie = readb(chip->base + GPIOIE);
135         gpioie &= ~(1 << offset);
136         writeb(gpioie, chip->base + GPIOIE);
137         spin_unlock_irqrestore(&chip->irq_lock, flags);
138 }
139
140 static void pl061_irq_enable(unsigned irq)
141 {
142         struct pl061_gpio *chip = get_irq_chip_data(irq);
143         int offset = irq - chip->irq_base;
144         unsigned long flags;
145         u8 gpioie;
146
147         spin_lock_irqsave(&chip->irq_lock, flags);
148         gpioie = readb(chip->base + GPIOIE);
149         gpioie |= 1 << offset;
150         writeb(gpioie, chip->base + GPIOIE);
151         spin_unlock_irqrestore(&chip->irq_lock, flags);
152 }
153
154 static int pl061_irq_type(unsigned irq, unsigned trigger)
155 {
156         struct pl061_gpio *chip = get_irq_chip_data(irq);
157         int offset = irq - chip->irq_base;
158         unsigned long flags;
159         u8 gpiois, gpioibe, gpioiev;
160
161         if (offset < 0 || offset > PL061_GPIO_NR)
162                 return -EINVAL;
163
164         spin_lock_irqsave(&chip->irq_lock, flags);
165
166         gpioiev = readb(chip->base + GPIOIEV);
167
168         gpiois = readb(chip->base + GPIOIS);
169         if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
170                 gpiois |= 1 << offset;
171                 if (trigger & IRQ_TYPE_LEVEL_HIGH)
172                         gpioiev |= 1 << offset;
173                 else
174                         gpioiev &= ~(1 << offset);
175         } else
176                 gpiois &= ~(1 << offset);
177         writeb(gpiois, chip->base + GPIOIS);
178
179         gpioibe = readb(chip->base + GPIOIBE);
180         if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
181                 gpioibe |= 1 << offset;
182         else {
183                 gpioibe &= ~(1 << offset);
184                 if (trigger & IRQ_TYPE_EDGE_RISING)
185                         gpioiev |= 1 << offset;
186                 else
187                         gpioiev &= ~(1 << offset);
188         }
189         writeb(gpioibe, chip->base + GPIOIBE);
190
191         writeb(gpioiev, chip->base + GPIOIEV);
192
193         spin_unlock_irqrestore(&chip->irq_lock, flags);
194
195         return 0;
196 }
197
198 static struct irq_chip pl061_irqchip = {
199         .name           = "GPIO",
200         .enable         = pl061_irq_enable,
201         .disable        = pl061_irq_disable,
202         .set_type       = pl061_irq_type,
203 };
204
205 static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
206 {
207         struct list_head *chip_list = get_irq_chip_data(irq);
208         struct list_head *ptr;
209         struct pl061_gpio *chip;
210
211         desc->chip->ack(irq);
212         list_for_each(ptr, chip_list) {
213                 unsigned long pending;
214                 int offset;
215
216                 chip = list_entry(ptr, struct pl061_gpio, list);
217                 pending = readb(chip->base + GPIOMIS);
218                 writeb(pending, chip->base + GPIOIC);
219
220                 if (pending == 0)
221                         continue;
222
223                 for_each_set_bit(offset, &pending, PL061_GPIO_NR)
224                         generic_handle_irq(pl061_to_irq(&chip->gc, offset));
225         }
226         desc->chip->unmask(irq);
227 }
228
229 static int __init pl061_probe(struct amba_device *dev, struct amba_id *id)
230 {
231         struct pl061_platform_data *pdata;
232         struct pl061_gpio *chip;
233         struct list_head *chip_list;
234         int ret, irq, i;
235         static DECLARE_BITMAP(init_irq, NR_IRQS);
236
237         pdata = dev->dev.platform_data;
238         if (pdata == NULL)
239                 return -ENODEV;
240
241         chip = kzalloc(sizeof(*chip), GFP_KERNEL);
242         if (chip == NULL)
243                 return -ENOMEM;
244
245         if (!request_mem_region(dev->res.start,
246                                 resource_size(&dev->res), "pl061")) {
247                 ret = -EBUSY;
248                 goto free_mem;
249         }
250
251         chip->base = ioremap(dev->res.start, resource_size(&dev->res));
252         if (chip->base == NULL) {
253                 ret = -ENOMEM;
254                 goto release_region;
255         }
256
257         spin_lock_init(&chip->lock);
258         spin_lock_init(&chip->irq_lock);
259         INIT_LIST_HEAD(&chip->list);
260
261         chip->gc.direction_input = pl061_direction_input;
262         chip->gc.direction_output = pl061_direction_output;
263         chip->gc.get = pl061_get_value;
264         chip->gc.set = pl061_set_value;
265         chip->gc.to_irq = pl061_to_irq;
266         chip->gc.base = pdata->gpio_base;
267         chip->gc.ngpio = PL061_GPIO_NR;
268         chip->gc.label = dev_name(&dev->dev);
269         chip->gc.dev = &dev->dev;
270         chip->gc.owner = THIS_MODULE;
271
272         chip->irq_base = pdata->irq_base;
273
274         ret = gpiochip_add(&chip->gc);
275         if (ret)
276                 goto iounmap;
277
278         /*
279          * irq_chip support
280          */
281
282         if (chip->irq_base == (unsigned) -1)
283                 return 0;
284
285         writeb(0, chip->base + GPIOIE); /* disable irqs */
286         irq = dev->irq[0];
287         if (irq < 0) {
288                 ret = -ENODEV;
289                 goto iounmap;
290         }
291         set_irq_chained_handler(irq, pl061_irq_handler);
292         if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */
293                 chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL);
294                 if (chip_list == NULL) {
295                         clear_bit(irq, init_irq);
296                         ret = -ENOMEM;
297                         goto iounmap;
298                 }
299                 INIT_LIST_HEAD(chip_list);
300                 set_irq_chip_data(irq, chip_list);
301         } else
302                 chip_list = get_irq_chip_data(irq);
303         list_add(&chip->list, chip_list);
304
305         for (i = 0; i < PL061_GPIO_NR; i++) {
306                 if (pdata->directions & (1 << i))
307                         pl061_direction_output(&chip->gc, i,
308                                         pdata->values & (1 << i));
309                 else
310                         pl061_direction_input(&chip->gc, i);
311
312                 set_irq_chip(i+chip->irq_base, &pl061_irqchip);
313                 set_irq_handler(i+chip->irq_base, handle_simple_irq);
314                 set_irq_flags(i+chip->irq_base, IRQF_VALID);
315                 set_irq_chip_data(i+chip->irq_base, chip);
316         }
317
318         return 0;
319
320 iounmap:
321         iounmap(chip->base);
322 release_region:
323         release_mem_region(dev->res.start, resource_size(&dev->res));
324 free_mem:
325         kfree(chip);
326
327         return ret;
328 }
329
330 static struct amba_id pl061_ids[] __initdata = {
331         {
332                 .id     = 0x00041061,
333                 .mask   = 0x000fffff,
334         },
335         { 0, 0 },
336 };
337
338 static struct amba_driver pl061_gpio_driver = {
339         .drv = {
340                 .name   = "pl061_gpio",
341         },
342         .id_table       = pl061_ids,
343         .probe          = pl061_probe,
344 };
345
346 static int __init pl061_gpio_init(void)
347 {
348         return amba_driver_register(&pl061_gpio_driver);
349 }
350 subsys_initcall(pl061_gpio_init);
351
352 MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
353 MODULE_DESCRIPTION("PL061 GPIO driver");
354 MODULE_LICENSE("GPL");