root/drivers/staging/comedi/drivers/rtd520.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rtd_ns_to_timer_base
  2. rtd_ns_to_timer
  3. rtd_convert_chan_gain
  4. rtd_load_channelgain_list
  5. rtd520_probe_fifo_depth
  6. rtd_ai_eoc
  7. rtd_ai_rinsn
  8. ai_read_n
  9. rtd_interrupt
  10. rtd_ai_cmdtest
  11. rtd_ai_cmd
  12. rtd_ai_cancel
  13. rtd_ao_eoc
  14. rtd_ao_insn_write
  15. rtd_dio_insn_bits
  16. rtd_dio_insn_config
  17. rtd_counter_insn_config
  18. rtd_reset
  19. rtd_init_board
  20. rtd_pci_latency_quirk
  21. rtd_auto_attach
  22. rtd_detach
  23. rtd520_pci_probe

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

/* [<][>][^][v][top][bottom][index][help] */