linux/drivers/staging/comedi/drivers/aio_aio12_8.c
<<
>>
Prefs
   1/*
   2
   3    comedi/drivers/aio_aio12_8.c
   4
   5    Driver for Acces I/O Products PC-104 AIO12-8 Analog I/O Board
   6    Copyright (C) 2006 C&C Technologies, Inc.
   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    You should have received a copy of the GNU General Public License
  19    along with this program; if not, write to the Free Software
  20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21*/
  22
  23/*
  24
  25Driver: aio_aio12_8
  26Description: Acces I/O Products PC-104 AIO12-8 Analog I/O Board
  27Author: Pablo Mejia <pablo.mejia@cctechnol.com>
  28Devices:
  29 [Acces I/O] PC-104 AIO12-8
  30Status: experimental
  31
  32Configuration Options:
  33  [0] - I/O port base address
  34
  35Notes:
  36
  37  Only synchronous operations are supported.
  38
  39*/
  40
  41#include "../comedidev.h"
  42#include <linux/ioport.h>
  43#include "8255.h"
  44
  45#define AIO12_8_STATUS                  0x00
  46#define AIO12_8_INTERRUPT               0x01
  47#define AIO12_8_ADC                     0x02
  48#define AIO12_8_DAC_0                   0x04
  49#define AIO12_8_DAC_1                   0x06
  50#define AIO12_8_DAC_2                   0x08
  51#define AIO12_8_DAC_3                   0x0A
  52#define AIO12_8_COUNTER_0               0x0C
  53#define AIO12_8_COUNTER_1               0x0D
  54#define AIO12_8_COUNTER_2               0x0E
  55#define AIO12_8_COUNTER_CONTROL         0x0F
  56#define AIO12_8_DIO_0                   0x10
  57#define AIO12_8_DIO_1                   0x11
  58#define AIO12_8_DIO_2                   0x12
  59#define AIO12_8_DIO_STATUS              0x13
  60#define AIO12_8_DIO_CONTROL             0x14
  61#define AIO12_8_ADC_TRIGGER_CONTROL     0x15
  62#define AIO12_8_TRIGGER                 0x16
  63#define AIO12_8_POWER                   0x17
  64
  65#define STATUS_ADC_EOC                  0x80
  66
  67#define ADC_MODE_NORMAL                 0x00
  68#define ADC_MODE_INTERNAL_CLOCK         0x40
  69#define ADC_MODE_STANDBY                0x80
  70#define ADC_MODE_POWERDOWN              0xC0
  71
  72#define DAC_ENABLE                      0x18
  73
  74struct aio12_8_boardtype {
  75        const char *name;
  76};
  77
  78static const struct aio12_8_boardtype board_types[] = {
  79        {
  80         .name = "aio_aio12_8"},
  81};
  82
  83#define thisboard       ((const struct aio12_8_boardtype  *) dev->board_ptr)
  84
  85struct aio12_8_private {
  86        unsigned int ao_readback[4];
  87};
  88
  89#define devpriv ((struct aio12_8_private *) dev->private)
  90
  91static int aio_aio12_8_ai_read(struct comedi_device *dev,
  92                               struct comedi_subdevice *s,
  93                               struct comedi_insn *insn, unsigned int *data)
  94{
  95        int n;
  96        unsigned char control =
  97            ADC_MODE_NORMAL |
  98            (CR_RANGE(insn->chanspec) << 3) | CR_CHAN(insn->chanspec);
  99
 100        /* read status to clear EOC latch */
 101        inb(dev->iobase + AIO12_8_STATUS);
 102
 103        for (n = 0; n < insn->n; n++) {
 104                int timeout = 5;
 105
 106                /*  Setup and start conversion */
 107                outb(control, dev->iobase + AIO12_8_ADC);
 108
 109                /*  Wait for conversion to complete */
 110                while (timeout &&
 111                       !(inb(dev->iobase + AIO12_8_STATUS) & STATUS_ADC_EOC)) {
 112                        timeout--;
 113                        printk("timeout %d\n", timeout);
 114                        udelay(1);
 115                }
 116                if (timeout == 0) {
 117                        comedi_error(dev, "ADC timeout");
 118                        return -EIO;
 119                }
 120
 121                data[n] = inw(dev->iobase + AIO12_8_ADC) & 0x0FFF;
 122        }
 123        return n;
 124}
 125
 126static int aio_aio12_8_ao_read(struct comedi_device *dev,
 127                               struct comedi_subdevice *s,
 128                               struct comedi_insn *insn, unsigned int *data)
 129{
 130        int i;
 131        int val = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
 132
 133        for (i = 0; i < insn->n; i++)
 134                data[i] = val;
 135        return insn->n;
 136}
 137
 138static int aio_aio12_8_ao_write(struct comedi_device *dev,
 139                                struct comedi_subdevice *s,
 140                                struct comedi_insn *insn, unsigned int *data)
 141{
 142        int i;
 143        int chan = CR_CHAN(insn->chanspec);
 144        unsigned long port = dev->iobase + AIO12_8_DAC_0 + (2 * chan);
 145
 146        /* enable DACs */
 147        outb(0x01, dev->iobase + DAC_ENABLE);
 148
 149        for (i = 0; i < insn->n; i++) {
 150                outb(data[i] & 0xFF, port);     /*  LSB */
 151                outb((data[i] >> 8) & 0x0F, port + 1);  /*  MSB */
 152                devpriv->ao_readback[chan] = data[i];
 153        }
 154        return insn->n;
 155}
 156
 157static const struct comedi_lrange range_aio_aio12_8 = {
 158        4,
 159        {
 160         UNI_RANGE(5),
 161         BIP_RANGE(5),
 162         UNI_RANGE(10),
 163         BIP_RANGE(10),
 164         }
 165};
 166
 167static int aio_aio12_8_attach(struct comedi_device *dev,
 168                              struct comedi_devconfig *it)
 169{
 170        int iobase;
 171        struct comedi_subdevice *s;
 172
 173        iobase = it->options[0];
 174        if (!request_region(iobase, 24, "aio_aio12_8")) {
 175                printk("I/O port conflict");
 176                return -EIO;
 177        }
 178
 179        dev->board_name = thisboard->name;
 180
 181        dev->iobase = iobase;
 182
 183        if (alloc_private(dev, sizeof(struct aio12_8_private)) < 0)
 184                return -ENOMEM;
 185
 186        if (alloc_subdevices(dev, 3) < 0)
 187                return -ENOMEM;
 188
 189        s = &dev->subdevices[0];
 190        s->type = COMEDI_SUBD_AI;
 191        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
 192        s->n_chan = 8;
 193        s->maxdata = (1 << 12) - 1;
 194        s->range_table = &range_aio_aio12_8;
 195        s->insn_read = aio_aio12_8_ai_read;
 196
 197        s = &dev->subdevices[1];
 198        s->type = COMEDI_SUBD_AO;
 199        s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_DIFF;
 200        s->n_chan = 4;
 201        s->maxdata = (1 << 12) - 1;
 202        s->range_table = &range_aio_aio12_8;
 203        s->insn_read = aio_aio12_8_ao_read;
 204        s->insn_write = aio_aio12_8_ao_write;
 205
 206        s = &dev->subdevices[2];
 207        subdev_8255_init(dev, s, NULL, dev->iobase + AIO12_8_DIO_0);
 208
 209        return 0;
 210}
 211
 212static int aio_aio12_8_detach(struct comedi_device *dev)
 213{
 214        subdev_8255_cleanup(dev, &dev->subdevices[2]);
 215        if (dev->iobase)
 216                release_region(dev->iobase, 24);
 217        return 0;
 218}
 219
 220static struct comedi_driver driver_aio_aio12_8 = {
 221        .driver_name = "aio_aio12_8",
 222        .module = THIS_MODULE,
 223        .attach = aio_aio12_8_attach,
 224        .detach = aio_aio12_8_detach,
 225        .board_name = &board_types[0].name,
 226        .num_names = 1,
 227        .offset = sizeof(struct aio12_8_boardtype),
 228};
 229
 230COMEDI_INITCLEANUP(driver_aio_aio12_8);
 231