ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / sh / kernel / cpu / sh4 / irq_intc2.c
1 /*
2  * linux/arch/sh/kernel/irq_intc2.c
3  *
4  * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
5  *
6  * May be copied or modified under the terms of the GNU General Public
7  * License.  See linux/COPYING for more information.                            
8  *
9  * Interrupt handling for INTC2-based IRQ.
10  *
11  * These are the "new Hitachi style" interrupts, as present on the 
12  * Hitachi 7751 and the STM ST40 STB1.
13  */
14
15 #include <linux/kernel.h>
16 #include <linux/init.h>
17 #include <linux/irq.h>
18
19 #include <asm/system.h>
20 #include <asm/io.h>
21 #include <asm/machvec.h>
22
23
24 struct intc2_data {
25         unsigned int addr;      /* Address of Interrupt Priority Register */
26         int mask; /*Mask to apply */
27 };
28
29
30 static struct intc2_data intc2_data[NR_INTC2_IRQS];
31
32 static void enable_intc2_irq(unsigned int irq);
33 static void disable_intc2_irq(unsigned int irq);
34
35 /* shutdown is same as "disable" */
36 #define shutdown_intc2_irq disable_intc2_irq
37
38 static void mask_and_ack_intc2(unsigned int);
39 static void end_intc2_irq(unsigned int irq);
40
41 static unsigned int startup_intc2_irq(unsigned int irq)
42
43         enable_intc2_irq(irq);
44         return 0; /* never anything pending */
45 }
46
47 static struct hw_interrupt_type intc2_irq_type = {
48         "INTC2-IRQ",
49         startup_intc2_irq,
50         shutdown_intc2_irq,
51         enable_intc2_irq,
52         disable_intc2_irq,
53         mask_and_ack_intc2,
54         end_intc2_irq
55 };
56
57 static void disable_intc2_irq(unsigned int irq)
58 {
59         unsigned addr;
60         int offset=irq-INTC2_FIRST_IRQ;
61         unsigned val,flags;
62
63         // Sanity check
64         if(offset<0 || offset>=NR_INTC2_IRQS) return;
65
66         addr=intc2_data[offset].addr+INTC2_INTMSK_OFFSET;
67
68         local_irq_save(flags);
69         val=ctrl_inl(addr);
70         val|=intc2_data[offset].mask;
71         ctrl_outl(val,addr);
72
73         local_irq_restore(flags);
74 }
75
76 static void enable_intc2_irq(unsigned int irq)
77 {
78         int offset=irq-INTC2_FIRST_IRQ;
79
80         // Sanity check
81         if(offset<0 || offset>=NR_INTC2_IRQS) return;
82
83         ctrl_outl(intc2_data[offset].mask,
84                   intc2_data[offset].addr+INTC2_INTMSKCLR_OFFSET);
85
86 }
87
88 static void mask_and_ack_intc2(unsigned int irq)
89 {
90         disable_intc2_irq(irq);
91 }
92
93 static void end_intc2_irq(unsigned int irq)
94 {
95         if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
96                 enable_intc2_irq(irq);
97 }
98
99 void make_intc2_irq(unsigned int irq, unsigned int addr, 
100                     unsigned int group,int pos, int priority)
101 {
102         int offset=irq-INTC2_FIRST_IRQ;
103         unsigned flags,val;
104
105         if(offset<0 || offset>=NR_INTC2_IRQS) {
106                 return;
107         }
108
109         disable_irq_nosync(irq);
110         /* Fill the data we need */
111         intc2_data[offset].addr=addr;
112         intc2_data[offset].mask=1<<pos;
113                 
114         /* Set the priority level */
115         local_irq_save(flags);
116         val=ctrl_inl(addr+INTC2_INTPRI_OFFSET);
117         val|=(priority)<< (group<<4);
118         ctrl_outl(val,addr+INTC2_INTPRI_OFFSET);
119         local_irq_restore(flags);
120
121         irq_desc[irq].handler=&intc2_irq_type;
122
123         disable_intc2_irq(irq);
124 }
125
126
127