]> git.karo-electronics.de Git - linux-beck.git/commitdiff
staging: comedi: pcmmio: cleanup ai_rinsn()
authorH Hartley Sweeten <hsweeten@visionengravers.com>
Mon, 9 Dec 2013 22:30:41 +0000 (15:30 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 17 Dec 2013 18:01:50 +0000 (10:01 -0800)
Rename this function to have namespace associated with the driver.

Refactor the function to remove the extra write to the command register
between each ADC conversion. We only need to do one dummy conversion in
order to flush the serial ADC. After that each command will return the
result of the previous conversion.

Define the register map for the analog input registers.

Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Reviewed-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/comedi/drivers/pcmmio.c

index eb6139570f3eed45edf05597bfa37981442c85cb..bd45b84a376981b2cb0727405d7b60f21898e6aa 100644 (file)
@@ -80,6 +80,17 @@ Configuration Options:
 
 #include "comedi_fc.h"
 
+/*
+ * Register I/O map
+ */
+#define PCMMIO_AI_LSB_REG              0x00
+#define PCMMIO_AI_MSB_REG              0x01
+#define PCMMIO_AI_CMD_REG              0x02
+#define PCMMIO_AI_CMD_SE               (1 << 7)
+#define PCMMIO_AI_CMD_ODD_CHAN         (1 << 6)
+#define PCMMIO_AI_CMD_CHAN_SEL(x)      (((x) & 0x3) << 4)
+#define PCMMIO_AI_CMD_RANGE(x)         (((x) & 0x3) << 2)
+
 /* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */
 #define CHANS_PER_PORT   8
 #define PORTS_PER_ASIC   6
@@ -761,85 +772,67 @@ static int adc_wait_ready(unsigned long iobase)
        return 1;
 }
 
-/* All this is for AI and AO */
-static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
-                   struct comedi_insn *insn, unsigned int *data)
+static int pcmmio_ai_insn_read(struct comedi_device *dev,
+                              struct comedi_subdevice *s,
+                              struct comedi_insn *insn,
+                              unsigned int *data)
 {
-       int n;
        unsigned long iobase = subpriv->iobase;
+       unsigned int chan = CR_CHAN(insn->chanspec);
+       unsigned int range = CR_RANGE(insn->chanspec);
+       unsigned int aref = CR_AREF(insn->chanspec);
+       unsigned char cmd = 0;
+       unsigned int val;
+       int i;
 
        /*
-          1. write the CMD byte (to BASE+2)
-          2. read junk lo byte (BASE+0)
-          3. read junk hi byte (BASE+1)
-          4. (mux settled so) write CMD byte again (BASE+2)
-          5. read valid lo byte(BASE+0)
-          6. read valid hi byte(BASE+1)
-
-          Additionally note that the BASE += 4 if the channel >= 8
+        * The PCM-MIO uses two Linear Tech LTC1859CG 8-channel A/D converters.
+        * The devices use a full duplex serial interface which transmits and
+        * receives data simultaneously. An 8-bit command is shifted into the
+        * ADC interface to configure it for the next conversion. At the same
+        * time, the data from the previous conversion is shifted out of the
+        * device. Consequently, the conversion result is delayed by one
+        * conversion from the command word.
+        *
+        * Setup the cmd for the conversions then do a dummy conversion to
+        * flush the junk data. Then do each conversion requested by the
+        * comedi_insn. Note that the last conversion will leave junk data
+        * in ADC which will get flushed on the next comedi_insn.
         */
 
-       /* convert n samples */
-       for (n = 0; n < insn->n; n++) {
-               unsigned chan = CR_CHAN(insn->chanspec), range =
-                   CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec);
-               unsigned char command_byte = 0;
-               unsigned iooffset = 0;
-               unsigned int val;
-
-               if (chan > 7)
-                       chan -= 8, iooffset = 4;        /*
-                                                        * use the second dword
-                                                        * for channels > 7
-                                                        */
-
-               if (aref != AREF_DIFF) {
-                       aref = AREF_GROUND;
-                       command_byte |= 1 << 7; /*
-                                                * set bit 7 to indicate
-                                                * single-ended
-                                                */
-               }
-
-               if (chan % 2) {
-                       command_byte |= 1 << 6; /*
-                                                * odd-numbered channels
-                                                * have bit 6 set
-                                                */
-               }
-
-               /* select the channel, bits 4-5 == chan/2 */
-               command_byte |= ((chan / 2) & 0x3) << 4;
-
-               /* set the range, bits 2-3 */
-               command_byte |= (range & 0x3) << 2;
-
-               /* need to do this twice to make sure mux settled */
-               /* chan/range/aref select */
-               outb(command_byte, iobase + iooffset + 2);
+       if (chan > 7) {
+               chan -= 8;
+               iobase += 0x4;
+       }
 
-               /* wait for the adc to say it finised the conversion */
-               adc_wait_ready(iobase + iooffset);
+       if (aref == AREF_GROUND)
+               cmd |= PCMMIO_AI_CMD_SE;
+       if (chan % 2)
+               cmd |= PCMMIO_AI_CMD_ODD_CHAN;
+       cmd |= PCMMIO_AI_CMD_CHAN_SEL(chan / 2);
+       cmd |= PCMMIO_AI_CMD_RANGE(range);
 
-               /* select the chan/range/aref AGAIN */
-               outb(command_byte, iobase + iooffset + 2);
+       outb(cmd, iobase + PCMMIO_AI_CMD_REG);
+       adc_wait_ready(iobase);
 
-               adc_wait_ready(iobase + iooffset);
+       val = inb(iobase + PCMMIO_AI_LSB_REG);
+       val |= inb(iobase + PCMMIO_AI_MSB_REG) << 8;
 
-               /* read data lo byte */
-               val = inb(iobase + iooffset + 0);
+       for (i = 0; i < insn->n; i++) {
+               outb(cmd, iobase + PCMMIO_AI_CMD_REG);
+               adc_wait_ready(iobase);
 
-               /* read data hi byte */
-               val |= inb(iobase + iooffset + 1) << 8;
+               val = inb(iobase + PCMMIO_AI_LSB_REG);
+               val |= inb(iobase + PCMMIO_AI_MSB_REG) << 8;
 
                /* bipolar data is two's complement */
                if (comedi_range_is_bipolar(s, range))
                        val = comedi_offset_munge(s, val);
 
-               data[n] = val;
+               data[i] = val;
        }
-       /* return the number of samples read/written */
-       return n;
+
+       return insn->n;
 }
 
 static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -972,7 +965,7 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        s->type = COMEDI_SUBD_AI;
        s->n_chan = 16;
        s->len_chanlist = s->n_chan;
-       s->insn_read = ai_rinsn;
+       s->insn_read = pcmmio_ai_insn_read;
        subpriv->iobase = dev->iobase + 0;
        /* initialize the resource enable register by clearing it */
        outb(0, subpriv->iobase + 3);