[PATCH 14/15] staging: comedi: ni_daq_700: add a counter subdevice

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The DAQ700Card has an 8254 counter/timer that provides 3 counters.
Counter 0 controls the onboard data acquisition timing, and all three
counters are available for general-purpose timing functions.

Add a subdevice to allow the user to use the counters.

Signed-off-by: H Hartley Sweeten <hsweeten@xxxxxxxxxxxxxxxxxxx>
Cc: Ian Abbott <abbotti@xxxxxxxxx>
Cc: Greg Kroah-Hartman <gregk@xxxxxxxxxxxxxxxxxxx>
---
 drivers/staging/comedi/comedi.h             |   9 ++
 drivers/staging/comedi/drivers/ni_daq_700.c | 125 +++++++++++++++++++++++++++-
 2 files changed, 133 insertions(+), 1 deletion(-)

diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h
index dbaeba7..c722748 100644
--- a/drivers/staging/comedi/comedi.h
+++ b/drivers/staging/comedi/comedi.h
@@ -987,4 +987,13 @@ enum ke_counter_clock_source {
 	KE_CLK_EXT	/* external clock on pin 21 of D-Sub */
 };
 
+/*
+ * Values for setting the counter 1 clock source with INSN_CONFIG_SET_CLOCK_SRC
+ * for the counter subdevice on the NI PCMCIA DAQCard-700 (ni_daq_700 driver).
+ */
+enum ni_daq700_counter_clock_source {
+	DAQ700_CLK_EXT,		/* external CLK1 signal (default) */
+	DAQ700_CLK_1MHZ,	/* internal 1MHz */
+};
+
 #endif /* _COMEDI_H */
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index e1e7ba7..4ff3556 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -589,6 +589,112 @@ static int daq700_ai_cmdtest(struct comedi_device *dev,
 	return 0;
 }
 
+static int daq700_counter_insn_read(struct comedi_device *dev,
+				    struct comedi_subdevice *s,
+				    struct comedi_insn *insn,
+				    unsigned int *data)
+{
+	unsigned long timer_base = dev->iobase + DAQ700_TIMER_BASE;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	int i;
+
+	for (i = 0; i < insn->n; i++)
+		data[i] = i8254_read(timer_base, 0, chan);
+
+	return insn->n;
+}
+
+static int daq700_counter_insn_write(struct comedi_device *dev,
+				     struct comedi_subdevice *s,
+				     struct comedi_insn *insn,
+				     unsigned int *data)
+{
+	unsigned long timer_base = dev->iobase + DAQ700_TIMER_BASE;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+
+	/* only write the final value to the counter */
+	if (insn->n)
+		i8254_write(timer_base, 0, chan, data[insn->n - 1]);
+
+	return insn->n;
+}
+
+static int daq700_counter_insn_config(struct comedi_device *dev,
+				      struct comedi_subdevice *s,
+				      struct comedi_insn *insn,
+				      unsigned int *data)
+{
+	struct daq700_private *devpriv = dev->private;
+	unsigned long timer_base = dev->iobase + DAQ700_TIMER_BASE;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+
+	switch (data[0]) {
+	case INSN_CONFIG_SET_CLOCK_SRC:
+		switch (chan) {
+		case 1:
+			switch (data[1]) {
+			case DAQ700_CLK_EXT:
+				/* CLK1 signal from I/O connector */
+				devpriv->cmd3 &= ~DAQ700_CMD3_CLK1SRC;
+				break;
+			case DAQ700_CLK_1MHZ:
+				/* CLK1 from internal 1MHz */
+				devpriv->cmd3 |= DAQ700_CMD3_CLK1SRC;
+				break;
+			default:
+				return -EINVAL;
+			}
+			outb(devpriv->cmd3, dev->iobase + DAQ700_CMD3_REG);
+			break;
+		default:
+			/*
+			 * The clock source cannot be changed for all
+			 * other channels.
+			 */
+			return -EINVAL;
+		}
+		break;
+	case INSN_CONFIG_GET_CLOCK_SRC:
+		switch (chan) {
+		case 0:
+			/* counter 0 is connected to the 1MHz internal clock */
+			data[1] = DAQ700_CLK_1MHZ;
+			data[2] = I8254_OSC_BASE_1MHZ;
+			break;
+		case 1:
+			/*
+			 * Counter 1 can use the 1MHz internal clock or an
+			 * external clock.
+			 */
+			if (devpriv->cmd3 & DAQ700_CMD3_CLK1SRC) {
+				data[1] = DAQ700_CLK_1MHZ;
+				data[2] = I8254_OSC_BASE_1MHZ;
+			} else {
+				data[1] = DAQ700_CLK_EXT;
+				data[2] = 0;	/* unknown */
+			}
+			break;
+		case 2:
+			/* counter 2 uses an external clock */
+			data[1] = DAQ700_CLK_EXT;
+			data[2] = 0;	/* unknown */
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case INSN_CONFIG_SET_COUNTER_MODE:
+		i8254_set_mode(timer_base, 0, chan, data[1]);
+		break;
+	case INSN_CONFIG_8254_READ_STATUS:
+		data[1] = i8254_status(timer_base, 0, chan);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return insn->n;
+}
+
 /*
  * Data acquisition is enabled.
  * The counter 0 output is high.
@@ -640,7 +746,7 @@ static int daq700_auto_attach(struct comedi_device *dev,
 	if (ret == 0)
 		dev->irq = link->irq;
 
-	ret = comedi_alloc_subdevices(dev, 2);
+	ret = comedi_alloc_subdevices(dev, 3);
 	if (ret)
 		return ret;
 
@@ -672,6 +778,23 @@ static int daq700_auto_attach(struct comedi_device *dev,
 		s->cancel	= daq700_ai_cancel;
 	}
 
+	/*
+	 * Counter/Timer subdevice
+	 *
+	 * The 8254 has three counters - 0, 1, and 2. Counter 0 controls
+	 * the onboard data acquisition timing, and all three counters
+	 * are available for general-purpose timing functions.
+	 */
+	s = &dev->subdevices[2];
+	s->type		= COMEDI_SUBD_COUNTER;
+	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
+	s->n_chan	= 3;
+	s->maxdata	= 0xffff;
+	s->range_table	= &range_unknown;
+	s->insn_config	= daq700_counter_insn_config;
+	s->insn_write	= daq700_counter_insn_write;
+	s->insn_read	= daq700_counter_insn_read;
+
 	return 0;
 }
 
-- 
1.9.3

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel




[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux