From 455bf3c35c840c85392046fb4f7d0941fabafce9 Mon Sep 17 00:00:00 2001 From: Frank Mori Hess Date: Fri, 8 Dec 2006 16:53:38 +0000 Subject: [PATCH] First pass at consistent support for NI general-purpose counters. Will replace counter support in ni_mio_common.c and ni_660x.c. Note quite done yet, but it compiles. --- comedi/comedi_fops.c | 9 +- comedi/drivers/Kbuild | 11 +- comedi/drivers/Makefile.am | 10 +- comedi/drivers/das08.c | 2 +- comedi/drivers/ni_mio_common.c | 2 - comedi/drivers/ni_tio.c | 858 +++++++++++++++++++++++++++++++++ comedi/drivers/ni_tio.h | 110 +++++ include/linux/comedi.h | 91 +++- 8 files changed, 1055 insertions(+), 38 deletions(-) create mode 100644 comedi/drivers/ni_tio.c create mode 100644 comedi/drivers/ni_tio.h diff --git a/comedi/comedi_fops.c b/comedi/comedi_fops.c index 6c9a3009..59cd8955 100644 --- a/comedi/comedi_fops.c +++ b/comedi/comedi_fops.c @@ -630,6 +630,8 @@ static int check_insn_config_length(comedi_insn *insn, lsampl_t *data) { case INSN_CONFIG_DIO_OUTPUT: case INSN_CONFIG_DIO_INPUT: + case INSN_CONFIG_ARM: + case INSN_CONFIG_DISARM: if(insn->n == 1) return 0; break; case INSN_CONFIG_DIO_QUERY: @@ -637,16 +639,17 @@ static int check_insn_config_length(comedi_insn *insn, lsampl_t *data) case INSN_CONFIG_SERIAL_CLOCK: case INSN_CONFIG_BIDIRECTIONAL_DATA: case INSN_CONFIG_ALT_SOURCE: - case INSN_CONFIG_8254_SET_MODE: + case INSN_CONFIG_SET_COUNTER_MODE: case INSN_CONFIG_8254_READ_STATUS: - case INSN_CONFIG_SET_GATE_SRC: - case INSN_CONFIG_GET_GATE_SRC: case INSN_CONFIG_SET_ROUTING: case INSN_CONFIG_GET_ROUTING: if(insn->n == 2) return 0; break; + case INSN_CONFIG_SET_GATE_SRC: + case INSN_CONFIG_GET_GATE_SRC: case INSN_CONFIG_SET_CLOCK_SRC: case INSN_CONFIG_GET_CLOCK_SRC: + case INSN_CONFIG_GET_COUNTER_STATUS: if(insn->n == 3) return 0; break; case INSN_CONFIG_PWM_OUTPUT: diff --git a/comedi/drivers/Kbuild b/comedi/drivers/Kbuild index e8d50aa3..b09ffeda 100644 --- a/comedi/drivers/Kbuild +++ b/comedi/drivers/Kbuild @@ -69,16 +69,17 @@ obj-m += me_daq.o obj-m += me4000.o obj-m += mpc624.o obj-m += multiq3.o +obj-m += ni_6527.o +obj-m += ni_65xx.o obj-m += ni_660x.o obj-m += ni_670x.o +obj-m += ni_at_a2150.o +obj-m += ni_at_ao.o obj-m += ni_atmio.o +obj-m += ni_atmio16d.o obj-m += ni_pcimio.o obj-m += ni_pcidio.o -obj-m += ni_6527.o -obj-m += ni_65xx.o -obj-m += ni_atmio16d.o -obj-m += ni_at_a2150.o -obj-m += ni_at_ao.o +obj-m += ni_tio.o obj-m += pcm3724.o obj-m += pcm3730.o obj-m += pcmad.o diff --git a/comedi/drivers/Makefile.am b/comedi/drivers/Makefile.am index 4a82d442..01a8a94b 100644 --- a/comedi/drivers/Makefile.am +++ b/comedi/drivers/Makefile.am @@ -8,7 +8,8 @@ LINK = $(top_builddir)/modtool --link -o $@ \ -i .mods/comedi_fc.o.symvers \ -i .mods/das08.o.symvers \ -i .mods/mite.o.symvers \ - -i .mods/ni_labpc.o.symvers + -i .mods/ni_labpc.o.symvers \ + -i .mods/ni_tio.o.symvers 8255_ko_LINK = $(top_builddir)/modtool --link -o $@ \ -i ../.mods/comedi.o.symvers @@ -20,13 +21,15 @@ mite_ko_LINK = $(top_builddir)/modtool --link -o $@ \ -i ../.mods/comedi.o.symvers ni_labpc_ko_LINK = $(top_builddir)/modtool --link -o $@ \ -i ../.mods/comedi.o.symvers +ni_tio_ko_LINK = $(top_builddir)/modtool --link -o $@ \ + -i ../.mods/comedi.o.symvers 8255_ko_CFLAGS = $(AM_CFLAGS) -DEXPORT_SYMTAB comedi_fc_ko_CFLAGS = $(AM_CFLAGS) -DEXPORT_SYMTAB das08_ko_CFLAGS = $(AM_CFLAGS) -DEXPORT_SYMTAB mite_ko_CFLAGS = $(AM_CFLAGS) -DEXPORT_SYMTAB ni_labpc_ko_CFLAGS = $(AM_CFLAGS) -DEXPORT_SYMTAB - +ni_tio_ko_CFLAGS = $(AM_CFLAGS) -DEXPORT_SYMTAB EXTRA_DIST = \ @@ -44,6 +47,7 @@ EXTRA_DIST = \ ni_labpc.h \ ni_mio_common.c \ ni_stc.h \ + ni_tio.h \ plx9052.h \ plx9080.h \ rtd520.h \ @@ -144,6 +148,7 @@ module_PROGRAMS = \ ni_atmio16d.ko \ ni_at_a2150.ko \ ni_at_ao.ko \ + ni_tio.ko \ pcm3724.ko \ pcm3730.ko \ pcmad.ko \ @@ -241,6 +246,7 @@ ni_labpc_ko_SOURCES = ni_labpc.c ni_labpc_cs_ko_SOURCES = ni_labpc_cs.c ni_daq_dio24_ko_SOURCES = ni_daq_dio24.c ni_at_ao_ko_SOURCES = ni_at_ao.c +ni_tio_ko_SOURCES = ni_tio.c pcm3724_ko_SOURCES = pcm3724.c pcm3730_ko_SOURCES = pcm3730.c pcmad_ko_SOURCES = pcmad.c diff --git a/comedi/drivers/das08.c b/comedi/drivers/das08.c index bbd5c0aa..0f2b967c 100644 --- a/comedi/drivers/das08.c +++ b/comedi/drivers/das08.c @@ -780,7 +780,7 @@ static int das08_counter_config(comedi_device *dev,comedi_subdevice *s,comedi_in if(insn->n != 2)return -EINVAL; switch (data[0]){ - case INSN_CONFIG_8254_SET_MODE: + case INSN_CONFIG_SET_COUNTER_MODE: i8254_set_mode(&devpriv->i8254,chan,data[1]); break; case INSN_CONFIG_8254_READ_STATUS: diff --git a/comedi/drivers/ni_mio_common.c b/comedi/drivers/ni_mio_common.c index cde29e4c..df285d5e 100644 --- a/comedi/drivers/ni_mio_common.c +++ b/comedi/drivers/ni_mio_common.c @@ -3803,8 +3803,6 @@ static int pack_ad8842(int addr,int val,int *bitstring) * Low level stuff...Each STC counter has two 24 bit load registers * (A&B). Just make it easier to access them. * - * These are inlined _only_ because they are used once in subsequent - * code. Otherwise they should not be inlined. */ static inline void GPCT_Load_A(comedi_device *dev, int chan, unsigned int value) { diff --git a/comedi/drivers/ni_tio.c b/comedi/drivers/ni_tio.c new file mode 100644 index 00000000..bb545bec --- /dev/null +++ b/comedi/drivers/ni_tio.c @@ -0,0 +1,858 @@ +/* + comedi/drivers/ni_tio.c + Support for NI general purpose counters + + 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 + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* +Driver: ni_tio.o +Description: National Instruments general purpose counters +Devices: +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 +Updated: Thu Nov 16 09:50:32 EST 2006 +Status: experimental + +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. + +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: +need to provide init function(s) that will init hardware and +gpct_counter struct + + */ + +#include "ni_tio.h" + +MODULE_AUTHOR("Comedi "); +MODULE_DESCRIPTION("Comedi support for NI general-purpose counters"); +MODULE_LICENSE("GPL"); + +static inline enum ni_gpct_register NITIO_Gi_Command_Reg(unsigned counter_index) +{ + switch(counter_index) + { + case 0: + return NITIO_G0_Command_Reg; + break; + case 1: + return NITIO_G1_Command_Reg; + break; + case 2: + return NITIO_G2_Command_Reg; + break; + case 3: + return NITIO_G3_Command_Reg; + break; + default: + BUG(); + break; + } + return 0; +} + +static inline enum ni_gpct_register NITIO_Gi_Counting_Mode_Reg(unsigned counter_index) +{ + switch(counter_index) + { + case 0: + return NITIO_G0_Counting_Mode_Reg; + break; + case 1: + return NITIO_G1_Counting_Mode_Reg; + break; + case 2: + return NITIO_G2_Counting_Mode_Reg; + break; + case 3: + return NITIO_G3_Counting_Mode_Reg; + break; + default: + BUG(); + break; + } + return 0; +} + +static inline enum ni_gpct_register NITIO_Gi_Input_Select_Reg(unsigned counter_index) +{ + switch(counter_index) + { + case 0: + return NITIO_G0_Input_Select_Reg; + break; + case 1: + return NITIO_G1_Input_Select_Reg; + break; + case 2: + return NITIO_G2_Input_Select_Reg; + break; + case 3: + return NITIO_G3_Input_Select_Reg; + break; + default: + BUG(); + break; + } + return 0; +} + +static inline enum ni_gpct_register NITIO_Gxx_Joint_Reset_Reg(unsigned counter_index) +{ + switch(counter_index) + { + case 0: + case 1: + return NITIO_G01_Joint_Reset_Reg; + break; + case 2: + case 3: + return NITIO_G23_Joint_Reset_Reg; + break; + default: + BUG(); + break; + } + return 0; +} + +static inline enum ni_gpct_register NITIO_Gxx_Status_Reg(unsigned counter_index) +{ + switch(counter_index) + { + case 0: + case 1: + return NITIO_G01_Status_Reg; + break; + case 2: + case 3: + return NITIO_G23_Status_Reg; + break; + default: + BUG(); + break; + } + return 0; +} + +static inline enum ni_gpct_register NITIO_Gi_LoadA_Reg(unsigned counter_index) +{ + switch(counter_index) + { + case 0: + return NITIO_G0_LoadA_Reg; + break; + case 1: + return NITIO_G1_LoadA_Reg; + break; + case 2: + return NITIO_G2_LoadA_Reg; + break; + case 3: + return NITIO_G3_LoadA_Reg; + break; + default: + BUG(); + break; + } + return 0; +} + +static inline enum ni_gpct_register NITIO_Gi_LoadB_Reg(unsigned counter_index) +{ + switch(counter_index) + { + case 0: + return NITIO_G0_LoadB_Reg; + break; + case 1: + return NITIO_G1_LoadB_Reg; + break; + case 2: + return NITIO_G2_LoadB_Reg; + break; + case 3: + return NITIO_G3_LoadB_Reg; + break; + default: + BUG(); + break; + } + return 0; +} + +static inline enum ni_gpct_register NITIO_Gi_Mode_Reg(unsigned counter_index) +{ + switch(counter_index) + { + case 0: + return NITIO_G0_Mode_Reg; + break; + case 1: + return NITIO_G1_Mode_Reg; + break; + case 2: + return NITIO_G2_Mode_Reg; + break; + case 3: + return NITIO_G3_Mode_Reg; + break; + default: + BUG(); + break; + } + return 0; +} + +static inline enum ni_gpct_register NITIO_Gi_SW_Save_Reg(int counter_index) +{ + switch(counter_index) + { + case 0: + return NITIO_G0_SW_Save_Reg; + break; + case 1: + return NITIO_G1_SW_Save_Reg; + break; + case 2: + return NITIO_G2_SW_Save_Reg; + break; + case 3: + return NITIO_G3_SW_Save_Reg; + break; + default: + BUG(); + break; + } + return 0; +} + +static inline enum ni_gpct_register NITIO_Gi_Second_Gate_Reg(int counter_index) +{ + switch(counter_index) + { + case 0: + return NITIO_G0_Second_Gate_Reg; + break; + case 1: + return NITIO_G1_Second_Gate_Reg; + break; + case 2: + return NITIO_G2_Second_Gate_Reg; + break; + case 3: + return NITIO_G3_Second_Gate_Reg; + break; + default: + BUG(); + break; + } + return 0; +} + +enum Gi_Auto_Increment_Reg_Bits +{ + Gi_Auto_Increment_Mask = 0xff +}; + +#define Gi_Up_Down_Shift 5 +enum Gi_Command_Reg_Bits +{ + Gi_Arm_Bit = 0x1, + Gi_Save_Trace_Bit = 0x2, + Gi_Load_Bit = 0x4, + Gi_Disarm_Bit = 0x10, + Gi_Up_Down_Mask = 0x3 << Gi_Up_Down_Shift, + Gi_Always_Down_Bits = 0x0 << Gi_Up_Down_Shift, + Gi_Always_Up_Bits = 0x1 << Gi_Up_Down_Shift, + 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_Little_Big_Endian_Bit = 0x200, + Gi_Bank_Switch_Start_Bit = 0x400, + Gi_Bank_Switch_Mode_Bit = 0x800, + Gi_Bank_Switch_Enable_Bit = 0x1000, + Gi_Arm_Copy_Bit = 0x2000, + Gi_Save_Trace_Copy_Bit = 0x4000, + Gi_Disarm_Copy_Bit = 0x8000 +}; + +#define Gi_Index_Phase_Bitshift 5 +enum Gi_Counting_Mode_Reg_Bits +{ + Gi_Counting_Mode_Mask = 0x7, + Gi_Counting_Mode_Normal_Bits = 0x0, + Gi_Counting_Mode_QuadratureX1_Bits = 0x1, + Gi_Counting_Mode_QuadratureX2_Bits = 0x2, + Gi_Counting_Mode_QuadratureX4_Bits = 0x3, + Gi_Counting_Mode_Two_Pulse_Bits = 0x4, + Gi_Counting_Mode_Sync_Source_Bits = 0x6, + Gi_Index_Mode_Bit = 0x10, + Gi_Index_Phase_Mask = 0x3 << Gi_Index_Phase_Bitshift, + Gi_Index_Phase_LowA_LowB = 0x0 << Gi_Index_Phase_Bitshift, + 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, + /* must be set for clocks over 40MHz, which includes synchronous counting and quadrature modes */ + Gi_Alternate_Sync_Bit = 0x2000 +}; + +/*FIXME: these gates/sources are 660x specific. See m-series example code for its gates/sources */ +#define Gi_Source_Select_Shift 2 +#define Gi_Gate_Select_Shift 7 +enum Gi_Input_Select_Bits +{ + Gi_Source_Select_Mask = 0x7c, + Gi_Source_Select_Timebase_1_Bits = 0x0 << Gi_Source_Select_Shift, /* 20MHz */ + Gi_Source_Select_Source_Pin_i_Bits = 0x1 << Gi_Source_Select_Shift, + Gi_Source_Select_Next_Gate_Bits = 0xa << Gi_Source_Select_Shift, + Gi_Source_Select_Timebase_2_Bits = 0x12 << Gi_Source_Select_Shift, /* 100KHz */ + Gi_Source_Select_Next_TC_Bits = 0x13 << Gi_Source_Select_Shift, + Gi_Source_Select_Timebase_3_Bits = 0x1e << Gi_Source_Select_Shift, /* 80MHz */ + Gi_Source_Select_Logic_Low_Bits = 0x1f << Gi_Source_Select_Shift, + 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_Load_Source_Bit = 0x1000, + Gi_Or_Gate_Bit = 0x2000, + Gi_Output_Polarity_Bit = 0x4000, /* set to invert */ + Gi_Source_Polarity_Bit = 0x8000 /* set to invert */ +}; +static inline unsigned Gi_Source_Select_RTSI_Bits(unsigned n) +{ + BUG_ON(n > 6); + return (0xb + n) << Gi_Source_Select_Shift; +} +static inline unsigned Gi_Source_Select_Source_Pin_Bits(unsigned n) +{ + BUG_ON(n > 7); + return (0x2 + n) << Gi_Source_Select_Shift; +} +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) +{ + BUG_ON(n > 6); + return (0xb + n) << Gi_Gate_Select_Shift; +} + +enum Gi_Mode_Bits +{ + Gi_Gating_Mode_Mask = 0x3, + Gi_Gating_Disabled_Bits = 0x0, + Gi_Level_Gating_Bits = 0x1, + Gi_Rising_Edge_Gating_Bits = 0x2, + Gi_Falling_Edge_Gating_Bits = 0x2, + Gi_Gate_On_Both_Edges_Bit = 0x4, /* used in conjunction with rising edge gating mode */ + Gi_Trigger_Mode_for_Edge_Gate_Mask = 0x18, + Gi_Edge_Gate_Starts_Stops_Bits = 0x0, + Gi_Edge_Gate_Stops_Starts_Bits = 0x8, + Gi_Edge_Gate_Starts_Bits = 0x10, + Gi_Edge_Gate_No_Starts_or_Stops_Bits = 0x18, + Gi_Stop_Mode_Mask = 0x60, + Gi_Stop_on_Gate_Bits = 0x00, + Gi_Stop_on_Gate_or_TC_Bits = 0x20, + Gi_Stop_on_Gate_or_Second_TC_Bits = 0x40, + Gi_Load_Source_Select_Bit = 0x80, + Gi_Output_Mode_Mask = 0x300, + Gi_Output_TC_Pulse_Bits = 0x100, + Gi_Output_TC_Toggle_Bits = 0x200, + Gi_Output_TC_or_Gate_Toggle_Bits = 0x300, + Gi_Counting_Once_Mask = 0xc00, + Gi_No_Hardware_Disarm_Bits = 0x000, + Gi_Disarm_at_TC_Bits = 0x400, + Gi_Disarm_at_Gate_Bits = 0x800, + Gi_Disarm_at_TC_or_Gate_Bits = 0xc00, + Gi_Loading_On_TC_Bit = 0x1000, + Gi_Gate_Polarity_Bit = 0x2000, + Gi_Loading_On_Gate_Bit = 0x4000, + Gi_Reload_Source_Switching_Bit = 0x8000 +}; +#define Gi_Second_Gate_Select_Shift 7 +/*FIXME: these gates are 660x specific. See m-series example code for its gates/sources*/ +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_Polarity_Bit = 0x2000 +}; +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) +{ + BUG_ON(n > 6); + return (0xb + n) << 7; +} + +enum Gxx_Status_Bits +{ + G0_Save_Bit = 0x1, + G1_Save_Bit = 0x2, + G0_Counting_Bit = 0x4, + G1_Counting_Bit = 0x8, + G0_Next_Load_Source_Bit = 0x10, + G1_Next_Load_Source_Bit = 0x20, + G0_Stale_Data_Bit = 0x40, + G1_Stale_Data_Bit = 0x80, + G0_Armed_Bit = 0x100, + G1_Armed_Bit = 0x200, + G0_No_Load_Between_Gates_Bit = 0x400, + G1_No_Load_Between_Gates_Bit = 0x800, + G0_TC_Error_Bit = 0x1000, + G1_TC_Error_Bit = 0x2000 +}; +static inline unsigned G_Counting_Bit(unsigned counter_index) +{ + if(counter_index % 2) return G1_Counting_Bit; + return G0_Counting_Bit; +} +static inline unsigned G_Armed_Bit(unsigned counter_index) +{ + if(counter_index % 2) return G1_Armed_Bit; + return G0_Armed_Bit; +} + +static const lsampl_t counter_status_mask = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING; + +static int __init ni_tio_init_module(void) +{ + return 0; +} +module_init(ni_tio_init_module); + +static void __exit ni_tio_cleanup_module(void) +{ +} +module_exit(ni_tio_cleanup_module); + +static lsampl_t ni_tio_counter_status(struct ni_gpct *counter) +{ + lsampl_t status = 0; + const unsigned bits = counter->read_register(counter, NITIO_Gxx_Status_Reg(counter->counter_index)); + if(bits & G_Armed_Bit(counter->counter_index)) + { + status |= COMEDI_COUNTER_ARMED; + if(bits & G_Counting_Bit(counter->counter_index)) + status |= COMEDI_COUNTER_COUNTING; + } + return status; +} + +static void ni_tio_set_sync_mode(struct ni_gpct *counter, int force_alt_sync) +{ + const unsigned counting_mode_reg = NITIO_Gi_Counting_Mode_Reg(counter->counter_index); + static const unsigned min_normal_sync_period_ns = 25; + + if(counter->counting_mode_registers_present == 0) return; + + switch(counter->regs[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_ns is set to zero, so we are not + using the alt sync in that case, but allow the caller to decide by using the + force_alt_sync parameter. */ + /* FIXME: take into account possibility of the divide-by-8 prescale*/ + if(force_alt_sync || + (counter->clock_period_ns && counter->clock_period_ns < min_normal_sync_period_ns)) + { + counter->regs[counting_mode_reg] |= Gi_Alternate_Sync_Bit; + }else + { + counter->regs[counting_mode_reg] &= ~Gi_Alternate_Sync_Bit; + } + counter->write_register(counter, counter->regs[counting_mode_reg], counting_mode_reg); +} + +static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode) +{ + const unsigned counting_mode_reg = NITIO_Gi_Counting_Mode_Reg(counter->counter_index); + const unsigned mode_reg = NITIO_Gi_Mode_Reg(counter->counter_index); + const unsigned command_reg = NITIO_Gi_Command_Reg(counter->counter_index); + const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index); + /* 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; + + switch(mode & NI_GPCT_RELOAD_SOURCE_MASK) + { + 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; + break; + case NI_GPCT_RELOAD_SOURCE_GATE_SELECT_BITS: + counter->regs[input_select_reg] |= Gi_Gate_Select_Load_Source_Bit; + counter->regs[mode_reg] &= ~(Gi_Reload_Source_Switching_Bit | Gi_Gating_Mode_Mask); + counter->regs[mode_reg] |= Gi_Level_Gating_Bits; + break; + default: + break; + } + + counter->regs[mode_reg] &= ~mode_reg_direct_mask; + counter->regs[mode_reg] |= mode & mode_reg_direct_mask; + counter->write_register(counter, counter->regs[mode_reg], mode_reg); + + if(counter->counting_mode_registers_present) + { + counter->regs[counting_mode_reg] &= ~Gi_Counting_Mode_Mask; + counter->regs[counting_mode_reg] |= (mode >> NI_GPCT_COUNTING_MODE_SHIFT) & Gi_Counting_Mode_Mask; + counter->regs[counting_mode_reg] &= ~Gi_Index_Phase_Mask; + counter->regs[counting_mode_reg] |= ((mode >> NI_GPCT_INDEX_PHASE_BITSHIFT) << Gi_Index_Phase_Bitshift) & Gi_Index_Phase_Mask; + if(mode & NI_GPCT_INDEX_ENABLE_BIT) + { + counter->regs[counting_mode_reg] |= Gi_Index_Mode_Bit; + }else + { + counter->regs[counting_mode_reg] &= ~Gi_Index_Mode_Bit; + } + counter->write_register(counter, counter->regs[counting_mode_reg], counting_mode_reg); + ni_tio_set_sync_mode(counter, 0); + } + + counter->regs[command_reg] &= ~Gi_Up_Down_Mask; + counter->regs[command_reg] |= ((mode >> NI_GPCT_COUNTING_DIRECTION_SHIFT) << Gi_Up_Down_Shift) & Gi_Up_Down_Mask; + counter->write_register(counter, counter->regs[command_reg], command_reg); + + if(mode & NI_GPCT_OR_GATE_BIT) + { + counter->regs[input_select_reg] |= Gi_Or_Gate_Bit; + }else + { + counter->regs[input_select_reg] &= ~Gi_Or_Gate_Bit; + } + if(mode & NI_GPCT_INVERT_OUTPUT_BIT) + { + counter->regs[input_select_reg] |= Gi_Output_Polarity_Bit; + }else + { + counter->regs[input_select_reg] &= ~Gi_Output_Polarity_Bit; + } + counter->write_register(counter, counter->regs[input_select_reg], input_select_reg); + + return 0; +} + +static void ni_tio_arm(struct ni_gpct *counter, int arm) +{ + unsigned bits = counter->regs[NITIO_Gi_Command_Reg(counter->counter_index)]; + if(arm) + bits |= Gi_Arm_Bit; + else + bits |= Gi_Disarm_Bit; + counter->write_register(counter, bits, NITIO_Gi_Command_Reg(counter->counter_index)); +} + +static int ni_tio_set_clock_src(struct ni_gpct *counter, lsampl_t clock_source, lsampl_t period_ns) +{ + const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index); + const unsigned source_bits = CR_CHAN(clock_source) << Gi_Source_Select_Shift; + +/*FIXME: m-series has a couple extra gate sources using Gi_src_subselect bit */ +/*FIXME: add support for prescale in counting mode register */ + if((source_bits & Gi_Source_Select_Mask) != source_bits) return -EINVAL; + counter->regs[input_select_reg] &= ~Gi_Source_Select_Mask; + counter->regs[input_select_reg] |= source_bits; + if(clock_source & CR_INVERT) + counter->regs[input_select_reg] |= Gi_Source_Polarity_Bit; + else + counter->regs[input_select_reg] &= ~Gi_Source_Polarity_Bit; + counter->write_register(counter, counter->regs[input_select_reg], input_select_reg); + counter->update_clock_period(counter, clock_source, period_ns); + ni_tio_set_sync_mode(counter, 0); + return 0; +} + +static void ni_tio_get_clock_src(struct ni_gpct *counter, lsampl_t *clock_source, lsampl_t *period_ns) +{ + const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index); + *clock_source = (counter->regs[input_select_reg] & Gi_Source_Select_Mask) >> Gi_Source_Select_Shift; + *period_ns = counter->clock_period_ns; +} + +static int ni_tio_set_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; + unsigned second_gate_select_bits; + + switch(gate_index) + { + case 0: + if(CR_CHAN(gate_source) == 0) + { + 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); + }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[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); + } + break; + case 1: + if(counter->second_gate_registers_present == 0) return -EINVAL; + if(CR_CHAN(gate_source) == 0) + { + counter->regs[second_gate_reg] &= ~Gi_Second_Gate_Mode_Bit; + }else + { + 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) + { + return -EINVAL; + } + counter->regs[second_gate_reg] &= ~Gi_Second_Gate_Select_Mask; + counter->regs[second_gate_reg] |= second_gate_select_bits; + if(gate_source & CR_INVERT) + { + counter->regs[second_gate_reg] |= Gi_Second_Gate_Polarity_Bit; + } + } + counter->write_register(counter, counter->regs[second_gate_reg], second_gate_reg); + break; + default: + return -EINVAL; + } + 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); + + switch(gate_index) + { + case 0: + if((counter->regs[mode_reg] & Gi_Gating_Mode_Mask) == Gi_Gating_Disabled_Bits) + { + *gate_source = 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; + } + } + 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; + }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; + } + } + break; + default: + return -EINVAL; + break; + } + return 0; +} + +int ni_tio_insn_config(struct ni_gpct *counter, + comedi_insn *insn, + lsampl_t *data) +{ + switch(data[0]) + { + case INSN_CONFIG_SET_COUNTER_MODE: + return ni_tio_set_counter_mode(counter, data[1]); + break; + case INSN_CONFIG_ARM: + ni_tio_arm(counter, 1); + return 0; + break; + case INSN_CONFIG_DISARM: + ni_tio_arm(counter, 0); + return 0; + break; + case INSN_CONFIG_GET_COUNTER_STATUS: + data[1] = ni_tio_counter_status(counter); + data[2] = counter_status_mask; + return 0; + break; + case INSN_CONFIG_SET_CLOCK_SRC: + return ni_tio_set_clock_src(counter, data[1], data[2]); + break; + case INSN_CONFIG_GET_CLOCK_SRC: + ni_tio_get_clock_src(counter, &data[1], &data[2]); + return 0; + break; + case INSN_CONFIG_SET_GATE_SRC: + return ni_tio_set_gate_src(counter, data[1], data[2]); + break; + case INSN_CONFIG_GET_GATE_SRC: + return ni_tio_get_gate_src(counter, data[1], &data[2]); + break; + default: + break; + } + return -EINVAL; +} + +int ni_tio_rinsn(struct ni_gpct *counter, + comedi_insn *insn, + lsampl_t *data) +{ + const unsigned command_reg = NITIO_Gi_Command_Reg(counter->counter_index); + const unsigned channel = CR_CHAN(insn->chanspec); + unsigned first_read; + unsigned second_read; + unsigned correct_read; + + if(insn->n < 1) return 0; + switch(channel) + { + case 0: + counter->regs[command_reg] &= ~Gi_Save_Trace_Bit; + counter->write_register(counter, counter->regs[command_reg], command_reg); + counter->write_register(counter, counter->regs[command_reg] | Gi_Save_Trace_Bit, + 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, + 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)); + if(first_read != second_read) + correct_read = counter->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->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)]; + break; + case 2: + data[0] = counter->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)]; + break; + }; + return 0; +} + +int ni_tio_winsn(struct ni_gpct *counter, + comedi_insn *insn, + lsampl_t * data) +{ + const unsigned channel = CR_CHAN(insn->chanspec); + const unsigned command_reg = NITIO_Gi_Command_Reg(counter->counter_index); + const unsigned mode_reg = NITIO_Gi_Mode_Reg(counter->counter_index); + + if(insn->n < 1) return 0; + switch(channel) + { + case 0: + counter->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)] = data[0]; + counter->write_register(counter, data[0], NITIO_Gi_LoadA_Reg(counter->counter_index)); + counter->regs[mode_reg] &= ~Gi_Load_Source_Select_Bit; + counter->write_register(counter, counter->regs[mode_reg], mode_reg); + counter->write_register(counter, counter->regs[command_reg] | Gi_Load_Bit, command_reg); + break; + case 1: + counter->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)] = data[0]; + counter->write_register(counter, data[0], NITIO_Gi_LoadA_Reg(counter->counter_index)); + break; + case 2: + counter->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)] = data[0]; + counter->write_register(counter, data[0], NITIO_Gi_LoadB_Reg(counter->counter_index)); + break; + default: + return -EINVAL; + } + return 0; +} diff --git a/comedi/drivers/ni_tio.h b/comedi/drivers/ni_tio.h new file mode 100644 index 00000000..95201987 --- /dev/null +++ b/comedi/drivers/ni_tio.h @@ -0,0 +1,110 @@ +/* + drivers/ni_tio.h + Header file for NI general purpose counter support code (ni_tio.c) + + COMEDI - Linux Control and Measurement Device Interface + + 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 + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef _COMEDI_NI_TIO_H +#define _COMEDI_NI_TIO_H + +#include + +enum ni_gpct_register +{ + NITIO_G0_Autoincrement_Reg, + NITIO_G1_Autoincrement_Reg, + NITIO_G2_Autoincrement_Reg, + NITIO_G3_Autoincrement_Reg, + NITIO_G0_Command_Reg, + NITIO_G1_Command_Reg, + NITIO_G2_Command_Reg, + NITIO_G3_Command_Reg, + NITIO_G0_HW_Save_Reg, + NITIO_G1_HW_Save_Reg, + NITIO_G2_HW_Save_Reg, + NITIO_G3_HW_Save_Reg, + NITIO_G0_SW_Save_Reg, + NITIO_G1_SW_Save_Reg, + NITIO_G2_SW_Save_Reg, + NITIO_G3_SW_Save_Reg, + NITIO_G0_Mode_Reg, + NITIO_G1_Mode_Reg, + NITIO_G2_Mode_Reg, + NITIO_G3_Mode_Reg, + NITIO_G0_LoadA_Reg, + NITIO_G1_LoadA_Reg, + NITIO_G2_LoadA_Reg, + NITIO_G3_LoadA_Reg, + NITIO_G0_LoadB_Reg, + NITIO_G1_LoadB_Reg, + NITIO_G2_LoadB_Reg, + NITIO_G3_LoadB_Reg, + NITIO_G0_Input_Select_Reg, + NITIO_G1_Input_Select_Reg, + NITIO_G2_Input_Select_Reg, + NITIO_G3_Input_Select_Reg, + NITIO_G0_Counting_Mode_Reg, + NITIO_G1_Counting_Mode_Reg, + NITIO_G2_Counting_Mode_Reg, + NITIO_G3_Counting_Mode_Reg, + NITIO_G0_Second_Gate_Reg, + NITIO_G1_Second_Gate_Reg, + NITIO_G2_Second_Gate_Reg, + NITIO_G3_Second_Gate_Reg, + NITIO_G01_Status_Reg, + NITIO_G23_Status_Reg, + NITIO_G01_Joint_Reset_Reg, + NITIO_G23_Joint_Reset_Reg, + NITIO_G01_Joint_Status1_Reg, + NITIO_G23_Joint_Status1_Reg, + NITIO_G01_Joint_Status2_Reg, + NITIO_G23_Joint_Status2_Reg, + NITIO_Num_Registers, +}; + +#define MAX_NUM_NITIO_REGS 0x40 +struct ni_gpct +{ + comedi_device *dev; + unsigned counter_index; + unsigned chip_index; + void (*write_register)(struct ni_gpct *this, unsigned bits, enum ni_gpct_register); + unsigned (*read_register)(struct ni_gpct *this, enum ni_gpct_register); + /* update_clock_period() should update the clock_period_ns field appropriately for the + given source. It is needed since the different hardware families provide different + clock sources. */ + void (*update_clock_period)(struct ni_gpct *this, lsampl_t clock_source, lsampl_t period_ns); + lsampl_t clock_period_ns; + unsigned counting_mode_registers_present : 1; + unsigned second_gate_registers_present : 1; + unsigned regs[MAX_NUM_NITIO_REGS]; +}; + +extern int ni_tio_rinsn(struct ni_gpct *counter, + comedi_insn *insn, + lsampl_t *data); +extern int ni_tio_insn_config(struct ni_gpct *counter, + comedi_insn *insn, + lsampl_t *data); +extern int ni_tio_winsn(struct ni_gpct *counter, + comedi_insn *insn, + lsampl_t * data); + +#endif /* _COMEDI_NI_TIO_H */ + diff --git a/include/linux/comedi.h b/include/linux/comedi.h index e6371773..6d6b200f 100644 --- a/include/linux/comedi.h +++ b/include/linux/comedi.h @@ -239,6 +239,9 @@ enum configuration_ids INSN_CONFIG_DIO_QUERY = 28, INSN_CONFIG_PWM_OUTPUT = 29, INSN_CONFIG_GET_PWM_OUTPUT = 30, + INSN_CONFIG_ARM = 31, + INSN_CONFIG_DISARM = 32, + INSN_CONFIG_GET_COUNTER_STATUS = 33, INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR = 1001, // Use CTR as single pulsegenerator INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR = 1002, // Use CTR as pulsetraingenerator INSN_CONFIG_GPCT_QUADRATURE_ENCODER = 1003, // Use the counter as encoder @@ -246,7 +249,8 @@ enum configuration_ids INSN_CONFIG_GET_GATE_SRC = 2002, // Get gate source INSN_CONFIG_SET_CLOCK_SRC = 2003, // Set master clock source INSN_CONFIG_GET_CLOCK_SRC = 2004, // Get master clock source - INSN_CONFIG_8254_SET_MODE = 4097, + INSN_CONFIG_SET_COUNTER_MODE = 4097, + INSN_CONFIG_8254_SET_MODE = INSN_CONFIG_SET_COUNTER_MODE, /* deprecated */ INSN_CONFIG_8254_READ_STATUS = 4098, INSN_CONFIG_SET_ROUTING = 4099, INSN_CONFIG_GET_ROUTING = 4109, @@ -473,35 +477,12 @@ struct comedi_bufinfo_struct{ // Reset when index pulse arrives? #define GPCT_RESET_COUNTER_ON_INDEX 1 -/* - Counter clock and gate source configuration. - - Four config commands to set/get the gate/clock source for a counter channel: - - 0 ID: INSN_CONFIG_SET_GATE_SRC - 1 gate source - - 0 ID: INSN_CONFIG_GET_GATE_SRC - 1 <-- Current gate source returned here. - - 0 ID: INSN_CONFIG_SET_CLOCK_SRC - 1 clock source - - 0 ID: INSN_CONFIG_GET_CLOCK_SRC - 1 <-- Current clock source returned here. - - Notes: - 1. Gate and clock sources are hardware-specific. - 2. 'chanspec' indicates the channel to configure (if the hardware supports - per-channel configuration of the gate and clock sources). -*/ - /* 8254 specific configuration. It supports two config commands: - 0 ID: INSN_CONFIG_8254_SET_MODE + 0 ID: INSN_CONFIG_SET_COUNTER_MODE 1 8254 Mode I8254_MODE0, I8254_MODE1, ..., I8254_MODE5 OR'ed with: @@ -527,6 +508,58 @@ enum i8254_mode I8254_BINARY = 0 }; +/* mode bits for NI general-purpose counters, set with INSN_CONFIG_SET_COUNTER_MODE */ +#define NI_GPCT_COUNTING_MODE_SHIFT 16 +#define NI_GPCT_INDEX_PHASE_BITSHIFT 20 +#define NI_GPCT_COUNTING_DIRECTION_SHIFT 24 +enum ni_gpct_mode_bits +{ + NI_GPCT_GATE_ON_BOTH_EDGES_BIT = 0x4, + NI_GPCT_EDGE_GATE_MODE_MASK = 0x18, + NI_GPCT_EDGE_GATE_STARTS_STOPS_BITS = 0x0, + NI_GPCT_EDGE_GATE_STOPS_STARTS_BITS = 0x8, + NI_GPCT_EDGE_GATE_STARTS_BITS = 0x10, + NI_GPCT_EDGE_GATE_NO_STARTS_NO_STOPS_BITS = 0x18, + NI_GPCT_STOP_MODE_MASK = 0x60, + NI_GPCT_STOP_ON_GATE_BITS = 0x00, + NI_GPCT_STOP_ON_GATE_OR_TC_BITS = 0x20, + NI_GPCT_STOP_ON_GATE_OR_SECOND_TC_BITS = 0x40, + NI_GPCT_OUTPUT_MODE_MASK = 0x300, + NI_GPCT_OUTPUT_TC_PULSE_BITS = 0x100, + NI_GPCT_OUTPUT_TC_TOGGLE_BITS = 0x200, + NI_GPCT_OUTPUT_TC_OR_GATE_TOGGLE_BITS = 0x300, + NI_GPCT_HARDWARE_DISARM_MASK = 0xc00, + NI_GPCT_NO_HARDWARE_DISARM_BITS = 0x000, + NI_GPCT_DISARM_AT_TC_BITS = 0x400, + NI_GPCT_DISARM_AT_GATE_BITS = 0x800, + NI_GPCT_DISARM_AT_TC_OR_GATE_BITS = 0xc00, + NI_GPCT_LOADING_ON_TC_BIT = 0x1000, + NI_GPCT_LOADING_ON_GATE_BIT = 0x4000, + NI_GPCT_COUNTING_MODE_MASK = 0x7 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_NORMAL_BITS = 0x0 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_QUADRATURE_X1_BITS = 0x1 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_QUADRATURE_X2_BITS = 0x2 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_QUADRATURE_X4_BITS = 0x3 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_TWO_PULSE_BITS = 0x4 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_SYNC_SOURCE_BITS = 0x6 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_INDEX_PHASE_MASK = 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT, + NI_GPCT_INDEX_PHASE_LOW_A_LOW_B_BITS = 0x0 << NI_GPCT_INDEX_PHASE_BITSHIFT, + NI_GPCT_INDEX_PHASE_LOW_A_HIGH_B_BITS = 0x1 << NI_GPCT_INDEX_PHASE_BITSHIFT, + NI_GPCT_INDEX_PHASE_HIGH_A_LOW_B_BITS = 0x2 << NI_GPCT_INDEX_PHASE_BITSHIFT, + NI_GPCT_INDEX_PHASE_HIGH_A_HIGH_B_BITS = 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT, + NI_GPCT_INDEX_ENABLE_BIT = 0x400000, + NI_GPCT_COUNTING_DIRECTION_MASK = 0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT, + NI_GPCT_COUNTING_DIRECTION_DOWN_BITS = 0x00 << NI_GPCT_COUNTING_DIRECTION_SHIFT, + NI_GPCT_COUNTING_DIRECTION_UP_BITS = 0x1 << NI_GPCT_COUNTING_DIRECTION_SHIFT, + 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_SWITCHING_BITS = 0x4000000, + NI_GPCT_RELOAD_SOURCE_GATE_SELECT_BITS = 0x8000000, + NI_GPCT_OR_GATE_BIT = 0x10000000, + NI_GPCT_INVERT_OUTPUT_BIT = 0x20000000 +}; + /* clock sources for ni mio boards and INSN_CONFIG_SET_CLOCK_SRC */ enum ni_mio_clock_source { @@ -614,6 +647,14 @@ static inline unsigned NI_EXT_RTSI(unsigned rtsi_channel) else return 19 + rtsi_channel; } +/* status bits for INSN_CONFIG_GET_COUNTER_STATUS */ +enum comedi_counter_status_flags +{ + COMEDI_COUNTER_ARMED = 0x1, + COMEDI_COUNTER_COUNTING = 0x2, + COMEDI_COUNTER_TERMINAL_COUNT = 0x4, +}; + #ifdef __cplusplus } #endif -- 2.26.2