root/drivers/staging/comedi/drivers/adv_pci1724.c

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

DEFINITIONS

This source file includes following definitions.
  1. adv_pci1724_dac_idle
  2. adv_pci1724_insn_write
  3. adv_pci1724_auto_attach
  4. adv_pci1724_pci_probe

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * adv_pci1724.c
   4  * Comedi driver for the Advantech PCI-1724U card.
   5  *
   6  * Author:  Frank Mori Hess <fmh6jj@gmail.com>
   7  * Copyright (C) 2013 GnuBIO Inc
   8  *
   9  * COMEDI - Linux Control and Measurement Device Interface
  10  * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
  11  */
  12 
  13 /*
  14  * Driver: adv_pci1724
  15  * Description: Advantech PCI-1724U
  16  * Devices: [Advantech] PCI-1724U (adv_pci1724)
  17  * Author: Frank Mori Hess <fmh6jj@gmail.com>
  18  * Updated: 2013-02-09
  19  * Status: works
  20  *
  21  * Configuration Options: not applicable, uses comedi PCI auto config
  22  *
  23  * Subdevice 0 is the analog output.
  24  * Subdevice 1 is the offset calibration for the analog output.
  25  * Subdevice 2 is the gain calibration for the analog output.
  26  *
  27  * The calibration offset and gains have quite a large effect on the
  28  * analog output, so it is possible to adjust the analog output to
  29  * have an output range significantly different from the board's
  30  * nominal output ranges. For a calibrated +/-10V range, the analog
  31  * output's offset will be set somewhere near mid-range (0x2000) and
  32  * its gain will be near maximum (0x3fff).
  33  *
  34  * There is really no difference between the board's documented 0-20mA
  35  * versus 4-20mA output ranges. To pick one or the other is simply a
  36  * matter of adjusting the offset and gain calibration until the board
  37  * outputs in the desired range.
  38  */
  39 
  40 #include <linux/module.h>
  41 
  42 #include "../comedi_pci.h"
  43 
  44 /*
  45  * PCI bar 2 Register I/O map (dev->iobase)
  46  */
  47 #define PCI1724_DAC_CTRL_REG            0x00
  48 #define PCI1724_DAC_CTRL_GX(x)          BIT(20 + ((x) / 8))
  49 #define PCI1724_DAC_CTRL_CX(x)          (((x) % 8) << 16)
  50 #define PCI1724_DAC_CTRL_MODE(x)        (((x) & 0x3) << 14)
  51 #define PCI1724_DAC_CTRL_MODE_GAIN      PCI1724_DAC_CTRL_MODE(1)
  52 #define PCI1724_DAC_CTRL_MODE_OFFSET    PCI1724_DAC_CTRL_MODE(2)
  53 #define PCI1724_DAC_CTRL_MODE_NORMAL    PCI1724_DAC_CTRL_MODE(3)
  54 #define PCI1724_DAC_CTRL_MODE_MASK      PCI1724_DAC_CTRL_MODE(3)
  55 #define PCI1724_DAC_CTRL_DATA(x)        (((x) & 0x3fff) << 0)
  56 #define PCI1724_SYNC_CTRL_REG           0x04
  57 #define PCI1724_SYNC_CTRL_DACSTAT       BIT(1)
  58 #define PCI1724_SYNC_CTRL_SYN           BIT(0)
  59 #define PCI1724_EEPROM_CTRL_REG         0x08
  60 #define PCI1724_SYNC_TRIG_REG           0x0c  /* any value works */
  61 #define PCI1724_BOARD_ID_REG            0x10
  62 #define PCI1724_BOARD_ID_MASK           (0xf << 0)
  63 
  64 static const struct comedi_lrange adv_pci1724_ao_ranges = {
  65         4, {
  66                 BIP_RANGE(10),
  67                 RANGE_mA(0, 20),
  68                 RANGE_mA(4, 20),
  69                 RANGE_unitless(0, 1)
  70         }
  71 };
  72 
  73 static int adv_pci1724_dac_idle(struct comedi_device *dev,
  74                                 struct comedi_subdevice *s,
  75                                 struct comedi_insn *insn,
  76                                 unsigned long context)
  77 {
  78         unsigned int status;
  79 
  80         status = inl(dev->iobase + PCI1724_SYNC_CTRL_REG);
  81         if ((status & PCI1724_SYNC_CTRL_DACSTAT) == 0)
  82                 return 0;
  83         return -EBUSY;
  84 }
  85 
  86 static int adv_pci1724_insn_write(struct comedi_device *dev,
  87                                   struct comedi_subdevice *s,
  88                                   struct comedi_insn *insn,
  89                                   unsigned int *data)
  90 {
  91         unsigned long mode = (unsigned long)s->private;
  92         unsigned int chan = CR_CHAN(insn->chanspec);
  93         unsigned int ctrl;
  94         int ret;
  95         int i;
  96 
  97         ctrl = PCI1724_DAC_CTRL_GX(chan) | PCI1724_DAC_CTRL_CX(chan) | mode;
  98 
  99         /* turn off synchronous mode */
 100         outl(0, dev->iobase + PCI1724_SYNC_CTRL_REG);
 101 
 102         for (i = 0; i < insn->n; ++i) {
 103                 unsigned int val = data[i];
 104 
 105                 ret = comedi_timeout(dev, s, insn, adv_pci1724_dac_idle, 0);
 106                 if (ret)
 107                         return ret;
 108 
 109                 outl(ctrl | PCI1724_DAC_CTRL_DATA(val),
 110                      dev->iobase + PCI1724_DAC_CTRL_REG);
 111 
 112                 s->readback[chan] = val;
 113         }
 114 
 115         return insn->n;
 116 }
 117 
 118 static int adv_pci1724_auto_attach(struct comedi_device *dev,
 119                                    unsigned long context_unused)
 120 {
 121         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 122         struct comedi_subdevice *s;
 123         unsigned int board_id;
 124         int ret;
 125 
 126         ret = comedi_pci_enable(dev);
 127         if (ret)
 128                 return ret;
 129 
 130         dev->iobase = pci_resource_start(pcidev, 2);
 131         board_id = inl(dev->iobase + PCI1724_BOARD_ID_REG);
 132         dev_info(dev->class_dev, "board id: %d\n",
 133                  board_id & PCI1724_BOARD_ID_MASK);
 134 
 135         ret = comedi_alloc_subdevices(dev, 3);
 136         if (ret)
 137                 return ret;
 138 
 139         /* Analog Output subdevice */
 140         s = &dev->subdevices[0];
 141         s->type         = COMEDI_SUBD_AO;
 142         s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
 143         s->n_chan       = 32;
 144         s->maxdata      = 0x3fff;
 145         s->range_table  = &adv_pci1724_ao_ranges;
 146         s->insn_write   = adv_pci1724_insn_write;
 147         s->private      = (void *)PCI1724_DAC_CTRL_MODE_NORMAL;
 148 
 149         ret = comedi_alloc_subdev_readback(s);
 150         if (ret)
 151                 return ret;
 152 
 153         /* Offset Calibration subdevice */
 154         s = &dev->subdevices[1];
 155         s->type         = COMEDI_SUBD_CALIB;
 156         s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
 157         s->n_chan       = 32;
 158         s->maxdata      = 0x3fff;
 159         s->insn_write   = adv_pci1724_insn_write;
 160         s->private      = (void *)PCI1724_DAC_CTRL_MODE_OFFSET;
 161 
 162         ret = comedi_alloc_subdev_readback(s);
 163         if (ret)
 164                 return ret;
 165 
 166         /* Gain Calibration subdevice */
 167         s = &dev->subdevices[2];
 168         s->type         = COMEDI_SUBD_CALIB;
 169         s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
 170         s->n_chan       = 32;
 171         s->maxdata      = 0x3fff;
 172         s->insn_write   = adv_pci1724_insn_write;
 173         s->private      = (void *)PCI1724_DAC_CTRL_MODE_GAIN;
 174 
 175         return comedi_alloc_subdev_readback(s);
 176 }
 177 
 178 static struct comedi_driver adv_pci1724_driver = {
 179         .driver_name    = "adv_pci1724",
 180         .module         = THIS_MODULE,
 181         .auto_attach    = adv_pci1724_auto_attach,
 182         .detach         = comedi_pci_detach,
 183 };
 184 
 185 static int adv_pci1724_pci_probe(struct pci_dev *dev,
 186                                  const struct pci_device_id *id)
 187 {
 188         return comedi_pci_auto_config(dev, &adv_pci1724_driver,
 189                                       id->driver_data);
 190 }
 191 
 192 static const struct pci_device_id adv_pci1724_pci_table[] = {
 193         { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1724) },
 194         { 0 }
 195 };
 196 MODULE_DEVICE_TABLE(pci, adv_pci1724_pci_table);
 197 
 198 static struct pci_driver adv_pci1724_pci_driver = {
 199         .name           = "adv_pci1724",
 200         .id_table       = adv_pci1724_pci_table,
 201         .probe          = adv_pci1724_pci_probe,
 202         .remove         = comedi_pci_auto_unconfig,
 203 };
 204 module_comedi_pci_driver(adv_pci1724_driver, adv_pci1724_pci_driver);
 205 
 206 MODULE_AUTHOR("Frank Mori Hess <fmh6jj@gmail.com>");
 207 MODULE_DESCRIPTION("Advantech PCI-1724U Comedi driver");
 208 MODULE_LICENSE("GPL");

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