From: Frank Mori Hess <fmhess@speakeasy.net> Date: Thu, 14 Dec 2006 19:43:26 +0000 (+0000) Subject: Made setting of gate sources more uniform across different hardware X-Git-Tag: r0_7_74~135 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=4b4acaeb3c29f5b3b419b14b4eb99ac822475c09;p=comedi.git Made setting of gate sources more uniform across different hardware families. --- diff --git a/comedi/drivers/ni_tio.c b/comedi/drivers/ni_tio.c index 47c4d013..b856e526 100644 --- a/comedi/drivers/ni_tio.c +++ b/comedi/drivers/ni_tio.c @@ -2,6 +2,8 @@ comedi/drivers/ni_tio.c Support for NI general purpose counters + Copyright (C) 2006 Frank Mori Hess <fmhess@users.sourceforge.net> + This program 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 @@ -294,7 +296,7 @@ enum Gi_Command_Reg_Bits Gi_Up_Down_Hardware_IO_Bits = 0x2 << Gi_Up_Down_Shift, Gi_Up_Down_Hardware_Gate_Bits = 0x3 << Gi_Up_Down_Shift, Gi_Write_Switch_Bit = 0x80, - Gi_Synchronize_Gate_Bit = 0x100, + Gi_Synchronize_Gate_Bit = 0x100, /*FIXME: use as appropriate*/ Gi_Little_Big_Endian_Bit = 0x200, Gi_Bank_Switch_Start_Bit = 0x400, Gi_Bank_Switch_Mode_Bit = 0x800, @@ -320,10 +322,55 @@ enum Gi_Counting_Mode_Reg_Bits Gi_Index_Phase_LowA_HighB = 0x1 << Gi_Index_Phase_Bitshift, Gi_Index_Phase_HighA_LowB = 0x2 << Gi_Index_Phase_Bitshift, Gi_Index_Phase_HighA_HighB = 0x3 << Gi_Index_Phase_Bitshift, - Gi_Prescale_Bit = 0x1000, + Gi_HW_Arm_Enable_Bit = 0x80, /* from m-series example code, not documented in 660x register level manual */ + Gi_660x_HW_Arm_Select_Mask = 0x700, /* from m-series example code, not documented in 660x register level manual */ + Gi_660x_Prescale_X8_Bit = 0x1000, + Gi_M_Series_Prescale_X8_Bit = 0x2000, + Gi_M_Series_HW_Arm_Select_Mask = 0x1f00, /* must be set for clocks over 40MHz, which includes synchronous counting and quadrature modes */ - Gi_Alternate_Sync_Bit = 0x2000 + Gi_660x_Alternate_Sync_Bit = 0x2000, + Gi_M_Series_Alternate_Sync_Bit = 0x4000, + Gi_660x_Prescale_X2_Bit = 0x4000, /* from m-series example code, not documented in 660x register level manual */ + Gi_M_Series_Prescale_X2_Bit = 0x8000, }; +static inline unsigned Gi_Alternate_Sync_Bit(enum ni_gpct_variant variant) +{ + switch(variant) + { + case ni_gpct_variant_e_series: + return 0; + break; + case ni_gpct_variant_m_series: + return Gi_M_Series_Alternate_Sync_Bit; + break; + case ni_gpct_variant_660x: + return Gi_660x_Alternate_Sync_Bit; + break; + default: + BUG(); + break; + } + return 0; +} +static inline unsigned Gi_Prescale_X8_Bit(enum ni_gpct_variant variant) +{ + switch(variant) + { + case ni_gpct_variant_e_series: + return 0; + break; + case ni_gpct_variant_m_series: + return Gi_M_Series_Prescale_X8_Bit; + break; + case ni_gpct_variant_660x: + return Gi_660x_Prescale_X8_Bit; + break; + default: + BUG(); + break; + } + return 0; +} /* clock sources for ni_660x boards, get bits with Gi_Source_Select_Bits() */ enum ni_660x_clock_source @@ -359,7 +406,7 @@ enum ni_m_series_clock_source NI_M_Series_PXI_Star_Trigger_Clock = 0x14, /* when Gi_Src_SubSelect = 1 */ NI_M_Series_PXI10_Clock = 0x1d, NI_M_Series_Timebase_3_Clock = 0x1e, /* 80MHz, when Gi_Src_SubSelect = 0 */ - NI_M_Series_Analog_Trigger_Clock = 0x1e, /* when Gi_Src_SubSelect = 1 */ + NI_M_Series_Analog_Trigger_Out_Clock = 0x1e, /* when Gi_Src_SubSelect = 1 */ NI_M_Series_Logic_Low_Clock = 0x1f, }; static const unsigned ni_m_series_max_pfi_channel = 15; @@ -377,18 +424,59 @@ static inline unsigned NI_M_Series_RTSI_Clock(unsigned n) else return 0xb + n; } +enum ni_660x_gate_select +{ + NI_660x_Source_Pin_i_Gate_Select = 0x0, + NI_660x_Gate_Pin_i_Gate_Select = 0x1, + NI_660x_Next_SRC_Gate_Select = 0xa, + NI_660x_Next_Out_Gate_Select = 0x14, + NI_660x_Logic_Low_Gate_Select = 0x1f, +}; +static const unsigned ni_660x_max_gate_pin = 7; +static inline unsigned NI_660x_Gate_Pin_Gate_Select(unsigned n) +{ + BUG_ON(n > ni_660x_max_gate_pin); + return 0x2 + n; +} +static inline unsigned NI_660x_RTSI_Gate_Select(unsigned n) +{ + BUG_ON(n > ni_660x_max_rtsi_channel); + return 0xb + n; +} + +enum ni_m_series_gate_select +{ + NI_M_Series_Timestamp_Mux_Gate_Select = 0x0, + NI_M_Series_AI_START2_Gate_Select = 0x12, + NI_M_Series_PXI_Star_Trigger_Gate_Select = 0x13, + NI_M_Series_Next_Out_Gate_Select = 0x14, + NI_M_Series_AI_START1_Gate_Select = 0x1c, + NI_M_Series_Next_SRC_Gate_Select = 0x1d, + NI_M_Series_Analog_Trigger_Out_Gate_Select = 0x1e, + NI_M_Series_Logic_Low_Gate_Select = 0x1f, +}; +static inline unsigned NI_M_Series_RTSI_Gate_Select(unsigned n) +{ + BUG_ON(n > ni_m_series_max_rtsi_channel); + if(n == 7) + return 0x1b; + return 0xb + n; +} +static inline unsigned NI_M_Series_PFI_Gate_Select(unsigned n) +{ + BUG_ON(n > ni_m_series_max_pfi_channel); + if(n < 10) + return 1 + n; + return 0xb + n; +} + #define Gi_Source_Select_Shift 2 #define Gi_Gate_Select_Shift 7 /*FIXME: these gates are 660x specific. See m-series example code for its gates/sources*/ enum Gi_Input_Select_Bits { Gi_Source_Select_Mask = 0x7c, - Gi_Gate_Select_Mask = 0xf80, - Gi_Gate_Select_Source_Pin_Bits = 0x0 << Gi_Gate_Select_Shift, - Gi_Gate_Select_Gate_Pin_i_Bits = 0x1 << Gi_Gate_Select_Shift, - Gi_Gate_Select_Next_SRC_Bits = 0xa << Gi_Gate_Select_Shift, - Gi_Gate_Select_Next_Out_Bits = 0x14 << Gi_Gate_Select_Shift, - Gi_Gate_Select_Logic_Low_Bits = 0x1e << Gi_Gate_Select_Shift, + Gi_Gate_Select_Mask = 0x1f << Gi_Gate_Select_Shift, Gi_Gate_Select_Load_Source_Bit = 0x1000, Gi_Or_Gate_Bit = 0x2000, Gi_Output_Polarity_Bit = 0x4000, /* set to invert */ @@ -398,15 +486,9 @@ static inline unsigned Gi_Source_Select_Bits(unsigned source) { return (source << Gi_Source_Select_Shift) & Gi_Source_Select_Mask; } -static inline unsigned Gi_Gate_Select_Gate_Pin_Bits(unsigned n) -{ - BUG_ON(n > 7); - return (0x2 + n) << Gi_Gate_Select_Shift; -} -static inline unsigned Gi_Gate_Select_RTSI_Bits(unsigned n) +static inline unsigned Gi_Gate_Select_Bits(unsigned gate_select) { - BUG_ON(n > 6); - return (0xb + n) << Gi_Gate_Select_Shift; + return (gate_select << Gi_Gate_Select_Shift) & Gi_Gate_Select_Mask; } enum Gi_Mode_Bits @@ -441,32 +523,42 @@ enum Gi_Mode_Bits Gi_Loading_On_Gate_Bit = 0x4000, Gi_Reload_Source_Switching_Bit = 0x8000 }; + +enum ni_660x_second_gate_select +{ + NI_660x_Source_Pin_i_Second_Gate_Select = 0x0, + NI_660x_Up_Down_Pin_i_Second_Gate_Select = 0x1, + NI_660x_Next_SRC_Second_Gate_Select = 0xa, + NI_660x_Next_Out_Second_Gate_Select = 0x14, + NI_660x_Selected_Gate_Second_Gate_Select = 0x1e, + NI_660x_Logic_Low_Second_Gate_Select = 0x1f, +}; +static const unsigned ni_660x_max_up_down_pin = 7; +static inline unsigned NI_660x_Up_Down_Pin_Second_Gate_Select(unsigned n) +{ + BUG_ON(n > ni_660x_max_up_down_pin); + return 0x2 + n; +} +static inline unsigned NI_660x_RTSI_Second_Gate_Select(unsigned n) +{ + BUG_ON(n > ni_660x_max_rtsi_channel); + return 0xb + n; +} + #define Gi_Second_Gate_Select_Shift 7 -/*FIXME: these gates are 660x specific. See m-series example code for its gates/sources*/ /*FIXME: m-series has a second gate subselect bit */ +/*FIXME: m-series second gate sources are undocumented (by NI)*/ enum Gi_Second_Gate_Bits { Gi_Second_Gate_Mode_Bit = 0x1, - Gi_Second_Gate_Select_Mask = 0xf80, - Gi_Second_Gate_Select_Source_Pin_i_Bits = 0x0 << Gi_Second_Gate_Select_Shift, - Gi_Second_Gate_Select_Up_Down_Pin_i_Bits = 0x1 << Gi_Second_Gate_Select_Shift, - Gi_Second_Gate_Select_Next_SRC_Bits = 0xa << Gi_Second_Gate_Select_Shift, - Gi_Second_Gate_Select_Next_Out_Bits = 0x14 << Gi_Second_Gate_Select_Shift, - Gi_Second_Gate_Select_Selected_Gate_Bits = 0x1e << Gi_Second_Gate_Select_Shift, - Gi_Second_Gate_Select_Logic_Low_Bits = 0x1f << Gi_Second_Gate_Select_Shift, + Gi_Second_Gate_Select_Mask = 0x1f << Gi_Second_Gate_Select_Shift, Gi_Second_Gate_Polarity_Bit = 0x2000, Gi_Second_Gate_Subselect_Bit = 0x4000, /* m-series only */ Gi_Source_Subselect_Bit = 0x8000 /* m-series only */ }; -static inline unsigned Gi_Second_Gate_Select_Up_Down_Pin_Bits(unsigned n) -{ - BUG_ON(n > 7); - return (0x2 + n) << 7; -} -static inline unsigned Gi_Second_Gate_Select_RTSI_Bits(unsigned n) +static inline unsigned Gi_Second_Gate_Select_Bits(unsigned second_gate_select) { - BUG_ON(n > 6); - return (0xb + n) << 7; + return (second_gate_select << Gi_Second_Gate_Select_Shift) & Gi_Second_Gate_Select_Mask; } enum Gxx_Status_Bits @@ -584,10 +676,10 @@ static void ni_tio_set_sync_mode(struct ni_gpct *counter, int force_alt_sync) if(force_alt_sync || (counter->clock_period_ps && counter->clock_period_ps < min_normal_sync_period_ps)) { - counter->regs[counting_mode_reg] |= Gi_Alternate_Sync_Bit; + counter->regs[counting_mode_reg] |= Gi_Alternate_Sync_Bit(counter->variant); }else { - counter->regs[counting_mode_reg] &= ~Gi_Alternate_Sync_Bit; + counter->regs[counting_mode_reg] &= ~Gi_Alternate_Sync_Bit(counter->variant); } counter->write_register(counter, counter->regs[counting_mode_reg], counting_mode_reg); } @@ -606,6 +698,10 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode) switch(mode & NI_GPCT_RELOAD_SOURCE_MASK) { + case NI_GPCT_RELOAD_SOURCE_FIXED_BITS: + counter->regs[mode_reg] &= ~Gi_Reload_Source_Switching_Bit; + counter->regs[input_select_reg] &= ~Gi_Gate_Select_Load_Source_Bit; + break; case NI_GPCT_RELOAD_SOURCE_SWITCHING_BITS: counter->regs[mode_reg] |= Gi_Reload_Source_Switching_Bit; counter->regs[input_select_reg] &= ~Gi_Gate_Select_Load_Source_Bit; @@ -757,8 +853,8 @@ static unsigned ni_m_series_source_select_bits(lsampl_t clock_source) 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_CLOCK_SRC_BITS: - ni_m_series_clock = NI_M_Series_Analog_Trigger_Clock; + 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) @@ -821,7 +917,7 @@ static void ni_tio_set_second_source_select(struct ni_gpct *counter, lsampl_t cl counter->regs[second_gate_reg] &= ~Gi_Source_Subselect_Bit; break; /* Gi_Source_Subselect is one */ - case NI_GPCT_ANALOG_TRIGGER_CLOCK_SRC_BITS: + case NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS: case NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS: counter->regs[second_gate_reg] |= Gi_Source_Subselect_Bit; break; @@ -838,6 +934,8 @@ static int ni_tio_set_clock_src(struct ni_gpct *counter, lsampl_t clock_source, const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index); /*FIXME: add support for prescale in counting mode register */ +/*FIXME: add support for prescale x2*/ +/*FIXME: is clock period specified before or after prescaling? */ /*FIXME: validate clock source */ counter->regs[input_select_reg] &= ~Gi_Source_Select_Mask; switch(counter->variant) @@ -864,9 +962,9 @@ static int ni_tio_set_clock_src(struct ni_gpct *counter, lsampl_t clock_source, const unsigned counting_mode_reg = NITIO_Gi_Counting_Mode_Reg(counter->counter_index); if(clock_source & NI_GPCT_PRESCALE_CLOCK_SRC_BIT) - counter->regs[counting_mode_reg] |= Gi_Prescale_Bit; + counter->regs[counting_mode_reg] |= Gi_Prescale_X8_Bit(counter->variant); else - counter->regs[counting_mode_reg] &= ~Gi_Prescale_Bit; + counter->regs[counting_mode_reg] &= ~Gi_Prescale_X8_Bit(counter->variant); counter->write_register(counter, counter->regs[counting_mode_reg], counting_mode_reg); } ni_tio_update_clock_period(counter, clock_source, period_ns); @@ -882,9 +980,7 @@ static unsigned ni_tio_clock_src_modifiers(struct ni_gpct *counter) if(counter->regs[input_select_reg] & Gi_Source_Polarity_Bit) bits |= NI_GPCT_INVERT_CLOCK_SRC_BIT; - /* should work for e-series too, since counter->regs[counting_mode_reg] will always be zero - in that case. */ - if(counter->regs[counting_mode_reg] & Gi_Prescale_Bit) + if(counter->regs[counting_mode_reg] & Gi_Prescale_X8_Bit(counter->variant)) bits |= NI_GPCT_PRESCALE_CLOCK_SRC_BIT; return bits; } @@ -907,7 +1003,7 @@ static unsigned ni_m_series_clock_src_select(struct ni_gpct *counter) break; case NI_M_Series_Timebase_3_Clock: if(counter->regs[second_gate_reg] & Gi_Source_Subselect_Bit) - clock_source = NI_GPCT_ANALOG_TRIGGER_CLOCK_SRC_BITS; + clock_source = NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS; else clock_source = NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS; break; @@ -1026,118 +1122,475 @@ static void ni_tio_get_clock_src(struct ni_gpct *counter, lsampl_t *clock_source *period_ns = temp64; } -static int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned gate_index, lsampl_t gate_source) +static void ni_tio_set_first_gate_modifiers(struct ni_gpct *counter, lsampl_t gate_source) +{ + const unsigned mode_reg = NITIO_Gi_Mode_Reg(counter->counter_index); + + if(gate_source & CR_INVERT) + { + counter->regs[mode_reg] |= Gi_Gate_Polarity_Bit; + }else + { + counter->regs[mode_reg] &= ~Gi_Gate_Polarity_Bit; + } + counter->regs[mode_reg] &= ~Gi_Gating_Mode_Mask; + if(gate_source & CR_EDGE) + { + counter->regs[mode_reg] |= Gi_Level_Gating_Bits; + }else + { + counter->regs[mode_reg] |= Gi_Rising_Edge_Gating_Bits; + } + counter->write_register(counter, counter->regs[mode_reg], mode_reg); +} + +static int ni_660x_set_first_gate(struct ni_gpct *counter, lsampl_t gate_source) { const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index); + const unsigned selected_gate = CR_CHAN(gate_source); + /* bits of selected_gate that may be meaningful to input select register */ + const unsigned 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; + } + } + for(i = 0; i <= ni_660x_max_source_pin; ++i) + { + if(selected_gate == NI_GPCT_UP_DOWN_PIN_GATE_SELECT(i)) + { + ni_660x_gate_select = selected_gate & selected_gate_mask; + break; + } + } + return -EINVAL; + break; + } + counter->regs[input_select_reg] &= ~Gi_Gate_Select_Mask; + counter->regs[input_select_reg] |= Gi_Gate_Select_Bits(ni_660x_gate_select); + counter->write_register(counter, counter->regs[input_select_reg], input_select_reg); + return 0; +} + +static int ni_m_series_set_first_gate(struct ni_gpct *counter, lsampl_t gate_source) +{ + const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index); + const unsigned selected_gate = CR_CHAN(gate_source); + /* bits of selected_gate that may be meaningful to input select register */ + const unsigned selected_gate_mask = 0x1f; + unsigned ni_m_series_gate_select; + unsigned i; + + switch(selected_gate) + { + 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; + } + } + 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; + } + } + return -EINVAL; + break; + } + counter->regs[input_select_reg] &= ~Gi_Gate_Select_Mask; + counter->regs[input_select_reg] |= Gi_Gate_Select_Bits(ni_m_series_gate_select); + counter->write_register(counter, counter->regs[input_select_reg], input_select_reg); + return 0; +} + +static int ni_660x_set_second_gate(struct ni_gpct *counter, lsampl_t gate_source) +{ + const unsigned second_gate_reg = NITIO_Gi_Second_Gate_Reg(counter->counter_index); + const unsigned selected_second_gate = CR_CHAN(gate_source); + /* bits of second_gate that may be meaningful to second gate register */ + static const unsigned selected_second_gate_mask = 0x1f; + unsigned ni_660x_second_gate_select; + unsigned i; + + 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; + } + } + for(i = 0; i <= ni_660x_max_source_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; + } + } + return -EINVAL; + break; + }; + counter->regs[second_gate_reg] |= Gi_Second_Gate_Mode_Bit; + counter->regs[second_gate_reg] &= ~Gi_Second_Gate_Select_Mask; + counter->regs[second_gate_reg] |= Gi_Second_Gate_Select_Bits(ni_660x_second_gate_select); + counter->write_register(counter, counter->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) +{ + const unsigned second_gate_reg = NITIO_Gi_Second_Gate_Reg(counter->counter_index); + const unsigned selected_second_gate = CR_CHAN(gate_source); + /* bits of second_gate that may be meaningful to second gate register */ + static const unsigned selected_second_gate_mask = 0x1f; + unsigned 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->regs[second_gate_reg] |= Gi_Second_Gate_Mode_Bit; + counter->regs[second_gate_reg] &= ~Gi_Second_Gate_Select_Mask; + counter->regs[second_gate_reg] |= Gi_Second_Gate_Select_Bits(ni_m_series_second_gate_select); + counter->write_register(counter, counter->regs[second_gate_reg], second_gate_reg); + return 0; +} + +static int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned gate_index, lsampl_t gate_source) +{ const unsigned mode_reg = NITIO_Gi_Mode_Reg(counter->counter_index); const unsigned second_gate_reg = NITIO_Gi_Second_Gate_Reg(counter->counter_index); - unsigned gate_select_bits; - unsigned second_gate_select_bits; switch(gate_index) { case 0: - if(CR_CHAN(gate_source) == 0) + if(CR_CHAN(gate_source) == NI_GPCT_DISABLED_GATE_SELECT) { counter->regs[mode_reg] &= ~Gi_Gating_Mode_Mask; counter->regs[mode_reg] |= Gi_Gating_Disabled_Bits; counter->write_register(counter, counter->regs[mode_reg], mode_reg); + return 0; + } + ni_tio_set_first_gate_modifiers(counter, gate_source); + switch(counter->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) == 0) return -EINVAL; + if(CR_CHAN(gate_source) == NI_GPCT_DISABLED_GATE_SELECT) + { + counter->regs[second_gate_reg] &= ~Gi_Second_Gate_Mode_Bit; + counter->write_register(counter, counter->regs[second_gate_reg], second_gate_reg); + return 0; + } + if(gate_source & CR_INVERT) + { + counter->regs[second_gate_reg] |= Gi_Second_Gate_Polarity_Bit; }else { - gate_select_bits = (CR_CHAN(gate_source) - 1) << Gi_Gate_Select_Shift; - if((gate_select_bits & Gi_Gate_Select_Mask) != gate_select_bits) - return -EINVAL; - counter->regs[input_select_reg] &= ~Gi_Gate_Select_Mask; - counter->regs[input_select_reg] |= gate_select_bits; - counter->write_register(counter, counter->regs[input_select_reg], input_select_reg); - if(gate_source & CR_INVERT) + counter->regs[second_gate_reg] &= ~Gi_Second_Gate_Polarity_Bit; + } + switch(counter->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 unsigned ni_660x_first_gate_to_generic_gate_source(unsigned ni_660x_gate_select) +{ + unsigned 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)) { - counter->regs[mode_reg] |= Gi_Gate_Polarity_Bit; - }else + return NI_GPCT_RTSI_GATE_SELECT(i); + break; + } + } + for(i = 0; i <= ni_660x_max_gate_pin; ++i) + { + if(ni_660x_gate_select == NI_660x_Gate_Pin_Gate_Select(i)) { - counter->regs[mode_reg] &= ~Gi_Gate_Polarity_Bit; + return NI_GPCT_GATE_PIN_GATE_SELECT(i); + break; } - counter->regs[mode_reg] &= ~Gi_Gating_Mode_Mask; - if(gate_source & CR_EDGE) + } + BUG(); + break; + } + return 0; +}; + +static unsigned ni_m_series_first_gate_to_generic_gate_source(unsigned ni_m_series_gate_select) +{ + unsigned i; + + switch(ni_m_series_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_m_series_max_rtsi_channel; ++i) + { + if(ni_m_series_gate_select == NI_M_Series_RTSI_Gate_Select(i)) { - counter->regs[mode_reg] |= Gi_Level_Gating_Bits; - }else + return NI_GPCT_RTSI_GATE_SELECT(i); + 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)) { - counter->regs[mode_reg] |= Gi_Rising_Edge_Gating_Bits; + return NI_GPCT_PFI_GATE_SELECT(i); + break; } - counter->write_register(counter, counter->regs[mode_reg], mode_reg); } + BUG(); break; - case 1: - if(ni_tio_second_gate_registers_present(counter) == 0) return -EINVAL; - if(CR_CHAN(gate_source) == 0) - { - counter->regs[second_gate_reg] &= ~Gi_Second_Gate_Mode_Bit; - }else + } + return 0; +}; + +static unsigned ni_660x_second_gate_to_generic_gate_source(unsigned ni_660x_gate_select) +{ + unsigned 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) { - counter->regs[second_gate_reg] |= Gi_Second_Gate_Mode_Bit; - second_gate_select_bits = (CR_CHAN(gate_source) - 1) << Gi_Second_Gate_Select_Shift; - if((second_gate_select_bits & Gi_Second_Gate_Select_Mask) != second_gate_select_bits) + if(ni_660x_gate_select == NI_660x_RTSI_Second_Gate_Select(i)) { - return -EINVAL; + return NI_GPCT_RTSI_GATE_SELECT(i); + break; } - counter->regs[second_gate_reg] &= ~Gi_Second_Gate_Select_Mask; - counter->regs[second_gate_reg] |= second_gate_select_bits; - if(gate_source & CR_INVERT) + } + 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)) { - counter->regs[second_gate_reg] |= Gi_Second_Gate_Polarity_Bit; + return NI_GPCT_UP_DOWN_PIN_GATE_SELECT(i); + break; } } - counter->write_register(counter, counter->regs[second_gate_reg], second_gate_reg); + BUG(); break; + } + return 0; +}; + +static unsigned ni_m_series_second_gate_to_generic_gate_source(unsigned 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 -EINVAL; + return ni_m_series_gate_select; + break; } return 0; -} +}; static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index, lsampl_t *gate_source) { const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index); const unsigned mode_reg = NITIO_Gi_Mode_Reg(counter->counter_index); const unsigned second_gate_reg = NITIO_Gi_Second_Gate_Reg(counter->counter_index); + unsigned gate_select_bits; switch(gate_index) { case 0: if((counter->regs[mode_reg] & Gi_Gating_Mode_Mask) == Gi_Gating_Disabled_Bits) { - *gate_source = 0; + *gate_source = NI_GPCT_DISABLED_GATE_SELECT; + return 0; }else { - *gate_source = (counter->regs[input_select_reg] & Gi_Gate_Select_Mask) >> Gi_Gate_Select_Shift; - if(counter->regs[input_select_reg] & Gi_Gate_Polarity_Bit) - { - *gate_source |= CR_INVERT; - } - if((counter->regs[mode_reg] & Gi_Gating_Mode_Mask) != Gi_Level_Gating_Bits) - { - *gate_source |= CR_EDGE; - } + gate_select_bits = (counter->regs[input_select_reg] & Gi_Gate_Select_Mask) >> Gi_Gate_Select_Shift; + } + switch(counter->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(counter->regs[input_select_reg] & Gi_Gate_Polarity_Bit) + { + *gate_source |= CR_INVERT; + } + if((counter->regs[mode_reg] & Gi_Gating_Mode_Mask) != Gi_Level_Gating_Bits) + { + *gate_source |= CR_EDGE; } break; case 1: if((counter->regs[mode_reg] & Gi_Gating_Mode_Mask) == Gi_Gating_Disabled_Bits || (counter->regs[second_gate_reg] & Gi_Second_Gate_Mode_Bit) == 0) { - *gate_source = 0; + *gate_source = NI_GPCT_DISABLED_GATE_SELECT; + return 0; }else { - *gate_source = (counter->regs[second_gate_reg] & Gi_Second_Gate_Select_Mask) >> Gi_Second_Gate_Select_Shift; - if(counter->regs[second_gate_reg] & Gi_Second_Gate_Polarity_Bit) - { - *gate_source |= CR_INVERT; - } - /* second gate can't have edge/level mode set independently */ - if((counter->regs[mode_reg] & Gi_Gating_Mode_Mask) != Gi_Level_Gating_Bits) - { - *gate_source |= CR_EDGE; - } + gate_select_bits = (counter->regs[second_gate_reg] & Gi_Second_Gate_Select_Mask) >> Gi_Second_Gate_Select_Shift; + } + switch(counter->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->regs[second_gate_reg] & Gi_Second_Gate_Polarity_Bit) + { + *gate_source |= CR_INVERT; + } + /* second gate can't have edge/level mode set independently */ + if((counter->regs[mode_reg] & Gi_Gating_Mode_Mask) != Gi_Level_Gating_Bits) + { + *gate_source |= CR_EDGE; } break; default: @@ -1208,7 +1661,8 @@ int ni_tio_rinsn(struct ni_gpct *counter, command_reg); /* 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, we need to read twice and make sure the reading hasn't changed. If it has, + 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 = counter->read_register(counter, NITIO_Gi_SW_Save_Reg(counter->counter_index)); second_read = counter->read_register(counter, NITIO_Gi_SW_Save_Reg(counter->counter_index)); @@ -1257,6 +1711,7 @@ int ni_tio_winsn(struct ni_gpct *counter, break; default: return -EINVAL; + break; } return 0; } diff --git a/include/linux/comedi.h b/include/linux/comedi.h index a06e1f7e..829c7549 100644 --- a/include/linux/comedi.h +++ b/include/linux/comedi.h @@ -554,6 +554,7 @@ enum ni_gpct_mode_bits NI_GPCT_COUNTING_DIRECTION_HW_UP_DOWN_BITS = 0x2 << NI_GPCT_COUNTING_DIRECTION_SHIFT, NI_GPCT_COUNTING_DIRECTION_HW_GATE_BITS = 0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT, NI_GPCT_RELOAD_SOURCE_MASK = 0xc000000, + NI_GPCT_RELOAD_SOURCE_FIXED_BITS = 0x0, NI_GPCT_RELOAD_SOURCE_SWITCHING_BITS = 0x4000000, NI_GPCT_RELOAD_SOURCE_GATE_SELECT_BITS = 0x8000000, NI_GPCT_OR_GATE_BIT = 0x10000000, @@ -574,7 +575,7 @@ enum ni_gpct_clock_source_bits NI_GPCT_SOURCE_PIN_i_CLOCK_SRC_BITS = 0x6, /* NI 660x-specific */ NI_GPCT_PXI10_CLOCK_SRC_BITS = 0x7, NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS = 0x8, - NI_GPCT_ANALOG_TRIGGER_CLOCK_SRC_BITS = 0x9, + NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS = 0x9, /* modifier bits */ NI_GPCT_PRESCALE_CLOCK_SRC_BIT = 0x20000000, /* divide source by 8 */ NI_GPCT_INVERT_CLOCK_SRC_BIT = 0x80000000 @@ -592,6 +593,51 @@ static inline unsigned NI_GPCT_PFI_CLOCK_SRC_BITS(unsigned n) /* no pfi on NI 66 return 0x20 + n; } +/* Possibilities for setting a gate source with +INSN_CONFIG_SET_GATE_SRC when using NI general-purpose counters. +May be bitwise-or'd with CR_EDGE or CR_INVERT. */ +enum ni_gpct_gate_select +{ + /* m-series gates */ + NI_GPCT_AI_START2_GATE_SELECT = 0x12, + NI_GPCT_PXI_STAR_TRIGGER_GATE_SELECT = 0x13, + NI_GPCT_NEXT_OUT_GATE_SELECT = 0x14, + NI_GPCT_AI_START1_GATE_SELECT = 0x1c, + NI_GPCT_NEXT_SOURCE_GATE_SELECT = 0x1d, + NI_GPCT_ANALOG_TRIGGER_OUT_GATE_SELECT = 0x1e, + NI_GPCT_LOGIC_LOW_GATE_SELECT = 0x1f, + /* more gates for 660x */ + NI_GPCT_SOURCE_PIN_i_GATE_SELECT = 0x100, + NI_GPCT_GATE_PIN_i_GATE_SELECT = 0x101, + /* more gates for 660x "second gate" */ + NI_GPCT_UP_DOWN_PIN_i_GATE_SELECT = 0x201, + NI_GPCT_SELECTED_GATE_GATE_SELECT = 0x21e, + /* m-series "second gate" sources are unknown */ + NI_GPCT_DISABLED_GATE_SELECT = 0x10000, +}; +static inline unsigned NI_GPCT_GATE_PIN_GATE_SELECT(unsigned n) +{ + return 0x102 + n; +} +static inline unsigned NI_GPCT_RTSI_GATE_SELECT(unsigned n) +{ + if(n < 7) + return 0xb + n; + else + return 0x1b; +} +static inline unsigned NI_GPCT_PFI_GATE_SELECT(unsigned n) +{ + if(n < 10) + return 0x1 + n; + else + return 0xb + n; +} +static inline unsigned NI_GPCT_UP_DOWN_PIN_GATE_SELECT(unsigned n) +{ + return 0x202 + n; +} + /* master clock sources for ni mio boards and INSN_CONFIG_SET_CLOCK_SRC */ enum ni_mio_clock_source { diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 3a5ad5f5..2e7b46ae 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -28,6 +28,7 @@ typedef void irqreturn_t; #define IRQ_RETVAL(x) (void)(x) #endif +/* if interrupt handler prototype has pt_regs* parameter */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) #define PT_REGS_ARG , struct pt_regs *regs #else