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 m68k_handle_int(mach_irq
);
101 static void cia_enable_irq(unsigned int irq
)
105 if (irq
>= IRQ_AMIGA_CIAB
) {
106 mask
= 1 << (irq
- IRQ_AMIGA_CIAB
);
107 cia_set_irq(&ciab_base
, mask
);
108 cia_able_irq(&ciab_base
, CIA_ICR_SETCLR
| mask
);
110 mask
= 1 << (irq
- IRQ_AMIGA_CIAA
);
111 cia_set_irq(&ciaa_base
, mask
);
112 cia_able_irq(&ciaa_base
, CIA_ICR_SETCLR
| mask
);
116 static void cia_disable_irq(unsigned int irq
)
118 if (irq
>= IRQ_AMIGA_CIAB
)
119 cia_able_irq(&ciab_base
, 1 << (irq
- IRQ_AMIGA_CIAB
));
121 cia_able_irq(&ciaa_base
, 1 << (irq
- IRQ_AMIGA_CIAA
));
124 static struct irq_controller cia_irq_controller
= {
126 .lock
= __SPIN_LOCK_UNLOCKED(cia_irq_controller
.lock
),
127 .enable
= cia_enable_irq
,
128 .disable
= cia_disable_irq
,
132 * Override auto irq 2 & 6 and use them as general chain
133 * for external interrupts, we link the CIA interrupt sources
137 static void auto_enable_irq(unsigned int irq
)
141 amiga_custom
.intena
= IF_SETCLR
| IF_PORTS
;
144 amiga_custom
.intena
= IF_SETCLR
| IF_EXTER
;
149 static void auto_disable_irq(unsigned int irq
)
153 amiga_custom
.intena
= IF_PORTS
;
156 amiga_custom
.intena
= IF_EXTER
;
161 static struct irq_controller auto_irq_controller
= {
163 .lock
= __SPIN_LOCK_UNLOCKED(auto_irq_controller
.lock
),
164 .enable
= auto_enable_irq
,
165 .disable
= auto_disable_irq
,
168 void __init
cia_init_IRQ(struct ciabase
*base
)
170 m68k_setup_irq_controller(&cia_irq_controller
, base
->cia_irq
, CIA_IRQS
);
172 /* clear any pending interrupt and turn off all interrupts */
173 cia_set_irq(base
, CIA_ICR_ALL
);
174 cia_able_irq(base
, CIA_ICR_ALL
);
176 /* override auto int and install CIA handler */
177 m68k_setup_irq_controller(&auto_irq_controller
, base
->handler_irq
, 1);
178 m68k_irq_startup(base
->handler_irq
);
179 if (request_irq(base
->handler_irq
, cia_handler
, IRQF_SHARED
,
181 pr_err("Couldn't register %s interrupt\n", base
->name
);