1/* $Id: telespci.c,v 1.1.1.1 2007/08/03 18:52:36 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 "hisax.h"
17#include "isac.h"
18#include "hscx.h"
19#include "isdnl1.h"
20#include <linux/pci.h>
21
22extern const char *CardType[];
23static const char *telespci_revision = "$Revision: 1.1.1.1 $";
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
44static inline u_char
45readisac(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
61static inline void
62writeisac(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
77static inline u_char
78readhscx(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
93static inline void
94writehscx(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
108static inline void
109read_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
126static void
127write_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
143static inline void
144read_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
161static inline void
162write_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
181static u_char
182ReadISAC(struct IsdnCardState *cs, u_char offset)
183{
184	return (readisac(cs->hw.teles0.membase, offset));
185}
186
187static void
188WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
189{
190	writeisac(cs->hw.teles0.membase, offset, value);
191}
192
193static void
194ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
195{
196	read_fifo_isac(cs->hw.teles0.membase, data, size);
197}
198
199static void
200WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
201{
202	write_fifo_isac(cs->hw.teles0.membase, data, size);
203}
204
205static u_char
206ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
207{
208	return (readhscx(cs->hw.teles0.membase, hscx, offset));
209}
210
211static void
212WriteHSCX(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
228static irqreturn_t
229telespci_interrupt(int intno, void *dev_id)
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
259static void
260release_io_telespci(struct IsdnCardState *cs)
261{
262	iounmap(cs->hw.teles0.membase);
263}
264
265static int
266TelesPCI_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
287static struct pci_dev *dev_tel __devinitdata = NULL;
288
289int __devinit
290setup_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);
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);
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 |= IRQF_SHARED;
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}
360