]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * $Id: setup.c,v 1.4 2003/08/03 03:05:10 lethal Exp $ | |
3 | * | |
4 | * Setup and IRQ handling code for the HD64465 companion chip. | |
5 | * by Greg Banks <gbanks@pocketpenguins.com> | |
6 | * Copyright (c) 2000 PocketPenguins Inc | |
7 | * | |
8 | * Derived from setup_hd64461.c which bore the message: | |
9 | * Copyright (C) 2000 YAEGASHI Takeshi | |
10 | */ | |
11 | ||
1da177e4 LT |
12 | #include <linux/sched.h> |
13 | #include <linux/module.h> | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/param.h> | |
16 | #include <linux/ioport.h> | |
17 | #include <linux/interrupt.h> | |
18 | #include <linux/init.h> | |
19 | #include <linux/irq.h> | |
1da177e4 LT |
20 | #include <asm/io.h> |
21 | #include <asm/irq.h> | |
1da177e4 LT |
22 | #include <asm/hd64465/hd64465.h> |
23 | ||
24 | static void disable_hd64465_irq(unsigned int irq) | |
25 | { | |
1da177e4 LT |
26 | unsigned short nimr; |
27 | unsigned short mask = 1 << (irq - HD64465_IRQ_BASE); | |
28 | ||
f99cb7a4 | 29 | pr_debug("disable_hd64465_irq(%d): mask=%x\n", irq, mask); |
1da177e4 LT |
30 | nimr = inw(HD64465_REG_NIMR); |
31 | nimr |= mask; | |
32 | outw(nimr, HD64465_REG_NIMR); | |
1da177e4 LT |
33 | } |
34 | ||
1da177e4 LT |
35 | static void enable_hd64465_irq(unsigned int irq) |
36 | { | |
1da177e4 LT |
37 | unsigned short nimr; |
38 | unsigned short mask = 1 << (irq - HD64465_IRQ_BASE); | |
39 | ||
f99cb7a4 | 40 | pr_debug("enable_hd64465_irq(%d): mask=%x\n", irq, mask); |
1da177e4 LT |
41 | nimr = inw(HD64465_REG_NIMR); |
42 | nimr &= ~mask; | |
43 | outw(nimr, HD64465_REG_NIMR); | |
1da177e4 LT |
44 | } |
45 | ||
1da177e4 LT |
46 | static void mask_and_ack_hd64465(unsigned int irq) |
47 | { | |
48 | disable_hd64465_irq(irq); | |
49 | } | |
50 | ||
1da177e4 LT |
51 | static void end_hd64465_irq(unsigned int irq) |
52 | { | |
53 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | |
54 | enable_hd64465_irq(irq); | |
55 | } | |
56 | ||
1da177e4 | 57 | static unsigned int startup_hd64465_irq(unsigned int irq) |
f99cb7a4 | 58 | { |
1da177e4 LT |
59 | enable_hd64465_irq(irq); |
60 | return 0; | |
61 | } | |
62 | ||
1da177e4 LT |
63 | static void shutdown_hd64465_irq(unsigned int irq) |
64 | { | |
65 | disable_hd64465_irq(irq); | |
66 | } | |
67 | ||
1da177e4 LT |
68 | static struct hw_interrupt_type hd64465_irq_type = { |
69 | .typename = "HD64465-IRQ", | |
70 | .startup = startup_hd64465_irq, | |
71 | .shutdown = shutdown_hd64465_irq, | |
72 | .enable = enable_hd64465_irq, | |
73 | .disable = disable_hd64465_irq, | |
74 | .ack = mask_and_ack_hd64465, | |
75 | .end = end_hd64465_irq, | |
76 | }; | |
77 | ||
35f3c518 | 78 | static irqreturn_t hd64465_interrupt(int irq, void *dev_id) |
1da177e4 LT |
79 | { |
80 | printk(KERN_INFO | |
81 | "HD64465: spurious interrupt, nirr: 0x%x nimr: 0x%x\n", | |
82 | inw(HD64465_REG_NIRR), inw(HD64465_REG_NIMR)); | |
83 | ||
84 | return IRQ_NONE; | |
85 | } | |
86 | ||
1da177e4 LT |
87 | /* |
88 | * Support for a secondary IRQ demux step. This is necessary | |
89 | * because the HD64465 presents a very thin interface to the | |
90 | * PCMCIA bus; a lot of features (such as remapping interrupts) | |
91 | * normally done in hardware by other PCMCIA host bridges is | |
92 | * instead done in software. | |
93 | */ | |
f99cb7a4 | 94 | static struct { |
1da177e4 LT |
95 | int (*func)(int, void *); |
96 | void *dev; | |
97 | } hd64465_demux[HD64465_IRQ_NUM]; | |
98 | ||
99 | void hd64465_register_irq_demux(int irq, | |
100 | int (*demux)(int irq, void *dev), void *dev) | |
101 | { | |
f99cb7a4 PM |
102 | hd64465_demux[irq - HD64465_IRQ_BASE].func = demux; |
103 | hd64465_demux[irq - HD64465_IRQ_BASE].dev = dev; | |
1da177e4 LT |
104 | } |
105 | EXPORT_SYMBOL(hd64465_register_irq_demux); | |
106 | ||
107 | void hd64465_unregister_irq_demux(int irq) | |
108 | { | |
f99cb7a4 | 109 | hd64465_demux[irq - HD64465_IRQ_BASE].func = 0; |
1da177e4 LT |
110 | } |
111 | EXPORT_SYMBOL(hd64465_unregister_irq_demux); | |
112 | ||
1da177e4 LT |
113 | int hd64465_irq_demux(int irq) |
114 | { | |
115 | if (irq == CONFIG_HD64465_IRQ) { | |
116 | unsigned short i, bit; | |
117 | unsigned short nirr = inw(HD64465_REG_NIRR); | |
118 | unsigned short nimr = inw(HD64465_REG_NIMR); | |
119 | ||
f99cb7a4 | 120 | pr_debug("hd64465_irq_demux, nirr=%04x, nimr=%04x\n", nirr, nimr); |
1da177e4 LT |
121 | nirr &= ~nimr; |
122 | for (bit = 1, i = 0 ; i < HD64465_IRQ_NUM ; bit <<= 1, i++) | |
123 | if (nirr & bit) | |
f99cb7a4 | 124 | break; |
1da177e4 | 125 | |
f99cb7a4 | 126 | if (i < HD64465_IRQ_NUM) { |
1da177e4 | 127 | irq = HD64465_IRQ_BASE + i; |
f99cb7a4 PM |
128 | if (hd64465_demux[i].func != 0) |
129 | irq = hd64465_demux[i].func(irq, hd64465_demux[i].dev); | |
1da177e4 LT |
130 | } |
131 | } | |
132 | return irq; | |
133 | } | |
134 | ||
e1fb4552 TG |
135 | static struct irqaction irq0 = { |
136 | .handler = hd64465_interrupt, | |
137 | .flags = IRQF_DISABLED, | |
138 | .mask = CPU_MASK_NONE, | |
139 | .name = "HD64465", | |
140 | }; | |
1da177e4 | 141 | |
1da177e4 LT |
142 | static int __init setup_hd64465(void) |
143 | { | |
144 | int i; | |
145 | unsigned short rev; | |
146 | unsigned short smscr; | |
147 | ||
148 | if (!MACH_HD64465) | |
149 | return 0; | |
150 | ||
151 | printk(KERN_INFO "HD64465 configured at 0x%x on irq %d(mapped into %d to %d)\n", | |
152 | CONFIG_HD64465_IOBASE, | |
153 | CONFIG_HD64465_IRQ, | |
154 | HD64465_IRQ_BASE, | |
155 | HD64465_IRQ_BASE+HD64465_IRQ_NUM-1); | |
156 | ||
157 | if (inw(HD64465_REG_SDID) != HD64465_SDID) { | |
158 | printk(KERN_ERR "HD64465 device ID not found, check base address\n"); | |
159 | } | |
160 | ||
161 | rev = inw(HD64465_REG_SRR); | |
162 | printk(KERN_INFO "HD64465 hardware revision %d.%d\n", (rev >> 8) & 0xff, rev & 0xff); | |
f99cb7a4 PM |
163 | |
164 | outw(0xffff, HD64465_REG_NIMR); /* mask all interrupts */ | |
1da177e4 LT |
165 | |
166 | for (i = 0; i < HD64465_IRQ_NUM ; i++) { | |
d1bef4ed | 167 | irq_desc[HD64465_IRQ_BASE + i].chip = &hd64465_irq_type; |
1da177e4 LT |
168 | } |
169 | ||
170 | setup_irq(CONFIG_HD64465_IRQ, &irq0); | |
171 | ||
1da177e4 LT |
172 | /* wake up the UART from STANDBY at this point */ |
173 | smscr = inw(HD64465_REG_SMSCR); | |
174 | outw(smscr & (~HD64465_SMSCR_UARTST), HD64465_REG_SMSCR); | |
175 | ||
176 | /* remap IO ports for first ISA serial port to HD64465 UART */ | |
177 | hd64465_port_map(0x3f8, 8, CONFIG_HD64465_IOBASE + 0x8000, 1); | |
1da177e4 LT |
178 | |
179 | return 0; | |
180 | } | |
1da177e4 | 181 | module_init(setup_hd64465); |