blob: 0661c6c31ad0629b3ae07792f05136718ca31f68 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $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
23extern const char *CardType[];
24const 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
45static inline u_char
46readisac(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
62static inline void
63writeisac(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
78static inline u_char
79readhscx(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
94static inline void
95writehscx(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
109static inline void
110read_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
127static void
128write_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
144static inline void
145read_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
162static inline void
163write_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
182static u_char
183ReadISAC(struct IsdnCardState *cs, u_char offset)
184{
185 return (readisac(cs->hw.teles0.membase, offset));
186}
187
188static void
189WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
190{
191 writeisac(cs->hw.teles0.membase, offset, value);
192}
193
194static void
195ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
196{
197 read_fifo_isac(cs->hw.teles0.membase, data, size);
198}
199
200static void
201WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
202{
203 write_fifo_isac(cs->hw.teles0.membase, data, size);
204}
205
206static u_char
207ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
208{
209 return (readhscx(cs->hw.teles0.membase, hscx, offset));
210}
211
212static void
213WriteHSCX(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
229static irqreturn_t
230telespci_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
260void
261release_io_telespci(struct IsdnCardState *cs)
262{
263 iounmap(cs->hw.teles0.membase);
264}
265
266static int
267TelesPCI_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
288static struct pci_dev *dev_tel __initdata = NULL;
289
290int __init
291setup_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}