staging: comedi: ni_mio_common: Cleans up/clarifies ni_ao_cmd
This patch implements ni_ao_cmd much more closely organized like NI MHDDK examples and DAQ-STC pseudo-code. Adds comments with some more specific references to the DAQ-STC. For stop_src==TRIG_NONE (continuous output mode of entire buffer), the count for the UC counter was corrected to represent the maximum count possible (0xffffff). Prior behavior for stop_src=TRIG_NONE did not actually follow the DAQ-STC. Furthermore, stop_src==TRIG_NONE now correctly uses code specialized for either m-series or e-series devices. It should be noted that stop_src==TRIG_NONE does _not_ with this patch (or with prior behavior in ni_mio_common) actually implement true continuous output. Rather, the output is simply configured to operate as a single buffer output, but where the buffer is as large as is possible with NI-STC hardware. Signed-off-by: Spencer E. Olson <olsonse@umich.edu> Reviewed-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
d2a6c32a22
Коммит
080e6795cb
|
@ -2912,42 +2912,68 @@ static int ni_ao_inttrig(struct comedi_device *dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
/*
|
||||||
|
* begin ni_ao_cmd.
|
||||||
|
* Organized similar to NI-STC and MHDDK examples.
|
||||||
|
* ni_ao_cmd is broken out into configuration sub-routines for clarity.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void ni_ao_cmd_personalize(struct comedi_device *dev,
|
||||||
|
const struct comedi_cmd *cmd)
|
||||||
{
|
{
|
||||||
const struct ni_board_struct *board = dev->board_ptr;
|
const struct ni_board_struct *board = dev->board_ptr;
|
||||||
struct ni_private *devpriv = dev->private;
|
unsigned bits;
|
||||||
const struct comedi_cmd *cmd = &s->async->cmd;
|
|
||||||
int bits;
|
|
||||||
int i;
|
|
||||||
unsigned trigvar;
|
|
||||||
unsigned val;
|
|
||||||
|
|
||||||
if (dev->irq == 0) {
|
|
||||||
dev_err(dev->class_dev, "cannot run command without an irq\n");
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
ni_stc_writew(dev, NISTC_RESET_AO_CFG_START, NISTC_RESET_REG);
|
ni_stc_writew(dev, NISTC_RESET_AO_CFG_START, NISTC_RESET_REG);
|
||||||
|
|
||||||
ni_stc_writew(dev, NISTC_AO_CMD1_DISARM, NISTC_AO_CMD1_REG);
|
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...
|
||||||
|
*/
|
||||||
|
|
||||||
if (devpriv->is_6xxx) {
|
/*
|
||||||
ni_ao_win_outw(dev, NI611X_AO_MISC_CLEAR_WG,
|
* F Hess: windows driver does not set NISTC_AO_PERSONAL_NUM_DAC bit for
|
||||||
NI611X_AO_MISC_REG);
|
* 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);
|
||||||
|
|
||||||
bits = 0;
|
ni_stc_writew(dev, NISTC_RESET_AO_CFG_END, NISTC_RESET_REG);
|
||||||
for (i = 0; i < cmd->chanlist_len; i++) {
|
}
|
||||||
int chan;
|
|
||||||
|
|
||||||
chan = CR_CHAN(cmd->chanlist[i]);
|
static void ni_ao_cmd_set_trigger(struct comedi_device *dev,
|
||||||
bits |= 1 << chan;
|
const struct comedi_cmd *cmd)
|
||||||
ni_ao_win_outw(dev, chan, NI611X_AO_WAVEFORM_GEN_REG);
|
{
|
||||||
}
|
struct ni_private *devpriv = dev->private;
|
||||||
ni_ao_win_outw(dev, bits, NI611X_AO_TIMED_REG);
|
|
||||||
}
|
|
||||||
|
|
||||||
ni_ao_config_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len, 1);
|
ni_stc_writew(dev, NISTC_RESET_AO_CFG_START, NISTC_RESET_REG);
|
||||||
|
|
||||||
|
/* sync */
|
||||||
if (cmd->stop_src == TRIG_NONE) {
|
if (cmd->stop_src == TRIG_NONE) {
|
||||||
devpriv->ao_mode1 |= NISTC_AO_MODE1_CONTINUOUS;
|
devpriv->ao_mode1 |= NISTC_AO_MODE1_CONTINUOUS;
|
||||||
devpriv->ao_mode1 &= ~NISTC_AO_MODE1_TRIGGER_ONCE;
|
devpriv->ao_mode1 &= ~NISTC_AO_MODE1_TRIGGER_ONCE;
|
||||||
|
@ -2957,179 +2983,346 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||||
}
|
}
|
||||||
ni_stc_writew(dev, devpriv->ao_mode1, NISTC_AO_MODE1_REG);
|
ni_stc_writew(dev, devpriv->ao_mode1, NISTC_AO_MODE1_REG);
|
||||||
|
|
||||||
val = devpriv->ao_trigger_select;
|
{
|
||||||
switch (cmd->start_src) {
|
unsigned int trigsel = devpriv->ao_trigger_select;
|
||||||
case TRIG_INT:
|
|
||||||
case TRIG_NOW:
|
switch (cmd->start_src) {
|
||||||
val &= ~(NISTC_AO_TRIG_START1_POLARITY |
|
case TRIG_INT:
|
||||||
NISTC_AO_TRIG_START1_SEL_MASK);
|
case TRIG_NOW:
|
||||||
val |= NISTC_AO_TRIG_START1_EDGE |
|
trigsel &= ~(NISTC_AO_TRIG_START1_POLARITY |
|
||||||
NISTC_AO_TRIG_START1_SYNC;
|
NISTC_AO_TRIG_START1_SEL_MASK);
|
||||||
break;
|
trigsel |= NISTC_AO_TRIG_START1_EDGE |
|
||||||
case TRIG_EXT:
|
NISTC_AO_TRIG_START1_SYNC;
|
||||||
val = NISTC_AO_TRIG_START1_SEL(CR_CHAN(cmd->start_arg) + 1);
|
break;
|
||||||
if (cmd->start_arg & CR_INVERT) {
|
case TRIG_EXT:
|
||||||
/* 0=active high, 1=active low. see daq-stc 3-24 (p186) */
|
trigsel = NISTC_AO_TRIG_START1_SEL(
|
||||||
val |= NISTC_AO_TRIG_START1_POLARITY;
|
CR_CHAN(cmd->start_arg) + 1);
|
||||||
}
|
if (cmd->start_arg & CR_INVERT)
|
||||||
if (cmd->start_arg & CR_EDGE) {
|
/*
|
||||||
/* 0=edge detection disabled, 1=enabled */
|
* 0=active high, 1=active low.
|
||||||
val |= NISTC_AO_TRIG_START1_EDGE;
|
* see daq-stc 3-24 (p186)
|
||||||
|
*/
|
||||||
|
trigsel |= NISTC_AO_TRIG_START1_POLARITY;
|
||||||
|
if (cmd->start_arg & CR_EDGE)
|
||||||
|
/* 0=edge detection disabled, 1=enabled */
|
||||||
|
trigsel |= NISTC_AO_TRIG_START1_EDGE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
devpriv->ao_trigger_select = trigsel;
|
||||||
ni_stc_writew(dev, devpriv->ao_trigger_select,
|
ni_stc_writew(dev, devpriv->ao_trigger_select,
|
||||||
NISTC_AO_TRIG_SEL_REG);
|
NISTC_AO_TRIG_SEL_REG);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BUG();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
devpriv->ao_trigger_select = val;
|
/* AO_Delayed_START1 = 0, we do not support delayed start...yet */
|
||||||
ni_stc_writew(dev, devpriv->ao_trigger_select, NISTC_AO_TRIG_SEL_REG);
|
|
||||||
|
|
||||||
|
/* sync */
|
||||||
|
/* select DA_START1 as PFI6/AO_START1 when configured as an output */
|
||||||
devpriv->ao_mode3 &= ~NISTC_AO_MODE3_TRIG_LEN;
|
devpriv->ao_mode3 &= ~NISTC_AO_MODE3_TRIG_LEN;
|
||||||
ni_stc_writew(dev, devpriv->ao_mode3, NISTC_AO_MODE3_REG);
|
ni_stc_writew(dev, devpriv->ao_mode3, NISTC_AO_MODE3_REG);
|
||||||
|
|
||||||
|
ni_stc_writew(dev, NISTC_RESET_AO_CFG_END, NISTC_RESET_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ni_ao_cmd_set_counters(struct comedi_device *dev,
|
||||||
|
const struct 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);
|
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;
|
devpriv->ao_mode2 &= ~NISTC_AO_MODE2_BC_INIT_LOAD_SRC;
|
||||||
ni_stc_writew(dev, devpriv->ao_mode2, NISTC_AO_MODE2_REG);
|
ni_stc_writew(dev, devpriv->ao_mode2, NISTC_AO_MODE2_REG);
|
||||||
if (cmd->stop_src == TRIG_NONE)
|
|
||||||
ni_stc_writel(dev, 0xffffff, NISTC_AO_BC_LOADA_REG);
|
/*
|
||||||
else
|
* if the BC_TC interrupt is still issued in spite of UC, BC, UI
|
||||||
ni_stc_writel(dev, 0, NISTC_AO_BC_LOADA_REG);
|
* 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);
|
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;
|
devpriv->ao_mode2 &= ~NISTC_AO_MODE2_UC_INIT_LOAD_SRC;
|
||||||
ni_stc_writew(dev, devpriv->ao_mode2, NISTC_AO_MODE2_REG);
|
ni_stc_writew(dev, devpriv->ao_mode2, NISTC_AO_MODE2_REG);
|
||||||
switch (cmd->stop_src) {
|
|
||||||
case TRIG_COUNT:
|
{
|
||||||
|
/*
|
||||||
|
* Current behavior is to configure the maximum update count
|
||||||
|
* possible when continuous output mode is requested.
|
||||||
|
*/
|
||||||
|
unsigned int stop_arg = cmd->stop_src == TRIG_COUNT ?
|
||||||
|
(cmd->stop_arg & 0xffffff) : 0xffffff;
|
||||||
|
|
||||||
if (devpriv->is_m_series) {
|
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, cmd->stop_arg - 1,
|
* this is how the NI example code does it for m-series
|
||||||
NISTC_AO_UC_LOADA_REG);
|
* 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,
|
ni_stc_writew(dev, NISTC_AO_CMD1_UC_LOAD,
|
||||||
NISTC_AO_CMD1_REG);
|
NISTC_AO_CMD1_REG);
|
||||||
} else {
|
} else {
|
||||||
ni_stc_writel(dev, cmd->stop_arg,
|
ni_stc_writel(dev, stop_arg, NISTC_AO_UC_LOADA_REG);
|
||||||
NISTC_AO_UC_LOADA_REG);
|
|
||||||
|
/* sync (issue cmd to load number of updates in MISB) */
|
||||||
ni_stc_writew(dev, NISTC_AO_CMD1_UC_LOAD,
|
ni_stc_writew(dev, NISTC_AO_CMD1_UC_LOAD,
|
||||||
NISTC_AO_CMD1_REG);
|
NISTC_AO_CMD1_REG);
|
||||||
ni_stc_writel(dev, cmd->stop_arg - 1,
|
|
||||||
NISTC_AO_UC_LOADA_REG);
|
/*
|
||||||
|
* sync (upload number of updates-1 in MISB)
|
||||||
|
* --eseries only?
|
||||||
|
*/
|
||||||
|
ni_stc_writel(dev, stop_arg - 1, NISTC_AO_UC_LOADA_REG);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case TRIG_NONE:
|
|
||||||
ni_stc_writel(dev, 0xffffff, NISTC_AO_UC_LOADA_REG);
|
|
||||||
ni_stc_writew(dev, NISTC_AO_CMD1_UC_LOAD, NISTC_AO_CMD1_REG);
|
|
||||||
ni_stc_writel(dev, 0xffffff, NISTC_AO_UC_LOADA_REG);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ni_stc_writel(dev, 0, NISTC_AO_UC_LOADA_REG);
|
|
||||||
ni_stc_writew(dev, NISTC_AO_CMD1_UC_LOAD, NISTC_AO_CMD1_REG);
|
|
||||||
ni_stc_writel(dev, cmd->stop_arg, NISTC_AO_UC_LOADA_REG);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
devpriv->ao_mode1 &= ~(NISTC_AO_MODE1_UPDATE_SRC_MASK |
|
ni_stc_writew(dev, NISTC_RESET_AO_CFG_END, NISTC_RESET_REG);
|
||||||
NISTC_AO_MODE1_UI_SRC_MASK |
|
}
|
||||||
NISTC_AO_MODE1_UPDATE_SRC_POLARITY |
|
|
||||||
NISTC_AO_MODE1_UI_SRC_POLARITY);
|
static void ni_ao_cmd_set_update(struct comedi_device *dev,
|
||||||
|
const struct comedi_cmd *cmd)
|
||||||
|
{
|
||||||
|
struct ni_private *devpriv = dev->private;
|
||||||
|
|
||||||
|
ni_stc_writew(dev, NISTC_RESET_AO_CFG_START, NISTC_RESET_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
|
||||||
|
);
|
||||||
|
|
||||||
switch (cmd->scan_begin_src) {
|
switch (cmd->scan_begin_src) {
|
||||||
case TRIG_TIMER:
|
case TRIG_TIMER:
|
||||||
devpriv->ao_cmd2 &= ~NISTC_AO_CMD2_BC_GATE_ENA;
|
devpriv->ao_cmd2 &= ~NISTC_AO_CMD2_BC_GATE_ENA;
|
||||||
trigvar =
|
|
||||||
ni_ns_to_timer(dev, cmd->scan_begin_arg,
|
/*
|
||||||
CMDF_ROUND_NEAREST);
|
* NOTE: there are several other ways of configuring internal
|
||||||
ni_stc_writel(dev, 1, NISTC_AO_UI_LOADA_REG);
|
* updates, but we'll only support one for now: using
|
||||||
ni_stc_writew(dev, NISTC_AO_CMD1_UI_LOAD, NISTC_AO_CMD1_REG);
|
* AO_IN_TIMEBASE, w/o waveform staging, w/o a delay between
|
||||||
ni_stc_writel(dev, trigvar, NISTC_AO_UI_LOADA_REG);
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
{
|
||||||
|
unsigned trigvar = ni_ns_to_timer(dev,
|
||||||
|
cmd->scan_begin_arg,
|
||||||
|
CMDF_ROUND_NEAREST);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait N TB3 ticks after the start trigger before
|
||||||
|
* clocking(N must be >=2).
|
||||||
|
*/
|
||||||
|
/* following line: 2-1 per STC */
|
||||||
|
ni_stc_writel(dev, 1, NISTC_AO_UI_LOADA_REG);
|
||||||
|
ni_stc_writew(dev, NISTC_AO_CMD1_UI_LOAD,
|
||||||
|
NISTC_AO_CMD1_REG);
|
||||||
|
/* following line: N-1 per STC */
|
||||||
|
ni_stc_writel(dev, trigvar - 1, NISTC_AO_UI_LOADA_REG);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case TRIG_EXT:
|
case TRIG_EXT:
|
||||||
devpriv->ao_mode1 |=
|
/* FIXME: assert scan_begin_arg != 0, ret failure otherwise */
|
||||||
NISTC_AO_MODE1_UPDATE_SRC(cmd->scan_begin_arg);
|
devpriv->ao_cmd2 |= NISTC_AO_CMD2_BC_GATE_ENA;
|
||||||
|
devpriv->ao_mode1 |= NISTC_AO_MODE1_UPDATE_SRC(
|
||||||
|
CR_CHAN(cmd->scan_begin_arg));
|
||||||
if (cmd->scan_begin_arg & CR_INVERT)
|
if (cmd->scan_begin_arg & CR_INVERT)
|
||||||
devpriv->ao_mode1 |= NISTC_AO_MODE1_UPDATE_SRC_POLARITY;
|
devpriv->ao_mode1 |= NISTC_AO_MODE1_UPDATE_SRC_POLARITY;
|
||||||
devpriv->ao_cmd2 |= NISTC_AO_CMD2_BC_GATE_ENA;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BUG();
|
BUG();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ni_stc_writew(dev, devpriv->ao_cmd2, NISTC_AO_CMD2_REG);
|
ni_stc_writew(dev, devpriv->ao_cmd2, NISTC_AO_CMD2_REG);
|
||||||
ni_stc_writew(dev, devpriv->ao_mode1, NISTC_AO_MODE1_REG);
|
ni_stc_writew(dev, devpriv->ao_mode1, NISTC_AO_MODE1_REG);
|
||||||
devpriv->ao_mode2 &= ~(NISTC_AO_MODE2_UI_RELOAD_MODE(3) |
|
devpriv->ao_mode2 &= ~(NISTC_AO_MODE2_UI_RELOAD_MODE(3) |
|
||||||
NISTC_AO_MODE2_UI_INIT_LOAD_SRC);
|
NISTC_AO_MODE2_UI_INIT_LOAD_SRC);
|
||||||
ni_stc_writew(dev, devpriv->ao_mode2, NISTC_AO_MODE2_REG);
|
ni_stc_writew(dev, devpriv->ao_mode2, NISTC_AO_MODE2_REG);
|
||||||
|
|
||||||
if (cmd->scan_end_arg > 1) {
|
|
||||||
devpriv->ao_mode1 |= NISTC_AO_MODE1_MULTI_CHAN;
|
|
||||||
ni_stc_writew(dev,
|
|
||||||
NISTC_AO_OUT_CTRL_CHANS(cmd->scan_end_arg - 1) |
|
|
||||||
NISTC_AO_OUT_CTRL_UPDATE_SEL_HIGHZ,
|
|
||||||
NISTC_AO_OUT_CTRL_REG);
|
|
||||||
} else {
|
|
||||||
unsigned bits;
|
|
||||||
|
|
||||||
devpriv->ao_mode1 &= ~NISTC_AO_MODE1_MULTI_CHAN;
|
|
||||||
bits = NISTC_AO_OUT_CTRL_UPDATE_SEL_HIGHZ;
|
|
||||||
if (devpriv->is_m_series || devpriv->is_6xxx) {
|
|
||||||
bits |= NISTC_AO_OUT_CTRL_CHANS(0);
|
|
||||||
} else {
|
|
||||||
bits |=
|
|
||||||
NISTC_AO_OUT_CTRL_CHANS(CR_CHAN(cmd->chanlist[0]));
|
|
||||||
}
|
|
||||||
ni_stc_writew(dev, bits, NISTC_AO_OUT_CTRL_REG);
|
|
||||||
}
|
|
||||||
ni_stc_writew(dev, devpriv->ao_mode1, NISTC_AO_MODE1_REG);
|
|
||||||
|
|
||||||
/* Configure DAQ-STC for Timed update mode */
|
/* Configure DAQ-STC for Timed update mode */
|
||||||
devpriv->ao_cmd1 |= NISTC_AO_CMD1_DAC1_UPDATE_MODE |
|
devpriv->ao_cmd1 |= NISTC_AO_CMD1_DAC1_UPDATE_MODE |
|
||||||
NISTC_AO_CMD1_DAC0_UPDATE_MODE;
|
NISTC_AO_CMD1_DAC0_UPDATE_MODE;
|
||||||
/* We are not using UPDATE2-->don't have to set DACx_Source_Select */
|
/* We are not using UPDATE2-->don't have to set DACx_Source_Select */
|
||||||
ni_stc_writew(dev, devpriv->ao_cmd1, NISTC_AO_CMD1_REG);
|
ni_stc_writew(dev, devpriv->ao_cmd1, NISTC_AO_CMD1_REG);
|
||||||
|
|
||||||
|
ni_stc_writew(dev, NISTC_RESET_AO_CFG_END, NISTC_RESET_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ni_ao_cmd_set_channels(struct comedi_device *dev,
|
||||||
|
struct comedi_subdevice *s)
|
||||||
|
{
|
||||||
|
struct ni_private *devpriv = dev->private;
|
||||||
|
const struct comedi_cmd *cmd = &s->async->cmd;
|
||||||
|
unsigned bits = 0;
|
||||||
|
|
||||||
|
ni_stc_writew(dev, NISTC_RESET_AO_CFG_START, NISTC_RESET_REG);
|
||||||
|
|
||||||
|
if (devpriv->is_6xxx) {
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
bits = 0;
|
||||||
|
for (i = 0; i < cmd->chanlist_len; ++i) {
|
||||||
|
int chan = CR_CHAN(cmd->chanlist[i]);
|
||||||
|
|
||||||
|
bits |= 1 << chan;
|
||||||
|
ni_ao_win_outw(dev, chan, NI611X_AO_WAVEFORM_GEN_REG);
|
||||||
|
}
|
||||||
|
ni_ao_win_outw(dev, bits, NI611X_AO_TIMED_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
ni_ao_config_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len, 1);
|
||||||
|
|
||||||
|
if (cmd->scan_end_arg > 1) {
|
||||||
|
devpriv->ao_mode1 |= NISTC_AO_MODE1_MULTI_CHAN;
|
||||||
|
bits = NISTC_AO_OUT_CTRL_CHANS(cmd->scan_end_arg - 1)
|
||||||
|
| NISTC_AO_OUT_CTRL_UPDATE_SEL_HIGHZ;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
devpriv->ao_mode1 &= ~NISTC_AO_MODE1_MULTI_CHAN;
|
||||||
|
bits = NISTC_AO_OUT_CTRL_UPDATE_SEL_HIGHZ;
|
||||||
|
if (devpriv->is_m_series | devpriv->is_6xxx)
|
||||||
|
bits |= NISTC_AO_OUT_CTRL_CHANS(0);
|
||||||
|
else
|
||||||
|
bits |= NISTC_AO_OUT_CTRL_CHANS(
|
||||||
|
CR_CHAN(cmd->chanlist[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
ni_stc_writew(dev, devpriv->ao_mode1, NISTC_AO_MODE1_REG);
|
||||||
|
ni_stc_writew(dev, bits, NISTC_AO_OUT_CTRL_REG);
|
||||||
|
|
||||||
|
ni_stc_writew(dev, NISTC_RESET_AO_CFG_END, NISTC_RESET_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ni_ao_cmd_set_stop_conditions(struct comedi_device *dev,
|
||||||
|
const struct comedi_cmd *cmd)
|
||||||
|
{
|
||||||
|
struct ni_private *devpriv = dev->private;
|
||||||
|
|
||||||
|
ni_stc_writew(dev, NISTC_RESET_AO_CFG_START, NISTC_RESET_REG);
|
||||||
|
|
||||||
devpriv->ao_mode3 |= NISTC_AO_MODE3_STOP_ON_OVERRUN_ERR;
|
devpriv->ao_mode3 |= NISTC_AO_MODE3_STOP_ON_OVERRUN_ERR;
|
||||||
ni_stc_writew(dev, devpriv->ao_mode3, NISTC_AO_MODE3_REG);
|
ni_stc_writew(dev, devpriv->ao_mode3, NISTC_AO_MODE3_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
|
||||||
|
*/
|
||||||
|
|
||||||
|
ni_stc_writew(dev, NISTC_RESET_AO_CFG_END, NISTC_RESET_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ni_ao_cmd_set_fifo_mode(struct comedi_device *dev)
|
||||||
|
{
|
||||||
|
struct ni_private *devpriv = dev->private;
|
||||||
|
|
||||||
|
ni_stc_writew(dev, NISTC_RESET_AO_CFG_START, NISTC_RESET_REG);
|
||||||
|
|
||||||
devpriv->ao_mode2 &= ~NISTC_AO_MODE2_FIFO_MODE_MASK;
|
devpriv->ao_mode2 &= ~NISTC_AO_MODE2_FIFO_MODE_MASK;
|
||||||
#ifdef PCIDMA
|
#ifdef PCIDMA
|
||||||
devpriv->ao_mode2 |= NISTC_AO_MODE2_FIFO_MODE_HF_F;
|
devpriv->ao_mode2 |= NISTC_AO_MODE2_FIFO_MODE_HF_F;
|
||||||
#else
|
#else
|
||||||
devpriv->ao_mode2 |= NISTC_AO_MODE2_FIFO_MODE_HF;
|
devpriv->ao_mode2 |= NISTC_AO_MODE2_FIFO_MODE_HF;
|
||||||
#endif
|
#endif
|
||||||
|
/* NOTE: this is where use_onboard_memory=True would be implemented */
|
||||||
devpriv->ao_mode2 &= ~NISTC_AO_MODE2_FIFO_REXMIT_ENA;
|
devpriv->ao_mode2 &= ~NISTC_AO_MODE2_FIFO_REXMIT_ENA;
|
||||||
ni_stc_writew(dev, devpriv->ao_mode2, NISTC_AO_MODE2_REG);
|
ni_stc_writew(dev, devpriv->ao_mode2, NISTC_AO_MODE2_REG);
|
||||||
|
|
||||||
bits = NISTC_AO_PERSONAL_BC_SRC_SEL |
|
/* enable sending of ao fifo requests (dma request) */
|
||||||
NISTC_AO_PERSONAL_UPDATE_PW |
|
|
||||||
NISTC_AO_PERSONAL_TMRDACWR_PW;
|
|
||||||
if (board->ao_fifo_depth)
|
|
||||||
bits |= NISTC_AO_PERSONAL_FIFO_ENA;
|
|
||||||
else
|
|
||||||
bits |= NISTC_AO_PERSONAL_DMA_PIO_CTRL;
|
|
||||||
#if 0
|
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
/* enable sending of ao dma requests */
|
|
||||||
ni_stc_writew(dev, NISTC_AO_START_AOFREQ_ENA, NISTC_AO_START_SEL_REG);
|
ni_stc_writew(dev, NISTC_AO_START_AOFREQ_ENA, NISTC_AO_START_SEL_REG);
|
||||||
|
|
||||||
ni_stc_writew(dev, NISTC_RESET_AO_CFG_END, NISTC_RESET_REG);
|
ni_stc_writew(dev, NISTC_RESET_AO_CFG_END, NISTC_RESET_REG);
|
||||||
|
|
||||||
if (cmd->stop_src == TRIG_COUNT) {
|
/* we are not supporting boards with virtual fifos */
|
||||||
ni_stc_writew(dev, NISTC_INTB_ACK_AO_BC_TC,
|
}
|
||||||
NISTC_INTB_ACK_REG);
|
|
||||||
|
static void ni_ao_cmd_set_interrupts(struct comedi_device *dev,
|
||||||
|
struct comedi_subdevice *s)
|
||||||
|
{
|
||||||
|
if (s->async->cmd.stop_src == TRIG_COUNT)
|
||||||
ni_set_bits(dev, NISTC_INTB_ENA_REG,
|
ni_set_bits(dev, NISTC_INTB_ENA_REG,
|
||||||
NISTC_INTB_ENA_AO_BC_TC, 1);
|
NISTC_INTB_ENA_AO_BC_TC, 1);
|
||||||
}
|
|
||||||
|
|
||||||
s->async->inttrig = ni_ao_inttrig;
|
s->async->inttrig = ni_ao_inttrig;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||||
|
{
|
||||||
|
struct ni_private *devpriv = dev->private;
|
||||||
|
const struct comedi_cmd *cmd = &s->async->cmd;
|
||||||
|
|
||||||
|
if (dev->irq == 0) {
|
||||||
|
dev_err(dev->class_dev, "cannot run command without an irq");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ni_ao_reset should have already been done */
|
||||||
|
ni_ao_cmd_personalize(dev, cmd);
|
||||||
|
/* clearing fifo and preload happens elsewhere */
|
||||||
|
|
||||||
|
ni_ao_cmd_set_trigger(dev, cmd);
|
||||||
|
ni_ao_cmd_set_counters(dev, cmd);
|
||||||
|
ni_ao_cmd_set_update(dev, cmd);
|
||||||
|
ni_ao_cmd_set_channels(dev, s);
|
||||||
|
ni_ao_cmd_set_stop_conditions(dev, cmd);
|
||||||
|
ni_ao_cmd_set_fifo_mode(dev);
|
||||||
|
ni_ao_cmd_set_interrupts(dev, s);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* arm(ing) and star(ting) happen in ni_ao_inttrig, which _must_ be
|
||||||
|
* called for ao commands since 1) TRIG_NOW is not supported and 2) DMA
|
||||||
|
* must be setup and initially written to before arm/start happen.
|
||||||
|
*/
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* end ni_ao_cmd */
|
||||||
|
|
||||||
static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
|
static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
|
||||||
struct comedi_cmd *cmd)
|
struct comedi_cmd *cmd)
|
||||||
{
|
{
|
||||||
|
|
Загрузка…
Ссылка в новой задаче