[PATCH] USB: lh7a40x gadget driver: Fixed a dead lock
[linux-2.6] / drivers / isdn / hisax / telespci.c
1 /* $Id: telespci.c,v 2.23.2.3 2004/01/13 14:31:26 keil Exp $
2  *
3  * low level stuff for Teles PCI isdn cards
4  *
5  * Author       Ton van Rosmalen
6  *              Karsten Keil
7  * Copyright    by Ton van Rosmalen
8  *              by Karsten Keil      <keil@isdn4linux.de>
9  * 
10  * This software may be used and distributed according to the terms
11  * of the GNU General Public License, incorporated herein by reference.
12  *
13  */
14
15 #include <linux/init.h>
16 #include <linux/config.h>
17 #include "hisax.h"
18 #include "isac.h"
19 #include "hscx.h"
20 #include "isdnl1.h"
21 #include <linux/pci.h>
22
23 extern const char *CardType[];
24 static const char *telespci_revision = "$Revision: 2.23.2.3 $";
25
26 #define ZORAN_PO_RQ_PEN 0x02000000
27 #define ZORAN_PO_WR     0x00800000
28 #define ZORAN_PO_GID0   0x00000000
29 #define ZORAN_PO_GID1   0x00100000
30 #define ZORAN_PO_GREG0  0x00000000
31 #define ZORAN_PO_GREG1  0x00010000
32 #define ZORAN_PO_DMASK  0xFF
33
34 #define WRITE_ADDR_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG0)
35 #define READ_DATA_ISAC  (ZORAN_PO_GID0 | ZORAN_PO_GREG1)
36 #define WRITE_DATA_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG1)
37 #define WRITE_ADDR_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG0)
38 #define READ_DATA_HSCX  (ZORAN_PO_GID1 | ZORAN_PO_GREG1)
39 #define WRITE_DATA_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG1)
40
41 #define ZORAN_WAIT_NOBUSY       do { \
42                                         portdata = readl(adr + 0x200); \
43                                 } while (portdata & ZORAN_PO_RQ_PEN)
44
45 static inline u_char
46 readisac(void __iomem *adr, u_char off)
47 {
48         register unsigned int portdata;
49
50         ZORAN_WAIT_NOBUSY;
51         
52         /* set address for ISAC */
53         writel(WRITE_ADDR_ISAC | off, adr + 0x200);
54         ZORAN_WAIT_NOBUSY;
55         
56         /* read data from ISAC */
57         writel(READ_DATA_ISAC, adr + 0x200);
58         ZORAN_WAIT_NOBUSY;
59         return((u_char)(portdata & ZORAN_PO_DMASK));
60 }
61
62 static inline void
63 writeisac(void __iomem *adr, u_char off, u_char data)
64 {
65         register unsigned int portdata;
66
67         ZORAN_WAIT_NOBUSY;
68         
69         /* set address for ISAC */
70         writel(WRITE_ADDR_ISAC | off, adr + 0x200);
71         ZORAN_WAIT_NOBUSY;
72
73         /* write data to ISAC */
74         writel(WRITE_DATA_ISAC | data, adr + 0x200);
75         ZORAN_WAIT_NOBUSY;
76 }
77
78 static inline u_char
79 readhscx(void __iomem *adr, int hscx, u_char off)
80 {
81         register unsigned int portdata;
82
83         ZORAN_WAIT_NOBUSY;
84         /* set address for HSCX */
85         writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200);
86         ZORAN_WAIT_NOBUSY;
87         
88         /* read data from HSCX */
89         writel(READ_DATA_HSCX, adr + 0x200);
90         ZORAN_WAIT_NOBUSY;
91         return ((u_char)(portdata & ZORAN_PO_DMASK));
92 }
93
94 static inline void
95 writehscx(void __iomem *adr, int hscx, u_char off, u_char data)
96 {
97         register unsigned int portdata;
98
99         ZORAN_WAIT_NOBUSY;
100         /* set address for HSCX */
101         writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200);
102         ZORAN_WAIT_NOBUSY;
103
104         /* write data to HSCX */
105         writel(WRITE_DATA_HSCX | data, adr + 0x200);
106         ZORAN_WAIT_NOBUSY;
107 }
108
109 static inline void
110 read_fifo_isac(void __iomem *adr, u_char * data, int size)
111 {
112         register unsigned int portdata;
113         register int i;
114
115         ZORAN_WAIT_NOBUSY;
116         /* read data from ISAC */
117         for (i = 0; i < size; i++) {
118                 /* set address for ISAC fifo */
119                 writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200);
120                 ZORAN_WAIT_NOBUSY;
121                 writel(READ_DATA_ISAC, adr + 0x200);
122                 ZORAN_WAIT_NOBUSY;
123                 data[i] = (u_char)(portdata & ZORAN_PO_DMASK);
124         }
125 }
126
127 static void
128 write_fifo_isac(void __iomem *adr, u_char * data, int size)
129 {
130         register unsigned int portdata;
131         register int i;
132
133         ZORAN_WAIT_NOBUSY;
134         /* write data to ISAC */
135         for (i = 0; i < size; i++) {
136                 /* set address for ISAC fifo */
137                 writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200);
138                 ZORAN_WAIT_NOBUSY;
139                 writel(WRITE_DATA_ISAC | data[i], adr + 0x200);
140                 ZORAN_WAIT_NOBUSY;
141         }
142 }
143
144 static inline void
145 read_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size)
146 {
147         register unsigned int portdata;
148         register int i;
149
150         ZORAN_WAIT_NOBUSY;
151         /* read data from HSCX */
152         for (i = 0; i < size; i++) {
153                 /* set address for HSCX fifo */
154                 writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200);
155                 ZORAN_WAIT_NOBUSY;
156                 writel(READ_DATA_HSCX, adr + 0x200);
157                 ZORAN_WAIT_NOBUSY;
158                 data[i] = (u_char) (portdata & ZORAN_PO_DMASK);
159         }
160 }
161
162 static inline void
163 write_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size)
164 {
165         unsigned int portdata;
166         register int i;
167
168         ZORAN_WAIT_NOBUSY;
169         /* write data to HSCX */
170         for (i = 0; i < size; i++) {
171                 /* set address for HSCX fifo */
172                 writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200);
173                 ZORAN_WAIT_NOBUSY;
174                 writel(WRITE_DATA_HSCX | data[i], adr + 0x200);
175                 ZORAN_WAIT_NOBUSY;
176                 udelay(10);
177         }
178 }
179
180 /* Interface functions */
181
182 static u_char
183 ReadISAC(struct IsdnCardState *cs, u_char offset)
184 {
185         return (readisac(cs->hw.teles0.membase, offset));
186 }
187
188 static void
189 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
190 {
191         writeisac(cs->hw.teles0.membase, offset, value);
192 }
193
194 static void
195 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
196 {
197         read_fifo_isac(cs->hw.teles0.membase, data, size);
198 }
199
200 static void
201 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
202 {
203         write_fifo_isac(cs->hw.teles0.membase, data, size);
204 }
205
206 static u_char
207 ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
208 {
209         return (readhscx(cs->hw.teles0.membase, hscx, offset));
210 }
211
212 static void
213 WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
214 {
215         writehscx(cs->hw.teles0.membase, hscx, offset, value);
216 }
217
218 /*
219  * fast interrupt HSCX stuff goes here
220  */
221
222 #define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg)
223 #define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data)
224 #define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
225 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
226
227 #include "hscx_irq.c"
228
229 static irqreturn_t
230 telespci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
231 {
232         struct IsdnCardState *cs = dev_id;
233         u_char hval, ival;
234         u_long flags;
235
236         spin_lock_irqsave(&cs->lock, flags);
237         hval = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
238         if (hval)
239                 hscx_int_main(cs, hval);
240         ival = readisac(cs->hw.teles0.membase, ISAC_ISTA);
241         if ((hval | ival) == 0) {
242                 spin_unlock_irqrestore(&cs->lock, flags);
243                 return IRQ_NONE;
244         }
245         if (ival)
246                 isac_interrupt(cs, ival);
247         /* Clear interrupt register for Zoran PCI controller */
248         writel(0x70000000, cs->hw.teles0.membase + 0x3C);
249
250         writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF);
251         writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF);
252         writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
253         writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
254         writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0);
255         writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0);
256         spin_unlock_irqrestore(&cs->lock, flags);
257         return IRQ_HANDLED;
258 }
259
260 static void
261 release_io_telespci(struct IsdnCardState *cs)
262 {
263         iounmap(cs->hw.teles0.membase);
264 }
265
266 static int
267 TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg)
268 {
269         u_long flags;
270
271         switch (mt) {
272                 case CARD_RESET:
273                         return(0);
274                 case CARD_RELEASE:
275                         release_io_telespci(cs);
276                         return(0);
277                 case CARD_INIT:
278                         spin_lock_irqsave(&cs->lock, flags);
279                         inithscxisac(cs, 3);
280                         spin_unlock_irqrestore(&cs->lock, flags);
281                         return(0);
282                 case CARD_TEST:
283                         return(0);
284         }
285         return(0);
286 }
287
288 static struct pci_dev *dev_tel __initdata = NULL;
289
290 int __init
291 setup_telespci(struct IsdnCard *card)
292 {
293         struct IsdnCardState *cs = card->cs;
294         char tmp[64];
295
296 #ifdef __BIG_ENDIAN
297 #error "not running on big endian machines now"
298 #endif
299         strcpy(tmp, telespci_revision);
300         printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
301         if (cs->typ != ISDN_CTYPE_TELESPCI)
302                 return (0);
303 #ifdef CONFIG_PCI
304         if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
305                 if (pci_enable_device(dev_tel))
306                         return(0);
307                 cs->irq = dev_tel->irq;
308                 if (!cs->irq) {
309                         printk(KERN_WARNING "Teles: No IRQ for PCI card found\n");
310                         return(0);
311                 }
312                 cs->hw.teles0.membase = ioremap(pci_resource_start(dev_tel, 0),
313                         PAGE_SIZE);
314                 printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n",
315                         pci_resource_start(dev_tel, 0), dev_tel->irq);
316         } else {
317                 printk(KERN_WARNING "TelesPCI: No PCI card found\n");
318                 return(0);
319         }
320 #else
321         printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n");
322         printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n");
323         return (0);
324 #endif /* CONFIG_PCI */
325
326         /* Initialize Zoran PCI controller */
327         writel(0x00000000, cs->hw.teles0.membase + 0x28);
328         writel(0x01000000, cs->hw.teles0.membase + 0x28);
329         writel(0x01000000, cs->hw.teles0.membase + 0x28);
330         writel(0x7BFFFFFF, cs->hw.teles0.membase + 0x2C);
331         writel(0x70000000, cs->hw.teles0.membase + 0x3C);
332         writel(0x61000000, cs->hw.teles0.membase + 0x40);
333         /* writel(0x00800000, cs->hw.teles0.membase + 0x200); */
334
335         printk(KERN_INFO
336                "HiSax: %s config irq:%d mem:%p\n",
337                CardType[cs->typ], cs->irq,
338                cs->hw.teles0.membase);
339
340         setup_isac(cs);
341         cs->readisac = &ReadISAC;
342         cs->writeisac = &WriteISAC;
343         cs->readisacfifo = &ReadISACfifo;
344         cs->writeisacfifo = &WriteISACfifo;
345         cs->BC_Read_Reg = &ReadHSCX;
346         cs->BC_Write_Reg = &WriteHSCX;
347         cs->BC_Send_Data = &hscx_fill_fifo;
348         cs->cardmsg = &TelesPCI_card_msg;
349         cs->irq_func = &telespci_interrupt;
350         cs->irq_flags |= SA_SHIRQ;
351         ISACVersion(cs, "TelesPCI:");
352         if (HscxVersion(cs, "TelesPCI:")) {
353                 printk(KERN_WARNING
354                  "TelesPCI: wrong HSCX versions check IO/MEM addresses\n");
355                 release_io_telespci(cs);
356                 return (0);
357         }
358         return (1);
359 }