staging: comedi: pcmmio: cleanup ao_winsn()
authorH Hartley Sweeten <hsweeten@visionengravers.com>
Mon, 9 Dec 2013 22:30:47 +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
to set the range before writing the DAC value. Since the range is constant
for the entire comedi_insn it only needs to be set once. All writes to the
DAC after that will use the same range.

Define the register map for the analog output 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 5726ded45f9203e72d64d684a2cbf36eb1dc9f56..42d7f1479323d1685e8b3b5d6d96f03275ad64e7 100644 (file)
@@ -83,24 +83,47 @@ Configuration Options:
 /*
  * 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)
-#define PCMMIO_AI_STATUS_REG           0x03
-#define PCMMIO_AI_STATUS_DATA_READY    (1 << 7)
-#define PCMMIO_AI_STATUS_DATA_DMA_PEND (1 << 6)
-#define PCMMIO_AI_STATUS_CMD_DMA_PEND  (1 << 5)
-#define PCMMIO_AI_STATUS_IRQ_PEND      (1 << 4)
-#define PCMMIO_AI_STATUS_DATA_DRQ_ENA  (1 << 2)
-#define PCMMIO_AI_STATUS_REG_SEL       (1 << 3)
-#define PCMMIO_AI_STATUS_CMD_DRQ_ENA   (1 << 1)
-#define PCMMIO_AI_STATUS_IRQ_ENA       (1 << 0)
-#define PCMMIO_AI_RESOURCE_REG         0x03
-#define PCMMIO_AI_2ND_ADC_OFFSET       0x04
+#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)
+#define PCMMIO_AI_STATUS_REG                   0x03
+#define PCMMIO_AI_STATUS_DATA_READY            (1 << 7)
+#define PCMMIO_AI_STATUS_DATA_DMA_PEND         (1 << 6)
+#define PCMMIO_AI_STATUS_CMD_DMA_PEND          (1 << 5)
+#define PCMMIO_AI_STATUS_IRQ_PEND              (1 << 4)
+#define PCMMIO_AI_STATUS_DATA_DRQ_ENA          (1 << 2)
+#define PCMMIO_AI_STATUS_REG_SEL               (1 << 3)
+#define PCMMIO_AI_STATUS_CMD_DRQ_ENA           (1 << 1)
+#define PCMMIO_AI_STATUS_IRQ_ENA               (1 << 0)
+#define PCMMIO_AI_RESOURCE_REG                 0x03
+#define PCMMIO_AI_2ND_ADC_OFFSET               0x04
+
+#define PCMMIO_AO_LSB_REG                      0x08
+#define PCMMIO_AO_LSB_SPAN(x)                  (((x) & 0xf) << 0)
+#define PCMMIO_AO_MSB_REG                      0x09
+#define PCMMIO_AO_CMD_REG                      0x0a
+#define PCMMIO_AO_CMD_WR_SPAN                  (0x2 << 4)
+#define PCMMIO_AO_CMD_WR_CODE                  (0x3 << 4)
+#define PCMMIO_AO_CMD_UPDATE                   (0x4 << 4)
+#define PCMMIO_AO_CMD_UPDATE_ALL               (0x5 << 4)
+#define PCMMIO_AO_CMD_WR_SPAN_UPDATE           (0x6 << 4)
+#define PCMMIO_AO_CMD_WR_CODE_UPDATE           (0x7 << 4)
+#define PCMMIO_AO_CMD_WR_SPAN_UPDATE_ALL       (0x8 << 4)
+#define PCMMIO_AO_CMD_WR_CODE_UPDATE_ALL       (0x9 << 4)
+#define PCMMIO_AO_CMD_RD_B1_SPAN               (0xa << 4)
+#define PCMMIO_AO_CMD_RD_B1_CODE               (0xb << 4)
+#define PCMMIO_AO_CMD_RD_B2_SPAN               (0xc << 4)
+#define PCMMIO_AO_CMD_RD_B2_CODE               (0xd << 4)
+#define PCMMIO_AO_CMD_NOP                      (0xf << 4)
+#define PCMMIO_AO_CMD_CHAN_SEL(x)              (((x) & 0x03) << 1)
+#define PCMMIO_AO_CMD_CHAN_SEL_ALL             (0x0f << 0)
+#define PCMMIO_AO_STATUS_REG                   0x0b
+#define PCMMIO_AO_RESOURCE_ENA_REG             0x0b
+#define PCMMIO_AO_2ND_DAC_OFFSET               0x04
 
 /* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */
 #define CHANS_PER_PORT   8
@@ -880,53 +903,51 @@ static int wait_dac_ready(unsigned long iobase)
        return 1;
 }
 
-static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
-                   struct comedi_insn *insn, unsigned int *data)
+static int pcmmio_ao_insn_write(struct comedi_device *dev,
+                               struct comedi_subdevice *s,
+                               struct comedi_insn *insn,
+                               unsigned int *data)
 {
        struct pcmmio_private *devpriv = dev->private;
-       unsigned long iobase = dev->iobase + 8;
-       unsigned int iooffset = 0;
-       int n;
-
-       for (n = 0; n < insn->n; n++) {
-               unsigned chan = CR_CHAN(insn->chanspec), range =
-                   CR_RANGE(insn->chanspec);
-               if (chan < s->n_chan) {
-                       unsigned char command_byte = 0, range_byte =
-                           range & ((1 << 4) - 1);
-                       if (chan >= 4)
-                               chan -= 4, iooffset += 4;
-                       /* set the range.. */
-                       outb(range_byte, iobase + iooffset + 0);
-                       outb(0, iobase + iooffset + 1);
-
-                       /* tell it to begin */
-                       command_byte = (chan << 1) | 0x60;
-                       outb(command_byte, iobase + iooffset + 2);
+       unsigned long iobase = dev->iobase;
+       unsigned int chan = CR_CHAN(insn->chanspec);
+       unsigned int range = CR_RANGE(insn->chanspec);
+       unsigned int val = devpriv->ao_readback[chan];
+       unsigned char cmd = 0;
+       int i;
 
-                       wait_dac_ready(iobase + iooffset);
+       /*
+        * The PCM-MIO has two Linear Tech LTC2704 DAC devices. Each device
+        * is a 4-channel converter with software-selectable output range.
+        */
 
-                       /* low order byte */
-                       outb(data[n] & 0xff, iobase + iooffset + 0);
+       if (chan > 3) {
+               cmd |= PCMMIO_AO_CMD_CHAN_SEL(chan - 4);
+               iobase += PCMMIO_AO_2ND_DAC_OFFSET;
+       } else {
+               cmd |= PCMMIO_AO_CMD_CHAN_SEL(chan);
+       }
 
-                       /* high order byte */
-                       outb((data[n] >> 8) & 0xff, iobase + iooffset + 1);
+       /* set the range for the channel */
+       outb(PCMMIO_AO_LSB_SPAN(range), iobase + PCMMIO_AO_LSB_REG);
+       outb(0, iobase + PCMMIO_AO_MSB_REG);
+       outb(cmd | PCMMIO_AO_CMD_WR_SPAN_UPDATE, iobase + PCMMIO_AO_CMD_REG);
+       wait_dac_ready(iobase);
 
-                       /*
-                        * set bit 4 of command byte to indicate
-                        * data is loaded and trigger conversion
-                        */
-                       command_byte = 0x70 | (chan << 1);
-                       /* trigger converion */
-                       outb(command_byte, iobase + iooffset + 2);
+       for (i = 0; i < insn->n; i++) {
+               val = data[i];
 
-                       wait_dac_ready(iobase + iooffset);
+               /* write the data to the channel */
+               outb(val & 0xff, iobase + PCMMIO_AO_LSB_REG);
+               outb((val >> 8) & 0xff, iobase + PCMMIO_AO_MSB_REG);
+               outb(cmd | PCMMIO_AO_CMD_WR_CODE_UPDATE,
+                    iobase + PCMMIO_AO_CMD_REG);
+               wait_dac_ready(iobase);
 
-                       /* save to shadow register for ao_rinsn */
-                       devpriv->ao_readback[chan] = data[n];
-               }
+               devpriv->ao_readback[chan] = val;
        }
-       return n;
+
+       return insn->n;
 }
 
 static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -996,11 +1017,12 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        s->n_chan = 8;
        s->len_chanlist = s->n_chan;
        s->insn_read = ao_rinsn;
-       s->insn_write = ao_winsn;
+       s->insn_write = pcmmio_ao_insn_write;
 
        /* initialize the resource enable register by clearing it */
-       outb(0, dev->iobase + 8 + 3);
-       outb(0, dev->iobase + 8 + 4 + 3);
+       outb(0, dev->iobase + PCMMIO_AO_RESOURCE_ENA_REG);
+       outb(0, dev->iobase + PCMMIO_AO_2ND_DAC_OFFSET +
+               PCMMIO_AO_RESOURCE_ENA_REG);
 
        port = 0;
        asic = 0;