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)));
115 static void pl061_irq_disable(unsigned irq
)
117 struct pl061_gpio
*chip
= get_irq_chip_data(irq
);
118 int offset
= irq
- chip
->irq_base
;
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
);
129 static void pl061_irq_enable(unsigned irq
)
131 struct pl061_gpio
*chip
= get_irq_chip_data(irq
);
132 int offset
= irq
- chip
->irq_base
;
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
);
143 static int pl061_irq_type(unsigned irq
, unsigned trigger
)
145 struct pl061_gpio
*chip
= get_irq_chip_data(irq
);
146 int offset
= irq
- chip
->irq_base
;
148 u8 gpiois
, gpioibe
, gpioiev
;
150 if (offset
< 0 || offset
> PL061_GPIO_NR
)
153 spin_lock_irqsave(&chip
->irq_lock
, flags
);
155 gpioiev
= readb(chip
->base
+ GPIOIEV
);
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
;
163 gpioiev
&= ~(1 << offset
);
165 gpiois
&= ~(1 << offset
);
166 writeb(gpiois
, chip
->base
+ GPIOIS
);
168 gpioibe
= readb(chip
->base
+ GPIOIBE
);
169 if ((trigger
& IRQ_TYPE_EDGE_BOTH
) == IRQ_TYPE_EDGE_BOTH
)
170 gpioibe
|= 1 << offset
;
172 gpioibe
&= ~(1 << offset
);
173 if (trigger
& IRQ_TYPE_EDGE_RISING
)
174 gpioiev
|= 1 << offset
;
176 gpioiev
&= ~(1 << offset
);
178 writeb(gpioibe
, chip
->base
+ GPIOIBE
);
180 writeb(gpioiev
, chip
->base
+ GPIOIEV
);
182 spin_unlock_irqrestore(&chip
->irq_lock
, flags
);
187 static struct irq_chip pl061_irqchip
= {
189 .enable
= pl061_irq_enable
,
190 .disable
= pl061_irq_disable
,
191 .set_type
= pl061_irq_type
,
194 static void pl061_irq_handler(unsigned irq
, struct irq_desc
*desc
)
196 struct list_head
*chip_list
= get_irq_chip_data(irq
);
197 struct list_head
*ptr
;
198 struct pl061_gpio
*chip
;
200 desc
->chip
->ack(irq
);
201 list_for_each(ptr
, chip_list
) {
202 unsigned long pending
;
205 chip
= list_entry(ptr
, struct pl061_gpio
, list
);
206 pending
= readb(chip
->base
+ GPIOMIS
);
207 writeb(pending
, chip
->base
+ GPIOIC
);
212 for_each_bit(gpio
, &pending
, PL061_GPIO_NR
)
213 generic_handle_irq(gpio_to_irq(gpio
));
215 desc
->chip
->unmask(irq
);
218 static int __init
pl061_probe(struct amba_device
*dev
, struct amba_id
*id
)
220 struct pl061_platform_data
*pdata
;
221 struct pl061_gpio
*chip
;
222 struct list_head
*chip_list
;
224 static unsigned long init_irq
[BITS_TO_LONGS(NR_IRQS
)];
226 pdata
= dev
->dev
.platform_data
;
230 chip
= kzalloc(sizeof(*chip
), GFP_KERNEL
);
234 if (!request_mem_region(dev
->res
.start
,
235 resource_size(&dev
->res
), "pl061")) {
240 chip
->base
= ioremap(dev
->res
.start
, resource_size(&dev
->res
));
241 if (chip
->base
== NULL
) {
246 spin_lock_init(&chip
->lock
);
247 spin_lock_init(&chip
->irq_lock
);
248 INIT_LIST_HEAD(&chip
->list
);
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
;
260 chip
->irq_base
= pdata
->irq_base
;
262 ret
= gpiochip_add(&chip
->gc
);
270 if (chip
->irq_base
== (unsigned) -1)
273 writeb(0, chip
->base
+ GPIOIE
); /* disable irqs */
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
) {
286 INIT_LIST_HEAD(chip_list
);
287 set_irq_chip_data(irq
, chip_list
);
289 chip_list
= get_irq_chip_data(irq
);
290 list_add(&chip
->list
, chip_list
);
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
));
297 pl061_direction_input(&chip
->gc
, i
);
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
);
310 release_mem_region(dev
->res
.start
, resource_size(&dev
->res
));
317 static struct amba_id pl061_ids
[] __initdata
= {
325 static struct amba_driver pl061_gpio_driver
= {
327 .name
= "pl061_gpio",
329 .id_table
= pl061_ids
,
330 .probe
= pl061_probe
,
333 static int __init
pl061_gpio_init(void)
335 return amba_driver_register(&pl061_gpio_driver
);
337 subsys_initcall(pl061_gpio_init
);
339 MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
340 MODULE_DESCRIPTION("PL061 GPIO driver");
341 MODULE_LICENSE("GPL");