static int ni_tio_set_clock_src(struct ni_gpct *counter, unsigned int clock_source, unsigned int period_ns) { struct ni_gpct_device *counter_dev = counter->counter_dev; unsigned input_select_bits = 0; static const uint64_t pico_per_nano = 1000; /*FIXME: validate clock source */ switch (counter_dev->variant) { case ni_gpct_variant_660x: input_select_bits |= ni_660x_source_select_bits(clock_source); break; case ni_gpct_variant_e_series: case ni_gpct_variant_m_series: input_select_bits |= ni_m_series_source_select_bits(clock_source); break; default: BUG(); break; } if (clock_source & NI_GPCT_INVERT_CLOCK_SRC_BIT) input_select_bits |= Gi_Source_Polarity_Bit; ni_tio_set_bits(counter, NITIO_Gi_Input_Select_Reg(counter->counter_index), Gi_Source_Select_Mask | Gi_Source_Polarity_Bit, input_select_bits); ni_tio_set_source_subselect(counter, clock_source); if (ni_tio_counting_mode_registers_present(counter_dev)) { const unsigned prescaling_mode = clock_source & NI_GPCT_PRESCALE_MODE_CLOCK_SRC_MASK; unsigned counting_mode_bits = 0; switch (prescaling_mode) { case NI_GPCT_NO_PRESCALE_CLOCK_SRC_BITS: break; case NI_GPCT_PRESCALE_X2_CLOCK_SRC_BITS: counting_mode_bits |= Gi_Prescale_X2_Bit(counter_dev->variant); break; case NI_GPCT_PRESCALE_X8_CLOCK_SRC_BITS: counting_mode_bits |= Gi_Prescale_X8_Bit(counter_dev->variant); break; default: return -EINVAL; break; } ni_tio_set_bits(counter, NITIO_Gi_Counting_Mode_Reg(counter-> counter_index), Gi_Prescale_X2_Bit(counter_dev->variant) | Gi_Prescale_X8_Bit(counter_dev->variant), counting_mode_bits); } counter->clock_period_ps = pico_per_nano * period_ns; ni_tio_set_sync_mode(counter, 0); return 0; }
int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger) { struct ni_gpct_device *counter_dev = counter->counter_dev; unsigned command_transient_bits = 0; if (arm) { switch (start_trigger) { case NI_GPCT_ARM_IMMEDIATE: command_transient_bits |= Gi_Arm_Bit; break; case NI_GPCT_ARM_PAIRED_IMMEDIATE: command_transient_bits |= Gi_Arm_Bit | Gi_Arm_Copy_Bit; break; default: break; } if (ni_tio_counting_mode_registers_present(counter_dev)) { unsigned counting_mode_bits = 0; switch (start_trigger) { case NI_GPCT_ARM_IMMEDIATE: case NI_GPCT_ARM_PAIRED_IMMEDIATE: break; default: if (start_trigger & NI_GPCT_ARM_UNKNOWN) { /* pass-through the least significant bits so we can figure out what select later */ unsigned hw_arm_select_bits = (start_trigger << Gi_HW_Arm_Select_Shift) & Gi_HW_Arm_Select_Mask (counter_dev->variant); counting_mode_bits |= Gi_HW_Arm_Enable_Bit | hw_arm_select_bits; } else { return -EINVAL; } break; } ni_tio_set_bits(counter, NITIO_Gi_Counting_Mode_Reg (counter->counter_index), Gi_HW_Arm_Select_Mask (counter_dev->variant) | Gi_HW_Arm_Enable_Bit, counting_mode_bits); } } else { command_transient_bits |= Gi_Disarm_Bit; } ni_tio_set_bits_transient(counter, NITIO_Gi_Command_Reg(counter->counter_index), 0, 0, command_transient_bits); return 0; }
void ni_tio_init_counter(struct ni_gpct *counter) { struct ni_gpct_device *counter_dev = counter->counter_dev; ni_tio_reset_count_and_disarm(counter); /* initialize counter registers */ counter_dev->regs[NITIO_Gi_Autoincrement_Reg(counter->counter_index)] = 0x0; write_register(counter, counter_dev-> regs[NITIO_Gi_Autoincrement_Reg(counter->counter_index)], NITIO_Gi_Autoincrement_Reg(counter->counter_index)); ni_tio_set_bits(counter, NITIO_Gi_Command_Reg(counter->counter_index), ~0, Gi_Synchronize_Gate_Bit); ni_tio_set_bits(counter, NITIO_Gi_Mode_Reg(counter->counter_index), ~0, 0); counter_dev->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)] = 0x0; write_register(counter, counter_dev-> regs[NITIO_Gi_LoadA_Reg(counter->counter_index)], NITIO_Gi_LoadA_Reg(counter->counter_index)); counter_dev->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)] = 0x0; write_register(counter, counter_dev-> regs[NITIO_Gi_LoadB_Reg(counter->counter_index)], NITIO_Gi_LoadB_Reg(counter->counter_index)); ni_tio_set_bits(counter, NITIO_Gi_Input_Select_Reg(counter->counter_index), ~0, 0); if (ni_tio_counting_mode_registers_present(counter_dev)) { ni_tio_set_bits(counter, NITIO_Gi_Counting_Mode_Reg(counter-> counter_index), ~0, 0); } if (ni_tio_second_gate_registers_present(counter_dev)) { counter_dev-> regs[NITIO_Gi_Second_Gate_Reg(counter->counter_index)] = 0x0; write_register(counter, counter_dev-> regs[NITIO_Gi_Second_Gate_Reg (counter->counter_index)], NITIO_Gi_Second_Gate_Reg(counter-> counter_index)); } ni_tio_set_bits(counter, NITIO_Gi_DMA_Config_Reg(counter->counter_index), ~0, 0x0); ni_tio_set_bits(counter, NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index), ~0, 0x0); }
static void ni_tio_set_sync_mode(struct ni_gpct *counter, int force_alt_sync) { struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned counting_mode_reg = NITIO_Gi_Counting_Mode_Reg(counter->counter_index); static const uint64_t min_normal_sync_period_ps = 25000; const uint64_t clock_period_ps = ni_tio_clock_period_ps(counter, ni_tio_generic_clock_src_select(counter)); if (ni_tio_counting_mode_registers_present(counter_dev) == 0) return; switch (ni_tio_get_soft_copy(counter, counting_mode_reg) & Gi_Counting_Mode_Mask) { case Gi_Counting_Mode_QuadratureX1_Bits: case Gi_Counting_Mode_QuadratureX2_Bits: case Gi_Counting_Mode_QuadratureX4_Bits: case Gi_Counting_Mode_Sync_Source_Bits: force_alt_sync = 1; break; default: break; } /* It's not clear what we should do if clock_period is unknown, so we are not using the alt sync bit in that case, but allow the caller to decide by using the force_alt_sync parameter. */ if (force_alt_sync || (clock_period_ps && clock_period_ps < min_normal_sync_period_ps)) { ni_tio_set_bits(counter, counting_mode_reg, Gi_Alternate_Sync_Bit(counter_dev->variant), Gi_Alternate_Sync_Bit(counter_dev->variant)); } else { ni_tio_set_bits(counter, counting_mode_reg, Gi_Alternate_Sync_Bit(counter_dev->variant), 0x0); } }
static void ni_tio_set_sync_mode(struct ni_gpct *counter, int force_alt_sync) { struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned counting_mode_reg = NITIO_Gi_Counting_Mode_Reg(counter->counter_index); static const uint64_t min_normal_sync_period_ps = 25000; const uint64_t clock_period_ps = ni_tio_clock_period_ps(counter, ni_tio_generic_clock_src_select (counter)); if (ni_tio_counting_mode_registers_present(counter_dev) == 0) return; switch (ni_tio_get_soft_copy(counter, counting_mode_reg) & Gi_Counting_Mode_Mask) { case Gi_Counting_Mode_QuadratureX1_Bits: case Gi_Counting_Mode_QuadratureX2_Bits: case Gi_Counting_Mode_QuadratureX4_Bits: case Gi_Counting_Mode_Sync_Source_Bits: force_alt_sync = 1; break; default: break; } if (force_alt_sync || (clock_period_ps && clock_period_ps < min_normal_sync_period_ps)) { ni_tio_set_bits(counter, counting_mode_reg, Gi_Alternate_Sync_Bit(counter_dev->variant), Gi_Alternate_Sync_Bit(counter_dev->variant)); } else { ni_tio_set_bits(counter, counting_mode_reg, Gi_Alternate_Sync_Bit(counter_dev->variant), 0x0); } }
int ni_tio_cmdtest(struct ni_gpct *counter, comedi_cmd * cmd) { int err = 0; int tmp; int sources; /* step 1: make sure trigger sources are trivially valid */ tmp = cmd->start_src; sources = TRIG_NOW | TRIG_INT | TRIG_OTHER; if (ni_tio_counting_mode_registers_present(counter->counter_dev)) sources |= TRIG_EXT; cmd->start_src &= sources; if (!cmd->start_src || tmp != cmd->start_src) err++; tmp = cmd->scan_begin_src; cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT | TRIG_OTHER; if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) err++; tmp = cmd->convert_src; sources = TRIG_NOW | TRIG_EXT | TRIG_OTHER; cmd->convert_src &= sources; if (!cmd->convert_src || tmp != cmd->convert_src) err++; tmp = cmd->scan_end_src; cmd->scan_end_src &= TRIG_COUNT; if (!cmd->scan_end_src || tmp != cmd->scan_end_src) err++; tmp = cmd->stop_src; cmd->stop_src &= TRIG_NONE; if (!cmd->stop_src || tmp != cmd->stop_src) err++; if (err) return 1; /* step 2: make sure trigger sources are unique... */ if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_INT && cmd->start_src != TRIG_EXT && cmd->start_src != TRIG_OTHER) err++; if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->scan_begin_src != TRIG_EXT && cmd->scan_begin_src != TRIG_OTHER) err++; if (cmd->convert_src != TRIG_OTHER && cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) err++; if (cmd->stop_src != TRIG_NONE) err++; /* ... and mutually compatible */ if (cmd->convert_src != TRIG_NOW && cmd->scan_begin_src != TRIG_FOLLOW) err++; if (err) return 2; /* step 3: make sure arguments are trivially compatible */ if (cmd->start_src != TRIG_EXT) { if (cmd->start_arg != 0) { cmd->start_arg = 0; err++; } } if (cmd->scan_begin_src != TRIG_EXT) { if (cmd->scan_begin_arg) { cmd->scan_begin_arg = 0; err++; } } if (cmd->convert_src != TRIG_EXT) { if (cmd->convert_arg) { cmd->convert_arg = 0; err++; } } if (cmd->scan_end_arg != cmd->chanlist_len) { cmd->scan_end_arg = cmd->chanlist_len; err++; } if (cmd->stop_src == TRIG_NONE) { if (cmd->stop_arg != 0) { cmd->stop_arg = 0; err++; } } if (err) return 3; /* step 4: fix up any arguments */ if (err) return 4; return 0; }
int ni_tio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { struct ni_gpct *counter = s->private; int err = 0; unsigned int sources; /* Step 1 : check if triggers are trivially valid */ sources = TRIG_NOW | TRIG_INT | TRIG_OTHER; if (ni_tio_counting_mode_registers_present(counter->counter_dev)) sources |= TRIG_EXT; err |= comedi_check_trigger_src(&cmd->start_src, sources); err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW | TRIG_EXT | TRIG_OTHER); err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW | TRIG_EXT | TRIG_OTHER); err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE); if (err) return 1; /* Step 2a : make sure trigger sources are unique */ err |= comedi_check_trigger_is_unique(cmd->start_src); err |= comedi_check_trigger_is_unique(cmd->scan_begin_src); err |= comedi_check_trigger_is_unique(cmd->convert_src); /* Step 2b : and mutually compatible */ if (cmd->convert_src != TRIG_NOW && cmd->scan_begin_src != TRIG_FOLLOW) err |= -EINVAL; if (err) return 2; /* Step 3: check if arguments are trivially valid */ switch (cmd->start_src) { case TRIG_NOW: case TRIG_INT: case TRIG_OTHER: err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); break; case TRIG_EXT: /* start_arg is the start_trigger passed to ni_tio_arm() */ break; } if (cmd->scan_begin_src != TRIG_EXT) err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0); if (cmd->convert_src != TRIG_EXT) err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0); err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) return 3; /* Step 4: fix up any arguments */ /* Step 5: check channel list if it exists */ return 0; }
int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd) { int err = 0; int tmp; int sources; tmp = cmd->start_src; sources = TRIG_NOW | TRIG_INT | TRIG_OTHER; if (ni_tio_counting_mode_registers_present(counter->counter_dev)) sources |= TRIG_EXT; cmd->start_src &= sources; if (!cmd->start_src || tmp != cmd->start_src) err++; tmp = cmd->scan_begin_src; cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT | TRIG_OTHER; if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) err++; tmp = cmd->convert_src; sources = TRIG_NOW | TRIG_EXT | TRIG_OTHER; cmd->convert_src &= sources; if (!cmd->convert_src || tmp != cmd->convert_src) err++; tmp = cmd->scan_end_src; cmd->scan_end_src &= TRIG_COUNT; if (!cmd->scan_end_src || tmp != cmd->scan_end_src) err++; tmp = cmd->stop_src; cmd->stop_src &= TRIG_NONE; if (!cmd->stop_src || tmp != cmd->stop_src) err++; if (err) return 1; if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_INT && cmd->start_src != TRIG_EXT && cmd->start_src != TRIG_OTHER) err++; if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->scan_begin_src != TRIG_EXT && cmd->scan_begin_src != TRIG_OTHER) err++; if (cmd->convert_src != TRIG_OTHER && cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) err++; if (cmd->stop_src != TRIG_NONE) err++; if (cmd->convert_src != TRIG_NOW && cmd->scan_begin_src != TRIG_FOLLOW) err++; if (err) return 2; if (cmd->start_src != TRIG_EXT) { if (cmd->start_arg != 0) { cmd->start_arg = 0; err++; } } if (cmd->scan_begin_src != TRIG_EXT) { if (cmd->scan_begin_arg) { cmd->scan_begin_arg = 0; err++; } } if (cmd->convert_src != TRIG_EXT) { if (cmd->convert_arg) { cmd->convert_arg = 0; err++; } } if (cmd->scan_end_arg != cmd->chanlist_len) { cmd->scan_end_arg = cmd->chanlist_len; err++; } if (cmd->stop_src == TRIG_NONE) { if (cmd->stop_arg != 0) { cmd->stop_arg = 0; err++; } } if (err) return 3; if (err) return 4; return 0; }
int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd) { int err = 0; int tmp; int sources; /* step 1: make sure trigger sources are trivially valid */ tmp = cmd->start_src; sources = TRIG_NOW | TRIG_INT | TRIG_OTHER; if (ni_tio_counting_mode_registers_present(counter->counter_dev)) sources |= TRIG_EXT; cmd->start_src &= sources; if (!cmd->start_src || tmp != cmd->start_src) err++; tmp = cmd->scan_begin_src; cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT | TRIG_OTHER; if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) err++; tmp = cmd->convert_src; sources = TRIG_NOW | TRIG_EXT | TRIG_OTHER; cmd->convert_src &= sources; if (!cmd->convert_src || tmp != cmd->convert_src) err++; tmp = cmd->scan_end_src; cmd->scan_end_src &= TRIG_COUNT; if (!cmd->scan_end_src || tmp != cmd->scan_end_src) err++; tmp = cmd->stop_src; cmd->stop_src &= TRIG_NONE; if (!cmd->stop_src || tmp != cmd->stop_src) err++; if (err) return 1; /* step 2: make sure trigger sources are unique... */ if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_INT && cmd->start_src != TRIG_EXT && cmd->start_src != TRIG_OTHER) err++; if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->scan_begin_src != TRIG_EXT && cmd->scan_begin_src != TRIG_OTHER) err++; if (cmd->convert_src != TRIG_OTHER && cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) err++; if (cmd->stop_src != TRIG_NONE) err++; /* ... and mutually compatible */ if (cmd->convert_src != TRIG_NOW && cmd->scan_begin_src != TRIG_FOLLOW) err++; if (err) re