Sources 6 1 6
0 PPI-X-C0 JUMPER-J5 PPI-X-C0
1 PPI-X-C3 PPI-X-C3
- 2 CTR-Y1-OUT PPI-Y-C0
- 3 CTR-Y2-OUT PPI-Y-C3
- 4 CTR-Z1-OUT CTR-Z1-OUT
- 5 CTR-Z2-OUT CTR-Z2-OUT
+ 2 CTR-Y1-OUT1 PPI-Y-C0
+ 3 CTR-Y2-OUT1 PPI-Y-C3
+ 4 CTR-Z1-OUT1 CTR-Z1-OUT1
+ 5 CTR-Z2-OUT1 CTR-Z2-OUT1
PCIe215 PC218E PCIe236
------------- ------------- -------------
Sources 6 6 6
- 0 PPI-X-C0 CTR-X1-OUT PPI-X-C0
- 1 PPI-X-C3 CTR-X2-OUT PPI-X-C3
- 2 PPI-Y-C0 CTR-Y1-OUT unused
- 3 PPI-Y-C3 CTR-Y2-OUT unused
- 4 CTR-Z1-OUT CTR-Z1-OUT CTR-Z1-OUT
- 5 CTR-Z2-OUT CTR-Z2-OUT CTR-Z2-OUT
+ 0 PPI-X-C0 CTR-X1-OUT1 PPI-X-C0
+ 1 PPI-X-C3 CTR-X2-OUT1 PPI-X-C3
+ 2 PPI-Y-C0 CTR-Y1-OUT1 unused
+ 3 PPI-Y-C3 CTR-Y2-OUT1 unused
+ 4 CTR-Z1-OUT1 CTR-Z1-OUT1 CTR-Z1-OUT1
+ 5 CTR-Z2-OUT1 CTR-Z2-OUT1 CTR-Z2-OUT1
PC272E/PCI272 PCIe296
------------- -------------
1 PPI-X-C3 PPI-X1-C3
2 PPI-Y-C0 PPI-Y1-C0
3 PPI-Y-C3 PPI-Y2-C3
- 4 PPI-Z-C0 CTR-Z1-OUT
- 5 PPI-Z-C3 CTR-Z2-OUT
+ 4 PPI-Z-C0 CTR-Z1-OUT1
+ 5 PPI-Z-C3 CTR-Z2-OUT1
When an interrupt source is enabled in the interrupt source enable
register, a rising edge on the source signal latches the corresponding
#define DIO200_YGAT_SCE 0x1c /* Group Y gate selection register */
#define DIO200_ZGAT_SCE 0x1d /* Group Z gate selection register */
#define DIO200_INT_SCE 0x1e /* Interrupt enable/status register */
+/* 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
*
* 'which' is: 0 for CTR-X1, CTR-Y1, CTR-Z1; 1 for CTR-X2, CTR-Y2 or CTR-Z2.
* 'chan' is the channel: 0, 1 or 2.
- * 'source' is the signal source: 0 to 7.
+ * 'source' is the signal source: 0 to 7, or 0 to 31 for "enhanced" boards.
*/
-#define CLK_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
-#define GAT_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source))
+#define CLK_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | \
+ (((source) & 030) << 3) | ((source) & 007))
+#define GAT_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | \
+ (((source) & 030) << 3) | ((source) & 007))
/*
- * Periods of the internal clock sources in nanoseconds.
+ * Timestamp timer configuration register (for new PCIe boards).
*/
-static const unsigned clock_period[8] = {
+#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 */
100, /* 10 MHz */
1000, /* 1 MHz */
100000, /* 10 kHz */
1000000, /* 1 kHz */
0, /* OUT N-1 */
- 0 /* group clock input pin */
+ 0, /* group clock input pin */
+ 0, /* HIGH (VCC) (enhanced) */
+ 0, /* LOW (GND) (enhanced) */
+ 0, /* pattern present (enhanced) */
+ 50, /* 20 MHz (enhanced) */
+ /* remaining clock sources reserved (enhanced) */
};
/*
unsigned char sdinfo[DIO200_MAX_SUBDEVS]; /* depends on sdtype */
char has_int_sce; /* has interrupt enable/status register */
char has_clk_gat_sce; /* has clock/gate selection registers */
+ char has_enhancements; /* has enhanced features */
} dio200_layout;
static const dio200_layout dio200_layouts[] = {
0x3F},
has_int_sce:1,
has_clk_gat_sce:1,
+ has_enhancements:0,
},
[pc214_layout] = {
n_subdevs:4,
sdinfo: {0x00, 0x08, 0x10, 0x01},
has_int_sce:0,
has_clk_gat_sce:0,
+ has_enhancements:0,
},
[pc215_layout] = {
n_subdevs:5,
sdinfo: {0x00, 0x08, 0x10, 0x14, 0x3F},
has_int_sce:1,
has_clk_gat_sce:1,
+ has_enhancements:0,
},
[pc218_layout] = {
n_subdevs:7,
0x3F},
has_int_sce:1,
has_clk_gat_sce:1,
+ has_enhancements:0,
},
[pc272_layout] = {
n_subdevs:4,
sdinfo: {0x00, 0x08, 0x10, 0x3F},
has_int_sce:1,
has_clk_gat_sce:0,
+ has_enhancements:0,
},
#ifdef CONFIG_COMEDI_PCI
[pcie215_layout] = {
sdinfo: {0x00, 0x00, 0x08, 0x00, 0x10, 0x14, 0x00, 0x3F},
has_int_sce:1,
has_clk_gat_sce:1,
+ has_enhancements:1,
},
[pcie236_layout] = {
n_subdevs:8,
sdinfo: {0x00, 0x00, 0x00, 0x00, 0x10, 0x14, 0x00, 0x3F},
has_int_sce:1,
has_clk_gat_sce:1,
+ has_enhancements:1,
},
[pcie296_layout] = {
n_subdevs:8,
sdinfo: {0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x00, 0x3F},
has_int_sce:1,
has_clk_gat_sce:1,
+ has_enhancements:1,
},
#endif
};
writeb(val, devpriv->io.u.membase + offset);
}
+/*
+ * Read 32-bit register.
+ */
+#ifdef CONFIG_COMEDI_PCI
+static unsigned int dio200_read32(comedi_device * dev, unsigned int offset)
+{
+ offset <<= devpriv->io.regshift;
+ if (devpriv->io.regtype == io_regtype)
+ return inl(devpriv->io.u.iobase + offset);
+ else
+ return readl(devpriv->io.u.membase + offset);
+}
+#endif
+
+/*
+ * Write 32-bit register.
+ */
+#ifdef CONFIG_COMEDI_PCI
+static void dio200_write32(comedi_device * dev, unsigned int offset,
+ unsigned int val)
+{
+ offset <<= devpriv->io.regshift;
+ if (devpriv->io.regtype == io_regtype)
+ outl(val, devpriv->io.u.iobase + offset);
+ else
+ writel(val, devpriv->io.u.membase + offset);
+}
+#endif
+
/*
* This function looks for a PCI device matching the requested board name,
* bus and slot.
return -1;
if (counter_number > 2)
return -1;
- if (gate_src > 7)
+ if (gate_src > (thislayout->has_enhancements ? 31 : 7))
return -1;
subpriv->gate_src[counter_number] = gate_src;
return -1;
if (counter_number > 2)
return -1;
- if (clock_src > 7)
+ if (clock_src > (thislayout->has_enhancements ? 31 : 7))
return -1;
subpriv->clock_src[counter_number] = clock_src;
}
}
+/*
+ * 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
}
writel(0x80, brbase + 0x50);
iounmap(brbase);
+ /*
+ * Enable "enhanced" features of board.
+ */
+ dio200_write8(dev, DIO200_ENHANCE, 1);
return 0;
}
#endif
}
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;
}