/* * Hardware driver for NI general purpose counter * Copyright (C) 2006 Frank Mori Hess * * This code is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * This code is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Xenomai; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Description: National Instruments general purpose counters * This module is not used directly by end-users. Rather, it is used * by other drivers (for example ni_660x and ni_pcimio) to provide * support for NI's general purpose counters. It was originally based * on the counter code from ni_660x.c and ni_mio_common.c. * * Author: * J.P. Mellor * Herman.Bruyninckx@mech.kuleuven.ac.be * Wim.Meeussen@mech.kuleuven.ac.be, * Klaas.Gadeyne@mech.kuleuven.ac.be, * Frank Mori Hess * * References: * DAQ 660x Register-Level Programmer Manual (NI 370505A-01) * DAQ 6601/6602 User Manual (NI 322137B-01) * 340934b.pdf DAQ-STC reference manual * * TODO: * - Support use of both banks X and Y * */ #include #include #include #include #include "ni_tio.h" #include "ni_mio.h" static inline void write_register(struct ni_gpct *counter, unsigned int bits, enum ni_gpct_register reg) { BUG_ON(reg >= NITIO_Num_Registers); counter->counter_dev->write_register(counter, bits, reg); } static inline unsigned int read_register(struct ni_gpct *counter, enum ni_gpct_register reg) { BUG_ON(reg >= NITIO_Num_Registers); return counter->counter_dev->read_register(counter, reg); } struct ni_gpct_device *a4l_ni_gpct_device_construct(struct a4l_device * dev, void (*write_register) (struct ni_gpct * counter, unsigned int bits, enum ni_gpct_register reg), unsigned int (*read_register) (struct ni_gpct * counter, enum ni_gpct_register reg), enum ni_gpct_variant variant, unsigned int num_counters) { struct ni_gpct_device *counter_dev = kmalloc(sizeof(struct ni_gpct_device), GFP_KERNEL); if (counter_dev == NULL) return NULL; memset(counter_dev, 0, sizeof(struct ni_gpct_device)); counter_dev->dev = dev; counter_dev->write_register = write_register; counter_dev->read_register = read_register; counter_dev->variant = variant; rtdm_lock_init(&counter_dev->regs_lock); BUG_ON(num_counters == 0); counter_dev->counters = kmalloc(sizeof(struct ni_gpct *) * num_counters, GFP_KERNEL); if (counter_dev->counters == NULL) { kfree(counter_dev); return NULL; } memset(counter_dev->counters, 0, sizeof(struct ni_gpct *) * num_counters); counter_dev->num_counters = num_counters; return counter_dev; } void a4l_ni_gpct_device_destroy(struct ni_gpct_device *counter_dev) { if (counter_dev->counters == NULL) return; kfree(counter_dev->counters); kfree(counter_dev); } static int ni_tio_counting_mode_registers_present(const struct ni_gpct_device *counter_dev) { switch (counter_dev->variant) { case ni_gpct_variant_e_series: return 0; break; case ni_gpct_variant_m_series: case ni_gpct_variant_660x: return 1; break; default: BUG(); break; } return 0; } static int ni_tio_second_gate_registers_present(const struct ni_gpct_device *counter_dev) { switch (counter_dev->variant) { case ni_gpct_variant_e_series: return 0; break; case ni_gpct_variant_m_series: case ni_gpct_variant_660x: return 1; break; default: BUG(); break; } return 0; } static inline void ni_tio_set_bits_transient(struct ni_gpct *counter, enum ni_gpct_register register_index, unsigned int bit_mask, unsigned int bit_values, unsigned transient_bit_values) { struct ni_gpct_device *counter_dev = counter->counter_dev; unsigned long flags; BUG_ON(register_index >= NITIO_Num_Registers); rtdm_lock_get_irqsave(&counter_dev->regs_lock, flags); counter_dev->regs[register_index] &= ~bit_mask; counter_dev->regs[register_index] |= (bit_values & bit_mask); write_register(counter, counter_dev->regs[register_index] | transient_bit_values, register_index); mmiowb(); rtdm_lock_put_irqrestore(&counter_dev->regs_lock, flags); } /* ni_tio_set_bits( ) is for safely writing to registers whose bits may be twiddled in interrupt context, or whose software copy may be read in interrupt context. */ static inline void ni_tio_set_bits(struct ni_gpct *counter, enum ni_gpct_register register_index, unsigned int bit_mask, unsigned int bit_values) { ni_tio_set_bits_transient(counter, register_index, bit_mask, bit_values, 0x0); } /* ni_tio_get_soft_copy( ) is for safely reading the software copy of a register whose bits might be modified in interrupt context, or whose software copy might need to be read in interrupt context. */ static inline unsigned int ni_tio_get_soft_copy(const struct ni_gpct *counter, enum ni_gpct_register register_index) { struct ni_gpct_device *counter_dev = counter->counter_dev; unsigned long flags; unsigned value; BUG_ON(register_index >= NITIO_Num_Registers); rtdm_lock_get_irqsave(&counter_dev->regs_lock, flags); value = counter_dev->regs[register_index]; rtdm_lock_put_irqrestore(&counter_dev->regs_lock, flags); return value; } static void ni_tio_reset_count_and_disarm(struct ni_gpct *counter) { write_register(counter, Gi_Reset_Bit(counter->counter_index), NITIO_Gxx_Joint_Reset_Reg(counter->counter_index)); } void a4l_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 lsampl_t ni_tio_counter_status(struct ni_gpct *counter) { lsampl_t status = 0; unsigned int bits; bits = read_register(counter,NITIO_Gxx_Status_Reg(counter->counter_index)); if (bits & Gi_Armed_Bit(counter->counter_index)) { status |= A4L_COUNTER_ARMED; if (bits & Gi_Counting_Bit(counter->counter_index)) status |= A4L_COUNTER_COUNTING; } return status; } static uint64_t ni_tio_clock_period_ps(const struct ni_gpct *counter, unsigned int generic_clock_source); static unsigned int ni_tio_generic_clock_src_select(const struct ni_gpct *counter); 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 int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned int mode) { struct ni_gpct_device *counter_dev = counter->counter_dev; unsigned mode_reg_mask; unsigned mode_reg_values; unsigned input_select_bits = 0; /* these bits map directly on to the mode register */ static const unsigned mode_reg_direct_mask = NI_GPCT_GATE_ON_BOTH_EDGES_BIT | NI_GPCT_EDGE_GATE_MODE_MASK | NI_GPCT_STOP_MODE_MASK | NI_GPCT_OUTPUT_MODE_MASK | NI_GPCT_HARDWARE_DISARM_MASK | NI_GPCT_LOADING_ON_TC_BIT | NI_GPCT_LOADING_ON_GATE_BIT | NI_GPCT_LOAD_B_SELECT_BIT; mode_reg_mask = mode_reg_direct_mask | Gi_Reload_Source_Switching_Bit; mode_reg_values = mode & mode_reg_direct_mask; switch (mode & NI_GPCT_RELOAD_SOURCE_MASK) { case NI_GPCT_RELOAD_SOURCE_FIXED_BITS: break; case NI_GPCT_RELOAD_SOURCE_SWITCHING_BITS: mode_reg_values |= Gi_Reload_Source_Switching_Bit; break; case NI_GPCT_RELOAD_SOURCE_GATE_SELECT_BITS: input_select_bits |= Gi_Gate_Select_Load_Source_Bit; mode_reg_mask |= Gi_Gating_Mode_Mask; mode_reg_values |= Gi_Level_Gating_Bits; break; default: break; } ni_tio_set_bits(counter, NITIO_Gi_Mode_Reg(counter->counter_index), mode_reg_mask, mode_reg_values); if (ni_tio_counting_mode_registers_present(counter_dev)) { unsigned counting_mode_bits = 0; counting_mode_bits |= (mode >> NI_GPCT_COUNTING_MODE_SHIFT) & Gi_Counting_Mode_Mask; counting_mode_bits |= ((mode >> NI_GPCT_INDEX_PHASE_BITSHIFT) << Gi_Index_Phase_Bitshift) & Gi_Index_Phase_Mask; if (mode & NI_GPCT_INDEX_ENABLE_BIT) { counting_mode_bits |= Gi_Index_Mode_Bit; } ni_tio_set_bits(counter, NITIO_Gi_Counting_Mode_Reg(counter->counter_index), Gi_Counting_Mode_Mask | Gi_Index_Phase_Mask | Gi_Index_Mode_Bit, counting_mode_bits); ni_tio_set_sync_mode(counter, 0); } ni_tio_set_bits(counter, NITIO_Gi_Command_Reg(counter->counter_index), Gi_Up_Down_Mask, (mode >> NI_GPCT_COUNTING_DIRECTION_SHIFT) << Gi_Up_Down_Shift); if (mode & NI_GPCT_OR_GATE_BIT) { input_select_bits |= Gi_Or_Gate_Bit; } if (mode & NI_GPCT_INVERT_OUTPUT_BIT) { input_select_bits |= Gi_Output_Polarity_Bit; } ni_tio_set_bits(counter, NITIO_Gi_Input_Select_Reg(counter->counter_index), Gi_Gate_Select_Load_Source_Bit | Gi_Or_Gate_Bit | Gi_Output_Polarity_Bit, input_select_bits); return 0; } static int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned int start_trigger) { struct ni_gpct_device *counter_dev = counter->counter_dev; unsigned int 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; } static unsigned int ni_660x_source_select_bits(lsampl_t clock_source) { unsigned int ni_660x_clock; unsigned int i; const unsigned int clock_select_bits = clock_source & NI_GPCT_CLOCK_SRC_SELECT_MASK; switch (clock_select_bits) { case NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS: ni_660x_clock = NI_660x_Timebase_1_Clock; break; case NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS: ni_660x_clock = NI_660x_Timebase_2_Clock; break; case NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS: ni_660x_clock = NI_660x_Timebase_3_Clock; break; case NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS: ni_660x_clock = NI_660x_Logic_Low_Clock; break; case NI_GPCT_SOURCE_PIN_i_CLOCK_SRC_BITS: ni_660x_clock = NI_660x_Source_Pin_i_Clock; break; case NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS: ni_660x_clock = NI_660x_Next_Gate_Clock; break; case NI_GPCT_NEXT_TC_CLOCK_SRC_BITS: ni_660x_clock = NI_660x_Next_TC_Clock; break; default: for (i = 0; i <= ni_660x_max_rtsi_channel; ++i) { if (clock_select_bits == NI_GPCT_RTSI_CLOCK_SRC_BITS(i)) { ni_660x_clock = NI_660x_RTSI_Clock(i); break; } } if (i <= ni_660x_max_rtsi_channel) break; for (i = 0; i <= ni_660x_max_source_pin; ++i) { if (clock_select_bits == NI_GPCT_SOURCE_PIN_CLOCK_SRC_BITS(i)) { ni_660x_clock = NI_660x_Source_Pin_Clock(i); break; } } if (i <= ni_660x_max_source_pin) break; ni_660x_clock = 0; BUG(); break; } return Gi_Source_Select_Bits(ni_660x_clock); } static unsigned int ni_m_series_source_select_bits(lsampl_t clock_source) { unsigned int ni_m_series_clock; unsigned int i; const unsigned int clock_select_bits = clock_source & NI_GPCT_CLOCK_SRC_SELECT_MASK; switch (clock_select_bits) { case NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS: ni_m_series_clock = NI_M_Series_Timebase_1_Clock; break; case NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS: ni_m_series_clock = NI_M_Series_Timebase_2_Clock; break; case NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS: ni_m_series_clock = NI_M_Series_Timebase_3_Clock; break; case NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS: ni_m_series_clock = NI_M_Series_Logic_Low_Clock; break; case NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS: ni_m_series_clock = NI_M_Series_Next_Gate_Clock; break; case NI_GPCT_NEXT_TC_CLOCK_SRC_BITS: ni_m_series_clock = NI_M_Series_Next_TC_Clock; break; case NI_GPCT_PXI10_CLOCK_SRC_BITS: ni_m_series_clock = NI_M_Series_PXI10_Clock; break; case NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS: ni_m_series_clock = NI_M_Series_PXI_Star_Trigger_Clock; break; case NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS: ni_m_series_clock = NI_M_Series_Analog_Trigger_Out_Clock; break; default: for (i = 0; i <= ni_m_series_max_rtsi_channel; ++i) { if (clock_select_bits == NI_GPCT_RTSI_CLOCK_SRC_BITS(i)) { ni_m_series_clock = NI_M_Series_RTSI_Clock(i); break; } } if (i <= ni_m_series_max_rtsi_channel) break; for (i = 0; i <= ni_m_series_max_pfi_channel; ++i) { if (clock_select_bits == NI_GPCT_PFI_CLOCK_SRC_BITS(i)) { ni_m_series_clock = NI_M_Series_PFI_Clock(i); break; } } if (i <= ni_m_series_max_pfi_channel) break; __a4l_err("invalid clock source 0x%lx\n", (unsigned long)clock_source); BUG(); ni_m_series_clock = 0; break; } return Gi_Source_Select_Bits(ni_m_series_clock); } static void ni_tio_set_source_subselect(struct ni_gpct *counter, lsampl_t clock_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned second_gate_reg = NITIO_Gi_Second_Gate_Reg(counter->counter_index); if (counter_dev->variant != ni_gpct_variant_m_series) return; switch (clock_source & NI_GPCT_CLOCK_SRC_SELECT_MASK) { /* Gi_Source_Subselect is zero */ case NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS: case NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS: counter_dev->regs[second_gate_reg] &= ~Gi_Source_Subselect_Bit; break; /* Gi_Source_Subselect is one */ case NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS: case NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS: counter_dev->regs[second_gate_reg] |= Gi_Source_Subselect_Bit; break; /* Gi_Source_Subselect doesn't matter */ default: return; break; } write_register(counter, counter_dev->regs[second_gate_reg], second_gate_reg); } static int ni_tio_set_clock_src(struct ni_gpct *counter, lsampl_t clock_source, lsampl_t 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; } static unsigned int ni_tio_clock_src_modifiers(const struct ni_gpct *counter) { struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned counting_mode_bits = ni_tio_get_soft_copy(counter, NITIO_Gi_Counting_Mode_Reg(counter->counter_index)); unsigned int bits = 0; if (ni_tio_get_soft_copy(counter, NITIO_Gi_Input_Select_Reg(counter-> counter_index)) & Gi_Source_Polarity_Bit) bits |= NI_GPCT_INVERT_CLOCK_SRC_BIT; if (counting_mode_bits & Gi_Prescale_X2_Bit(counter_dev->variant)) bits |= NI_GPCT_PRESCALE_X2_CLOCK_SRC_BITS; if (counting_mode_bits & Gi_Prescale_X8_Bit(counter_dev->variant)) bits |= NI_GPCT_PRESCALE_X8_CLOCK_SRC_BITS; return bits; } static unsigned int ni_m_series_clock_src_select(const struct ni_gpct *counter) { struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned int second_gate_reg = NITIO_Gi_Second_Gate_Reg(counter->counter_index); unsigned int i, clock_source = 0; const unsigned int input_select = (ni_tio_get_soft_copy(counter, NITIO_Gi_Input_Select_Reg(counter-> counter_index)) & Gi_Source_Select_Mask) >> Gi_Source_Select_Shift; switch (input_select) { case NI_M_Series_Timebase_1_Clock: clock_source = NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS; break; case NI_M_Series_Timebase_2_Clock: clock_source = NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS; break; case NI_M_Series_Timebase_3_Clock: if (counter_dev-> regs[second_gate_reg] & Gi_Source_Subselect_Bit) clock_source = NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS; else clock_source = NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS; break; case NI_M_Series_Logic_Low_Clock: clock_source = NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS; break; case NI_M_Series_Next_Gate_Clock: if (counter_dev-> regs[second_gate_reg] & Gi_Source_Subselect_Bit) clock_source = NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS; else clock_source = NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS; break; case NI_M_Series_PXI10_Clock: clock_source = NI_GPCT_PXI10_CLOCK_SRC_BITS; break; case NI_M_Series_Next_TC_Clock: clock_source = NI_GPCT_NEXT_TC_CLOCK_SRC_BITS; break; default: for (i = 0; i <= ni_m_series_max_rtsi_channel; ++i) { if (input_select == NI_M_Series_RTSI_Clock(i)) { clock_source = NI_GPCT_RTSI_CLOCK_SRC_BITS(i); break; } } if (i <= ni_m_series_max_rtsi_channel) break; for (i = 0; i <= ni_m_series_max_pfi_channel; ++i) { if (input_select == NI_M_Series_PFI_Clock(i)) { clock_source = NI_GPCT_PFI_CLOCK_SRC_BITS(i); break; } } if (i <= ni_m_series_max_pfi_channel) break; BUG(); break; } clock_source |= ni_tio_clock_src_modifiers(counter); return clock_source; } static unsigned int ni_660x_clock_src_select(const struct ni_gpct *counter) { unsigned int i, clock_source = 0; const unsigned input_select = (ni_tio_get_soft_copy(counter, NITIO_Gi_Input_Select_Reg(counter-> counter_index)) & Gi_Source_Select_Mask) >> Gi_Source_Select_Shift; switch (input_select) { case NI_660x_Timebase_1_Clock: clock_source = NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS; break; case NI_660x_Timebase_2_Clock: clock_source = NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS; break; case NI_660x_Timebase_3_Clock: clock_source = NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS; break; case NI_660x_Logic_Low_Clock: clock_source = NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS; break; case NI_660x_Source_Pin_i_Clock: clock_source = NI_GPCT_SOURCE_PIN_i_CLOCK_SRC_BITS; break; case NI_660x_Next_Gate_Clock: clock_source = NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS; break; case NI_660x_Next_TC_Clock: clock_source = NI_GPCT_NEXT_TC_CLOCK_SRC_BITS; break; default: for (i = 0; i <= ni_660x_max_rtsi_channel; ++i) { if (input_select == NI_660x_RTSI_Clock(i)) { clock_source = NI_GPCT_RTSI_CLOCK_SRC_BITS(i); break; } } if (i <= ni_660x_max_rtsi_channel) break; for (i = 0; i <= ni_660x_max_source_pin; ++i) { if (input_select == NI_660x_Source_Pin_Clock(i)) { clock_source = NI_GPCT_SOURCE_PIN_CLOCK_SRC_BITS(i); break; } } if (i <= ni_660x_max_source_pin) break; BUG(); break; } clock_source |= ni_tio_clock_src_modifiers(counter); return clock_source; } static unsigned int ni_tio_generic_clock_src_select(const struct ni_gpct *counter) { switch (counter->counter_dev->variant) { case ni_gpct_variant_e_series: case ni_gpct_variant_m_series: return ni_m_series_clock_src_select(counter); break; case ni_gpct_variant_660x: return ni_660x_clock_src_select(counter); break; default: BUG(); break; } return 0; } static uint64_t ni_tio_clock_period_ps(const struct ni_gpct *counter, unsigned int generic_clock_source) { uint64_t clock_period_ps; switch (generic_clock_source & NI_GPCT_CLOCK_SRC_SELECT_MASK) { case NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS: clock_period_ps = 50000; break; case NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS: clock_period_ps = 10000000; break; case NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS: clock_period_ps = 12500; break; case NI_GPCT_PXI10_CLOCK_SRC_BITS: clock_period_ps = 100000; break; default: /* Clock period is specified by user with prescaling already taken into account. */ return counter->clock_period_ps; break; } switch (generic_clock_source & NI_GPCT_PRESCALE_MODE_CLOCK_SRC_MASK) { case NI_GPCT_NO_PRESCALE_CLOCK_SRC_BITS: break; case NI_GPCT_PRESCALE_X2_CLOCK_SRC_BITS: clock_period_ps *= 2; break; case NI_GPCT_PRESCALE_X8_CLOCK_SRC_BITS: clock_period_ps *= 8; break; default: BUG(); break; } return clock_period_ps; } static void ni_tio_get_clock_src(struct ni_gpct *counter, unsigned int * clock_source, unsigned int * period_ns) { static const unsigned int pico_per_nano = 1000; uint64_t temp64; *clock_source = ni_tio_generic_clock_src_select(counter); temp64 = ni_tio_clock_period_ps(counter, *clock_source); do_div(temp64, pico_per_nano); *period_ns = temp64; } static void ni_tio_set_first_gate_modifiers(struct ni_gpct *counter, lsampl_t gate_source) { const unsigned int mode_mask = Gi_Gate_Polarity_Bit | Gi_Gating_Mode_Mask; unsigned int mode_values = 0; if (gate_source & CR_INVERT) { mode_values |= Gi_Gate_Polarity_Bit; } if (gate_source & CR_EDGE) { mode_values |= Gi_Rising_Edge_Gating_Bits; } else { mode_values |= Gi_Level_Gating_Bits; } ni_tio_set_bits(counter, NITIO_Gi_Mode_Reg(counter->counter_index), mode_mask, mode_values); } static int ni_660x_set_first_gate(struct ni_gpct *counter, lsampl_t gate_source) { const unsigned int selected_gate = CR_CHAN(gate_source); /* Bits of selected_gate that may be meaningful to input select register */ const unsigned int selected_gate_mask = 0x1f; unsigned ni_660x_gate_select; unsigned i; switch (selected_gate) { case NI_GPCT_NEXT_SOURCE_GATE_SELECT: ni_660x_gate_select = NI_660x_Next_SRC_Gate_Select; break; case NI_GPCT_NEXT_OUT_GATE_SELECT: case NI_GPCT_LOGIC_LOW_GATE_SELECT: case NI_GPCT_SOURCE_PIN_i_GATE_SELECT: case NI_GPCT_GATE_PIN_i_GATE_SELECT: ni_660x_gate_select = selected_gate & selected_gate_mask; break; default: for (i = 0; i <= ni_660x_max_rtsi_channel; ++i) { if (selected_gate == NI_GPCT_RTSI_GATE_SELECT(i)) { ni_660x_gate_select = selected_gate & selected_gate_mask; break; } } if (i <= ni_660x_max_rtsi_channel) break; for (i = 0; i <= ni_660x_max_gate_pin; ++i) { if (selected_gate == NI_GPCT_GATE_PIN_GATE_SELECT(i)) { ni_660x_gate_select = selected_gate & selected_gate_mask; break; } } if (i <= ni_660x_max_gate_pin) break; return -EINVAL; break; } ni_tio_set_bits(counter, NITIO_Gi_Input_Select_Reg(counter->counter_index), Gi_Gate_Select_Mask, Gi_Gate_Select_Bits(ni_660x_gate_select)); return 0; } static int ni_m_series_set_first_gate(struct ni_gpct *counter, lsampl_t gate_source) { const unsigned int selected_gate = CR_CHAN(gate_source); /* bits of selected_gate that may be meaningful to input select register */ const unsigned int selected_gate_mask = 0x1f; unsigned int i, ni_m_series_gate_select; switch (selected_gate) { case NI_GPCT_TIMESTAMP_MUX_GATE_SELECT: case NI_GPCT_AI_START2_GATE_SELECT: case NI_GPCT_PXI_STAR_TRIGGER_GATE_SELECT: case NI_GPCT_NEXT_OUT_GATE_SELECT: case NI_GPCT_AI_START1_GATE_SELECT: case NI_GPCT_NEXT_SOURCE_GATE_SELECT: case NI_GPCT_ANALOG_TRIGGER_OUT_GATE_SELECT: case NI_GPCT_LOGIC_LOW_GATE_SELECT: ni_m_series_gate_select = selected_gate & selected_gate_mask; break; default: for (i = 0; i <= ni_m_series_max_rtsi_channel; ++i) { if (selected_gate == NI_GPCT_RTSI_GATE_SELECT(i)) { ni_m_series_gate_select = selected_gate & selected_gate_mask; break; } } if (i <= ni_m_series_max_rtsi_channel) break; for (i = 0; i <= ni_m_series_max_pfi_channel; ++i) { if (selected_gate == NI_GPCT_PFI_GATE_SELECT(i)) { ni_m_series_gate_select = selected_gate & selected_gate_mask; break; } } if (i <= ni_m_series_max_pfi_channel) break; return -EINVAL; break; } ni_tio_set_bits(counter, NITIO_Gi_Input_Select_Reg(counter->counter_index), Gi_Gate_Select_Mask, Gi_Gate_Select_Bits(ni_m_series_gate_select)); return 0; } static int ni_660x_set_second_gate(struct ni_gpct *counter, lsampl_t gate_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned int second_gate_reg = NITIO_Gi_Second_Gate_Reg(counter->counter_index); const unsigned int selected_second_gate = CR_CHAN(gate_source); /* bits of second_gate that may be meaningful to second gate register */ static const unsigned int selected_second_gate_mask = 0x1f; unsigned int i, ni_660x_second_gate_select; switch (selected_second_gate) { case NI_GPCT_SOURCE_PIN_i_GATE_SELECT: case NI_GPCT_UP_DOWN_PIN_i_GATE_SELECT: case NI_GPCT_SELECTED_GATE_GATE_SELECT: case NI_GPCT_NEXT_OUT_GATE_SELECT: case NI_GPCT_LOGIC_LOW_GATE_SELECT: ni_660x_second_gate_select = selected_second_gate & selected_second_gate_mask; break; case NI_GPCT_NEXT_SOURCE_GATE_SELECT: ni_660x_second_gate_select = NI_660x_Next_SRC_Second_Gate_Select; break; default: for (i = 0; i <= ni_660x_max_rtsi_channel; ++i) { if (selected_second_gate == NI_GPCT_RTSI_GATE_SELECT(i)) { ni_660x_second_gate_select = selected_second_gate & selected_second_gate_mask; break; } } if (i <= ni_660x_max_rtsi_channel) break; for (i = 0; i <= ni_660x_max_up_down_pin; ++i) { if (selected_second_gate == NI_GPCT_UP_DOWN_PIN_GATE_SELECT(i)) { ni_660x_second_gate_select = selected_second_gate & selected_second_gate_mask; break; } } if (i <= ni_660x_max_up_down_pin) break; return -EINVAL; break; }; counter_dev->regs[second_gate_reg] |= Gi_Second_Gate_Mode_Bit; counter_dev->regs[second_gate_reg] &= ~Gi_Second_Gate_Select_Mask; counter_dev->regs[second_gate_reg] |= Gi_Second_Gate_Select_Bits(ni_660x_second_gate_select); write_register(counter, counter_dev->regs[second_gate_reg], second_gate_reg); return 0; } static int ni_m_series_set_second_gate(struct ni_gpct *counter, lsampl_t gate_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned int second_gate_reg = NITIO_Gi_Second_Gate_Reg(counter->counter_index); const unsigned int selected_second_gate = CR_CHAN(gate_source); /* Bits of second_gate that may be meaningful to second gate register */ static const unsigned int selected_second_gate_mask = 0x1f; unsigned int ni_m_series_second_gate_select; /* FIXME: We don't know what the m-series second gate codes are, so we'll just pass the bits through for now. */ switch (selected_second_gate) { default: ni_m_series_second_gate_select = selected_second_gate & selected_second_gate_mask; break; }; counter_dev->regs[second_gate_reg] |= Gi_Second_Gate_Mode_Bit; counter_dev->regs[second_gate_reg] &= ~Gi_Second_Gate_Select_Mask; counter_dev->regs[second_gate_reg] |= Gi_Second_Gate_Select_Bits(ni_m_series_second_gate_select); write_register(counter, counter_dev->regs[second_gate_reg], second_gate_reg); return 0; } static int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned int gate_index, lsampl_t gate_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned int second_gate_reg = NITIO_Gi_Second_Gate_Reg(counter->counter_index); switch (gate_index) { case 0: if (CR_CHAN(gate_source) == NI_GPCT_DISABLED_GATE_SELECT) { ni_tio_set_bits(counter, NITIO_Gi_Mode_Reg(counter->counter_index), Gi_Gating_Mode_Mask, Gi_Gating_Disabled_Bits); return 0; } ni_tio_set_first_gate_modifiers(counter, gate_source); switch (counter_dev->variant) { case ni_gpct_variant_e_series: case ni_gpct_variant_m_series: return ni_m_series_set_first_gate(counter, gate_source); break; case ni_gpct_variant_660x: return ni_660x_set_first_gate(counter, gate_source); break; default: BUG(); break; } break; case 1: if (ni_tio_second_gate_registers_present(counter_dev) == 0) return -EINVAL; if (CR_CHAN(gate_source) == NI_GPCT_DISABLED_GATE_SELECT) { counter_dev->regs[second_gate_reg] &= ~Gi_Second_Gate_Mode_Bit; write_register(counter, counter_dev->regs[second_gate_reg], second_gate_reg); return 0; } if (gate_source & CR_INVERT) { counter_dev->regs[second_gate_reg] |= Gi_Second_Gate_Polarity_Bit; } else { counter_dev->regs[second_gate_reg] &= ~Gi_Second_Gate_Polarity_Bit; } switch (counter_dev->variant) { case ni_gpct_variant_m_series: return ni_m_series_set_second_gate(counter, gate_source); break; case ni_gpct_variant_660x: return ni_660x_set_second_gate(counter, gate_source); break; default: BUG(); break; } break; default: return -EINVAL; break; } return 0; } static int ni_tio_set_other_src(struct ni_gpct *counter, unsigned int index, unsigned int source) { struct ni_gpct_device *counter_dev = counter->counter_dev; if (counter_dev->variant == ni_gpct_variant_m_series) { unsigned int abz_reg, shift, mask; abz_reg = NITIO_Gi_ABZ_Reg(counter->counter_index); switch (index) { case NI_GPCT_SOURCE_ENCODER_A: shift = 10; break; case NI_GPCT_SOURCE_ENCODER_B: shift = 5; break; case NI_GPCT_SOURCE_ENCODER_Z: shift = 0; break; default: return -EINVAL; break; } mask = 0x1f << shift; if (source > 0x1f) { /* Disable gate */ source = 0x1f; } counter_dev->regs[abz_reg] &= ~mask; counter_dev->regs[abz_reg] |= (source << shift) & mask; write_register(counter, counter_dev->regs[abz_reg], abz_reg); return 0; } return -EINVAL; } static unsigned int ni_660x_first_gate_to_generic_gate_source(unsigned int ni_660x_gate_select) { unsigned int i; switch (ni_660x_gate_select) { case NI_660x_Source_Pin_i_Gate_Select: return NI_GPCT_SOURCE_PIN_i_GATE_SELECT; break; case NI_660x_Gate_Pin_i_Gate_Select: return NI_GPCT_GATE_PIN_i_GATE_SELECT; break; case NI_660x_Next_SRC_Gate_Select: return NI_GPCT_NEXT_SOURCE_GATE_SELECT; break; case NI_660x_Next_Out_Gate_Select: return NI_GPCT_NEXT_OUT_GATE_SELECT; break; case NI_660x_Logic_Low_Gate_Select: return NI_GPCT_LOGIC_LOW_GATE_SELECT; break; default: for (i = 0; i <= ni_660x_max_rtsi_channel; ++i) { if (ni_660x_gate_select == NI_660x_RTSI_Gate_Select(i)) { return NI_GPCT_RTSI_GATE_SELECT(i); break; } } if (i <= ni_660x_max_rtsi_channel) break; for (i = 0; i <= ni_660x_max_gate_pin; ++i) { if (ni_660x_gate_select == NI_660x_Gate_Pin_Gate_Select(i)) { return NI_GPCT_GATE_PIN_GATE_SELECT(i); break; } } if (i <= ni_660x_max_gate_pin) break; BUG(); break; } return 0; } static unsigned int ni_m_series_first_gate_to_generic_gate_source(unsigned int ni_m_series_gate_select) { unsigned int i; switch (ni_m_series_gate_select) { case NI_M_Series_Timestamp_Mux_Gate_Select: return NI_GPCT_TIMESTAMP_MUX_GATE_SELECT; break; case NI_M_Series_AI_START2_Gate_Select: return NI_GPCT_AI_START2_GATE_SELECT; break; case NI_M_Series_PXI_Star_Trigger_Gate_Select: return NI_GPCT_PXI_STAR_TRIGGER_GATE_SELECT; break; case NI_M_Series_Next_Out_Gate_Select: return NI_GPCT_NEXT_OUT_GATE_SELECT; break; case NI_M_Series_AI_START1_Gate_Select: return NI_GPCT_AI_START1_GATE_SELECT; break; case NI_M_Series_Next_SRC_Gate_Select: return NI_GPCT_NEXT_SOURCE_GATE_SELECT; break; case NI_M_Series_Analog_Trigger_Out_Gate_Select: return NI_GPCT_ANALOG_TRIGGER_OUT_GATE_SELECT; break; case NI_M_Series_Logic_Low_Gate_Select: return NI_GPCT_LOGIC_LOW_GATE_SELECT; break; default: for (i = 0; i <= ni_m_series_max_rtsi_channel; ++i) { if (ni_m_series_gate_select == NI_M_Series_RTSI_Gate_Select(i)) { return NI_GPCT_RTSI_GATE_SELECT(i); break; } } if (i <= ni_m_series_max_rtsi_channel) break; for (i = 0; i <= ni_m_series_max_pfi_channel; ++i) { if (ni_m_series_gate_select == NI_M_Series_PFI_Gate_Select(i)) { return NI_GPCT_PFI_GATE_SELECT(i); break; } } if (i <= ni_m_series_max_pfi_channel) break; BUG(); break; } return 0; } static unsigned int ni_660x_second_gate_to_generic_gate_source(unsigned int ni_660x_gate_select) { unsigned int i; switch (ni_660x_gate_select) { case NI_660x_Source_Pin_i_Second_Gate_Select: return NI_GPCT_SOURCE_PIN_i_GATE_SELECT; break; case NI_660x_Up_Down_Pin_i_Second_Gate_Select: return NI_GPCT_UP_DOWN_PIN_i_GATE_SELECT; break; case NI_660x_Next_SRC_Second_Gate_Select: return NI_GPCT_NEXT_SOURCE_GATE_SELECT; break; case NI_660x_Next_Out_Second_Gate_Select: return NI_GPCT_NEXT_OUT_GATE_SELECT; break; case NI_660x_Selected_Gate_Second_Gate_Select: return NI_GPCT_SELECTED_GATE_GATE_SELECT; break; case NI_660x_Logic_Low_Second_Gate_Select: return NI_GPCT_LOGIC_LOW_GATE_SELECT; break; default: for (i = 0; i <= ni_660x_max_rtsi_channel; ++i) { if (ni_660x_gate_select == NI_660x_RTSI_Second_Gate_Select(i)) { return NI_GPCT_RTSI_GATE_SELECT(i); break; } } if (i <= ni_660x_max_rtsi_channel) break; for (i = 0; i <= ni_660x_max_up_down_pin; ++i) { if (ni_660x_gate_select == NI_660x_Up_Down_Pin_Second_Gate_Select(i)) { return NI_GPCT_UP_DOWN_PIN_GATE_SELECT(i); break; } } if (i <= ni_660x_max_up_down_pin) break; BUG(); break; } return 0; } static unsigned int ni_m_series_second_gate_to_generic_gate_source(unsigned int ni_m_series_gate_select) { /* FIXME: the second gate sources for the m series are undocumented, so we just return the raw bits for now. */ switch (ni_m_series_gate_select) { default: return ni_m_series_gate_select; break; } return 0; }; static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned int gate_index, unsigned int * gate_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned int mode_bits = ni_tio_get_soft_copy(counter, NITIO_Gi_Mode_Reg(counter->counter_index)); const unsigned int second_gate_reg = NITIO_Gi_Second_Gate_Reg(counter->counter_index); unsigned int gate_select_bits; switch (gate_index) { case 0: if ((mode_bits & Gi_Gating_Mode_Mask) == Gi_Gating_Disabled_Bits) { *gate_source = NI_GPCT_DISABLED_GATE_SELECT; return 0; } else { gate_select_bits = (ni_tio_get_soft_copy(counter, NITIO_Gi_Input_Select_Reg(counter-> counter_index)) & Gi_Gate_Select_Mask) >> Gi_Gate_Select_Shift; } switch (counter_dev->variant) { case ni_gpct_variant_e_series: case ni_gpct_variant_m_series: *gate_source = ni_m_series_first_gate_to_generic_gate_source (gate_select_bits); break; case ni_gpct_variant_660x: *gate_source = ni_660x_first_gate_to_generic_gate_source (gate_select_bits); break; default: BUG(); break; } if (mode_bits & Gi_Gate_Polarity_Bit) { *gate_source |= CR_INVERT; } if ((mode_bits & Gi_Gating_Mode_Mask) != Gi_Level_Gating_Bits) { *gate_source |= CR_EDGE; } break; case 1: if ((mode_bits & Gi_Gating_Mode_Mask) == Gi_Gating_Disabled_Bits || (counter_dev-> regs[second_gate_reg] & Gi_Second_Gate_Mode_Bit) == 0) { *gate_source = NI_GPCT_DISABLED_GATE_SELECT; return 0; } else { gate_select_bits = (counter_dev-> regs[second_gate_reg] & Gi_Second_Gate_Select_Mask) >> Gi_Second_Gate_Select_Shift; } switch (counter_dev->variant) { case ni_gpct_variant_e_series: case ni_gpct_variant_m_series: *gate_source = ni_m_series_second_gate_to_generic_gate_source (gate_select_bits); break; case ni_gpct_variant_660x: *gate_source = ni_660x_second_gate_to_generic_gate_source (gate_select_bits); break; default: BUG(); break; } if (counter_dev-> regs[second_gate_reg] & Gi_Second_Gate_Polarity_Bit) { *gate_source |= CR_INVERT; } /* Second gate can't have edge/level mode set independently */ if ((mode_bits & Gi_Gating_Mode_Mask) != Gi_Level_Gating_Bits) { *gate_source |= CR_EDGE; } break; default: return -EINVAL; break; } return 0; } int a4l_ni_tio_insn_config(struct ni_gpct *counter, struct a4l_kernel_instruction *insn) { unsigned int *data = (unsigned int *)insn->data; switch (data[0]) { case A4L_INSN_CONFIG_SET_COUNTER_MODE: return ni_tio_set_counter_mode(counter, data[1]); break; case A4L_INSN_CONFIG_ARM: return ni_tio_arm(counter, 1, data[1]); break; case A4L_INSN_CONFIG_DISARM: ni_tio_arm(counter, 0, 0); return 0; break; case A4L_INSN_CONFIG_GET_COUNTER_STATUS: data[1] = ni_tio_counter_status(counter); data[2] = counter_status_mask; return 0; break; case A4L_INSN_CONFIG_SET_CLOCK_SRC: return ni_tio_set_clock_src(counter, data[1], data[2]); break; case A4L_INSN_CONFIG_GET_CLOCK_SRC: ni_tio_get_clock_src(counter, &data[1], &data[2]); return 0; break; case A4L_INSN_CONFIG_SET_GATE_SRC: return ni_tio_set_gate_src(counter, data[1], data[2]); break; case A4L_INSN_CONFIG_GET_GATE_SRC: return ni_tio_get_gate_src(counter, data[1], &data[2]); break; case A4L_INSN_CONFIG_SET_OTHER_SRC: return ni_tio_set_other_src(counter, data[1], data[2]); break; case A4L_INSN_CONFIG_RESET: ni_tio_reset_count_and_disarm(counter); return 0; break; default: break; } return -EINVAL; } int a4l_ni_tio_rinsn(struct ni_gpct *counter, struct a4l_kernel_instruction *insn) { struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned int channel = CR_CHAN(insn->chan_desc); unsigned int first_read; unsigned int second_read; unsigned int correct_read; uint32_t *data = (uint32_t *)insn->data; if (insn->data_size != sizeof(uint32_t)) return -EINVAL; switch (channel) { case 0: ni_tio_set_bits(counter, NITIO_Gi_Command_Reg(counter->counter_index), Gi_Save_Trace_Bit, 0); ni_tio_set_bits(counter, NITIO_Gi_Command_Reg(counter->counter_index), Gi_Save_Trace_Bit, Gi_Save_Trace_Bit); /* The count doesn't get latched until the next clock edge, so it is possible the count may change (once) while we are reading. Since the read of the SW_Save_Reg isn't atomic (apparently even when it's a 32 bit register according to 660x docs), we need to read twice and make sure the reading hasn't changed. If it has, a third read will be correct since the count value will definitely have latched by then. */ first_read = read_register(counter, NITIO_Gi_SW_Save_Reg(counter->counter_index)); second_read = read_register(counter, NITIO_Gi_SW_Save_Reg(counter->counter_index)); if (first_read != second_read) correct_read = read_register(counter, NITIO_Gi_SW_Save_Reg(counter->counter_index)); else correct_read = first_read; data[0] = correct_read; return 0; break; case 1: data[0] = counter_dev->regs [NITIO_Gi_LoadA_Reg(counter->counter_index)]; break; case 2: data[0] = counter_dev->regs [NITIO_Gi_LoadB_Reg(counter->counter_index)]; break; }; return 0; } static unsigned int ni_tio_next_load_register(struct ni_gpct *counter) { const unsigned int bits = read_register(counter, NITIO_Gxx_Status_Reg(counter->counter_index)); if (bits & Gi_Next_Load_Source_Bit(counter->counter_index)) { return NITIO_Gi_LoadB_Reg(counter->counter_index); } else { return NITIO_Gi_LoadA_Reg(counter->counter_index); } } int a4l_ni_tio_winsn(struct ni_gpct *counter, struct a4l_kernel_instruction *insn) { struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned int channel = CR_CHAN(insn->chan_desc); unsigned int load_reg; uint32_t *data = (uint32_t *)insn->data; if (insn->data_size != sizeof(uint32_t)) return -EINVAL; switch (channel) { case 0: /* Unsafe if counter is armed. Should probably check status and return -EBUSY if armed. */ /* Don't disturb load source select, just use whichever load register is already selected. */ load_reg = ni_tio_next_load_register(counter); write_register(counter, data[0], load_reg); ni_tio_set_bits_transient(counter, NITIO_Gi_Command_Reg(counter->counter_index), 0, 0, Gi_Load_Bit); /* Restore state of load reg to whatever the user set last set it to */ write_register(counter, counter_dev->regs[load_reg], load_reg); break; case 1: counter_dev->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)] = data[0]; write_register(counter, data[0], NITIO_Gi_LoadA_Reg(counter->counter_index)); break; case 2: counter_dev->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)] = data[0]; write_register(counter, data[0], NITIO_Gi_LoadB_Reg(counter->counter_index)); break; default: return -EINVAL; break; } return 0; } #if (defined(CONFIG_XENO_DRIVERS_ANALOGY_NI_MITE) || \ defined(CONFIG_XENO_DRIVERS_ANALOGY_NI_MITE_MODULE)) static void ni_tio_configure_dma(struct ni_gpct *counter, short enable, short read_not_write) { struct ni_gpct_device *counter_dev = counter->counter_dev; unsigned int input_select_bits = 0; if (enable) { if (read_not_write) { input_select_bits |= Gi_Read_Acknowledges_Irq; } else { input_select_bits |= Gi_Write_Acknowledges_Irq; } } ni_tio_set_bits(counter, NITIO_Gi_Input_Select_Reg(counter->counter_index), Gi_Read_Acknowledges_Irq | Gi_Write_Acknowledges_Irq, input_select_bits); switch (counter_dev->variant) { case ni_gpct_variant_e_series: break; case ni_gpct_variant_m_series: case ni_gpct_variant_660x: { unsigned gi_dma_config_bits = 0; if (enable) { gi_dma_config_bits |= Gi_DMA_Enable_Bit; gi_dma_config_bits |= Gi_DMA_Int_Bit; } if (read_not_write == 0) { gi_dma_config_bits |= Gi_DMA_Write_Bit; } ni_tio_set_bits(counter, NITIO_Gi_DMA_Config_Reg(counter->counter_index), Gi_DMA_Enable_Bit | Gi_DMA_Int_Bit | Gi_DMA_Write_Bit, gi_dma_config_bits); } break; } } /* TODO: a4l_ni_tio_input_inttrig is left unused because the trigger callback cannot be changed at run time */ int a4l_ni_tio_input_inttrig(struct ni_gpct *counter, lsampl_t trignum) { unsigned long flags; int retval = 0; BUG_ON(counter == NULL); if (trignum != 0) return -EINVAL; rtdm_lock_get_irqsave(&counter->lock, flags); if (counter->mite_chan) a4l_mite_dma_arm(counter->mite_chan); else retval = -EIO; rtdm_lock_put_irqrestore(&counter->lock, flags); if (retval < 0) return retval; retval = ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE); /* TODO: disable trigger until a command is recorded. Null trig at beginning prevent ao start trigger from executing more than once per command (and doing things like trying to allocate the ao dma channel multiple times) */ return retval; } static int ni_tio_input_cmd(struct ni_gpct *counter, struct a4l_cmd_desc *cmd) { struct ni_gpct_device *counter_dev = counter->counter_dev; int retval = 0; counter->mite_chan->dir = A4L_INPUT; switch (counter_dev->variant) { case ni_gpct_variant_m_series: case ni_gpct_variant_660x: a4l_mite_prep_dma(counter->mite_chan, 32, 32); break; case ni_gpct_variant_e_series: a4l_mite_prep_dma(counter->mite_chan, 16, 32); break; default: BUG(); break; } ni_tio_set_bits(counter, NITIO_Gi_Command_Reg(counter->counter_index), Gi_Save_Trace_Bit, 0); ni_tio_configure_dma(counter, 1, 1); switch (cmd->start_src) { case TRIG_NOW: a4l_mite_dma_arm(counter->mite_chan); retval = ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE); break; case TRIG_INT: break; case TRIG_EXT: a4l_mite_dma_arm(counter->mite_chan); retval = ni_tio_arm(counter, 1, cmd->start_arg); break; case TRIG_OTHER: a4l_mite_dma_arm(counter->mite_chan); break; default: BUG(); break; } return retval; } static int ni_tio_output_cmd(struct ni_gpct *counter, struct a4l_cmd_desc *cmd) { __a4l_err("ni_tio: output commands not yet implemented.\n"); return -ENOTSUPP; } static int ni_tio_cmd_setup(struct ni_gpct *counter, struct a4l_cmd_desc *cmd) { int retval = 0, set_gate_source = 0; unsigned int gate_source; if (cmd->scan_begin_src == TRIG_EXT) { set_gate_source = 1; gate_source = cmd->scan_begin_arg; } else if (cmd->convert_src == TRIG_EXT) { set_gate_source = 1; gate_source = cmd->convert_arg; } if (set_gate_source) { retval = ni_tio_set_gate_src(counter, 0, gate_source); } if (cmd->flags & TRIG_WAKE_EOS) { ni_tio_set_bits(counter, NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index), Gi_Gate_Interrupt_Enable_Bit(counter->counter_index), Gi_Gate_Interrupt_Enable_Bit(counter->counter_index)); } return retval; } int a4l_ni_tio_cmd(struct ni_gpct *counter, struct a4l_cmd_desc *cmd) { int retval = 0; unsigned long flags; rtdm_lock_get_irqsave(&counter->lock, flags); if (counter->mite_chan == NULL) { __a4l_err("a4l_ni_tio_cmd: commands only supported with DMA." " Interrupt-driven commands not yet implemented.\n"); retval = -EIO; } else { retval = ni_tio_cmd_setup(counter, cmd); if (retval == 0) { if (cmd->flags & A4L_CMD_WRITE) { retval = ni_tio_output_cmd(counter, cmd); } else { retval = ni_tio_input_cmd(counter, cmd); } } } rtdm_lock_put_irqrestore(&counter->lock, flags); return retval; } struct a4l_cmd_desc a4l_ni_tio_cmd_mask = { .idx_subd = 0, .start_src = TRIG_NOW | TRIG_INT | TRIG_OTHER | TRIG_EXT, .scan_begin_src = TRIG_FOLLOW | TRIG_EXT | TRIG_OTHER, .convert_src = TRIG_NOW | TRIG_EXT | TRIG_OTHER, .scan_end_src = TRIG_COUNT, .stop_src = TRIG_NONE, }; int a4l_ni_tio_cmdtest(struct ni_gpct *counter, struct a4l_cmd_desc *cmd) { /* Make sure trigger sources are trivially valid */ if ((cmd->start_src & TRIG_EXT) != 0 && ni_tio_counting_mode_registers_present(counter->counter_dev) == 0) return -EINVAL; /* Make sure trigger sources are mutually compatible */ if (cmd->convert_src != TRIG_NOW && cmd->scan_begin_src != TRIG_FOLLOW) return -EINVAL; /* Make sure arguments are trivially compatible */ if (cmd->start_src != TRIG_EXT) { if (cmd->start_arg != 0) { return -EINVAL; } } if (cmd->scan_begin_src != TRIG_EXT) { if (cmd->scan_begin_arg) { return -EINVAL; } } if (cmd->convert_src != TRIG_EXT) { if (cmd->convert_arg) { return -EINVAL; } } if (cmd->scan_end_arg != cmd->nb_chan) { return -EINVAL; } if (cmd->stop_src == TRIG_NONE) { if (cmd->stop_arg != 0) { return -EINVAL; } } return 0; } int a4l_ni_tio_cancel(struct ni_gpct *counter) { unsigned long flags; ni_tio_arm(counter, 0, 0); rtdm_lock_get_irqsave(&counter->lock, flags); if (counter->mite_chan) { a4l_mite_dma_disarm(counter->mite_chan); } rtdm_lock_put_irqrestore(&counter->lock, flags); ni_tio_configure_dma(counter, 0, 0); ni_tio_set_bits(counter, NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index), Gi_Gate_Interrupt_Enable_Bit(counter->counter_index), 0x0); return 0; } /* During buffered input counter operation for e-series, the gate interrupt is acked automatically by the dma controller, due to the Gi_Read/Write_Acknowledges_IRQ bits in the input select register. */ static int should_ack_gate(struct ni_gpct *counter) { unsigned long flags; int retval = 0; switch (counter->counter_dev->variant) { case ni_gpct_variant_m_series: case ni_gpct_variant_660x: /* Not sure if 660x really supports gate interrupts (the bits are not listed in register-level manual) */ return 1; break; case ni_gpct_variant_e_series: rtdm_lock_get_irqsave(&counter->lock, flags); { if (counter->mite_chan == NULL || counter->mite_chan->dir != A4L_INPUT || (a4l_mite_done(counter->mite_chan))) { retval = 1; } } rtdm_lock_put_irqrestore(&counter->lock, flags); break; } return retval; } void a4l_ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, int *tc_error, int *perm_stale_data, int *stale_data) { const unsigned short gxx_status = read_register(counter, NITIO_Gxx_Status_Reg(counter->counter_index)); const unsigned short gi_status = read_register(counter, NITIO_Gi_Status_Reg(counter->counter_index)); unsigned ack = 0; if (gate_error) *gate_error = 0; if (tc_error) *tc_error = 0; if (perm_stale_data) *perm_stale_data = 0; if (stale_data) *stale_data = 0; if (gxx_status & Gi_Gate_Error_Bit(counter->counter_index)) { ack |= Gi_Gate_Error_Confirm_Bit(counter->counter_index); if (gate_error) { /* 660x don't support automatic acknowledgement of gate interrupt via dma read/write and report bogus gate errors */ if (counter->counter_dev->variant != ni_gpct_variant_660x) { *gate_error = 1; } } } if (gxx_status & Gi_TC_Error_Bit(counter->counter_index)) { ack |= Gi_TC_Error_Confirm_Bit(counter->counter_index); if (tc_error) *tc_error = 1; } if (gi_status & Gi_TC_Bit) { ack |= Gi_TC_Interrupt_Ack_Bit; } if (gi_status & Gi_Gate_Interrupt_Bit) { if (should_ack_gate(counter)) ack |= Gi_Gate_Interrupt_Ack_Bit; } if (ack) write_register(counter, ack, NITIO_Gi_Interrupt_Acknowledge_Reg(counter-> counter_index)); if (ni_tio_get_soft_copy(counter, NITIO_Gi_Mode_Reg(counter-> counter_index)) & Gi_Loading_On_Gate_Bit) { if (gxx_status & Gi_Stale_Data_Bit(counter->counter_index)) { if (stale_data) *stale_data = 1; } if (read_register(counter, NITIO_Gxx_Joint_Status2_Reg(counter-> counter_index)) & Gi_Permanent_Stale_Bit(counter->counter_index)) { __a4l_err("%s: Gi_Permanent_Stale_Data detected.\n", __FUNCTION__); if (perm_stale_data) *perm_stale_data = 1; } } } /* TODO: to be adapted after a4l_buf_evt review */ void a4l_ni_tio_handle_interrupt(struct ni_gpct *counter, struct a4l_device *dev) { unsigned gpct_mite_status; unsigned long flags; int gate_error; int tc_error; int perm_stale_data; struct a4l_subdevice *subd = a4l_get_subd(dev, NI_GPCT_SUBDEV(counter->counter_index)); a4l_ni_tio_acknowledge_and_confirm(counter, &gate_error, &tc_error, &perm_stale_data, NULL); if (gate_error) { __a4l_err("%s: Gi_Gate_Error detected.\n", __FUNCTION__); a4l_buf_evt(subd, A4L_BUF_ERROR); } if (perm_stale_data) { a4l_buf_evt(subd, A4L_BUF_ERROR); } switch (counter->counter_dev->variant) { case ni_gpct_variant_m_series: case ni_gpct_variant_660x: if (read_register(counter, NITIO_Gi_DMA_Status_Reg(counter->counter_index)) & Gi_DRQ_Error_Bit) { __a4l_err("%s: Gi_DRQ_Error detected.\n", __FUNCTION__); a4l_buf_evt(subd, A4L_BUF_ERROR); } break; case ni_gpct_variant_e_series: break; } rtdm_lock_get_irqsave(&counter->lock, flags); if (counter->mite_chan == NULL) { rtdm_lock_put_irqrestore(&counter->lock, flags); return; } gpct_mite_status = a4l_mite_get_status(counter->mite_chan); if (gpct_mite_status & CHSR_LINKC) { writel(CHOR_CLRLC, counter->mite_chan->mite->mite_io_addr + MITE_CHOR(counter->mite_chan->channel)); } a4l_mite_sync_input_dma(counter->mite_chan, subd); rtdm_lock_put_irqrestore(&counter->lock, flags); } void a4l_ni_tio_set_mite_channel(struct ni_gpct *counter, struct mite_channel *mite_chan) { unsigned long flags; rtdm_lock_get_irqsave(&counter->lock, flags); counter->mite_chan = mite_chan; rtdm_lock_put_irqrestore(&counter->lock, flags); } #endif /* CONFIG_XENO_DRIVERS_ANALOGY_NI_MITE */ static int __init ni_tio_init_module(void) { return 0; } static void __exit ni_tio_cleanup_module(void) { } MODULE_DESCRIPTION("Analogy support for NI general-purpose counters"); MODULE_LICENSE("GPL"); module_init(ni_tio_init_module); module_exit(ni_tio_cleanup_module); EXPORT_SYMBOL_GPL(a4l_ni_tio_rinsn); EXPORT_SYMBOL_GPL(a4l_ni_tio_winsn); EXPORT_SYMBOL_GPL(a4l_ni_tio_insn_config); EXPORT_SYMBOL_GPL(a4l_ni_tio_init_counter); EXPORT_SYMBOL_GPL(a4l_ni_gpct_device_construct); EXPORT_SYMBOL_GPL(a4l_ni_gpct_device_destroy); #if (defined(CONFIG_XENO_DRIVERS_ANALOGY_NI_MITE) || \ defined(CONFIG_XENO_DRIVERS_ANALOGY_NI_MITE_MODULE)) EXPORT_SYMBOL_GPL(a4l_ni_tio_input_inttrig); EXPORT_SYMBOL_GPL(a4l_ni_tio_cmd); EXPORT_SYMBOL_GPL(a4l_ni_tio_cmd_mask); EXPORT_SYMBOL_GPL(a4l_ni_tio_cmdtest); EXPORT_SYMBOL_GPL(a4l_ni_tio_cancel); EXPORT_SYMBOL_GPL(a4l_ni_tio_handle_interrupt); EXPORT_SYMBOL_GPL(a4l_ni_tio_set_mite_channel); EXPORT_SYMBOL_GPL(a4l_ni_tio_acknowledge_and_confirm); #endif /* CONFIG_XENO_DRIVERS_ANALOGY_NI_MITE */