diff options
author | Greg Ungerer <gerg@uclinux.org> | 2011-03-11 02:06:58 -0500 |
---|---|---|
committer | Greg Ungerer <gerg@uclinux.org> | 2011-03-15 07:01:57 -0400 |
commit | 57b481436f2a5580054784af8f044d2e3f602b53 (patch) | |
tree | c061e392e9001cdc7798a8cecc5763e605186e05 /arch/m68knommu | |
parent | ce3de78a1c9504dba1781e47613b397e4028ae2b (diff) |
m68knommu: external interrupt support to ColdFire intc-2 controller
The EDGE Port module of some ColdFire parts using the intc-2 interrupt
controller provides support for 7 external interrupts. These interrupts
go off-chip (that is they are not for internal peripherals). They need
some special handling and have some extra setup registers. Add code to
support them.
Signed-off-by: Greg Ungerer <gerg@uclinux.org>
Diffstat (limited to 'arch/m68knommu')
-rw-r--r-- | arch/m68knommu/platform/coldfire/intc-2.c | 85 |
1 files changed, 81 insertions, 4 deletions
diff --git a/arch/m68knommu/platform/coldfire/intc-2.c b/arch/m68knommu/platform/coldfire/intc-2.c index 66d4e47dd8d0..2cbfbf035db9 100644 --- a/arch/m68knommu/platform/coldfire/intc-2.c +++ b/arch/m68knommu/platform/coldfire/intc-2.c | |||
@@ -7,7 +7,10 @@ | |||
7 | * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such | 7 | * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such |
8 | * controllers, and the 547x and 548x families which have only one of them. | 8 | * controllers, and the 547x and 548x families which have only one of them. |
9 | * | 9 | * |
10 | * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com> | 10 | * The external 7 fixed interrupts are part the the Edge Port unit of these |
11 | * ColdFire parts. They can be configured as level or edge triggered. | ||
12 | * | ||
13 | * (C) Copyright 2009-2011, Greg Ungerer <gerg@snapgear.com> | ||
11 | * | 14 | * |
12 | * This file is subject to the terms and conditions of the GNU General Public | 15 | * This file is subject to the terms and conditions of the GNU General Public |
13 | * License. See the file COPYING in the main directory of this archive | 16 | * License. See the file COPYING in the main directory of this archive |
@@ -30,6 +33,14 @@ | |||
30 | #define MCFSIM_ICR_LEVEL(l) ((l)<<3) /* Level l intr */ | 33 | #define MCFSIM_ICR_LEVEL(l) ((l)<<3) /* Level l intr */ |
31 | #define MCFSIM_ICR_PRI(p) (p) /* Priority p intr */ | 34 | #define MCFSIM_ICR_PRI(p) (p) /* Priority p intr */ |
32 | 35 | ||
36 | /* | ||
37 | * The EDGE Port interrupts are the fixed 7 external interrupts. | ||
38 | * They need some special treatment, for example they need to be acked. | ||
39 | */ | ||
40 | #define EINT0 64 /* Is not actually used, but spot reserved for it */ | ||
41 | #define EINT1 65 /* EDGE Port interrupt 1 */ | ||
42 | #define EINT7 71 /* EDGE Port interrupt 7 */ | ||
43 | |||
33 | #ifdef MCFICM_INTC1 | 44 | #ifdef MCFICM_INTC1 |
34 | #define NR_VECS 128 | 45 | #define NR_VECS 128 |
35 | #else | 46 | #else |
@@ -76,9 +87,17 @@ static void intc_irq_unmask(struct irq_data *d) | |||
76 | __raw_writel(val & ~imrbit, imraddr); | 87 | __raw_writel(val & ~imrbit, imraddr); |
77 | } | 88 | } |
78 | 89 | ||
79 | static int intc_irq_set_type(struct irq_data *d, unsigned int type) | 90 | /* |
91 | * Only the external (or EDGE Port) interrupts need to be acknowledged | ||
92 | * here, as part of the IRQ handler. They only really need to be ack'ed | ||
93 | * if they are in edge triggered mode, but there is no harm in doing it | ||
94 | * for all types. | ||
95 | */ | ||
96 | static void intc_irq_ack(struct irq_data *d) | ||
80 | { | 97 | { |
81 | return 0; | 98 | unsigned int irq = d->irq; |
99 | |||
100 | __raw_writeb(0x1 << (irq - EINT0), MCFEPORT_EPFR); | ||
82 | } | 101 | } |
83 | 102 | ||
84 | /* | 103 | /* |
@@ -104,15 +123,70 @@ static unsigned int intc_irq_startup(struct irq_data *d) | |||
104 | if (__raw_readb(icraddr) == 0) | 123 | if (__raw_readb(icraddr) == 0) |
105 | __raw_writeb(intc_intpri--, icraddr); | 124 | __raw_writeb(intc_intpri--, icraddr); |
106 | 125 | ||
126 | irq = d->irq; | ||
127 | if ((irq >= EINT1) && (irq <= EINT7)) { | ||
128 | u8 v; | ||
129 | |||
130 | irq -= EINT0; | ||
131 | |||
132 | /* Set EPORT line as input */ | ||
133 | v = __raw_readb(MCFEPORT_EPDDR); | ||
134 | __raw_writeb(v & ~(0x1 << irq), MCFEPORT_EPDDR); | ||
135 | |||
136 | /* Set EPORT line as interrupt source */ | ||
137 | v = __raw_readb(MCFEPORT_EPIER); | ||
138 | __raw_writeb(v | (0x1 << irq), MCFEPORT_EPIER); | ||
139 | } | ||
140 | |||
107 | intc_irq_unmask(d); | 141 | intc_irq_unmask(d); |
108 | return 0; | 142 | return 0; |
109 | } | 143 | } |
110 | 144 | ||
145 | static int intc_irq_set_type(struct irq_data *d, unsigned int type) | ||
146 | { | ||
147 | unsigned int irq = d->irq; | ||
148 | u16 pa, tb; | ||
149 | |||
150 | switch (type) { | ||
151 | case IRQ_TYPE_EDGE_RISING: | ||
152 | tb = 0x1; | ||
153 | break; | ||
154 | case IRQ_TYPE_EDGE_FALLING: | ||
155 | tb = 0x2; | ||
156 | break; | ||
157 | case IRQ_TYPE_EDGE_BOTH: | ||
158 | tb = 0x3; | ||
159 | break; | ||
160 | default: | ||
161 | /* Level triggered */ | ||
162 | tb = 0; | ||
163 | break; | ||
164 | } | ||
165 | |||
166 | if (tb) | ||
167 | set_irq_handler(irq, handle_edge_irq); | ||
168 | |||
169 | irq -= EINT0; | ||
170 | pa = __raw_readw(MCFEPORT_EPPAR); | ||
171 | pa = (pa & ~(0x3 << (irq * 2))) | (tb << (irq * 2)); | ||
172 | __raw_writew(pa, MCFEPORT_EPPAR); | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
111 | static struct irq_chip intc_irq_chip = { | 177 | static struct irq_chip intc_irq_chip = { |
112 | .name = "CF-INTC", | 178 | .name = "CF-INTC", |
113 | .irq_startup = intc_irq_startup, | 179 | .irq_startup = intc_irq_startup, |
114 | .irq_mask = intc_irq_mask, | 180 | .irq_mask = intc_irq_mask, |
115 | .irq_unmask = intc_irq_unmask, | 181 | .irq_unmask = intc_irq_unmask, |
182 | }; | ||
183 | |||
184 | static struct irq_chip intc_irq_chip_edge_port = { | ||
185 | .name = "CF-INTC-EP", | ||
186 | .irq_startup = intc_irq_startup, | ||
187 | .irq_mask = intc_irq_mask, | ||
188 | .irq_unmask = intc_irq_unmask, | ||
189 | .irq_ack = intc_irq_ack, | ||
116 | .irq_set_type = intc_irq_set_type, | 190 | .irq_set_type = intc_irq_set_type, |
117 | }; | 191 | }; |
118 | 192 | ||
@@ -129,7 +203,10 @@ void __init init_IRQ(void) | |||
129 | #endif | 203 | #endif |
130 | 204 | ||
131 | for (irq = MCFINT_VECBASE; (irq < MCFINT_VECBASE + NR_VECS); irq++) { | 205 | for (irq = MCFINT_VECBASE; (irq < MCFINT_VECBASE + NR_VECS); irq++) { |
132 | set_irq_chip(irq, &intc_irq_chip); | 206 | if ((irq >= EINT1) && (irq <=EINT7)) |
207 | set_irq_chip(irq, &intc_irq_chip_edge_port); | ||
208 | else | ||
209 | set_irq_chip(irq, &intc_irq_chip); | ||
133 | set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); | 210 | set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); |
134 | set_irq_handler(irq, handle_level_irq); | 211 | set_irq_handler(irq, handle_level_irq); |
135 | } | 212 | } |