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>
21 #include <linux/irq.h>
24 #include <asm/amigahw.h>
25 #include <asm/amigaints.h>
28 volatile struct CIA
*cia
;
29 unsigned char icr_mask
, icr_data
;
30 unsigned short int_mask
;
31 int handler_irq
, cia_irq
, server_irq
;
36 .handler_irq
= IRQ_AMIGA_PORTS
,
37 .cia_irq
= IRQ_AMIGA_CIAA
,
42 .handler_irq
= IRQ_AMIGA_EXTER
,
43 .cia_irq
= IRQ_AMIGA_CIAB
,
48 * Cause or clear CIA interrupts, return old interrupt status.
51 unsigned char cia_set_irq(struct ciabase
*base
, unsigned char mask
)
55 old
= (base
->icr_data
|= base
->cia
->icr
);
56 if (mask
& CIA_ICR_SETCLR
)
57 base
->icr_data
|= mask
;
59 base
->icr_data
&= ~mask
;
60 if (base
->icr_data
& base
->icr_mask
)
61 amiga_custom
.intreq
= IF_SETCLR
| base
->int_mask
;
62 return old
& base
->icr_mask
;
66 * Enable or disable CIA interrupts, return old interrupt mask,
69 unsigned char cia_able_irq(struct ciabase
*base
, unsigned char mask
)
74 base
->icr_data
|= base
->cia
->icr
;
75 base
->cia
->icr
= mask
;
76 if (mask
& CIA_ICR_SETCLR
)
77 base
->icr_mask
|= mask
;
79 base
->icr_mask
&= ~mask
;
80 base
->icr_mask
&= CIA_ICR_ALL
;
81 if (base
->icr_data
& base
->icr_mask
)
82 amiga_custom
.intreq
= IF_SETCLR
| base
->int_mask
;
86 static irqreturn_t
cia_handler(int irq
, void *dev_id
)
88 struct ciabase
*base
= dev_id
;
93 /* Interrupts get disabled while the timer irq flag is cleared and
94 * the timer interrupt serviced.
96 mach_irq
= base
->cia_irq
;
97 local_irq_save(flags
);
98 ints
= cia_set_irq(base
, CIA_ICR_ALL
);
99 amiga_custom
.intreq
= base
->int_mask
;
101 generic_handle_irq(mach_irq
);
102 local_irq_restore(flags
);
103 mach_irq
++, ints
>>= 1;
104 for (; ints
; mach_irq
++, ints
>>= 1) {
106 generic_handle_irq(mach_irq
);
111 static void cia_irq_enable(struct irq_data
*data
)
113 unsigned int irq
= data
->irq
;
116 if (irq
>= IRQ_AMIGA_CIAB
) {
117 mask
= 1 << (irq
- IRQ_AMIGA_CIAB
);
118 cia_set_irq(&ciab_base
, mask
);
119 cia_able_irq(&ciab_base
, CIA_ICR_SETCLR
| mask
);
121 mask
= 1 << (irq
- IRQ_AMIGA_CIAA
);
122 cia_set_irq(&ciaa_base
, mask
);
123 cia_able_irq(&ciaa_base
, CIA_ICR_SETCLR
| mask
);
127 static void cia_irq_disable(struct irq_data
*data
)
129 unsigned int irq
= data
->irq
;
131 if (irq
>= IRQ_AMIGA_CIAB
)
132 cia_able_irq(&ciab_base
, 1 << (irq
- IRQ_AMIGA_CIAB
));
134 cia_able_irq(&ciaa_base
, 1 << (irq
- IRQ_AMIGA_CIAA
));
137 static struct irq_chip cia_irq_chip
= {
139 .irq_enable
= cia_irq_enable
,
140 .irq_disable
= cia_irq_disable
,
144 * Override auto irq 2 & 6 and use them as general chain
145 * for external interrupts, we link the CIA interrupt sources
149 static void auto_irq_enable(struct irq_data
*data
)
153 amiga_custom
.intena
= IF_SETCLR
| IF_PORTS
;
156 amiga_custom
.intena
= IF_SETCLR
| IF_EXTER
;
161 static void auto_irq_disable(struct irq_data
*data
)
165 amiga_custom
.intena
= IF_PORTS
;
168 amiga_custom
.intena
= IF_EXTER
;
173 static struct irq_chip auto_irq_chip
= {
175 .irq_enable
= auto_irq_enable
,
176 .irq_disable
= auto_irq_disable
,
179 void __init
cia_init_IRQ(struct ciabase
*base
)
181 m68k_setup_irq_controller(&cia_irq_chip
, handle_simple_irq
,
182 base
->cia_irq
, CIA_IRQS
);
184 /* clear any pending interrupt and turn off all interrupts */
185 cia_set_irq(base
, CIA_ICR_ALL
);
186 cia_able_irq(base
, CIA_ICR_ALL
);
188 /* override auto int and install CIA handler */
189 m68k_setup_irq_controller(&auto_irq_chip
, handle_simple_irq
,
190 base
->handler_irq
, 1);
191 m68k_irq_startup_irq(base
->handler_irq
);
192 if (request_irq(base
->handler_irq
, cia_handler
, IRQF_SHARED
,
194 pr_err("Couldn't register %s interrupt\n", base
->name
);