2 * linux/drivers/gpio/pl061.c
4 * Copyright (C) 2008, 2009 Provigent Ltd.
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.
10 * Driver for the ARM PrimeCell(tm) General Purpose Input/Output (PL061)
12 * Data sheet: ARM DDI 0190B, September 2000
14 #include <linux/spinlock.h>
15 #include <linux/errno.h>
16 #include <linux/module.h>
17 #include <linux/list.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>
37 #define PL061_GPIO_NR 8
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.
45 struct list_head list
;
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.
52 spinlock_t lock
; /* GPIO registers */
53 spinlock_t irq_lock
; /* IRQ registers */
60 static int pl061_direction_input(struct gpio_chip
*gc
, unsigned offset
)
62 struct pl061_gpio
*chip
= container_of(gc
, struct pl061_gpio
, gc
);
64 unsigned char gpiodir
;
66 if (offset
>= gc
->ngpio
)
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
);
78 static int pl061_direction_output(struct gpio_chip
*gc
, unsigned offset
,
81 struct pl061_gpio
*chip
= container_of(gc
, struct pl061_gpio
, gc
);
83 unsigned char gpiodir
;
85 if (offset
>= gc
->ngpio
)
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
);
98 static int pl061_get_value(struct gpio_chip
*gc
, unsigned offset
)
100 struct pl061_gpio
*chip
= container_of(gc
, struct pl061_gpio
, gc
);
102 return !!readb(chip
->base
+ (1 << (offset
+ 2)));
105 static void pl061_set_value(struct gpio_chip
*gc
, unsigned offset
, int value
)
107 struct pl061_gpio
*chip
= container_of(gc
, struct pl061_gpio
, gc
);
109 writeb(!!value
<< offset
, chip
->base
+ (1 << (offset
+ 2)));
112 static int pl061_to_irq(struct gpio_chip
*gc
, unsigned offset
)
114 struct pl061_gpio
*chip
= container_of(gc
, struct pl061_gpio
, gc
);
116 if (chip
->irq_base
== (unsigned) -1)
119 return chip
->irq_base
+ offset
;
125 static void pl061_irq_disable(unsigned irq
)
127 struct pl061_gpio
*chip
= get_irq_chip_data(irq
);
128 int offset
= irq
- chip
->irq_base
;
132 spin_lock_irqsave(&chip
->irq_lock
, flags
);
133 gpioie
= readb(chip
->base
+ GPIOIE
);
134 gpioie
&= ~(1 << offset
);
135 writeb(gpioie
, chip
->base
+ GPIOIE
);
136 spin_unlock_irqrestore(&chip
->irq_lock
, flags
);
139 static void pl061_irq_enable(unsigned irq
)
141 struct pl061_gpio
*chip
= get_irq_chip_data(irq
);
142 int offset
= irq
- chip
->irq_base
;
146 spin_lock_irqsave(&chip
->irq_lock
, flags
);
147 gpioie
= readb(chip
->base
+ GPIOIE
);
148 gpioie
|= 1 << offset
;
149 writeb(gpioie
, chip
->base
+ GPIOIE
);
150 spin_unlock_irqrestore(&chip
->irq_lock
, flags
);
153 static int pl061_irq_type(unsigned irq
, unsigned trigger
)
155 struct pl061_gpio
*chip
= get_irq_chip_data(irq
);
156 int offset
= irq
- chip
->irq_base
;
158 u8 gpiois
, gpioibe
, gpioiev
;
160 if (offset
< 0 || offset
> PL061_GPIO_NR
)
163 spin_lock_irqsave(&chip
->irq_lock
, flags
);
165 gpioiev
= readb(chip
->base
+ GPIOIEV
);
167 gpiois
= readb(chip
->base
+ GPIOIS
);
168 if (trigger
& (IRQ_TYPE_LEVEL_HIGH
| IRQ_TYPE_LEVEL_LOW
)) {
169 gpiois
|= 1 << offset
;
170 if (trigger
& IRQ_TYPE_LEVEL_HIGH
)
171 gpioiev
|= 1 << offset
;
173 gpioiev
&= ~(1 << offset
);
175 gpiois
&= ~(1 << offset
);
176 writeb(gpiois
, chip
->base
+ GPIOIS
);
178 gpioibe
= readb(chip
->base
+ GPIOIBE
);
179 if ((trigger
& IRQ_TYPE_EDGE_BOTH
) == IRQ_TYPE_EDGE_BOTH
)
180 gpioibe
|= 1 << offset
;
182 gpioibe
&= ~(1 << offset
);
183 if (trigger
& IRQ_TYPE_EDGE_RISING
)
184 gpioiev
|= 1 << offset
;
186 gpioiev
&= ~(1 << offset
);
188 writeb(gpioibe
, chip
->base
+ GPIOIBE
);
190 writeb(gpioiev
, chip
->base
+ GPIOIEV
);
192 spin_unlock_irqrestore(&chip
->irq_lock
, flags
);
197 static struct irq_chip pl061_irqchip
= {
199 .enable
= pl061_irq_enable
,
200 .disable
= pl061_irq_disable
,
201 .set_type
= pl061_irq_type
,
204 static void pl061_irq_handler(unsigned irq
, struct irq_desc
*desc
)
206 struct list_head
*chip_list
= get_irq_chip_data(irq
);
207 struct list_head
*ptr
;
208 struct pl061_gpio
*chip
;
210 desc
->chip
->ack(irq
);
211 list_for_each(ptr
, chip_list
) {
212 unsigned long pending
;
215 chip
= list_entry(ptr
, struct pl061_gpio
, list
);
216 pending
= readb(chip
->base
+ GPIOMIS
);
217 writeb(pending
, chip
->base
+ GPIOIC
);
222 for_each_bit(offset
, &pending
, PL061_GPIO_NR
)
223 generic_handle_irq(pl061_to_irq(&chip
->gc
, offset
));
225 desc
->chip
->unmask(irq
);
228 static int __init
pl061_probe(struct amba_device
*dev
, struct amba_id
*id
)
230 struct pl061_platform_data
*pdata
;
231 struct pl061_gpio
*chip
;
232 struct list_head
*chip_list
;
234 static DECLARE_BITMAP(init_irq
, NR_IRQS
);
236 pdata
= dev
->dev
.platform_data
;
240 chip
= kzalloc(sizeof(*chip
), GFP_KERNEL
);
244 if (!request_mem_region(dev
->res
.start
,
245 resource_size(&dev
->res
), "pl061")) {
250 chip
->base
= ioremap(dev
->res
.start
, resource_size(&dev
->res
));
251 if (chip
->base
== NULL
) {
256 spin_lock_init(&chip
->lock
);
257 spin_lock_init(&chip
->irq_lock
);
258 INIT_LIST_HEAD(&chip
->list
);
260 chip
->gc
.direction_input
= pl061_direction_input
;
261 chip
->gc
.direction_output
= pl061_direction_output
;
262 chip
->gc
.get
= pl061_get_value
;
263 chip
->gc
.set
= pl061_set_value
;
264 chip
->gc
.to_irq
= pl061_to_irq
;
265 chip
->gc
.base
= pdata
->gpio_base
;
266 chip
->gc
.ngpio
= PL061_GPIO_NR
;
267 chip
->gc
.label
= dev_name(&dev
->dev
);
268 chip
->gc
.dev
= &dev
->dev
;
269 chip
->gc
.owner
= THIS_MODULE
;
271 chip
->irq_base
= pdata
->irq_base
;
273 ret
= gpiochip_add(&chip
->gc
);
281 if (chip
->irq_base
== (unsigned) -1)
284 writeb(0, chip
->base
+ GPIOIE
); /* disable irqs */
290 set_irq_chained_handler(irq
, pl061_irq_handler
);
291 if (!test_and_set_bit(irq
, init_irq
)) { /* list initialized? */
292 chip_list
= kmalloc(sizeof(*chip_list
), GFP_KERNEL
);
293 if (chip_list
== NULL
) {
294 clear_bit(irq
, init_irq
);
298 INIT_LIST_HEAD(chip_list
);
299 set_irq_chip_data(irq
, chip_list
);
301 chip_list
= get_irq_chip_data(irq
);
302 list_add(&chip
->list
, chip_list
);
304 for (i
= 0; i
< PL061_GPIO_NR
; i
++) {
305 if (pdata
->directions
& (1 << i
))
306 pl061_direction_output(&chip
->gc
, i
,
307 pdata
->values
& (1 << i
));
309 pl061_direction_input(&chip
->gc
, i
);
311 set_irq_chip(i
+chip
->irq_base
, &pl061_irqchip
);
312 set_irq_handler(i
+chip
->irq_base
, handle_simple_irq
);
313 set_irq_flags(i
+chip
->irq_base
, IRQF_VALID
);
314 set_irq_chip_data(i
+chip
->irq_base
, chip
);
322 release_mem_region(dev
->res
.start
, resource_size(&dev
->res
));
329 static struct amba_id pl061_ids
[] __initdata
= {
337 static struct amba_driver pl061_gpio_driver
= {
339 .name
= "pl061_gpio",
341 .id_table
= pl061_ids
,
342 .probe
= pl061_probe
,
345 static int __init
pl061_gpio_init(void)
347 return amba_driver_register(&pl061_gpio_driver
);
349 subsys_initcall(pl061_gpio_init
);
351 MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
352 MODULE_DESCRIPTION("PL061 GPIO driver");
353 MODULE_LICENSE("GPL");