2 * linux/arch/m68k/amiga/cia.c - CIA support
4 * Copyright (C) 1996 Roman Zippel
6 * The concept of some functions bases on the original Amiga OS function
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file COPYING in the main directory of this archive
13 #include <linux/types.h>
14 #include <linux/kernel.h>
15 #include <linux/sched.h>
16 #include <linux/errno.h>
17 #include <linux/kernel_stat.h>
18 #include <linux/init.h>
19 #include <linux/seq_file.h>
20 #include <linux/interrupt.h>
23 #include <asm/amigahw.h>
24 #include <asm/amigaints.h>
27 volatile struct CIA
*cia
;
28 unsigned char icr_mask
, icr_data
;
29 unsigned short int_mask
;
30 int handler_irq
, cia_irq
, server_irq
;
35 .handler_irq
= IRQ_AMIGA_PORTS
,
36 .cia_irq
= IRQ_AMIGA_CIAA
,
41 .handler_irq
= IRQ_AMIGA_EXTER
,
42 .cia_irq
= IRQ_AMIGA_CIAB
,
47 * Cause or clear CIA interrupts, return old interrupt status.
50 unsigned char cia_set_irq(struct ciabase
*base
, unsigned char mask
)
54 old
= (base
->icr_data
|= base
->cia
->icr
);
55 if (mask
& CIA_ICR_SETCLR
)
56 base
->icr_data
|= mask
;
58 base
->icr_data
&= ~mask
;
59 if (base
->icr_data
& base
->icr_mask
)
60 amiga_custom
.intreq
= IF_SETCLR
| base
->int_mask
;
61 return old
& base
->icr_mask
;
65 * Enable or disable CIA interrupts, return old interrupt mask,
68 unsigned char cia_able_irq(struct ciabase
*base
, unsigned char mask
)
73 base
->icr_data
|= base
->cia
->icr
;
74 base
->cia
->icr
= mask
;
75 if (mask
& CIA_ICR_SETCLR
)
76 base
->icr_mask
|= mask
;
78 base
->icr_mask
&= ~mask
;
79 base
->icr_mask
&= CIA_ICR_ALL
;
80 if (base
->icr_data
& base
->icr_mask
)
81 amiga_custom
.intreq
= IF_SETCLR
| base
->int_mask
;
85 static irqreturn_t
cia_handler(int irq
, void *dev_id
)
87 struct ciabase
*base
= dev_id
;
91 mach_irq
= base
->cia_irq
;
92 ints
= cia_set_irq(base
, CIA_ICR_ALL
);
93 amiga_custom
.intreq
= base
->int_mask
;
94 for (; ints
; mach_irq
++, ints
>>= 1) {
96 generic_handle_irq(mach_irq
);
101 static void cia_irq_enable(struct irq_data
*data
)
103 unsigned int irq
= data
->irq
;
106 if (irq
>= IRQ_AMIGA_CIAB
) {
107 mask
= 1 << (irq
- IRQ_AMIGA_CIAB
);
108 cia_set_irq(&ciab_base
, mask
);
109 cia_able_irq(&ciab_base
, CIA_ICR_SETCLR
| mask
);
111 mask
= 1 << (irq
- IRQ_AMIGA_CIAA
);
112 cia_set_irq(&ciaa_base
, mask
);
113 cia_able_irq(&ciaa_base
, CIA_ICR_SETCLR
| mask
);
117 static void cia_irq_disable(struct irq_data
*data
)
119 unsigned int irq
= data
->irq
;
121 if (irq
>= IRQ_AMIGA_CIAB
)
122 cia_able_irq(&ciab_base
, 1 << (irq
- IRQ_AMIGA_CIAB
));
124 cia_able_irq(&ciaa_base
, 1 << (irq
- IRQ_AMIGA_CIAA
));
127 static struct irq_chip cia_irq_chip
= {
129 .irq_enable
= cia_irq_enable
,
130 .irq_disable
= cia_irq_disable
,
134 * Override auto irq 2 & 6 and use them as general chain
135 * for external interrupts, we link the CIA interrupt sources
139 static void auto_irq_enable(struct irq_data
*data
)
143 amiga_custom
.intena
= IF_SETCLR
| IF_PORTS
;
146 amiga_custom
.intena
= IF_SETCLR
| IF_EXTER
;
151 static void auto_irq_disable(struct irq_data
*data
)
155 amiga_custom
.intena
= IF_PORTS
;
158 amiga_custom
.intena
= IF_EXTER
;
163 static struct irq_chip auto_irq_chip
= {
165 .irq_enable
= auto_irq_enable
,
166 .irq_disable
= auto_irq_disable
,
169 void __init
cia_init_IRQ(struct ciabase
*base
)
171 m68k_setup_irq_controller(&cia_irq_chip
, handle_simple_irq
,
172 base
->cia_irq
, CIA_IRQS
);
174 /* clear any pending interrupt and turn off all interrupts */
175 cia_set_irq(base
, CIA_ICR_ALL
);
176 cia_able_irq(base
, CIA_ICR_ALL
);
178 /* override auto int and install CIA handler */
179 m68k_setup_irq_controller(&auto_irq_chip
, handle_simple_irq
,
180 base
->handler_irq
, 1);
181 m68k_irq_startup_irq(base
->handler_irq
);
182 if (request_irq(base
->handler_irq
, cia_handler
, IRQF_SHARED
,
184 pr_err("Couldn't register %s interrupt\n", base
->name
);