• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500-V1.0.1.40_1.0.68/src/linux/linux-2.6/arch/sh/cchips/hd6446x/hd64461/
1/*
2 *	$Id: setup.c,v 1.1.1.1 2007/08/03 18:52:15 Exp $
3 *	Copyright (C) 2000 YAEGASHI Takeshi
4 *	Hitachi HD64461 companion chip support
5 */
6
7#include <linux/sched.h>
8#include <linux/module.h>
9#include <linux/kernel.h>
10#include <linux/param.h>
11#include <linux/interrupt.h>
12#include <linux/init.h>
13#include <linux/irq.h>
14#include <asm/io.h>
15#include <asm/irq.h>
16#include <asm/hd64461.h>
17
18static void disable_hd64461_irq(unsigned int irq)
19{
20	unsigned short nimr;
21	unsigned short mask = 1 << (irq - HD64461_IRQBASE);
22
23	nimr = inw(HD64461_NIMR);
24	nimr |= mask;
25	outw(nimr, HD64461_NIMR);
26}
27
28static void enable_hd64461_irq(unsigned int irq)
29{
30	unsigned short nimr;
31	unsigned short mask = 1 << (irq - HD64461_IRQBASE);
32
33	nimr = inw(HD64461_NIMR);
34	nimr &= ~mask;
35	outw(nimr, HD64461_NIMR);
36}
37
38static void mask_and_ack_hd64461(unsigned int irq)
39{
40	disable_hd64461_irq(irq);
41#ifdef CONFIG_HD64461_ENABLER
42	if (irq == HD64461_IRQBASE + 13)
43		outb(0x00, HD64461_PCC1CSCR);
44#endif
45}
46
47static void end_hd64461_irq(unsigned int irq)
48{
49	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
50		enable_hd64461_irq(irq);
51}
52
53static unsigned int startup_hd64461_irq(unsigned int irq)
54{
55	enable_hd64461_irq(irq);
56	return 0;
57}
58
59static void shutdown_hd64461_irq(unsigned int irq)
60{
61	disable_hd64461_irq(irq);
62}
63
64static struct hw_interrupt_type hd64461_irq_type = {
65	.typename	= "HD64461-IRQ",
66	.startup	= startup_hd64461_irq,
67	.shutdown	= shutdown_hd64461_irq,
68	.enable		= enable_hd64461_irq,
69	.disable	= disable_hd64461_irq,
70	.ack		= mask_and_ack_hd64461,
71	.end		= end_hd64461_irq,
72};
73
74static irqreturn_t hd64461_interrupt(int irq, void *dev_id)
75{
76	printk(KERN_INFO
77	       "HD64461: spurious interrupt, nirr: 0x%x nimr: 0x%x\n",
78	       inw(HD64461_NIRR), inw(HD64461_NIMR));
79
80	return IRQ_NONE;
81}
82
83static struct {
84	int (*func) (int, void *);
85	void *dev;
86} hd64461_demux[HD64461_IRQ_NUM];
87
88void hd64461_register_irq_demux(int irq,
89				int (*demux) (int irq, void *dev), void *dev)
90{
91	hd64461_demux[irq - HD64461_IRQBASE].func = demux;
92	hd64461_demux[irq - HD64461_IRQBASE].dev = dev;
93}
94
95EXPORT_SYMBOL(hd64461_register_irq_demux);
96
97void hd64461_unregister_irq_demux(int irq)
98{
99	hd64461_demux[irq - HD64461_IRQBASE].func = 0;
100}
101
102EXPORT_SYMBOL(hd64461_unregister_irq_demux);
103
104int hd64461_irq_demux(int irq)
105{
106	if (irq == CONFIG_HD64461_IRQ) {
107		unsigned short bit;
108		unsigned short nirr = inw(HD64461_NIRR);
109		unsigned short nimr = inw(HD64461_NIMR);
110		int i;
111
112		nirr &= ~nimr;
113		for (bit = 1, i = 0; i < 16; bit <<= 1, i++)
114			if (nirr & bit)
115				break;
116		if (i == 16)
117			irq = CONFIG_HD64461_IRQ;
118		else {
119			irq = HD64461_IRQBASE + i;
120			if (hd64461_demux[i].func != 0) {
121				irq = hd64461_demux[i].func(irq, hd64461_demux[i].dev);
122			}
123		}
124	}
125	return __irq_demux(irq);
126}
127
128static struct irqaction irq0 = { hd64461_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "HD64461", NULL, NULL };
129
130int __init setup_hd64461(void)
131{
132	int i;
133
134	if (!MACH_HD64461)
135		return 0;
136
137	printk(KERN_INFO
138	       "HD64461 configured at 0x%x on irq %d(mapped into %d to %d)\n",
139	       CONFIG_HD64461_IOBASE, CONFIG_HD64461_IRQ, HD64461_IRQBASE,
140	       HD64461_IRQBASE + 15);
141
142#if defined(CONFIG_CPU_SUBTYPE_SH7709)	    /* Should be at processor specific part.. */
143	outw(0x2240, INTC_ICR1);
144#endif
145	outw(0xffff, HD64461_NIMR);
146
147	for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++) {
148		irq_desc[i].chip = &hd64461_irq_type;
149	}
150
151	setup_irq(CONFIG_HD64461_IRQ, &irq0);
152
153#ifdef CONFIG_HD64461_ENABLER
154	printk(KERN_INFO "HD64461: enabling PCMCIA devices\n");
155	outb(0x4c, HD64461_PCC1CSCIER);
156	outb(0x00, HD64461_PCC1CSCR);
157#endif
158
159	return 0;
160}
161
162module_init(setup_hd64461);
163