2 * Copyright (C) 2008, 2009 Provigent Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * Driver for the ARM PrimeCell(tm) General Purpose Input/Output (PL061)
10 * Data sheet: ARM DDI 0190B, September 2000
12 #include <linux/spinlock.h>
13 #include <linux/errno.h>
14 #include <linux/module.h>
16 #include <linux/ioport.h>
17 #include <linux/irq.h>
18 #include <linux/bitops.h>
19 #include <linux/workqueue.h>
20 #include <linux/gpio.h>
21 #include <linux/device.h>
22 #include <linux/amba/bus.h>
23 #include <linux/amba/pl061.h>
24 #include <linux/slab.h>
26 #include <asm/mach/irq.h>
37 #define PL061_GPIO_NR 8
40 struct pl061_context_save_regs
{
51 /* Each of the two spinlocks protects a different set of hardware
52 * regiters and data structurs. This decouples the code of the IRQ from
53 * the GPIO code. This also makes the case of a GPIO routine call from
54 * the IRQ code simpler.
56 spinlock_t lock
; /* GPIO registers */
60 struct irq_chip_generic
*irq_gc
;
64 struct pl061_context_save_regs csave_regs
;
68 static int pl061_direction_input(struct gpio_chip
*gc
, unsigned offset
)
70 struct pl061_gpio
*chip
= container_of(gc
, struct pl061_gpio
, gc
);
72 unsigned char gpiodir
;
74 if (offset
>= gc
->ngpio
)
77 spin_lock_irqsave(&chip
->lock
, flags
);
78 gpiodir
= readb(chip
->base
+ GPIODIR
);
79 gpiodir
&= ~(1 << offset
);
80 writeb(gpiodir
, chip
->base
+ GPIODIR
);
81 spin_unlock_irqrestore(&chip
->lock
, flags
);
86 static int pl061_direction_output(struct gpio_chip
*gc
, unsigned offset
,
89 struct pl061_gpio
*chip
= container_of(gc
, struct pl061_gpio
, gc
);
91 unsigned char gpiodir
;
93 if (offset
>= gc
->ngpio
)
96 spin_lock_irqsave(&chip
->lock
, flags
);
97 writeb(!!value
<< offset
, chip
->base
+ (1 << (offset
+ 2)));
98 gpiodir
= readb(chip
->base
+ GPIODIR
);
99 gpiodir
|= 1 << offset
;
100 writeb(gpiodir
, chip
->base
+ GPIODIR
);
103 * gpio value is set again, because pl061 doesn't allow to set value of
104 * a gpio pin before configuring it in OUT mode.
106 writeb(!!value
<< offset
, chip
->base
+ (1 << (offset
+ 2)));
107 spin_unlock_irqrestore(&chip
->lock
, flags
);
112 static int pl061_get_value(struct gpio_chip
*gc
, unsigned offset
)
114 struct pl061_gpio
*chip
= container_of(gc
, struct pl061_gpio
, gc
);
116 return !!readb(chip
->base
+ (1 << (offset
+ 2)));
119 static void pl061_set_value(struct gpio_chip
*gc
, unsigned offset
, int value
)
121 struct pl061_gpio
*chip
= container_of(gc
, struct pl061_gpio
, gc
);
123 writeb(!!value
<< offset
, chip
->base
+ (1 << (offset
+ 2)));
126 static int pl061_to_irq(struct gpio_chip
*gc
, unsigned offset
)
128 struct pl061_gpio
*chip
= container_of(gc
, struct pl061_gpio
, gc
);
130 if (chip
->irq_base
<= 0)
133 return chip
->irq_base
+ offset
;
136 static int pl061_irq_type(struct irq_data
*d
, unsigned trigger
)
138 struct irq_chip_generic
*gc
= irq_data_get_irq_chip_data(d
);
139 struct pl061_gpio
*chip
= gc
->private;
140 int offset
= d
->irq
- chip
->irq_base
;
142 u8 gpiois
, gpioibe
, gpioiev
;
144 if (offset
< 0 || offset
>= PL061_GPIO_NR
)
147 raw_spin_lock_irqsave(&gc
->lock
, flags
);
149 gpioiev
= readb(chip
->base
+ GPIOIEV
);
151 gpiois
= readb(chip
->base
+ GPIOIS
);
152 if (trigger
& (IRQ_TYPE_LEVEL_HIGH
| IRQ_TYPE_LEVEL_LOW
)) {
153 gpiois
|= 1 << offset
;
154 if (trigger
& IRQ_TYPE_LEVEL_HIGH
)
155 gpioiev
|= 1 << offset
;
157 gpioiev
&= ~(1 << offset
);
159 gpiois
&= ~(1 << offset
);
160 writeb(gpiois
, chip
->base
+ GPIOIS
);
162 gpioibe
= readb(chip
->base
+ GPIOIBE
);
163 if ((trigger
& IRQ_TYPE_EDGE_BOTH
) == IRQ_TYPE_EDGE_BOTH
)
164 gpioibe
|= 1 << offset
;
166 gpioibe
&= ~(1 << offset
);
167 if (trigger
& IRQ_TYPE_EDGE_RISING
)
168 gpioiev
|= 1 << offset
;
169 else if (trigger
& IRQ_TYPE_EDGE_FALLING
)
170 gpioiev
&= ~(1 << offset
);
172 writeb(gpioibe
, chip
->base
+ GPIOIBE
);
174 writeb(gpioiev
, chip
->base
+ GPIOIEV
);
176 raw_spin_unlock_irqrestore(&gc
->lock
, flags
);
181 static void pl061_irq_handler(unsigned irq
, struct irq_desc
*desc
)
183 unsigned long pending
;
185 struct pl061_gpio
*chip
= irq_desc_get_handler_data(desc
);
186 struct irq_chip
*irqchip
= irq_desc_get_chip(desc
);
188 chained_irq_enter(irqchip
, desc
);
190 pending
= readb(chip
->base
+ GPIOMIS
);
191 writeb(pending
, chip
->base
+ GPIOIC
);
193 for_each_set_bit(offset
, &pending
, PL061_GPIO_NR
)
194 generic_handle_irq(pl061_to_irq(&chip
->gc
, offset
));
197 chained_irq_exit(irqchip
, desc
);
200 static void __init
pl061_init_gc(struct pl061_gpio
*chip
, int irq_base
)
202 struct irq_chip_type
*ct
;
204 chip
->irq_gc
= irq_alloc_generic_chip("gpio-pl061", 1, irq_base
,
205 chip
->base
, handle_simple_irq
);
206 chip
->irq_gc
->private = chip
;
208 ct
= chip
->irq_gc
->chip_types
;
209 ct
->chip
.irq_mask
= irq_gc_mask_clr_bit
;
210 ct
->chip
.irq_unmask
= irq_gc_mask_set_bit
;
211 ct
->chip
.irq_set_type
= pl061_irq_type
;
212 ct
->chip
.irq_set_wake
= irq_gc_set_wake
;
213 ct
->regs
.mask
= GPIOIE
;
215 irq_setup_generic_chip(chip
->irq_gc
, IRQ_MSK(PL061_GPIO_NR
),
216 IRQ_GC_INIT_NESTED_LOCK
, IRQ_NOREQUEST
, 0);
219 static int pl061_probe(struct amba_device
*dev
, const struct amba_id
*id
)
221 struct pl061_platform_data
*pdata
;
222 struct pl061_gpio
*chip
;
225 chip
= kzalloc(sizeof(*chip
), GFP_KERNEL
);
229 pdata
= dev
->dev
.platform_data
;
231 chip
->gc
.base
= pdata
->gpio_base
;
232 chip
->irq_base
= pdata
->irq_base
;
233 } else if (dev
->dev
.of_node
) {
241 if (!request_mem_region(dev
->res
.start
,
242 resource_size(&dev
->res
), "pl061")) {
247 chip
->base
= ioremap(dev
->res
.start
, resource_size(&dev
->res
));
248 if (chip
->base
== NULL
) {
253 spin_lock_init(&chip
->lock
);
255 chip
->gc
.direction_input
= pl061_direction_input
;
256 chip
->gc
.direction_output
= pl061_direction_output
;
257 chip
->gc
.get
= pl061_get_value
;
258 chip
->gc
.set
= pl061_set_value
;
259 chip
->gc
.to_irq
= pl061_to_irq
;
260 chip
->gc
.ngpio
= PL061_GPIO_NR
;
261 chip
->gc
.label
= dev_name(&dev
->dev
);
262 chip
->gc
.dev
= &dev
->dev
;
263 chip
->gc
.owner
= THIS_MODULE
;
265 ret
= gpiochip_add(&chip
->gc
);
273 if (chip
->irq_base
<= 0)
276 pl061_init_gc(chip
, chip
->irq_base
);
278 writeb(0, chip
->base
+ GPIOIE
); /* disable irqs */
284 irq_set_chained_handler(irq
, pl061_irq_handler
);
285 irq_set_handler_data(irq
, chip
);
287 for (i
= 0; i
< PL061_GPIO_NR
; i
++) {
289 if (pdata
->directions
& (1 << i
))
290 pl061_direction_output(&chip
->gc
, i
,
291 pdata
->values
& (1 << i
));
293 pl061_direction_input(&chip
->gc
, i
);
297 amba_set_drvdata(dev
, chip
);
304 release_mem_region(dev
->res
.start
, resource_size(&dev
->res
));
312 static int pl061_suspend(struct device
*dev
)
314 struct pl061_gpio
*chip
= dev_get_drvdata(dev
);
317 chip
->csave_regs
.gpio_data
= 0;
318 chip
->csave_regs
.gpio_dir
= readb(chip
->base
+ GPIODIR
);
319 chip
->csave_regs
.gpio_is
= readb(chip
->base
+ GPIOIS
);
320 chip
->csave_regs
.gpio_ibe
= readb(chip
->base
+ GPIOIBE
);
321 chip
->csave_regs
.gpio_iev
= readb(chip
->base
+ GPIOIEV
);
322 chip
->csave_regs
.gpio_ie
= readb(chip
->base
+ GPIOIE
);
324 for (offset
= 0; offset
< PL061_GPIO_NR
; offset
++) {
325 if (chip
->csave_regs
.gpio_dir
& (1 << offset
))
326 chip
->csave_regs
.gpio_data
|=
327 pl061_get_value(&chip
->gc
, offset
) << offset
;
333 static int pl061_resume(struct device
*dev
)
335 struct pl061_gpio
*chip
= dev_get_drvdata(dev
);
338 for (offset
= 0; offset
< PL061_GPIO_NR
; offset
++) {
339 if (chip
->csave_regs
.gpio_dir
& (1 << offset
))
340 pl061_direction_output(&chip
->gc
, offset
,
341 chip
->csave_regs
.gpio_data
&
344 pl061_direction_input(&chip
->gc
, offset
);
347 writeb(chip
->csave_regs
.gpio_is
, chip
->base
+ GPIOIS
);
348 writeb(chip
->csave_regs
.gpio_ibe
, chip
->base
+ GPIOIBE
);
349 writeb(chip
->csave_regs
.gpio_iev
, chip
->base
+ GPIOIEV
);
350 writeb(chip
->csave_regs
.gpio_ie
, chip
->base
+ GPIOIE
);
355 static SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops
, pl061_suspend
, pl061_resume
);
358 static struct amba_id pl061_ids
[] = {
366 MODULE_DEVICE_TABLE(amba
, pl061_ids
);
368 static struct amba_driver pl061_gpio_driver
= {
370 .name
= "pl061_gpio",
372 .pm
= &pl061_dev_pm_ops
,
375 .id_table
= pl061_ids
,
376 .probe
= pl061_probe
,
379 static int __init
pl061_gpio_init(void)
381 return amba_driver_register(&pl061_gpio_driver
);
383 subsys_initcall(pl061_gpio_init
);
385 MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
386 MODULE_DESCRIPTION("PL061 GPIO driver");
387 MODULE_LICENSE("GPL");