Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
[cascardo/linux.git] / drivers / staging / comedi / drivers / adq12b.c
index b4ea377..8b15cbe 100644 (file)
@@ -79,20 +79,20 @@ If you do not specify any options, they will default to
 #include "../comedidev.h"
 
 /* address scheme (page 2.17 of the manual) */
-#define ADQ12B_SIZE     16
-
-#define ADQ12B_CTREG    0x00
-#define ADQ12B_STINR    0x00
-#define ADQ12B_OUTBR    0x04
-#define ADQ12B_ADLOW    0x08
-#define ADQ12B_ADHIG    0x09
-#define ADQ12B_CONT0    0x0c
-#define ADQ12B_CONT1    0x0d
-#define ADQ12B_CONT2    0x0e
-#define ADQ12B_COWORD   0x0f
-
-/* mask of the bit at STINR to check end of conversion */
-#define ADQ12B_EOC     0x20
+#define ADQ12B_CTREG           0x00
+#define ADQ12B_CTREG_MSKP      (1 << 7)        /* enable pacer interrupt */
+#define ADQ12B_CTREG_GTP       (1 << 6)        /* enable pacer */
+#define ADQ12B_CTREG_RANGE(x)  ((x) << 4)
+#define ADQ12B_CTREG_CHAN(x)   ((x) << 0)
+#define ADQ12B_STINR           0x00
+#define ADQ12B_STINR_OUT2      (1 << 7)        /* timer 2 output state */
+#define ADQ12B_STINR_OUTP      (1 << 6)        /* pacer output state */
+#define ADQ12B_STINR_EOC       (1 << 5)        /* A/D end-of-conversion */
+#define ADQ12B_STINR_IN_MASK   (0x1f << 0)
+#define ADQ12B_OUTBR           0x04
+#define ADQ12B_ADLOW           0x08
+#define ADQ12B_ADHIG           0x09
+#define ADQ12B_TIMER_BASE      0x0c
 
 /* available ranges through the PGA gains */
 static const struct comedi_lrange range_adq12b_ai_bipolar = {
@@ -114,10 +114,7 @@ static const struct comedi_lrange range_adq12b_ai_unipolar = {
 };
 
 struct adq12b_private {
-       int unipolar;           /* option 2 of comedi_config (1 is iobase) */
-       int differential;       /* option 3 of comedi_config */
-       int last_channel;
-       int last_range;
+       unsigned int last_ctreg;
 };
 
 static int adq12b_ai_eoc(struct comedi_device *dev,
@@ -128,50 +125,45 @@ static int adq12b_ai_eoc(struct comedi_device *dev,
        unsigned char status;
 
        status = inb(dev->iobase + ADQ12B_STINR);
-       if (status & ADQ12B_EOC)
+       if (status & ADQ12B_STINR_EOC)
                return 0;
        return -EBUSY;
 }
 
-static int adq12b_ai_rinsn(struct comedi_device *dev,
-                          struct comedi_subdevice *s, struct comedi_insn *insn,
-                          unsigned int *data)
+static int adq12b_ai_insn_read(struct comedi_device *dev,
+                              struct comedi_subdevice *s,
+                              struct comedi_insn *insn,
+                              unsigned int *data)
 {
        struct adq12b_private *devpriv = dev->private;
-       int n;
-       int range, channel;
-       unsigned char hi, lo, status;
+       unsigned int chan = CR_CHAN(insn->chanspec);
+       unsigned int range = CR_RANGE(insn->chanspec);
+       unsigned int val;
        int ret;
+       int i;
 
        /* change channel and range only if it is different from the previous */
-       range = CR_RANGE(insn->chanspec);
-       channel = CR_CHAN(insn->chanspec);
-       if (channel != devpriv->last_channel || range != devpriv->last_range) {
-               outb((range << 4) | channel, dev->iobase + ADQ12B_CTREG);
+       val = ADQ12B_CTREG_RANGE(range) | ADQ12B_CTREG_CHAN(chan);
+       if (val != devpriv->last_ctreg) {
+               outb(val, dev->iobase + ADQ12B_CTREG);
+               devpriv->last_ctreg = val;
                udelay(50);     /* wait for the mux to settle */
        }
 
-       /* trigger conversion */
-       status = inb(dev->iobase + ADQ12B_ADLOW);
-
-       /* convert n samples */
-       for (n = 0; n < insn->n; n++) {
+       val = inb(dev->iobase + ADQ12B_ADLOW);  /* trigger A/D */
 
-               /* wait for end of conversion */
+       for (i = 0; i < insn->n; i++) {
                ret = comedi_timeout(dev, s, insn, adq12b_ai_eoc, 0);
                if (ret)
                        return ret;
 
-               /* read data */
-               hi = inb(dev->iobase + ADQ12B_ADHIG);
-               lo = inb(dev->iobase + ADQ12B_ADLOW);
-
-               data[n] = (hi << 8) | lo;
+               val = inb(dev->iobase + ADQ12B_ADHIG) << 8;
+               val |= inb(dev->iobase + ADQ12B_ADLOW); /* retriggers A/D */
 
+               data[i] = val;
        }
 
-       /* return the number of samples read/written */
-       return n;
+       return insn->n;
 }
 
 static int adq12b_di_insn_bits(struct comedi_device *dev,
@@ -180,7 +172,7 @@ static int adq12b_di_insn_bits(struct comedi_device *dev,
 {
 
        /* only bits 0-4 have information about digital inputs */
-       data[1] = (inb(dev->iobase + ADQ12B_STINR) & (0x1f));
+       data[1] = (inb(dev->iobase + ADQ12B_STINR) & ADQ12B_STINR_IN_MASK);
 
        return insn->n;
 }
@@ -216,7 +208,7 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        struct comedi_subdevice *s;
        int ret;
 
-       ret = comedi_request_region(dev, it->options[0], ADQ12B_SIZE);
+       ret = comedi_request_region(dev, it->options[0], 0x10);
        if (ret)
                return ret;
 
@@ -224,58 +216,44 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        if (!devpriv)
                return -ENOMEM;
 
-       devpriv->unipolar = it->options[1];
-       devpriv->differential = it->options[2];
-       /*
-        * initialize channel and range to -1 so we make sure we
-        * always write at least once to the CTREG in the instruction
-        */
-       devpriv->last_channel = -1;
-       devpriv->last_range = -1;
+       devpriv->last_ctreg = -1;       /* force ctreg update */
 
        ret = comedi_alloc_subdevices(dev, 3);
        if (ret)
                return ret;
 
+       /* Analog Input subdevice */
        s = &dev->subdevices[0];
-       /* analog input subdevice */
-       s->type = COMEDI_SUBD_AI;
-       if (devpriv->differential) {
-               s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
-               s->n_chan = 8;
+       s->type         = COMEDI_SUBD_AI;
+       if (it->options[2]) {
+               s->subdev_flags = SDF_READABLE | SDF_DIFF;
+               s->n_chan       = 8;
        } else {
-               s->subdev_flags = SDF_READABLE | SDF_GROUND;
-               s->n_chan = 16;
+               s->subdev_flags = SDF_READABLE | SDF_GROUND;
+               s->n_chan       = 16;
        }
+       s->maxdata      = 0xfff;
+       s->range_table  = it->options[1] ? &range_adq12b_ai_unipolar
+                                        : &range_adq12b_ai_bipolar;
+       s->insn_read    = adq12b_ai_insn_read;
 
-       if (devpriv->unipolar)
-               s->range_table = &range_adq12b_ai_unipolar;
-       else
-               s->range_table = &range_adq12b_ai_bipolar;
-
-       s->maxdata = 0xfff;
-
-       s->len_chanlist = 4;    /* This is the maximum chanlist length that
-                                  the board can handle */
-       s->insn_read = adq12b_ai_rinsn;
-
+       /* Digital Input subdevice */
        s = &dev->subdevices[1];
-       /* digital input subdevice */
-       s->type = COMEDI_SUBD_DI;
-       s->subdev_flags = SDF_READABLE;
-       s->n_chan = 5;
-       s->maxdata = 1;
-       s->range_table = &range_digital;
-       s->insn_bits = adq12b_di_insn_bits;
-
+       s->type         = COMEDI_SUBD_DI;
+       s->subdev_flags = SDF_READABLE;
+       s->n_chan       = 5;
+       s->maxdata      = 1;
+       s->range_table  = &range_digital;
+       s->insn_bits    = adq12b_di_insn_bits;
+
+       /* Digital Output subdevice */
        s = &dev->subdevices[2];
-       /* digital output subdevice */
-       s->type = COMEDI_SUBD_DO;
-       s->subdev_flags = SDF_WRITABLE;
-       s->n_chan = 8;
-       s->maxdata = 1;
-       s->range_table = &range_digital;
-       s->insn_bits = adq12b_do_insn_bits;
+       s->type         = COMEDI_SUBD_DO;
+       s->subdev_flags = SDF_WRITABLE;
+       s->n_chan       = 8;
+       s->maxdata      = 1;
+       s->range_table  = &range_digital;
+       s->insn_bits    = adq12b_do_insn_bits;
 
        return 0;
 }