[PATCH 07/21] staging: comedi: ni_at_ao: tidy up the calibration subdevice

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

 



The AT-AO-6/10 boards use DAC8800 TrimDACs to software calibrate the
analog output channels. These are exposed to the user as a calibration
subdevice.

Tidy up, and document, the calibration subdevice.

Since the TrimDACs are not readable, store the calibration values in the
private data for the user to read back as needed.

Signed-off-by: H Hartley Sweeten <hsweeten@xxxxxxxxxxxxxxxxxxx>
Cc: Ian Abbott <abbotti@xxxxxxxxx>
Cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
 drivers/staging/comedi/drivers/ni_at_ao.c | 139 +++++++++++++++++++-----------
 1 file changed, 88 insertions(+), 51 deletions(-)

diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c
index bba5bc0..cbf2b0c 100644
--- a/drivers/staging/comedi/drivers/ni_at_ao.c
+++ b/drivers/staging/comedi/drivers/ni_at_ao.c
@@ -43,23 +43,15 @@ Configuration options:
  * Register map
  */
 #define ATAO_DIO_REG		0x00
-#define ATAO_CFG2		0x02	/* W 16 */
-#define CALLD1			(1 << 15)
-#define CALLD0			(1 << 14)
-#define FFRTEN			(1 << 13)
-#define DAC2S8			(1 << 12)
-#define DAC2S6			(1 << 11)
-#define DAC2S4			(1 << 10)
-#define DAC2S2			(1 << 9)
-#define DAC2S0			(1 << 8)
-#define LDAC8			(1 << 7)
-#define LDAC6			(1 << 6)
-#define LDAC4			(1 << 5)
-#define LDAC2			(1 << 4)
-#define LDAC0			(1 << 3)
-#define PROMEN			(1 << 2)
-#define SCLK			(1 << 1)
-#define SDATA			(1 << 0)
+#define ATAO_CFG2_REG		0x02
+#define ATAO_CFG2_CALLD_NOP	(0 << 14)
+#define ATAO_CFG2_CALLD(x)	((((x) >> 3) + 1) << 14)
+#define ATAO_CFG2_FFRTEN	(1 << 13)
+#define ATAO_CFG2_DACS(x)	(1 << (((x) / 2) + 8))
+#define ATAO_CFG2_LDAC(x)	(1 << (((x) / 2) + 3))
+#define ATAO_CFG2_PROMEN	(1 << 2)
+#define ATAO_CFG2_SCLK		(1 << 1)
+#define ATAO_CFG2_SDATA		(1 << 0)
 #define ATAO_CFG3		0x04	/* W 16 */
 #define DMAMODE			(1 << 6)
 #define CLKOUT			(1 << 5)
@@ -147,6 +139,9 @@ struct atao_private {
 
 	/* Used for AO readback */
 	unsigned int ao_readback[10];
+
+	/* Used for caldac readback */
+	unsigned char caldac[21];
 };
 
 static void atao_reset(struct comedi_device *dev)
@@ -162,7 +157,7 @@ static void atao_reset(struct comedi_device *dev)
 	outb(0x03, dev->iobase + ATAO_82C53_CNTR1);
 	outb(CNTRSEL0 | RWSEL0 | MODESEL2, dev->iobase + ATAO_82C53_CNTRCMD);
 
-	outw(0, dev->iobase + ATAO_CFG2);
+	outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG);
 
 	devpriv->cfg3 = 0;
 	outw(devpriv->cfg3, dev->iobase + ATAO_CFG3);
@@ -265,41 +260,83 @@ static int atao_dio_insn_config(struct comedi_device *dev,
 }
 
 /*
- * Figure 2-1 in the manual shows 3 chips labeled DAC8800, which
- * are 8-channel 8-bit DACs.  These are most likely the calibration
- * DACs.  It is not explicitly stated in the manual how to access
- * the caldacs, but we can guess.
+ * There are three DAC8800 TrimDACs on the board. These are 8-channel,
+ * 8-bit DACs that are used to calibrate the Analog Output channels.
+ * The factory default calibration values are stored in the EEPROM.
+ * The TrimDACs, and EEPROM addresses, are mapped as:
+ *
+ *        Channel       EEPROM  Description
+ *   -----------------  ------  -----------------------------------
+ *    0 - DAC0 Chan 0    0x30   AO Channel 0 Offset
+ *    1 - DAC0 Chan 1    0x31   AO Channel 0 Gain
+ *    2 - DAC0 Chan 2    0x32   AO Channel 1 Offset
+ *    3 - DAC0 Chan 3    0x33   AO Channel 1 Gain
+ *    4 - DAC0 Chan 4    0x34   AO Channel 2 Offset
+ *    5 - DAC0 Chan 5    0x35   AO Channel 2 Gain
+ *    6 - DAC0 Chan 6    0x36   AO Channel 3 Offset
+ *    7 - DAC0 Chan 7    0x37   AO Channel 3 Gain
+ *    8 - DAC1 Chan 0    0x38   AO Channel 4 Offset
+ *    9 - DAC1 Chan 1    0x39   AO Channel 4 Gain
+ *   10 - DAC1 Chan 2    0x3a   AO Channel 5 Offset
+ *   11 - DAC1 Chan 3    0x3b   AO Channel 5 Gain
+ *   12 - DAC1 Chan 4    0x3c   2.5V Offset
+ *   13 - DAC1 Chan 5    0x3d   AO Channel 6 Offset (at-ao-10 only)
+ *   14 - DAC1 Chan 6    0x3e   AO Channel 6 Gain   (at-ao-10 only)
+ *   15 - DAC1 Chan 7    0x3f   AO Channel 7 Offset (at-ao-10 only)
+ *   16 - DAC2 Chan 0    0x40   AO Channel 7 Gain   (at-ao-10 only)
+ *   17 - DAC2 Chan 1    0x41   AO Channel 8 Offset (at-ao-10 only)
+ *   18 - DAC2 Chan 2    0x42   AO Channel 8 Gain   (at-ao-10 only)
+ *   19 - DAC2 Chan 3    0x43   AO Channel 9 Offset (at-ao-10 only)
+ *   20 - DAC2 Chan 4    0x44   AO Channel 9 Gain   (at-ao-10 only)
+ *        DAC2 Chan 5    0x45   Reserved
+ *        DAC2 Chan 6    0x46   Reserved
+ *        DAC2 Chan 7    0x47   Reserved
  */
-static int atao_calib_insn_read(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data)
-{
-	int i;
-	for (i = 0; i < insn->n; i++)
-		data[i] = 0;	/* XXX */
-	return insn->n;
-}
-
 static int atao_calib_insn_write(struct comedi_device *dev,
 				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn, unsigned int *data)
+				 struct comedi_insn *insn,
+				 unsigned int *data)
 {
 	struct atao_private *devpriv = dev->private;
-	unsigned int bitstring, bit;
 	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int bitstring;
+	unsigned int val;
+	int bit;
+
+	if (insn->n == 0)
+		return 0;
+
+	devpriv->caldac[chan] = data[insn->n - 1] & s->maxdata;
+
+	/* write the channel and last data value to the caldac */
+	bitstring = ((chan & 0x7) << 8) | devpriv->caldac[chan];
 
-	bitstring = ((chan & 0x7) << 8) | (data[insn->n - 1] & 0xff);
+	/* clock the bitstring to the caldac; MSB -> LSB */
+	for (bit = 1 << 10; bit; bit >>= 1) {
+		val = (bit & bitstring) ? ATAO_CFG2_SDATA : 0;
 
-	for (bit = 1 << (11 - 1); bit; bit >>= 1) {
-		outw(((bit & bitstring) ? SDATA : 0),
-		     dev->iobase + ATAO_CFG2);
-		outw(SCLK | ((bit & bitstring) ? SDATA : 0),
-		     dev->iobase + ATAO_CFG2);
+		outw(val, dev->iobase + ATAO_CFG2_REG);
+		outw(val | ATAO_CFG2_SCLK, dev->iobase + ATAO_CFG2_REG);
 	}
-	/* strobe the appropriate caldac */
-	outw((((chan >> 3) + 1) << 14),
-	     dev->iobase + ATAO_CFG2);
-	outw(0, dev->iobase + ATAO_CFG2);
+
+	/* strobe the caldac to load the value */
+	outw(ATAO_CFG2_CALLD(chan), dev->iobase + ATAO_CFG2_REG);
+	outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG);
+
+	return insn->n;
+}
+
+static int atao_calib_insn_read(struct comedi_device *dev,
+				struct comedi_subdevice *s,
+				struct comedi_insn *insn,
+				unsigned int *data)
+{
+	struct atao_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	int i;
+
+	for (i = 0; i < insn->n; i++)
+		data[i] = devpriv->caldac[chan];
 
 	return insn->n;
 }
@@ -349,14 +386,14 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 	s->insn_bits = atao_dio_insn_bits;
 	s->insn_config = atao_dio_insn_config;
 
-	s = &dev->subdevices[2];
 	/* caldac subdevice */
-	s->type = COMEDI_SUBD_CALIB;
-	s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
-	s->n_chan = 21;
-	s->maxdata = 0xff;
-	s->insn_read = atao_calib_insn_read;
-	s->insn_write = atao_calib_insn_write;
+	s = &dev->subdevices[2];
+	s->type		= COMEDI_SUBD_CALIB;
+	s->subdev_flags	= SDF_WRITABLE | SDF_INTERNAL;
+	s->n_chan	= (board->n_ao_chans * 2) + 1;
+	s->maxdata	= 0xff;
+	s->insn_read	= atao_calib_insn_read;
+	s->insn_write	= atao_calib_insn_write;
 
 	s = &dev->subdevices[3];
 	/* eeprom subdevice */
-- 
1.8.3.2

_______________________________________________
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