linux/drivers/isdn/hisax/telespci.c
<<
>>
Prefs
   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 = 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
 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}
 355