blob: 9c002c9dc7715c653957c9017f5c2113b66194ed [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>
Joe Perches475be4d2012-02-19 19:52:38 -08009 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 * 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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include "hisax.h"
17#include "isac.h"
18#include "hscx.h"
19#include "isdnl1.h"
20#include <linux/pci.h>
21
Adrian Bunk672c3fd2005-06-25 14:59:18 -070022static const char *telespci_revision = "$Revision: 2.23.2.3 $";
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
24#define ZORAN_PO_RQ_PEN 0x02000000
25#define ZORAN_PO_WR 0x00800000
26#define ZORAN_PO_GID0 0x00000000
27#define ZORAN_PO_GID1 0x00100000
28#define ZORAN_PO_GREG0 0x00000000
29#define ZORAN_PO_GREG1 0x00010000
30#define ZORAN_PO_DMASK 0xFF
31
32#define WRITE_ADDR_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG0)
33#define READ_DATA_ISAC (ZORAN_PO_GID0 | ZORAN_PO_GREG1)
34#define WRITE_DATA_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG1)
35#define WRITE_ADDR_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG0)
36#define READ_DATA_HSCX (ZORAN_PO_GID1 | ZORAN_PO_GREG1)
37#define WRITE_DATA_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG1)
38
Joe Perches475be4d2012-02-19 19:52:38 -080039#define ZORAN_WAIT_NOBUSY do { \
40 portdata = readl(adr + 0x200); \
41 } while (portdata & ZORAN_PO_RQ_PEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43static inline u_char
44readisac(void __iomem *adr, u_char off)
45{
46 register unsigned int portdata;
47
48 ZORAN_WAIT_NOBUSY;
Joe Perches475be4d2012-02-19 19:52:38 -080049
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 /* set address for ISAC */
51 writel(WRITE_ADDR_ISAC | off, adr + 0x200);
52 ZORAN_WAIT_NOBUSY;
Joe Perches475be4d2012-02-19 19:52:38 -080053
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 /* read data from ISAC */
55 writel(READ_DATA_ISAC, adr + 0x200);
56 ZORAN_WAIT_NOBUSY;
Joe Perches475be4d2012-02-19 19:52:38 -080057 return ((u_char)(portdata & ZORAN_PO_DMASK));
Linus Torvalds1da177e2005-04-16 15:20:36 -070058}
59
60static inline void
61writeisac(void __iomem *adr, u_char off, u_char data)
62{
63 register unsigned int portdata;
64
65 ZORAN_WAIT_NOBUSY;
Joe Perches475be4d2012-02-19 19:52:38 -080066
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 /* set address for ISAC */
68 writel(WRITE_ADDR_ISAC | off, adr + 0x200);
69 ZORAN_WAIT_NOBUSY;
70
71 /* write data to ISAC */
72 writel(WRITE_DATA_ISAC | data, adr + 0x200);
73 ZORAN_WAIT_NOBUSY;
74}
75
76static inline u_char
77readhscx(void __iomem *adr, int hscx, u_char off)
78{
79 register unsigned int portdata;
80
81 ZORAN_WAIT_NOBUSY;
82 /* set address for HSCX */
Joe Perches475be4d2012-02-19 19:52:38 -080083 writel(WRITE_ADDR_HSCX | ((hscx ? 0x40 : 0) + off), adr + 0x200);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 ZORAN_WAIT_NOBUSY;
Joe Perches475be4d2012-02-19 19:52:38 -080085
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 /* read data from HSCX */
87 writel(READ_DATA_HSCX, adr + 0x200);
88 ZORAN_WAIT_NOBUSY;
89 return ((u_char)(portdata & ZORAN_PO_DMASK));
90}
91
92static inline void
93writehscx(void __iomem *adr, int hscx, u_char off, u_char data)
94{
95 register unsigned int portdata;
96
97 ZORAN_WAIT_NOBUSY;
98 /* set address for HSCX */
Joe Perches475be4d2012-02-19 19:52:38 -080099 writel(WRITE_ADDR_HSCX | ((hscx ? 0x40 : 0) + off), adr + 0x200);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 ZORAN_WAIT_NOBUSY;
101
102 /* write data to HSCX */
103 writel(WRITE_DATA_HSCX | data, adr + 0x200);
104 ZORAN_WAIT_NOBUSY;
105}
106
107static inline void
Joe Perches475be4d2012-02-19 19:52:38 -0800108read_fifo_isac(void __iomem *adr, u_char *data, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109{
110 register unsigned int portdata;
111 register int i;
112
113 ZORAN_WAIT_NOBUSY;
114 /* read data from ISAC */
115 for (i = 0; i < size; i++) {
116 /* set address for ISAC fifo */
117 writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200);
118 ZORAN_WAIT_NOBUSY;
119 writel(READ_DATA_ISAC, adr + 0x200);
120 ZORAN_WAIT_NOBUSY;
121 data[i] = (u_char)(portdata & ZORAN_PO_DMASK);
122 }
123}
124
125static void
Joe Perches475be4d2012-02-19 19:52:38 -0800126write_fifo_isac(void __iomem *adr, u_char *data, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127{
128 register unsigned int portdata;
129 register int i;
130
131 ZORAN_WAIT_NOBUSY;
132 /* write data to ISAC */
133 for (i = 0; i < size; i++) {
134 /* set address for ISAC fifo */
135 writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200);
136 ZORAN_WAIT_NOBUSY;
137 writel(WRITE_DATA_ISAC | data[i], adr + 0x200);
138 ZORAN_WAIT_NOBUSY;
139 }
140}
141
142static inline void
Joe Perches475be4d2012-02-19 19:52:38 -0800143read_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144{
145 register unsigned int portdata;
146 register int i;
147
148 ZORAN_WAIT_NOBUSY;
149 /* read data from HSCX */
150 for (i = 0; i < size; i++) {
151 /* set address for HSCX fifo */
Joe Perches475be4d2012-02-19 19:52:38 -0800152 writel(WRITE_ADDR_HSCX | (hscx ? 0x5F : 0x1F), adr + 0x200);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 ZORAN_WAIT_NOBUSY;
154 writel(READ_DATA_HSCX, adr + 0x200);
155 ZORAN_WAIT_NOBUSY;
156 data[i] = (u_char) (portdata & ZORAN_PO_DMASK);
157 }
158}
159
160static inline void
Joe Perches475be4d2012-02-19 19:52:38 -0800161write_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162{
163 unsigned int portdata;
164 register int i;
165
166 ZORAN_WAIT_NOBUSY;
167 /* write data to HSCX */
168 for (i = 0; i < size; i++) {
169 /* set address for HSCX fifo */
Joe Perches475be4d2012-02-19 19:52:38 -0800170 writel(WRITE_ADDR_HSCX | (hscx ? 0x5F : 0x1F), adr + 0x200);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 ZORAN_WAIT_NOBUSY;
172 writel(WRITE_DATA_HSCX | data[i], adr + 0x200);
173 ZORAN_WAIT_NOBUSY;
174 udelay(10);
175 }
176}
177
178/* Interface functions */
179
180static u_char
181ReadISAC(struct IsdnCardState *cs, u_char offset)
182{
183 return (readisac(cs->hw.teles0.membase, offset));
184}
185
186static void
187WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
188{
189 writeisac(cs->hw.teles0.membase, offset, value);
190}
191
192static void
Joe Perches475be4d2012-02-19 19:52:38 -0800193ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194{
195 read_fifo_isac(cs->hw.teles0.membase, data, size);
196}
197
198static void
Joe Perches475be4d2012-02-19 19:52:38 -0800199WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200{
201 write_fifo_isac(cs->hw.teles0.membase, data, size);
202}
203
204static u_char
205ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
206{
207 return (readhscx(cs->hw.teles0.membase, hscx, offset));
208}
209
210static void
211WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
212{
213 writehscx(cs->hw.teles0.membase, hscx, offset, value);
214}
215
216/*
217 * fast interrupt HSCX stuff goes here
218 */
219
220#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg)
221#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data)
222#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
223#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
224
225#include "hscx_irq.c"
226
227static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100228telespci_interrupt(int intno, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229{
230 struct IsdnCardState *cs = dev_id;
231 u_char hval, ival;
232 u_long flags;
233
234 spin_lock_irqsave(&cs->lock, flags);
235 hval = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
236 if (hval)
237 hscx_int_main(cs, hval);
238 ival = readisac(cs->hw.teles0.membase, ISAC_ISTA);
239 if ((hval | ival) == 0) {
240 spin_unlock_irqrestore(&cs->lock, flags);
241 return IRQ_NONE;
242 }
243 if (ival)
244 isac_interrupt(cs, ival);
245 /* Clear interrupt register for Zoran PCI controller */
246 writel(0x70000000, cs->hw.teles0.membase + 0x3C);
247
248 writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF);
249 writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF);
250 writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
251 writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
252 writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0);
253 writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0);
254 spin_unlock_irqrestore(&cs->lock, flags);
255 return IRQ_HANDLED;
256}
257
Adrian Bunk672c3fd2005-06-25 14:59:18 -0700258static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259release_io_telespci(struct IsdnCardState *cs)
260{
261 iounmap(cs->hw.teles0.membase);
262}
263
264static int
265TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg)
266{
267 u_long flags;
268
269 switch (mt) {
Joe Perches475be4d2012-02-19 19:52:38 -0800270 case CARD_RESET:
271 return (0);
272 case CARD_RELEASE:
273 release_io_telespci(cs);
274 return (0);
275 case CARD_INIT:
276 spin_lock_irqsave(&cs->lock, flags);
277 inithscxisac(cs, 3);
278 spin_unlock_irqrestore(&cs->lock, flags);
279 return (0);
280 case CARD_TEST:
281 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 }
Joe Perches475be4d2012-02-19 19:52:38 -0800283 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284}
285
Karsten Keil67eb5db2006-07-10 04:44:11 -0700286static struct pci_dev *dev_tel __devinitdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Karsten Keil67eb5db2006-07-10 04:44:11 -0700288int __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289setup_telespci(struct IsdnCard *card)
290{
291 struct IsdnCardState *cs = card->cs;
292 char tmp[64];
293
294#ifdef __BIG_ENDIAN
295#error "not running on big endian machines now"
296#endif
Jeff Garzikbfc7c892007-08-02 16:56:22 -0400297
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 strcpy(tmp, telespci_revision);
299 printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
300 if (cs->typ != ISDN_CTYPE_TELESPCI)
301 return (0);
Jeff Garzikbfc7c892007-08-02 16:56:22 -0400302
Joe Perches475be4d2012-02-19 19:52:38 -0800303 if ((dev_tel = hisax_find_pci_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 if (pci_enable_device(dev_tel))
Joe Perches475be4d2012-02-19 19:52:38 -0800305 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 cs->irq = dev_tel->irq;
307 if (!cs->irq) {
308 printk(KERN_WARNING "Teles: No IRQ for PCI card found\n");
Joe Perches475be4d2012-02-19 19:52:38 -0800309 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 }
311 cs->hw.teles0.membase = ioremap(pci_resource_start(dev_tel, 0),
Joe Perches475be4d2012-02-19 19:52:38 -0800312 PAGE_SIZE);
Greg Kroah-Hartmane29419f2006-06-12 15:20:16 -0700313 printk(KERN_INFO "Found: Zoran, base-address: 0x%llx, irq: 0x%x\n",
Joe Perches475be4d2012-02-19 19:52:38 -0800314 (unsigned long long)pci_resource_start(dev_tel, 0),
315 dev_tel->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 } else {
317 printk(KERN_WARNING "TelesPCI: No PCI card found\n");
Joe Perches475be4d2012-02-19 19:52:38 -0800318 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
321 /* Initialize Zoran PCI controller */
322 writel(0x00000000, cs->hw.teles0.membase + 0x28);
323 writel(0x01000000, cs->hw.teles0.membase + 0x28);
324 writel(0x01000000, cs->hw.teles0.membase + 0x28);
325 writel(0x7BFFFFFF, cs->hw.teles0.membase + 0x2C);
326 writel(0x70000000, cs->hw.teles0.membase + 0x3C);
327 writel(0x61000000, cs->hw.teles0.membase + 0x40);
328 /* writel(0x00800000, cs->hw.teles0.membase + 0x200); */
329
330 printk(KERN_INFO
Jeff Garzik83493042007-10-31 03:42:07 -0400331 "HiSax: Teles PCI config irq:%d mem:%p\n",
332 cs->irq,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 cs->hw.teles0.membase);
334
335 setup_isac(cs);
336 cs->readisac = &ReadISAC;
337 cs->writeisac = &WriteISAC;
338 cs->readisacfifo = &ReadISACfifo;
339 cs->writeisacfifo = &WriteISACfifo;
340 cs->BC_Read_Reg = &ReadHSCX;
341 cs->BC_Write_Reg = &WriteHSCX;
342 cs->BC_Send_Data = &hscx_fill_fifo;
343 cs->cardmsg = &TelesPCI_card_msg;
344 cs->irq_func = &telespci_interrupt;
Thomas Gleixner9ba02be2006-07-01 19:29:36 -0700345 cs->irq_flags |= IRQF_SHARED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 ISACVersion(cs, "TelesPCI:");
347 if (HscxVersion(cs, "TelesPCI:")) {
348 printk(KERN_WARNING
Joe Perches475be4d2012-02-19 19:52:38 -0800349 "TelesPCI: wrong HSCX versions check IO/MEM addresses\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 release_io_telespci(cs);
351 return (0);
352 }
353 return (1);
354}