diff options
author | Andrew Lunn <andrew@lunn.ch> | 2012-06-27 07:40:04 -0400 |
---|---|---|
committer | Andrew Lunn <andrew@lunn.ch> | 2012-07-27 10:48:14 -0400 |
commit | 278b45b06bf721b7cf5de67a0126786c60c720e6 (patch) | |
tree | 4e2a3af2527110f9328aebca560cf6c1cef32c1c /arch/arm | |
parent | 89fb2d77d5daa821e3868ea59963f28249974840 (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')
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/boot/dts/kirkwood.dtsi | 27 | ||||
-rw-r--r-- | arch/arm/mach-dove/irq.c | 58 | ||||
-rw-r--r-- | arch/arm/mach-kirkwood/board-dt.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-kirkwood/irq.c | 38 | ||||
-rw-r--r-- | arch/arm/mach-mv78xx0/irq.c | 22 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/irq.c | 22 | ||||
-rw-r--r-- | arch/arm/plat-orion/gpio.c | 166 | ||||
-rw-r--r-- | arch/arm/plat-orion/include/plat/gpio.h | 16 | ||||
-rw-r--r-- | arch/arm/plat-orion/include/plat/irq.h | 3 | ||||
-rw-r--r-- | arch/arm/plat-orion/irq.c | 40 |
11 files changed, 264 insertions, 132 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a91009c61870..39bb94112a30 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -1105,6 +1105,7 @@ config PLAT_ORION | |||
1105 | bool | 1105 | bool |
1106 | select CLKSRC_MMIO | 1106 | select CLKSRC_MMIO |
1107 | select GENERIC_IRQ_CHIP | 1107 | select GENERIC_IRQ_CHIP |
1108 | select IRQ_DOMAIN | ||
1108 | select COMMON_CLK | 1109 | select COMMON_CLK |
1109 | 1110 | ||
1110 | config PLAT_PXA | 1111 | config PLAT_PXA |
diff --git a/arch/arm/boot/dts/kirkwood.dtsi b/arch/arm/boot/dts/kirkwood.dtsi index f95dbc190ab6..cbaa7b6eb5da 100644 --- a/arch/arm/boot/dts/kirkwood.dtsi +++ b/arch/arm/boot/dts/kirkwood.dtsi | |||
@@ -2,6 +2,15 @@ | |||
2 | 2 | ||
3 | / { | 3 | / { |
4 | compatible = "marvell,kirkwood"; | 4 | compatible = "marvell,kirkwood"; |
5 | interrupt-parent = <&intc>; | ||
6 | |||
7 | intc: interrupt-controller { | ||
8 | compatible = "marvell,orion-intc", "marvell,intc"; | ||
9 | interrupt-controller; | ||
10 | #interrupt-cells = <1>; | ||
11 | reg = <0xf1020204 0x04>, | ||
12 | <0xf1020214 0x04>; | ||
13 | }; | ||
5 | 14 | ||
6 | ocp@f1000000 { | 15 | ocp@f1000000 { |
7 | compatible = "simple-bus"; | 16 | compatible = "simple-bus"; |
@@ -9,6 +18,24 @@ | |||
9 | #address-cells = <1>; | 18 | #address-cells = <1>; |
10 | #size-cells = <1>; | 19 | #size-cells = <1>; |
11 | 20 | ||
21 | gpio0: gpio@10100 { | ||
22 | compatible = "marvell,orion-gpio"; | ||
23 | #gpio-cells = <2>; | ||
24 | gpio-controller; | ||
25 | reg = <0x10100 0x40>; | ||
26 | ngpio = <32>; | ||
27 | interrupts = <35>, <36>, <37>, <38>; | ||
28 | }; | ||
29 | |||
30 | gpio1: gpio@10140 { | ||
31 | compatible = "marvell,orion-gpio"; | ||
32 | #gpio-cells = <2>; | ||
33 | gpio-controller; | ||
34 | reg = <0x10140 0x40>; | ||
35 | ngpio = <18>; | ||
36 | interrupts = <39>, <40>, <41>; | ||
37 | }; | ||
38 | |||
12 | serial@12000 { | 39 | serial@12000 { |
13 | compatible = "ns16550a"; | 40 | compatible = "ns16550a"; |
14 | reg = <0x12000 0x100>; | 41 | reg = <0x12000 0x100>; |
diff --git a/arch/arm/mach-dove/irq.c b/arch/arm/mach-dove/irq.c index f07fd16e0c9b..9bc97a5baaa8 100644 --- a/arch/arm/mach-dove/irq.c +++ b/arch/arm/mach-dove/irq.c | |||
@@ -20,22 +20,6 @@ | |||
20 | #include <mach/bridge-regs.h> | 20 | #include <mach/bridge-regs.h> |
21 | #include "common.h" | 21 | #include "common.h" |
22 | 22 | ||
23 | static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
24 | { | ||
25 | int irqoff; | ||
26 | BUG_ON(irq < IRQ_DOVE_GPIO_0_7 || irq > IRQ_DOVE_HIGH_GPIO); | ||
27 | |||
28 | irqoff = irq <= IRQ_DOVE_GPIO_16_23 ? irq - IRQ_DOVE_GPIO_0_7 : | ||
29 | 3 + irq - IRQ_DOVE_GPIO_24_31; | ||
30 | |||
31 | orion_gpio_irq_handler(irqoff << 3); | ||
32 | if (irq == IRQ_DOVE_HIGH_GPIO) { | ||
33 | orion_gpio_irq_handler(40); | ||
34 | orion_gpio_irq_handler(48); | ||
35 | orion_gpio_irq_handler(56); | ||
36 | } | ||
37 | } | ||
38 | |||
39 | static void pmu_irq_mask(struct irq_data *d) | 23 | static void pmu_irq_mask(struct irq_data *d) |
40 | { | 24 | { |
41 | int pin = irq_to_pmu(d->irq); | 25 | int pin = irq_to_pmu(d->irq); |
@@ -90,6 +74,27 @@ static void pmu_irq_handler(unsigned int irq, struct irq_desc *desc) | |||
90 | } | 74 | } |
91 | } | 75 | } |
92 | 76 | ||
77 | static int __initdata gpio0_irqs[4] = { | ||
78 | IRQ_DOVE_GPIO_0_7, | ||
79 | IRQ_DOVE_GPIO_8_15, | ||
80 | IRQ_DOVE_GPIO_16_23, | ||
81 | IRQ_DOVE_GPIO_24_31, | ||
82 | }; | ||
83 | |||
84 | static int __initdata gpio1_irqs[4] = { | ||
85 | IRQ_DOVE_HIGH_GPIO, | ||
86 | 0, | ||
87 | 0, | ||
88 | 0, | ||
89 | }; | ||
90 | |||
91 | static int __initdata gpio2_irqs[4] = { | ||
92 | 0, | ||
93 | 0, | ||
94 | 0, | ||
95 | 0, | ||
96 | }; | ||
97 | |||
93 | void __init dove_init_irq(void) | 98 | void __init dove_init_irq(void) |
94 | { | 99 | { |
95 | int i; | 100 | int i; |
@@ -100,19 +105,14 @@ void __init dove_init_irq(void) | |||
100 | /* | 105 | /* |
101 | * Initialize gpiolib for GPIOs 0-71. | 106 | * Initialize gpiolib for GPIOs 0-71. |
102 | */ | 107 | */ |
103 | orion_gpio_init(0, 32, DOVE_GPIO_LO_VIRT_BASE, 0, | 108 | orion_gpio_init(NULL, 0, 32, (void __iomem *)DOVE_GPIO_LO_VIRT_BASE, 0, |
104 | IRQ_DOVE_GPIO_START); | 109 | IRQ_DOVE_GPIO_START, gpio0_irqs); |
105 | irq_set_chained_handler(IRQ_DOVE_GPIO_0_7, gpio_irq_handler); | 110 | |
106 | irq_set_chained_handler(IRQ_DOVE_GPIO_8_15, gpio_irq_handler); | 111 | orion_gpio_init(NULL, 32, 32, (void __iomem *)DOVE_GPIO_HI_VIRT_BASE, 0, |
107 | irq_set_chained_handler(IRQ_DOVE_GPIO_16_23, gpio_irq_handler); | 112 | IRQ_DOVE_GPIO_START + 32, gpio1_irqs); |
108 | irq_set_chained_handler(IRQ_DOVE_GPIO_24_31, gpio_irq_handler); | 113 | |
109 | 114 | orion_gpio_init(NULL, 64, 8, (void __iomem *)DOVE_GPIO2_VIRT_BASE, 0, | |
110 | orion_gpio_init(32, 32, DOVE_GPIO_HI_VIRT_BASE, 0, | 115 | IRQ_DOVE_GPIO_START + 64, gpio2_irqs); |
111 | IRQ_DOVE_GPIO_START + 32); | ||
112 | irq_set_chained_handler(IRQ_DOVE_HIGH_GPIO, gpio_irq_handler); | ||
113 | |||
114 | orion_gpio_init(64, 8, DOVE_GPIO2_VIRT_BASE, 0, | ||
115 | IRQ_DOVE_GPIO_START + 64); | ||
116 | 116 | ||
117 | /* | 117 | /* |
118 | * Mask and clear PMU interrupts | 118 | * Mask and clear PMU interrupts |
diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c index edc3f8a9d45e..27ac3d84016b 100644 --- a/arch/arm/mach-kirkwood/board-dt.c +++ b/arch/arm/mach-kirkwood/board-dt.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <asm/mach/arch.h> | 18 | #include <asm/mach/arch.h> |
19 | #include <asm/mach/map.h> | 19 | #include <asm/mach/map.h> |
20 | #include <mach/bridge-regs.h> | 20 | #include <mach/bridge-regs.h> |
21 | #include <plat/irq.h> | ||
21 | #include "common.h" | 22 | #include "common.h" |
22 | 23 | ||
23 | static struct of_device_id kirkwood_dt_match_table[] __initdata = { | 24 | static struct of_device_id kirkwood_dt_match_table[] __initdata = { |
@@ -84,7 +85,7 @@ DT_MACHINE_START(KIRKWOOD_DT, "Marvell Kirkwood (Flattened Device Tree)") | |||
84 | /* Maintainer: Jason Cooper <jason@lakedaemon.net> */ | 85 | /* Maintainer: Jason Cooper <jason@lakedaemon.net> */ |
85 | .map_io = kirkwood_map_io, | 86 | .map_io = kirkwood_map_io, |
86 | .init_early = kirkwood_init_early, | 87 | .init_early = kirkwood_init_early, |
87 | .init_irq = kirkwood_init_irq, | 88 | .init_irq = orion_dt_init_irq, |
88 | .timer = &kirkwood_timer, | 89 | .timer = &kirkwood_timer, |
89 | .init_machine = kirkwood_dt_init, | 90 | .init_machine = kirkwood_dt_init, |
90 | .restart = kirkwood_restart, | 91 | .restart = kirkwood_restart, |
diff --git a/arch/arm/mach-kirkwood/irq.c b/arch/arm/mach-kirkwood/irq.c index c4c68e5b94f1..720063ffa19d 100644 --- a/arch/arm/mach-kirkwood/irq.c +++ b/arch/arm/mach-kirkwood/irq.c | |||
@@ -9,20 +9,23 @@ | |||
9 | */ | 9 | */ |
10 | #include <linux/gpio.h> | 10 | #include <linux/gpio.h> |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/init.h> | ||
13 | #include <linux/irq.h> | 12 | #include <linux/irq.h> |
14 | #include <linux/io.h> | ||
15 | #include <mach/bridge-regs.h> | 13 | #include <mach/bridge-regs.h> |
16 | #include <plat/irq.h> | 14 | #include <plat/irq.h> |
17 | #include "common.h" | ||
18 | 15 | ||
19 | static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) | 16 | static int __initdata gpio0_irqs[4] = { |
20 | { | 17 | IRQ_KIRKWOOD_GPIO_LOW_0_7, |
21 | BUG_ON(irq < IRQ_KIRKWOOD_GPIO_LOW_0_7); | 18 | IRQ_KIRKWOOD_GPIO_LOW_8_15, |
22 | BUG_ON(irq > IRQ_KIRKWOOD_GPIO_HIGH_16_23); | 19 | IRQ_KIRKWOOD_GPIO_LOW_16_23, |
20 | IRQ_KIRKWOOD_GPIO_LOW_24_31, | ||
21 | }; | ||
23 | 22 | ||
24 | orion_gpio_irq_handler((irq - IRQ_KIRKWOOD_GPIO_LOW_0_7) << 3); | 23 | static int __initdata gpio1_irqs[4] = { |
25 | } | 24 | IRQ_KIRKWOOD_GPIO_HIGH_0_7, |
25 | IRQ_KIRKWOOD_GPIO_HIGH_8_15, | ||
26 | IRQ_KIRKWOOD_GPIO_HIGH_16_23, | ||
27 | 0, | ||
28 | }; | ||
26 | 29 | ||
27 | void __init kirkwood_init_irq(void) | 30 | void __init kirkwood_init_irq(void) |
28 | { | 31 | { |
@@ -32,17 +35,8 @@ void __init kirkwood_init_irq(void) | |||
32 | /* | 35 | /* |
33 | * Initialize gpiolib for GPIOs 0-49. | 36 | * Initialize gpiolib for GPIOs 0-49. |
34 | */ | 37 | */ |
35 | orion_gpio_init(0, 32, GPIO_LOW_VIRT_BASE, 0, | 38 | orion_gpio_init(NULL, 0, 32, (void __iomem *)GPIO_LOW_VIRT_BASE, 0, |
36 | IRQ_KIRKWOOD_GPIO_START); | 39 | IRQ_KIRKWOOD_GPIO_START, gpio0_irqs); |
37 | irq_set_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_0_7, gpio_irq_handler); | 40 | orion_gpio_init(NULL, 32, 18, (void __iomem *)GPIO_HIGH_VIRT_BASE, 0, |
38 | irq_set_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_8_15, gpio_irq_handler); | 41 | IRQ_KIRKWOOD_GPIO_START + 32, gpio1_irqs); |
39 | irq_set_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_16_23, gpio_irq_handler); | ||
40 | irq_set_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_24_31, gpio_irq_handler); | ||
41 | |||
42 | orion_gpio_init(32, 18, GPIO_HIGH_VIRT_BASE, 0, | ||
43 | IRQ_KIRKWOOD_GPIO_START + 32); | ||
44 | irq_set_chained_handler(IRQ_KIRKWOOD_GPIO_HIGH_0_7, gpio_irq_handler); | ||
45 | irq_set_chained_handler(IRQ_KIRKWOOD_GPIO_HIGH_8_15, gpio_irq_handler); | ||
46 | irq_set_chained_handler(IRQ_KIRKWOOD_GPIO_HIGH_16_23, | ||
47 | gpio_irq_handler); | ||
48 | } | 42 | } |
diff --git a/arch/arm/mach-mv78xx0/irq.c b/arch/arm/mach-mv78xx0/irq.c index e421b701663b..eff9a750bbe2 100644 --- a/arch/arm/mach-mv78xx0/irq.c +++ b/arch/arm/mach-mv78xx0/irq.c | |||
@@ -9,19 +9,17 @@ | |||
9 | */ | 9 | */ |
10 | #include <linux/gpio.h> | 10 | #include <linux/gpio.h> |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/init.h> | ||
13 | #include <linux/pci.h> | ||
14 | #include <linux/irq.h> | 12 | #include <linux/irq.h> |
15 | #include <mach/bridge-regs.h> | 13 | #include <mach/bridge-regs.h> |
16 | #include <plat/irq.h> | 14 | #include <plat/irq.h> |
17 | #include "common.h" | 15 | #include "common.h" |
18 | 16 | ||
19 | static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) | 17 | static int __initdata gpio0_irqs[4] = { |
20 | { | 18 | IRQ_MV78XX0_GPIO_0_7, |
21 | BUG_ON(irq < IRQ_MV78XX0_GPIO_0_7 || irq > IRQ_MV78XX0_GPIO_24_31); | 19 | IRQ_MV78XX0_GPIO_8_15, |
22 | 20 | IRQ_MV78XX0_GPIO_16_23, | |
23 | orion_gpio_irq_handler((irq - IRQ_MV78XX0_GPIO_0_7) << 3); | 21 | IRQ_MV78XX0_GPIO_24_31, |
24 | } | 22 | }; |
25 | 23 | ||
26 | void __init mv78xx0_init_irq(void) | 24 | void __init mv78xx0_init_irq(void) |
27 | { | 25 | { |
@@ -34,11 +32,7 @@ void __init mv78xx0_init_irq(void) | |||
34 | * registers for core #1 are at an offset of 0x18 from those of | 32 | * registers for core #1 are at an offset of 0x18 from those of |
35 | * core #0.) | 33 | * core #0.) |
36 | */ | 34 | */ |
37 | orion_gpio_init(0, 32, GPIO_VIRT_BASE, | 35 | orion_gpio_init(NULL, 0, 32, (void __iomem *)GPIO_VIRT_BASE, |
38 | mv78xx0_core_index() ? 0x18 : 0, | 36 | mv78xx0_core_index() ? 0x18 : 0, |
39 | IRQ_MV78XX0_GPIO_START); | 37 | IRQ_MV78XX0_GPIO_START, gpio0_irqs); |
40 | irq_set_chained_handler(IRQ_MV78XX0_GPIO_0_7, gpio_irq_handler); | ||
41 | irq_set_chained_handler(IRQ_MV78XX0_GPIO_8_15, gpio_irq_handler); | ||
42 | irq_set_chained_handler(IRQ_MV78XX0_GPIO_16_23, gpio_irq_handler); | ||
43 | irq_set_chained_handler(IRQ_MV78XX0_GPIO_24_31, gpio_irq_handler); | ||
44 | } | 38 | } |
diff --git a/arch/arm/mach-orion5x/irq.c b/arch/arm/mach-orion5x/irq.c index b1b45fff776e..17da7091d310 100644 --- a/arch/arm/mach-orion5x/irq.c +++ b/arch/arm/mach-orion5x/irq.c | |||
@@ -11,19 +11,16 @@ | |||
11 | */ | 11 | */ |
12 | #include <linux/gpio.h> | 12 | #include <linux/gpio.h> |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/init.h> | ||
15 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
16 | #include <linux/io.h> | ||
17 | #include <mach/bridge-regs.h> | 15 | #include <mach/bridge-regs.h> |
18 | #include <plat/irq.h> | 16 | #include <plat/irq.h> |
19 | #include "common.h" | ||
20 | 17 | ||
21 | static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) | 18 | static int __initdata gpio0_irqs[4] = { |
22 | { | 19 | IRQ_ORION5X_GPIO_0_7, |
23 | BUG_ON(irq < IRQ_ORION5X_GPIO_0_7 || irq > IRQ_ORION5X_GPIO_24_31); | 20 | IRQ_ORION5X_GPIO_8_15, |
24 | 21 | IRQ_ORION5X_GPIO_16_23, | |
25 | orion_gpio_irq_handler((irq - IRQ_ORION5X_GPIO_0_7) << 3); | 22 | IRQ_ORION5X_GPIO_24_31, |
26 | } | 23 | }; |
27 | 24 | ||
28 | void __init orion5x_init_irq(void) | 25 | void __init orion5x_init_irq(void) |
29 | { | 26 | { |
@@ -32,9 +29,6 @@ void __init orion5x_init_irq(void) | |||
32 | /* | 29 | /* |
33 | * Initialize gpiolib for GPIOs 0-31. | 30 | * Initialize gpiolib for GPIOs 0-31. |
34 | */ | 31 | */ |
35 | orion_gpio_init(0, 32, GPIO_VIRT_BASE, 0, IRQ_ORION5X_GPIO_START); | 32 | orion_gpio_init(NULL, 0, 32, (void __iomem *)GPIO_VIRT_BASE, 0, |
36 | irq_set_chained_handler(IRQ_ORION5X_GPIO_0_7, gpio_irq_handler); | 33 | IRQ_ORION5X_GPIO_START, gpio0_irqs); |
37 | irq_set_chained_handler(IRQ_ORION5X_GPIO_8_15, gpio_irq_handler); | ||
38 | irq_set_chained_handler(IRQ_ORION5X_GPIO_16_23, gpio_irq_handler); | ||
39 | irq_set_chained_handler(IRQ_ORION5X_GPIO_24_31, gpio_irq_handler); | ||
40 | } | 34 | } |
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 | ||
43 | static void __iomem *GPIO_OUT(struct orion_gpio_chip *ochip) | 51 | static 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 | ||
404 | void __init orion_gpio_init(int gpio_base, int ngpio, | 409 | static 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 | |||
442 | void __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 | ||
472 | void 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; | 543 | static 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; | ||
577 | out: | ||
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)); | 581 | void __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, | |||
27 | void orion_gpio_set_valid(unsigned pin, int mode); | 27 | void orion_gpio_set_valid(unsigned pin, int mode); |
28 | 28 | ||
29 | /* Initialize gpiolib. */ | 29 | /* Initialize gpiolib. */ |
30 | void __init orion_gpio_init(int gpio_base, int ngpio, | 30 | void __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 | */ | ||
36 | void orion_gpio_irq_handler(int irqoff); | ||
37 | |||
38 | 35 | ||
36 | void __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 | ||
14 | void orion_irq_init(unsigned int irq_start, void __iomem *maskaddr); | 14 | void orion_irq_init(unsigned int irq_start, void __iomem *maskaddr); |
15 | 15 | void __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 | ||
17 | void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr) | 21 | void __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 | ||
41 | static 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 | |||
64 | static const struct of_device_id orion_irq_match[] = { | ||
65 | { .compatible = "marvell,orion-intc", | ||
66 | .data = orion_add_irq_domain, }, | ||
67 | {}, | ||
68 | }; | ||
69 | |||
70 | void __init orion_dt_init_irq(void) | ||
71 | { | ||
72 | of_irq_init(orion_irq_match); | ||
73 | } | ||
74 | #endif | ||