// SPDX-License-Identifier: GPL-2.0+ /* * Hardware driver for DAQ-STC based boards * * COMEDI - Linux Control and Measurement Device Interface * Copyright (C) 1997-2001 David A. Schleef <ds@schleef.org> * Copyright (C) 2002-2006 Frank Mori Hess <fmhess@users.sourceforge.net>
*/
/* * This file is meant to be included by another file, e.g., * ni_atmio.c or ni_pcimio.c. * * Interrupt support originally added by Truxton Fulton <trux@truxton.com> * * References (ftp://ftp.natinst.com/support/manuals): * 340747b.pdf AT-MIO E series Register Level Programmer Manual * 341079b.pdf PCI E Series RLPM * 340934b.pdf DAQ-STC reference manual * * 67xx and 611x registers (ftp://ftp.ni.com/support/daq/mhddk/documentation/) * release_ni611x.pdf * release_ni67xx.pdf * * Other possibly relevant info: * 320517c.pdf User manual (obsolete) * 320517f.pdf User manual (new) * 320889a.pdf delete * 320906c.pdf maximum signal ratings * 321066a.pdf about 16x * 321791a.pdf discontinuation of at-mio-16e-10 rev. c * 321808a.pdf about at-mio-16e-10 rev P * 321837a.pdf discontinuation of at-mio-16de-10 rev d * 321838a.pdf about at-mio-16de-10 rev N * * ISSUES: * - the interrupt routine needs to be cleaned up * * 2006-02-07: S-Series PCI-6143: Support has been added but is not * fully tested as yet. Terry Barnaby, BEAM Ltd.
*/
/* * We automatically take advantage of STC registers that can be * read/written directly in the I/O space of the board. * * The AT-MIO and DAQCard devices map the low 8 STC registers to * iobase+reg*2. * * Most PCIMIO devices also map the low 8 STC registers but the * 611x devices map the read registers to iobase+(addr-1)*2. * For now non-windowed STC access is disabled if a PCIMIO device * is detected (devpriv->mite has been initialized). * * The M series devices do not used windowed registers for the * STC registers. The functions below handle the mapping of the * windowed STC registers to the m series register offsets.
*/
struct mio_regmap { unsignedint mio_reg; int size;
};
spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
mite_chan = mite_request_channel(devpriv->mite, devpriv->cdo_mite_ring); if (!mite_chan) {
spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
dev_err(dev->class_dev, "failed to reserve mite dma channel for correlated digital output\n"); return -EBUSY;
}
mite_chan->dir = COMEDI_OUTPUT;
devpriv->cdo_mite_chan = mite_chan;
/* * XXX just guessing NI_STC_DMA_CHAN_SEL() * returns the right bits, under the assumption the cdio dma * selection works just like ai/ao/gpct. * Definitely works for dma channels 0 and 1.
*/
bits = NI_STC_DMA_CHAN_SEL(mite_chan->channel);
ni_set_bitfield(dev, NI_M_CDIO_DMA_SEL_REG,
NI_M_CDIO_DMA_SEL_CDO_MASK,
NI_M_CDIO_DMA_SEL_CDO(bits));
staticvoid ni_e_series_enable_second_irq(struct comedi_device *dev, unsignedint gpct_index, short enable)
{ struct ni_private *devpriv = dev->private; unsignedint val = 0; int reg;
if (devpriv->is_m_series || gpct_index > 1) return;
/* * e-series boards use the second irq signals to generate * dma requests for their counters
*/ if (gpct_index == 0) {
reg = NISTC_INTA2_ENA_REG; if (enable)
val = NISTC_INTA_ENA_G0_GATE;
} else {
reg = NISTC_INTB2_ENA_REG; if (enable)
val = NISTC_INTB_ENA_G1_GATE;
}
ni_stc_writew(dev, val, reg);
} #endif/* PCIDMA */
if (devpriv->is_6143) { /* Flush the 6143 data FIFO */
ni_writel(dev, 0x10, NI6143_AI_FIFO_CTRL_REG);
ni_writel(dev, 0x00, NI6143_AI_FIFO_CTRL_REG); /* Wait for complete */ for (i = 0; i < timeout; i++) { if (!(ni_readl(dev, NI6143_AI_FIFO_STATUS_REG) & 0x10)) break;
udelay(1);
} if (i == timeout)
dev_err(dev->class_dev, "FIFO flush timeout\n");
} else {
ni_stc_writew(dev, 1, NISTC_ADC_FIFO_CLR_REG); if (devpriv->is_625x) {
ni_writeb(dev, 0, NI_M_STATIC_AI_CTRL_REG(0));
ni_writeb(dev, 1, NI_M_STATIC_AI_CTRL_REG(0)); #if 0 /* * The NI example code does 3 convert pulses for 625x * boards, But that appears to be wrong in practice.
*/
ni_stc_writew(dev, NISTC_AI_CMD1_CONVERT_PULSE,
NISTC_AI_CMD1_REG);
ni_stc_writew(dev, NISTC_AI_CMD1_CONVERT_PULSE,
NISTC_AI_CMD1_REG);
ni_stc_writew(dev, NISTC_AI_CMD1_CONVERT_PULSE,
NISTC_AI_CMD1_REG); #endif
}
}
}
/* * ni_set_bits( ) allows different parts of the ni_mio_common driver to * share registers (such as Interrupt_A_Register) without interfering with * each other. * * NOTE: the switch/case statements are optimized out for a constant argument * so this is actually quite fast--- If you must wrap another function around * this make it inline to avoid a large speed penalty. * * value should only be 1 or 0.
*/ staticinlinevoid ni_set_bits(struct comedi_device *dev, int reg, unsignedint bits, unsignedint value)
{ unsignedint bit_values;
for (i = 0; i < timeout; i++) { unsignedshort b_status;
b_status = ni_stc_readw(dev, NISTC_AO_STATUS1_REG); if (b_status & NISTC_AO_STATUS1_FIFO_HF) break; /* * If we poll too often, the pci bus activity seems * to slow the dma transfer down.
*/
usleep_range(10, 100);
} if (i == timeout) {
dev_err(dev->class_dev, "timed out waiting for dma load\n"); return -EPIPE;
} return 0;
} #endif/* PCIDMA */
for (i = 0; i < n; i++) {
comedi_buf_read_samples(s, &d, 1);
if (devpriv->is_6xxx) {
packed_data = d & 0xffff; /* 6711 only has 16 bit wide ao fifo */ if (!devpriv->is_6711) {
comedi_buf_read_samples(s, &d, 1);
i++;
packed_data |= (d << 16) & 0xffff0000;
}
ni_writel(dev, packed_data, NI611X_AO_FIFO_DATA_REG);
} else {
ni_writew(dev, d, NI_E_AO_FIFO_DATA_REG);
}
}
}
/* * There's a small problem if the FIFO gets really low and we * don't have the data to fill it. Basically, if after we fill * the FIFO with all the data available, the FIFO is _still_ * less than half full, we never clear the interrupt. If the * IRQ is in edge mode, we never get another interrupt, because * this one wasn't cleared. If in level mode, we get flooded * with interrupts that we can't fulfill, because nothing ever * gets put into the buffer. * * This kind of situation is recoverable, but it is easier to * just pretend we had a FIFO underrun, since there is a good * chance it will happen anyway. This is _not_ the case for * RT code, as RT code might purposely be running close to the * metal. Needs to be fixed eventually.
*/ staticint ni_ao_fifo_half_empty(struct comedi_device *dev, struct comedi_subdevice *s)
{ conststruct ni_board_struct *board = dev->board_ptr; unsignedint nbytes; unsignedint nsamples;
if (devpriv->is_611x) { for (i = 0; i < n / 2; i++) {
dl = ni_readl(dev, NI611X_AI_FIFO_DATA_REG); /* This may get the hi/lo data in the wrong order */
data = (dl >> 16) & 0xffff;
comedi_buf_write_samples(s, &data, 1);
data = dl & 0xffff;
comedi_buf_write_samples(s, &data, 1);
} /* Check if there's a single sample stuck in the FIFO */ if (n % 2) {
dl = ni_readl(dev, NI611X_AI_FIFO_DATA_REG);
data = dl & 0xffff;
comedi_buf_write_samples(s, &data, 1);
}
} elseif (devpriv->is_6143) { /* * This just reads the FIFO assuming the data is present, * no checks on the FIFO status are performed.
*/ for (i = 0; i < n / 2; i++) {
dl = ni_readl(dev, NI6143_AI_FIFO_DATA_REG);
data = (dl >> 16) & 0xffff;
comedi_buf_write_samples(s, &data, 1);
data = dl & 0xffff;
comedi_buf_write_samples(s, &data, 1);
} if (n % 2) { /* Assume there is a single sample stuck in the FIFO */ /* Get stranded sample into FIFO */
ni_writel(dev, 0x01, NI6143_AI_FIFO_CTRL_REG);
dl = ni_readl(dev, NI6143_AI_FIFO_DATA_REG);
data = (dl >> 16) & 0xffff;
comedi_buf_write_samples(s, &data, 1);
}
} else { if (n > ARRAY_SIZE(devpriv->ai_fifo_buffer)) {
dev_err(dev->class_dev, "bug! ai_fifo_buffer too small\n");
async->events |= COMEDI_CB_ERROR; return;
} for (i = 0; i < n; i++) {
devpriv->ai_fifo_buffer[i] =
ni_readw(dev, NI_E_AI_FIFO_DATA_REG);
}
comedi_buf_write_samples(s, devpriv->ai_fifo_buffer, n);
}
}
/* Empties the AI fifo */ staticvoid ni_handle_fifo_dregs(struct comedi_device *dev)
{ struct ni_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; unsignedint dl; unsignedshort data; int i;
if (devpriv->is_611x) { while ((ni_stc_readw(dev, NISTC_AI_STATUS1_REG) &
NISTC_AI_STATUS1_FIFO_E) == 0) {
dl = ni_readl(dev, NI611X_AI_FIFO_DATA_REG);
/* This may get the hi/lo data in the wrong order */
data = dl >> 16;
comedi_buf_write_samples(s, &data, 1);
data = dl & 0xffff;
comedi_buf_write_samples(s, &data, 1);
}
} elseif (devpriv->is_6143) {
i = 0; while (ni_readl(dev, NI6143_AI_FIFO_STATUS_REG) & 0x04) {
dl = ni_readl(dev, NI6143_AI_FIFO_DATA_REG);
/* This may get the hi/lo data in the wrong order */
data = dl >> 16;
comedi_buf_write_samples(s, &data, 1);
data = dl & 0xffff;
comedi_buf_write_samples(s, &data, 1);
i += 2;
} /* Check if stranded sample is present */ if (ni_readl(dev, NI6143_AI_FIFO_STATUS_REG) & 0x01) { /* Get stranded sample into FIFO */
ni_writel(dev, 0x01, NI6143_AI_FIFO_CTRL_REG);
dl = ni_readl(dev, NI6143_AI_FIFO_DATA_REG);
data = (dl >> 16) & 0xffff;
comedi_buf_write_samples(s, &data, 1);
}
} else { unsignedshort fe; /* fifo empty */
fe = ni_stc_readw(dev, NISTC_AI_STATUS1_REG) &
NISTC_AI_STATUS1_FIFO_E; while (fe == 0) { for (i = 0;
i < ARRAY_SIZE(devpriv->ai_fifo_buffer); i++) {
fe = ni_stc_readw(dev, NISTC_AI_STATUS1_REG) &
NISTC_AI_STATUS1_FIFO_E; if (fe) break;
devpriv->ai_fifo_buffer[i] =
ni_readw(dev, NI_E_AI_FIFO_DATA_REG);
}
comedi_buf_write_samples(s, devpriv->ai_fifo_buffer, i);
}
}
}
/* Check if there's a single sample stuck in the FIFO */ if (ni_readb(dev, NI_E_STATUS_REG) & 0x80) {
dl = ni_readl(dev, NI611X_AI_FIFO_DATA_REG);
data = dl & 0xffff;
comedi_buf_write_samples(s, &data, 1);
}
}
/* Check if there's a single sample stuck in the FIFO */ if (ni_readl(dev, NI6143_AI_FIFO_STATUS_REG) & 0x01) { /* Get stranded sample into FIFO */
ni_writel(dev, 0x01, NI6143_AI_FIFO_CTRL_REG);
dl = ni_readl(dev, NI6143_AI_FIFO_DATA_REG);
/* This may get the hi/lo data in the wrong order */
data = (dl >> 16) & 0xffff;
comedi_buf_write_samples(s, &data, 1);
}
}
if (devpriv->aimode == AIMODE_SCAN) { #ifdef PCIDMA staticconstint timeout = 10; int i;
for (i = 0; i < timeout; i++) {
ni_sync_ai_dma(dev); if ((s->async->events & COMEDI_CB_EOS)) break;
udelay(1);
} #else
ni_handle_fifo_dregs(dev);
s->async->events |= COMEDI_CB_EOS; #endif
} /* handle special case of single scan */ if (devpriv->ai_cmd2 & NISTC_AI_CMD2_END_ON_EOS)
shutdown_ai_command(dev);
}
/* test for all uncommon interrupt events at the same time */ if (status & (NISTC_AI_STATUS1_ERR |
NISTC_AI_STATUS1_SC_TC | NISTC_AI_STATUS1_START1)) { if (status == 0xffff) {
dev_err(dev->class_dev, "Card removed?\n"); /* * We probably aren't even running a command now, * so it's a good idea to be careful.
*/ if (comedi_is_subdevice_running(s))
s->async->events |= COMEDI_CB_ERROR; return;
} if (status & NISTC_AI_STATUS1_ERR) {
dev_err(dev->class_dev, "ai error a_status=%04x\n",
status);
shutdown_ai_command(dev);
s->async->events |= COMEDI_CB_ERROR; if (status & NISTC_AI_STATUS1_OVER)
s->async->events |= COMEDI_CB_OVERFLOW; return;
} if (status & NISTC_AI_STATUS1_SC_TC) { if (cmd->stop_src == TRIG_COUNT)
shutdown_ai_command(dev);
}
} #ifndef PCIDMA if (status & NISTC_AI_STATUS1_FIFO_HF) { int i; staticconstint timeout = 10; /* * PCMCIA cards (at least 6036) seem to stop producing * interrupts if we fail to get the fifo less than half * full, so loop to be sure.
*/ for (i = 0; i < timeout; ++i) {
ni_handle_fifo_half_full(dev); if ((ni_stc_readw(dev, NISTC_AI_STATUS1_REG) &
NISTC_AI_STATUS1_FIFO_HF) == 0) break;
}
} #endif/* !PCIDMA */
if (status & NISTC_AI_STATUS1_STOP)
ni_handle_eos(dev, s);
}
retval = ni_request_ao_mite_channel(dev); if (retval) return retval;
/* read alloc the entire buffer */
comedi_buf_read_alloc(s, s->async->prealloc_bufsz);
spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->ao_mite_chan) { if (devpriv->is_611x || devpriv->is_6713) {
mite_prep_dma(devpriv->ao_mite_chan, 32, 32);
} else { /* * Doing 32 instead of 16 bit wide transfers from * memory makes the mite do 32 bit pci transfers, * doubling pci bandwidth.
*/
mite_prep_dma(devpriv->ao_mite_chan, 16, 32);
}
mite_dma_arm(devpriv->ao_mite_chan);
} else {
retval = -EIO;
}
spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
return retval;
}
#endif/* PCIDMA */
/* * used for both cancel ioctl and board initialization * * this is pretty harsh for a cancel, but it works...
*/ staticint ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s)
{ struct ni_private *devpriv = dev->private; unsignedint ai_personal; unsignedint ai_out_ctrl;
ni_release_ai_mite_channel(dev); /* ai configuration */
ni_stc_writew(dev, NISTC_RESET_AI_CFG_START | NISTC_RESET_AI,
NISTC_RESET_REG);
/* the following registers should not be changed, because there * are no backup registers in devpriv. If you want to change * any of these, add a backup register and other appropriate code: * NISTC_AI_MODE1_REG * NISTC_AI_MODE3_REG * NISTC_AI_PERSONAL_REG * NISTC_AI_OUT_CTRL_REG
*/
range_code = ni_gainlkup[board->gainlkup][range];
devpriv->ai_offset[i] = 0; switch (aref) { case AREF_DIFF:
config_bits |= NI_M_AI_CFG_CHAN_TYPE_DIFF; break; case AREF_COMMON:
config_bits |= NI_M_AI_CFG_CHAN_TYPE_COMMON; break; case AREF_GROUND:
config_bits |= NI_M_AI_CFG_CHAN_TYPE_GROUND; break; case AREF_OTHER: break;
}
config_bits |= NI_M_AI_CFG_CHAN_SEL(chan);
config_bits |= NI_M_AI_CFG_BANK_SEL(chan);
config_bits |= NI_M_AI_CFG_GAIN(range_code); if (i == n_chan - 1)
config_bits |= NI_M_AI_CFG_LAST_CHAN; if (dither)
config_bits |= NI_M_AI_CFG_DITHER; /* don't use 2's complement encoding */
config_bits |= NI_M_AI_CFG_POLARITY;
ni_writew(dev, config_bits, NI_M_AI_CFG_FIFO_DATA_REG);
}
ni_prime_channelgain_list(dev);
}
/* * Notes on the 6110 and 6111: * These boards a slightly different than the rest of the series, since * they have multiple A/D converters. * From the driver side, the configuration memory is a * little different. * Configuration Memory Low: * bits 15-9: same * bit 8: unipolar/bipolar (should be 0 for bipolar) * bits 0-3: gain. This is 4 bits instead of 3 for the other boards * 1001 gain=0.1 (+/- 50) * 1010 0.2 * 1011 0.1 * 0001 1 * 0010 2 * 0011 5 * 0100 10 * 0101 20 * 0110 50 * Configuration Memory High: * bits 12-14: Channel Type * 001 for differential * 000 for calibration * bit 11: coupling (this is not currently handled) * 1 AC coupling * 0 DC coupling * bits 0-2: channel * valid channels are 0-3
*/ staticvoid ni_load_channelgain_list(struct comedi_device *dev, struct comedi_subdevice *s, unsignedint n_chan, unsignedint *list)
{ conststruct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; unsignedint offset = (s->maxdata + 1) >> 1; unsignedint chan, range, aref; unsignedint i; unsignedint hi, lo; unsignedint dither;
/* Set up Calibration mode if required */ if (devpriv->is_6143) { if ((list[0] & CR_ALT_SOURCE) &&
!devpriv->ai_calib_source_enabled) { /* Strobe Relay enable bit */
ni_writew(dev, devpriv->ai_calib_source |
NI6143_CALIB_CHAN_RELAY_ON,
NI6143_CALIB_CHAN_REG);
ni_writew(dev, devpriv->ai_calib_source,
NI6143_CALIB_CHAN_REG);
devpriv->ai_calib_source_enabled = 1; /* Allow relays to change */
msleep_interruptible(100);
} elseif (!(list[0] & CR_ALT_SOURCE) &&
devpriv->ai_calib_source_enabled) { /* Strobe Relay disable bit */
ni_writew(dev, devpriv->ai_calib_source |
NI6143_CALIB_CHAN_RELAY_OFF,
NI6143_CALIB_CHAN_REG);
ni_writew(dev, devpriv->ai_calib_source,
NI6143_CALIB_CHAN_REG);
devpriv->ai_calib_source_enabled = 0; /* Allow relays to change */
msleep_interruptible(100);
}
}
for (i = 0; i < n_chan; i++) { if (!devpriv->is_6143 && (list[i] & CR_ALT_SOURCE))
chan = devpriv->ai_calib_source; else
chan = CR_CHAN(list[i]);
aref = CR_AREF(list[i]);
range = CR_RANGE(list[i]);
dither = (list[i] & CR_ALT_FILTER) != 0;
/* fix the external/internal range differences */
range = ni_gainlkup[board->gainlkup][range]; if (devpriv->is_611x)
devpriv->ai_offset[i] = offset; else
devpriv->ai_offset[i] = (range & 0x100) ? 0 : offset;
hi = 0; if ((list[i] & CR_ALT_SOURCE)) { if (devpriv->is_611x)
ni_writew(dev, CR_CHAN(list[i]) & 0x0003,
NI611X_CALIB_CHAN_SEL_REG);
} else { if (devpriv->is_611x)
aref = AREF_DIFF; elseif (devpriv->is_6143)
aref = AREF_OTHER; switch (aref) { case AREF_DIFF:
hi |= NI_E_AI_CFG_HI_TYPE_DIFF; break; case AREF_COMMON:
hi |= NI_E_AI_CFG_HI_TYPE_COMMON; break; case AREF_GROUND:
hi |= NI_E_AI_CFG_HI_TYPE_GROUND; break; case AREF_OTHER: break;
}
}
hi |= NI_E_AI_CFG_HI_CHAN(chan);
ni_writew(dev, hi, NI_E_AI_CFG_HI_REG);
if (!devpriv->is_6143) {
lo = NI_E_AI_CFG_LO_GAIN(range);
if (i == n_chan - 1)
lo |= NI_E_AI_CFG_LO_LAST_CHAN; if (dither)
lo |= NI_E_AI_CFG_LO_DITHER;
ni_writew(dev, lo, NI_E_AI_CFG_LO_REG);
}
}
/* prime the channel/gain list */ if (!devpriv->is_611x && !devpriv->is_6143)
ni_prime_channelgain_list(dev);
}
signbits = devpriv->ai_offset[0]; if (devpriv->is_611x) { for (n = 0; n < num_adc_stages_611x; n++) {
ni_stc_writew(dev, NISTC_AI_CMD1_CONVERT_PULSE,
NISTC_AI_CMD1_REG);
udelay(1);
} for (n = 0; n < insn->n; n++) {
ni_stc_writew(dev, NISTC_AI_CMD1_CONVERT_PULSE,
NISTC_AI_CMD1_REG); /* The 611x has screwy 32-bit FIFOs. */
d = 0; for (i = 0; i < NI_TIMEOUT; i++) { if (ni_readb(dev, NI_E_STATUS_REG) & 0x80) {
d = ni_readl(dev,
NI611X_AI_FIFO_DATA_REG);
d >>= 16;
d &= 0xffff; break;
} if (!(ni_stc_readw(dev, NISTC_AI_STATUS1_REG) &
NISTC_AI_STATUS1_FIFO_E)) {
d = ni_readl(dev,
NI611X_AI_FIFO_DATA_REG);
d &= 0xffff; break;
}
} if (i == NI_TIMEOUT) {
dev_err(dev->class_dev, "timeout\n"); return -ETIME;
}
d += signbits;
data[n] = d & 0xffff;
}
} elseif (devpriv->is_6143) { for (n = 0; n < insn->n; n++) {
ni_stc_writew(dev, NISTC_AI_CMD1_CONVERT_PULSE,
NISTC_AI_CMD1_REG);
/* * The 6143 has 32-bit FIFOs. You need to strobe a * bit to move a single 16bit stranded sample into * the FIFO.
*/
d = 0; for (i = 0; i < NI_TIMEOUT; i++) { if (ni_readl(dev, NI6143_AI_FIFO_STATUS_REG) &
0x01) { /* Get stranded sample into FIFO */
ni_writel(dev, 0x01,
NI6143_AI_FIFO_CTRL_REG);
d = ni_readl(dev,
NI6143_AI_FIFO_DATA_REG); break;
}
} if (i == NI_TIMEOUT) {
dev_err(dev->class_dev, "timeout\n"); return -ETIME;
}
data[n] = (((d >> 16) & 0xFFFF) + signbits) & 0xFFFF;
}
} else { for (n = 0; n < insn->n; n++) {
ni_stc_writew(dev, NISTC_AI_CMD1_CONVERT_PULSE,
NISTC_AI_CMD1_REG); for (i = 0; i < NI_TIMEOUT; i++) { if (!(ni_stc_readw(dev, NISTC_AI_STATUS1_REG) &
NISTC_AI_STATUS1_FIFO_E)) break;
} if (i == NI_TIMEOUT) {
dev_err(dev->class_dev, "timeout\n"); return -ETIME;
} if (devpriv->is_m_series) {
d = ni_readl(dev, NI_M_AI_FIFO_DATA_REG);
d &= mask;
data[n] = d;
} else {
d = ni_readw(dev, NI_E_AI_FIFO_DATA_REG);
d += signbits;
data[n] = d & 0xffff;
}
}
} return insn->n;
}
if (nbytes > sdev->async->prealloc_bufsz) { if (cmd->stop_arg > 0)
dev_err(sdev->device->class_dev, "%s: tried exact data transfer limits greater than buffer size\n",
__func__);
/* * we can only transfer up to the size of the buffer. In this * case, the user is expected to continue to write into the * comedi buffer (already implemented as a ring buffer).
*/
nbytes = sdev->async->prealloc_bufsz;
}
mite_init_ring_descriptors(ring, sdev, nbytes); #else
dev_err(sdev->device->class_dev, "%s: exact data transfer limits not implemented yet without DMA\n",
__func__); #endif
}
/* * Disable analog triggering for now, since it interferes * with the use of pfi0.
*/
devpriv->an_trig_etc_reg &= ~NISTC_ATRIG_ETC_ENA;
ni_stc_writew(dev, devpriv->an_trig_etc_reg, NISTC_ATRIG_ETC_REG);
ai_trig = NISTC_AI_TRIG_START2_SEL(0) | NISTC_AI_TRIG_START1_SYNC; switch (cmd->start_src) { case TRIG_INT: case TRIG_NOW:
ai_trig |= NISTC_AI_TRIG_START1_EDGE |
NISTC_AI_TRIG_START1_SEL(0); break; case TRIG_EXT:
ai_trig |= NISTC_AI_TRIG_START1_SEL(
ni_get_reg_value_roffs(
CR_CHAN(cmd->start_arg),
NI_AI_StartTrigger,
&devpriv->routing_tables, 1));
if (cmd->start_arg & CR_INVERT)
ai_trig |= NISTC_AI_TRIG_START1_POLARITY; if (cmd->start_arg & CR_EDGE)
ai_trig |= NISTC_AI_TRIG_START1_EDGE; break;
}
ni_stc_writew(dev, ai_trig, NISTC_AI_TRIG_SEL_REG);
if (devpriv->is_611x) { /* have to take 3 stage adc pipeline into account */
stop_count += num_adc_stages_611x;
} /* stage number of scans */
ni_stc_writel(dev, stop_count, NISTC_AI_SC_LOADA_REG);
if (stop_count == 0) {
devpriv->ai_cmd2 |= NISTC_AI_CMD2_END_ON_EOS;
interrupt_a_enable |= NISTC_INTA_ENA_AI_STOP; /* * This is required to get the last sample for * chanlist_len > 1, not sure why.
*/ if (cmd->chanlist_len > 1)
start_stop_select |= NISTC_AI_STOP_POLARITY |
NISTC_AI_STOP_EDGE;
} break; case TRIG_NONE: /* stage number of scans */
ni_stc_writel(dev, 0, NISTC_AI_SC_LOADA_REG);
if (timed) { for (i = 0; i < s->n_chan; ++i) {
devpriv->ao_conf[i] &= ~NI_M_AO_CFG_BANK_UPDATE_TIMED;
ni_writeb(dev, devpriv->ao_conf[i],
NI_M_AO_CFG_BANK_REG(i));
ni_writeb(dev, 0xf, NI_M_AO_WAVEFORM_ORDER_REG(i));
}
} for (i = 0; i < n_chans; i++) { conststruct comedi_krange *krange;
for (i = 0; i < insn->n; i++) { unsignedint val = data[i];
s->readback[chan] = val;
if (devpriv->is_6xxx) { /* * 6xxx boards have bipolar outputs, munge the * unsigned comedi values to 2's complement
*/
val = comedi_offset_munge(s, val);
ni_ao_win_outw(dev, val, reg);
} elseif (devpriv->is_m_series) { /* * M-series boards use offset binary values for * bipolar and uinpolar outputs
*/
ni_writew(dev, val, reg);
} else { /* * Non-M series boards need two's complement values * for bipolar ranges.
*/ if (comedi_range_is_bipolar(s, range))
val = comedi_offset_munge(s, val);
ni_writew(dev, val, reg);
}
}
return insn->n;
}
/* * Arms the AO device in preparation for a trigger event. * This function also allocates and prepares a DMA channel (or FIFO if DMA is * not used). As a part of this preparation, this function preloads the DAC * registers with the first values of the output stream. This ensures that the * first clock cycle after the trigger can be used for output. * * Note that this function _must_ happen after a user has written data to the * output buffers via either mmap or write(fileno,...).
*/ staticint ni_ao_arm(struct comedi_device *dev, struct comedi_subdevice *s)
{ struct ni_private *devpriv = dev->private; int ret; int interrupt_b_bits; int i; staticconstint timeout = 1000;
/* * Prevent ao from doing things like trying to allocate the ao dma * channel multiple times.
*/ if (!devpriv->ao_needs_arming) {
dev_dbg(dev->class_dev, "%s: device does not need arming!\n",
__func__); return -EINVAL;
}
devpriv->ao_needs_arming = 0;
ni_set_bits(dev, NISTC_INTB_ENA_REG,
NISTC_INTB_ENA_AO_FIFO | NISTC_INTB_ENA_AO_ERR, 0);
interrupt_b_bits = NISTC_INTB_ENA_AO_ERR; #ifdef PCIDMA
ni_stc_writew(dev, 1, NISTC_DAC_FIFO_CLR_REG); if (devpriv->is_6xxx)
ni_ao_win_outl(dev, 0x6, NI611X_AO_FIFO_OFFSET_LOAD_REG);
ret = ni_ao_setup_MITE_dma(dev); if (ret) return ret;
ret = ni_ao_wait_for_dma_load(dev); if (ret < 0) return ret; #else
ret = ni_ao_prep_fifo(dev, s); if (ret == 0) return -EPIPE;
ni_stc_writew(dev, devpriv->ao_mode3 | NISTC_AO_MODE3_NOT_AN_UPDATE,
NISTC_AO_MODE3_REG);
ni_stc_writew(dev, devpriv->ao_mode3, NISTC_AO_MODE3_REG); /* wait for DACs to be loaded */ for (i = 0; i < timeout; i++) {
udelay(1); if ((ni_stc_readw(dev, NISTC_STATUS2_REG) &
NISTC_STATUS2_AO_TMRDACWRS_IN_PROGRESS) == 0) break;
} if (i == timeout) {
dev_err(dev->class_dev, "timed out waiting for AO_TMRDACWRs_In_Progress_St to clear\n"); return -EIO;
} /* * stc manual says we are need to clear error interrupt after * AO_TMRDACWRs_In_Progress_St clears
*/
ni_stc_writew(dev, NISTC_INTB_ACK_AO_ERR, NISTC_INTB_ACK_REG);
/* * Require trig_num == cmd->start_arg when cmd->start_src == TRIG_INT. * For backwards compatibility, also allow trig_num == 0 when * cmd->start_src != TRIG_INT (i.e. when cmd->start_src == TRIG_EXT); * in that case, the internal trigger is being used as a pre-trigger * before the external trigger.
*/ if (!(trig_num == cmd->start_arg ||
(trig_num == 0 && cmd->start_src != TRIG_INT))) return -EINVAL;
/* * Null trig at beginning prevent ao start trigger from executing more * than once per command.
*/
s->async->inttrig = NULL;
if (devpriv->ao_needs_arming) { /* only arm this device if it still needs arming */
ret = ni_ao_arm(dev, s); if (ret) return ret;
}
bits = /* fast CPU interface--only eseries */ /* ((slow CPU interface) ? 0 : AO_Fast_CPU) | */
NISTC_AO_PERSONAL_BC_SRC_SEL |
0 /* (use_original_pulse ? 0 : NISTC_AO_PERSONAL_UPDATE_TIMEBASE) */ | /* * FIXME: start setting following bit when appropriate. Need to * determine whether board is E4 or E1. * FROM MHHDK: * if board is E4 or E1 * Set bit "NISTC_AO_PERSONAL_UPDATE_PW" to 0 * else * set it to 1
*/
NISTC_AO_PERSONAL_UPDATE_PW | /* FIXME: when should we set following bit to zero? */
NISTC_AO_PERSONAL_TMRDACWR_PW |
(board->ao_fifo_depth ?
NISTC_AO_PERSONAL_FIFO_ENA : NISTC_AO_PERSONAL_DMA_PIO_CTRL)
; #if 0 /* * FIXME: * add something like ".has_individual_dacs = 0" to ni_board_struct * since, as F Hess pointed out, not all in m series have singles. not * sure if e-series all have duals...
*/
/* * F Hess: windows driver does not set NISTC_AO_PERSONAL_NUM_DAC bit for * 6281, verified with bus analyzer.
*/ if (devpriv->is_m_series)
bits |= NISTC_AO_PERSONAL_NUM_DAC; #endif
ni_stc_writew(dev, bits, NISTC_AO_PERSONAL_REG);
/* AO_Delayed_START1 = 0, we do not support delayed start...yet */
/* sync */ /* select DA_START1 as PFI6/AO_START1 when configured as an output */
devpriv->ao_mode3 &= ~NISTC_AO_MODE3_TRIG_LEN;
ni_stc_writew(dev, devpriv->ao_mode3, NISTC_AO_MODE3_REG);
staticvoid ni_ao_cmd_set_counters(struct comedi_device *dev, conststruct comedi_cmd *cmd)
{ struct ni_private *devpriv = dev->private; /* Not supporting 'waveform staging' or 'local buffer with pauses' */
ni_stc_writew(dev, NISTC_RESET_AO_CFG_START, NISTC_RESET_REG); /* * This relies on ao_mode1/(Trigger_Once | Continuous) being set in * set_trigger above. It is unclear whether we really need to re-write * this register with these values. The mhddk examples for e-series * show writing this in both places, but the examples for m-series show * a single write in the set_counters function (here).
*/
ni_stc_writew(dev, devpriv->ao_mode1, NISTC_AO_MODE1_REG);
/* sync (upload number of buffer iterations -1) */ /* indicate that we want to use BC_Load_A_Register as the source */
devpriv->ao_mode2 &= ~NISTC_AO_MODE2_BC_INIT_LOAD_SRC;
ni_stc_writew(dev, devpriv->ao_mode2, NISTC_AO_MODE2_REG);
/* * if the BC_TC interrupt is still issued in spite of UC, BC, UI * ignoring BC_TC, then we will need to find a way to ignore that * interrupt in continuous mode.
*/
ni_stc_writel(dev, 0, NISTC_AO_BC_LOADA_REG); /* iter once */
/* sync (issue command to load number of buffer iterations -1) */
ni_stc_writew(dev, NISTC_AO_CMD1_BC_LOAD, NISTC_AO_CMD1_REG);
/* sync (upload number of updates in buffer) */ /* indicate that we want to use UC_Load_A_Register as the source */
devpriv->ao_mode2 &= ~NISTC_AO_MODE2_UC_INIT_LOAD_SRC;
ni_stc_writew(dev, devpriv->ao_mode2, NISTC_AO_MODE2_REG);
/* * if a user specifies '0', this automatically assumes the entire 24bit * address space is available for the (multiple iterations of single * buffer) MISB. Otherwise, stop_arg specifies the MISB length that * will be used, regardless of whether we are in continuous mode or not. * In continuous mode, the output will just iterate indefinitely over * the MISB.
*/
{ unsignedint stop_arg = cmd->stop_arg > 0 ?
(cmd->stop_arg & 0xffffff) : 0xffffff;
if (devpriv->is_m_series) { /* * this is how the NI example code does it for m-series * boards, verified correct with 6259
*/
ni_stc_writel(dev, stop_arg - 1, NISTC_AO_UC_LOADA_REG);
/* sync (issue cmd to load number of updates in MISB) */
ni_stc_writew(dev, NISTC_AO_CMD1_UC_LOAD,
NISTC_AO_CMD1_REG);
} else {
ni_stc_writel(dev, stop_arg, NISTC_AO_UC_LOADA_REG);
/* sync (issue cmd to load number of updates in MISB) */
ni_stc_writew(dev, NISTC_AO_CMD1_UC_LOAD,
NISTC_AO_CMD1_REG);
/* * sync (upload number of updates-1 in MISB) * --eseries only?
*/
ni_stc_writel(dev, stop_arg - 1, NISTC_AO_UC_LOADA_REG);
}
}
/* * zero out these bit fields to be set below. Does an ao-reset do this * automatically?
*/
devpriv->ao_mode1 &= ~(NISTC_AO_MODE1_UI_SRC_MASK |
NISTC_AO_MODE1_UI_SRC_POLARITY |
NISTC_AO_MODE1_UPDATE_SRC_MASK |
NISTC_AO_MODE1_UPDATE_SRC_POLARITY);
if (cmd->scan_begin_src == TRIG_TIMER) { unsignedint trigvar;
devpriv->ao_cmd2 &= ~NISTC_AO_CMD2_BC_GATE_ENA;
/* * NOTE: there are several other ways of configuring internal * updates, but we'll only support one for now: using * AO_IN_TIMEBASE, w/o waveform staging, w/o a delay between * START1 and first update, and also w/o local buffer mode w/ * pauses.
*/
/* * This is already done above: * devpriv->ao_mode1 &= ~( * // set UPDATE_Source to UI_TC: * NISTC_AO_MODE1_UPDATE_SRC_MASK | * // set UPDATE_Source_Polarity to rising (required?) * NISTC_AO_MODE1_UPDATE_SRC_POLARITY | * // set UI_Source to AO_IN_TIMEBASE1: * NISTC_AO_MODE1_UI_SRC_MASK | * // set UI_Source_Polarity to rising (required?) * NISTC_AO_MODE1_UI_SRC_POLARITY * );
*/
/* * TODO: use ao_ui_clock_source to allow all possible signals * to be routed to UI_Source_Select. See tSTC.h for * eseries/ni67xx and tMSeries.h for mseries.
*/
/* Configure DAQ-STC for Timed update mode */
devpriv->ao_cmd1 |= NISTC_AO_CMD1_DAC1_UPDATE_MODE |
NISTC_AO_CMD1_DAC0_UPDATE_MODE; /* We are not using UPDATE2-->don't have to set DACx_Source_Select */
ni_stc_writew(dev, devpriv->ao_cmd1, NISTC_AO_CMD1_REG);
/* * Since we are not supporting waveform staging, we ignore these errors: * NISTC_AO_MODE3_STOP_ON_BC_TC_ERR, * NISTC_AO_MODE3_STOP_ON_BC_TC_TRIG_ERR
*/
/* * arm(ing) must happen later so that DMA can be setup and DACs * preloaded with the actual output buffer before starting. * * start(ing) must happen _after_ arming is completed. Starting can be * done either via ni_ao_inttrig, or via an external trigger. * * **Currently, ni_ao_inttrig will automatically attempt a call to * ni_ao_arm if the device still needs arming at that point. This * allows backwards compatibility.
*/
devpriv->ao_needs_arming = 1; return 0;
}
/* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) {
tmp = cmd->scan_begin_arg;
cmd->scan_begin_arg =
ni_timer_to_ns(dev, ni_ns_to_timer(dev,
cmd->scan_begin_arg,
cmd->flags)); if (tmp != cmd->scan_begin_arg)
err++;
} if (err) return 4;
return 0;
}
staticint ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s)
{ /* See 3.6.1.2 "Resetting", of DAQ-STC Technical Reference Manual */
/* * In the following, the "--sync" comments are meant to denote * asynchronous boundaries for setting the registers as described in the * DAQ-STC mostly in the order also described in the DAQ-STC.
*/
struct ni_private *devpriv = dev->private;
ni_release_ao_mite_channel(dev);
/* --sync (reset AO) */ if (devpriv->is_m_series) /* following example in mhddk for m-series */
ni_stc_writew(dev, NISTC_RESET_AO, NISTC_RESET_REG);
/* Make sure we're not using the serial part of the dio */ if ((data[0] & (NISTC_DIO_SDIN | NISTC_DIO_SDOUT)) &&
devpriv->serial_interval_ns) return -EBUSY;
/* * Although NI_D[IO]_SampleClock are the same, perhaps we should still, * for completeness, test whether the cmd is output or input?
*/
err |= ni_check_trigger_arg(CR_CHAN(cmd->scan_begin_arg),
NI_DO_SampleClock,
&devpriv->routing_tables); if (CR_RANGE(cmd->scan_begin_arg) != 0 ||
CR_AREF(cmd->scan_begin_arg) != 0)
err |= -EINVAL;
/* read alloc the entire buffer */
comedi_buf_read_alloc(s, s->async->prealloc_bufsz);
spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->cdo_mite_chan) {
mite_prep_dma(devpriv->cdo_mite_chan, 32, 32);
mite_dma_arm(devpriv->cdo_mite_chan);
} else {
dev_err(dev->class_dev, "BUG: no cdo mite channel?\n");
retval = -EIO;
}
spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); if (retval < 0) return retval;
/* * XXX not sure what interrupt C group does * wait for dma to fill output fifo * ni_writeb(dev, NI_M_INTC_ENA, NI_M_INTC_ENA_REG);
*/ for (i = 0; i < timeout; ++i) { if (ni_readl(dev, NI_M_CDIO_STATUS_REG) &
NI_M_CDIO_STATUS_CDO_FIFO_FULL) break;
usleep_range(10, 100);
} if (i == timeout) {
dev_err(dev->class_dev, "dma failed to fill cdo fifo!\n");
s->cancel(dev, s); return -EIO;
}
ni_writel(dev, NI_M_CDO_CMD_ARM |
NI_M_CDO_CMD_ERR_INT_ENA_SET |
NI_M_CDO_CMD_F_E_INT_ENA_SET,
NI_M_CDIO_CMD_REG); return retval;
}
ni_writel(dev, NI_M_CDO_CMD_RESET, NI_M_CDIO_CMD_REG); /* * Although NI_D[IO]_SampleClock are the same, perhaps we should still, * for completeness, test whether the cmd is output or input(?)
*/
cdo_mode_bits = NI_M_CDO_MODE_FIFO_MODE |
NI_M_CDO_MODE_HALT_ON_ERROR |
NI_M_CDO_MODE_SAMPLE_SRC(
ni_get_reg_value(
CR_CHAN(cmd->scan_begin_arg),
NI_DO_SampleClock,
&devpriv->routing_tables)); if (cmd->scan_begin_arg & CR_INVERT)
cdo_mode_bits |= NI_M_CDO_MODE_POLARITY;
ni_writel(dev, cdo_mode_bits, NI_M_CDO_MODE_REG); if (s->io_bits) {
ni_writel(dev, s->state, NI_M_CDO_FIFO_DATA_REG);
ni_writel(dev, NI_M_CDO_CMD_SW_UPDATE, NI_M_CDIO_CMD_REG);
ni_writel(dev, s->io_bits, NI_M_CDO_MASK_ENA_REG);
} else {
dev_err(dev->class_dev, "attempted to run digital output command with no lines configured as outputs\n"); return -EIO;
}
retval = ni_request_cdo_mite_channel(dev); if (retval < 0) return retval;
/* Wait until STC says we're done, but don't loop infinitely. */ while ((status1 = ni_stc_readw(dev, NISTC_STATUS1_REG)) &
NISTC_STATUS1_SERIO_IN_PROG) { /* Delay one bit per loop */
udelay((devpriv->serial_interval_ns + 999) / 1000); if (--count < 0) {
dev_err(dev->class_dev, "SPI serial I/O didn't finish in time!\n");
err = -ETIME; goto error;
}
}
/* * Delay for last bit. This delay is absolutely necessary, because * NISTC_STATUS1_SERIO_IN_PROG goes high one bit too early.
*/
udelay((devpriv->serial_interval_ns + 999) / 1000);
if (data_in)
*data_in = ni_stc_readw(dev, NISTC_DIO_SERIAL_IN_REG);
/* Wait for one bit before transfer */
udelay((devpriv->serial_interval_ns + 999) / 1000);
for (mask = 0x80; mask; mask >>= 1) { /* * Output current bit; note that we cannot touch s->state * because it is a per-subdevice field, and serial is * a separate subdevice from DIO.
*/
devpriv->dio_output &= ~NISTC_DIO_SDOUT; if (data_out & mask)
devpriv->dio_output |= NISTC_DIO_SDOUT;
ni_stc_writew(dev, devpriv->dio_output, NISTC_DIO_OUT_REG);
/* * Assert SDCLK (active low, inverted), wait for half of * the delay, deassert SDCLK, and wait for the other half.
*/
devpriv->dio_control |= NISTC_DIO_SDCLK;
ni_stc_writew(dev, devpriv->dio_control, NISTC_DIO_CTRL_REG);
switch (reg) { /* m-series only registers */ case NITIO_G0_CNT_MODE: case NITIO_G1_CNT_MODE: case NITIO_G0_GATE2: case NITIO_G1_GATE2: case NITIO_G0_DMA_CFG: case NITIO_G1_DMA_CFG: case NITIO_G0_ABZ: case NITIO_G1_ABZ:
ni_writew(dev, bits, stc_register); break;
/* 32 bit registers */ case NITIO_G0_LOADA: case NITIO_G1_LOADA: case NITIO_G0_LOADB: case NITIO_G1_LOADB:
ni_stc_writel(dev, bits, stc_register); break;
/* 16 bit registers */ case NITIO_G0_INT_ENA:
ni_set_bitfield(dev, stc_register,
NISTC_INTA_ENA_G0_GATE | NISTC_INTA_ENA_G0_TC,
bits); break; case NITIO_G1_INT_ENA:
ni_set_bitfield(dev, stc_register,
NISTC_INTB_ENA_G1_GATE | NISTC_INTB_ENA_G1_TC,
bits); break; default:
ni_stc_writew(dev, bits, stc_register);
}
}
switch (reg) { /* m-series only registers */ case NITIO_G0_DMA_STATUS: case NITIO_G1_DMA_STATUS: return ni_readw(dev, stc_register);
/* 32 bit registers */ case NITIO_G0_HW_SAVE: case NITIO_G1_HW_SAVE: case NITIO_G0_SW_SAVE: case NITIO_G1_SW_SAVE: return ni_stc_readl(dev, stc_register);
for (i = 0; i < insn->n; i++)
data[0] = devpriv->caldacs[CR_CHAN(insn->chanspec)];
return insn->n;
}
staticvoid caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s)
{ conststruct ni_board_struct *board = dev->board_ptr; struct ni_private *devpriv = dev->private; int i, j; int n_dacs; int n_chans = 0; int n_bits; int diffbits = 0; int type; int chan;
type = board->caldac[0]; if (type == caldac_none) return;
n_bits = caldacs[type].n_bits; for (i = 0; i < 3; i++) {
type = board->caldac[i]; if (type == caldac_none) break; if (caldacs[type].n_bits != n_bits)
diffbits = 1;
n_chans += caldacs[type].n_chans;
}
n_dacs = i;
s->n_chan = n_chans;
if (diffbits) { unsignedint *maxdata_list = devpriv->caldac_maxdata_list;
if (n_chans > MAX_N_CALDACS)
dev_err(dev->class_dev, "BUG! MAX_N_CALDACS too small\n");
s->maxdata_list = maxdata_list;
chan = 0; for (i = 0; i < n_dacs; i++) {
type = board->caldac[i]; for (j = 0; j < caldacs[type].n_chans; j++) {
maxdata_list[chan] =
(1 << caldacs[type].n_bits) - 1;
chan++;
}
}
for (chan = 0; chan < s->n_chan; chan++)
ni_write_caldac(dev, i, s->maxdata_list[i] / 2);
} else {
type = board->caldac[0];
s->maxdata = (1 << caldacs[type].n_bits) - 1;
for (chan = 0; chan < s->n_chan; chan++)
ni_write_caldac(dev, i, s->maxdata / 2);
}
}
staticint ni_read_eeprom(struct comedi_device *dev, int addr)
{ unsignedint cmd = NI_E_SERIAL_CMD_EEPROM_CS; int bit; int bitstring;
if (chan >= NI_PFI(0)) { /* allow new and old names of pfi channels to work. */
chan -= NI_PFI(0);
} return (devpriv->is_m_series)
? ni_m_series_get_pfi_routing(dev, chan)
: ni_old_get_pfi_routing(dev, chan);
}
/* Sets the output mux for the specified PFI channel. */ staticint ni_set_pfi_routing(struct comedi_device *dev, unsignedint chan, unsignedint source)
{ struct ni_private *devpriv = dev->private;
if (chan >= NI_PFI(0)) { /* allow new and old names of pfi channels to work. */
chan -= NI_PFI(0);
} return (devpriv->is_m_series)
? ni_m_series_set_pfi_routing(dev, chan, source)
: ni_old_set_pfi_routing(dev, chan, source);
}
for (i = 0; i < timeout; i++) {
status = ni_ao_win_inw(dev, NI67XX_CAL_STATUS_REG); if ((status & NI67XX_CAL_STATUS_BUSY) == 0) break;
set_current_state(TASK_INTERRUPTIBLE); if (schedule_timeout(1)) return -EIO;
} if (i == timeout) {
dev_err(dev->class_dev, "timeout\n"); return -ETIME;
} return 0;
}
ni_ao_win_outw(dev, value, NI67XX_CAL_CMD_REG); /* give time for command to start being serially clocked into cs5529. * this insures that the NI67XX_CAL_STATUS_BUSY bit will get properly * set before we exit this function.
*/ for (i = 0; i < timeout; i++) { if (ni_ao_win_inw(dev, NI67XX_CAL_STATUS_REG) &
NI67XX_CAL_STATUS_BUSY) break;
udelay(1);
} if (i == timeout)
dev_err(dev->class_dev, "possible problem - never saw adc go busy?\n");
}
#if 1 /* do self-calibration */
cs5529_config_write(dev, config_bits | CS5529_CFG_CALIB_BOTH_SELF,
CS5529_CFG_REG); /* need to force a conversion for calibration to run */
cs5529_do_conversion(dev, NULL); #else /* force gain calibration to 1 */
cs5529_config_write(dev, 0x400000, CS5529_GAIN_REG);
cs5529_config_write(dev, config_bits | CS5529_CFG_CALIB_OFFSET_SELF,
CS5529_CFG_REG); if (cs5529_wait_for_idle(dev))
dev_err(dev->class_dev, "timeout or signal in %s\n", __func__); #endif return 0;
}
/* * Find best multiplier/divider to try and get the PLL running at 80 MHz * given an arbitrary frequency input clock.
*/ staticint ni_mseries_get_pll_parameters(unsignedint reference_period_ns, unsignedint *freq_divider, unsignedint *freq_multiplier, unsignedint *actual_period_ns)
{ unsignedint div; unsignedint best_div = 1; unsignedint mult; unsignedint best_mult = 1; staticconstunsignedint pico_per_nano = 1000; constunsignedint reference_picosec = reference_period_ns *
pico_per_nano; /* * m-series wants the phased-locked loop to output 80MHz, which is * divided by 4 to 20 MHz for most timing clocks
*/ staticconstunsignedint target_picosec = 12500; int best_period_picosec = 0;
for (div = 1; div <= NI_M_PLL_MAX_DIVISOR; ++div) { for (mult = 1; mult <= NI_M_PLL_MAX_MULTIPLIER; ++mult) { unsignedint new_period_ps =
(reference_picosec * div) / mult; if (abs(new_period_ps - target_picosec) <
abs(best_period_picosec - target_picosec)) {
best_period_picosec = new_period_ps;
best_div = div;
best_mult = mult;
}
}
} if (best_period_picosec == 0) return -EIO;
*freq_divider = best_div;
*freq_multiplier = best_mult; /* return the actual period (* fudge factor for 80 to 20 MHz) */
*actual_period_ns = DIV_ROUND_CLOSEST(best_period_picosec * 4,
pico_per_nano); return 0;
}
ni_writew(dev, pll_control_bits, NI_M_PLL_CTRL_REG);
devpriv->clock_source = source; /* it takes a few hundred microseconds for PLL to lock */ for (i = 0; i < timeout; ++i) { if (ni_readw(dev, NI_M_PLL_STATUS_REG) & NI_M_PLL_STATUS_LOCKED) break;
udelay(1);
} if (i == timeout) {
dev_err(dev->class_dev, "%s: timed out waiting for PLL to lock to reference clock source %i with period %i ns\n",
__func__, source, period_ns); return -ETIMEDOUT;
} return 3;
}
if (chan >= NISTC_RTSI_TRIG_NUM_CHAN(devpriv->is_m_series)) { if (chan == NISTC_RTSI_TRIG_OLD_CLK_CHAN) { if (source == NI_RTSI_OUTPUT_RTSI_OSC) return 1;
dev_err(dev->class_dev, "%s: invalid source for channel=%i, channel %i is always the RTSI clock for pre-m-series boards\n",
__func__, chan, NISTC_RTSI_TRIG_OLD_CLK_CHAN); return 0;
} return 0;
} switch (source) { case NI_RTSI_OUTPUT_ADR_START1: case NI_RTSI_OUTPUT_ADR_START2: case NI_RTSI_OUTPUT_SCLKG: case NI_RTSI_OUTPUT_DACUPDN: case NI_RTSI_OUTPUT_DA_START1: case NI_RTSI_OUTPUT_G_SRC0: case NI_RTSI_OUTPUT_G_GATE0: case NI_RTSI_OUTPUT_RGOUT0: case NI_RTSI_OUTPUT_RTSI_BRD(0): case NI_RTSI_OUTPUT_RTSI_BRD(1): case NI_RTSI_OUTPUT_RTSI_BRD(2): case NI_RTSI_OUTPUT_RTSI_BRD(3): return 1; case NI_RTSI_OUTPUT_RTSI_OSC: return (devpriv->is_m_series) ? 1 : 0; default: return 0;
}
}
switch (data[0]) { case COMEDI_OUTPUT: case COMEDI_INPUT:
ni_set_rtsi_direction(dev, chan, data[0]); break; case INSN_CONFIG_DIO_QUERY: { int ret = ni_get_rtsi_direction(dev, chan);
if (ret < 0) return ret;
data[1] = ret; return 2;
} case INSN_CONFIG_SET_CLOCK_SRC: return ni_set_master_clock(dev, data[1], data[2]); case INSN_CONFIG_GET_CLOCK_SRC:
data[1] = devpriv->clock_source;
data[2] = devpriv->clock_ns; return 3; case INSN_CONFIG_SET_ROUTING: return ni_set_rtsi_routing(dev, chan, data[1]); case INSN_CONFIG_GET_ROUTING: { int ret = ni_get_rtsi_routing(dev, chan);
/* * Default routing for RTSI trigger lines. * * These values are used here in the init function, as well as in the * disconnect_route function, after a RTSI route has been disconnected.
*/ staticconstint default_rtsi_routing[] = {
[0] = NI_RTSI_OUTPUT_ADR_START1,
[1] = NI_RTSI_OUTPUT_ADR_START2,
[2] = NI_RTSI_OUTPUT_SCLKG,
[3] = NI_RTSI_OUTPUT_DACUPDN,
[4] = NI_RTSI_OUTPUT_DA_START1,
[5] = NI_RTSI_OUTPUT_G_SRC0,
[6] = NI_RTSI_OUTPUT_G_GATE0,
[7] = NI_RTSI_OUTPUT_RTSI_OSC,
};
/* * Route signals through RGOUT0 terminal. * @reg: raw register value of RGOUT0 bits (only bit0 is important). * @dev: comedi device handle.
*/ staticvoid set_rgout0_reg(int reg, struct comedi_device *dev)
{ struct ni_private *devpriv = dev->private;
/* * Route signals through RGOUT0 terminal and increment the RGOUT0 use for this * particular route. * @src: device-global signal name * @dev: comedi device handle * * Return: -EINVAL if the source is not valid to route to RGOUT0; * -EBUSY if the RGOUT0 is already used; * 0 if successful.
*/ staticint incr_rgout0_src_use(int src, struct comedi_device *dev)
{ struct ni_private *devpriv = dev->private;
s8 reg = ni_lookup_route_register(CR_CHAN(src), NI_RGOUT0,
&devpriv->routing_tables);
if (reg < 0) return -EINVAL;
if (devpriv->rgout0_usage > 0 && get_rgout0_reg(dev) != reg) return -EBUSY;
/* * Unroute signals through RGOUT0 terminal and deccrement the RGOUT0 use for * this particular source. This function does not actually unroute anything * with respect to RGOUT0. It does, on the other hand, decrement the usage * counter for the current src->RGOUT0 mapping. * * Return: -EINVAL if the source is not already routed to RGOUT0 (or usage is * already at zero); 0 if successful.
*/ staticint decr_rgout0_src_use(int src, struct comedi_device *dev)
{ struct ni_private *devpriv = dev->private;
s8 reg = ni_lookup_route_register(CR_CHAN(src), NI_RGOUT0,
&devpriv->routing_tables);
if (devpriv->rgout0_usage > 0 && get_rgout0_reg(dev) == reg) {
--devpriv->rgout0_usage; if (!devpriv->rgout0_usage)
set_rgout0_reg(0, dev); /* ok default? */ return 0;
} return -EINVAL;
}
/* * Route signals through given NI_RTSI_BRD mux. * @i: index of mux to route * @reg: raw register value of RTSI_BRD bits * @dev: comedi device handle
*/ staticvoid set_ith_rtsi_brd_reg(int i, int reg, struct comedi_device *dev)
{ struct ni_private *devpriv = dev->private; int reg_i_sz = 3; /* value for e-series */ int reg_i_mask; int reg_i_shift;
if (devpriv->is_m_series)
reg_i_sz = 4;
reg_i_mask = ~((~0) << reg_i_sz);
reg_i_shift = i * reg_i_sz;
/* clear out the current reg_i for ith brd */
devpriv->rtsi_shared_mux_reg &= ~(reg_i_mask << reg_i_shift); /* (softcopy) write the new reg_i for ith brd */
devpriv->rtsi_shared_mux_reg |= (reg & reg_i_mask) << reg_i_shift; /* (hardcopy) write the new reg_i for ith brd */
ni_stc_writew(dev, devpriv->rtsi_shared_mux_reg, NISTC_RTSI_BOARD_REG);
}
staticint get_ith_rtsi_brd_reg(int i, struct comedi_device *dev)
{ struct ni_private *devpriv = dev->private; int reg_i_sz = 3; /* value for e-series */ int reg_i_mask; int reg_i_shift;
if (devpriv->is_m_series)
reg_i_sz = 4;
reg_i_mask = ~((~0) << reg_i_sz);
reg_i_shift = i * reg_i_sz;
/* * Route signals through NI_RTSI_BRD mux and increment the use counter for this * particular route. * * Return: -EINVAL if the source is not valid to route to NI_RTSI_BRD(i); * -EBUSY if all NI_RTSI_BRD muxes are already used; * NI_RTSI_BRD(i) of allocated ith mux if successful.
*/ staticint incr_rtsi_brd_src_use(int src, struct comedi_device *dev)
{ struct ni_private *devpriv = dev->private; int first_available = -1; int err = -EINVAL;
s8 reg; int i;
/* first look for a mux that is already configured to provide src */ for (i = 0; i < NUM_RTSI_SHARED_MUXS; ++i) {
reg = ni_lookup_route_register(CR_CHAN(src), NI_RTSI_BRD(i),
&devpriv->routing_tables);
if (reg < 0) continue; /* invalid route */
if (!devpriv->rtsi_shared_mux_usage[i]) { if (first_available < 0) /* found the first unused, but usable mux */
first_available = i;
} else { /* * we've seen at least one possible route, so change the * final error to -EBUSY in case there are no muxes * available.
*/
err = -EBUSY;
if (get_ith_rtsi_brd_reg(i, dev) == reg) { /* * we've found a mux that is already being used * to provide the requested signal. Reuse it.
*/ goto success;
}
}
}
if (first_available < 0) return err;
/* we did not find a mux to reuse, but there is at least one usable */
i = first_available;
/* * Unroute signals through NI_RTSI_BRD mux and decrement the user counter for * this particular route. * * Return: -EINVAL if the source is not already routed to rtsi_brd(i) (or usage * is already at zero); 0 if successful.
*/ staticint decr_rtsi_brd_src_use(int src, int rtsi_brd, struct comedi_device *dev)
{ struct ni_private *devpriv = dev->private;
s8 reg = ni_lookup_route_register(CR_CHAN(src), rtsi_brd,
&devpriv->routing_tables); constint i = rtsi_brd - NI_RTSI_BRD(0);
if (devpriv->rtsi_shared_mux_usage[i] > 0 &&
get_ith_rtsi_brd_reg(i, dev) == reg) {
--devpriv->rtsi_shared_mux_usage[i]; if (!devpriv->rtsi_shared_mux_usage[i])
set_ith_rtsi_brd_reg(i, 0, dev); /* ok default? */ return 0;
}
/* Initialises the RTSI bus signal switch to a default state */
/* * Use 10MHz instead of 20MHz for RTSI clock frequency. Appears * to have no effect, at least on pxi-6281, which always uses * 20MHz rtsi clock frequency
*/
devpriv->clock_and_fout2 = NI_M_CLK_FOUT2_RTSI_10MHZ; /* Set clock mode to internal */ if (ni_set_master_clock(dev, NI_MIO_INTERNAL_CLOCK, 0) < 0)
dev_err(dev->class_dev, "ni_set_master_clock failed, bug?\n");
/* default internal lines routing to RTSI bus lines */ for (i = 0; i < 8; ++i) {
ni_set_rtsi_direction(dev, i, COMEDI_INPUT);
ni_set_rtsi_routing(dev, i, default_rtsi_routing[i]);
}
/* * Sets the source and direction of the 4 on board lines. * This configures all board lines to be: * for e-series: * 1) inputs (not sure what "output" would mean) * 2) copying TRIGGER_LINE(0) (or RTSI0) output * for m-series: * copying NI_PFI(0) output
*/
devpriv->rtsi_shared_mux_reg = 0; for (i = 0; i < 4; ++i)
set_ith_rtsi_brd_reg(i, 0, dev);
memset(devpriv->rtsi_shared_mux_usage, 0, sizeof(devpriv->rtsi_shared_mux_usage));
/* * Retrieves the current source of the output selector for the given * destination. If the terminal for the destination is not already configured * as an output, this function returns -EINVAL as error. * * Return: the register value of the destination output selector; * -EINVAL if terminal is not configured for output.
*/ staticint get_output_select_source(int dest, struct comedi_device *dev)
{ struct ni_private *devpriv = dev->private; int reg = -1;
if (channel_is_pfi(dest)) { if (ni_get_pfi_direction(dev, dest) == COMEDI_OUTPUT)
reg = ni_get_pfi_routing(dev, dest);
} elseif (channel_is_rtsi(dest)) { if (ni_get_rtsi_direction(dev, dest) == COMEDI_OUTPUT) {
reg = ni_get_rtsi_routing(dev, dest);
if (reg == NI_RTSI_OUTPUT_RGOUT0) {
dest = NI_RGOUT0; /* prepare for lookup below */
reg = get_rgout0_reg(dev);
} elseif (reg >= NI_RTSI_OUTPUT_RTSI_BRD(0) &&
reg <= NI_RTSI_OUTPUT_RTSI_BRD(3)) { constint i = reg - NI_RTSI_OUTPUT_RTSI_BRD(0);
dest = NI_RTSI_BRD(i); /* prepare for lookup */
reg = get_ith_rtsi_brd_reg(i, dev);
}
}
} elseif (dest >= NI_CtrOut(0) && dest <= NI_CtrOut(-1)) { /* * not handled by ni_tio. Only available for GPFO registers in * e/m series.
*/
dest -= NI_CtrOut(0); if (dest > 1) /* there are only two g_out outputs. */ return -EINVAL;
reg = ni_get_gout_routing(dest, dev);
} elseif (channel_is_ctr(dest)) {
reg = ni_tio_get_routing(devpriv->counter_dev, dest);
} else {
dev_dbg(dev->class_dev, "%s: unhandled destination (%d) queried\n",
__func__, dest);
}
if (reg < 0) /* route is not valid */ return -EINVAL;
current_src = get_output_select_source(dest, dev); if (current_src == CR_CHAN(src)) return -EALREADY; if (current_src >= 0) /* destination mux is already busy. complain, don't overwrite */ return -EBUSY;
/* The route is valid and available. Now connect... */ if (channel_is_pfi(dest)) { /* set routing source, then open output */
ni_set_pfi_routing(dev, dest, reg);
ni_set_pfi_direction(dev, dest, COMEDI_OUTPUT);
} elseif (channel_is_rtsi(dest)) { if (reg == NI_RTSI_OUTPUT_RGOUT0) { int ret = incr_rgout0_src_use(src, dev);
if (ret < 0) return ret;
} elseif (ni_rtsi_route_requires_mux(reg)) { /* Attempt to allocate and route (src->brd) */ int brd = incr_rtsi_brd_src_use(src, dev);
if (brd < 0) return brd;
/* Now lookup the register value for (brd->dest) */
reg = ni_lookup_route_register(
brd, dest, &devpriv->routing_tables);
}
ni_set_rtsi_direction(dev, dest, COMEDI_OUTPUT);
ni_set_rtsi_routing(dev, dest, reg);
} elseif (dest >= NI_CtrOut(0) && dest <= NI_CtrOut(-1)) { /* * not handled by ni_tio. Only available for GPFO registers in * e/m series.
*/
dest -= NI_CtrOut(0); if (dest > 1) /* there are only two g_out outputs. */ return -EINVAL; if (ni_set_gout_routing(src, dest, dev)) return -EINVAL;
} elseif (channel_is_ctr(dest)) { /* * we are adding back the channel modifier info to set * invert/edge info passed by the user
*/
ni_tio_set_routing(devpriv->counter_dev, dest,
reg | (src & ~CR_CHAN(-1)));
} else { return -EINVAL;
} return 0;
}
if (reg < 0) /* route is not valid */ return -EINVAL; if (get_output_select_source(dest, dev) != src) /* cannot disconnect something not connected */ return -EINVAL;
/* The route is valid and is connected. Now disconnect... */ if (channel_is_pfi(dest)) { /* set the pfi to high impedance, and disconnect */
ni_set_pfi_direction(dev, dest, COMEDI_INPUT);
ni_set_pfi_routing(dev, dest, NI_PFI_OUTPUT_PFI_DEFAULT);
} elseif (channel_is_rtsi(dest)) { if (reg == NI_RTSI_OUTPUT_RGOUT0) { int ret = decr_rgout0_src_use(src, dev);
if (ret < 0) return ret;
} elseif (ni_rtsi_route_requires_mux(reg)) { /* find which RTSI_BRD line is source for rtsi pin */ int brd = ni_find_route_source(
ni_get_rtsi_routing(dev, dest), dest,
&devpriv->routing_tables);
if (brd < 0) return brd;
/* decrement/disconnect RTSI_BRD line from source */
decr_rtsi_brd_src_use(src, brd, dev);
}
/* set rtsi output selector to default state */
reg = default_rtsi_routing[dest - TRIGGER_LINE(0)];
ni_set_rtsi_direction(dev, dest, COMEDI_INPUT);
ni_set_rtsi_routing(dev, dest, reg);
} elseif (dest >= NI_CtrOut(0) && dest <= NI_CtrOut(-1)) { /* * not handled by ni_tio. Only available for GPFO registers in * e/m series.
*/
dest -= NI_CtrOut(0); if (dest > 1) /* there are only two g_out outputs. */ return -EINVAL;
reg = ni_disable_gout_routing(dest, dev);
} elseif (channel_is_ctr(dest)) {
ni_tio_unset_routing(devpriv->counter_dev, dest);
} else { return -EINVAL;
} return 0;
}
staticint ni_global_insn_config(struct comedi_device *dev, struct comedi_insn *insn, unsignedint *data)
{ switch (data[0]) { case INSN_DEVICE_CONFIG_TEST_ROUTE:
data[0] = test_route(data[1], data[2], dev); return 2; case INSN_DEVICE_CONFIG_CONNECT_ROUTE: return connect_route(data[1], data[2], dev); case INSN_DEVICE_CONFIG_DISCONNECT_ROUTE: return disconnect_route(data[1], data[2], dev); /* * This case is already handled one level up. * case INSN_DEVICE_CONFIG_GET_ROUTES:
*/ default: return -EINVAL;
} return 1;
}
retval = ni_request_gpct_mite_channel(dev, counter->counter_index,
COMEDI_INPUT); if (retval) {
dev_err(dev->class_dev, "no dma channel available for use by counter\n"); return retval;
}
ni_tio_acknowledge(counter);
ni_e_series_enable_second_irq(dev, counter->counter_index, 1);
/* prepare the device for globally-named routes. */ if (ni_assign_device_routes(dev_family, board->name,
board->alt_route_name,
&devpriv->routing_tables) < 0) {
dev_warn(dev->class_dev, "%s: %s device has no signal routing table.\n",
__func__, board->name);
dev_warn(dev->class_dev, "%s: High level NI signal names will not be available for this %s board.\n",
__func__, board->name);
} else { /* * only(?) assign insn_device_config if we have global names for * this device.
*/
dev->insn_device_config = ni_global_insn_config;
dev->get_valid_routes = _ni_get_valid_routes;
}
ret = comedi_alloc_subdev_readback(s); if (ret) return ret;
/* * Along with the IRQ we need either a FIFO or DMA for * async command support.
*/ if (dev->irq && (board->ao_fifo_depth || devpriv->mite)) {
dev->write_subdev = s;
s->subdev_flags |= SDF_CMD_WRITE;
s->len_chanlist = s->n_chan;
s->do_cmdtest = ni_ao_cmdtest;
s->do_cmd = ni_ao_cmd;
s->cancel = ni_ao_reset; if (!devpriv->is_m_series)
s->munge = ni_ao_munge;
if (devpriv->mite)
s->async_dma_dir = DMA_TO_DEVICE;
}
if (devpriv->is_67xx)
init_ao_67xx(dev, s);
/* reset the analog output configuration */
ni_ao_reset(dev, s);
} else {
s->type = COMEDI_SUBD_UNUSED;
}
if (devpriv)
ni_gpct_device_destroy(devpriv->counter_dev);
}
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.103Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-04-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.