PageRenderTime 35ms CodeModel.GetById 20ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/isdn/hisax/telespci.c

https://bitbucket.org/ndreys/linux-sunxi
C | 354 lines | 267 code | 51 blank | 36 comment | 17 complexity | 54398f53ed0b9ee07c7cfbb82b87f410 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  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 "hisax.h"
 17#include "isac.h"
 18#include "hscx.h"
 19#include "isdnl1.h"
 20#include <linux/pci.h>
 21
 22static const char *telespci_revision = "$Revision: 2.23.2.3 $";
 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
 43static inline u_char
 44readisac(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
 60static inline void
 61writeisac(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
 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 */
 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
 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 */
 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
107static inline void
108read_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
125static void
126write_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
142static inline void
143read_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
160static inline void
161write_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
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
193ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
194{
195	read_fifo_isac(cs->hw.teles0.membase, data, size);
196}
197
198static void
199WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
200{
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
228telespci_interrupt(int intno, void *dev_id)
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
258static void
259release_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) {
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
286static struct pci_dev *dev_tel __devinitdata = NULL;
287
288int __devinit
289setup_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
297
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
303	if ((dev_tel = hisax_find_pci_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
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
331	       "HiSax: Teles PCI config irq:%d mem:%p\n",
332	       cs->irq,
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;
345	cs->irq_flags |= IRQF_SHARED;
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}