aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorMagnus Damm <damm@opensource.se>2012-05-17 02:22:23 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-05-17 18:00:45 -0400
commita07e103ef08c6907d695a06467d7ee950796fccf (patch)
tree9670ebf990788fc46bd8ac3648b01eb8846bdc23 /drivers/gpio
parent4da773193414788b52ae14bc246543390faca5ce (diff)
gpio: Emma Mobile GPIO driver V2
This patch is V2 of the Emma Mobile GPIO driver. This driver is designed to be reusable between multiple SoCs that share the same basic building block, but so far it has only been used on Emma Mobile EV2. Each driver instance handles 32 GPIOs with individually maskable IRQs. The driver operates on two I/O memory ranges and the 32 GPIOs are hooked up to two interrupts. In the case of Emma Mobile EV2 this GPIO building block is used as main external interrupt controller hooking up 159 GPIOS as 159 interrupts via 5 driver instances and 10 interrupts to the GIC and the Cortex-A9 Dual. Signed-off-by: Magnus Damm <damm@opensource.se> Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig6
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-em.c418
3 files changed, 425 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index e03653d69357..eb80ba300452 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -91,6 +91,12 @@ config GPIO_IT8761E
91 help 91 help
92 Say yes here to support GPIO functionality of IT8761E super I/O chip. 92 Say yes here to support GPIO functionality of IT8761E super I/O chip.
93 93
94config GPIO_EM
95 tristate "Emma Mobile GPIO"
96 depends on ARM
97 help
98 Say yes here to support GPIO on Renesas Emma Mobile SoCs.
99
94config GPIO_EP93XX 100config GPIO_EP93XX
95 def_bool y 101 def_bool y
96 depends on ARCH_EP93XX 102 depends on ARCH_EP93XX
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 007f54bd0081..3f1f829260bb 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
15obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o 15obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
16obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o 16obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
17obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o 17obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o
18obj-$(CONFIG_GPIO_EM) += gpio-em.o
18obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o 19obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
19obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o 20obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
20obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o 21obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o
diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c
new file mode 100644
index 000000000000..150d9768811d
--- /dev/null
+++ b/drivers/gpio/gpio-em.c
@@ -0,0 +1,418 @@
1/*
2 * Emma Mobile GPIO Support - GIO
3 *
4 * Copyright (C) 2012 Magnus Damm
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 as published by
8 * the Free Software Foundation; either version 2 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#include <linux/init.h>
21#include <linux/platform_device.h>
22#include <linux/spinlock.h>
23#include <linux/interrupt.h>
24#include <linux/ioport.h>
25#include <linux/io.h>
26#include <linux/irq.h>
27#include <linux/irqdomain.h>
28#include <linux/bitops.h>
29#include <linux/err.h>
30#include <linux/gpio.h>
31#include <linux/slab.h>
32#include <linux/module.h>
33#include <linux/platform_data/gpio-em.h>
34
35struct em_gio_priv {
36 void __iomem *base0;
37 void __iomem *base1;
38 unsigned int irq_base;
39 spinlock_t sense_lock;
40 struct platform_device *pdev;
41 struct gpio_chip gpio_chip;
42 struct irq_chip irq_chip;
43 struct irq_domain *irq_domain;
44};
45
46#define GIO_E1 0x00
47#define GIO_E0 0x04
48#define GIO_EM 0x04
49#define GIO_OL 0x08
50#define GIO_OH 0x0c
51#define GIO_I 0x10
52#define GIO_IIA 0x14
53#define GIO_IEN 0x18
54#define GIO_IDS 0x1c
55#define GIO_IIM 0x1c
56#define GIO_RAW 0x20
57#define GIO_MST 0x24
58#define GIO_IIR 0x28
59
60#define GIO_IDT0 0x40
61#define GIO_IDT1 0x44
62#define GIO_IDT2 0x48
63#define GIO_IDT3 0x4c
64#define GIO_RAWBL 0x50
65#define GIO_RAWBH 0x54
66#define GIO_IRBL 0x58
67#define GIO_IRBH 0x5c
68
69#define GIO_IDT(n) (GIO_IDT0 + ((n) * 4))
70
71static inline unsigned long em_gio_read(struct em_gio_priv *p, int offs)
72{
73 if (offs < GIO_IDT0)
74 return ioread32(p->base0 + offs);
75 else
76 return ioread32(p->base1 + (offs - GIO_IDT0));
77}
78
79static inline void em_gio_write(struct em_gio_priv *p, int offs,
80 unsigned long value)
81{
82 if (offs < GIO_IDT0)
83 iowrite32(value, p->base0 + offs);
84 else
85 iowrite32(value, p->base1 + (offs - GIO_IDT0));
86}
87
88static inline struct em_gio_priv *irq_to_priv(struct irq_data *d)
89{
90 struct irq_chip *chip = irq_data_get_irq_chip(d);
91 return container_of(chip, struct em_gio_priv, irq_chip);
92}
93
94static void em_gio_irq_disable(struct irq_data *d)
95{
96 struct em_gio_priv *p = irq_to_priv(d);
97
98 em_gio_write(p, GIO_IDS, BIT(irqd_to_hwirq(d)));
99}
100
101static void em_gio_irq_enable(struct irq_data *d)
102{
103 struct em_gio_priv *p = irq_to_priv(d);
104
105 em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d)));
106}
107
108#define GIO_ASYNC(x) (x + 8)
109
110static unsigned char em_gio_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
111 [IRQ_TYPE_EDGE_RISING] = GIO_ASYNC(0x00),
112 [IRQ_TYPE_EDGE_FALLING] = GIO_ASYNC(0x01),
113 [IRQ_TYPE_LEVEL_HIGH] = GIO_ASYNC(0x02),
114 [IRQ_TYPE_LEVEL_LOW] = GIO_ASYNC(0x03),
115 [IRQ_TYPE_EDGE_BOTH] = GIO_ASYNC(0x04),
116};
117
118static int em_gio_irq_set_type(struct irq_data *d, unsigned int type)
119{
120 unsigned char value = em_gio_sense_table[type & IRQ_TYPE_SENSE_MASK];
121 struct em_gio_priv *p = irq_to_priv(d);
122 unsigned int reg, offset, shift;
123 unsigned long flags;
124 unsigned long tmp;
125
126 if (!value)
127 return -EINVAL;
128
129 offset = irqd_to_hwirq(d);
130
131 pr_debug("gio: sense irq = %d, mode = %d\n", offset, value);
132
133 /* 8 x 4 bit fields in 4 IDT registers */
134 reg = GIO_IDT(offset >> 3);
135 shift = (offset & 0x07) << 4;
136
137 spin_lock_irqsave(&p->sense_lock, flags);
138
139 /* disable the interrupt in IIA */
140 tmp = em_gio_read(p, GIO_IIA);
141 tmp &= ~BIT(offset);
142 em_gio_write(p, GIO_IIA, tmp);
143
144 /* change the sense setting in IDT */
145 tmp = em_gio_read(p, reg);
146 tmp &= ~(0xf << shift);
147 tmp |= value << shift;
148 em_gio_write(p, reg, tmp);
149
150 /* clear pending interrupts */
151 em_gio_write(p, GIO_IIR, BIT(offset));
152
153 /* enable the interrupt in IIA */
154 tmp = em_gio_read(p, GIO_IIA);
155 tmp |= BIT(offset);
156 em_gio_write(p, GIO_IIA, tmp);
157
158 spin_unlock_irqrestore(&p->sense_lock, flags);
159
160 return 0;
161}
162
163static irqreturn_t em_gio_irq_handler(int irq, void *dev_id)
164{
165 struct em_gio_priv *p = dev_id;
166 unsigned long pending;
167 unsigned int offset, irqs_handled = 0;
168
169 while ((pending = em_gio_read(p, GIO_MST))) {
170 offset = __ffs(pending);
171 em_gio_write(p, GIO_IIR, BIT(offset));
172 generic_handle_irq(irq_find_mapping(p->irq_domain, offset));
173 irqs_handled++;
174 }
175
176 return irqs_handled ? IRQ_HANDLED : IRQ_NONE;
177}
178
179static inline struct em_gio_priv *gpio_to_priv(struct gpio_chip *chip)
180{
181 return container_of(chip, struct em_gio_priv, gpio_chip);
182}
183
184static int em_gio_direction_input(struct gpio_chip *chip, unsigned offset)
185{
186 em_gio_write(gpio_to_priv(chip), GIO_E0, BIT(offset));
187 return 0;
188}
189
190static int em_gio_get(struct gpio_chip *chip, unsigned offset)
191{
192 return (int)(em_gio_read(gpio_to_priv(chip), GIO_I) & BIT(offset));
193}
194
195static void __em_gio_set(struct gpio_chip *chip, unsigned int reg,
196 unsigned shift, int value)
197{
198 /* upper 16 bits contains mask and lower 16 actual value */
199 em_gio_write(gpio_to_priv(chip), reg,
200 (1 << (shift + 16)) | (value << shift));
201}
202
203static void em_gio_set(struct gpio_chip *chip, unsigned offset, int value)
204{
205 /* output is split into two registers */
206 if (offset < 16)
207 __em_gio_set(chip, GIO_OL, offset, value);
208 else
209 __em_gio_set(chip, GIO_OH, offset - 16, value);
210}
211
212static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset,
213 int value)
214{
215 /* write GPIO value to output before selecting output mode of pin */
216 em_gio_set(chip, offset, value);
217 em_gio_write(gpio_to_priv(chip), GIO_E1, BIT(offset));
218 return 0;
219}
220
221static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset)
222{
223 return irq_find_mapping(gpio_to_priv(chip)->irq_domain, offset);
224}
225
226static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq,
227 irq_hw_number_t hw)
228{
229 struct em_gio_priv *p = h->host_data;
230
231 pr_debug("gio: map hw irq = %d, virq = %d\n", (int)hw, virq);
232
233 irq_set_chip_data(virq, h->host_data);
234 irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
235 set_irq_flags(virq, IRQF_VALID); /* kill me now */
236 return 0;
237}
238
239static struct irq_domain_ops em_gio_irq_domain_ops = {
240 .map = em_gio_irq_domain_map,
241};
242
243static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p)
244{
245 struct platform_device *pdev = p->pdev;
246 struct gpio_em_config *pdata = pdev->dev.platform_data;
247
248 p->irq_base = irq_alloc_descs(pdata->irq_base, 0,
249 pdata->number_of_pins, numa_node_id());
250 if (IS_ERR_VALUE(p->irq_base)) {
251 dev_err(&pdev->dev, "cannot get irq_desc\n");
252 return -ENXIO;
253 }
254 pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n",
255 pdata->gpio_base, pdata->number_of_pins, p->irq_base);
256
257 p->irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
258 pdata->number_of_pins,
259 p->irq_base, 0,
260 &em_gio_irq_domain_ops, p);
261 if (!p->irq_domain) {
262 irq_free_descs(p->irq_base, pdata->number_of_pins);
263 return -ENXIO;
264 }
265
266 return 0;
267}
268
269static void __devexit em_gio_irq_domain_cleanup(struct em_gio_priv *p)
270{
271 struct gpio_em_config *pdata = p->pdev->dev.platform_data;
272
273 irq_free_descs(p->irq_base, pdata->number_of_pins);
274 /* FIXME: irq domain wants to be freed! */
275}
276
277static int __devinit em_gio_probe(struct platform_device *pdev)
278{
279 struct gpio_em_config *pdata = pdev->dev.platform_data;
280 struct em_gio_priv *p;
281 struct resource *io[2], *irq[2];
282 struct gpio_chip *gpio_chip;
283 struct irq_chip *irq_chip;
284 const char *name = dev_name(&pdev->dev);
285 int ret;
286
287 p = kzalloc(sizeof(*p), GFP_KERNEL);
288 if (!p) {
289 dev_err(&pdev->dev, "failed to allocate driver data\n");
290 ret = -ENOMEM;
291 goto err0;
292 }
293
294 p->pdev = pdev;
295 platform_set_drvdata(pdev, p);
296 spin_lock_init(&p->sense_lock);
297
298 io[0] = platform_get_resource(pdev, IORESOURCE_MEM, 0);
299 io[1] = platform_get_resource(pdev, IORESOURCE_MEM, 1);
300 irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
301 irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
302
303 if (!io[0] || !io[1] || !irq[0] || !irq[1] || !pdata) {
304 dev_err(&pdev->dev, "missing IRQ, IOMEM or configuration\n");
305 ret = -EINVAL;
306 goto err1;
307 }
308
309 p->base0 = ioremap_nocache(io[0]->start, resource_size(io[0]));
310 if (!p->base0) {
311 dev_err(&pdev->dev, "failed to remap low I/O memory\n");
312 ret = -ENXIO;
313 goto err1;
314 }
315
316 p->base1 = ioremap_nocache(io[1]->start, resource_size(io[1]));
317 if (!p->base1) {
318 dev_err(&pdev->dev, "failed to remap high I/O memory\n");
319 ret = -ENXIO;
320 goto err2;
321 }
322
323 gpio_chip = &p->gpio_chip;
324 gpio_chip->direction_input = em_gio_direction_input;
325 gpio_chip->get = em_gio_get;
326 gpio_chip->direction_output = em_gio_direction_output;
327 gpio_chip->set = em_gio_set;
328 gpio_chip->to_irq = em_gio_to_irq;
329 gpio_chip->label = name;
330 gpio_chip->owner = THIS_MODULE;
331 gpio_chip->base = pdata->gpio_base;
332 gpio_chip->ngpio = pdata->number_of_pins;
333
334 irq_chip = &p->irq_chip;
335 irq_chip->name = name;
336 irq_chip->irq_mask = em_gio_irq_disable;
337 irq_chip->irq_unmask = em_gio_irq_enable;
338 irq_chip->irq_enable = em_gio_irq_enable;
339 irq_chip->irq_disable = em_gio_irq_disable;
340 irq_chip->irq_set_type = em_gio_irq_set_type;
341 irq_chip->flags = IRQCHIP_SKIP_SET_WAKE;
342
343 ret = em_gio_irq_domain_init(p);
344 if (ret) {
345 dev_err(&pdev->dev, "cannot initialize irq domain\n");
346 goto err3;
347 }
348
349 if (request_irq(irq[0]->start, em_gio_irq_handler, 0, name, p)) {
350 dev_err(&pdev->dev, "failed to request low IRQ\n");
351 ret = -ENOENT;
352 goto err4;
353 }
354
355 if (request_irq(irq[1]->start, em_gio_irq_handler, 0, name, p)) {
356 dev_err(&pdev->dev, "failed to request high IRQ\n");
357 ret = -ENOENT;
358 goto err5;
359 }
360
361 ret = gpiochip_add(gpio_chip);
362 if (ret) {
363 dev_err(&pdev->dev, "failed to add GPIO controller\n");
364 goto err6;
365 }
366 return 0;
367
368err6:
369 free_irq(irq[1]->start, pdev);
370err5:
371 free_irq(irq[0]->start, pdev);
372err4:
373 em_gio_irq_domain_cleanup(p);
374err3:
375 iounmap(p->base1);
376err2:
377 iounmap(p->base0);
378err1:
379 kfree(p);
380err0:
381 return ret;
382}
383
384static int __devexit em_gio_remove(struct platform_device *pdev)
385{
386 struct em_gio_priv *p = platform_get_drvdata(pdev);
387 struct resource *irq[2];
388 int ret;
389
390 ret = gpiochip_remove(&p->gpio_chip);
391 if (ret)
392 return ret;
393
394 irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
395 irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
396
397 free_irq(irq[1]->start, pdev);
398 free_irq(irq[0]->start, pdev);
399 em_gio_irq_domain_cleanup(p);
400 iounmap(p->base1);
401 iounmap(p->base0);
402 kfree(p);
403 return 0;
404}
405
406static struct platform_driver em_gio_device_driver = {
407 .probe = em_gio_probe,
408 .remove = __devexit_p(em_gio_remove),
409 .driver = {
410 .name = "em_gio",
411 }
412};
413
414module_platform_driver(em_gio_device_driver);
415
416MODULE_AUTHOR("Magnus Damm");
417MODULE_DESCRIPTION("Renesas Emma Mobile GIO Driver");
418MODULE_LICENSE("GPL v2");