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 = NULL; 287 288int setup_telespci(struct IsdnCard *card) 289{ 290 struct IsdnCardState *cs = card->cs; 291 char tmp[64]; 292 293 strcpy(tmp, telespci_revision); 294 printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp)); 295 if (cs->typ != ISDN_CTYPE_TELESPCI) 296 return (0); 297 298 if ((dev_tel = hisax_find_pci_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { 299 if (pci_enable_device(dev_tel)) 300 return (0); 301 cs->irq = dev_tel->irq; 302 if (!cs->irq) { 303 printk(KERN_WARNING "Teles: No IRQ for PCI card found\n"); 304 return (0); 305 } 306 cs->hw.teles0.membase = ioremap(pci_resource_start(dev_tel, 0), 307 PAGE_SIZE); 308 printk(KERN_INFO "Found: Zoran, base-address: 0x%llx, irq: 0x%x\n", 309 (unsigned long long)pci_resource_start(dev_tel, 0), 310 dev_tel->irq); 311 } else { 312 printk(KERN_WARNING "TelesPCI: No PCI card found\n"); 313 return (0); 314 } 315 316 /* Initialize Zoran PCI controller */ 317 writel(0x00000000, cs->hw.teles0.membase + 0x28); 318 writel(0x01000000, cs->hw.teles0.membase + 0x28); 319 writel(0x01000000, cs->hw.teles0.membase + 0x28); 320 writel(0x7BFFFFFF, cs->hw.teles0.membase + 0x2C); 321 writel(0x70000000, cs->hw.teles0.membase + 0x3C); 322 writel(0x61000000, cs->hw.teles0.membase + 0x40); 323 /* writel(0x00800000, cs->hw.teles0.membase + 0x200); */ 324 325 printk(KERN_INFO 326 "HiSax: Teles PCI config irq:%d mem:%p\n", 327 cs->irq, 328 cs->hw.teles0.membase); 329 330 setup_isac(cs); 331 cs->readisac = &ReadISAC; 332 cs->writeisac = &WriteISAC; 333 cs->readisacfifo = &ReadISACfifo; 334 cs->writeisacfifo = &WriteISACfifo; 335 cs->BC_Read_Reg = &ReadHSCX; 336 cs->BC_Write_Reg = &WriteHSCX; 337 cs->BC_Send_Data = &hscx_fill_fifo; 338 cs->cardmsg = &TelesPCI_card_msg; 339 cs->irq_func = &telespci_interrupt; 340 cs->irq_flags |= IRQF_SHARED; 341 ISACVersion(cs, "TelesPCI:"); 342 if (HscxVersion(cs, "TelesPCI:")) { 343 printk(KERN_WARNING 344 "TelesPCI: wrong HSCX versions check IO/MEM addresses\n"); 345 release_io_telespci(cs); 346 return (0); 347 } 348 return (1); 349} 350