]>
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 | ||
22 | extern const char *CardType[]; | |
672c3fd9 | 23 | static const char *telespci_revision = "$Revision: 2.23.2.3 $"; |
1da177e4 LT |
24 | |
25 | #define ZORAN_PO_RQ_PEN 0x02000000 | |
26 | #define ZORAN_PO_WR 0x00800000 | |
27 | #define ZORAN_PO_GID0 0x00000000 | |
28 | #define ZORAN_PO_GID1 0x00100000 | |
29 | #define ZORAN_PO_GREG0 0x00000000 | |
30 | #define ZORAN_PO_GREG1 0x00010000 | |
31 | #define ZORAN_PO_DMASK 0xFF | |
32 | ||
33 | #define WRITE_ADDR_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG0) | |
34 | #define READ_DATA_ISAC (ZORAN_PO_GID0 | ZORAN_PO_GREG1) | |
35 | #define WRITE_DATA_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG1) | |
36 | #define WRITE_ADDR_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG0) | |
37 | #define READ_DATA_HSCX (ZORAN_PO_GID1 | ZORAN_PO_GREG1) | |
38 | #define WRITE_DATA_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG1) | |
39 | ||
40 | #define ZORAN_WAIT_NOBUSY do { \ | |
41 | portdata = readl(adr + 0x200); \ | |
42 | } while (portdata & ZORAN_PO_RQ_PEN) | |
43 | ||
44 | static inline u_char | |
45 | readisac(void __iomem *adr, u_char off) | |
46 | { | |
47 | register unsigned int portdata; | |
48 | ||
49 | ZORAN_WAIT_NOBUSY; | |
50 | ||
51 | /* set address for ISAC */ | |
52 | writel(WRITE_ADDR_ISAC | off, adr + 0x200); | |
53 | ZORAN_WAIT_NOBUSY; | |
54 | ||
55 | /* read data from ISAC */ | |
56 | writel(READ_DATA_ISAC, adr + 0x200); | |
57 | ZORAN_WAIT_NOBUSY; | |
58 | return((u_char)(portdata & ZORAN_PO_DMASK)); | |
59 | } | |
60 | ||
61 | static inline void | |
62 | writeisac(void __iomem *adr, u_char off, u_char data) | |
63 | { | |
64 | register unsigned int portdata; | |
65 | ||
66 | ZORAN_WAIT_NOBUSY; | |
67 | ||
68 | /* set address for ISAC */ | |
69 | writel(WRITE_ADDR_ISAC | off, adr + 0x200); | |
70 | ZORAN_WAIT_NOBUSY; | |
71 | ||
72 | /* write data to ISAC */ | |
73 | writel(WRITE_DATA_ISAC | data, adr + 0x200); | |
74 | ZORAN_WAIT_NOBUSY; | |
75 | } | |
76 | ||
77 | static inline u_char | |
78 | readhscx(void __iomem *adr, int hscx, u_char off) | |
79 | { | |
80 | register unsigned int portdata; | |
81 | ||
82 | ZORAN_WAIT_NOBUSY; | |
83 | /* set address for HSCX */ | |
84 | writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200); | |
85 | ZORAN_WAIT_NOBUSY; | |
86 | ||
87 | /* read data from HSCX */ | |
88 | writel(READ_DATA_HSCX, adr + 0x200); | |
89 | ZORAN_WAIT_NOBUSY; | |
90 | return ((u_char)(portdata & ZORAN_PO_DMASK)); | |
91 | } | |
92 | ||
93 | static inline void | |
94 | writehscx(void __iomem *adr, int hscx, u_char off, u_char data) | |
95 | { | |
96 | register unsigned int portdata; | |
97 | ||
98 | ZORAN_WAIT_NOBUSY; | |
99 | /* set address for HSCX */ | |
100 | writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200); | |
101 | ZORAN_WAIT_NOBUSY; | |
102 | ||
103 | /* write data to HSCX */ | |
104 | writel(WRITE_DATA_HSCX | data, adr + 0x200); | |
105 | ZORAN_WAIT_NOBUSY; | |
106 | } | |
107 | ||
108 | static inline void | |
109 | read_fifo_isac(void __iomem *adr, u_char * data, int size) | |
110 | { | |
111 | register unsigned int portdata; | |
112 | register int i; | |
113 | ||
114 | ZORAN_WAIT_NOBUSY; | |
115 | /* read data from ISAC */ | |
116 | for (i = 0; i < size; i++) { | |
117 | /* set address for ISAC fifo */ | |
118 | writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200); | |
119 | ZORAN_WAIT_NOBUSY; | |
120 | writel(READ_DATA_ISAC, adr + 0x200); | |
121 | ZORAN_WAIT_NOBUSY; | |
122 | data[i] = (u_char)(portdata & ZORAN_PO_DMASK); | |
123 | } | |
124 | } | |
125 | ||
126 | static void | |
127 | write_fifo_isac(void __iomem *adr, u_char * data, int size) | |
128 | { | |
129 | register unsigned int portdata; | |
130 | register int i; | |
131 | ||
132 | ZORAN_WAIT_NOBUSY; | |
133 | /* write data to ISAC */ | |
134 | for (i = 0; i < size; i++) { | |
135 | /* set address for ISAC fifo */ | |
136 | writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200); | |
137 | ZORAN_WAIT_NOBUSY; | |
138 | writel(WRITE_DATA_ISAC | data[i], adr + 0x200); | |
139 | ZORAN_WAIT_NOBUSY; | |
140 | } | |
141 | } | |
142 | ||
143 | static inline void | |
144 | read_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size) | |
145 | { | |
146 | register unsigned int portdata; | |
147 | register int i; | |
148 | ||
149 | ZORAN_WAIT_NOBUSY; | |
150 | /* read data from HSCX */ | |
151 | for (i = 0; i < size; i++) { | |
152 | /* set address for HSCX fifo */ | |
153 | writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200); | |
154 | ZORAN_WAIT_NOBUSY; | |
155 | writel(READ_DATA_HSCX, adr + 0x200); | |
156 | ZORAN_WAIT_NOBUSY; | |
157 | data[i] = (u_char) (portdata & ZORAN_PO_DMASK); | |
158 | } | |
159 | } | |
160 | ||
161 | static inline void | |
162 | write_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size) | |
163 | { | |
164 | unsigned int portdata; | |
165 | register int i; | |
166 | ||
167 | ZORAN_WAIT_NOBUSY; | |
168 | /* write data to HSCX */ | |
169 | for (i = 0; i < size; i++) { | |
170 | /* set address for HSCX fifo */ | |
171 | writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200); | |
172 | ZORAN_WAIT_NOBUSY; | |
173 | writel(WRITE_DATA_HSCX | data[i], adr + 0x200); | |
174 | ZORAN_WAIT_NOBUSY; | |
175 | udelay(10); | |
176 | } | |
177 | } | |
178 | ||
179 | /* Interface functions */ | |
180 | ||
181 | static u_char | |
182 | ReadISAC(struct IsdnCardState *cs, u_char offset) | |
183 | { | |
184 | return (readisac(cs->hw.teles0.membase, offset)); | |
185 | } | |
186 | ||
187 | static void | |
188 | WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) | |
189 | { | |
190 | writeisac(cs->hw.teles0.membase, offset, value); | |
191 | } | |
192 | ||
193 | static void | |
194 | ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) | |
195 | { | |
196 | read_fifo_isac(cs->hw.teles0.membase, data, size); | |
197 | } | |
198 | ||
199 | static void | |
200 | WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) | |
201 | { | |
202 | write_fifo_isac(cs->hw.teles0.membase, data, size); | |
203 | } | |
204 | ||
205 | static u_char | |
206 | ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) | |
207 | { | |
208 | return (readhscx(cs->hw.teles0.membase, hscx, offset)); | |
209 | } | |
210 | ||
211 | static void | |
212 | WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) | |
213 | { | |
214 | writehscx(cs->hw.teles0.membase, hscx, offset, value); | |
215 | } | |
216 | ||
217 | /* | |
218 | * fast interrupt HSCX stuff goes here | |
219 | */ | |
220 | ||
221 | #define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg) | |
222 | #define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data) | |
223 | #define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) | |
224 | #define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) | |
225 | ||
226 | #include "hscx_irq.c" | |
227 | ||
228 | static irqreturn_t | |
7d12e780 | 229 | telespci_interrupt(int intno, void *dev_id) |
1da177e4 LT |
230 | { |
231 | struct IsdnCardState *cs = dev_id; | |
232 | u_char hval, ival; | |
233 | u_long flags; | |
234 | ||
235 | spin_lock_irqsave(&cs->lock, flags); | |
236 | hval = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA); | |
237 | if (hval) | |
238 | hscx_int_main(cs, hval); | |
239 | ival = readisac(cs->hw.teles0.membase, ISAC_ISTA); | |
240 | if ((hval | ival) == 0) { | |
241 | spin_unlock_irqrestore(&cs->lock, flags); | |
242 | return IRQ_NONE; | |
243 | } | |
244 | if (ival) | |
245 | isac_interrupt(cs, ival); | |
246 | /* Clear interrupt register for Zoran PCI controller */ | |
247 | writel(0x70000000, cs->hw.teles0.membase + 0x3C); | |
248 | ||
249 | writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF); | |
250 | writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF); | |
251 | writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF); | |
252 | writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0); | |
253 | writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0); | |
254 | writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0); | |
255 | spin_unlock_irqrestore(&cs->lock, flags); | |
256 | return IRQ_HANDLED; | |
257 | } | |
258 | ||
672c3fd9 | 259 | static void |
1da177e4 LT |
260 | release_io_telespci(struct IsdnCardState *cs) |
261 | { | |
262 | iounmap(cs->hw.teles0.membase); | |
263 | } | |
264 | ||
265 | static int | |
266 | TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg) | |
267 | { | |
268 | u_long flags; | |
269 | ||
270 | switch (mt) { | |
271 | case CARD_RESET: | |
272 | return(0); | |
273 | case CARD_RELEASE: | |
274 | release_io_telespci(cs); | |
275 | return(0); | |
276 | case CARD_INIT: | |
277 | spin_lock_irqsave(&cs->lock, flags); | |
278 | inithscxisac(cs, 3); | |
279 | spin_unlock_irqrestore(&cs->lock, flags); | |
280 | return(0); | |
281 | case CARD_TEST: | |
282 | return(0); | |
283 | } | |
284 | return(0); | |
285 | } | |
286 | ||
67eb5db5 | 287 | static struct pci_dev *dev_tel __devinitdata = NULL; |
1da177e4 | 288 | |
67eb5db5 | 289 | int __devinit |
1da177e4 LT |
290 | setup_telespci(struct IsdnCard *card) |
291 | { | |
292 | struct IsdnCardState *cs = card->cs; | |
293 | char tmp[64]; | |
294 | ||
295 | #ifdef __BIG_ENDIAN | |
296 | #error "not running on big endian machines now" | |
297 | #endif | |
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); | |
302 | #ifdef CONFIG_PCI | |
303 | if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { | |
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 | } | |
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; | |
9ba02bec | 350 | cs->irq_flags |= IRQF_SHARED; |
1da177e4 LT |
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 | } |