Hopefully get the Kconfig PCI stuff right, finally.
[linux-2.6/linux-mips.git] / drivers / isdn / hisax / avm_a1p.c
blob3636b73dd5c0b783d7fda8bf5321674e6a9c8753
1 /* $Id: avm_a1p.c,v 2.7.6.2 2001/09/23 22:24:46 kai Exp $
3 * low level stuff for the following AVM cards:
4 * A1 PCMCIA
5 * FRITZ!Card PCMCIA
6 * FRITZ!Card PCMCIA 2.0
8 * Author Carsten Paeth
9 * Copyright by Carsten Paeth <calle@calle.de>
11 * This software may be used and distributed according to the terms
12 * of the GNU General Public License, incorporated herein by reference.
16 #include <linux/init.h>
17 #include "hisax.h"
18 #include "isac.h"
19 #include "hscx.h"
20 #include "isdnl1.h"
22 /* register offsets */
23 #define ADDRREG_OFFSET 0x02
24 #define DATAREG_OFFSET 0x03
25 #define ASL0_OFFSET 0x04
26 #define ASL1_OFFSET 0x05
27 #define MODREG_OFFSET 0x06
28 #define VERREG_OFFSET 0x07
30 /* address offsets */
31 #define ISAC_FIFO_OFFSET 0x00
32 #define ISAC_REG_OFFSET 0x20
33 #define HSCX_CH_DIFF 0x40
34 #define HSCX_FIFO_OFFSET 0x80
35 #define HSCX_REG_OFFSET 0xa0
37 /* read bits ASL0 */
38 #define ASL0_R_TIMER 0x10 /* active low */
39 #define ASL0_R_ISAC 0x20 /* active low */
40 #define ASL0_R_HSCX 0x40 /* active low */
41 #define ASL0_R_TESTBIT 0x80
42 #define ASL0_R_IRQPENDING (ASL0_R_ISAC|ASL0_R_HSCX|ASL0_R_TIMER)
44 /* write bits ASL0 */
45 #define ASL0_W_RESET 0x01
46 #define ASL0_W_TDISABLE 0x02
47 #define ASL0_W_TRESET 0x04
48 #define ASL0_W_IRQENABLE 0x08
49 #define ASL0_W_TESTBIT 0x80
51 /* write bits ASL1 */
52 #define ASL1_W_LED0 0x10
53 #define ASL1_W_LED1 0x20
54 #define ASL1_W_ENABLE_S0 0xC0
56 #define byteout(addr,val) outb(val,addr)
57 #define bytein(addr) inb(addr)
59 static const char *avm_revision = "$Revision: 2.7.6.2 $";
60 static spinlock_t avm_a1p_lock = SPIN_LOCK_UNLOCKED;
62 static inline u8
63 readreg(struct IsdnCardState *cs, int offset, u8 adr)
65 unsigned long flags;
66 u8 ret;
68 spin_lock_irqsave(&avm_a1p_lock, flags);
69 byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, offset + adr - 0x20);
70 ret = bytein(cs->hw.avm.cfg_reg + DATAREG_OFFSET);
71 spin_unlock_irqrestore(&avm_a1p_lock, flags);
72 return ret;
75 static inline void
76 writereg(struct IsdnCardState *cs, int offset, u8 adr, u8 value)
78 unsigned long flags;
80 spin_lock_irqsave(&avm_a1p_lock, flags);
81 byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET, offset + adr - 0x20);
82 byteout(cs->hw.avm.cfg_reg+DATAREG_OFFSET, value);
83 spin_unlock_irqrestore(&avm_a1p_lock, flags);
86 static inline void
87 readfifo(struct IsdnCardState *cs, int offset, u8 *data, int size)
89 byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, offset);
90 insb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size);
93 static inline void
94 writefifo(struct IsdnCardState *cs, int offset, u8 *data, int size)
96 byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET, offset);
97 outsb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
100 static u8
101 isac_read(struct IsdnCardState *cs, u8 adr)
103 return readreg(cs, ISAC_REG_OFFSET, adr);
106 static void
107 isac_write(struct IsdnCardState *cs, u8 adr, u8 value)
109 writereg(cs, ISAC_REG_OFFSET, adr, value);
112 static void
113 isac_read_fifo(struct IsdnCardState *cs, u8 *data, int size)
115 readfifo(cs, ISAC_FIFO_OFFSET, data, size);
118 static void
119 isac_write_fifo(struct IsdnCardState *cs, u8 *data, int size)
121 writefifo(cs, ISAC_FIFO_OFFSET, data, size);
124 static struct dc_hw_ops isac_ops = {
125 .read_reg = isac_read,
126 .write_reg = isac_write,
127 .read_fifo = isac_read_fifo,
128 .write_fifo = isac_write_fifo,
131 static u8
132 hscx_read(struct IsdnCardState *cs, int hscx, u8 adr)
134 return readreg(cs, HSCX_REG_OFFSET + hscx*HSCX_CH_DIFF, adr);
137 static void
138 hscx_write(struct IsdnCardState *cs, int hscx, u8 adr, u8 value)
140 writereg(cs, HSCX_REG_OFFSET + hscx*HSCX_CH_DIFF, adr, value);
143 static void
144 hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
146 return readfifo(cs, HSCX_FIFO_OFFSET + hscx*HSCX_CH_DIFF, data, size);
149 static void
150 hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
152 writefifo(cs, HSCX_FIFO_OFFSET + hscx*HSCX_CH_DIFF, data, size);
155 static struct bc_hw_ops hscx_ops = {
156 .read_reg = hscx_read,
157 .write_reg = hscx_write,
158 .read_fifo = hscx_read_fifo,
159 .write_fifo = hscx_write_fifo,
162 static irqreturn_t
163 avm_a1p_interrupt(int intno, void *dev_id, struct pt_regs *regs)
165 struct IsdnCardState *cs = dev_id;
166 u8 val, sval;
168 spin_lock(&cs->lock);
169 while ((sval = (~bytein(cs->hw.avm.cfg_reg+ASL0_OFFSET) & ASL0_R_IRQPENDING))) {
170 if (cs->debug & L1_DEB_INTSTAT)
171 debugl1(cs, "avm IntStatus %x", sval);
172 if (sval & ASL0_R_HSCX) {
173 val = hscx_read(cs, 1, HSCX_ISTA);
174 if (val)
175 hscx_int_main(cs, val);
177 if (sval & ASL0_R_ISAC) {
178 val = isac_read(cs, ISAC_ISTA);
179 if (val)
180 isac_interrupt(cs, val);
183 hscx_write(cs, 0, HSCX_MASK, 0xFF);
184 hscx_write(cs, 1, HSCX_MASK, 0xFF);
185 isac_write(cs, ISAC_MASK, 0xFF);
186 isac_write(cs, ISAC_MASK, 0x0);
187 hscx_write(cs, 0, HSCX_MASK, 0x0);
188 hscx_write(cs, 1, HSCX_MASK, 0x0);
189 spin_unlock(&cs->lock);
190 return IRQ_HANDLED;
193 static void
194 avm_a1p_init(struct IsdnCardState *cs)
196 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,
197 ASL0_W_TDISABLE|ASL0_W_TRESET|ASL0_W_IRQENABLE);
198 inithscxisac(cs);
201 static int
202 avm_a1p_reset(struct IsdnCardState *cs)
204 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
205 HZDELAY(HZ / 5 + 1);
206 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET);
207 HZDELAY(HZ / 5 + 1);
208 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
210 return 0;
213 static struct card_ops avm_a1p_ops = {
214 .init = avm_a1p_init,
215 .reset = avm_a1p_reset,
216 .irq_func = avm_a1p_interrupt,
219 static int __init
220 avm_a1p_probe(struct IsdnCardState *cs, struct IsdnCard *card)
222 u8 model, vers;
224 cs->irq = card->para[0];
225 cs->hw.avm.cfg_reg = card->para[1];
227 outb(cs->hw.avm.cfg_reg+ASL1_OFFSET, ASL1_W_ENABLE_S0);
229 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
230 HZDELAY(HZ / 5 + 1);
231 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET);
232 HZDELAY(HZ / 5 + 1);
233 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
235 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET, ASL0_W_TDISABLE|ASL0_W_TRESET);
237 model = bytein(cs->hw.avm.cfg_reg+MODREG_OFFSET);
238 vers = bytein(cs->hw.avm.cfg_reg+VERREG_OFFSET);
240 printk(KERN_INFO "AVM A1 PCMCIA: io 0x%x irq %d model %d version %d\n",
241 cs->hw.avm.cfg_reg, cs->irq, model, vers);
243 cs->card_ops = &avm_a1p_ops;
244 if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
245 goto err;
246 return 0;
247 err:
248 hisax_release_resources(cs);
249 return -EBUSY;
252 int __devinit
253 setup_avm_a1_pcmcia(struct IsdnCard *card)
255 char tmp[64];
257 strcpy(tmp, avm_revision);
258 printk(KERN_INFO "HiSax: AVM A1 PCMCIA driver Rev. %s\n",
259 HiSax_getrev(tmp));
260 if (avm_a1p_probe(card->cs, card))
261 return 0;
262 return 1;