1 /* $Id: avm_a1p.c,v 2.9.2.5 2004/01/24 20:47:19 keil 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.9.2.5 $";
62 ReadISAC(struct IsdnCardState
*cs
, u_char offset
)
67 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,ISAC_REG_OFFSET
+offset
);
68 ret
= bytein(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
);
73 WriteISAC(struct IsdnCardState
*cs
, u_char offset
, u_char value
)
76 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,ISAC_REG_OFFSET
+offset
);
77 byteout(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
, value
);
81 ReadISACfifo(struct IsdnCardState
*cs
, u_char
* data
, int size
)
83 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,ISAC_FIFO_OFFSET
);
84 insb(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
, data
, size
);
88 WriteISACfifo(struct IsdnCardState
*cs
, u_char
* data
, int size
)
90 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,ISAC_FIFO_OFFSET
);
91 outsb(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
, data
, size
);
95 ReadHSCX(struct IsdnCardState
*cs
, int hscx
, u_char offset
)
100 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,
101 HSCX_REG_OFFSET
+hscx
*HSCX_CH_DIFF
+offset
);
102 ret
= bytein(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
);
107 WriteHSCX(struct IsdnCardState
*cs
, int hscx
, u_char offset
, u_char value
)
110 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,
111 HSCX_REG_OFFSET
+hscx
*HSCX_CH_DIFF
+offset
);
112 byteout(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
, value
);
116 ReadHSCXfifo(struct IsdnCardState
*cs
, int hscx
, u_char
* data
, int size
)
118 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,
119 HSCX_FIFO_OFFSET
+hscx
*HSCX_CH_DIFF
);
120 insb(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
, data
, size
);
124 WriteHSCXfifo(struct IsdnCardState
*cs
, int hscx
, u_char
* data
, int size
)
126 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,
127 HSCX_FIFO_OFFSET
+hscx
*HSCX_CH_DIFF
);
128 outsb(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
, data
, size
);
132 * fast interrupt HSCX stuff goes here
135 #define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg)
136 #define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data)
137 #define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt)
138 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt)
140 #include "hscx_irq.c"
143 avm_a1p_interrupt(int intno
, void *dev_id
)
145 struct IsdnCardState
*cs
= dev_id
;
149 spin_lock_irqsave(&cs
->lock
, flags
);
150 while ((sval
= (~bytein(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
) & ASL0_R_IRQPENDING
))) {
151 if (cs
->debug
& L1_DEB_INTSTAT
)
152 debugl1(cs
, "avm IntStatus %x", sval
);
153 if (sval
& ASL0_R_HSCX
) {
154 val
= ReadHSCX(cs
, 1, HSCX_ISTA
);
156 hscx_int_main(cs
, val
);
158 if (sval
& ASL0_R_ISAC
) {
159 val
= ReadISAC(cs
, ISAC_ISTA
);
161 isac_interrupt(cs
, val
);
164 WriteHSCX(cs
, 0, HSCX_MASK
, 0xff);
165 WriteHSCX(cs
, 1, HSCX_MASK
, 0xff);
166 WriteISAC(cs
, ISAC_MASK
, 0xff);
167 WriteISAC(cs
, ISAC_MASK
, 0x00);
168 WriteHSCX(cs
, 0, HSCX_MASK
, 0x00);
169 WriteHSCX(cs
, 1, HSCX_MASK
, 0x00);
170 spin_unlock_irqrestore(&cs
->lock
, flags
);
175 AVM_card_msg(struct IsdnCardState
*cs
, int mt
, void *arg
)
181 spin_lock_irqsave(&cs
->lock
, flags
);
182 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,0x00);
184 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,ASL0_W_RESET
);
186 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,0x00);
187 spin_unlock_irqrestore(&cs
->lock
, flags
);
191 /* free_irq is done in HiSax_closecard(). */
192 /* free_irq(cs->irq, cs); */
196 spin_lock_irqsave(&cs
->lock
, flags
);
197 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,ASL0_W_TDISABLE
|ASL0_W_TRESET
|ASL0_W_IRQENABLE
);
198 clear_pending_isac_ints(cs
);
199 clear_pending_hscx_ints(cs
);
202 spin_unlock_irqrestore(&cs
->lock
, flags
);
206 /* we really don't need it for the PCMCIA Version */
210 /* all card drivers ignore others, so we do the same */
217 setup_avm_a1_pcmcia(struct IsdnCard
*card
)
220 struct IsdnCardState
*cs
= card
->cs
;
224 strcpy(tmp
, avm_revision
);
225 printk(KERN_INFO
"HiSax: AVM A1 PCMCIA driver Rev. %s\n",
227 if (cs
->typ
!= ISDN_CTYPE_A1_PCMCIA
)
230 cs
->hw
.avm
.cfg_reg
= card
->para
[1];
231 cs
->irq
= card
->para
[0];
234 byteout(cs
->hw
.avm
.cfg_reg
+ASL1_OFFSET
, ASL1_W_ENABLE_S0
);
235 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,0x00);
237 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,ASL0_W_RESET
);
239 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,0x00);
241 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
, ASL0_W_TDISABLE
|ASL0_W_TRESET
);
243 model
= bytein(cs
->hw
.avm
.cfg_reg
+MODREG_OFFSET
);
244 vers
= bytein(cs
->hw
.avm
.cfg_reg
+VERREG_OFFSET
);
246 printk(KERN_INFO
"AVM A1 PCMCIA: io 0x%x irq %d model %d version %d\n",
247 cs
->hw
.avm
.cfg_reg
, cs
->irq
, model
, vers
);
250 cs
->readisac
= &ReadISAC
;
251 cs
->writeisac
= &WriteISAC
;
252 cs
->readisacfifo
= &ReadISACfifo
;
253 cs
->writeisacfifo
= &WriteISACfifo
;
254 cs
->BC_Read_Reg
= &ReadHSCX
;
255 cs
->BC_Write_Reg
= &WriteHSCX
;
256 cs
->BC_Send_Data
= &hscx_fill_fifo
;
257 cs
->cardmsg
= &AVM_card_msg
;
258 cs
->irq_flags
= IRQF_SHARED
;
259 cs
->irq_func
= &avm_a1p_interrupt
;
261 ISACVersion(cs
, "AVM A1 PCMCIA:");
262 if (HscxVersion(cs
, "AVM A1 PCMCIA:")) {
264 "AVM A1 PCMCIA: wrong HSCX versions check IO address\n");