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
;
92 mach_irq
= base
->cia_irq
;
93 ints
= cia_set_irq(base
, CIA_ICR_ALL
);
94 amiga_custom
.intreq
= base
->int_mask
;
95 for (; ints
; mach_irq
++, ints
>>= 1) {
97 generic_handle_irq(mach_irq
);
102 static void cia_irq_enable(struct irq_data
*data
)
104 unsigned int irq
= data
->irq
;
107 if (irq
>= IRQ_AMIGA_CIAB
) {
108 mask
= 1 << (irq
- IRQ_AMIGA_CIAB
);
109 cia_set_irq(&ciab_base
, mask
);
110 cia_able_irq(&ciab_base
, CIA_ICR_SETCLR
| mask
);
112 mask
= 1 << (irq
- IRQ_AMIGA_CIAA
);
113 cia_set_irq(&ciaa_base
, mask
);
114 cia_able_irq(&ciaa_base
, CIA_ICR_SETCLR
| mask
);
118 static void cia_irq_disable(struct irq_data
*data
)
120 unsigned int irq
= data
->irq
;
122 if (irq
>= IRQ_AMIGA_CIAB
)
123 cia_able_irq(&ciab_base
, 1 << (irq
- IRQ_AMIGA_CIAB
));
125 cia_able_irq(&ciaa_base
, 1 << (irq
- IRQ_AMIGA_CIAA
));
128 static struct irq_chip cia_irq_chip
= {
130 .irq_enable
= cia_irq_enable
,
131 .irq_disable
= cia_irq_disable
,
135 * Override auto irq 2 & 6 and use them as general chain
136 * for external interrupts, we link the CIA interrupt sources
140 static void auto_irq_enable(struct irq_data
*data
)
144 amiga_custom
.intena
= IF_SETCLR
| IF_PORTS
;
147 amiga_custom
.intena
= IF_SETCLR
| IF_EXTER
;
152 static void auto_irq_disable(struct irq_data
*data
)
156 amiga_custom
.intena
= IF_PORTS
;
159 amiga_custom
.intena
= IF_EXTER
;
164 static struct irq_chip auto_irq_chip
= {
166 .irq_enable
= auto_irq_enable
,
167 .irq_disable
= auto_irq_disable
,
170 void __init
cia_init_IRQ(struct ciabase
*base
)
172 m68k_setup_irq_controller(&cia_irq_chip
, handle_simple_irq
,
173 base
->cia_irq
, CIA_IRQS
);
175 /* clear any pending interrupt and turn off all interrupts */
176 cia_set_irq(base
, CIA_ICR_ALL
);
177 cia_able_irq(base
, CIA_ICR_ALL
);
179 /* override auto int and install CIA handler */
180 m68k_setup_irq_controller(&auto_irq_chip
, handle_simple_irq
,
181 base
->handler_irq
, 1);
182 m68k_irq_startup_irq(base
->handler_irq
);
183 if (request_irq(base
->handler_irq
, cia_handler
, IRQF_SHARED
,
185 pr_err("Couldn't register %s interrupt\n", base
->name
);