linux/drivers/staging/comedi/drivers/ni_daq_700.c
<<
>>
Prefs
   1/*
   2 *     comedi/drivers/ni_daq_700.c
   3 *     Driver for DAQCard-700 DIO/AI
   4 *     copied from 8255
   5 *
   6 *     COMEDI - Linux Control and Measurement Device Interface
   7 *     Copyright (C) 1998 David A. Schleef <ds@schleef.org>
   8 *
   9 *     This program is free software; you can redistribute it and/or modify
  10 *     it under the terms of the GNU General Public License as published by
  11 *     the Free Software Foundation; either version 2 of the License, or
  12 *     (at your option) any later version.
  13 *
  14 *     This program is distributed in the hope that it will be useful,
  15 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 *     GNU General Public License for more details.
  18 */
  19
  20/*
  21 * Driver: ni_daq_700
  22 * Description: National Instruments PCMCIA DAQCard-700
  23 * Author: Fred Brooks <nsaspook@nsaspook.com>,
  24 *   based on ni_daq_dio24 by Daniel Vecino Castel <dvecino@able.es>
  25 * Devices: [National Instruments] PCMCIA DAQ-Card-700 (ni_daq_700)
  26 * Status: works
  27 * Updated: Wed, 21 May 2014 12:07:20 +0000
  28 *
  29 * The daqcard-700 appears in Comedi as a  digital I/O subdevice (0) with
  30 * 16 channels and a analog input subdevice (1) with 16 single-ended channels
  31 * or 8 differential channels, and three input ranges.
  32 *
  33 * Digital:  The channel 0 corresponds to the daqcard-700's output
  34 * port, bit 0; channel 8 corresponds to the input port, bit 0.
  35 *
  36 * Digital direction configuration: channels 0-7 output, 8-15 input.
  37 *
  38 * Analog: The input  range is 0 to 4095 with a default of -10 to +10 volts.
  39 * Valid ranges:
  40 *       0 for -10 to 10V bipolar
  41 *       1 for -5 to 5V bipolar
  42 *       2 for -2.5 to 2.5V bipolar
  43 *
  44 * IRQ is assigned but not used.
  45 *
  46 * Manuals:     Register level: http://www.ni.com/pdf/manuals/340698.pdf
  47 *              User Manual:    http://www.ni.com/pdf/manuals/320676d.pdf
  48 */
  49
  50#include <linux/module.h>
  51#include <linux/delay.h>
  52#include <linux/interrupt.h>
  53
  54#include "../comedi_pcmcia.h"
  55
  56/* daqcard700 registers */
  57#define DIO_W           0x04    /* WO 8bit */
  58#define DIO_R           0x05    /* RO 8bit */
  59#define CMD_R1          0x00    /* WO 8bit */
  60#define CMD_R2          0x07    /* RW 8bit */
  61#define CMD_R3          0x05    /* W0 8bit */
  62#define STA_R1          0x00    /* RO 8bit */
  63#define STA_R2          0x01    /* RO 8bit */
  64#define ADFIFO_R        0x02    /* RO 16bit */
  65#define ADCLEAR_R       0x01    /* WO 8bit */
  66#define CDA_R0          0x08    /* RW 8bit */
  67#define CDA_R1          0x09    /* RW 8bit */
  68#define CDA_R2          0x0A    /* RW 8bit */
  69#define CMO_R           0x0B    /* RO 8bit */
  70#define TIC_R           0x06    /* WO 8bit */
  71/* daqcard700 modes */
  72#define CMD_R3_DIFF     0x04    /* diff mode */
  73
  74static const struct comedi_lrange range_daq700_ai = {
  75        3,
  76        {
  77                BIP_RANGE(10),
  78                BIP_RANGE(5),
  79                BIP_RANGE(2.5)
  80        }
  81};
  82
  83static int daq700_dio_insn_bits(struct comedi_device *dev,
  84                                struct comedi_subdevice *s,
  85                                struct comedi_insn *insn,
  86                                unsigned int *data)
  87{
  88        unsigned int mask;
  89        unsigned int val;
  90
  91        mask = comedi_dio_update_state(s, data);
  92        if (mask) {
  93                if (mask & 0xff)
  94                        outb(s->state & 0xff, dev->iobase + DIO_W);
  95        }
  96
  97        val = s->state & 0xff;
  98        val |= inb(dev->iobase + DIO_R) << 8;
  99
 100        data[1] = val;
 101
 102        return insn->n;
 103}
 104
 105static int daq700_dio_insn_config(struct comedi_device *dev,
 106                                  struct comedi_subdevice *s,
 107                                  struct comedi_insn *insn,
 108                                  unsigned int *data)
 109{
 110        int ret;
 111
 112        ret = comedi_dio_insn_config(dev, s, insn, data, 0);
 113        if (ret)
 114                return ret;
 115
 116        /* The DIO channels are not configurable, fix the io_bits */
 117        s->io_bits = 0x00ff;
 118
 119        return insn->n;
 120}
 121
 122static int daq700_ai_eoc(struct comedi_device *dev,
 123                         struct comedi_subdevice *s,
 124                         struct comedi_insn *insn,
 125                         unsigned long context)
 126{
 127        unsigned int status;
 128
 129        status = inb(dev->iobase + STA_R2);
 130        if ((status & 0x03))
 131                return -EOVERFLOW;
 132        status = inb(dev->iobase + STA_R1);
 133        if ((status & 0x02))
 134                return -ENODATA;
 135        if ((status & 0x11) == 0x01)
 136                return 0;
 137        return -EBUSY;
 138}
 139
 140static int daq700_ai_rinsn(struct comedi_device *dev,
 141                           struct comedi_subdevice *s,
 142                           struct comedi_insn *insn, unsigned int *data)
 143{
 144        int n;
 145        int d;
 146        int ret;
 147        unsigned int chan       = CR_CHAN(insn->chanspec);
 148        unsigned int aref       = CR_AREF(insn->chanspec);
 149        unsigned int range      = CR_RANGE(insn->chanspec);
 150        unsigned int r3_bits    = 0;
 151
 152        /* set channel input modes */
 153        if (aref == AREF_DIFF)
 154                r3_bits |= CMD_R3_DIFF;
 155        /* write channel mode/range */
 156        if (range >= 1)
 157                range++;        /* convert range to hardware value */
 158        outb(r3_bits | (range & 0x03), dev->iobase + CMD_R3);
 159
 160        /* write channel to multiplexer */
 161        /* set mask scan bit high to disable scanning */
 162        outb(chan | 0x80, dev->iobase + CMD_R1);
 163        /* mux needs 2us to really settle [Fred Brooks]. */
 164        udelay(2);
 165
 166        /* convert n samples */
 167        for (n = 0; n < insn->n; n++) {
 168                /* trigger conversion with out0 L to H */
 169                outb(0x00, dev->iobase + CMD_R2); /* enable ADC conversions */
 170                outb(0x30, dev->iobase + CMO_R); /* mode 0 out0 L, from H */
 171                outb(0x00, dev->iobase + ADCLEAR_R);    /* clear the ADC FIFO */
 172                /* read 16bit junk from FIFO to clear */
 173                inw(dev->iobase + ADFIFO_R);
 174                /* mode 1 out0 H, L to H, start conversion */
 175                outb(0x32, dev->iobase + CMO_R);
 176
 177                /* wait for conversion to end */
 178                ret = comedi_timeout(dev, s, insn, daq700_ai_eoc, 0);
 179                if (ret)
 180                        return ret;
 181
 182                /* read data */
 183                d = inw(dev->iobase + ADFIFO_R);
 184                /* mangle the data as necessary */
 185                /* Bipolar Offset Binary: 0 to 4095 for -10 to +10 */
 186                d &= 0x0fff;
 187                d ^= 0x0800;
 188                data[n] = d;
 189        }
 190        return n;
 191}
 192
 193/*
 194 * Data acquisition is enabled.
 195 * The counter 0 output is high.
 196 * The I/O connector pin CLK1 drives counter 1 source.
 197 * Multiple-channel scanning is disabled.
 198 * All interrupts are disabled.
 199 * The analog input range is set to +-10 V
 200 * The analog input mode is single-ended.
 201 * The analog input circuitry is initialized to channel 0.
 202 * The A/D FIFO is cleared.
 203 */
 204static void daq700_ai_config(struct comedi_device *dev,
 205                             struct comedi_subdevice *s)
 206{
 207        unsigned long iobase = dev->iobase;
 208
 209        outb(0x80, iobase + CMD_R1);    /* disable scanning, ADC to chan 0 */
 210        outb(0x00, iobase + CMD_R2);    /* clear all bits */
 211        outb(0x00, iobase + CMD_R3);    /* set +-10 range */
 212        outb(0x32, iobase + CMO_R);     /* config counter mode1, out0 to H */
 213        outb(0x00, iobase + TIC_R);     /* clear counter interrupt */
 214        outb(0x00, iobase + ADCLEAR_R); /* clear the ADC FIFO */
 215        inw(iobase + ADFIFO_R);         /* read 16bit junk from FIFO to clear */
 216}
 217
 218static int daq700_auto_attach(struct comedi_device *dev,
 219                              unsigned long context)
 220{
 221        struct pcmcia_device *link = comedi_to_pcmcia_dev(dev);
 222        struct comedi_subdevice *s;
 223        int ret;
 224
 225        link->config_flags |= CONF_AUTO_SET_IO;
 226        ret = comedi_pcmcia_enable(dev, NULL);
 227        if (ret)
 228                return ret;
 229        dev->iobase = link->resource[0]->start;
 230
 231        ret = comedi_alloc_subdevices(dev, 2);
 232        if (ret)
 233                return ret;
 234
 235        /* DAQCard-700 dio */
 236        s = &dev->subdevices[0];
 237        s->type         = COMEDI_SUBD_DIO;
 238        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 239        s->n_chan       = 16;
 240        s->range_table  = &range_digital;
 241        s->maxdata      = 1;
 242        s->insn_bits    = daq700_dio_insn_bits;
 243        s->insn_config  = daq700_dio_insn_config;
 244        s->io_bits      = 0x00ff;
 245
 246        /* DAQCard-700 ai */
 247        s = &dev->subdevices[1];
 248        s->type = COMEDI_SUBD_AI;
 249        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
 250        s->n_chan = 16;
 251        s->maxdata = (1 << 12) - 1;
 252        s->range_table = &range_daq700_ai;
 253        s->insn_read = daq700_ai_rinsn;
 254        daq700_ai_config(dev, s);
 255
 256        return 0;
 257}
 258
 259static struct comedi_driver daq700_driver = {
 260        .driver_name    = "ni_daq_700",
 261        .module         = THIS_MODULE,
 262        .auto_attach    = daq700_auto_attach,
 263        .detach         = comedi_pcmcia_disable,
 264};
 265
 266static int daq700_cs_attach(struct pcmcia_device *link)
 267{
 268        return comedi_pcmcia_auto_config(link, &daq700_driver);
 269}
 270
 271static const struct pcmcia_device_id daq700_cs_ids[] = {
 272        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743),
 273        PCMCIA_DEVICE_NULL
 274};
 275MODULE_DEVICE_TABLE(pcmcia, daq700_cs_ids);
 276
 277static struct pcmcia_driver daq700_cs_driver = {
 278        .name           = "ni_daq_700",
 279        .owner          = THIS_MODULE,
 280        .id_table       = daq700_cs_ids,
 281        .probe          = daq700_cs_attach,
 282        .remove         = comedi_pcmcia_auto_unconfig,
 283};
 284module_comedi_pcmcia_driver(daq700_driver, daq700_cs_driver);
 285
 286MODULE_AUTHOR("Fred Brooks <nsaspook@nsaspook.com>");
 287MODULE_DESCRIPTION(
 288        "Comedi driver for National Instruments PCMCIA DAQCard-700 DIO/AI");
 289MODULE_LICENSE("GPL");
 290