Commit | Line | Data |
---|---|---|
1da177e4 LT |
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> | |
1da177e4 LT |
16 | #include "hisax.h" |
17 | #include "isac.h" | |
18 | #include "hscx.h" | |
19 | #include "isdnl1.h" | |
20 | #include <linux/pci.h> | |
21 | ||
672c3fd9 | 22 | static const char *telespci_revision = "$Revision: 2.23.2.3 $"; |
1da177e4 LT |
23 | |
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 | ||
39 | #define ZORAN_WAIT_NOBUSY do { \ | |
40 | portdata = readl(adr + 0x200); \ | |
41 | } while (portdata & ZORAN_PO_RQ_PEN) | |
42 | ||
43 | static inline u_char | |
44 | readisac(void __iomem *adr, u_char off) | |
45 | { | |
46 | register unsigned int portdata; | |
47 | ||
48 | ZORAN_WAIT_NOBUSY; | |
49 | ||
50 | /* set address for ISAC */ | |
51 | writel(WRITE_ADDR_ISAC | off, adr + 0x200); | |
52 | ZORAN_WAIT_NOBUSY; | |
53 | ||
54 | /* read data from ISAC */ | |
55 | writel(READ_DATA_ISAC, adr + 0x200); | |
56 | ZORAN_WAIT_NOBUSY; | |
57 | return((u_char)(portdata & ZORAN_PO_DMASK)); | |
58 | } | |
59 | ||
60 | static inline void | |
61 | writeisac(void __iomem *adr, u_char off, u_char data) | |
62 | { | |
63 | register unsigned int portdata; | |
64 | ||
65 | ZORAN_WAIT_NOBUSY; | |
66 | ||
67 | /* 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 | ||
76 | static inline u_char | |
77 | readhscx(void __iomem *adr, int hscx, u_char off) | |
78 | { | |
79 | register unsigned int portdata; | |
80 | ||
81 | ZORAN_WAIT_NOBUSY; | |
82 | /* set address for HSCX */ | |
83 | writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200); | |
84 | ZORAN_WAIT_NOBUSY; | |
85 | ||
86 | /* 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 | ||
92 | static inline void | |
93 | writehscx(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 */ | |
99 | writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200); | |
100 | ZORAN_WAIT_NOBUSY; | |
101 | ||
102 | /* write data to HSCX */ | |
103 | writel(WRITE_DATA_HSCX | data, adr + 0x200); | |
104 | ZORAN_WAIT_NOBUSY; | |
105 | } | |
106 | ||
107 | static inline void | |
108 | read_fifo_isac(void __iomem *adr, u_char * data, int size) | |
109 | { | |
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 | ||
125 | static void | |
126 | write_fifo_isac(void __iomem *adr, u_char * data, int size) | |
127 | { | |
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 | ||
142 | static inline void | |
143 | read_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size) | |
144 | { | |
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 */ | |
152 | writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200); | |
153 | 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 | ||
160 | static inline void | |
161 | write_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size) | |
162 | { | |
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 */ | |
170 | writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200); | |
171 | 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 | ||
180 | static u_char | |
181 | ReadISAC(struct IsdnCardState *cs, u_char offset) | |
182 | { | |
183 | return (readisac(cs->hw.teles0.membase, offset)); | |
184 | } | |
185 | ||
186 | static void | |
187 | WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) | |
188 | { | |
189 | writeisac(cs->hw.teles0.membase, offset, value); | |
190 | } | |
191 | ||
192 | static void | |
193 | ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) | |
194 | { | |
195 | read_fifo_isac(cs->hw.teles0.membase, data, size); | |
196 | } | |
197 | ||
198 | static void | |
199 | WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) | |
200 | { | |
201 | write_fifo_isac(cs->hw.teles0.membase, data, size); | |
202 | } | |
203 | ||
204 | static u_char | |
205 | ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) | |
206 | { | |
207 | return (readhscx(cs->hw.teles0.membase, hscx, offset)); | |
208 | } | |
209 | ||
210 | static void | |
211 | WriteHSCX(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 | ||
227 | static irqreturn_t | |
7d12e780 | 228 | telespci_interrupt(int intno, void *dev_id) |
1da177e4 LT |
229 | { |
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 | ||
672c3fd9 | 258 | static void |
1da177e4 LT |
259 | release_io_telespci(struct IsdnCardState *cs) |
260 | { | |
261 | iounmap(cs->hw.teles0.membase); | |
262 | } | |
263 | ||
264 | static int | |
265 | TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg) | |
266 | { | |
267 | u_long flags; | |
268 | ||
269 | switch (mt) { | |
270 | 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); | |
282 | } | |
283 | return(0); | |
284 | } | |
285 | ||
67eb5db5 | 286 | static struct pci_dev *dev_tel __devinitdata = NULL; |
1da177e4 | 287 | |
67eb5db5 | 288 | int __devinit |
1da177e4 LT |
289 | setup_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 | |
bfc7c89f | 297 | |
1da177e4 LT |
298 | 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); | |
bfc7c89f | 302 | |
41a68a74 | 303 | if ((dev_tel = hisax_find_pci_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { |
1da177e4 LT |
304 | if (pci_enable_device(dev_tel)) |
305 | return(0); | |
306 | cs->irq = dev_tel->irq; | |
307 | if (!cs->irq) { | |
308 | printk(KERN_WARNING "Teles: No IRQ for PCI card found\n"); | |
309 | return(0); | |
310 | } | |
311 | cs->hw.teles0.membase = ioremap(pci_resource_start(dev_tel, 0), | |
312 | PAGE_SIZE); | |
e29419ff GKH |
313 | printk(KERN_INFO "Found: Zoran, base-address: 0x%llx, irq: 0x%x\n", |
314 | (unsigned long long)pci_resource_start(dev_tel, 0), | |
315 | dev_tel->irq); | |
1da177e4 LT |
316 | } else { |
317 | printk(KERN_WARNING "TelesPCI: No PCI card found\n"); | |
318 | return(0); | |
319 | } | |
1da177e4 LT |
320 | |
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 | |
8349304d JG |
331 | "HiSax: Teles PCI config irq:%d mem:%p\n", |
332 | cs->irq, | |
1da177e4 LT |
333 | 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; | |
9ba02bec | 345 | cs->irq_flags |= IRQF_SHARED; |
1da177e4 LT |
346 | ISACVersion(cs, "TelesPCI:"); |
347 | if (HscxVersion(cs, "TelesPCI:")) { | |
348 | printk(KERN_WARNING | |
349 | "TelesPCI: wrong HSCX versions check IO/MEM addresses\n"); | |
350 | release_io_telespci(cs); | |
351 | return (0); | |
352 | } | |
353 | return (1); | |
354 | } |