staging: comedi: amplc_dio200_common: convert driver to use the comedi_8254 module
authorH Hartley Sweeten <hsweeten@visionengravers.com>
Tue, 24 Feb 2015 17:38:49 +0000 (10:38 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 2 Mar 2015 02:52:28 +0000 (18:52 -0800)
Convert this driver to use the comedi_8254 module to provide the 8254 timer support.

Add 'clock_src' and 'gate_src' members to the comedi_8254 data for convienence.

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/amplc_dio200_common.c
drivers/staging/comedi/drivers/comedi_8254.h

index 6ee50b481088ba646053441aeb4f5f480714b346..ebda03cd308da6d21dd0706c4a29c48815cbdc4d 100644 (file)
@@ -1275,6 +1275,7 @@ config COMEDI_KCOMEDILIB
          called kcomedilib.
 
 config COMEDI_AMPLC_DIO200
+       select COMEDI_8254
        tristate
 
 config COMEDI_AMPLC_PC236
index 08dab1fd91f2ea78c750b07b668edd98fd1165f6..0101e92667a16cfdbda2f23b7d724f7fc5d5999b 100644 (file)
@@ -26,7 +26,7 @@
 
 #include "amplc_dio200.h"
 #include "comedi_fc.h"
-#include "8253.h"
+#include "comedi_8254.h"
 #include "8255.h"              /* only for register defines */
 
 /* 200 series registers */
@@ -97,12 +97,6 @@ static const unsigned int ts_clock_period[TS_CONFIG_MAX_CLK_SRC + 1] = {
        1000000,                /* 1 millisecond. */
 };
 
-struct dio200_subdev_8254 {
-       unsigned int ofs;               /* Counter base offset */
-       unsigned int clock_src[3];      /* Current clock sources */
-       unsigned int gate_src[3];       /* Current gate sources */
-};
-
 struct dio200_subdev_8255 {
        unsigned int ofs;               /* DIO base offset */
 };
@@ -169,6 +163,27 @@ static void dio200_write32(struct comedi_device *dev,
                outl(val, dev->iobase + offset);
 }
 
+static unsigned int dio200_subdev_8254_offset(struct comedi_device *dev,
+                                             struct comedi_subdevice *s)
+{
+       const struct dio200_board *board = dev->board_ptr;
+       struct comedi_8254 *i8254 = s->private;
+       unsigned int offset;
+
+       /* get the offset that was passed to comedi_8254_*_init() */
+       if (dev->mmio)
+               offset = i8254->mmio - dev->mmio;
+       else
+               offset = i8254->iobase - dev->iobase;
+
+       /* remove the shift that was added for PCIe boards */
+       if (board->is_pcie)
+               offset >>= 3;
+
+       /* this offset now works for the dio200_{read,write} helpers */
+       return offset;
+}
+
 static int dio200_subdev_intr_insn_bits(struct comedi_device *dev,
                                        struct comedi_subdevice *s,
                                        struct comedi_insn *insn,
@@ -474,159 +489,26 @@ static irqreturn_t dio200_interrupt(int irq, void *d)
        return IRQ_RETVAL(handled);
 }
 
-static unsigned int dio200_subdev_8254_read_chan(struct comedi_device *dev,
-                                                struct comedi_subdevice *s,
-                                                unsigned int chan)
-{
-       struct dio200_subdev_8254 *subpriv = s->private;
-       unsigned int val;
-
-       /* latch counter */
-       val = chan << 6;
-       dio200_write8(dev, subpriv->ofs + i8254_control_reg, val);
-       /* read lsb, msb */
-       val = dio200_read8(dev, subpriv->ofs + chan);
-       val += dio200_read8(dev, subpriv->ofs + chan) << 8;
-       return val;
-}
-
-static void dio200_subdev_8254_write_chan(struct comedi_device *dev,
-                                         struct comedi_subdevice *s,
-                                         unsigned int chan,
-                                         unsigned int count)
-{
-       struct dio200_subdev_8254 *subpriv = s->private;
-
-       /* write lsb, msb */
-       dio200_write8(dev, subpriv->ofs + chan, count & 0xff);
-       dio200_write8(dev, subpriv->ofs + chan, (count >> 8) & 0xff);
-}
-
-static void dio200_subdev_8254_set_mode(struct comedi_device *dev,
-                                       struct comedi_subdevice *s,
-                                       unsigned int chan,
-                                       unsigned int mode)
-{
-       struct dio200_subdev_8254 *subpriv = s->private;
-       unsigned int byte;
-
-       byte = chan << 6;
-       byte |= 0x30;           /* access order: lsb, msb */
-       byte |= (mode & 0xf);   /* counter mode and BCD|binary */
-       dio200_write8(dev, subpriv->ofs + i8254_control_reg, byte);
-}
-
-static unsigned int dio200_subdev_8254_status(struct comedi_device *dev,
-                                             struct comedi_subdevice *s,
-                                             unsigned int chan)
-{
-       struct dio200_subdev_8254 *subpriv = s->private;
-
-       /* latch status */
-       dio200_write8(dev, subpriv->ofs + i8254_control_reg,
-                     0xe0 | (2 << chan));
-       /* read status */
-       return dio200_read8(dev, subpriv->ofs + chan);
-}
-
-static int dio200_subdev_8254_read(struct comedi_device *dev,
-                                  struct comedi_subdevice *s,
-                                  struct comedi_insn *insn,
-                                  unsigned int *data)
-{
-       int chan = CR_CHAN(insn->chanspec);
-       unsigned int n;
-
-       for (n = 0; n < insn->n; n++)
-               data[n] = dio200_subdev_8254_read_chan(dev, s, chan);
-
-       return insn->n;
-}
-
-static int dio200_subdev_8254_write(struct comedi_device *dev,
-                                   struct comedi_subdevice *s,
-                                   struct comedi_insn *insn,
-                                   unsigned int *data)
-{
-       int chan = CR_CHAN(insn->chanspec);
-       unsigned int n;
-
-       for (n = 0; n < insn->n; n++)
-               dio200_subdev_8254_write_chan(dev, s, chan, data[n]);
-
-       return insn->n;
-}
-
-static int dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
-                                          struct comedi_subdevice *s,
-                                          unsigned int counter_number,
-                                          unsigned int gate_src)
-{
-       const struct dio200_board *board = dev->board_ptr;
-       struct dio200_subdev_8254 *subpriv = s->private;
-       unsigned char byte;
-
-       if (!board->has_clk_gat_sce)
-               return -1;
-       if (gate_src > (board->is_pcie ? 31 : 7))
-               return -1;
-
-       subpriv->gate_src[counter_number] = gate_src;
-       byte = gat_sce((subpriv->ofs >> 2) & 1, counter_number, gate_src);
-       dio200_write8(dev, DIO200_GAT_SCE(subpriv->ofs >> 3), byte);
-
-       return 0;
-}
-
-static int dio200_subdev_8254_get_gate_src(struct comedi_device *dev,
-                                          struct comedi_subdevice *s,
-                                          unsigned int counter_number)
-{
-       const struct dio200_board *board = dev->board_ptr;
-       struct dio200_subdev_8254 *subpriv = s->private;
-
-       if (!board->has_clk_gat_sce)
-               return -1;
-
-       return subpriv->gate_src[counter_number];
-}
-
-static int dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
+static void dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
                                            struct comedi_subdevice *s,
-                                           unsigned int counter_number,
-                                           unsigned int clock_src)
+                                           unsigned int chan,
+                                           unsigned int src)
 {
-       const struct dio200_board *board = dev->board_ptr;
-       struct dio200_subdev_8254 *subpriv = s->private;
-       unsigned char byte;
-
-       if (!board->has_clk_gat_sce)
-               return -1;
-       if (clock_src > (board->is_pcie ? 31 : 7))
-               return -1;
-
-       subpriv->clock_src[counter_number] = clock_src;
-       byte = clk_sce((subpriv->ofs >> 2) & 1, counter_number, clock_src);
-       dio200_write8(dev, DIO200_CLK_SCE(subpriv->ofs >> 3), byte);
+       unsigned int offset = dio200_subdev_8254_offset(dev, s);
 
-       return 0;
+       dio200_write8(dev, DIO200_GAT_SCE(offset >> 3),
+                     gat_sce((offset >> 2) & 1, chan, src));
 }
 
-static int dio200_subdev_8254_get_clock_src(struct comedi_device *dev,
-                                           struct comedi_subdevice *s,
-                                           unsigned int counter_number,
-                                           unsigned int *period_ns)
+static void dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
+                                            struct comedi_subdevice *s,
+                                            unsigned int chan,
+                                            unsigned int src)
 {
-       const struct dio200_board *board = dev->board_ptr;
-       struct dio200_subdev_8254 *subpriv = s->private;
-       unsigned clock_src;
-
-       if (!board->has_clk_gat_sce)
-               return -1;
+       unsigned int offset = dio200_subdev_8254_offset(dev, s);
 
-       clock_src = subpriv->clock_src[counter_number];
-       *period_ns = clock_period[clock_src];
-       return clock_src;
+       dio200_write8(dev, DIO200_CLK_SCE(offset >> 3),
+                     clk_sce((offset >> 2) & 1, chan, src));
 }
 
 static int dio200_subdev_8254_config(struct comedi_device *dev,
@@ -634,51 +516,44 @@ static int dio200_subdev_8254_config(struct comedi_device *dev,
                                     struct comedi_insn *insn,
                                     unsigned int *data)
 {
-       int ret = 0;
-       int chan = CR_CHAN(insn->chanspec);
+       const struct dio200_board *board = dev->board_ptr;
+       struct comedi_8254 *i8254 = s->private;
+       unsigned int chan = CR_CHAN(insn->chanspec);
+       unsigned int max_src = board->is_pcie ? 31 : 7;
+       unsigned int src;
+
+       if (!board->has_clk_gat_sce)
+               return -EINVAL;
 
        switch (data[0]) {
-       case INSN_CONFIG_SET_COUNTER_MODE:
-               if (data[1] > (I8254_MODE5 | I8254_BCD))
-                       ret = -EINVAL;
-               else
-                       dio200_subdev_8254_set_mode(dev, s, chan, data[1]);
-               break;
-       case INSN_CONFIG_8254_READ_STATUS:
-               data[1] = dio200_subdev_8254_status(dev, s, chan);
-               break;
        case INSN_CONFIG_SET_GATE_SRC:
-               ret = dio200_subdev_8254_set_gate_src(dev, s, chan, data[2]);
-               if (ret < 0)
-                       ret = -EINVAL;
+               src = data[2];
+               if (src > max_src)
+                       return -EINVAL;
+
+               dio200_subdev_8254_set_gate_src(dev, s, chan, src);
+               i8254->gate_src[chan] = src;
                break;
        case INSN_CONFIG_GET_GATE_SRC:
-               ret = dio200_subdev_8254_get_gate_src(dev, s, chan);
-               if (ret < 0) {
-                       ret = -EINVAL;
-                       break;
-               }
-               data[2] = ret;
+               data[2] = i8254->gate_src[chan];
                break;
        case INSN_CONFIG_SET_CLOCK_SRC:
-               ret = dio200_subdev_8254_set_clock_src(dev, s, chan, data[1]);
-               if (ret < 0)
-                       ret = -EINVAL;
+               src = data[1];
+               if (src > max_src)
+                       return -EINVAL;
+
+               dio200_subdev_8254_set_clock_src(dev, s, chan, src);
+               i8254->clock_src[chan] = src;
                break;
        case INSN_CONFIG_GET_CLOCK_SRC:
-               ret = dio200_subdev_8254_get_clock_src(dev, s, chan, &data[2]);
-               if (ret < 0) {
-                       ret = -EINVAL;
-                       break;
-               }
-               data[1] = ret;
+               data[1] = i8254->clock_src[chan];
+               data[2] = clock_period[i8254->clock_src[chan]];
                break;
        default:
-               ret = -EINVAL;
-               break;
+               return -EINVAL;
        }
 
-       return ret < 0 ? ret : insn->n;
+       return insn->n;
 }
 
 static int dio200_subdev_8254_init(struct comedi_device *dev,
@@ -686,28 +561,46 @@ static int dio200_subdev_8254_init(struct comedi_device *dev,
                                   unsigned int offset)
 {
        const struct dio200_board *board = dev->board_ptr;
-       struct dio200_subdev_8254 *subpriv;
-       unsigned int chan;
+       struct comedi_8254 *i8254;
+       unsigned int regshift;
+       int chan;
+
+       /*
+        * PCIe boards need the offset shifted in order to get the
+        * correct base address of the timer.
+        */
+       if (board->is_pcie) {
+               offset <<= 3;
+               regshift = 3;
+       } else {
+               regshift = 0;
+       }
 
-       subpriv = comedi_alloc_spriv(s, sizeof(*subpriv));
-       if (!subpriv)
+       if (dev->mmio)
+               i8254 = comedi_8254_mm_init(dev->mmio + offset,
+                                           0, I8254_IO8, regshift);
+       else
+               i8254 = comedi_8254_init(dev->iobase + offset,
+                                        0, I8254_IO8, regshift);
+       if (!i8254)
                return -ENOMEM;
 
-       s->type = COMEDI_SUBD_COUNTER;
-       s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
-       s->n_chan = 3;
-       s->maxdata = 0xFFFF;
-       s->insn_read = dio200_subdev_8254_read;
-       s->insn_write = dio200_subdev_8254_write;
-       s->insn_config = dio200_subdev_8254_config;
+       comedi_8254_subdevice_init(s, i8254);
 
-       subpriv->ofs = offset;
+       i8254->insn_config = dio200_subdev_8254_config;
+
+       /*
+        * There could be multiple timers so this driver does not
+        * use dev->pacer to save the i8254 pointer. Instead,
+        * comedi_8254_subdevice_init() saved the i8254 pointer in
+        * s->private. Set the runflag bit so that the core will
+        * automatically free it when the driver is detached.
+        */
+       s->runflags |= COMEDI_SRF_FREE_SPRIV;
 
        /* Initialize channels. */
-       for (chan = 0; chan < 3; chan++) {
-               dio200_subdev_8254_set_mode(dev, s, chan,
-                                           I8254_MODE0 | I8254_BINARY);
-               if (board->has_clk_gat_sce) {
+       if (board->has_clk_gat_sce) {
+               for (chan = 0; chan < 3; chan++) {
                        /* Gate source 0 is VCC (logic 1). */
                        dio200_subdev_8254_set_gate_src(dev, s, chan, 0);
                        /* Clock source 0 is the dedicated clock input. */
index 54f2bf8d5bf644c0cb126ea2be73ec62997b7bd8..d89f6d94f8aa623e5f628eecb65f764de38a11f4 100644 (file)
@@ -71,6 +71,8 @@
  * #next_div:          next divisor for single counter
  * @next_div1:         next divisor to use for first cascaded counter
  * @next_div2:         next divisor to use for second cascaded counter
+ * @clock_src;         current clock source for each counter (driver specific)
+ * @gate_src;          current gate source  for each counter (driver specific)
  * @busy:              flags used to indicate that a counter is "busy"
  * @insn_config:       driver specific (*insn_config) callback
  */
@@ -86,6 +88,8 @@ struct comedi_8254 {
        unsigned int next_div;
        unsigned int next_div1;
        unsigned int next_div2;
+       unsigned int clock_src[3];
+       unsigned int gate_src[3];
        bool busy[3];
 
        int (*insn_config)(struct comedi_device *, struct comedi_subdevice *s,