staging: comedi: adv_pci1710: convert driver to use the comedi_8254 module
authorH Hartley Sweeten <hsweeten@visionengravers.com>
Mon, 23 Feb 2015 21:57:40 +0000 (14:57 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 2 Mar 2015 02:51:50 +0000 (18:51 -0800)
This driver uses an 8254 timer to generate the pacer clock used for analog
input data acquisition. It also provides a comedi_subdevice to allow the user
to use channel 0 of the 8254 timer. Currently the subdevice support does not
work correctly due to and (*insn_config) that does not follow the comedi API.

Convert it to use the comedi_8254 module to provide support for the 8254 timer
and proper support for the subdevice.

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/Kconfig
drivers/staging/comedi/drivers/adv_pci1710.c

index 85c5c876e65d565e79212734492b53c2d7547ad4..6d469e0d7095f2da3d70771093f861a15db89034 100644 (file)
@@ -739,6 +739,7 @@ config COMEDI_ADL_PCI9118
 
 config COMEDI_ADV_PCI1710
        tristate "Advantech PCI-171x, PCI-1720 and PCI-1731 support"
+       select COMEDI_8254
        ---help---
          Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711,
          PCI-1713, PCI-1720 and PCI-1731
index 9800c01e6fb97409966e1b35157656ff139f31ea..9c881ff01297208253c3a8ccb06e5801cb9795cc 100644 (file)
@@ -48,7 +48,7 @@ Configuration options:
 #include "../comedidev.h"
 
 #include "comedi_fc.h"
-#include "8253.h"
+#include "comedi_8254.h"
 #include "amcc_s5933.h"
 
 #define PCI171x_AD_DATA         0      /* R:   A/D data */
@@ -67,11 +67,6 @@ Configuration options:
 
 #define PCI171X_TIMER_BASE     0x18
 
-#define PCI171x_CNT0   24      /* R/W: 8254 counter 0 */
-#define PCI171x_CNT1   26      /* R/W: 8254 counter 1 */
-#define PCI171x_CNT2   28      /* R/W: 8254 counter 2 */
-#define PCI171x_CNTCTRL        30      /* W:   8254 counter control */
-
 /* upper bits from status register (PCI171x_STATUS) (lower is same with control
  * reg) */
 #define        Status_FE       0x0100  /* 1=FIFO is empty */
@@ -87,16 +82,6 @@ Configuration options:
 #define Control_EXT    0x0004  /* 1=external trigger source */
 #define Control_PACER  0x0002  /* 1=enable internal 8254 trigger source */
 #define Control_SW     0x0001  /* 1=enable software trigger source */
-/* bits from counter control register (PCI171x_CNTCTRL) */
-#define Counter_BCD     0x0001 /* 0 = binary counter, 1 = BCD counter */
-#define Counter_M0      0x0002 /* M0-M2 select modes 0-5 */
-#define Counter_M1      0x0004 /* 000 = mode 0, 010 = mode 2 ... */
-#define Counter_M2      0x0008
-#define Counter_RW0     0x0010 /* RW0/RW1 select read/write mode */
-#define Counter_RW1     0x0020
-#define Counter_SC0     0x0040 /* Select Counter. Only 00 or 11 may */
-#define Counter_SC1     0x0080 /* be used, 00 for CNT0,
-                                * 11 for read-back command */
 
 #define PCI1720_DA0     0      /* W:   D/A register 0 */
 #define PCI1720_DA1     2      /* W:   D/A register 1 */
@@ -265,15 +250,9 @@ struct pci1710_private {
        unsigned char ai_et;
        unsigned int ai_et_CntrlReg;
        unsigned int ai_et_MuxVal;
-       unsigned int next_divisor1;
-       unsigned int next_divisor2;
-       unsigned int divisor1;
-       unsigned int divisor2;
        unsigned int act_chanlist[32];  /*  list of scanned channel */
        unsigned char saved_seglen;     /* len of the non-repeating chanlist */
        unsigned char da_ranges;        /*  copy of D/A outpit range register */
-       unsigned int cnt0_write_wait;   /* after a write, wait for update of the
-                                        * internal state */
 };
 
 static int pci171x_ai_check_chanlist(struct comedi_device *dev,
@@ -509,105 +488,6 @@ static int pci171x_do_insn_bits(struct comedi_device *dev,
        return insn->n;
 }
 
-static void pci171x_start_pacer(struct comedi_device *dev,
-                               bool load_counters)
-{
-       struct pci1710_private *devpriv = dev->private;
-       unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE;
-
-       i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
-       i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
-
-       if (load_counters) {
-               i8254_write(timer_base, 1, 2, devpriv->divisor2);
-               i8254_write(timer_base, 1, 1, devpriv->divisor1);
-       }
-}
-
-static int pci171x_counter_insn_read(struct comedi_device *dev,
-                                    struct comedi_subdevice *s,
-                                    struct comedi_insn *insn,
-                                    unsigned int *data)
-{
-       unsigned int msb, lsb, ccntrl;
-       int i;
-
-       ccntrl = 0xD2;          /* count only */
-       for (i = 0; i < insn->n; i++) {
-               outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
-
-               lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
-               msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
-
-               data[0] = lsb | (msb << 8);
-       }
-
-       return insn->n;
-}
-
-static int pci171x_counter_insn_write(struct comedi_device *dev,
-                                     struct comedi_subdevice *s,
-                                     struct comedi_insn *insn,
-                                     unsigned int *data)
-{
-       struct pci1710_private *devpriv = dev->private;
-       uint msb, lsb, ccntrl, status;
-
-       lsb = data[0] & 0x00FF;
-       msb = (data[0] & 0xFF00) >> 8;
-
-       /* write lsb, then msb */
-       outw(lsb, dev->iobase + PCI171x_CNT0);
-       outw(msb, dev->iobase + PCI171x_CNT0);
-
-       if (devpriv->cnt0_write_wait) {
-               /* wait for the new count to be loaded */
-               ccntrl = 0xE2;
-               do {
-                       outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
-                       status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
-               } while (status & 0x40);
-       }
-
-       return insn->n;
-}
-
-static int pci171x_counter_insn_config(struct comedi_device *dev,
-                                      struct comedi_subdevice *s,
-                                      struct comedi_insn *insn,
-                                      unsigned int *data)
-{
-#ifdef unused
-       /* This doesn't work like a normal Comedi counter config */
-       struct pci1710_private *devpriv = dev->private;
-       uint ccntrl = 0;
-
-       devpriv->cnt0_write_wait = data[0] & 0x20;
-
-       /* internal or external clock? */
-       if (!(data[0] & 0x10)) {        /* internal */
-               devpriv->CntrlReg &= ~Control_CNT0;
-       } else {
-               devpriv->CntrlReg |= Control_CNT0;
-       }
-       outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
-
-       if (data[0] & 0x01)
-               ccntrl |= Counter_M0;
-       if (data[0] & 0x02)
-               ccntrl |= Counter_M1;
-       if (data[0] & 0x04)
-               ccntrl |= Counter_M2;
-       if (data[0] & 0x08)
-               ccntrl |= Counter_BCD;
-       ccntrl |= Counter_RW0;  /* set read/write mode */
-       ccntrl |= Counter_RW1;
-       outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
-#endif
-
-       return 1;
-}
-
 static int pci1720_ao_insn_write(struct comedi_device *dev,
                                 struct comedi_subdevice *s,
                                 struct comedi_insn *insn,
@@ -647,7 +527,7 @@ static int pci171x_ai_cancel(struct comedi_device *dev,
        devpriv->CntrlReg |= Control_SW;
        /* reset any operations */
        outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
-       pci171x_start_pacer(dev, false);
+       comedi_8254_pacer_enable(dev->pacer, 1, 2, false);
        outb(0, dev->iobase + PCI171x_CLRFIFO);
        outb(0, dev->iobase + PCI171x_CLRINT);
 
@@ -768,7 +648,7 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d)
                outb(0, dev->iobase + PCI171x_CLRINT);
                outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
                outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
-               pci171x_start_pacer(dev, true);
+               comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
                return IRQ_HANDLED;
        }
 
@@ -787,8 +667,6 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
        struct pci1710_private *devpriv = dev->private;
        struct comedi_cmd *cmd = &s->async->cmd;
 
-       pci171x_start_pacer(dev, false);
-
        pci171x_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len,
                                  devpriv->saved_seglen);
 
@@ -799,10 +677,9 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
        if ((cmd->flags & CMDF_WAKE_EOS) == 0)
                devpriv->CntrlReg |= Control_ONEFH;
 
-       devpriv->divisor1 = devpriv->next_divisor1;
-       devpriv->divisor2 = devpriv->next_divisor2;
-
        if (cmd->convert_src == TRIG_TIMER) {
+               comedi_8254_update_divisors(dev->pacer);
+
                devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
                if (cmd->start_src == TRIG_EXT) {
                        devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
@@ -816,7 +693,7 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
                outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
 
                if (cmd->start_src == TRIG_NOW)
-                       pci171x_start_pacer(dev, true);
+                       comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
        } else {        /* TRIG_EXT */
                devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
                outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
@@ -829,9 +706,7 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
                              struct comedi_subdevice *s,
                              struct comedi_cmd *cmd)
 {
-       struct pci1710_private *devpriv = dev->private;
        int err = 0;
-       unsigned int arg;
 
        /* Step 1 : check if triggers are trivially valid */
 
@@ -878,11 +753,9 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
        /* step 4: fix up any arguments */
 
        if (cmd->convert_src == TRIG_TIMER) {
-               arg = cmd->convert_arg;
-               i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
-                                         &devpriv->next_divisor1,
-                                         &devpriv->next_divisor2,
-                                         &arg, cmd->flags);
+               unsigned int arg = cmd->convert_arg;
+
+               comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
                err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
        }
 
@@ -899,19 +772,54 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
        return 0;
 }
 
+static int pci171x_insn_counter_config(struct comedi_device *dev,
+                                      struct comedi_subdevice *s,
+                                      struct comedi_insn *insn,
+                                      unsigned int *data)
+{
+       struct pci1710_private *devpriv = dev->private;
+
+       switch (data[0]) {
+       case INSN_CONFIG_SET_CLOCK_SRC:
+               switch (data[1]) {
+               case 0: /* internal */
+                       devpriv->ai_et_CntrlReg &= ~Control_CNT0;
+                       break;
+               case 1: /* external */
+                       devpriv->ai_et_CntrlReg |= Control_CNT0;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               outw(devpriv->ai_et_CntrlReg, dev->iobase + PCI171x_CONTROL);
+               break;
+       case INSN_CONFIG_GET_CLOCK_SRC:
+               if (devpriv->ai_et_CntrlReg & Control_CNT0) {
+                       data[1] = 1;
+                       data[2] = 0;
+               } else {
+                       data[1] = 0;
+                       data[2] = I8254_OSC_BASE_10MHZ;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return insn->n;
+}
+
 static int pci171x_reset(struct comedi_device *dev)
 {
        const struct boardtype *board = dev->board_ptr;
        struct pci1710_private *devpriv = dev->private;
 
-       outw(0x30, dev->iobase + PCI171x_CNTCTRL);
        /* Software trigger, CNT0=external */
        devpriv->CntrlReg = Control_SW | Control_CNT0;
        /* reset any operations */
        outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
        outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
        outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
-       pci171x_start_pacer(dev, false);
        devpriv->da_ranges = 0;
        if (board->has_ao) {
                /* set DACs to 0..5V */
@@ -978,6 +886,11 @@ static int pci1710_auto_attach(struct comedi_device *dev,
                return ret;
        dev->iobase = pci_resource_start(pcidev, 2);
 
+       dev->pacer = comedi_8254_init(dev->iobase + PCI171X_TIMER_BASE,
+                                     I8254_OSC_BASE_10MHZ, I8254_IO16, 0);
+       if (!dev->pacer)
+               return -ENOMEM;
+
        n_subdevices = 0;
        if (board->n_aichan)
                n_subdevices++;
@@ -1074,16 +987,17 @@ static int pci1710_auto_attach(struct comedi_device *dev,
                subdev++;
        }
 
+       /* Counter subdevice (8254) */
        if (board->has_counter) {
                s = &dev->subdevices[subdev];
-               s->type         = COMEDI_SUBD_COUNTER;
-               s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-               s->n_chan       = 1;
-               s->maxdata      = 0xffff;
-               s->range_table  = &range_unknown;
-               s->insn_read    = pci171x_counter_insn_read;
-               s->insn_write   = pci171x_counter_insn_write;
-               s->insn_config  = pci171x_counter_insn_config;
+               comedi_8254_subdevice_init(s, dev->pacer);
+
+               dev->pacer->insn_config = pci171x_insn_counter_config;
+
+               /* counters 1 and 2 are used internally for the pacer */
+               comedi_8254_set_busy(dev->pacer, 1, true);
+               comedi_8254_set_busy(dev->pacer, 2, true);
+
                subdev++;
        }