[PATCH 11/48] staging: comedi: pcmmio: cleanup ao_winsn()

H Hartley Sweeten hsweeten at visionengravers.com
Mon Dec 9 22:30:47 UTC 2013


Rename this function to have namespace associated with the driver.

Refactor the function to remove the extra write to the command register
to set the range before writing the DAC value. Since the range is constant
for the entire comedi_insn it only needs to be set once. All writes to the
DAC after that will use the same range.

Define the register map for the analog output registers.

Signed-off-by: H Hartley Sweeten <hsweeten at visionengravers.com>
Cc: Ian Abbott <abbotti at mev.co.uk>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
---
 drivers/staging/comedi/drivers/pcmmio.c | 140 ++++++++++++++++++--------------
 1 file changed, 81 insertions(+), 59 deletions(-)

diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index 5726ded..42d7f14 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -83,24 +83,47 @@ Configuration Options:
 /*
  * Register I/O map
  */
-#define PCMMIO_AI_LSB_REG		0x00
-#define PCMMIO_AI_MSB_REG		0x01
-#define PCMMIO_AI_CMD_REG		0x02
-#define PCMMIO_AI_CMD_SE		(1 << 7)
-#define PCMMIO_AI_CMD_ODD_CHAN		(1 << 6)
-#define PCMMIO_AI_CMD_CHAN_SEL(x)	(((x) & 0x3) << 4)
-#define PCMMIO_AI_CMD_RANGE(x)		(((x) & 0x3) << 2)
-#define PCMMIO_AI_STATUS_REG		0x03
-#define PCMMIO_AI_STATUS_DATA_READY	(1 << 7)
-#define PCMMIO_AI_STATUS_DATA_DMA_PEND	(1 << 6)
-#define PCMMIO_AI_STATUS_CMD_DMA_PEND	(1 << 5)
-#define PCMMIO_AI_STATUS_IRQ_PEND	(1 << 4)
-#define PCMMIO_AI_STATUS_DATA_DRQ_ENA	(1 << 2)
-#define PCMMIO_AI_STATUS_REG_SEL	(1 << 3)
-#define PCMMIO_AI_STATUS_CMD_DRQ_ENA	(1 << 1)
-#define PCMMIO_AI_STATUS_IRQ_ENA	(1 << 0)
-#define PCMMIO_AI_RESOURCE_REG		0x03
-#define PCMMIO_AI_2ND_ADC_OFFSET	0x04
+#define PCMMIO_AI_LSB_REG			0x00
+#define PCMMIO_AI_MSB_REG			0x01
+#define PCMMIO_AI_CMD_REG			0x02
+#define PCMMIO_AI_CMD_SE			(1 << 7)
+#define PCMMIO_AI_CMD_ODD_CHAN			(1 << 6)
+#define PCMMIO_AI_CMD_CHAN_SEL(x)		(((x) & 0x3) << 4)
+#define PCMMIO_AI_CMD_RANGE(x)			(((x) & 0x3) << 2)
+#define PCMMIO_AI_STATUS_REG			0x03
+#define PCMMIO_AI_STATUS_DATA_READY		(1 << 7)
+#define PCMMIO_AI_STATUS_DATA_DMA_PEND		(1 << 6)
+#define PCMMIO_AI_STATUS_CMD_DMA_PEND		(1 << 5)
+#define PCMMIO_AI_STATUS_IRQ_PEND		(1 << 4)
+#define PCMMIO_AI_STATUS_DATA_DRQ_ENA		(1 << 2)
+#define PCMMIO_AI_STATUS_REG_SEL		(1 << 3)
+#define PCMMIO_AI_STATUS_CMD_DRQ_ENA		(1 << 1)
+#define PCMMIO_AI_STATUS_IRQ_ENA		(1 << 0)
+#define PCMMIO_AI_RESOURCE_REG			0x03
+#define PCMMIO_AI_2ND_ADC_OFFSET		0x04
+
+#define PCMMIO_AO_LSB_REG			0x08
+#define PCMMIO_AO_LSB_SPAN(x)			(((x) & 0xf) << 0)
+#define PCMMIO_AO_MSB_REG			0x09
+#define PCMMIO_AO_CMD_REG			0x0a
+#define PCMMIO_AO_CMD_WR_SPAN			(0x2 << 4)
+#define PCMMIO_AO_CMD_WR_CODE			(0x3 << 4)
+#define PCMMIO_AO_CMD_UPDATE			(0x4 << 4)
+#define PCMMIO_AO_CMD_UPDATE_ALL		(0x5 << 4)
+#define PCMMIO_AO_CMD_WR_SPAN_UPDATE		(0x6 << 4)
+#define PCMMIO_AO_CMD_WR_CODE_UPDATE		(0x7 << 4)
+#define PCMMIO_AO_CMD_WR_SPAN_UPDATE_ALL	(0x8 << 4)
+#define PCMMIO_AO_CMD_WR_CODE_UPDATE_ALL	(0x9 << 4)
+#define PCMMIO_AO_CMD_RD_B1_SPAN		(0xa << 4)
+#define PCMMIO_AO_CMD_RD_B1_CODE		(0xb << 4)
+#define PCMMIO_AO_CMD_RD_B2_SPAN		(0xc << 4)
+#define PCMMIO_AO_CMD_RD_B2_CODE		(0xd << 4)
+#define PCMMIO_AO_CMD_NOP			(0xf << 4)
+#define PCMMIO_AO_CMD_CHAN_SEL(x)		(((x) & 0x03) << 1)
+#define PCMMIO_AO_CMD_CHAN_SEL_ALL		(0x0f << 0)
+#define PCMMIO_AO_STATUS_REG			0x0b
+#define PCMMIO_AO_RESOURCE_ENA_REG		0x0b
+#define PCMMIO_AO_2ND_DAC_OFFSET		0x04
 
 /* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */
 #define CHANS_PER_PORT   8
@@ -880,53 +903,51 @@ static int wait_dac_ready(unsigned long iobase)
 	return 1;
 }
 
-static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
-		    struct comedi_insn *insn, unsigned int *data)
+static int pcmmio_ao_insn_write(struct comedi_device *dev,
+				struct comedi_subdevice *s,
+				struct comedi_insn *insn,
+				unsigned int *data)
 {
 	struct pcmmio_private *devpriv = dev->private;
-	unsigned long iobase = dev->iobase + 8;
-	unsigned int iooffset = 0;
-	int n;
-
-	for (n = 0; n < insn->n; n++) {
-		unsigned chan = CR_CHAN(insn->chanspec), range =
-		    CR_RANGE(insn->chanspec);
-		if (chan < s->n_chan) {
-			unsigned char command_byte = 0, range_byte =
-			    range & ((1 << 4) - 1);
-			if (chan >= 4)
-				chan -= 4, iooffset += 4;
-			/* set the range.. */
-			outb(range_byte, iobase + iooffset + 0);
-			outb(0, iobase + iooffset + 1);
-
-			/* tell it to begin */
-			command_byte = (chan << 1) | 0x60;
-			outb(command_byte, iobase + iooffset + 2);
+	unsigned long iobase = dev->iobase;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int range = CR_RANGE(insn->chanspec);
+	unsigned int val = devpriv->ao_readback[chan];
+	unsigned char cmd = 0;
+	int i;
 
-			wait_dac_ready(iobase + iooffset);
+	/*
+	 * The PCM-MIO has two Linear Tech LTC2704 DAC devices. Each device
+	 * is a 4-channel converter with software-selectable output range.
+	 */
 
-			/* low order byte */
-			outb(data[n] & 0xff, iobase + iooffset + 0);
+	if (chan > 3) {
+		cmd |= PCMMIO_AO_CMD_CHAN_SEL(chan - 4);
+		iobase += PCMMIO_AO_2ND_DAC_OFFSET;
+	} else {
+		cmd |= PCMMIO_AO_CMD_CHAN_SEL(chan);
+	}
 
-			/* high order byte */
-			outb((data[n] >> 8) & 0xff, iobase + iooffset + 1);
+	/* set the range for the channel */
+	outb(PCMMIO_AO_LSB_SPAN(range), iobase + PCMMIO_AO_LSB_REG);
+	outb(0, iobase + PCMMIO_AO_MSB_REG);
+	outb(cmd | PCMMIO_AO_CMD_WR_SPAN_UPDATE, iobase + PCMMIO_AO_CMD_REG);
+	wait_dac_ready(iobase);
 
-			/*
-			 * set bit 4 of command byte to indicate
-			 * data is loaded and trigger conversion
-			 */
-			command_byte = 0x70 | (chan << 1);
-			/* trigger converion */
-			outb(command_byte, iobase + iooffset + 2);
+	for (i = 0; i < insn->n; i++) {
+		val = data[i];
 
-			wait_dac_ready(iobase + iooffset);
+		/* write the data to the channel */
+		outb(val & 0xff, iobase + PCMMIO_AO_LSB_REG);
+		outb((val >> 8) & 0xff, iobase + PCMMIO_AO_MSB_REG);
+		outb(cmd | PCMMIO_AO_CMD_WR_CODE_UPDATE,
+		     iobase + PCMMIO_AO_CMD_REG);
+		wait_dac_ready(iobase);
 
-			/* save to shadow register for ao_rinsn */
-			devpriv->ao_readback[chan] = data[n];
-		}
+		devpriv->ao_readback[chan] = val;
 	}
-	return n;
+
+	return insn->n;
 }
 
 static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -996,11 +1017,12 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	s->n_chan = 8;
 	s->len_chanlist = s->n_chan;
 	s->insn_read = ao_rinsn;
-	s->insn_write = ao_winsn;
+	s->insn_write = pcmmio_ao_insn_write;
 
 	/* initialize the resource enable register by clearing it */
-	outb(0, dev->iobase + 8 + 3);
-	outb(0, dev->iobase + 8 + 4 + 3);
+	outb(0, dev->iobase + PCMMIO_AO_RESOURCE_ENA_REG);
+	outb(0, dev->iobase + PCMMIO_AO_2ND_DAC_OFFSET +
+		PCMMIO_AO_RESOURCE_ENA_REG);
 
 	port = 0;
 	asic = 0;
-- 
1.8.4.4



More information about the devel mailing list