Pull sn2-mmio-writes into release branch
[linux-2.6] / drivers / isdn / hisax / teles0.c
1 /* $Id: teles0.c,v 2.15.2.4 2004/01/13 23:48:39 keil Exp $
2  *
3  * low level stuff for Teles Memory IO isdn cards
4  *
5  * Author       Karsten Keil
6  *              based on the teles driver from Jan den Ouden
7  * Copyright    by Karsten Keil      <keil@isdn4linux.de>
8  * 
9  * This software may be used and distributed according to the terms
10  * of the GNU General Public License, incorporated herein by reference.
11  *
12  * Thanks to    Jan den Ouden
13  *              Fritz Elfert
14  *              Beat Doebeli
15  *
16  */
17
18 #include <linux/init.h>
19 #include "hisax.h"
20 #include "isdnl1.h"
21 #include "isac.h"
22 #include "hscx.h"
23
24 extern const char *CardType[];
25
26 static const char *teles0_revision = "$Revision: 2.15.2.4 $";
27
28 #define TELES_IOMEM_SIZE        0x400
29 #define byteout(addr,val) outb(val,addr)
30 #define bytein(addr) inb(addr)
31
32 static inline u_char
33 readisac(void __iomem *adr, u_char off)
34 {
35         return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off);
36 }
37
38 static inline void
39 writeisac(void __iomem *adr, u_char off, u_char data)
40 {
41         writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb();
42 }
43
44
45 static inline u_char
46 readhscx(void __iomem *adr, int hscx, u_char off)
47 {
48         return readb(adr + (hscx ? 0x1c0 : 0x180) +
49                      ((off & 1) ? 0x1ff : 0) + off);
50 }
51
52 static inline void
53 writehscx(void __iomem *adr, int hscx, u_char off, u_char data)
54 {
55         writeb(data, adr + (hscx ? 0x1c0 : 0x180) +
56                ((off & 1) ? 0x1ff : 0) + off); mb();
57 }
58
59 static inline void
60 read_fifo_isac(void __iomem *adr, u_char * data, int size)
61 {
62         register int i;
63         register u_char __iomem *ad = adr + 0x100;
64         for (i = 0; i < size; i++)
65                 data[i] = readb(ad);
66 }
67
68 static inline void
69 write_fifo_isac(void __iomem *adr, u_char * data, int size)
70 {
71         register int i;
72         register u_char __iomem *ad = adr + 0x100;
73         for (i = 0; i < size; i++) {
74                 writeb(data[i], ad); mb();
75         }
76 }
77
78 static inline void
79 read_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size)
80 {
81         register int i;
82         register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180);
83         for (i = 0; i < size; i++)
84                 data[i] = readb(ad);
85 }
86
87 static inline void
88 write_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size)
89 {
90         int i;
91         register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180);
92         for (i = 0; i < size; i++) {
93                 writeb(data[i], ad); mb();
94         }
95 }
96
97 /* Interface functions */
98
99 static u_char
100 ReadISAC(struct IsdnCardState *cs, u_char offset)
101 {
102         return (readisac(cs->hw.teles0.membase, offset));
103 }
104
105 static void
106 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
107 {
108         writeisac(cs->hw.teles0.membase, offset, value);
109 }
110
111 static void
112 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
113 {
114         read_fifo_isac(cs->hw.teles0.membase, data, size);
115 }
116
117 static void
118 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
119 {
120         write_fifo_isac(cs->hw.teles0.membase, data, size);
121 }
122
123 static u_char
124 ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
125 {
126         return (readhscx(cs->hw.teles0.membase, hscx, offset));
127 }
128
129 static void
130 WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
131 {
132         writehscx(cs->hw.teles0.membase, hscx, offset, value);
133 }
134
135 /*
136  * fast interrupt HSCX stuff goes here
137  */
138
139 #define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg)
140 #define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data)
141 #define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
142 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
143
144 #include "hscx_irq.c"
145
146 static irqreturn_t
147 teles0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
148 {
149         struct IsdnCardState *cs = dev_id;
150         u_char val;
151         u_long flags;
152         int count = 0;
153
154         spin_lock_irqsave(&cs->lock, flags);
155         val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
156       Start_HSCX:
157         if (val)
158                 hscx_int_main(cs, val);
159         val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
160       Start_ISAC:
161         if (val)
162                 isac_interrupt(cs, val);
163         count++;
164         val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
165         if (val && count < 5) {
166                 if (cs->debug & L1_DEB_HSCX)
167                         debugl1(cs, "HSCX IntStat after IntRoutine");
168                 goto Start_HSCX;
169         }
170         val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
171         if (val && count < 5) {
172                 if (cs->debug & L1_DEB_ISAC)
173                         debugl1(cs, "ISAC IntStat after IntRoutine");
174                 goto Start_ISAC;
175         }
176         writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF);
177         writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF);
178         writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
179         writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
180         writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0);
181         writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0);
182         spin_unlock_irqrestore(&cs->lock, flags);
183         return IRQ_HANDLED;
184 }
185
186 static void
187 release_io_teles0(struct IsdnCardState *cs)
188 {
189         if (cs->hw.teles0.cfg_reg)
190                 release_region(cs->hw.teles0.cfg_reg, 8);
191         iounmap(cs->hw.teles0.membase);
192         release_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
193 }
194
195 static int
196 reset_teles0(struct IsdnCardState *cs)
197 {
198         u_char cfval;
199
200         if (cs->hw.teles0.cfg_reg) {
201                 switch (cs->irq) {
202                         case 2:
203                         case 9:
204                                 cfval = 0x00;
205                                 break;
206                         case 3:
207                                 cfval = 0x02;
208                                 break;
209                         case 4:
210                                 cfval = 0x04;
211                                 break;
212                         case 5:
213                                 cfval = 0x06;
214                                 break;
215                         case 10:
216                                 cfval = 0x08;
217                                 break;
218                         case 11:
219                                 cfval = 0x0A;
220                                 break;
221                         case 12:
222                                 cfval = 0x0C;
223                                 break;
224                         case 15:
225                                 cfval = 0x0E;
226                                 break;
227                         default:
228                                 return(1);
229                 }
230                 cfval |= ((cs->hw.teles0.phymem >> 9) & 0xF0);
231                 byteout(cs->hw.teles0.cfg_reg + 4, cfval);
232                 HZDELAY(HZ / 10 + 1);
233                 byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1);
234                 HZDELAY(HZ / 10 + 1);
235         }
236         writeb(0, cs->hw.teles0.membase + 0x80); mb();
237         HZDELAY(HZ / 5 + 1);
238         writeb(1, cs->hw.teles0.membase + 0x80); mb();
239         HZDELAY(HZ / 5 + 1);
240         return(0);
241 }
242
243 static int
244 Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
245 {
246         u_long flags;
247
248         switch (mt) {
249                 case CARD_RESET:
250                         spin_lock_irqsave(&cs->lock, flags);
251                         reset_teles0(cs);
252                         spin_unlock_irqrestore(&cs->lock, flags);
253                         return(0);
254                 case CARD_RELEASE:
255                         release_io_teles0(cs);
256                         return(0);
257                 case CARD_INIT:
258                         spin_lock_irqsave(&cs->lock, flags);
259                         inithscxisac(cs, 3);
260                         spin_unlock_irqrestore(&cs->lock, flags);
261                         return(0);
262                 case CARD_TEST:
263                         return(0);
264         }
265         return(0);
266 }
267
268 int __init
269 setup_teles0(struct IsdnCard *card)
270 {
271         u_char val;
272         struct IsdnCardState *cs = card->cs;
273         char tmp[64];
274
275         strcpy(tmp, teles0_revision);
276         printk(KERN_INFO "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp));
277         if ((cs->typ != ISDN_CTYPE_16_0) && (cs->typ != ISDN_CTYPE_8_0))
278                 return (0);
279
280         if (cs->typ == ISDN_CTYPE_16_0)
281                 cs->hw.teles0.cfg_reg = card->para[2];
282         else                    /* 8.0 */
283                 cs->hw.teles0.cfg_reg = 0;
284
285         if (card->para[1] < 0x10000) {
286                 card->para[1] <<= 4;
287                 printk(KERN_INFO
288                    "Teles0: membase configured DOSish, assuming 0x%lx\n",
289                        (unsigned long) card->para[1]);
290         }
291         cs->irq = card->para[0];
292         if (cs->hw.teles0.cfg_reg) {
293                 if (!request_region(cs->hw.teles0.cfg_reg, 8, "teles cfg")) {
294                         printk(KERN_WARNING
295                           "HiSax: %s config port %x-%x already in use\n",
296                                CardType[card->typ],
297                                cs->hw.teles0.cfg_reg,
298                                cs->hw.teles0.cfg_reg + 8);
299                         return (0);
300                 }
301         }
302         if (cs->hw.teles0.cfg_reg) {
303                 if ((val = bytein(cs->hw.teles0.cfg_reg + 0)) != 0x51) {
304                         printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
305                                cs->hw.teles0.cfg_reg + 0, val);
306                         release_region(cs->hw.teles0.cfg_reg, 8);
307                         return (0);
308                 }
309                 if ((val = bytein(cs->hw.teles0.cfg_reg + 1)) != 0x93) {
310                         printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
311                                cs->hw.teles0.cfg_reg + 1, val);
312                         release_region(cs->hw.teles0.cfg_reg, 8);
313                         return (0);
314                 }
315                 val = bytein(cs->hw.teles0.cfg_reg + 2);        /* 0x1e=without AB
316                                                                    * 0x1f=with AB
317                                                                    * 0x1c 16.3 ???
318                                                                  */
319                 if (val != 0x1e && val != 0x1f) {
320                         printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
321                                cs->hw.teles0.cfg_reg + 2, val);
322                         release_region(cs->hw.teles0.cfg_reg, 8);
323                         return (0);
324                 }
325         }
326         /* 16.0 and 8.0 designed for IOM1 */
327         test_and_set_bit(HW_IOM1, &cs->HW_Flags);
328         cs->hw.teles0.phymem = card->para[1];
329         if (!request_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE, "teles iomem")) {
330                 printk(KERN_WARNING
331                         "HiSax: %s memory region %lx-%lx already in use\n",
332                         CardType[card->typ],
333                         cs->hw.teles0.phymem,
334                         cs->hw.teles0.phymem + TELES_IOMEM_SIZE);
335                 if (cs->hw.teles0.cfg_reg)
336                         release_region(cs->hw.teles0.cfg_reg, 8);
337                 return (0);
338         }
339         cs->hw.teles0.membase = ioremap(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
340         printk(KERN_INFO
341                "HiSax: %s config irq:%d mem:%p cfg:0x%X\n",
342                CardType[cs->typ], cs->irq,
343                cs->hw.teles0.membase, cs->hw.teles0.cfg_reg);
344         if (reset_teles0(cs)) {
345                 printk(KERN_WARNING "Teles0: wrong IRQ\n");
346                 release_io_teles0(cs);
347                 return (0);
348         }
349         setup_isac(cs);
350         cs->readisac = &ReadISAC;
351         cs->writeisac = &WriteISAC;
352         cs->readisacfifo = &ReadISACfifo;
353         cs->writeisacfifo = &WriteISACfifo;
354         cs->BC_Read_Reg = &ReadHSCX;
355         cs->BC_Write_Reg = &WriteHSCX;
356         cs->BC_Send_Data = &hscx_fill_fifo;
357         cs->cardmsg = &Teles_card_msg;
358         cs->irq_func = &teles0_interrupt;
359         ISACVersion(cs, "Teles0:");
360         if (HscxVersion(cs, "Teles0:")) {
361                 printk(KERN_WARNING
362                  "Teles0: wrong HSCX versions check IO/MEM addresses\n");
363                 release_io_teles0(cs);
364                 return (0);
365         }
366         return (1);
367 }