root/drivers/staging/comedi/drivers/addi_apci_3501.c

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

DEFINITIONS

This source file includes following definitions.
  1. apci3501_wait_for_dac
  2. apci3501_ao_insn_write
  3. apci3501_di_insn_bits
  4. apci3501_do_insn_bits
  5. apci3501_eeprom_wait
  6. apci3501_eeprom_readw
  7. apci3501_eeprom_get_ao_n_chan
  8. apci3501_eeprom_insn_read
  9. apci3501_reset
  10. apci3501_auto_attach
  11. apci3501_detach
  12. apci3501_pci_probe

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * addi_apci_3501.c
   4  * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
   5  * Project manager: Eric Stolz
   6  *
   7  *      ADDI-DATA GmbH
   8  *      Dieselstrasse 3
   9  *      D-77833 Ottersweier
  10  *      Tel: +19(0)7223/9493-0
  11  *      Fax: +49(0)7223/9493-92
  12  *      http://www.addi-data.com
  13  *      info@addi-data.com
  14  */
  15 
  16 /*
  17  * Driver: addi_apci_3501
  18  * Description: ADDI-DATA APCI-3501 Analog output board
  19  * Devices: [ADDI-DATA] APCI-3501 (addi_apci_3501)
  20  * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
  21  * Updated: Mon, 20 Jun 2016 10:57:01 -0700
  22  * Status: untested
  23  *
  24  * Configuration Options: not applicable, uses comedi PCI auto config
  25  *
  26  * This board has the following features:
  27  *   - 4 or 8 analog output channels
  28  *   - 2 optically isolated digital inputs
  29  *   - 2 optically isolated digital outputs
  30  *   - 1 12-bit watchdog/timer
  31  *
  32  * There are 2 versions of the APCI-3501:
  33  *   - APCI-3501-4  4 analog output channels
  34  *   - APCI-3501-8  8 analog output channels
  35  *
  36  * These boards use the same PCI Vendor/Device IDs. The number of output
  37  * channels used by this driver is determined by reading the EEPROM on
  38  * the board.
  39  *
  40  * The watchdog/timer subdevice is not currently supported.
  41  */
  42 
  43 #include <linux/module.h>
  44 
  45 #include "../comedi_pci.h"
  46 #include "amcc_s5933.h"
  47 
  48 /*
  49  * PCI bar 1 register I/O map
  50  */
  51 #define APCI3501_AO_CTRL_STATUS_REG             0x00
  52 #define APCI3501_AO_CTRL_BIPOLAR                BIT(0)
  53 #define APCI3501_AO_STATUS_READY                BIT(8)
  54 #define APCI3501_AO_DATA_REG                    0x04
  55 #define APCI3501_AO_DATA_CHAN(x)                ((x) << 0)
  56 #define APCI3501_AO_DATA_VAL(x)                 ((x) << 8)
  57 #define APCI3501_AO_DATA_BIPOLAR                BIT(31)
  58 #define APCI3501_AO_TRIG_SCS_REG                0x08
  59 #define APCI3501_TIMER_BASE                     0x20
  60 #define APCI3501_DO_REG                         0x40
  61 #define APCI3501_DI_REG                         0x50
  62 
  63 /*
  64  * AMCC S5933 NVRAM
  65  */
  66 #define NVRAM_USER_DATA_START   0x100
  67 
  68 #define NVCMD_BEGIN_READ        (0x7 << 5)
  69 #define NVCMD_LOAD_LOW          (0x4 << 5)
  70 #define NVCMD_LOAD_HIGH         (0x5 << 5)
  71 
  72 /*
  73  * Function types stored in the eeprom
  74  */
  75 #define EEPROM_DIGITALINPUT             0
  76 #define EEPROM_DIGITALOUTPUT            1
  77 #define EEPROM_ANALOGINPUT              2
  78 #define EEPROM_ANALOGOUTPUT             3
  79 #define EEPROM_TIMER                    4
  80 #define EEPROM_WATCHDOG                 5
  81 #define EEPROM_TIMER_WATCHDOG_COUNTER   10
  82 
  83 struct apci3501_private {
  84         unsigned long amcc;
  85         unsigned char timer_mode;
  86 };
  87 
  88 static const struct comedi_lrange apci3501_ao_range = {
  89         2, {
  90                 BIP_RANGE(10),
  91                 UNI_RANGE(10)
  92         }
  93 };
  94 
  95 static int apci3501_wait_for_dac(struct comedi_device *dev)
  96 {
  97         unsigned int status;
  98 
  99         do {
 100                 status = inl(dev->iobase + APCI3501_AO_CTRL_STATUS_REG);
 101         } while (!(status & APCI3501_AO_STATUS_READY));
 102 
 103         return 0;
 104 }
 105 
 106 static int apci3501_ao_insn_write(struct comedi_device *dev,
 107                                   struct comedi_subdevice *s,
 108                                   struct comedi_insn *insn,
 109                                   unsigned int *data)
 110 {
 111         unsigned int chan = CR_CHAN(insn->chanspec);
 112         unsigned int range = CR_RANGE(insn->chanspec);
 113         unsigned int cfg = APCI3501_AO_DATA_CHAN(chan);
 114         int ret;
 115         int i;
 116 
 117         /*
 118          * All analog output channels have the same output range.
 119          *      14-bit bipolar: 0-10V
 120          *      13-bit unipolar: +/-10V
 121          * Changing the range of one channel changes all of them!
 122          */
 123         if (range) {
 124                 outl(0, dev->iobase + APCI3501_AO_CTRL_STATUS_REG);
 125         } else {
 126                 cfg |= APCI3501_AO_DATA_BIPOLAR;
 127                 outl(APCI3501_AO_CTRL_BIPOLAR,
 128                      dev->iobase + APCI3501_AO_CTRL_STATUS_REG);
 129         }
 130 
 131         for (i = 0; i < insn->n; i++) {
 132                 unsigned int val = data[i];
 133 
 134                 if (range == 1) {
 135                         if (data[i] > 0x1fff) {
 136                                 dev_err(dev->class_dev,
 137                                         "Unipolar resolution is only 13-bits\n");
 138                                 return -EINVAL;
 139                         }
 140                 }
 141 
 142                 ret = apci3501_wait_for_dac(dev);
 143                 if (ret)
 144                         return ret;
 145 
 146                 outl(cfg | APCI3501_AO_DATA_VAL(val),
 147                      dev->iobase + APCI3501_AO_DATA_REG);
 148 
 149                 s->readback[chan] = val;
 150         }
 151 
 152         return insn->n;
 153 }
 154 
 155 static int apci3501_di_insn_bits(struct comedi_device *dev,
 156                                  struct comedi_subdevice *s,
 157                                  struct comedi_insn *insn,
 158                                  unsigned int *data)
 159 {
 160         data[1] = inl(dev->iobase + APCI3501_DI_REG) & 0x3;
 161 
 162         return insn->n;
 163 }
 164 
 165 static int apci3501_do_insn_bits(struct comedi_device *dev,
 166                                  struct comedi_subdevice *s,
 167                                  struct comedi_insn *insn,
 168                                  unsigned int *data)
 169 {
 170         s->state = inl(dev->iobase + APCI3501_DO_REG);
 171 
 172         if (comedi_dio_update_state(s, data))
 173                 outl(s->state, dev->iobase + APCI3501_DO_REG);
 174 
 175         data[1] = s->state;
 176 
 177         return insn->n;
 178 }
 179 
 180 static void apci3501_eeprom_wait(unsigned long iobase)
 181 {
 182         unsigned char val;
 183 
 184         do {
 185                 val = inb(iobase + AMCC_OP_REG_MCSR_NVCMD);
 186         } while (val & 0x80);
 187 }
 188 
 189 static unsigned short apci3501_eeprom_readw(unsigned long iobase,
 190                                             unsigned short addr)
 191 {
 192         unsigned short val = 0;
 193         unsigned char tmp;
 194         unsigned char i;
 195 
 196         /* Add the offset to the start of the user data */
 197         addr += NVRAM_USER_DATA_START;
 198 
 199         for (i = 0; i < 2; i++) {
 200                 /* Load the low 8 bit address */
 201                 outb(NVCMD_LOAD_LOW, iobase + AMCC_OP_REG_MCSR_NVCMD);
 202                 apci3501_eeprom_wait(iobase);
 203                 outb((addr + i) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA);
 204                 apci3501_eeprom_wait(iobase);
 205 
 206                 /* Load the high 8 bit address */
 207                 outb(NVCMD_LOAD_HIGH, iobase + AMCC_OP_REG_MCSR_NVCMD);
 208                 apci3501_eeprom_wait(iobase);
 209                 outb(((addr + i) >> 8) & 0xff,
 210                      iobase + AMCC_OP_REG_MCSR_NVDATA);
 211                 apci3501_eeprom_wait(iobase);
 212 
 213                 /* Read the eeprom data byte */
 214                 outb(NVCMD_BEGIN_READ, iobase + AMCC_OP_REG_MCSR_NVCMD);
 215                 apci3501_eeprom_wait(iobase);
 216                 tmp = inb(iobase + AMCC_OP_REG_MCSR_NVDATA);
 217                 apci3501_eeprom_wait(iobase);
 218 
 219                 if (i == 0)
 220                         val |= tmp;
 221                 else
 222                         val |= (tmp << 8);
 223         }
 224 
 225         return val;
 226 }
 227 
 228 static int apci3501_eeprom_get_ao_n_chan(struct comedi_device *dev)
 229 {
 230         struct apci3501_private *devpriv = dev->private;
 231         unsigned char nfuncs;
 232         int i;
 233 
 234         nfuncs = apci3501_eeprom_readw(devpriv->amcc, 10) & 0xff;
 235 
 236         /* Read functionality details */
 237         for (i = 0; i < nfuncs; i++) {
 238                 unsigned short offset = i * 4;
 239                 unsigned short addr;
 240                 unsigned char func;
 241                 unsigned short val;
 242 
 243                 func = apci3501_eeprom_readw(devpriv->amcc, 12 + offset) & 0x3f;
 244                 addr = apci3501_eeprom_readw(devpriv->amcc, 14 + offset);
 245 
 246                 if (func == EEPROM_ANALOGOUTPUT) {
 247                         val = apci3501_eeprom_readw(devpriv->amcc, addr + 10);
 248                         return (val >> 4) & 0x3ff;
 249                 }
 250         }
 251         return 0;
 252 }
 253 
 254 static int apci3501_eeprom_insn_read(struct comedi_device *dev,
 255                                      struct comedi_subdevice *s,
 256                                      struct comedi_insn *insn,
 257                                      unsigned int *data)
 258 {
 259         struct apci3501_private *devpriv = dev->private;
 260         unsigned short addr = CR_CHAN(insn->chanspec);
 261         unsigned int val;
 262         unsigned int i;
 263 
 264         if (insn->n) {
 265                 /* No point reading the same EEPROM location more than once. */
 266                 val = apci3501_eeprom_readw(devpriv->amcc, 2 * addr);
 267                 for (i = 0; i < insn->n; i++)
 268                         data[i] = val;
 269         }
 270 
 271         return insn->n;
 272 }
 273 
 274 static int apci3501_reset(struct comedi_device *dev)
 275 {
 276         unsigned int val;
 277         int chan;
 278         int ret;
 279 
 280         /* Reset all digital outputs to "0" */
 281         outl(0x0, dev->iobase + APCI3501_DO_REG);
 282 
 283         /* Default all analog outputs to 0V (bipolar) */
 284         outl(APCI3501_AO_CTRL_BIPOLAR,
 285              dev->iobase + APCI3501_AO_CTRL_STATUS_REG);
 286         val = APCI3501_AO_DATA_BIPOLAR | APCI3501_AO_DATA_VAL(0);
 287 
 288         /* Set all analog output channels */
 289         for (chan = 0; chan < 8; chan++) {
 290                 ret = apci3501_wait_for_dac(dev);
 291                 if (ret) {
 292                         dev_warn(dev->class_dev,
 293                                  "%s: DAC not-ready for channel %i\n",
 294                                  __func__, chan);
 295                 } else {
 296                         outl(val | APCI3501_AO_DATA_CHAN(chan),
 297                              dev->iobase + APCI3501_AO_DATA_REG);
 298                 }
 299         }
 300 
 301         return 0;
 302 }
 303 
 304 static int apci3501_auto_attach(struct comedi_device *dev,
 305                                 unsigned long context_unused)
 306 {
 307         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 308         struct apci3501_private *devpriv;
 309         struct comedi_subdevice *s;
 310         int ao_n_chan;
 311         int ret;
 312 
 313         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 314         if (!devpriv)
 315                 return -ENOMEM;
 316 
 317         ret = comedi_pci_enable(dev);
 318         if (ret)
 319                 return ret;
 320 
 321         devpriv->amcc = pci_resource_start(pcidev, 0);
 322         dev->iobase = pci_resource_start(pcidev, 1);
 323 
 324         ao_n_chan = apci3501_eeprom_get_ao_n_chan(dev);
 325 
 326         ret = comedi_alloc_subdevices(dev, 5);
 327         if (ret)
 328                 return ret;
 329 
 330         /* Initialize the analog output subdevice */
 331         s = &dev->subdevices[0];
 332         if (ao_n_chan) {
 333                 s->type         = COMEDI_SUBD_AO;
 334                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
 335                 s->n_chan       = ao_n_chan;
 336                 s->maxdata      = 0x3fff;
 337                 s->range_table  = &apci3501_ao_range;
 338                 s->insn_write   = apci3501_ao_insn_write;
 339 
 340                 ret = comedi_alloc_subdev_readback(s);
 341                 if (ret)
 342                         return ret;
 343         } else {
 344                 s->type         = COMEDI_SUBD_UNUSED;
 345         }
 346 
 347         /* Initialize the digital input subdevice */
 348         s = &dev->subdevices[1];
 349         s->type         = COMEDI_SUBD_DI;
 350         s->subdev_flags = SDF_READABLE;
 351         s->n_chan       = 2;
 352         s->maxdata      = 1;
 353         s->range_table  = &range_digital;
 354         s->insn_bits    = apci3501_di_insn_bits;
 355 
 356         /* Initialize the digital output subdevice */
 357         s = &dev->subdevices[2];
 358         s->type         = COMEDI_SUBD_DO;
 359         s->subdev_flags = SDF_WRITABLE;
 360         s->n_chan       = 2;
 361         s->maxdata      = 1;
 362         s->range_table  = &range_digital;
 363         s->insn_bits    = apci3501_do_insn_bits;
 364 
 365         /* Timer/Watchdog subdevice */
 366         s = &dev->subdevices[3];
 367         s->type         = COMEDI_SUBD_UNUSED;
 368 
 369         /* Initialize the eeprom subdevice */
 370         s = &dev->subdevices[4];
 371         s->type         = COMEDI_SUBD_MEMORY;
 372         s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
 373         s->n_chan       = 256;
 374         s->maxdata      = 0xffff;
 375         s->insn_read    = apci3501_eeprom_insn_read;
 376 
 377         apci3501_reset(dev);
 378         return 0;
 379 }
 380 
 381 static void apci3501_detach(struct comedi_device *dev)
 382 {
 383         if (dev->iobase)
 384                 apci3501_reset(dev);
 385         comedi_pci_detach(dev);
 386 }
 387 
 388 static struct comedi_driver apci3501_driver = {
 389         .driver_name    = "addi_apci_3501",
 390         .module         = THIS_MODULE,
 391         .auto_attach    = apci3501_auto_attach,
 392         .detach         = apci3501_detach,
 393 };
 394 
 395 static int apci3501_pci_probe(struct pci_dev *dev,
 396                               const struct pci_device_id *id)
 397 {
 398         return comedi_pci_auto_config(dev, &apci3501_driver, id->driver_data);
 399 }
 400 
 401 static const struct pci_device_id apci3501_pci_table[] = {
 402         { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3001) },
 403         { 0 }
 404 };
 405 MODULE_DEVICE_TABLE(pci, apci3501_pci_table);
 406 
 407 static struct pci_driver apci3501_pci_driver = {
 408         .name           = "addi_apci_3501",
 409         .id_table       = apci3501_pci_table,
 410         .probe          = apci3501_pci_probe,
 411         .remove         = comedi_pci_auto_unconfig,
 412 };
 413 module_comedi_pci_driver(apci3501_driver, apci3501_pci_driver);
 414 
 415 MODULE_DESCRIPTION("ADDI-DATA APCI-3501 Analog output board");
 416 MODULE_AUTHOR("Comedi http://www.comedi.org");
 417 MODULE_LICENSE("GPL");

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