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:
6 * FRITZ!Card PCMCIA 2.0
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>
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
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
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)
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
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
;
63 readreg(struct IsdnCardState
*cs
, int offset
, u8 adr
)
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
);
76 writereg(struct IsdnCardState
*cs
, int offset
, u8 adr
, u8 value
)
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
);
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
);
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
);
101 isac_read(struct IsdnCardState
*cs
, u8 adr
)
103 return readreg(cs
, ISAC_REG_OFFSET
, adr
);
107 isac_write(struct IsdnCardState
*cs
, u8 adr
, u8 value
)
109 writereg(cs
, ISAC_REG_OFFSET
, adr
, value
);
113 isac_read_fifo(struct IsdnCardState
*cs
, u8
*data
, int size
)
115 readfifo(cs
, ISAC_FIFO_OFFSET
, data
, size
);
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
,
132 hscx_read(struct IsdnCardState
*cs
, int hscx
, u8 adr
)
134 return readreg(cs
, HSCX_REG_OFFSET
+ hscx
*HSCX_CH_DIFF
, adr
);
138 hscx_write(struct IsdnCardState
*cs
, int hscx
, u8 adr
, u8 value
)
140 writereg(cs
, HSCX_REG_OFFSET
+ hscx
*HSCX_CH_DIFF
, adr
, value
);
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
);
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
,
163 avm_a1p_interrupt(int intno
, void *dev_id
, struct pt_regs
*regs
)
165 struct IsdnCardState
*cs
= dev_id
;
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
);
175 hscx_int_main(cs
, val
);
177 if (sval
& ASL0_R_ISAC
) {
178 val
= isac_read(cs
, ISAC_ISTA
);
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
);
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
);
202 avm_a1p_reset(struct IsdnCardState
*cs
)
204 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,0x00);
206 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,ASL0_W_RESET
);
208 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,0x00);
213 static struct card_ops avm_a1p_ops
= {
214 .init
= avm_a1p_init
,
215 .reset
= avm_a1p_reset
,
216 .irq_func
= avm_a1p_interrupt
,
220 avm_a1p_probe(struct IsdnCardState
*cs
, struct IsdnCard
*card
)
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);
231 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,ASL0_W_RESET
);
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
))
248 hisax_release_resources(cs
);
253 setup_avm_a1_pcmcia(struct IsdnCard
*card
)
257 strcpy(tmp
, avm_revision
);
258 printk(KERN_INFO
"HiSax: AVM A1 PCMCIA driver Rev. %s\n",
260 if (avm_a1p_probe(card
->cs
, card
))