diff options
Diffstat (limited to 'drivers/staging/comedi/drivers/me_daq.c')
-rw-r--r-- | drivers/staging/comedi/drivers/me_daq.c | 315 |
1 files changed, 149 insertions, 166 deletions
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index 9ea1ba4b1b6f..3bf0caa18ab0 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -41,84 +41,63 @@ #define XILINX_DOWNLOAD_RESET 0x42 /* Xilinx registers */ -#define ME_CONTROL_1 0x0000 /* - | W */ -#define INTERRUPT_ENABLE (1<<15) -#define COUNTER_B_IRQ (1<<12) -#define COUNTER_A_IRQ (1<<11) -#define CHANLIST_READY_IRQ (1<<10) -#define EXT_IRQ (1<<9) -#define ADFIFO_HALFFULL_IRQ (1<<8) -#define SCAN_COUNT_ENABLE (1<<5) -#define SIMULTANEOUS_ENABLE (1<<4) -#define TRIGGER_FALLING_EDGE (1<<3) -#define CONTINUOUS_MODE (1<<2) -#define DISABLE_ADC (0<<0) -#define SOFTWARE_TRIGGERED_ADC (1<<0) -#define SCAN_TRIGGERED_ADC (2<<0) -#define EXT_TRIGGERED_ADC (3<<0) -#define ME_ADC_START 0x0000 /* R | - */ -#define ME_CONTROL_2 0x0002 /* - | W */ -#define ENABLE_ADFIFO (1<<10) -#define ENABLE_CHANLIST (1<<9) -#define ENABLE_PORT_B (1<<7) -#define ENABLE_PORT_A (1<<6) -#define ENABLE_COUNTER_B (1<<4) -#define ENABLE_COUNTER_A (1<<3) -#define ENABLE_DAC (1<<1) -#define BUFFERED_DAC (1<<0) -#define ME_DAC_UPDATE 0x0002 /* R | - */ -#define ME_STATUS 0x0004 /* R | - */ -#define COUNTER_B_IRQ_PENDING (1<<12) -#define COUNTER_A_IRQ_PENDING (1<<11) -#define CHANLIST_READY_IRQ_PENDING (1<<10) -#define EXT_IRQ_PENDING (1<<9) -#define ADFIFO_HALFFULL_IRQ_PENDING (1<<8) -#define ADFIFO_FULL (1<<4) -#define ADFIFO_HALFFULL (1<<3) -#define ADFIFO_EMPTY (1<<2) -#define CHANLIST_FULL (1<<1) -#define FST_ACTIVE (1<<0) -#define ME_RESET_INTERRUPT 0x0004 /* - | W */ -#define ME_DIO_PORT_A 0x0006 /* R | W */ -#define ME_DIO_PORT_B 0x0008 /* R | W */ -#define ME_TIMER_DATA_0 0x000A /* - | W */ -#define ME_TIMER_DATA_1 0x000C /* - | W */ -#define ME_TIMER_DATA_2 0x000E /* - | W */ -#define ME_CHANNEL_LIST 0x0010 /* - | W */ -#define ADC_UNIPOLAR (1<<6) -#define ADC_GAIN_0 (0<<4) -#define ADC_GAIN_1 (1<<4) -#define ADC_GAIN_2 (2<<4) -#define ADC_GAIN_3 (3<<4) -#define ME_READ_AD_FIFO 0x0010 /* R | - */ -#define ME_DAC_CONTROL 0x0012 /* - | W */ -#define DAC_UNIPOLAR_D (0<<4) -#define DAC_BIPOLAR_D (1<<4) -#define DAC_UNIPOLAR_C (0<<5) -#define DAC_BIPOLAR_C (1<<5) -#define DAC_UNIPOLAR_B (0<<6) -#define DAC_BIPOLAR_B (1<<6) -#define DAC_UNIPOLAR_A (0<<7) -#define DAC_BIPOLAR_A (1<<7) -#define DAC_GAIN_0_D (0<<8) -#define DAC_GAIN_1_D (1<<8) -#define DAC_GAIN_0_C (0<<9) -#define DAC_GAIN_1_C (1<<9) -#define DAC_GAIN_0_B (0<<10) -#define DAC_GAIN_1_B (1<<10) -#define DAC_GAIN_0_A (0<<11) -#define DAC_GAIN_1_A (1<<11) -#define ME_DAC_CONTROL_UPDATE 0x0012 /* R | - */ -#define ME_DAC_DATA_A 0x0014 /* - | W */ -#define ME_DAC_DATA_B 0x0016 /* - | W */ -#define ME_DAC_DATA_C 0x0018 /* - | W */ -#define ME_DAC_DATA_D 0x001A /* - | W */ -#define ME_COUNTER_ENDDATA_A 0x001C /* - | W */ -#define ME_COUNTER_ENDDATA_B 0x001E /* - | W */ -#define ME_COUNTER_STARTDATA_A 0x0020 /* - | W */ -#define ME_COUNTER_VALUE_A 0x0020 /* R | - */ -#define ME_COUNTER_STARTDATA_B 0x0022 /* - | W */ -#define ME_COUNTER_VALUE_B 0x0022 /* R | - */ +/* + * PCI BAR2 Memory map (dev->mmio) + */ +#define ME_CTRL1_REG 0x00 /* R (ai start) | W */ +#define ME_CTRL1_INT_ENA BIT(15) +#define ME_CTRL1_COUNTER_B_IRQ BIT(12) +#define ME_CTRL1_COUNTER_A_IRQ BIT(11) +#define ME_CTRL1_CHANLIST_READY_IRQ BIT(10) +#define ME_CTRL1_EXT_IRQ BIT(9) +#define ME_CTRL1_ADFIFO_HALFFULL_IRQ BIT(8) +#define ME_CTRL1_SCAN_COUNT_ENA BIT(5) +#define ME_CTRL1_SIMULTANEOUS_ENA BIT(4) +#define ME_CTRL1_TRIGGER_FALLING_EDGE BIT(3) +#define ME_CTRL1_CONTINUOUS_MODE BIT(2) +#define ME_CTRL1_ADC_MODE(x) (((x) & 0x3) << 0) +#define ME_CTRL1_ADC_MODE_DISABLE ME_CTRL1_ADC_MODE(0) +#define ME_CTRL1_ADC_MODE_SOFT_TRIG ME_CTRL1_ADC_MODE(1) +#define ME_CTRL1_ADC_MODE_SCAN_TRIG ME_CTRL1_ADC_MODE(2) +#define ME_CTRL1_ADC_MODE_EXT_TRIG ME_CTRL1_ADC_MODE(3) +#define ME_CTRL1_ADC_MODE_MASK ME_CTRL1_ADC_MODE(3) +#define ME_CTRL2_REG 0x02 /* R (dac update) | W */ +#define ME_CTRL2_ADFIFO_ENA BIT(10) +#define ME_CTRL2_CHANLIST_ENA BIT(9) +#define ME_CTRL2_PORT_B_ENA BIT(7) +#define ME_CTRL2_PORT_A_ENA BIT(6) +#define ME_CTRL2_COUNTER_B_ENA BIT(4) +#define ME_CTRL2_COUNTER_A_ENA BIT(3) +#define ME_CTRL2_DAC_ENA BIT(1) +#define ME_CTRL2_BUFFERED_DAC BIT(0) +#define ME_STATUS_REG 0x04 /* R | W (clears interrupts) */ +#define ME_STATUS_COUNTER_B_IRQ BIT(12) +#define ME_STATUS_COUNTER_A_IRQ BIT(11) +#define ME_STATUS_CHANLIST_READY_IRQ BIT(10) +#define ME_STATUS_EXT_IRQ BIT(9) +#define ME_STATUS_ADFIFO_HALFFULL_IRQ BIT(8) +#define ME_STATUS_ADFIFO_FULL BIT(4) +#define ME_STATUS_ADFIFO_HALFFULL BIT(3) +#define ME_STATUS_ADFIFO_EMPTY BIT(2) +#define ME_STATUS_CHANLIST_FULL BIT(1) +#define ME_STATUS_FST_ACTIVE BIT(0) +#define ME_DIO_PORT_A_REG 0x06 /* R | W */ +#define ME_DIO_PORT_B_REG 0x08 /* R | W */ +#define ME_TIMER_DATA_REG(x) (0x0a + ((x) * 2)) /* - | W */ +#define ME_AI_FIFO_REG 0x10 /* R (fifo) | W (chanlist) */ +#define ME_AI_FIFO_CHANLIST_DIFF BIT(7) +#define ME_AI_FIFO_CHANLIST_UNIPOLAR BIT(6) +#define ME_AI_FIFO_CHANLIST_GAIN(x) (((x) & 0x3) << 4) +#define ME_AI_FIFO_CHANLIST_CHAN(x) (((x) & 0xf) << 0) +#define ME_DAC_CTRL_REG 0x12 /* R (updates) | W */ +#define ME_DAC_CTRL_BIPOLAR(x) BIT(7 - ((x) & 0x3)) +#define ME_DAC_CTRL_GAIN(x) BIT(11 - ((x) & 0x3)) +#define ME_DAC_CTRL_MASK(x) (ME_DAC_CTRL_BIPOLAR(x) | \ + ME_DAC_CTRL_GAIN(x)) +#define ME_AO_DATA_REG(x) (0x14 + ((x) * 2)) /* - | W */ +#define ME_COUNTER_ENDDATA_REG(x) (0x1c + ((x) * 2)) /* - | W */ +#define ME_COUNTER_STARTDATA_REG(x) (0x20 + ((x) * 2)) /* - | W */ +#define ME_COUNTER_VALUE_REG(x) (0x20 + ((x) * 2)) /* R | - */ static const struct comedi_lrange me_ai_range = { 8, { @@ -166,9 +145,9 @@ static const struct me_board me_boards[] = { struct me_private_data { void __iomem *plx_regbase; /* PLX configuration base address */ - unsigned short control_1; /* Mirror of CONTROL_1 register */ - unsigned short control_2; /* Mirror of CONTROL_2 register */ - unsigned short dac_control; /* Mirror of the DAC_CONTROL register */ + unsigned short ctrl1; /* Mirror of CONTROL_1 register */ + unsigned short ctrl2; /* Mirror of CONTROL_2 register */ + unsigned short dac_ctrl; /* Mirror of the DAC_CONTROL register */ }; static inline void sleep(unsigned sec) @@ -196,15 +175,15 @@ static int me_dio_insn_config(struct comedi_device *dev, return ret; if (s->io_bits & 0x0000ffff) - devpriv->control_2 |= ENABLE_PORT_A; + devpriv->ctrl2 |= ME_CTRL2_PORT_A_ENA; else - devpriv->control_2 &= ~ENABLE_PORT_A; + devpriv->ctrl2 &= ~ME_CTRL2_PORT_A_ENA; if (s->io_bits & 0xffff0000) - devpriv->control_2 |= ENABLE_PORT_B; + devpriv->ctrl2 |= ME_CTRL2_PORT_B_ENA; else - devpriv->control_2 &= ~ENABLE_PORT_B; + devpriv->ctrl2 &= ~ME_CTRL2_PORT_B_ENA; - writew(devpriv->control_2, dev->mmio + ME_CONTROL_2); + writew(devpriv->ctrl2, dev->mmio + ME_CTRL2_REG); return insn->n; } @@ -214,8 +193,8 @@ static int me_dio_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - void __iomem *mmio_porta = dev->mmio + ME_DIO_PORT_A; - void __iomem *mmio_portb = dev->mmio + ME_DIO_PORT_B; + void __iomem *mmio_porta = dev->mmio + ME_DIO_PORT_A_REG; + void __iomem *mmio_portb = dev->mmio + ME_DIO_PORT_B_REG; unsigned int mask; unsigned int val; @@ -249,8 +228,8 @@ static int me_ai_eoc(struct comedi_device *dev, { unsigned int status; - status = readw(dev->mmio + ME_STATUS); - if ((status & 0x0004) == 0) + status = readw(dev->mmio + ME_STATUS_REG); + if ((status & ME_STATUS_ADFIFO_EMPTY) == 0) return 0; return -EBUSY; } @@ -260,57 +239,66 @@ static int me_ai_insn_read(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct me_private_data *dev_private = dev->private; + struct me_private_data *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int rang = CR_RANGE(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); unsigned int aref = CR_AREF(insn->chanspec); - unsigned short val; - int ret; + unsigned int val; + int ret = 0; + int i; - /* stop any running conversion */ - dev_private->control_1 &= 0xFFFC; - writew(dev_private->control_1, dev->mmio + ME_CONTROL_1); + /* + * For differential operation, there are only 8 input channels + * and only bipolar ranges are available. + */ + if (aref & AREF_DIFF) { + if (chan > 7 || comedi_range_is_unipolar(s, range)) + return -EINVAL; + } /* clear chanlist and ad fifo */ - dev_private->control_2 &= ~(ENABLE_ADFIFO | ENABLE_CHANLIST); - writew(dev_private->control_2, dev->mmio + ME_CONTROL_2); + devpriv->ctrl2 &= ~(ME_CTRL2_ADFIFO_ENA | ME_CTRL2_CHANLIST_ENA); + writew(devpriv->ctrl2, dev->mmio + ME_CTRL2_REG); - /* reset any pending interrupt */ - writew(0x00, dev->mmio + ME_RESET_INTERRUPT); + writew(0x00, dev->mmio + ME_STATUS_REG); /* clear interrupts */ /* enable the chanlist and ADC fifo */ - dev_private->control_2 |= (ENABLE_ADFIFO | ENABLE_CHANLIST); - writew(dev_private->control_2, dev->mmio + ME_CONTROL_2); + devpriv->ctrl2 |= (ME_CTRL2_ADFIFO_ENA | ME_CTRL2_CHANLIST_ENA); + writew(devpriv->ctrl2, dev->mmio + ME_CTRL2_REG); /* write to channel list fifo */ - val = chan & 0x0f; /* b3:b0 channel */ - val |= (rang & 0x03) << 4; /* b5:b4 gain */ - val |= (rang & 0x04) << 4; /* b6 polarity */ - val |= ((aref & AREF_DIFF) ? 0x80 : 0); /* b7 differential */ - writew(val & 0xff, dev->mmio + ME_CHANNEL_LIST); + val = ME_AI_FIFO_CHANLIST_CHAN(chan) | ME_AI_FIFO_CHANLIST_GAIN(range); + if (comedi_range_is_unipolar(s, range)) + val |= ME_AI_FIFO_CHANLIST_UNIPOLAR; + if (aref & AREF_DIFF) + val |= ME_AI_FIFO_CHANLIST_DIFF; + writew(val, dev->mmio + ME_AI_FIFO_REG); /* set ADC mode to software trigger */ - dev_private->control_1 |= SOFTWARE_TRIGGERED_ADC; - writew(dev_private->control_1, dev->mmio + ME_CONTROL_1); + devpriv->ctrl1 |= ME_CTRL1_ADC_MODE_SOFT_TRIG; + writew(devpriv->ctrl1, dev->mmio + ME_CTRL1_REG); + + for (i = 0; i < insn->n; i++) { + /* start ai conversion */ + readw(dev->mmio + ME_CTRL1_REG); - /* start conversion by reading from ADC_START */ - readw(dev->mmio + ME_ADC_START); + /* wait for ADC fifo not empty flag */ + ret = comedi_timeout(dev, s, insn, me_ai_eoc, 0); + if (ret) + break; - /* wait for ADC fifo not empty flag */ - ret = comedi_timeout(dev, s, insn, me_ai_eoc, 0); - if (ret) - return ret; + /* get value from ADC fifo */ + val = readw(dev->mmio + ME_AI_FIFO_REG) & s->maxdata; - /* get value from ADC fifo */ - val = readw(dev->mmio + ME_READ_AD_FIFO); - val = (val ^ 0x800) & 0x0fff; - data[0] = val; + /* munge 2's complement value to offset binary */ + data[i] = comedi_offset_munge(s, val); + } /* stop any running conversion */ - dev_private->control_1 &= 0xFFFC; - writew(dev_private->control_1, dev->mmio + ME_CONTROL_1); + devpriv->ctrl1 &= ~ME_CTRL1_ADC_MODE_MASK; + writew(devpriv->ctrl1, dev->mmio + ME_CTRL1_REG); - return 1; + return ret ? ret : insn->n; } static int me_ao_insn_write(struct comedi_device *dev, @@ -318,46 +306,41 @@ static int me_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct me_private_data *dev_private = dev->private; + struct me_private_data *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int rang = CR_RANGE(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); unsigned int val = s->readback[chan]; int i; /* Enable all DAC */ - dev_private->control_2 |= ENABLE_DAC; - writew(dev_private->control_2, dev->mmio + ME_CONTROL_2); + devpriv->ctrl2 |= ME_CTRL2_DAC_ENA; + writew(devpriv->ctrl2, dev->mmio + ME_CTRL2_REG); /* and set DAC to "buffered" mode */ - dev_private->control_2 |= BUFFERED_DAC; - writew(dev_private->control_2, dev->mmio + ME_CONTROL_2); + devpriv->ctrl2 |= ME_CTRL2_BUFFERED_DAC; + writew(devpriv->ctrl2, dev->mmio + ME_CTRL2_REG); /* Set dac-control register */ - for (i = 0; i < insn->n; i++) { - /* clear bits for this channel */ - dev_private->dac_control &= ~(0x0880 >> chan); - if (rang == 0) - dev_private->dac_control |= - ((DAC_BIPOLAR_A | DAC_GAIN_1_A) >> chan); - else if (rang == 1) - dev_private->dac_control |= - ((DAC_BIPOLAR_A | DAC_GAIN_0_A) >> chan); - } - writew(dev_private->dac_control, dev->mmio + ME_DAC_CONTROL); + devpriv->dac_ctrl &= ~ME_DAC_CTRL_MASK(chan); + if (range == 0) + devpriv->dac_ctrl |= ME_DAC_CTRL_GAIN(chan); + if (comedi_range_is_bipolar(s, range)) + devpriv->dac_ctrl |= ME_DAC_CTRL_BIPOLAR(chan); + writew(devpriv->dac_ctrl, dev->mmio + ME_DAC_CTRL_REG); /* Update dac-control register */ - readw(dev->mmio + ME_DAC_CONTROL_UPDATE); + readw(dev->mmio + ME_DAC_CTRL_REG); /* Set data register */ for (i = 0; i < insn->n; i++) { val = data[i]; - writew(val, dev->mmio + ME_DAC_DATA_A + (chan << 1)); + writew(val, dev->mmio + ME_AO_DATA_REG(chan)); } s->readback[chan] = val; /* Update dac with data registers */ - readw(dev->mmio + ME_DAC_UPDATE); + readw(dev->mmio + ME_CTRL2_REG); return insn->n; } @@ -366,13 +349,13 @@ static int me2600_xilinx_download(struct comedi_device *dev, const u8 *data, size_t size, unsigned long context) { - struct me_private_data *dev_private = dev->private; + struct me_private_data *devpriv = dev->private; unsigned int value; unsigned int file_length; unsigned int i; /* disable irq's on PLX */ - writel(0x00, dev_private->plx_regbase + PLX9052_INTCSR); + writel(0x00, devpriv->plx_regbase + PLX9052_INTCSR); /* First, make a dummy read to reset xilinx */ value = readw(dev->mmio + XILINX_DOWNLOAD_RESET); @@ -412,10 +395,10 @@ static int me2600_xilinx_download(struct comedi_device *dev, writeb(0x00, dev->mmio + 0x0); /* Test if there was an error during download -> INTB was thrown */ - value = readl(dev_private->plx_regbase + PLX9052_INTCSR); + value = readl(devpriv->plx_regbase + PLX9052_INTCSR); if (value & PLX9052_INTCSR_LI2STAT) { /* Disable interrupt */ - writel(0x00, dev_private->plx_regbase + PLX9052_INTCSR); + writel(0x00, devpriv->plx_regbase + PLX9052_INTCSR); dev_err(dev->class_dev, "Xilinx download failed\n"); return -EIO; } @@ -427,25 +410,25 @@ static int me2600_xilinx_download(struct comedi_device *dev, writel(PLX9052_INTCSR_LI1ENAB | PLX9052_INTCSR_LI1POL | PLX9052_INTCSR_PCIENAB, - dev_private->plx_regbase + PLX9052_INTCSR); + devpriv->plx_regbase + PLX9052_INTCSR); return 0; } static int me_reset(struct comedi_device *dev) { - struct me_private_data *dev_private = dev->private; + struct me_private_data *devpriv = dev->private; /* Reset board */ - writew(0x00, dev->mmio + ME_CONTROL_1); - writew(0x00, dev->mmio + ME_CONTROL_2); - writew(0x00, dev->mmio + ME_RESET_INTERRUPT); - writew(0x00, dev->mmio + ME_DAC_CONTROL); + writew(0x00, dev->mmio + ME_CTRL1_REG); + writew(0x00, dev->mmio + ME_CTRL2_REG); + writew(0x00, dev->mmio + ME_STATUS_REG); /* clear interrupts */ + writew(0x00, dev->mmio + ME_DAC_CTRL_REG); /* Save values in the board context */ - dev_private->dac_control = 0; - dev_private->control_1 = 0; - dev_private->control_2 = 0; + devpriv->dac_ctrl = 0; + devpriv->ctrl1 = 0; + devpriv->ctrl2 = 0; return 0; } @@ -455,7 +438,7 @@ static int me_auto_attach(struct comedi_device *dev, { struct pci_dev *pcidev = comedi_to_pci_dev(dev); const struct me_board *board = NULL; - struct me_private_data *dev_private; + struct me_private_data *devpriv; struct comedi_subdevice *s; int ret; @@ -466,16 +449,16 @@ static int me_auto_attach(struct comedi_device *dev, dev->board_ptr = board; dev->board_name = board->name; - dev_private = comedi_alloc_devpriv(dev, sizeof(*dev_private)); - if (!dev_private) + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) return -ENOMEM; ret = comedi_pci_enable(dev); if (ret) return ret; - dev_private->plx_regbase = pci_ioremap_bar(pcidev, 0); - if (!dev_private->plx_regbase) + devpriv->plx_regbase = pci_ioremap_bar(pcidev, 0); + if (!devpriv->plx_regbase) return -ENOMEM; dev->mmio = pci_ioremap_bar(pcidev, 2); @@ -498,7 +481,7 @@ static int me_auto_attach(struct comedi_device *dev, s = &dev->subdevices[0]; s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_COMMON; + s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_DIFF; s->n_chan = 16; s->maxdata = 0x0fff; s->len_chanlist = 16; @@ -537,13 +520,13 @@ static int me_auto_attach(struct comedi_device *dev, static void me_detach(struct comedi_device *dev) { - struct me_private_data *dev_private = dev->private; + struct me_private_data *devpriv = dev->private; - if (dev_private) { + if (devpriv) { if (dev->mmio) me_reset(dev); - if (dev_private->plx_regbase) - iounmap(dev_private->plx_regbase); + if (devpriv->plx_regbase) + iounmap(devpriv->plx_regbase); } comedi_pci_detach(dev); } |