linux/drivers/staging/comedi/drivers/rti802.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * rti802.c
   4 * Comedi driver for Analog Devices RTI-802 board
   5 *
   6 * COMEDI - Linux Control and Measurement Device Interface
   7 * Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se>
   8 */
   9
  10/*
  11 * Driver: rti802
  12 * Description: Analog Devices RTI-802
  13 * Author: Anders Blomdell <anders.blomdell@control.lth.se>
  14 * Devices: [Analog Devices] RTI-802 (rti802)
  15 * Status: works
  16 *
  17 * Configuration Options:
  18 *   [0] - i/o base
  19 *   [1] - unused
  20 *   [2,4,6,8,10,12,14,16] - dac#[0-7]  0=two's comp, 1=straight
  21 *   [3,5,7,9,11,13,15,17] - dac#[0-7]  0=bipolar, 1=unipolar
  22 */
  23
  24#include <linux/module.h>
  25#include "../comedidev.h"
  26
  27/*
  28 * Register I/O map
  29 */
  30#define RTI802_SELECT           0x00
  31#define RTI802_DATALOW          0x01
  32#define RTI802_DATAHIGH         0x02
  33
  34struct rti802_private {
  35        enum {
  36                dac_2comp, dac_straight
  37        } dac_coding[8];
  38        const struct comedi_lrange *range_type_list[8];
  39};
  40
  41static int rti802_ao_insn_write(struct comedi_device *dev,
  42                                struct comedi_subdevice *s,
  43                                struct comedi_insn *insn,
  44                                unsigned int *data)
  45{
  46        struct rti802_private *devpriv = dev->private;
  47        unsigned int chan = CR_CHAN(insn->chanspec);
  48        int i;
  49
  50        outb(chan, dev->iobase + RTI802_SELECT);
  51
  52        for (i = 0; i < insn->n; i++) {
  53                unsigned int val = data[i];
  54
  55                s->readback[chan] = val;
  56
  57                /* munge offset binary to two's complement if needed */
  58                if (devpriv->dac_coding[chan] == dac_2comp)
  59                        val = comedi_offset_munge(s, val);
  60
  61                outb(val & 0xff, dev->iobase + RTI802_DATALOW);
  62                outb((val >> 8) & 0xff, dev->iobase + RTI802_DATAHIGH);
  63        }
  64
  65        return insn->n;
  66}
  67
  68static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
  69{
  70        struct rti802_private *devpriv;
  71        struct comedi_subdevice *s;
  72        int i;
  73        int ret;
  74
  75        ret = comedi_request_region(dev, it->options[0], 0x04);
  76        if (ret)
  77                return ret;
  78
  79        devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
  80        if (!devpriv)
  81                return -ENOMEM;
  82
  83        ret = comedi_alloc_subdevices(dev, 1);
  84        if (ret)
  85                return ret;
  86
  87        /* Analog Output subdevice */
  88        s = &dev->subdevices[0];
  89        s->type         = COMEDI_SUBD_AO;
  90        s->subdev_flags = SDF_WRITABLE;
  91        s->maxdata      = 0xfff;
  92        s->n_chan       = 8;
  93        s->insn_write   = rti802_ao_insn_write;
  94
  95        ret = comedi_alloc_subdev_readback(s);
  96        if (ret)
  97                return ret;
  98
  99        s->range_table_list = devpriv->range_type_list;
 100        for (i = 0; i < 8; i++) {
 101                devpriv->dac_coding[i] = (it->options[3 + 2 * i])
 102                        ? (dac_straight) : (dac_2comp);
 103                devpriv->range_type_list[i] = (it->options[2 + 2 * i])
 104                        ? &range_unipolar10 : &range_bipolar10;
 105        }
 106
 107        return 0;
 108}
 109
 110static struct comedi_driver rti802_driver = {
 111        .driver_name    = "rti802",
 112        .module         = THIS_MODULE,
 113        .attach         = rti802_attach,
 114        .detach         = comedi_legacy_detach,
 115};
 116module_comedi_driver(rti802_driver);
 117
 118MODULE_AUTHOR("Comedi http://www.comedi.org");
 119MODULE_DESCRIPTION("Comedi driver for Analog Devices RTI-802 board");
 120MODULE_LICENSE("GPL");
 121