linux/drivers/staging/comedi/drivers/ni_at_ao.c
<<
>>
Prefs
   1/*
   2 * ni_at_ao.c
   3 * Driver for NI AT-AO-6/10 boards
   4 *
   5 * COMEDI - Linux Control and Measurement Device Interface
   6 * Copyright (C) 2000,2002 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: ni_at_ao
  21 * Description: National Instruments AT-AO-6/10
  22 * Devices: [National Instruments] AT-AO-6 (at-ao-6), AT-AO-10 (at-ao-10)
  23 * Status: should work
  24 * Author: David A. Schleef <ds@schleef.org>
  25 * Updated: Sun Dec 26 12:26:28 EST 2004
  26 *
  27 * Configuration options:
  28 *   [0] - I/O port base address
  29 *   [1] - IRQ (unused)
  30 *   [2] - DMA (unused)
  31 *   [3] - analog output range, set by jumpers on hardware
  32 *         0 for -10 to 10V bipolar
  33 *         1 for 0V to 10V unipolar
  34 */
  35
  36#include <linux/module.h>
  37
  38#include "../comedidev.h"
  39
  40#include "comedi_8254.h"
  41
  42/*
  43 * Register map
  44 *
  45 * Register-level programming information can be found in NI
  46 * document 320379.pdf.
  47 */
  48#define ATAO_DIO_REG            0x00
  49#define ATAO_CFG2_REG           0x02
  50#define ATAO_CFG2_CALLD_NOP     (0 << 14)
  51#define ATAO_CFG2_CALLD(x)      ((((x) >> 3) + 1) << 14)
  52#define ATAO_CFG2_FFRTEN        (1 << 13)
  53#define ATAO_CFG2_DACS(x)       (1 << (((x) / 2) + 8))
  54#define ATAO_CFG2_LDAC(x)       (1 << (((x) / 2) + 3))
  55#define ATAO_CFG2_PROMEN        (1 << 2)
  56#define ATAO_CFG2_SCLK          (1 << 1)
  57#define ATAO_CFG2_SDATA         (1 << 0)
  58#define ATAO_CFG3_REG           0x04
  59#define ATAO_CFG3_DMAMODE       (1 << 6)
  60#define ATAO_CFG3_CLKOUT        (1 << 5)
  61#define ATAO_CFG3_RCLKEN        (1 << 4)
  62#define ATAO_CFG3_DOUTEN2       (1 << 3)
  63#define ATAO_CFG3_DOUTEN1       (1 << 2)
  64#define ATAO_CFG3_EN2_5V        (1 << 1)
  65#define ATAO_CFG3_SCANEN        (1 << 0)
  66#define ATAO_82C53_BASE         0x06
  67#define ATAO_CFG1_REG           0x0a
  68#define ATAO_CFG1_EXTINT2EN     (1 << 15)
  69#define ATAO_CFG1_EXTINT1EN     (1 << 14)
  70#define ATAO_CFG1_CNTINT2EN     (1 << 13)
  71#define ATAO_CFG1_CNTINT1EN     (1 << 12)
  72#define ATAO_CFG1_TCINTEN       (1 << 11)
  73#define ATAO_CFG1_CNT1SRC       (1 << 10)
  74#define ATAO_CFG1_CNT2SRC       (1 << 9)
  75#define ATAO_CFG1_FIFOEN        (1 << 8)
  76#define ATAO_CFG1_GRP2WR        (1 << 7)
  77#define ATAO_CFG1_EXTUPDEN      (1 << 6)
  78#define ATAO_CFG1_DMARQ         (1 << 5)
  79#define ATAO_CFG1_DMAEN         (1 << 4)
  80#define ATAO_CFG1_CH(x)         (((x) & 0xf) << 0)
  81#define ATAO_STATUS_REG         0x0a
  82#define ATAO_STATUS_FH          (1 << 6)
  83#define ATAO_STATUS_FE          (1 << 5)
  84#define ATAO_STATUS_FF          (1 << 4)
  85#define ATAO_STATUS_INT2        (1 << 3)
  86#define ATAO_STATUS_INT1        (1 << 2)
  87#define ATAO_STATUS_TCINT       (1 << 1)
  88#define ATAO_STATUS_PROMOUT     (1 << 0)
  89#define ATAO_FIFO_WRITE_REG     0x0c
  90#define ATAO_FIFO_CLEAR_REG     0x0c
  91#define ATAO_AO_REG(x)          (0x0c + ((x) * 2))
  92
  93/* registers with _2_ are accessed when GRP2WR is set in CFG1 */
  94#define ATAO_2_DMATCCLR_REG     0x00
  95#define ATAO_2_INT1CLR_REG      0x02
  96#define ATAO_2_INT2CLR_REG      0x04
  97#define ATAO_2_RTSISHFT_REG     0x06
  98#define ATAO_2_RTSISHFT_RSI     (1 << 0)
  99#define ATAO_2_RTSISTRB_REG     0x07
 100
 101struct atao_board {
 102        const char *name;
 103        int n_ao_chans;
 104};
 105
 106static const struct atao_board atao_boards[] = {
 107        {
 108                .name           = "at-ao-6",
 109                .n_ao_chans     = 6,
 110        }, {
 111                .name           = "at-ao-10",
 112                .n_ao_chans     = 10,
 113        },
 114};
 115
 116struct atao_private {
 117        unsigned short cfg1;
 118        unsigned short cfg3;
 119
 120        /* Used for caldac readback */
 121        unsigned char caldac[21];
 122};
 123
 124static void atao_select_reg_group(struct comedi_device *dev, int group)
 125{
 126        struct atao_private *devpriv = dev->private;
 127
 128        if (group)
 129                devpriv->cfg1 |= ATAO_CFG1_GRP2WR;
 130        else
 131                devpriv->cfg1 &= ~ATAO_CFG1_GRP2WR;
 132        outw(devpriv->cfg1, dev->iobase + ATAO_CFG1_REG);
 133}
 134
 135static int atao_ao_insn_write(struct comedi_device *dev,
 136                              struct comedi_subdevice *s,
 137                              struct comedi_insn *insn,
 138                              unsigned int *data)
 139{
 140        unsigned int chan = CR_CHAN(insn->chanspec);
 141        unsigned int val = s->readback[chan];
 142        int i;
 143
 144        if (chan == 0)
 145                atao_select_reg_group(dev, 1);
 146
 147        for (i = 0; i < insn->n; i++) {
 148                val = data[i];
 149
 150                /* the hardware expects two's complement values */
 151                outw(comedi_offset_munge(s, val),
 152                     dev->iobase + ATAO_AO_REG(chan));
 153        }
 154        s->readback[chan] = val;
 155
 156        if (chan == 0)
 157                atao_select_reg_group(dev, 0);
 158
 159        return insn->n;
 160}
 161
 162static int atao_dio_insn_bits(struct comedi_device *dev,
 163                              struct comedi_subdevice *s,
 164                              struct comedi_insn *insn,
 165                              unsigned int *data)
 166{
 167        if (comedi_dio_update_state(s, data))
 168                outw(s->state, dev->iobase + ATAO_DIO_REG);
 169
 170        data[1] = inw(dev->iobase + ATAO_DIO_REG);
 171
 172        return insn->n;
 173}
 174
 175static int atao_dio_insn_config(struct comedi_device *dev,
 176                                struct comedi_subdevice *s,
 177                                struct comedi_insn *insn,
 178                                unsigned int *data)
 179{
 180        struct atao_private *devpriv = dev->private;
 181        unsigned int chan = CR_CHAN(insn->chanspec);
 182        unsigned int mask;
 183        int ret;
 184
 185        if (chan < 4)
 186                mask = 0x0f;
 187        else
 188                mask = 0xf0;
 189
 190        ret = comedi_dio_insn_config(dev, s, insn, data, mask);
 191        if (ret)
 192                return ret;
 193
 194        if (s->io_bits & 0x0f)
 195                devpriv->cfg3 |= ATAO_CFG3_DOUTEN1;
 196        else
 197                devpriv->cfg3 &= ~ATAO_CFG3_DOUTEN1;
 198        if (s->io_bits & 0xf0)
 199                devpriv->cfg3 |= ATAO_CFG3_DOUTEN2;
 200        else
 201                devpriv->cfg3 &= ~ATAO_CFG3_DOUTEN2;
 202
 203        outw(devpriv->cfg3, dev->iobase + ATAO_CFG3_REG);
 204
 205        return insn->n;
 206}
 207
 208/*
 209 * There are three DAC8800 TrimDACs on the board. These are 8-channel,
 210 * 8-bit DACs that are used to calibrate the Analog Output channels.
 211 * The factory default calibration values are stored in the EEPROM.
 212 * The TrimDACs, and EEPROM addresses, are mapped as:
 213 *
 214 *        Channel       EEPROM  Description
 215 *   -----------------  ------  -----------------------------------
 216 *    0 - DAC0 Chan 0    0x30   AO Channel 0 Offset
 217 *    1 - DAC0 Chan 1    0x31   AO Channel 0 Gain
 218 *    2 - DAC0 Chan 2    0x32   AO Channel 1 Offset
 219 *    3 - DAC0 Chan 3    0x33   AO Channel 1 Gain
 220 *    4 - DAC0 Chan 4    0x34   AO Channel 2 Offset
 221 *    5 - DAC0 Chan 5    0x35   AO Channel 2 Gain
 222 *    6 - DAC0 Chan 6    0x36   AO Channel 3 Offset
 223 *    7 - DAC0 Chan 7    0x37   AO Channel 3 Gain
 224 *    8 - DAC1 Chan 0    0x38   AO Channel 4 Offset
 225 *    9 - DAC1 Chan 1    0x39   AO Channel 4 Gain
 226 *   10 - DAC1 Chan 2    0x3a   AO Channel 5 Offset
 227 *   11 - DAC1 Chan 3    0x3b   AO Channel 5 Gain
 228 *   12 - DAC1 Chan 4    0x3c   2.5V Offset
 229 *   13 - DAC1 Chan 5    0x3d   AO Channel 6 Offset (at-ao-10 only)
 230 *   14 - DAC1 Chan 6    0x3e   AO Channel 6 Gain   (at-ao-10 only)
 231 *   15 - DAC1 Chan 7    0x3f   AO Channel 7 Offset (at-ao-10 only)
 232 *   16 - DAC2 Chan 0    0x40   AO Channel 7 Gain   (at-ao-10 only)
 233 *   17 - DAC2 Chan 1    0x41   AO Channel 8 Offset (at-ao-10 only)
 234 *   18 - DAC2 Chan 2    0x42   AO Channel 8 Gain   (at-ao-10 only)
 235 *   19 - DAC2 Chan 3    0x43   AO Channel 9 Offset (at-ao-10 only)
 236 *   20 - DAC2 Chan 4    0x44   AO Channel 9 Gain   (at-ao-10 only)
 237 *        DAC2 Chan 5    0x45   Reserved
 238 *        DAC2 Chan 6    0x46   Reserved
 239 *        DAC2 Chan 7    0x47   Reserved
 240 */
 241static int atao_calib_insn_write(struct comedi_device *dev,
 242                                 struct comedi_subdevice *s,
 243                                 struct comedi_insn *insn,
 244                                 unsigned int *data)
 245{
 246        unsigned int chan = CR_CHAN(insn->chanspec);
 247
 248        if (insn->n) {
 249                unsigned int val = data[insn->n - 1];
 250                unsigned int bitstring = ((chan & 0x7) << 8) | val;
 251                unsigned int bits;
 252                int bit;
 253
 254                /* write the channel and last data value to the caldac */
 255                /* clock the bitstring to the caldac; MSB -> LSB */
 256                for (bit = 1 << 10; bit; bit >>= 1) {
 257                        bits = (bit & bitstring) ? ATAO_CFG2_SDATA : 0;
 258
 259                        outw(bits, dev->iobase + ATAO_CFG2_REG);
 260                        outw(bits | ATAO_CFG2_SCLK,
 261                             dev->iobase + ATAO_CFG2_REG);
 262                }
 263
 264                /* strobe the caldac to load the value */
 265                outw(ATAO_CFG2_CALLD(chan), dev->iobase + ATAO_CFG2_REG);
 266                outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG);
 267
 268                s->readback[chan] = val;
 269        }
 270
 271        return insn->n;
 272}
 273
 274static void atao_reset(struct comedi_device *dev)
 275{
 276        struct atao_private *devpriv = dev->private;
 277
 278        /* This is the reset sequence described in the manual */
 279
 280        devpriv->cfg1 = 0;
 281        outw(devpriv->cfg1, dev->iobase + ATAO_CFG1_REG);
 282
 283        /* Put outputs of counter 1 and counter 2 in a high state */
 284        comedi_8254_set_mode(dev->pacer, 0, I8254_MODE4 | I8254_BINARY);
 285        comedi_8254_set_mode(dev->pacer, 1, I8254_MODE4 | I8254_BINARY);
 286        comedi_8254_write(dev->pacer, 0, 0x0003);
 287
 288        outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG);
 289
 290        devpriv->cfg3 = 0;
 291        outw(devpriv->cfg3, dev->iobase + ATAO_CFG3_REG);
 292
 293        inw(dev->iobase + ATAO_FIFO_CLEAR_REG);
 294
 295        atao_select_reg_group(dev, 1);
 296        outw(0, dev->iobase + ATAO_2_INT1CLR_REG);
 297        outw(0, dev->iobase + ATAO_2_INT2CLR_REG);
 298        outw(0, dev->iobase + ATAO_2_DMATCCLR_REG);
 299        atao_select_reg_group(dev, 0);
 300}
 301
 302static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 303{
 304        const struct atao_board *board = dev->board_ptr;
 305        struct atao_private *devpriv;
 306        struct comedi_subdevice *s;
 307        int ret;
 308
 309        ret = comedi_request_region(dev, it->options[0], 0x20);
 310        if (ret)
 311                return ret;
 312
 313        devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 314        if (!devpriv)
 315                return -ENOMEM;
 316
 317        dev->pacer = comedi_8254_init(dev->iobase + ATAO_82C53_BASE,
 318                                      0, I8254_IO8, 0);
 319        if (!dev->pacer)
 320                return -ENOMEM;
 321
 322        ret = comedi_alloc_subdevices(dev, 4);
 323        if (ret)
 324                return ret;
 325
 326        /* Analog Output subdevice */
 327        s = &dev->subdevices[0];
 328        s->type         = COMEDI_SUBD_AO;
 329        s->subdev_flags = SDF_WRITABLE;
 330        s->n_chan       = board->n_ao_chans;
 331        s->maxdata      = 0x0fff;
 332        s->range_table  = it->options[3] ? &range_unipolar10 : &range_bipolar10;
 333        s->insn_write   = atao_ao_insn_write;
 334
 335        ret = comedi_alloc_subdev_readback(s);
 336        if (ret)
 337                return ret;
 338
 339        /* Digital I/O subdevice */
 340        s = &dev->subdevices[1];
 341        s->type         = COMEDI_SUBD_DIO;
 342        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 343        s->n_chan       = 8;
 344        s->maxdata      = 1;
 345        s->range_table  = &range_digital;
 346        s->insn_bits    = atao_dio_insn_bits;
 347        s->insn_config  = atao_dio_insn_config;
 348
 349        /* caldac subdevice */
 350        s = &dev->subdevices[2];
 351        s->type         = COMEDI_SUBD_CALIB;
 352        s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
 353        s->n_chan       = (board->n_ao_chans * 2) + 1;
 354        s->maxdata      = 0xff;
 355        s->insn_write   = atao_calib_insn_write;
 356
 357        ret = comedi_alloc_subdev_readback(s);
 358        if (ret)
 359                return ret;
 360
 361        /* EEPROM subdevice */
 362        s = &dev->subdevices[3];
 363        s->type         = COMEDI_SUBD_UNUSED;
 364
 365        atao_reset(dev);
 366
 367        return 0;
 368}
 369
 370static struct comedi_driver ni_at_ao_driver = {
 371        .driver_name    = "ni_at_ao",
 372        .module         = THIS_MODULE,
 373        .attach         = atao_attach,
 374        .detach         = comedi_legacy_detach,
 375        .board_name     = &atao_boards[0].name,
 376        .offset         = sizeof(struct atao_board),
 377        .num_names      = ARRAY_SIZE(atao_boards),
 378};
 379module_comedi_driver(ni_at_ao_driver);
 380
 381MODULE_AUTHOR("Comedi http://www.comedi.org");
 382MODULE_DESCRIPTION("Comedi driver for NI AT-AO-6/10 boards");
 383MODULE_LICENSE("GPL");
 384