From 12c15b195f3bef40db68ceb0f172905c5aa07524 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Mon, 30 Sep 2013 17:51:54 -0700 Subject: [PATCH] staging: comedi: ni_at_ao: tidy up the calibration subdevice 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 Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- 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 bba5bc0c036b..cbf2b0c40347 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 */ -- 2.20.1