2 * Copyright (C) 2000 YAEGASHI Takeshi
3 * Hitachi HD64461 companion chip support
6 #include <linux/sched.h>
7 #include <linux/module.h>
8 #include <linux/kernel.h>
9 #include <linux/param.h>
10 #include <linux/interrupt.h>
11 #include <linux/init.h>
12 #include <linux/irq.h>
15 #include <asm/hd64461.h>
17 /* This belongs in cpu specific */
18 #define INTC_ICR1 0xA4140010UL
20 static void disable_hd64461_irq(unsigned int irq
)
23 unsigned short mask
= 1 << (irq
- HD64461_IRQBASE
);
25 nimr
= inw(HD64461_NIMR
);
27 outw(nimr
, HD64461_NIMR
);
30 static void enable_hd64461_irq(unsigned int irq
)
33 unsigned short mask
= 1 << (irq
- HD64461_IRQBASE
);
35 nimr
= inw(HD64461_NIMR
);
37 outw(nimr
, HD64461_NIMR
);
40 static void mask_and_ack_hd64461(unsigned int irq
)
42 disable_hd64461_irq(irq
);
43 #ifdef CONFIG_HD64461_ENABLER
44 if (irq
== HD64461_IRQBASE
+ 13)
45 outb(0x00, HD64461_PCC1CSCR
);
49 static void end_hd64461_irq(unsigned int irq
)
51 if (!(irq_desc
[irq
].status
& (IRQ_DISABLED
|IRQ_INPROGRESS
)))
52 enable_hd64461_irq(irq
);
55 static unsigned int startup_hd64461_irq(unsigned int irq
)
57 enable_hd64461_irq(irq
);
61 static void shutdown_hd64461_irq(unsigned int irq
)
63 disable_hd64461_irq(irq
);
66 static struct hw_interrupt_type hd64461_irq_type
= {
67 .typename
= "HD64461-IRQ",
68 .startup
= startup_hd64461_irq
,
69 .shutdown
= shutdown_hd64461_irq
,
70 .enable
= enable_hd64461_irq
,
71 .disable
= disable_hd64461_irq
,
72 .ack
= mask_and_ack_hd64461
,
73 .end
= end_hd64461_irq
,
76 static irqreturn_t
hd64461_interrupt(int irq
, void *dev_id
)
79 "HD64461: spurious interrupt, nirr: 0x%x nimr: 0x%x\n",
80 inw(HD64461_NIRR
), inw(HD64461_NIMR
));
86 int (*func
) (int, void *);
88 } hd64461_demux
[HD64461_IRQ_NUM
];
90 void hd64461_register_irq_demux(int irq
,
91 int (*demux
) (int irq
, void *dev
), void *dev
)
93 hd64461_demux
[irq
- HD64461_IRQBASE
].func
= demux
;
94 hd64461_demux
[irq
- HD64461_IRQBASE
].dev
= dev
;
97 EXPORT_SYMBOL(hd64461_register_irq_demux
);
99 void hd64461_unregister_irq_demux(int irq
)
101 hd64461_demux
[irq
- HD64461_IRQBASE
].func
= 0;
104 EXPORT_SYMBOL(hd64461_unregister_irq_demux
);
106 int hd64461_irq_demux(int irq
)
108 if (irq
== CONFIG_HD64461_IRQ
) {
110 unsigned short nirr
= inw(HD64461_NIRR
);
111 unsigned short nimr
= inw(HD64461_NIMR
);
115 for (bit
= 1, i
= 0; i
< 16; bit
<<= 1, i
++)
119 irq
= CONFIG_HD64461_IRQ
;
121 irq
= HD64461_IRQBASE
+ i
;
122 if (hd64461_demux
[i
].func
!= 0) {
123 irq
= hd64461_demux
[i
].func(irq
, hd64461_demux
[i
].dev
);
130 static struct irqaction irq0
= {
131 .handler
= hd64461_interrupt
,
132 .flags
= IRQF_DISABLED
,
133 .mask
= CPU_MASK_NONE
,
137 int __init
setup_hd64461(void)
145 "HD64461 configured at 0x%x on irq %d(mapped into %d to %d)\n",
146 CONFIG_HD64461_IOBASE
, CONFIG_HD64461_IRQ
, HD64461_IRQBASE
,
147 HD64461_IRQBASE
+ 15);
149 #if defined(CONFIG_CPU_SUBTYPE_SH7709) /* Should be at processor specific part.. */
150 outw(0x2240, INTC_ICR1
);
152 outw(0xffff, HD64461_NIMR
);
154 /* IRQ 80 -> 95 belongs to HD64461 */
155 for (i
= HD64461_IRQBASE
; i
< HD64461_IRQBASE
+ 16; i
++) {
156 irq_desc
[i
].chip
= &hd64461_irq_type
;
159 setup_irq(CONFIG_HD64461_IRQ
, &irq0
);
161 #ifdef CONFIG_HD64461_ENABLER
162 printk(KERN_INFO
"HD64461: enabling PCMCIA devices\n");
163 outb(0x4c, HD64461_PCC1CSCIER
);
164 outb(0x00, HD64461_PCC1CSCR
);
170 module_init(setup_hd64461
);