1 /* 2 * linux/arch/m68k/amiga/cia.c - CIA support 3 * 4 * Copyright (C) 1996 Roman Zippel 5 * 6 * The concept of some functions bases on the original Amiga OS function 7 * 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 10 * for more details. 11 */ 12 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 22 #include <asm/irq.h> 23 #include <asm/amigahw.h> 24 #include <asm/amigaints.h> 25 26 struct ciabase { 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; 31 char *name; 32 } ciaa_base = { 33 .cia = &ciaa, 34 .int_mask = IF_PORTS, 35 .handler_irq = IRQ_AMIGA_PORTS, 36 .cia_irq = IRQ_AMIGA_CIAA, 37 .name = "CIAA" 38 }, ciab_base = { 39 .cia = &ciab, 40 .int_mask = IF_EXTER, 41 .handler_irq = IRQ_AMIGA_EXTER, 42 .cia_irq = IRQ_AMIGA_CIAB, 43 .name = "CIAB" 44 }; 45 46 /* 47 * Cause or clear CIA interrupts, return old interrupt status. 48 */ 49 50 unsigned char cia_set_irq(struct ciabase *base, unsigned char mask) 51 { 52 unsigned char old; 53 54 old = (base->icr_data |= base->cia->icr); 55 if (mask & CIA_ICR_SETCLR) 56 base->icr_data |= mask; 57 else 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; 62 } 63 64 /* 65 * Enable or disable CIA interrupts, return old interrupt mask, 66 */ 67 68 unsigned char cia_able_irq(struct ciabase *base, unsigned char mask) 69 { 70 unsigned char old; 71 72 old = base->icr_mask; 73 base->icr_data |= base->cia->icr; 74 base->cia->icr = mask; 75 if (mask & CIA_ICR_SETCLR) 76 base->icr_mask |= mask; 77 else 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; 82 return old; 83 } 84 85 static irqreturn_t cia_handler(int irq, void *dev_id) 86 { 87 struct ciabase *base = dev_id; 88 int mach_irq; 89 unsigned char ints; 90 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) { 95 if (ints & 1) 96 m68k_handle_int(mach_irq); 97 } 98 return IRQ_HANDLED; 99 } 100 101 static void cia_enable_irq(unsigned int irq) 102 { 103 unsigned char mask; 104 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); 109 } else { 110 mask = 1 << (irq - IRQ_AMIGA_CIAA); 111 cia_set_irq(&ciaa_base, mask); 112 cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | mask); 113 } 114 } 115 116 static void cia_disable_irq(unsigned int irq) 117 { 118 if (irq >= IRQ_AMIGA_CIAB) 119 cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB)); 120 else 121 cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA)); 122 } 123 124 static struct irq_controller cia_irq_controller = { 125 .name = "cia", 126 .lock = __SPIN_LOCK_UNLOCKED(cia_irq_controller.lock), 127 .enable = cia_enable_irq, 128 .disable = cia_disable_irq, 129 }; 130 131 /* 132 * Override auto irq 2 & 6 and use them as general chain 133 * for external interrupts, we link the CIA interrupt sources 134 * into this chain. 135 */ 136 137 static void auto_enable_irq(unsigned int irq) 138 { 139 switch (irq) { 140 case IRQ_AUTO_2: 141 amiga_custom.intena = IF_SETCLR | IF_PORTS; 142 break; 143 case IRQ_AUTO_6: 144 amiga_custom.intena = IF_SETCLR | IF_EXTER; 145 break; 146 } 147 } 148 149 static void auto_disable_irq(unsigned int irq) 150 { 151 switch (irq) { 152 case IRQ_AUTO_2: 153 amiga_custom.intena = IF_PORTS; 154 break; 155 case IRQ_AUTO_6: 156 amiga_custom.intena = IF_EXTER; 157 break; 158 } 159 } 160 161 static struct irq_controller auto_irq_controller = { 162 .name = "auto", 163 .lock = __SPIN_LOCK_UNLOCKED(auto_irq_controller.lock), 164 .enable = auto_enable_irq, 165 .disable = auto_disable_irq, 166 }; 167 168 void __init cia_init_IRQ(struct ciabase *base) 169 { 170 m68k_setup_irq_controller(&cia_irq_controller, base->cia_irq, CIA_IRQS); 171 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); 175 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 request_irq(base->handler_irq, cia_handler, IRQF_SHARED, base->name, base); 180 } 181