/* Extra registers for new PCIe boards */
#define DIO200_ENHANCE 0x20 /* 1 to enable enhanced features */
#define DIO200_VERSION 0x24 /* Hardware version */
+#define DIO200_TS_CONFIG 0x600 /* Timestamp timer config register */
+#define DIO200_TS_COUNT 0x602 /* Timestamp timer count register */
/*
* Macros for constructing value for DIO_200_?CLK_SCE and
(((source) & 030) << 3) | ((source) & 007))
/*
- * Periods of the internal clock sources in nanoseconds.
+ * Timestamp timer configuration register (for new PCIe boards).
+ */
+#define TS_CONFIG_RESET 0x100 /* Reset counter to zero. */
+#define TS_CONFIG_CLK_SRC_MASK 0x0FF /* Clock source. */
+#define TS_CONFIG_MAX_CLK_SRC 2 /* Maximum clock source value. */
+
+/*
+ * Periods of the timestamp timer clock sources in nanoseconds.
+ */
+static const unsigned ts_clock_period[TS_CONFIG_MAX_CLK_SRC + 1] = {
+ 1, /* 1 nanosecond (but with 20 ns granularity). */
+ 1000, /* 1 microsecond. */
+ 1000000, /* 1 millisecond. */
+};
+
+/*
+ * Periods of the internal counter clock sources in nanoseconds.
*/
static const unsigned clock_period[32] = {
0, /* dedicated clock input/output pin */
}
}
+/*
+ * Handle 'insn_read' for a timer subdevice.
+ */
+#ifdef CONFIG_COMEDI_PCI
+static int
+dio200_subdev_timer_read(comedi_device * dev, comedi_subdevice * s,
+ comedi_insn * insn, lsampl_t * data)
+{
+ int n;
+
+ for (n = 0; n < insn->n; n++) {
+ data[n] = dio200_read32(dev, DIO200_TS_COUNT);
+ }
+ return n;
+}
+#endif
+
+/*
+ * Reset timer subdevice.
+ */
+#ifdef CONFIG_COMEDI_PCI
+static void
+dio200_subdev_timer_reset(comedi_device * dev, comedi_subdevice * s)
+{
+ unsigned int clock;
+
+ clock = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
+ dio200_write32(dev, DIO200_TS_CONFIG, clock | TS_CONFIG_RESET);
+ dio200_write32(dev, DIO200_TS_CONFIG, clock);
+}
+#endif
+
+/*
+ * Get timer subdevice clock source and period.
+ */
+#ifdef CONFIG_COMEDI_PCI
+static void
+dio200_subdev_timer_get_clock_src(comedi_device * dev, comedi_subdevice * s,
+ lsampl_t *src, lsampl_t *period)
+{
+ unsigned int clk;
+
+ clk = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
+ *src = clk;
+ *period = (clk < ARRAY_SIZE(ts_clock_period))
+ ? ts_clock_period[clk] : 0;
+}
+#endif
+
+/*
+ * Set timer subdevice clock source.
+ */
+#ifdef CONFIG_COMEDI_PCI
+static int
+dio200_subdev_timer_set_clock_src(comedi_device * dev, comedi_subdevice * s,
+ lsampl_t src)
+{
+ if (src > TS_CONFIG_MAX_CLK_SRC) {
+ return -EINVAL;
+ }
+ dio200_write32(dev, DIO200_TS_CONFIG, src);
+ return 0;
+}
+#endif
+
+/*
+ * Handle 'insn_config' for a timer subdevice.
+ */
+#ifdef CONFIG_COMEDI_PCI
+static int
+dio200_subdev_timer_config(comedi_device * dev, comedi_subdevice * s,
+ comedi_insn * insn, lsampl_t * data)
+{
+ int ret = 0;
+
+ switch (data[0]) {
+ case INSN_CONFIG_RESET:
+ dio200_subdev_timer_reset(dev, s);
+ break;
+ case INSN_CONFIG_SET_CLOCK_SRC:
+ ret = dio200_subdev_timer_set_clock_src(dev, s, data[1]);
+ if (ret < 0)
+ ret = -EINVAL;
+ break;
+ case INSN_CONFIG_GET_CLOCK_SRC:
+ dio200_subdev_timer_get_clock_src(dev, s, &data[1], &data[2]);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret < 0 ? ret : insn->n;
+}
+#endif
+
+/*
+ * This function initializes a timer subdevice.
+ *
+ * Uses the timestamp timer registers. There is only one timestamp timer.
+ */
+#ifdef CONFIG_COMEDI_PCI
+static int
+dio200_subdev_timer_init(comedi_device * dev, comedi_subdevice * s)
+{
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
+ s->n_chan = 1;
+ s->maxdata = 0xFFFFFFFF;
+ s->insn_read = dio200_subdev_timer_read;
+ s->insn_config = dio200_subdev_timer_config;
+ return 0;
+}
+#endif
+
+/*
+ * This function cleans up a timer subdevice.
+ */
+#ifdef CONFIG_COMEDI_PCI
+static void
+dio200_subdev_timer_cleanup(comedi_device * dev, comedi_subdevice * s)
+{
+ /* Nothing to do. */
+}
+#endif
+
#ifdef CONFIG_COMEDI_PCI
/*
* This function does some special set-up for the PCIe boards
}
break;
case sd_timer:
- /* TODO. Fall-thru to default for now. */
+ /* timer subdevice */
+#ifdef CONFIG_COMEDI_PCI
+ ret = dio200_subdev_timer_init(dev, s);
+ if (ret < 0) {
+ return ret;
+ }
+#else
+ s->type = COMEDI_SUBD_UNUSED;
+#endif
+ break;
default:
s->type = COMEDI_SUBD_UNUSED;
break;
case sd_intr:
dio200_subdev_intr_cleanup(dev, s);
break;
+ case sd_timer:
+#ifdef CONFIG_COMEDI_PCI
+ dio200_subdev_timer_cleanup(dev, s);
+#endif
+ break;
default:
break;
}