These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / staging / comedi / drivers / aio_aio12_8.c
index fbc3e5a..43a0ce5 100644 (file)
 /*
-
-    comedi/drivers/aio_aio12_8.c
-
-    Driver for Access I/O Products PC-104 AIO12-8 Analog I/O Board
-    Copyright (C) 2006 C&C Technologies, Inc.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-*/
+ * aio_aio12_8.c
+ * Driver for Access I/O Products PC-104 AIO12-8 Analog I/O Board
+ * Copyright (C) 2006 C&C Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
 
 /*
-
-Driver: aio_aio12_8
-Description: Access I/O Products PC-104 AIO12-8 Analog I/O Board
-Author: Pablo Mejia <pablo.mejia@cctechnol.com>
-Devices: [Access I/O] PC-104 AIO12-8 (aio_aio12_8)
-        [Access I/O] PC-104 AI12-8 (aio_ai12_8)
-        [Access I/O] PC-104 AO12-8 (aio_ao12_8)
-Status: experimental
-
-Configuration Options:
-  [0] - I/O port base address
-
-Notes:
-
-  Only synchronous operations are supported.
-
-*/
+ * Driver: aio_aio12_8
+ * Description: Access I/O Products PC-104 AIO12-8 Analog I/O Board
+ * Author: Pablo Mejia <pablo.mejia@cctechnol.com>
+ * Devices: [Access I/O] PC-104 AIO12-8 (aio_aio12_8),
+ *   [Access I/O] PC-104 AI12-8 (aio_ai12_8),
+ *   [Access I/O] PC-104 AO12-4 (aio_ao12_4)
+ * Status: experimental
+ *
+ * Configuration Options:
+ *   [0] - I/O port base address
+ *
+ * Notes:
+ * Only synchronous operations are supported.
+ */
 
 #include <linux/module.h>
 #include "../comedidev.h"
+
+#include "comedi_8254.h"
 #include "8255.h"
 
 /*
  * Register map
  */
 #define AIO12_8_STATUS_REG             0x00
-#define AIO12_8_STATUS_ADC_EOC         (1 << 7)
-#define AIO12_8_STATUS_PORT_C_COS      (1 << 6)
-#define AIO12_8_STATUS_IRQ_ENA         (1 << 2)
+#define AIO12_8_STATUS_ADC_EOC         BIT(7)
+#define AIO12_8_STATUS_PORT_C_COS      BIT(6)
+#define AIO12_8_STATUS_IRQ_ENA         BIT(2)
 #define AIO12_8_INTERRUPT_REG          0x01
-#define AIO12_8_INTERRUPT_ADC          (1 << 7)
-#define AIO12_8_INTERRUPT_COS          (1 << 6)
-#define AIO12_8_INTERRUPT_COUNTER1     (1 << 5)
-#define AIO12_8_INTERRUPT_PORT_C3      (1 << 4)
-#define AIO12_8_INTERRUPT_PORT_C0      (1 << 3)
-#define AIO12_8_INTERRUPT_ENA          (1 << 2)
+#define AIO12_8_INTERRUPT_ADC          BIT(7)
+#define AIO12_8_INTERRUPT_COS          BIT(6)
+#define AIO12_8_INTERRUPT_COUNTER1     BIT(5)
+#define AIO12_8_INTERRUPT_PORT_C3      BIT(4)
+#define AIO12_8_INTERRUPT_PORT_C0      BIT(3)
+#define AIO12_8_INTERRUPT_ENA          BIT(2)
 #define AIO12_8_ADC_REG                        0x02
-#define AIO12_8_ADC_MODE_NORMAL                (0 << 6)
-#define AIO12_8_ADC_MODE_INT_CLK       (1 << 6)
-#define AIO12_8_ADC_MODE_STANDBY       (2 << 6)
-#define AIO12_8_ADC_MODE_POWERDOWN     (3 << 6)
-#define AIO12_8_ADC_ACQ_3USEC          (0 << 5)
-#define AIO12_8_ADC_ACQ_PROGRAM                (1 << 5)
+#define AIO12_8_ADC_MODE(x)            (((x) & 0x3) << 6)
+#define AIO12_8_ADC_MODE_NORMAL                AIO12_8_ADC_MODE(0)
+#define AIO12_8_ADC_MODE_INT_CLK       AIO12_8_ADC_MODE(1)
+#define AIO12_8_ADC_MODE_STANDBY       AIO12_8_ADC_MODE(2)
+#define AIO12_8_ADC_MODE_POWERDOWN     AIO12_8_ADC_MODE(3)
+#define AIO12_8_ADC_ACQ(x)             (((x) & 0x1) << 5)
+#define AIO12_8_ADC_ACQ_3USEC          AIO12_8_ADC_ACQ(0)
+#define AIO12_8_ADC_ACQ_PROGRAM                AIO12_8_ADC_ACQ(1)
 #define AIO12_8_ADC_RANGE(x)           ((x) << 3)
 #define AIO12_8_ADC_CHAN(x)            ((x) << 0)
 #define AIO12_8_DAC_REG(x)             (0x04 + (x) * 2)
 #define AIO12_8_8254_BASE_REG          0x0c
 #define AIO12_8_8255_BASE_REG          0x10
 #define AIO12_8_DIO_CONTROL_REG                0x14
-#define AIO12_8_DIO_CONTROL_TST                (1 << 0)
+#define AIO12_8_DIO_CONTROL_TST                BIT(0)
 #define AIO12_8_ADC_TRIGGER_REG                0x15
 #define AIO12_8_ADC_TRIGGER_RANGE(x)   ((x) << 3)
 #define AIO12_8_ADC_TRIGGER_CHAN(x)    ((x) << 0)
 #define AIO12_8_TRIGGER_REG            0x16
-#define AIO12_8_TRIGGER_ADTRIG         (1 << 1)
-#define AIO12_8_TRIGGER_DACTRIG                (1 << 0)
+#define AIO12_8_TRIGGER_ADTRIG         BIT(1)
+#define AIO12_8_TRIGGER_DACTRIG                BIT(0)
 #define AIO12_8_COS_REG                        0x17
 #define AIO12_8_DAC_ENABLE_REG         0x18
-#define AIO12_8_DAC_ENABLE_REF_ENA     (1 << 0)
+#define AIO12_8_DAC_ENABLE_REF_ENA     BIT(0)
+
+static const struct comedi_lrange aio_aio12_8_range = {
+       4, {
+               UNI_RANGE(5),
+               BIP_RANGE(5),
+               UNI_RANGE(10),
+               BIP_RANGE(10)
+       }
+};
 
 struct aio12_8_boardtype {
        const char *name;
-       int ai_nchan;
-       int ao_nchan;
+       unsigned int has_ai:1;
+       unsigned int has_ao:1;
 };
 
 static const struct aio12_8_boardtype board_types[] = {
        {
                .name           = "aio_aio12_8",
-               .ai_nchan       = 8,
-               .ao_nchan       = 4,
+               .has_ai         = 1,
+               .has_ao         = 1,
        }, {
                .name           = "aio_ai12_8",
-               .ai_nchan       = 8,
+               .has_ai         = 1,
        }, {
-               .name           = "aio_ao12_8",
-               .ao_nchan       = 4,
+               .name           = "aio_ao12_4",
+               .has_ao         = 1,
        },
 };
 
@@ -112,13 +120,15 @@ static int aio_aio12_8_ai_eoc(struct comedi_device *dev,
 
 static int aio_aio12_8_ai_read(struct comedi_device *dev,
                               struct comedi_subdevice *s,
-                              struct comedi_insn *insn, unsigned int *data)
+                              struct comedi_insn *insn,
+                              unsigned int *data)
 {
        unsigned int chan = CR_CHAN(insn->chanspec);
        unsigned int range = CR_RANGE(insn->chanspec);
+       unsigned int val;
        unsigned char control;
        int ret;
-       int n;
+       int i;
 
        /*
         * Setup the control byte for internal 2MHz clock, 3uS conversion,
@@ -130,7 +140,7 @@ static int aio_aio12_8_ai_read(struct comedi_device *dev,
        /* Read status to clear EOC latch */
        inb(dev->iobase + AIO12_8_STATUS_REG);
 
-       for (n = 0; n < insn->n; n++) {
+       for (i = 0; i < insn->n; i++) {
                /*  Setup and start conversion */
                outb(control, dev->iobase + AIO12_8_ADC_REG);
 
@@ -139,7 +149,13 @@ static int aio_aio12_8_ai_read(struct comedi_device *dev,
                if (ret)
                        return ret;
 
-               data[n] = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata;
+               val = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata;
+
+               /* munge bipolar 2's complement data to offset binary */
+               if (comedi_range_is_bipolar(s, range))
+                       val = comedi_offset_munge(s, val);
+
+               data[i] = val;
        }
 
        return insn->n;
@@ -166,14 +182,28 @@ static int aio_aio12_8_ao_insn_write(struct comedi_device *dev,
        return insn->n;
 }
 
-static const struct comedi_lrange range_aio_aio12_8 = {
-       4, {
-               UNI_RANGE(5),
-               BIP_RANGE(5),
-               UNI_RANGE(10),
-               BIP_RANGE(10)
+static int aio_aio12_8_counter_insn_config(struct comedi_device *dev,
+                                          struct comedi_subdevice *s,
+                                          struct comedi_insn *insn,
+                                          unsigned int *data)
+{
+       unsigned int chan = CR_CHAN(insn->chanspec);
+
+       switch (data[0]) {
+       case INSN_CONFIG_GET_CLOCK_SRC:
+               /*
+                * Channels 0 and 2 have external clock sources.
+                * Channel 1 has a fixed 1 MHz clock source.
+                */
+               data[0] = 0;
+               data[1] = (chan == 1) ? I8254_OSC_BASE_1MHZ : 0;
+               break;
+       default:
+               return -EINVAL;
        }
-};
+
+       return insn->n;
+}
 
 static int aio_aio12_8_attach(struct comedi_device *dev,
                              struct comedi_devconfig *it)
@@ -186,31 +216,36 @@ static int aio_aio12_8_attach(struct comedi_device *dev,
        if (ret)
                return ret;
 
+       dev->pacer = comedi_8254_init(dev->iobase + AIO12_8_8254_BASE_REG,
+                                     0, I8254_IO8, 0);
+       if (!dev->pacer)
+               return -ENOMEM;
+
        ret = comedi_alloc_subdevices(dev, 4);
        if (ret)
                return ret;
 
+       /* Analog Input subdevice */
        s = &dev->subdevices[0];
-       if (board->ai_nchan) {
-               /* Analog input subdevice */
+       if (board->has_ai) {
                s->type         = COMEDI_SUBD_AI;
                s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
-               s->n_chan       = board->ai_nchan;
+               s->n_chan       = 8;
                s->maxdata      = 0x0fff;
-               s->range_table  = &range_aio_aio12_8;
+               s->range_table  = &aio_aio12_8_range;
                s->insn_read    = aio_aio12_8_ai_read;
        } else {
                s->type = COMEDI_SUBD_UNUSED;
        }
 
+       /* Analog Output subdevice */
        s = &dev->subdevices[1];
-       if (board->ao_nchan) {
-               /* Analog output subdevice */
+       if (board->has_ao) {
                s->type         = COMEDI_SUBD_AO;
-               s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_DIFF;
+               s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
                s->n_chan       = 4;
                s->maxdata      = 0x0fff;
-               s->range_table  = &range_aio_aio12_8;
+               s->range_table  = &aio_aio12_8_range;
                s->insn_write   = aio_aio12_8_ao_insn_write;
 
                ret = comedi_alloc_subdev_readback(s);
@@ -220,15 +255,17 @@ static int aio_aio12_8_attach(struct comedi_device *dev,
                s->type = COMEDI_SUBD_UNUSED;
        }
 
+       /* Digital I/O subdevice (8255) */
        s = &dev->subdevices[2];
-       /* 8255 Digital i/o subdevice */
        ret = subdev_8255_init(dev, s, NULL, AIO12_8_8255_BASE_REG);
        if (ret)
                return ret;
 
+       /* Counter subdevice (8254) */
        s = &dev->subdevices[3];
-       /* 8254 counter/timer subdevice */
-       s->type         = COMEDI_SUBD_UNUSED;
+       comedi_8254_subdevice_init(s, dev->pacer);
+
+       dev->pacer->insn_config = aio_aio12_8_counter_insn_config;
 
        return 0;
 }
@@ -245,5 +282,5 @@ static struct comedi_driver aio_aio12_8_driver = {
 module_comedi_driver(aio_aio12_8_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for Access I/O AIO12-8 Analog I/O Board");
 MODULE_LICENSE("GPL");