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