From 68533c7b8e87a907babab1da39652f1fa518697d Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Mon, 9 Dec 2013 15:30:47 -0700 Subject: [PATCH] staging: comedi: pcmmio: cleanup ao_winsn() 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 Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- 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 5726ded45f92..42d7f1479323 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; -- 2.30.2