linux/drivers/staging/comedi/drivers/rtd520.c
<<
>>
Prefs
   1/*
   2 * comedi/drivers/rtd520.c
   3 * Comedi driver for Real Time Devices (RTD) PCI4520/DM7520
   4 *
   5 * COMEDI - Linux Control and Measurement Device Interface
   6 * Copyright (C) 2001 David A. Schleef <ds@schleef.org>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 * GNU General Public License for more details.
  17 */
  18
  19/*
  20 * Driver: rtd520
  21 * Description: Real Time Devices PCI4520/DM7520
  22 * Devices: [Real Time Devices] DM7520HR-1 (DM7520), DM7520HR-8,
  23 *   PCI4520 (PCI4520), PCI4520-8
  24 * Author: Dan Christian
  25 * Status: Works. Only tested on DM7520-8. Not SMP safe.
  26 *
  27 * Configuration options: not applicable, uses PCI auto config
  28 */
  29
  30/*
  31 * Created by Dan Christian, NASA Ames Research Center.
  32 *
  33 * The PCI4520 is a PCI card. The DM7520 is a PC/104-plus card.
  34 * Both have:
  35 *   8/16 12 bit ADC with FIFO and channel gain table
  36 *   8 bits high speed digital out (for external MUX) (or 8 in or 8 out)
  37 *   8 bits high speed digital in with FIFO and interrupt on change (or 8 IO)
  38 *   2 12 bit DACs with FIFOs
  39 *   2 bits output
  40 *   2 bits input
  41 *   bus mastering DMA
  42 *   timers: ADC sample, pacer, burst, about, delay, DA1, DA2
  43 *   sample counter
  44 *   3 user timer/counters (8254)
  45 *   external interrupt
  46 *
  47 * The DM7520 has slightly fewer features (fewer gain steps).
  48 *
  49 * These boards can support external multiplexors and multi-board
  50 * synchronization, but this driver doesn't support that.
  51 *
  52 * Board docs: http://www.rtdusa.com/PC104/DM/analog%20IO/dm7520.htm
  53 * Data sheet: http://www.rtdusa.com/pdf/dm7520.pdf
  54 * Example source: http://www.rtdusa.com/examples/dm/dm7520.zip
  55 * Call them and ask for the register level manual.
  56 * PCI chip: http://www.plxtech.com/products/io/pci9080
  57 *
  58 * Notes:
  59 * This board is memory mapped. There is some IO stuff, but it isn't needed.
  60 *
  61 * I use a pretty loose naming style within the driver (rtd_blah).
  62 * All externally visible names should be rtd520_blah.
  63 * I use camelCase for structures (and inside them).
  64 * I may also use upper CamelCase for function names (old habit).
  65 *
  66 * This board is somewhat related to the RTD PCI4400 board.
  67 *
  68 * I borrowed heavily from the ni_mio_common, ni_atmio16d, mite, and
  69 * das1800, since they have the best documented code. Driver cb_pcidas64.c
  70 * uses the same DMA controller.
  71 *
  72 * As far as I can tell, the About interrupt doesn't work if Sample is
  73 * also enabled. It turns out that About really isn't needed, since
  74 * we always count down samples read.
  75 */
  76
  77/*
  78 * driver status:
  79 *
  80 * Analog-In supports instruction and command mode.
  81 *
  82 * With DMA, you can sample at 1.15Mhz with 70% idle on a 400Mhz K6-2
  83 * (single channel, 64K read buffer). I get random system lockups when
  84 * using DMA with ALI-15xx based systems. I haven't been able to test
  85 * any other chipsets. The lockups happen soon after the start of an
  86 * acquistion, not in the middle of a long run.
  87 *
  88 * Without DMA, you can do 620Khz sampling with 20% idle on a 400Mhz K6-2
  89 * (with a 256K read buffer).
  90 *
  91 * Digital-IO and Analog-Out only support instruction mode.
  92 */
  93
  94#include <linux/module.h>
  95#include <linux/delay.h>
  96#include <linux/interrupt.h>
  97
  98#include "../comedi_pci.h"
  99
 100#include "comedi_8254.h"
 101#include "plx9080.h"
 102
 103/*
 104 * Local Address Space 0 Offsets
 105 */
 106#define LAS0_USER_IO            0x0008  /* User I/O */
 107#define LAS0_ADC                0x0010  /* FIFO Status/Software A/D Start */
 108#define FS_DAC1_NOT_EMPTY       BIT(0)  /* DAC1 FIFO not empty */
 109#define FS_DAC1_HEMPTY          BIT(1)  /* DAC1 FIFO half empty */
 110#define FS_DAC1_NOT_FULL        BIT(2)  /* DAC1 FIFO not full */
 111#define FS_DAC2_NOT_EMPTY       BIT(4)  /* DAC2 FIFO not empty */
 112#define FS_DAC2_HEMPTY          BIT(5)  /* DAC2 FIFO half empty */
 113#define FS_DAC2_NOT_FULL        BIT(6)  /* DAC2 FIFO not full */
 114#define FS_ADC_NOT_EMPTY        BIT(8)  /* ADC FIFO not empty */
 115#define FS_ADC_HEMPTY           BIT(9)  /* ADC FIFO half empty */
 116#define FS_ADC_NOT_FULL         BIT(10) /* ADC FIFO not full */
 117#define FS_DIN_NOT_EMPTY        BIT(12) /* DIN FIFO not empty */
 118#define FS_DIN_HEMPTY           BIT(13) /* DIN FIFO half empty */
 119#define FS_DIN_NOT_FULL         BIT(14) /* DIN FIFO not full */
 120#define LAS0_UPDATE_DAC(x)      (0x0014 + ((x) * 0x4))  /* D/Ax Update (w) */
 121#define LAS0_DAC                0x0024  /* Software Simultaneous Update (w) */
 122#define LAS0_PACER              0x0028  /* Software Pacer Start/Stop */
 123#define LAS0_TIMER              0x002c  /* Timer Status/HDIN Software Trig. */
 124#define LAS0_IT                 0x0030  /* Interrupt Status/Enable */
 125#define IRQM_ADC_FIFO_WRITE     BIT(0)  /* ADC FIFO Write */
 126#define IRQM_CGT_RESET          BIT(1)  /* Reset CGT */
 127#define IRQM_CGT_PAUSE          BIT(3)  /* Pause CGT */
 128#define IRQM_ADC_ABOUT_CNT      BIT(4)  /* About Counter out */
 129#define IRQM_ADC_DELAY_CNT      BIT(5)  /* Delay Counter out */
 130#define IRQM_ADC_SAMPLE_CNT     BIT(6)  /* ADC Sample Counter */
 131#define IRQM_DAC1_UCNT          BIT(7)  /* DAC1 Update Counter */
 132#define IRQM_DAC2_UCNT          BIT(8)  /* DAC2 Update Counter */
 133#define IRQM_UTC1               BIT(9)  /* User TC1 out */
 134#define IRQM_UTC1_INV           BIT(10) /* User TC1 out, inverted */
 135#define IRQM_UTC2               BIT(11) /* User TC2 out */
 136#define IRQM_DIGITAL_IT         BIT(12) /* Digital Interrupt */
 137#define IRQM_EXTERNAL_IT        BIT(13) /* External Interrupt */
 138#define IRQM_ETRIG_RISING       BIT(14) /* Ext Trigger rising-edge */
 139#define IRQM_ETRIG_FALLING      BIT(15) /* Ext Trigger falling-edge */
 140#define LAS0_CLEAR              0x0034  /* Clear/Set Interrupt Clear Mask */
 141#define LAS0_OVERRUN            0x0038  /* Pending interrupts/Clear Overrun */
 142#define LAS0_PCLK               0x0040  /* Pacer Clock (24bit) */
 143#define LAS0_BCLK               0x0044  /* Burst Clock (10bit) */
 144#define LAS0_ADC_SCNT           0x0048  /* A/D Sample counter (10bit) */
 145#define LAS0_DAC1_UCNT          0x004c  /* D/A1 Update counter (10 bit) */
 146#define LAS0_DAC2_UCNT          0x0050  /* D/A2 Update counter (10 bit) */
 147#define LAS0_DCNT               0x0054  /* Delay counter (16 bit) */
 148#define LAS0_ACNT               0x0058  /* About counter (16 bit) */
 149#define LAS0_DAC_CLK            0x005c  /* DAC clock (16bit) */
 150#define LAS0_8254_TIMER_BASE    0x0060  /* 8254 timer/counter base */
 151#define LAS0_DIO0               0x0070  /* Digital I/O Port 0 */
 152#define LAS0_DIO1               0x0074  /* Digital I/O Port 1 */
 153#define LAS0_DIO0_CTRL          0x0078  /* Digital I/O Control */
 154#define LAS0_DIO_STATUS         0x007c  /* Digital I/O Status */
 155#define LAS0_BOARD_RESET        0x0100  /* Board reset */
 156#define LAS0_DMA0_SRC           0x0104  /* DMA 0 Sources select */
 157#define LAS0_DMA1_SRC           0x0108  /* DMA 1 Sources select */
 158#define LAS0_ADC_CONVERSION     0x010c  /* A/D Conversion Signal select */
 159#define LAS0_BURST_START        0x0110  /* Burst Clock Start Trigger select */
 160#define LAS0_PACER_START        0x0114  /* Pacer Clock Start Trigger select */
 161#define LAS0_PACER_STOP         0x0118  /* Pacer Clock Stop Trigger select */
 162#define LAS0_ACNT_STOP_ENABLE   0x011c  /* About Counter Stop Enable */
 163#define LAS0_PACER_REPEAT       0x0120  /* Pacer Start Trigger Mode select */
 164#define LAS0_DIN_START          0x0124  /* HiSpd DI Sampling Signal select */
 165#define LAS0_DIN_FIFO_CLEAR     0x0128  /* Digital Input FIFO Clear */
 166#define LAS0_ADC_FIFO_CLEAR     0x012c  /* A/D FIFO Clear */
 167#define LAS0_CGT_WRITE          0x0130  /* Channel Gain Table Write */
 168#define LAS0_CGL_WRITE          0x0134  /* Channel Gain Latch Write */
 169#define LAS0_CG_DATA            0x0138  /* Digital Table Write */
 170#define LAS0_CGT_ENABLE         0x013c  /* Channel Gain Table Enable */
 171#define LAS0_CG_ENABLE          0x0140  /* Digital Table Enable */
 172#define LAS0_CGT_PAUSE          0x0144  /* Table Pause Enable */
 173#define LAS0_CGT_RESET          0x0148  /* Reset Channel Gain Table */
 174#define LAS0_CGT_CLEAR          0x014c  /* Clear Channel Gain Table */
 175#define LAS0_DAC_CTRL(x)        (0x0150 + ((x) * 0x14)) /* D/Ax type/range */
 176#define LAS0_DAC_SRC(x)         (0x0154 + ((x) * 0x14)) /* D/Ax update source */
 177#define LAS0_DAC_CYCLE(x)       (0x0158 + ((x) * 0x14)) /* D/Ax cycle mode */
 178#define LAS0_DAC_RESET(x)       (0x015c + ((x) * 0x14)) /* D/Ax FIFO reset */
 179#define LAS0_DAC_FIFO_CLEAR(x)  (0x0160 + ((x) * 0x14)) /* D/Ax FIFO clear */
 180#define LAS0_ADC_SCNT_SRC       0x0178  /* A/D Sample Counter Source select */
 181#define LAS0_PACER_SELECT       0x0180  /* Pacer Clock select */
 182#define LAS0_SBUS0_SRC          0x0184  /* SyncBus 0 Source select */
 183#define LAS0_SBUS0_ENABLE       0x0188  /* SyncBus 0 enable */
 184#define LAS0_SBUS1_SRC          0x018c  /* SyncBus 1 Source select */
 185#define LAS0_SBUS1_ENABLE       0x0190  /* SyncBus 1 enable */
 186#define LAS0_SBUS2_SRC          0x0198  /* SyncBus 2 Source select */
 187#define LAS0_SBUS2_ENABLE       0x019c  /* SyncBus 2 enable */
 188#define LAS0_ETRG_POLARITY      0x01a4  /* Ext. Trigger polarity select */
 189#define LAS0_EINT_POLARITY      0x01a8  /* Ext. Interrupt polarity select */
 190#define LAS0_8254_CLK_SEL(x)    (0x01ac + ((x) * 0x8))  /* 8254 clock select */
 191#define LAS0_8254_GATE_SEL(x)   (0x01b0 + ((x) * 0x8))  /* 8254 gate select */
 192#define LAS0_UOUT0_SELECT       0x01c4  /* User Output 0 source select */
 193#define LAS0_UOUT1_SELECT       0x01c8  /* User Output 1 source select */
 194#define LAS0_DMA0_RESET         0x01cc  /* DMA0 Request state machine reset */
 195#define LAS0_DMA1_RESET         0x01d0  /* DMA1 Request state machine reset */
 196
 197/*
 198 * Local Address Space 1 Offsets
 199 */
 200#define LAS1_ADC_FIFO           0x0000  /* A/D FIFO (16bit) */
 201#define LAS1_HDIO_FIFO          0x0004  /* HiSpd DI FIFO (16bit) */
 202#define LAS1_DAC_FIFO(x)        (0x0008 + ((x) * 0x4))  /* D/Ax FIFO (16bit) */
 203
 204/*
 205 * Driver specific stuff (tunable)
 206 */
 207
 208/*
 209 * We really only need 2 buffers.  More than that means being much
 210 * smarter about knowing which ones are full.
 211 */
 212#define DMA_CHAIN_COUNT 2       /* max DMA segments/buffers in a ring (min 2) */
 213
 214/* Target period for periodic transfers.  This sets the user read latency. */
 215/* Note: There are certain rates where we give this up and transfer 1/2 FIFO */
 216/* If this is too low, efficiency is poor */
 217#define TRANS_TARGET_PERIOD 10000000    /* 10 ms (in nanoseconds) */
 218
 219/* Set a practical limit on how long a list to support (affects memory use) */
 220/* The board support a channel list up to the FIFO length (1K or 8K) */
 221#define RTD_MAX_CHANLIST        128     /* max channel list that we allow */
 222
 223/*
 224 * Board specific stuff
 225 */
 226
 227#define RTD_CLOCK_RATE  8000000 /* 8Mhz onboard clock */
 228#define RTD_CLOCK_BASE  125     /* clock period in ns */
 229
 230/* Note: these speed are slower than the spec, but fit the counter resolution*/
 231#define RTD_MAX_SPEED   1625    /* when sampling, in nanoseconds */
 232/* max speed if we don't have to wait for settling */
 233#define RTD_MAX_SPEED_1 875     /* if single channel, in nanoseconds */
 234
 235#define RTD_MIN_SPEED   2097151875      /* (24bit counter) in nanoseconds */
 236/* min speed when only 1 channel (no burst counter) */
 237#define RTD_MIN_SPEED_1 5000000 /* 200Hz, in nanoseconds */
 238
 239/* Setup continuous ring of 1/2 FIFO transfers.  See RTD manual p91 */
 240#define DMA_MODE_BITS (\
 241                       PLX_LOCAL_BUS_16_WIDE_BITS \
 242                       | PLX_DMA_EN_READYIN_BIT \
 243                       | PLX_DMA_LOCAL_BURST_EN_BIT \
 244                       | PLX_EN_CHAIN_BIT \
 245                       | PLX_DMA_INTR_PCI_BIT \
 246                       | PLX_LOCAL_ADDR_CONST_BIT \
 247                       | PLX_DEMAND_MODE_BIT)
 248
 249#define DMA_TRANSFER_BITS (\
 250/* descriptors in PCI memory*/  PLX_DESC_IN_PCI_BIT \
 251/* interrupt at end of block */ | PLX_INTR_TERM_COUNT \
 252/* from board to PCI */         | PLX_XFER_LOCAL_TO_PCI)
 253
 254/*
 255 * Comedi specific stuff
 256 */
 257
 258/*
 259 * The board has 3 input modes and the gains of 1,2,4,...32 (, 64, 128)
 260 */
 261static const struct comedi_lrange rtd_ai_7520_range = {
 262        18, {
 263                /* +-5V input range gain steps */
 264                BIP_RANGE(5.0),
 265                BIP_RANGE(5.0 / 2),
 266                BIP_RANGE(5.0 / 4),
 267                BIP_RANGE(5.0 / 8),
 268                BIP_RANGE(5.0 / 16),
 269                BIP_RANGE(5.0 / 32),
 270                /* +-10V input range gain steps */
 271                BIP_RANGE(10.0),
 272                BIP_RANGE(10.0 / 2),
 273                BIP_RANGE(10.0 / 4),
 274                BIP_RANGE(10.0 / 8),
 275                BIP_RANGE(10.0 / 16),
 276                BIP_RANGE(10.0 / 32),
 277                /* +10V input range gain steps */
 278                UNI_RANGE(10.0),
 279                UNI_RANGE(10.0 / 2),
 280                UNI_RANGE(10.0 / 4),
 281                UNI_RANGE(10.0 / 8),
 282                UNI_RANGE(10.0 / 16),
 283                UNI_RANGE(10.0 / 32),
 284        }
 285};
 286
 287/* PCI4520 has two more gains (6 more entries) */
 288static const struct comedi_lrange rtd_ai_4520_range = {
 289        24, {
 290                /* +-5V input range gain steps */
 291                BIP_RANGE(5.0),
 292                BIP_RANGE(5.0 / 2),
 293                BIP_RANGE(5.0 / 4),
 294                BIP_RANGE(5.0 / 8),
 295                BIP_RANGE(5.0 / 16),
 296                BIP_RANGE(5.0 / 32),
 297                BIP_RANGE(5.0 / 64),
 298                BIP_RANGE(5.0 / 128),
 299                /* +-10V input range gain steps */
 300                BIP_RANGE(10.0),
 301                BIP_RANGE(10.0 / 2),
 302                BIP_RANGE(10.0 / 4),
 303                BIP_RANGE(10.0 / 8),
 304                BIP_RANGE(10.0 / 16),
 305                BIP_RANGE(10.0 / 32),
 306                BIP_RANGE(10.0 / 64),
 307                BIP_RANGE(10.0 / 128),
 308                /* +10V input range gain steps */
 309                UNI_RANGE(10.0),
 310                UNI_RANGE(10.0 / 2),
 311                UNI_RANGE(10.0 / 4),
 312                UNI_RANGE(10.0 / 8),
 313                UNI_RANGE(10.0 / 16),
 314                UNI_RANGE(10.0 / 32),
 315                UNI_RANGE(10.0 / 64),
 316                UNI_RANGE(10.0 / 128),
 317        }
 318};
 319
 320/* Table order matches range values */
 321static const struct comedi_lrange rtd_ao_range = {
 322        4, {
 323                UNI_RANGE(5),
 324                UNI_RANGE(10),
 325                BIP_RANGE(5),
 326                BIP_RANGE(10),
 327        }
 328};
 329
 330enum rtd_boardid {
 331        BOARD_DM7520,
 332        BOARD_PCI4520,
 333};
 334
 335struct rtd_boardinfo {
 336        const char *name;
 337        int range_bip10;        /* start of +-10V range */
 338        int range_uni10;        /* start of +10V range */
 339        const struct comedi_lrange *ai_range;
 340};
 341
 342static const struct rtd_boardinfo rtd520_boards[] = {
 343        [BOARD_DM7520] = {
 344                .name           = "DM7520",
 345                .range_bip10    = 6,
 346                .range_uni10    = 12,
 347                .ai_range       = &rtd_ai_7520_range,
 348        },
 349        [BOARD_PCI4520] = {
 350                .name           = "PCI4520",
 351                .range_bip10    = 8,
 352                .range_uni10    = 16,
 353                .ai_range       = &rtd_ai_4520_range,
 354        },
 355};
 356
 357struct rtd_private {
 358        /* memory mapped board structures */
 359        void __iomem *las1;
 360        void __iomem *lcfg;
 361
 362        long ai_count;          /* total transfer size (samples) */
 363        int xfer_count;         /* # to transfer data. 0->1/2FIFO */
 364        int flags;              /* flag event modes */
 365        unsigned int fifosz;
 366
 367        /* 8254 Timer/Counter gate and clock sources */
 368        unsigned char timer_gate_src[3];
 369        unsigned char timer_clk_src[3];
 370};
 371
 372/* bit defines for "flags" */
 373#define SEND_EOS        0x01    /* send End Of Scan events */
 374#define DMA0_ACTIVE     0x02    /* DMA0 is active */
 375#define DMA1_ACTIVE     0x04    /* DMA1 is active */
 376
 377/*
 378 * Given a desired period and the clock period (both in ns), return the
 379 * proper counter value (divider-1). Sets the original period to be the
 380 * true value.
 381 * Note: you have to check if the value is larger than the counter range!
 382 */
 383static int rtd_ns_to_timer_base(unsigned int *nanosec,
 384                                unsigned int flags, int base)
 385{
 386        int divider;
 387
 388        switch (flags & CMDF_ROUND_MASK) {
 389        case CMDF_ROUND_NEAREST:
 390        default:
 391                divider = DIV_ROUND_CLOSEST(*nanosec, base);
 392                break;
 393        case CMDF_ROUND_DOWN:
 394                divider = (*nanosec) / base;
 395                break;
 396        case CMDF_ROUND_UP:
 397                divider = DIV_ROUND_UP(*nanosec, base);
 398                break;
 399        }
 400        if (divider < 2)
 401                divider = 2;    /* min is divide by 2 */
 402
 403        /*
 404         * Note: we don't check for max, because different timers
 405         * have different ranges
 406         */
 407
 408        *nanosec = base * divider;
 409        return divider - 1;     /* countdown is divisor+1 */
 410}
 411
 412/*
 413 * Given a desired period (in ns), return the proper counter value
 414 * (divider-1) for the internal clock. Sets the original period to
 415 * be the true value.
 416 */
 417static int rtd_ns_to_timer(unsigned int *ns, unsigned int flags)
 418{
 419        return rtd_ns_to_timer_base(ns, flags, RTD_CLOCK_BASE);
 420}
 421
 422/* Convert a single comedi channel-gain entry to a RTD520 table entry */
 423static unsigned short rtd_convert_chan_gain(struct comedi_device *dev,
 424                                            unsigned int chanspec, int index)
 425{
 426        const struct rtd_boardinfo *board = dev->board_ptr;
 427        unsigned int chan = CR_CHAN(chanspec);
 428        unsigned int range = CR_RANGE(chanspec);
 429        unsigned int aref = CR_AREF(chanspec);
 430        unsigned short r = 0;
 431
 432        r |= chan & 0xf;
 433
 434        /* Note: we also setup the channel list bipolar flag array */
 435        if (range < board->range_bip10) {
 436                /* +-5 range */
 437                r |= 0x000;
 438                r |= (range & 0x7) << 4;
 439        } else if (range < board->range_uni10) {
 440                /* +-10 range */
 441                r |= 0x100;
 442                r |= ((range - board->range_bip10) & 0x7) << 4;
 443        } else {
 444                /* +10 range */
 445                r |= 0x200;
 446                r |= ((range - board->range_uni10) & 0x7) << 4;
 447        }
 448
 449        switch (aref) {
 450        case AREF_GROUND:       /* on-board ground */
 451                break;
 452
 453        case AREF_COMMON:
 454                r |= 0x80;      /* ref external analog common */
 455                break;
 456
 457        case AREF_DIFF:
 458                r |= 0x400;     /* differential inputs */
 459                break;
 460
 461        case AREF_OTHER:        /* ??? */
 462                break;
 463        }
 464        return r;
 465}
 466
 467/* Setup the channel-gain table from a comedi list */
 468static void rtd_load_channelgain_list(struct comedi_device *dev,
 469                                      unsigned int n_chan, unsigned int *list)
 470{
 471        if (n_chan > 1) {       /* setup channel gain table */
 472                int ii;
 473
 474                writel(0, dev->mmio + LAS0_CGT_CLEAR);
 475                writel(1, dev->mmio + LAS0_CGT_ENABLE);
 476                for (ii = 0; ii < n_chan; ii++) {
 477                        writel(rtd_convert_chan_gain(dev, list[ii], ii),
 478                               dev->mmio + LAS0_CGT_WRITE);
 479                }
 480        } else {                /* just use the channel gain latch */
 481                writel(0, dev->mmio + LAS0_CGT_ENABLE);
 482                writel(rtd_convert_chan_gain(dev, list[0], 0),
 483                       dev->mmio + LAS0_CGL_WRITE);
 484        }
 485}
 486
 487/*
 488 * Determine fifo size by doing adc conversions until the fifo half
 489 * empty status flag clears.
 490 */
 491static int rtd520_probe_fifo_depth(struct comedi_device *dev)
 492{
 493        unsigned int chanspec = CR_PACK(0, 0, AREF_GROUND);
 494        unsigned int i;
 495        static const unsigned int limit = 0x2000;
 496        unsigned int fifo_size = 0;
 497
 498        writel(0, dev->mmio + LAS0_ADC_FIFO_CLEAR);
 499        rtd_load_channelgain_list(dev, 1, &chanspec);
 500        /* ADC conversion trigger source: SOFTWARE */
 501        writel(0, dev->mmio + LAS0_ADC_CONVERSION);
 502        /* convert  samples */
 503        for (i = 0; i < limit; ++i) {
 504                unsigned int fifo_status;
 505                /* trigger conversion */
 506                writew(0, dev->mmio + LAS0_ADC);
 507                usleep_range(1, 1000);
 508                fifo_status = readl(dev->mmio + LAS0_ADC);
 509                if ((fifo_status & FS_ADC_HEMPTY) == 0) {
 510                        fifo_size = 2 * i;
 511                        break;
 512                }
 513        }
 514        if (i == limit) {
 515                dev_info(dev->class_dev, "failed to probe fifo size.\n");
 516                return -EIO;
 517        }
 518        writel(0, dev->mmio + LAS0_ADC_FIFO_CLEAR);
 519        if (fifo_size != 0x400 && fifo_size != 0x2000) {
 520                dev_info(dev->class_dev,
 521                         "unexpected fifo size of %i, expected 1024 or 8192.\n",
 522                         fifo_size);
 523                return -EIO;
 524        }
 525        return fifo_size;
 526}
 527
 528static int rtd_ai_eoc(struct comedi_device *dev,
 529                      struct comedi_subdevice *s,
 530                      struct comedi_insn *insn,
 531                      unsigned long context)
 532{
 533        unsigned int status;
 534
 535        status = readl(dev->mmio + LAS0_ADC);
 536        if (status & FS_ADC_NOT_EMPTY)
 537                return 0;
 538        return -EBUSY;
 539}
 540
 541static int rtd_ai_rinsn(struct comedi_device *dev,
 542                        struct comedi_subdevice *s, struct comedi_insn *insn,
 543                        unsigned int *data)
 544{
 545        struct rtd_private *devpriv = dev->private;
 546        unsigned int range = CR_RANGE(insn->chanspec);
 547        int ret;
 548        int n;
 549
 550        /* clear any old fifo data */
 551        writel(0, dev->mmio + LAS0_ADC_FIFO_CLEAR);
 552
 553        /* write channel to multiplexer and clear channel gain table */
 554        rtd_load_channelgain_list(dev, 1, &insn->chanspec);
 555
 556        /* ADC conversion trigger source: SOFTWARE */
 557        writel(0, dev->mmio + LAS0_ADC_CONVERSION);
 558
 559        /* convert n samples */
 560        for (n = 0; n < insn->n; n++) {
 561                unsigned short d;
 562                /* trigger conversion */
 563                writew(0, dev->mmio + LAS0_ADC);
 564
 565                ret = comedi_timeout(dev, s, insn, rtd_ai_eoc, 0);
 566                if (ret)
 567                        return ret;
 568
 569                /* read data */
 570                d = readw(devpriv->las1 + LAS1_ADC_FIFO);
 571                d >>= 3;        /* low 3 bits are marker lines */
 572
 573                /* convert bipolar data to comedi unsigned data */
 574                if (comedi_range_is_bipolar(s, range))
 575                        d = comedi_offset_munge(s, d);
 576
 577                data[n] = d & s->maxdata;
 578        }
 579
 580        /* return the number of samples read/written */
 581        return n;
 582}
 583
 584static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s,
 585                     int count)
 586{
 587        struct rtd_private *devpriv = dev->private;
 588        struct comedi_async *async = s->async;
 589        struct comedi_cmd *cmd = &async->cmd;
 590        int ii;
 591
 592        for (ii = 0; ii < count; ii++) {
 593                unsigned int range = CR_RANGE(cmd->chanlist[async->cur_chan]);
 594                unsigned short d;
 595
 596                if (devpriv->ai_count == 0) {   /* done */
 597                        d = readw(devpriv->las1 + LAS1_ADC_FIFO);
 598                        continue;
 599                }
 600
 601                d = readw(devpriv->las1 + LAS1_ADC_FIFO);
 602                d >>= 3;        /* low 3 bits are marker lines */
 603
 604                /* convert bipolar data to comedi unsigned data */
 605                if (comedi_range_is_bipolar(s, range))
 606                        d = comedi_offset_munge(s, d);
 607                d &= s->maxdata;
 608
 609                if (!comedi_buf_write_samples(s, &d, 1))
 610                        return -1;
 611
 612                if (devpriv->ai_count > 0)      /* < 0, means read forever */
 613                        devpriv->ai_count--;
 614        }
 615        return 0;
 616}
 617
 618static irqreturn_t rtd_interrupt(int irq, void *d)
 619{
 620        struct comedi_device *dev = d;
 621        struct comedi_subdevice *s = dev->read_subdev;
 622        struct rtd_private *devpriv = dev->private;
 623        u32 overrun;
 624        u16 status;
 625        u16 fifo_status;
 626
 627        if (!dev->attached)
 628                return IRQ_NONE;
 629
 630        fifo_status = readl(dev->mmio + LAS0_ADC);
 631        /* check for FIFO full, this automatically halts the ADC! */
 632        if (!(fifo_status & FS_ADC_NOT_FULL))   /* 0 -> full */
 633                goto xfer_abort;
 634
 635        status = readw(dev->mmio + LAS0_IT);
 636        /* if interrupt was not caused by our board, or handled above */
 637        if (status == 0)
 638                return IRQ_HANDLED;
 639
 640        if (status & IRQM_ADC_ABOUT_CNT) {      /* sample count -> read FIFO */
 641                /*
 642                 * since the priority interrupt controller may have queued
 643                 * a sample counter interrupt, even though we have already
 644                 * finished, we must handle the possibility that there is
 645                 * no data here
 646                 */
 647                if (!(fifo_status & FS_ADC_HEMPTY)) {
 648                        /* FIFO half full */
 649                        if (ai_read_n(dev, s, devpriv->fifosz / 2) < 0)
 650                                goto xfer_abort;
 651
 652                        if (devpriv->ai_count == 0)
 653                                goto xfer_done;
 654                } else if (devpriv->xfer_count > 0) {
 655                        if (fifo_status & FS_ADC_NOT_EMPTY) {
 656                                /* FIFO not empty */
 657                                if (ai_read_n(dev, s, devpriv->xfer_count) < 0)
 658                                        goto xfer_abort;
 659
 660                                if (devpriv->ai_count == 0)
 661                                        goto xfer_done;
 662                        }
 663                }
 664        }
 665
 666        overrun = readl(dev->mmio + LAS0_OVERRUN) & 0xffff;
 667        if (overrun)
 668                goto xfer_abort;
 669
 670        /* clear the interrupt */
 671        writew(status, dev->mmio + LAS0_CLEAR);
 672        readw(dev->mmio + LAS0_CLEAR);
 673
 674        comedi_handle_events(dev, s);
 675
 676        return IRQ_HANDLED;
 677
 678xfer_abort:
 679        s->async->events |= COMEDI_CB_ERROR;
 680
 681xfer_done:
 682        s->async->events |= COMEDI_CB_EOA;
 683
 684        /* clear the interrupt */
 685        status = readw(dev->mmio + LAS0_IT);
 686        writew(status, dev->mmio + LAS0_CLEAR);
 687        readw(dev->mmio + LAS0_CLEAR);
 688
 689        fifo_status = readl(dev->mmio + LAS0_ADC);
 690        overrun = readl(dev->mmio + LAS0_OVERRUN) & 0xffff;
 691
 692        comedi_handle_events(dev, s);
 693
 694        return IRQ_HANDLED;
 695}
 696
 697static int rtd_ai_cmdtest(struct comedi_device *dev,
 698                          struct comedi_subdevice *s, struct comedi_cmd *cmd)
 699{
 700        int err = 0;
 701        unsigned int arg;
 702
 703        /* Step 1 : check if triggers are trivially valid */
 704
 705        err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
 706        err |= comedi_check_trigger_src(&cmd->scan_begin_src,
 707                                        TRIG_TIMER | TRIG_EXT);
 708        err |= comedi_check_trigger_src(&cmd->convert_src,
 709                                        TRIG_TIMER | TRIG_EXT);
 710        err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
 711        err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 712
 713        if (err)
 714                return 1;
 715
 716        /* Step 2a : make sure trigger sources are unique */
 717
 718        err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
 719        err |= comedi_check_trigger_is_unique(cmd->convert_src);
 720        err |= comedi_check_trigger_is_unique(cmd->stop_src);
 721
 722        /* Step 2b : and mutually compatible */
 723
 724        if (err)
 725                return 2;
 726
 727        /* Step 3: check if arguments are trivially valid */
 728
 729        err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
 730
 731        if (cmd->scan_begin_src == TRIG_TIMER) {
 732                /* Note: these are time periods, not actual rates */
 733                if (cmd->chanlist_len == 1) {   /* no scanning */
 734                        if (comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
 735                                                         RTD_MAX_SPEED_1)) {
 736                                rtd_ns_to_timer(&cmd->scan_begin_arg,
 737                                                CMDF_ROUND_UP);
 738                                err |= -EINVAL;
 739                        }
 740                        if (comedi_check_trigger_arg_max(&cmd->scan_begin_arg,
 741                                                         RTD_MIN_SPEED_1)) {
 742                                rtd_ns_to_timer(&cmd->scan_begin_arg,
 743                                                CMDF_ROUND_DOWN);
 744                                err |= -EINVAL;
 745                        }
 746                } else {
 747                        if (comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
 748                                                         RTD_MAX_SPEED)) {
 749                                rtd_ns_to_timer(&cmd->scan_begin_arg,
 750                                                CMDF_ROUND_UP);
 751                                err |= -EINVAL;
 752                        }
 753                        if (comedi_check_trigger_arg_max(&cmd->scan_begin_arg,
 754                                                         RTD_MIN_SPEED)) {
 755                                rtd_ns_to_timer(&cmd->scan_begin_arg,
 756                                                CMDF_ROUND_DOWN);
 757                                err |= -EINVAL;
 758                        }
 759                }
 760        } else {
 761                /* external trigger */
 762                /* should be level/edge, hi/lo specification here */
 763                /* should specify multiple external triggers */
 764                err |= comedi_check_trigger_arg_max(&cmd->scan_begin_arg, 9);
 765        }
 766
 767        if (cmd->convert_src == TRIG_TIMER) {
 768                if (cmd->chanlist_len == 1) {   /* no scanning */
 769                        if (comedi_check_trigger_arg_min(&cmd->convert_arg,
 770                                                         RTD_MAX_SPEED_1)) {
 771                                rtd_ns_to_timer(&cmd->convert_arg,
 772                                                CMDF_ROUND_UP);
 773                                err |= -EINVAL;
 774                        }
 775                        if (comedi_check_trigger_arg_max(&cmd->convert_arg,
 776                                                         RTD_MIN_SPEED_1)) {
 777                                rtd_ns_to_timer(&cmd->convert_arg,
 778                                                CMDF_ROUND_DOWN);
 779                                err |= -EINVAL;
 780                        }
 781                } else {
 782                        if (comedi_check_trigger_arg_min(&cmd->convert_arg,
 783                                                         RTD_MAX_SPEED)) {
 784                                rtd_ns_to_timer(&cmd->convert_arg,
 785                                                CMDF_ROUND_UP);
 786                                err |= -EINVAL;
 787                        }
 788                        if (comedi_check_trigger_arg_max(&cmd->convert_arg,
 789                                                         RTD_MIN_SPEED)) {
 790                                rtd_ns_to_timer(&cmd->convert_arg,
 791                                                CMDF_ROUND_DOWN);
 792                                err |= -EINVAL;
 793                        }
 794                }
 795        } else {
 796                /* external trigger */
 797                /* see above */
 798                err |= comedi_check_trigger_arg_max(&cmd->convert_arg, 9);
 799        }
 800
 801        err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
 802                                           cmd->chanlist_len);
 803
 804        if (cmd->stop_src == TRIG_COUNT)
 805                err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
 806        else    /* TRIG_NONE */
 807                err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
 808
 809        if (err)
 810                return 3;
 811
 812        /* step 4: fix up any arguments */
 813
 814        if (cmd->scan_begin_src == TRIG_TIMER) {
 815                arg = cmd->scan_begin_arg;
 816                rtd_ns_to_timer(&arg, cmd->flags);
 817                err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
 818        }
 819
 820        if (cmd->convert_src == TRIG_TIMER) {
 821                arg = cmd->convert_arg;
 822                rtd_ns_to_timer(&arg, cmd->flags);
 823                err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
 824
 825                if (cmd->scan_begin_src == TRIG_TIMER) {
 826                        arg = cmd->convert_arg * cmd->scan_end_arg;
 827                        err |= comedi_check_trigger_arg_min(&cmd->
 828                                                            scan_begin_arg,
 829                                                            arg);
 830                }
 831        }
 832
 833        if (err)
 834                return 4;
 835
 836        return 0;
 837}
 838
 839static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 840{
 841        struct rtd_private *devpriv = dev->private;
 842        struct comedi_cmd *cmd = &s->async->cmd;
 843        int timer;
 844
 845        /* stop anything currently running */
 846        /* pacer stop source: SOFTWARE */
 847        writel(0, dev->mmio + LAS0_PACER_STOP);
 848        writel(0, dev->mmio + LAS0_PACER);      /* stop pacer */
 849        writel(0, dev->mmio + LAS0_ADC_CONVERSION);
 850        writew(0, dev->mmio + LAS0_IT);
 851        writel(0, dev->mmio + LAS0_ADC_FIFO_CLEAR);
 852        writel(0, dev->mmio + LAS0_OVERRUN);
 853
 854        /* start configuration */
 855        /* load channel list and reset CGT */
 856        rtd_load_channelgain_list(dev, cmd->chanlist_len, cmd->chanlist);
 857
 858        /* setup the common case and override if needed */
 859        if (cmd->chanlist_len > 1) {
 860                /* pacer start source: SOFTWARE */
 861                writel(0, dev->mmio + LAS0_PACER_START);
 862                /* burst trigger source: PACER */
 863                writel(1, dev->mmio + LAS0_BURST_START);
 864                /* ADC conversion trigger source: BURST */
 865                writel(2, dev->mmio + LAS0_ADC_CONVERSION);
 866        } else {                /* single channel */
 867                /* pacer start source: SOFTWARE */
 868                writel(0, dev->mmio + LAS0_PACER_START);
 869                /* ADC conversion trigger source: PACER */
 870                writel(1, dev->mmio + LAS0_ADC_CONVERSION);
 871        }
 872        writel((devpriv->fifosz / 2 - 1) & 0xffff, dev->mmio + LAS0_ACNT);
 873
 874        if (cmd->scan_begin_src == TRIG_TIMER) {
 875                /* scan_begin_arg is in nanoseconds */
 876                /* find out how many samples to wait before transferring */
 877                if (cmd->flags & CMDF_WAKE_EOS) {
 878                        /*
 879                         * this may generate un-sustainable interrupt rates
 880                         * the application is responsible for doing the
 881                         * right thing
 882                         */
 883                        devpriv->xfer_count = cmd->chanlist_len;
 884                        devpriv->flags |= SEND_EOS;
 885                } else {
 886                        /* arrange to transfer data periodically */
 887                        devpriv->xfer_count =
 888                            (TRANS_TARGET_PERIOD * cmd->chanlist_len) /
 889                            cmd->scan_begin_arg;
 890                        if (devpriv->xfer_count < cmd->chanlist_len) {
 891                                /* transfer after each scan (and avoid 0) */
 892                                devpriv->xfer_count = cmd->chanlist_len;
 893                        } else {        /* make a multiple of scan length */
 894                                devpriv->xfer_count =
 895                                    DIV_ROUND_UP(devpriv->xfer_count,
 896                                                 cmd->chanlist_len);
 897                                devpriv->xfer_count *= cmd->chanlist_len;
 898                        }
 899                        devpriv->flags |= SEND_EOS;
 900                }
 901                if (devpriv->xfer_count >= (devpriv->fifosz / 2)) {
 902                        /* out of counter range, use 1/2 fifo instead */
 903                        devpriv->xfer_count = 0;
 904                        devpriv->flags &= ~SEND_EOS;
 905                } else {
 906                        /* interrupt for each transfer */
 907                        writel((devpriv->xfer_count - 1) & 0xffff,
 908                               dev->mmio + LAS0_ACNT);
 909                }
 910        } else {                /* unknown timing, just use 1/2 FIFO */
 911                devpriv->xfer_count = 0;
 912                devpriv->flags &= ~SEND_EOS;
 913        }
 914        /* pacer clock source: INTERNAL 8MHz */
 915        writel(1, dev->mmio + LAS0_PACER_SELECT);
 916        /* just interrupt, don't stop */
 917        writel(1, dev->mmio + LAS0_ACNT_STOP_ENABLE);
 918
 919        /* BUG??? these look like enumerated values, but they are bit fields */
 920
 921        /* First, setup when to stop */
 922        switch (cmd->stop_src) {
 923        case TRIG_COUNT:        /* stop after N scans */
 924                devpriv->ai_count = cmd->stop_arg * cmd->chanlist_len;
 925                if ((devpriv->xfer_count > 0) &&
 926                    (devpriv->xfer_count > devpriv->ai_count)) {
 927                        devpriv->xfer_count = devpriv->ai_count;
 928                }
 929                break;
 930
 931        case TRIG_NONE: /* stop when cancel is called */
 932                devpriv->ai_count = -1; /* read forever */
 933                break;
 934        }
 935
 936        /* Scan timing */
 937        switch (cmd->scan_begin_src) {
 938        case TRIG_TIMER:        /* periodic scanning */
 939                timer = rtd_ns_to_timer(&cmd->scan_begin_arg,
 940                                        CMDF_ROUND_NEAREST);
 941                /* set PACER clock */
 942                writel(timer & 0xffffff, dev->mmio + LAS0_PCLK);
 943
 944                break;
 945
 946        case TRIG_EXT:
 947                /* pacer start source: EXTERNAL */
 948                writel(1, dev->mmio + LAS0_PACER_START);
 949                break;
 950        }
 951
 952        /* Sample timing within a scan */
 953        switch (cmd->convert_src) {
 954        case TRIG_TIMER:        /* periodic */
 955                if (cmd->chanlist_len > 1) {
 956                        /* only needed for multi-channel */
 957                        timer = rtd_ns_to_timer(&cmd->convert_arg,
 958                                                CMDF_ROUND_NEAREST);
 959                        /* setup BURST clock */
 960                        writel(timer & 0x3ff, dev->mmio + LAS0_BCLK);
 961                }
 962
 963                break;
 964
 965        case TRIG_EXT:          /* external */
 966                /* burst trigger source: EXTERNAL */
 967                writel(2, dev->mmio + LAS0_BURST_START);
 968                break;
 969        }
 970        /* end configuration */
 971
 972        /*
 973         * This doesn't seem to work.  There is no way to clear an interrupt
 974         * that the priority controller has queued!
 975         */
 976        writew(~0, dev->mmio + LAS0_CLEAR);
 977        readw(dev->mmio + LAS0_CLEAR);
 978
 979        /* TODO: allow multiple interrupt sources */
 980        /* transfer every N samples */
 981        writew(IRQM_ADC_ABOUT_CNT, dev->mmio + LAS0_IT);
 982
 983        /* BUG: start_src is ASSUMED to be TRIG_NOW */
 984        /* BUG? it seems like things are running before the "start" */
 985        readl(dev->mmio + LAS0_PACER);  /* start pacer */
 986        return 0;
 987}
 988
 989static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 990{
 991        struct rtd_private *devpriv = dev->private;
 992
 993        /* pacer stop source: SOFTWARE */
 994        writel(0, dev->mmio + LAS0_PACER_STOP);
 995        writel(0, dev->mmio + LAS0_PACER);      /* stop pacer */
 996        writel(0, dev->mmio + LAS0_ADC_CONVERSION);
 997        writew(0, dev->mmio + LAS0_IT);
 998        devpriv->ai_count = 0;  /* stop and don't transfer any more */
 999        writel(0, dev->mmio + LAS0_ADC_FIFO_CLEAR);
1000        return 0;
1001}
1002
1003static int rtd_ao_eoc(struct comedi_device *dev,
1004                      struct comedi_subdevice *s,
1005                      struct comedi_insn *insn,
1006                      unsigned long context)
1007{
1008        unsigned int chan = CR_CHAN(insn->chanspec);
1009        unsigned int bit = (chan == 0) ? FS_DAC1_NOT_EMPTY : FS_DAC2_NOT_EMPTY;
1010        unsigned int status;
1011
1012        status = readl(dev->mmio + LAS0_ADC);
1013        if (status & bit)
1014                return 0;
1015        return -EBUSY;
1016}
1017
1018static int rtd_ao_insn_write(struct comedi_device *dev,
1019                             struct comedi_subdevice *s,
1020                             struct comedi_insn *insn,
1021                             unsigned int *data)
1022{
1023        struct rtd_private *devpriv = dev->private;
1024        unsigned int chan = CR_CHAN(insn->chanspec);
1025        unsigned int range = CR_RANGE(insn->chanspec);
1026        int ret;
1027        int i;
1028
1029        /* Configure the output range (table index matches the range values) */
1030        writew(range & 7, dev->mmio + LAS0_DAC_CTRL(chan));
1031
1032        for (i = 0; i < insn->n; ++i) {
1033                unsigned int val = data[i];
1034
1035                /* bipolar uses 2's complement values with an extended sign */
1036                if (comedi_range_is_bipolar(s, range)) {
1037                        val = comedi_offset_munge(s, val);
1038                        val |= (val & ((s->maxdata + 1) >> 1)) << 1;
1039                }
1040
1041                /* shift the 12-bit data (+ sign) to match the register */
1042                val <<= 3;
1043
1044                writew(val, devpriv->las1 + LAS1_DAC_FIFO(chan));
1045                writew(0, dev->mmio + LAS0_UPDATE_DAC(chan));
1046
1047                ret = comedi_timeout(dev, s, insn, rtd_ao_eoc, 0);
1048                if (ret)
1049                        return ret;
1050
1051                s->readback[chan] = data[i];
1052        }
1053
1054        return insn->n;
1055}
1056
1057static int rtd_dio_insn_bits(struct comedi_device *dev,
1058                             struct comedi_subdevice *s,
1059                             struct comedi_insn *insn,
1060                             unsigned int *data)
1061{
1062        if (comedi_dio_update_state(s, data))
1063                writew(s->state & 0xff, dev->mmio + LAS0_DIO0);
1064
1065        data[1] = readw(dev->mmio + LAS0_DIO0) & 0xff;
1066
1067        return insn->n;
1068}
1069
1070static int rtd_dio_insn_config(struct comedi_device *dev,
1071                               struct comedi_subdevice *s,
1072                               struct comedi_insn *insn,
1073                               unsigned int *data)
1074{
1075        int ret;
1076
1077        ret = comedi_dio_insn_config(dev, s, insn, data, 0);
1078        if (ret)
1079                return ret;
1080
1081        /* TODO support digital match interrupts and strobes */
1082
1083        /* set direction */
1084        writew(0x01, dev->mmio + LAS0_DIO_STATUS);
1085        writew(s->io_bits & 0xff, dev->mmio + LAS0_DIO0_CTRL);
1086
1087        /* clear interrupts */
1088        writew(0x00, dev->mmio + LAS0_DIO_STATUS);
1089
1090        /* port1 can only be all input or all output */
1091
1092        /* there are also 2 user input lines and 2 user output lines */
1093
1094        return insn->n;
1095}
1096
1097static int rtd_counter_insn_config(struct comedi_device *dev,
1098                                   struct comedi_subdevice *s,
1099                                   struct comedi_insn *insn,
1100                                   unsigned int *data)
1101{
1102        struct rtd_private *devpriv = dev->private;
1103        unsigned int chan = CR_CHAN(insn->chanspec);
1104        unsigned int max_src;
1105        unsigned int src;
1106
1107        switch (data[0]) {
1108        case INSN_CONFIG_SET_GATE_SRC:
1109                /*
1110                 * 8254 Timer/Counter gate sources:
1111                 *
1112                 * 0 = Not gated, free running (reset state)
1113                 * 1 = Gated, off
1114                 * 2 = Ext. TC Gate 1
1115                 * 3 = Ext. TC Gate 2
1116                 * 4 = Previous TC out (chan 1 and 2 only)
1117                 */
1118                src = data[2];
1119                max_src = (chan == 0) ? 3 : 4;
1120                if (src > max_src)
1121                        return -EINVAL;
1122
1123                devpriv->timer_gate_src[chan] = src;
1124                writeb(src, dev->mmio + LAS0_8254_GATE_SEL(chan));
1125                break;
1126        case INSN_CONFIG_GET_GATE_SRC:
1127                data[2] = devpriv->timer_gate_src[chan];
1128                break;
1129        case INSN_CONFIG_SET_CLOCK_SRC:
1130                /*
1131                 * 8254 Timer/Counter clock sources:
1132                 *
1133                 * 0 = 8 MHz (reset state)
1134                 * 1 = Ext. TC Clock 1
1135                 * 2 = Ext. TX Clock 2
1136                 * 3 = Ext. Pacer Clock
1137                 * 4 = Previous TC out (chan 1 and 2 only)
1138                 * 5 = High-Speed Digital Input Sampling signal (chan 1 only)
1139                 */
1140                src = data[1];
1141                switch (chan) {
1142                case 0:
1143                        max_src = 3;
1144                        break;
1145                case 1:
1146                        max_src = 5;
1147                        break;
1148                case 2:
1149                        max_src = 4;
1150                        break;
1151                default:
1152                        return -EINVAL;
1153                }
1154                if (src > max_src)
1155                        return -EINVAL;
1156
1157                devpriv->timer_clk_src[chan] = src;
1158                writeb(src, dev->mmio + LAS0_8254_CLK_SEL(chan));
1159                break;
1160        case INSN_CONFIG_GET_CLOCK_SRC:
1161                src = devpriv->timer_clk_src[chan];
1162                data[1] = devpriv->timer_clk_src[chan];
1163                data[2] = (src == 0) ? RTD_CLOCK_BASE : 0;
1164                break;
1165        default:
1166                return -EINVAL;
1167        }
1168
1169        return insn->n;
1170}
1171
1172static void rtd_reset(struct comedi_device *dev)
1173{
1174        struct rtd_private *devpriv = dev->private;
1175
1176        writel(0, dev->mmio + LAS0_BOARD_RESET);
1177        usleep_range(100, 1000);        /* needed? */
1178        writel(0, devpriv->lcfg + PLX_REG_INTCSR);
1179        writew(0, dev->mmio + LAS0_IT);
1180        writew(~0, dev->mmio + LAS0_CLEAR);
1181        readw(dev->mmio + LAS0_CLEAR);
1182}
1183
1184/*
1185 * initialize board, per RTD spec
1186 * also, initialize shadow registers
1187 */
1188static void rtd_init_board(struct comedi_device *dev)
1189{
1190        rtd_reset(dev);
1191
1192        writel(0, dev->mmio + LAS0_OVERRUN);
1193        writel(0, dev->mmio + LAS0_CGT_CLEAR);
1194        writel(0, dev->mmio + LAS0_ADC_FIFO_CLEAR);
1195        writel(0, dev->mmio + LAS0_DAC_RESET(0));
1196        writel(0, dev->mmio + LAS0_DAC_RESET(1));
1197        /* clear digital IO fifo */
1198        writew(0, dev->mmio + LAS0_DIO_STATUS);
1199        /* TODO: set user out source ??? */
1200}
1201
1202/* The RTD driver does this */
1203static void rtd_pci_latency_quirk(struct comedi_device *dev,
1204                                  struct pci_dev *pcidev)
1205{
1206        unsigned char pci_latency;
1207
1208        pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency);
1209        if (pci_latency < 32) {
1210                dev_info(dev->class_dev,
1211                         "PCI latency changed from %d to %d\n",
1212                         pci_latency, 32);
1213                pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, 32);
1214        }
1215}
1216
1217static int rtd_auto_attach(struct comedi_device *dev,
1218                           unsigned long context)
1219{
1220        struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1221        const struct rtd_boardinfo *board = NULL;
1222        struct rtd_private *devpriv;
1223        struct comedi_subdevice *s;
1224        int ret;
1225
1226        if (context < ARRAY_SIZE(rtd520_boards))
1227                board = &rtd520_boards[context];
1228        if (!board)
1229                return -ENODEV;
1230        dev->board_ptr = board;
1231        dev->board_name = board->name;
1232
1233        devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1234        if (!devpriv)
1235                return -ENOMEM;
1236
1237        ret = comedi_pci_enable(dev);
1238        if (ret)
1239                return ret;
1240
1241        dev->mmio = pci_ioremap_bar(pcidev, 2);
1242        devpriv->las1 = pci_ioremap_bar(pcidev, 3);
1243        devpriv->lcfg = pci_ioremap_bar(pcidev, 0);
1244        if (!dev->mmio || !devpriv->las1 || !devpriv->lcfg)
1245                return -ENOMEM;
1246
1247        rtd_pci_latency_quirk(dev, pcidev);
1248
1249        if (pcidev->irq) {
1250                ret = request_irq(pcidev->irq, rtd_interrupt, IRQF_SHARED,
1251                                  dev->board_name, dev);
1252                if (ret == 0)
1253                        dev->irq = pcidev->irq;
1254        }
1255
1256        ret = comedi_alloc_subdevices(dev, 4);
1257        if (ret)
1258                return ret;
1259
1260        s = &dev->subdevices[0];
1261        /* analog input subdevice */
1262        s->type         = COMEDI_SUBD_AI;
1263        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF;
1264        s->n_chan       = 16;
1265        s->maxdata      = 0x0fff;
1266        s->range_table  = board->ai_range;
1267        s->len_chanlist = RTD_MAX_CHANLIST;
1268        s->insn_read    = rtd_ai_rinsn;
1269        if (dev->irq) {
1270                dev->read_subdev = s;
1271                s->subdev_flags |= SDF_CMD_READ;
1272                s->do_cmd       = rtd_ai_cmd;
1273                s->do_cmdtest   = rtd_ai_cmdtest;
1274                s->cancel       = rtd_ai_cancel;
1275        }
1276
1277        s = &dev->subdevices[1];
1278        /* analog output subdevice */
1279        s->type         = COMEDI_SUBD_AO;
1280        s->subdev_flags = SDF_WRITABLE;
1281        s->n_chan       = 2;
1282        s->maxdata      = 0x0fff;
1283        s->range_table  = &rtd_ao_range;
1284        s->insn_write   = rtd_ao_insn_write;
1285
1286        ret = comedi_alloc_subdev_readback(s);
1287        if (ret)
1288                return ret;
1289
1290        s = &dev->subdevices[2];
1291        /* digital i/o subdevice */
1292        s->type         = COMEDI_SUBD_DIO;
1293        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1294        /* we only support port 0 right now.  Ignoring port 1 and user IO */
1295        s->n_chan       = 8;
1296        s->maxdata      = 1;
1297        s->range_table  = &range_digital;
1298        s->insn_bits    = rtd_dio_insn_bits;
1299        s->insn_config  = rtd_dio_insn_config;
1300
1301        /* 8254 Timer/Counter subdevice */
1302        s = &dev->subdevices[3];
1303        dev->pacer = comedi_8254_mm_init(dev->mmio + LAS0_8254_TIMER_BASE,
1304                                         RTD_CLOCK_BASE, I8254_IO8, 2);
1305        if (!dev->pacer)
1306                return -ENOMEM;
1307
1308        comedi_8254_subdevice_init(s, dev->pacer);
1309        dev->pacer->insn_config = rtd_counter_insn_config;
1310
1311        rtd_init_board(dev);
1312
1313        ret = rtd520_probe_fifo_depth(dev);
1314        if (ret < 0)
1315                return ret;
1316        devpriv->fifosz = ret;
1317
1318        if (dev->irq)
1319                writel(PLX_INTCSR_PIEN | PLX_INTCSR_PLIEN,
1320                       devpriv->lcfg + PLX_REG_INTCSR);
1321
1322        return 0;
1323}
1324
1325static void rtd_detach(struct comedi_device *dev)
1326{
1327        struct rtd_private *devpriv = dev->private;
1328
1329        if (devpriv) {
1330                /* Shut down any board ops by resetting it */
1331                if (dev->mmio && devpriv->lcfg)
1332                        rtd_reset(dev);
1333                if (dev->irq)
1334                        free_irq(dev->irq, dev);
1335                if (dev->mmio)
1336                        iounmap(dev->mmio);
1337                if (devpriv->las1)
1338                        iounmap(devpriv->las1);
1339                if (devpriv->lcfg)
1340                        iounmap(devpriv->lcfg);
1341        }
1342        comedi_pci_disable(dev);
1343}
1344
1345static struct comedi_driver rtd520_driver = {
1346        .driver_name    = "rtd520",
1347        .module         = THIS_MODULE,
1348        .auto_attach    = rtd_auto_attach,
1349        .detach         = rtd_detach,
1350};
1351
1352static int rtd520_pci_probe(struct pci_dev *dev,
1353                            const struct pci_device_id *id)
1354{
1355        return comedi_pci_auto_config(dev, &rtd520_driver, id->driver_data);
1356}
1357
1358static const struct pci_device_id rtd520_pci_table[] = {
1359        { PCI_VDEVICE(RTD, 0x7520), BOARD_DM7520 },
1360        { PCI_VDEVICE(RTD, 0x4520), BOARD_PCI4520 },
1361        { 0 }
1362};
1363MODULE_DEVICE_TABLE(pci, rtd520_pci_table);
1364
1365static struct pci_driver rtd520_pci_driver = {
1366        .name           = "rtd520",
1367        .id_table       = rtd520_pci_table,
1368        .probe          = rtd520_pci_probe,
1369        .remove         = comedi_pci_auto_unconfig,
1370};
1371module_comedi_pci_driver(rtd520_driver, rtd520_pci_driver);
1372
1373MODULE_AUTHOR("Comedi http://www.comedi.org");
1374MODULE_DESCRIPTION("Comedi low-level driver");
1375MODULE_LICENSE("GPL");
1376