diff options
Diffstat (limited to 'drivers/isdn/hisax/telespci.c')
-rw-r--r-- | drivers/isdn/hisax/telespci.c | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c new file mode 100644 index 000000000000..0661c6c31ad0 --- /dev/null +++ b/drivers/isdn/hisax/telespci.c | |||
@@ -0,0 +1,359 @@ | |||
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 | 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 | 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 | } | ||