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
{
55 struct irq_chip_generic
*irq_gc
;
59 struct pl061_context_save_regs csave_regs
;
63 static int pl061_direction_input(struct gpio_chip
*gc
, unsigned offset
)
65 struct pl061_gpio
*chip
= container_of(gc
, struct pl061_gpio
, gc
);
67 unsigned char gpiodir
;
69 if (offset
>= gc
->ngpio
)
72 spin_lock_irqsave(&chip
->lock
, flags
);
73 gpiodir
= readb(chip
->base
+ GPIODIR
);
74 gpiodir
&= ~(1 << offset
);
75 writeb(gpiodir
, chip
->base
+ GPIODIR
);
76 spin_unlock_irqrestore(&chip
->lock
, flags
);
81 static int pl061_direction_output(struct gpio_chip
*gc
, unsigned offset
,
84 struct pl061_gpio
*chip
= container_of(gc
, struct pl061_gpio
, gc
);
86 unsigned char gpiodir
;
88 if (offset
>= gc
->ngpio
)
91 spin_lock_irqsave(&chip
->lock
, flags
);
92 writeb(!!value
<< offset
, chip
->base
+ (1 << (offset
+ 2)));
93 gpiodir
= readb(chip
->base
+ GPIODIR
);
94 gpiodir
|= 1 << offset
;
95 writeb(gpiodir
, chip
->base
+ GPIODIR
);
98 * gpio value is set again, because pl061 doesn't allow to set value of
99 * a gpio pin before configuring it in OUT mode.
101 writeb(!!value
<< offset
, chip
->base
+ (1 << (offset
+ 2)));
102 spin_unlock_irqrestore(&chip
->lock
, flags
);
107 static int pl061_get_value(struct gpio_chip
*gc
, unsigned offset
)
109 struct pl061_gpio
*chip
= container_of(gc
, struct pl061_gpio
, gc
);
111 return !!readb(chip
->base
+ (1 << (offset
+ 2)));
114 static void pl061_set_value(struct gpio_chip
*gc
, unsigned offset
, int value
)
116 struct pl061_gpio
*chip
= container_of(gc
, struct pl061_gpio
, gc
);
118 writeb(!!value
<< offset
, chip
->base
+ (1 << (offset
+ 2)));
121 static int pl061_to_irq(struct gpio_chip
*gc
, unsigned offset
)
123 struct pl061_gpio
*chip
= container_of(gc
, struct pl061_gpio
, gc
);
125 if (chip
->irq_base
<= 0)
128 return chip
->irq_base
+ offset
;
131 static int pl061_irq_type(struct irq_data
*d
, unsigned trigger
)
133 struct irq_chip_generic
*gc
= irq_data_get_irq_chip_data(d
);
134 struct pl061_gpio
*chip
= gc
->private;
135 int offset
= d
->irq
- chip
->irq_base
;
137 u8 gpiois
, gpioibe
, gpioiev
;
139 if (offset
< 0 || offset
>= PL061_GPIO_NR
)
142 raw_spin_lock_irqsave(&gc
->lock
, flags
);
144 gpioiev
= readb(chip
->base
+ GPIOIEV
);
146 gpiois
= readb(chip
->base
+ GPIOIS
);
147 if (trigger
& (IRQ_TYPE_LEVEL_HIGH
| IRQ_TYPE_LEVEL_LOW
)) {
148 gpiois
|= 1 << offset
;
149 if (trigger
& IRQ_TYPE_LEVEL_HIGH
)
150 gpioiev
|= 1 << offset
;
152 gpioiev
&= ~(1 << offset
);
154 gpiois
&= ~(1 << offset
);
155 writeb(gpiois
, chip
->base
+ GPIOIS
);
157 gpioibe
= readb(chip
->base
+ GPIOIBE
);
158 if ((trigger
& IRQ_TYPE_EDGE_BOTH
) == IRQ_TYPE_EDGE_BOTH
)
159 gpioibe
|= 1 << offset
;
161 gpioibe
&= ~(1 << offset
);
162 if (trigger
& IRQ_TYPE_EDGE_RISING
)
163 gpioiev
|= 1 << offset
;
164 else if (trigger
& IRQ_TYPE_EDGE_FALLING
)
165 gpioiev
&= ~(1 << offset
);
167 writeb(gpioibe
, chip
->base
+ GPIOIBE
);
169 writeb(gpioiev
, chip
->base
+ GPIOIEV
);
171 raw_spin_unlock_irqrestore(&gc
->lock
, flags
);
176 static void pl061_irq_handler(unsigned irq
, struct irq_desc
*desc
)
178 unsigned long pending
;
180 struct pl061_gpio
*chip
= irq_desc_get_handler_data(desc
);
181 struct irq_chip
*irqchip
= irq_desc_get_chip(desc
);
183 chained_irq_enter(irqchip
, desc
);
185 pending
= readb(chip
->base
+ GPIOMIS
);
186 writeb(pending
, chip
->base
+ GPIOIC
);
188 for_each_set_bit(offset
, &pending
, PL061_GPIO_NR
)
189 generic_handle_irq(pl061_to_irq(&chip
->gc
, offset
));
192 chained_irq_exit(irqchip
, desc
);
195 static void __init
pl061_init_gc(struct pl061_gpio
*chip
, int irq_base
)
197 struct irq_chip_type
*ct
;
199 chip
->irq_gc
= irq_alloc_generic_chip("gpio-pl061", 1, irq_base
,
200 chip
->base
, handle_simple_irq
);
201 chip
->irq_gc
->private = chip
;
203 ct
= chip
->irq_gc
->chip_types
;
204 ct
->chip
.irq_mask
= irq_gc_mask_clr_bit
;
205 ct
->chip
.irq_unmask
= irq_gc_mask_set_bit
;
206 ct
->chip
.irq_set_type
= pl061_irq_type
;
207 ct
->chip
.irq_set_wake
= irq_gc_set_wake
;
208 ct
->regs
.mask
= GPIOIE
;
210 irq_setup_generic_chip(chip
->irq_gc
, IRQ_MSK(PL061_GPIO_NR
),
211 IRQ_GC_INIT_NESTED_LOCK
, IRQ_NOREQUEST
, 0);
214 static int pl061_probe(struct amba_device
*adev
, const struct amba_id
*id
)
216 struct device
*dev
= &adev
->dev
;
217 struct pl061_platform_data
*pdata
= dev
->platform_data
;
218 struct pl061_gpio
*chip
;
221 chip
= devm_kzalloc(dev
, sizeof(*chip
), GFP_KERNEL
);
226 chip
->gc
.base
= pdata
->gpio_base
;
227 chip
->irq_base
= pdata
->irq_base
;
228 } else if (adev
->dev
.of_node
) {
234 if (!devm_request_mem_region(dev
, adev
->res
.start
,
235 resource_size(&adev
->res
), "pl061"))
238 chip
->base
= devm_ioremap(dev
, adev
->res
.start
,
239 resource_size(&adev
->res
));
240 if (chip
->base
== NULL
)
243 spin_lock_init(&chip
->lock
);
245 chip
->gc
.direction_input
= pl061_direction_input
;
246 chip
->gc
.direction_output
= pl061_direction_output
;
247 chip
->gc
.get
= pl061_get_value
;
248 chip
->gc
.set
= pl061_set_value
;
249 chip
->gc
.to_irq
= pl061_to_irq
;
250 chip
->gc
.ngpio
= PL061_GPIO_NR
;
251 chip
->gc
.label
= dev_name(dev
);
253 chip
->gc
.owner
= THIS_MODULE
;
255 ret
= gpiochip_add(&chip
->gc
);
263 if (chip
->irq_base
<= 0)
266 pl061_init_gc(chip
, chip
->irq_base
);
268 writeb(0, chip
->base
+ GPIOIE
); /* disable irqs */
273 irq_set_chained_handler(irq
, pl061_irq_handler
);
274 irq_set_handler_data(irq
, chip
);
276 for (i
= 0; i
< PL061_GPIO_NR
; i
++) {
278 if (pdata
->directions
& (1 << i
))
279 pl061_direction_output(&chip
->gc
, i
,
280 pdata
->values
& (1 << i
));
282 pl061_direction_input(&chip
->gc
, i
);
286 amba_set_drvdata(adev
, chip
);
292 static int pl061_suspend(struct device
*dev
)
294 struct pl061_gpio
*chip
= dev_get_drvdata(dev
);
297 chip
->csave_regs
.gpio_data
= 0;
298 chip
->csave_regs
.gpio_dir
= readb(chip
->base
+ GPIODIR
);
299 chip
->csave_regs
.gpio_is
= readb(chip
->base
+ GPIOIS
);
300 chip
->csave_regs
.gpio_ibe
= readb(chip
->base
+ GPIOIBE
);
301 chip
->csave_regs
.gpio_iev
= readb(chip
->base
+ GPIOIEV
);
302 chip
->csave_regs
.gpio_ie
= readb(chip
->base
+ GPIOIE
);
304 for (offset
= 0; offset
< PL061_GPIO_NR
; offset
++) {
305 if (chip
->csave_regs
.gpio_dir
& (1 << offset
))
306 chip
->csave_regs
.gpio_data
|=
307 pl061_get_value(&chip
->gc
, offset
) << offset
;
313 static int pl061_resume(struct device
*dev
)
315 struct pl061_gpio
*chip
= dev_get_drvdata(dev
);
318 for (offset
= 0; offset
< PL061_GPIO_NR
; offset
++) {
319 if (chip
->csave_regs
.gpio_dir
& (1 << offset
))
320 pl061_direction_output(&chip
->gc
, offset
,
321 chip
->csave_regs
.gpio_data
&
324 pl061_direction_input(&chip
->gc
, offset
);
327 writeb(chip
->csave_regs
.gpio_is
, chip
->base
+ GPIOIS
);
328 writeb(chip
->csave_regs
.gpio_ibe
, chip
->base
+ GPIOIBE
);
329 writeb(chip
->csave_regs
.gpio_iev
, chip
->base
+ GPIOIEV
);
330 writeb(chip
->csave_regs
.gpio_ie
, chip
->base
+ GPIOIE
);
335 static const struct dev_pm_ops pl061_dev_pm_ops
= {
336 .suspend
= pl061_suspend
,
337 .resume
= pl061_resume
,
338 .freeze
= pl061_suspend
,
339 .restore
= pl061_resume
,
343 static struct amba_id pl061_ids
[] = {
351 MODULE_DEVICE_TABLE(amba
, pl061_ids
);
353 static struct amba_driver pl061_gpio_driver
= {
355 .name
= "pl061_gpio",
357 .pm
= &pl061_dev_pm_ops
,
360 .id_table
= pl061_ids
,
361 .probe
= pl061_probe
,
364 static int __init
pl061_gpio_init(void)
366 return amba_driver_register(&pl061_gpio_driver
);
368 subsys_initcall(pl061_gpio_init
);
370 MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
371 MODULE_DESCRIPTION("PL061 GPIO driver");
372 MODULE_LICENSE("GPL");