diff options
author | Michael Schmitz <schmitzmic@gmail.com> | 2013-04-05 20:26:43 -0400 |
---|---|---|
committer | Geert Uytterhoeven <geert@linux-m68k.org> | 2013-04-16 15:35:39 -0400 |
commit | e6f80e87e05cc47188a141f68e9859ed438b4489 (patch) | |
tree | 9d1c6ea05d9754f8ebbf6a840d7ada94bac2f2dc /arch/m68k | |
parent | 1d87a8f2911fe6c22416f4a5dc5e0362f5bb9ef4 (diff) |
m68k/atari: EtherNAT - add interrupt chip definition for CPLD interrupts
Add a dedicated interrupt chip definition for the EtherNAT CPLD interrupts.
SMC91C111 and ISP1160 chips have separate interrupts that can be enabled
and disabled in a CPLD register at offset 0x23 from the card base.
Note the CPLD interrupt control register is mapped on demand, whenever any
interrupt enable/disable action is requested. The EtherNAT USB driver still
needs interrupts disabled around reset and start actions.
In particular, we cannot entirely rely on the irq_startup being called
first.
The smc91x and isp116x-hcd drivers will use this feature.
Signed-off-by: Michael Schmitz <schmitz@debian.org>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Diffstat (limited to 'arch/m68k')
-rw-r--r-- | arch/m68k/atari/ataints.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c index f699c829e594..20cde4e9fc77 100644 --- a/arch/m68k/atari/ataints.c +++ b/arch/m68k/atari/ataints.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <asm/atari_stdma.h> | 49 | #include <asm/atari_stdma.h> |
50 | #include <asm/irq.h> | 50 | #include <asm/irq.h> |
51 | #include <asm/entry.h> | 51 | #include <asm/entry.h> |
52 | #include <asm/io.h> | ||
52 | 53 | ||
53 | 54 | ||
54 | /* | 55 | /* |
@@ -177,6 +178,80 @@ static struct irq_chip atari_mfptimer_chip = { | |||
177 | .irq_disable = atari_mfptimer_disable, | 178 | .irq_disable = atari_mfptimer_disable, |
178 | }; | 179 | }; |
179 | 180 | ||
181 | |||
182 | /* | ||
183 | * EtherNAT CPLD interrupt handling | ||
184 | * CPLD interrupt register is at phys. 0x80000023 | ||
185 | * Need this mapped in at interrupt startup time | ||
186 | * Possibly need this mapped on demand anyway - | ||
187 | * EtherNAT USB driver needs to disable IRQ before | ||
188 | * startup! | ||
189 | */ | ||
190 | |||
191 | static unsigned char *enat_cpld; | ||
192 | |||
193 | static unsigned int atari_ethernat_startup(struct irq_data *data) | ||
194 | { | ||
195 | int enat_num = 140 - data->irq + 1; | ||
196 | |||
197 | m68k_irq_startup(data); | ||
198 | /* | ||
199 | * map CPLD interrupt register | ||
200 | */ | ||
201 | if (!enat_cpld) | ||
202 | enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2); | ||
203 | /* | ||
204 | * do _not_ enable the USB chip interrupt here - causes interrupt storm | ||
205 | * and triggers dead interrupt watchdog | ||
206 | * Need to reset the USB chip to a sane state in early startup before | ||
207 | * removing this hack | ||
208 | */ | ||
209 | if (enat_num == 1) | ||
210 | *enat_cpld |= 1 << enat_num; | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static void atari_ethernat_enable(struct irq_data *data) | ||
216 | { | ||
217 | int enat_num = 140 - data->irq + 1; | ||
218 | /* | ||
219 | * map CPLD interrupt register | ||
220 | */ | ||
221 | if (!enat_cpld) | ||
222 | enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2); | ||
223 | *enat_cpld |= 1 << enat_num; | ||
224 | } | ||
225 | |||
226 | static void atari_ethernat_disable(struct irq_data *data) | ||
227 | { | ||
228 | int enat_num = 140 - data->irq + 1; | ||
229 | /* | ||
230 | * map CPLD interrupt register | ||
231 | */ | ||
232 | if (!enat_cpld) | ||
233 | enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2); | ||
234 | *enat_cpld &= ~(1 << enat_num); | ||
235 | } | ||
236 | |||
237 | static void atari_ethernat_shutdown(struct irq_data *data) | ||
238 | { | ||
239 | int enat_num = 140 - data->irq + 1; | ||
240 | if (enat_cpld) { | ||
241 | *enat_cpld &= ~(1 << enat_num); | ||
242 | iounmap(enat_cpld); | ||
243 | enat_cpld = NULL; | ||
244 | } | ||
245 | } | ||
246 | |||
247 | static struct irq_chip atari_ethernat_chip = { | ||
248 | .name = "ethernat", | ||
249 | .irq_startup = atari_ethernat_startup, | ||
250 | .irq_shutdown = atari_ethernat_shutdown, | ||
251 | .irq_enable = atari_ethernat_enable, | ||
252 | .irq_disable = atari_ethernat_disable, | ||
253 | }; | ||
254 | |||
180 | /* | 255 | /* |
181 | * void atari_init_IRQ (void) | 256 | * void atari_init_IRQ (void) |
182 | * | 257 | * |
@@ -268,6 +343,13 @@ void __init atari_init_IRQ(void) | |||
268 | if (request_irq(IRQ_MFP_TIMD, mfptimer_handler, IRQF_SHARED, | 343 | if (request_irq(IRQ_MFP_TIMD, mfptimer_handler, IRQF_SHARED, |
269 | stmfp_base.name, &stmfp_base)) | 344 | stmfp_base.name, &stmfp_base)) |
270 | pr_err("Couldn't register %s interrupt\n", stmfp_base.name); | 345 | pr_err("Couldn't register %s interrupt\n", stmfp_base.name); |
346 | |||
347 | /* | ||
348 | * EtherNAT ethernet / USB interrupt handlers | ||
349 | */ | ||
350 | |||
351 | m68k_setup_irq_controller(&atari_ethernat_chip, handle_simple_irq, | ||
352 | 139, 2); | ||
271 | } | 353 | } |
272 | 354 | ||
273 | 355 | ||