aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-orion
diff options
context:
space:
mode:
authorAndrew Lunn <andrew@lunn.ch>2012-06-27 07:40:04 -0400
committerAndrew Lunn <andrew@lunn.ch>2012-07-27 10:48:14 -0400
commit278b45b06bf721b7cf5de67a0126786c60c720e6 (patch)
tree4e2a3af2527110f9328aebca560cf6c1cef32c1c /arch/arm/plat-orion
parent89fb2d77d5daa821e3868ea59963f28249974840 (diff)
ARM: Orion: DT support for IRQ and GPIO Controllers
Both IRQ and GPIO controllers can now be represented in DT. The IRQ controllers are setup first, and then the GPIO controllers. Interrupts for GPIO lines are placed directly after the main interrupts in the interrupt space. Signed-off-by: Andrew Lunn <andrew@lunn.ch> Acked-by: Sebastian Hesselbarth <sebastian.hesselbarth@googlemail.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Tested-by: Josh Coombs <josh.coombs@gmail.com> Tested-by: Simon Baatz <gmbnomis@gmail.com>
Diffstat (limited to 'arch/arm/plat-orion')
-rw-r--r--arch/arm/plat-orion/gpio.c166
-rw-r--r--arch/arm/plat-orion/include/plat/gpio.h16
-rw-r--r--arch/arm/plat-orion/include/plat/irq.h3
-rw-r--r--arch/arm/plat-orion/irq.c40
4 files changed, 173 insertions, 52 deletions
diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c
index af95af257301..dfda74fae6f2 100644
--- a/arch/arm/plat-orion/gpio.c
+++ b/arch/arm/plat-orion/gpio.c
@@ -8,15 +8,22 @@
8 * warranty of any kind, whether express or implied. 8 * warranty of any kind, whether express or implied.
9 */ 9 */
10 10
11#define DEBUG
12
11#include <linux/kernel.h> 13#include <linux/kernel.h>
12#include <linux/init.h> 14#include <linux/init.h>
13#include <linux/irq.h> 15#include <linux/irq.h>
16#include <linux/irqdomain.h>
14#include <linux/module.h> 17#include <linux/module.h>
15#include <linux/spinlock.h> 18#include <linux/spinlock.h>
16#include <linux/bitops.h> 19#include <linux/bitops.h>
17#include <linux/io.h> 20#include <linux/io.h>
18#include <linux/gpio.h> 21#include <linux/gpio.h>
19#include <linux/leds.h> 22#include <linux/leds.h>
23#include <linux/of.h>
24#include <linux/of_irq.h>
25#include <linux/of_address.h>
26#include <plat/gpio.h>
20 27
21/* 28/*
22 * GPIO unit register offsets. 29 * GPIO unit register offsets.
@@ -38,6 +45,7 @@ struct orion_gpio_chip {
38 unsigned long valid_output; 45 unsigned long valid_output;
39 int mask_offset; 46 int mask_offset;
40 int secondary_irq_base; 47 int secondary_irq_base;
48 struct irq_domain *domain;
41}; 49};
42 50
43static void __iomem *GPIO_OUT(struct orion_gpio_chip *ochip) 51static void __iomem *GPIO_OUT(struct orion_gpio_chip *ochip)
@@ -222,10 +230,10 @@ static int orion_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
222 struct orion_gpio_chip *ochip = 230 struct orion_gpio_chip *ochip =
223 container_of(chip, struct orion_gpio_chip, chip); 231 container_of(chip, struct orion_gpio_chip, chip);
224 232
225 return ochip->secondary_irq_base + pin; 233 return irq_create_mapping(ochip->domain,
234 ochip->secondary_irq_base + pin);
226} 235}
227 236
228
229/* 237/*
230 * Orion-specific GPIO API extensions. 238 * Orion-specific GPIO API extensions.
231 */ 239 */
@@ -353,12 +361,10 @@ static int gpio_irq_set_type(struct irq_data *d, u32 type)
353 int pin; 361 int pin;
354 u32 u; 362 u32 u;
355 363
356 pin = d->irq - gc->irq_base; 364 pin = d->hwirq - ochip->secondary_irq_base;
357 365
358 u = readl(GPIO_IO_CONF(ochip)) & (1 << pin); 366 u = readl(GPIO_IO_CONF(ochip)) & (1 << pin);
359 if (!u) { 367 if (!u) {
360 printk(KERN_ERR "orion gpio_irq_set_type failed "
361 "(irq %d, pin %d).\n", d->irq, pin);
362 return -EINVAL; 368 return -EINVAL;
363 } 369 }
364 370
@@ -397,17 +403,53 @@ static int gpio_irq_set_type(struct irq_data *d, u32 type)
397 u &= ~(1 << pin); /* rising */ 403 u &= ~(1 << pin); /* rising */
398 writel(u, GPIO_IN_POL(ochip)); 404 writel(u, GPIO_IN_POL(ochip));
399 } 405 }
400
401 return 0; 406 return 0;
402} 407}
403 408
404void __init orion_gpio_init(int gpio_base, int ngpio, 409static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
405 u32 base, int mask_offset, int secondary_irq_base) 410{
411 struct orion_gpio_chip *ochip = irq_get_handler_data(irq);
412 u32 cause, type;
413 int i;
414
415 if (ochip == NULL)
416 return;
417
418 cause = readl(GPIO_DATA_IN(ochip)) & readl(GPIO_LEVEL_MASK(ochip));
419 cause |= readl(GPIO_EDGE_CAUSE(ochip)) & readl(GPIO_EDGE_MASK(ochip));
420
421 for (i = 0; i < ochip->chip.ngpio; i++) {
422 int irq;
423
424 irq = ochip->secondary_irq_base + i;
425
426 if (!(cause & (1 << i)))
427 continue;
428
429 type = irqd_get_trigger_type(irq_get_irq_data(irq));
430 if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
431 /* Swap polarity (race with GPIO line) */
432 u32 polarity;
433
434 polarity = readl(GPIO_IN_POL(ochip));
435 polarity ^= 1 << i;
436 writel(polarity, GPIO_IN_POL(ochip));
437 }
438 generic_handle_irq(irq);
439 }
440}
441
442void __init orion_gpio_init(struct device_node *np,
443 int gpio_base, int ngpio,
444 void __iomem *base, int mask_offset,
445 int secondary_irq_base,
446 int irqs[4])
406{ 447{
407 struct orion_gpio_chip *ochip; 448 struct orion_gpio_chip *ochip;
408 struct irq_chip_generic *gc; 449 struct irq_chip_generic *gc;
409 struct irq_chip_type *ct; 450 struct irq_chip_type *ct;
410 char gc_label[16]; 451 char gc_label[16];
452 int i;
411 453
412 if (orion_gpio_chip_count == ARRAY_SIZE(orion_gpio_chips)) 454 if (orion_gpio_chip_count == ARRAY_SIZE(orion_gpio_chips))
413 return; 455 return;
@@ -426,6 +468,10 @@ void __init orion_gpio_init(int gpio_base, int ngpio,
426 ochip->chip.base = gpio_base; 468 ochip->chip.base = gpio_base;
427 ochip->chip.ngpio = ngpio; 469 ochip->chip.ngpio = ngpio;
428 ochip->chip.can_sleep = 0; 470 ochip->chip.can_sleep = 0;
471#ifdef CONFIG_OF
472 ochip->chip.of_node = np;
473#endif
474
429 spin_lock_init(&ochip->lock); 475 spin_lock_init(&ochip->lock);
430 ochip->base = (void __iomem *)base; 476 ochip->base = (void __iomem *)base;
431 ochip->valid_input = 0; 477 ochip->valid_input = 0;
@@ -435,8 +481,6 @@ void __init orion_gpio_init(int gpio_base, int ngpio,
435 481
436 gpiochip_add(&ochip->chip); 482 gpiochip_add(&ochip->chip);
437 483
438 orion_gpio_chip_count++;
439
440 /* 484 /*
441 * Mask and clear GPIO interrupts. 485 * Mask and clear GPIO interrupts.
442 */ 486 */
@@ -444,16 +488,28 @@ void __init orion_gpio_init(int gpio_base, int ngpio,
444 writel(0, GPIO_EDGE_MASK(ochip)); 488 writel(0, GPIO_EDGE_MASK(ochip));
445 writel(0, GPIO_LEVEL_MASK(ochip)); 489 writel(0, GPIO_LEVEL_MASK(ochip));
446 490
447 gc = irq_alloc_generic_chip("orion_gpio_irq", 2, secondary_irq_base, 491 /* Setup the interrupt handlers. Each chip can have up to 4
492 * interrupt handlers, with each handler dealing with 8 GPIO
493 * pins. */
494
495 for (i = 0; i < 4; i++) {
496 if (irqs[i]) {
497 irq_set_handler_data(irqs[i], ochip);
498 irq_set_chained_handler(irqs[i], gpio_irq_handler);
499 }
500 }
501
502 gc = irq_alloc_generic_chip("orion_gpio_irq", 2,
503 secondary_irq_base,
448 ochip->base, handle_level_irq); 504 ochip->base, handle_level_irq);
449 gc->private = ochip; 505 gc->private = ochip;
450
451 ct = gc->chip_types; 506 ct = gc->chip_types;
452 ct->regs.mask = ochip->mask_offset + GPIO_LEVEL_MASK_OFF; 507 ct->regs.mask = ochip->mask_offset + GPIO_LEVEL_MASK_OFF;
453 ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; 508 ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
454 ct->chip.irq_mask = irq_gc_mask_clr_bit; 509 ct->chip.irq_mask = irq_gc_mask_clr_bit;
455 ct->chip.irq_unmask = irq_gc_mask_set_bit; 510 ct->chip.irq_unmask = irq_gc_mask_set_bit;
456 ct->chip.irq_set_type = gpio_irq_set_type; 511 ct->chip.irq_set_type = gpio_irq_set_type;
512 ct->chip.name = ochip->chip.label;
457 513
458 ct++; 514 ct++;
459 ct->regs.mask = ochip->mask_offset + GPIO_EDGE_MASK_OFF; 515 ct->regs.mask = ochip->mask_offset + GPIO_EDGE_MASK_OFF;
@@ -464,41 +520,69 @@ void __init orion_gpio_init(int gpio_base, int ngpio,
464 ct->chip.irq_unmask = irq_gc_mask_set_bit; 520 ct->chip.irq_unmask = irq_gc_mask_set_bit;
465 ct->chip.irq_set_type = gpio_irq_set_type; 521 ct->chip.irq_set_type = gpio_irq_set_type;
466 ct->handler = handle_edge_irq; 522 ct->handler = handle_edge_irq;
523 ct->chip.name = ochip->chip.label;
467 524
468 irq_setup_generic_chip(gc, IRQ_MSK(ngpio), IRQ_GC_INIT_MASK_CACHE, 525 irq_setup_generic_chip(gc, IRQ_MSK(ngpio), IRQ_GC_INIT_MASK_CACHE,
469 IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); 526 IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
470}
471 527
472void orion_gpio_irq_handler(int pinoff) 528 /* Setup irq domain on top of the generic chip. */
473{ 529 ochip->domain = irq_domain_add_legacy(np,
474 struct orion_gpio_chip *ochip; 530 ochip->chip.ngpio,
475 u32 cause, type; 531 ochip->secondary_irq_base,
476 int i; 532 ochip->secondary_irq_base,
477 533 &irq_domain_simple_ops,
478 ochip = orion_gpio_chip_find(pinoff); 534 ochip);
479 if (ochip == NULL) 535 if (!ochip->domain)
480 return; 536 panic("%s: couldn't allocate irq domain (DT).\n",
481 537 ochip->chip.label);
482 cause = readl(GPIO_DATA_IN(ochip)) & readl(GPIO_LEVEL_MASK(ochip));
483 cause |= readl(GPIO_EDGE_CAUSE(ochip)) & readl(GPIO_EDGE_MASK(ochip));
484
485 for (i = 0; i < ochip->chip.ngpio; i++) {
486 int irq;
487 538
488 irq = ochip->secondary_irq_base + i; 539 orion_gpio_chip_count++;
540}
489 541
490 if (!(cause & (1 << i))) 542#ifdef CONFIG_OF
491 continue; 543static void __init orion_gpio_of_init_one(struct device_node *np,
544 int irq_gpio_base)
545{
546 int ngpio, gpio_base, mask_offset;
547 void __iomem *base;
548 int ret, i;
549 int irqs[4];
550 int secondary_irq_base;
551
552 ret = of_property_read_u32(np, "ngpio", &ngpio);
553 if (ret)
554 goto out;
555 ret = of_property_read_u32(np, "mask-offset", &mask_offset);
556 if (ret == -EINVAL)
557 mask_offset = 0;
558 else
559 goto out;
560 base = of_iomap(np, 0);
561 if (!base)
562 goto out;
563
564 secondary_irq_base = irq_gpio_base + (32 * orion_gpio_chip_count);
565 gpio_base = 32 * orion_gpio_chip_count;
566
567 /* Get the interrupt numbers. Each chip can have up to 4
568 * interrupt handlers, with each handler dealing with 8 GPIO
569 * pins. */
570
571 for (i = 0; i < 4; i++)
572 irqs[i] = irq_of_parse_and_map(np, i);
573
574 orion_gpio_init(np, gpio_base, ngpio, base, mask_offset,
575 secondary_irq_base, irqs);
576 return;
577out:
578 pr_err("%s: %s: missing mandatory property\n", __func__, np->name);
579}
492 580
493 type = irqd_get_trigger_type(irq_get_irq_data(irq)); 581void __init orion_gpio_of_init(int irq_gpio_base)
494 if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { 582{
495 /* Swap polarity (race with GPIO line) */ 583 struct device_node *np;
496 u32 polarity;
497 584
498 polarity = readl(GPIO_IN_POL(ochip)); 585 for_each_compatible_node(np, NULL, "marvell,orion-gpio")
499 polarity ^= 1 << i; 586 orion_gpio_of_init_one(np, irq_gpio_base);
500 writel(polarity, GPIO_IN_POL(ochip));
501 }
502 generic_handle_irq(irq);
503 }
504} 587}
588#endif
diff --git a/arch/arm/plat-orion/include/plat/gpio.h b/arch/arm/plat-orion/include/plat/gpio.h
index bec0c98ce41f..81c6fc8a7b28 100644
--- a/arch/arm/plat-orion/include/plat/gpio.h
+++ b/arch/arm/plat-orion/include/plat/gpio.h
@@ -13,7 +13,7 @@
13 13
14#include <linux/init.h> 14#include <linux/init.h>
15#include <linux/types.h> 15#include <linux/types.h>
16 16#include <linux/irqdomain.h>
17/* 17/*
18 * Orion-specific GPIO API extensions. 18 * Orion-specific GPIO API extensions.
19 */ 19 */
@@ -27,13 +27,11 @@ int orion_gpio_led_blink_set(unsigned gpio, int state,
27void orion_gpio_set_valid(unsigned pin, int mode); 27void orion_gpio_set_valid(unsigned pin, int mode);
28 28
29/* Initialize gpiolib. */ 29/* Initialize gpiolib. */
30void __init orion_gpio_init(int gpio_base, int ngpio, 30void __init orion_gpio_init(struct device_node *np,
31 u32 base, int mask_offset, int secondary_irq_base); 31 int gpio_base, int ngpio,
32 32 void __iomem *base, int mask_offset,
33/* 33 int secondary_irq_base,
34 * GPIO interrupt handling. 34 int irq[4]);
35 */
36void orion_gpio_irq_handler(int irqoff);
37
38 35
36void __init orion_gpio_of_init(int irq_gpio_base);
39#endif 37#endif
diff --git a/arch/arm/plat-orion/include/plat/irq.h b/arch/arm/plat-orion/include/plat/irq.h
index f05eeab94968..50547e417936 100644
--- a/arch/arm/plat-orion/include/plat/irq.h
+++ b/arch/arm/plat-orion/include/plat/irq.h
@@ -12,6 +12,5 @@
12#define __PLAT_IRQ_H 12#define __PLAT_IRQ_H
13 13
14void orion_irq_init(unsigned int irq_start, void __iomem *maskaddr); 14void orion_irq_init(unsigned int irq_start, void __iomem *maskaddr);
15 15void __init orion_dt_init_irq(void);
16
17#endif 16#endif
diff --git a/arch/arm/plat-orion/irq.c b/arch/arm/plat-orion/irq.c
index 2d5b9c1ef389..d751964def4c 100644
--- a/arch/arm/plat-orion/irq.c
+++ b/arch/arm/plat-orion/irq.c
@@ -11,8 +11,12 @@
11#include <linux/kernel.h> 11#include <linux/kernel.h>
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/irq.h> 13#include <linux/irq.h>
14#include <linux/irqdomain.h>
14#include <linux/io.h> 15#include <linux/io.h>
16#include <linux/of_address.h>
17#include <linux/of_irq.h>
15#include <plat/irq.h> 18#include <plat/irq.h>
19#include <plat/gpio.h>
16 20
17void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr) 21void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr)
18{ 22{
@@ -32,3 +36,39 @@ void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr)
32 irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_MASK_CACHE, 36 irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_MASK_CACHE,
33 IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); 37 IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
34} 38}
39
40#ifdef CONFIG_OF
41static int __init orion_add_irq_domain(struct device_node *np,
42 struct device_node *interrupt_parent)
43{
44 int i = 0, irq_gpio;
45 void __iomem *base;
46
47 do {
48 base = of_iomap(np, i);
49 if (base) {
50 orion_irq_init(i * 32, base);
51 i++;
52 }
53 } while (base);
54
55 irq_domain_add_legacy(np, i * 32, 0, 0,
56 &irq_domain_simple_ops, NULL);
57
58 irq_gpio = i * 32;
59 orion_gpio_of_init(irq_gpio);
60
61 return 0;
62}
63
64static const struct of_device_id orion_irq_match[] = {
65 { .compatible = "marvell,orion-intc",
66 .data = orion_add_irq_domain, },
67 {},
68};
69
70void __init orion_dt_init_irq(void)
71{
72 of_irq_init(orion_irq_match);
73}
74#endif