Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
[cascardo/linux.git] / drivers / staging / comedi / drivers / ni_tio.c
index a25e2f5..0525292 100644 (file)
@@ -49,349 +49,336 @@ TODO:
 
 #include "ni_tio_internal.h"
 
-static uint64_t ni_tio_clock_period_ps(const struct ni_gpct *counter,
-                                      unsigned generic_clock_source);
-static unsigned ni_tio_generic_clock_src_select(const struct ni_gpct *counter);
+/*
+ * clock sources for ni e and m series boards,
+ * get bits with GI_SRC_SEL()
+ */
+#define NI_M_TIMEBASE_1_CLK            0x0     /* 20MHz */
+#define NI_M_PFI_CLK(x)                        (((x) < 10) ? (1 + (x)) : (0xb + (x)))
+#define NI_M_RTSI_CLK(x)               (((x) == 7) ? 0x1b : (0xb + (x)))
+#define NI_M_TIMEBASE_2_CLK            0x12    /* 100KHz */
+#define NI_M_NEXT_TC_CLK               0x13
+#define NI_M_NEXT_GATE_CLK             0x14    /* Gi_Src_SubSelect=0 */
+#define NI_M_PXI_STAR_TRIGGER_CLK      0x14    /* Gi_Src_SubSelect=1 */
+#define NI_M_PXI10_CLK                 0x1d
+#define NI_M_TIMEBASE_3_CLK            0x1e    /* 80MHz, Gi_Src_SubSelect=0 */
+#define NI_M_ANALOG_TRIGGER_OUT_CLK    0x1e    /* Gi_Src_SubSelect=1 */
+#define NI_M_LOGIC_LOW_CLK             0x1f
+#define NI_M_MAX_PFI_CHAN              15
+#define NI_M_MAX_RTSI_CHAN             7
 
-static inline enum Gi_Counting_Mode_Reg_Bits Gi_Alternate_Sync_Bit(enum
-                                                                  ni_gpct_variant
-                                                                  variant)
+/*
+ * clock sources for ni_660x boards,
+ * get bits with GI_SRC_SEL()
+ */
+#define NI_660X_TIMEBASE_1_CLK         0x0     /* 20MHz */
+#define NI_660X_SRC_PIN_I_CLK          0x1
+#define NI_660X_SRC_PIN_CLK(x)         (0x2 + (x))
+#define NI_660X_NEXT_GATE_CLK          0xa
+#define NI_660X_RTSI_CLK(x)            (0xb + (x))
+#define NI_660X_TIMEBASE_2_CLK         0x12    /* 100KHz */
+#define NI_660X_NEXT_TC_CLK            0x13
+#define NI_660X_TIMEBASE_3_CLK         0x1e    /* 80MHz */
+#define NI_660X_LOGIC_LOW_CLK          0x1f
+#define NI_660X_MAX_SRC_PIN            7
+#define NI_660X_MAX_RTSI_CHAN          6
+
+/* ni m series gate_select */
+#define NI_M_TIMESTAMP_MUX_GATE_SEL    0x0
+#define NI_M_PFI_GATE_SEL(x)           (((x) < 10) ? (1 + (x)) : (0xb + (x)))
+#define NI_M_RTSI_GATE_SEL(x)          (((x) == 7) ? 0x1b : (0xb + (x)))
+#define NI_M_AI_START2_GATE_SEL                0x12
+#define NI_M_PXI_STAR_TRIGGER_GATE_SEL 0x13
+#define NI_M_NEXT_OUT_GATE_SEL         0x14
+#define NI_M_AI_START1_GATE_SEL                0x1c
+#define NI_M_NEXT_SRC_GATE_SEL         0x1d
+#define NI_M_ANALOG_TRIG_OUT_GATE_SEL  0x1e
+#define NI_M_LOGIC_LOW_GATE_SEL                0x1f
+
+/* ni_660x gate select */
+#define NI_660X_SRC_PIN_I_GATE_SEL     0x0
+#define NI_660X_GATE_PIN_I_GATE_SEL    0x1
+#define NI_660X_PIN_GATE_SEL(x)                (0x2 + (x))
+#define NI_660X_NEXT_SRC_GATE_SEL      0xa
+#define NI_660X_RTSI_GATE_SEL(x)       (0xb + (x))
+#define NI_660X_NEXT_OUT_GATE_SEL      0x14
+#define NI_660X_LOGIC_LOW_GATE_SEL     0x1f
+#define NI_660X_MAX_GATE_PIN           7
+
+/* ni_660x second gate select */
+#define NI_660X_SRC_PIN_I_GATE2_SEL    0x0
+#define NI_660X_UD_PIN_I_GATE2_SEL     0x1
+#define NI_660X_UD_PIN_GATE2_SEL(x)    (0x2 + (x))
+#define NI_660X_NEXT_SRC_GATE2_SEL     0xa
+#define NI_660X_RTSI_GATE2_SEL(x)      (0xb + (x))
+#define NI_660X_NEXT_OUT_GATE2_SEL     0x14
+#define NI_660X_SELECTED_GATE2_SEL     0x1e
+#define NI_660X_LOGIC_LOW_GATE2_SEL    0x1f
+#define NI_660X_MAX_UP_DOWN_PIN                7
+
+static inline unsigned GI_ALT_SYNC(enum ni_gpct_variant variant)
 {
        switch (variant) {
        case ni_gpct_variant_e_series:
+       default:
                return 0;
        case ni_gpct_variant_m_series:
-               return Gi_M_Series_Alternate_Sync_Bit;
+               return GI_M_ALT_SYNC;
        case ni_gpct_variant_660x:
-               return Gi_660x_Alternate_Sync_Bit;
-       default:
-               BUG();
-               break;
+               return GI_660X_ALT_SYNC;
        }
-       return 0;
 }
 
-static inline enum Gi_Counting_Mode_Reg_Bits Gi_Prescale_X2_Bit(enum
-                                                               ni_gpct_variant
-                                                               variant)
+static inline unsigned GI_PRESCALE_X2(enum ni_gpct_variant variant)
 {
        switch (variant) {
        case ni_gpct_variant_e_series:
+       default:
                return 0;
        case ni_gpct_variant_m_series:
-               return Gi_M_Series_Prescale_X2_Bit;
+               return GI_M_PRESCALE_X2;
        case ni_gpct_variant_660x:
-               return Gi_660x_Prescale_X2_Bit;
-       default:
-               BUG();
-               break;
+               return GI_660X_PRESCALE_X2;
        }
-       return 0;
 }
 
-static inline enum Gi_Counting_Mode_Reg_Bits Gi_Prescale_X8_Bit(enum
-                                                               ni_gpct_variant
-                                                               variant)
+static inline unsigned GI_PRESCALE_X8(enum ni_gpct_variant variant)
 {
        switch (variant) {
        case ni_gpct_variant_e_series:
+       default:
                return 0;
        case ni_gpct_variant_m_series:
-               return Gi_M_Series_Prescale_X8_Bit;
+               return GI_M_PRESCALE_X8;
        case ni_gpct_variant_660x:
-               return Gi_660x_Prescale_X8_Bit;
-       default:
-               BUG();
-               break;
+               return GI_660X_PRESCALE_X8;
        }
-       return 0;
 }
 
-static inline enum Gi_Counting_Mode_Reg_Bits Gi_HW_Arm_Select_Mask(enum
-                                                                  ni_gpct_variant
-                                                                  variant)
+static inline unsigned GI_HW_ARM_SEL_MASK(enum ni_gpct_variant variant)
 {
        switch (variant) {
        case ni_gpct_variant_e_series:
+       default:
                return 0;
        case ni_gpct_variant_m_series:
-               return Gi_M_Series_HW_Arm_Select_Mask;
+               return GI_M_HW_ARM_SEL_MASK;
        case ni_gpct_variant_660x:
-               return Gi_660x_HW_Arm_Select_Mask;
-       default:
-               BUG();
-               break;
+               return GI_660X_HW_ARM_SEL_MASK;
        }
-       return 0;
-}
-
-/* clock sources for ni_660x boards, get bits with Gi_Source_Select_Bits() */
-enum ni_660x_clock_source {
-       NI_660x_Timebase_1_Clock = 0x0, /* 20MHz */
-       NI_660x_Source_Pin_i_Clock = 0x1,
-       NI_660x_Next_Gate_Clock = 0xa,
-       NI_660x_Timebase_2_Clock = 0x12,        /* 100KHz */
-       NI_660x_Next_TC_Clock = 0x13,
-       NI_660x_Timebase_3_Clock = 0x1e,        /* 80MHz */
-       NI_660x_Logic_Low_Clock = 0x1f,
-};
-static const unsigned ni_660x_max_rtsi_channel = 6;
-static inline unsigned NI_660x_RTSI_Clock(unsigned n)
-{
-       BUG_ON(n > ni_660x_max_rtsi_channel);
-       return 0xb + n;
-}
-
-static const unsigned ni_660x_max_source_pin = 7;
-static inline unsigned NI_660x_Source_Pin_Clock(unsigned n)
-{
-       BUG_ON(n > ni_660x_max_source_pin);
-       return 0x2 + n;
-}
-
-/* clock sources for ni e and m series boards, get bits with Gi_Source_Select_Bits() */
-enum ni_m_series_clock_source {
-       NI_M_Series_Timebase_1_Clock = 0x0,     /* 20MHz */
-       NI_M_Series_Timebase_2_Clock = 0x12,    /* 100KHz */
-       NI_M_Series_Next_TC_Clock = 0x13,
-       NI_M_Series_Next_Gate_Clock = 0x14,     /* when Gi_Src_SubSelect = 0 */
-       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_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;
-static inline unsigned NI_M_Series_PFI_Clock(unsigned n)
-{
-       BUG_ON(n > ni_m_series_max_pfi_channel);
-       if (n < 10)
-               return 1 + n;
-       else
-               return 0xb + n;
-}
-
-static const unsigned ni_m_series_max_rtsi_channel = 7;
-static inline unsigned NI_M_Series_RTSI_Clock(unsigned n)
-{
-       BUG_ON(n > ni_m_series_max_rtsi_channel);
-       if (n == 7)
-               return 0x1b;
-       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)
+static int ni_tio_has_gate2_registers(const struct ni_gpct_device *counter_dev)
 {
-       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;
-}
-
-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_Bits(unsigned gate_select)
-{
-       return (gate_select << Gi_Gate_Select_Shift) & Gi_Gate_Select_Mask;
+       switch (counter_dev->variant) {
+       case ni_gpct_variant_e_series:
+       default:
+               return 0;
+       case ni_gpct_variant_m_series:
+       case ni_gpct_variant_660x:
+               return 1;
+       }
 }
 
-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)
+static void ni_tio_reset_count_and_disarm(struct ni_gpct *counter)
 {
-       BUG_ON(n > ni_660x_max_up_down_pin);
-       return 0x2 + n;
-}
+       unsigned cidx = counter->counter_index;
 
-static inline unsigned NI_660x_RTSI_Second_Gate_Select(unsigned n)
-{
-       BUG_ON(n > ni_660x_max_rtsi_channel);
-       return 0xb + n;
+       write_register(counter, GI_RESET(cidx), NITIO_RESET_REG(cidx));
 }
 
-static const unsigned int counter_status_mask =
-       COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING;
-
-struct ni_gpct_device *ni_gpct_device_construct(struct comedi_device *dev,
-                                               void (*write_register) (struct
-                                                                       ni_gpct
-                                                                       *
-                                                                       counter,
-                                                                       unsigned
-                                                                       bits,
-                                                                       enum
-                                                                       ni_gpct_register
-                                                                       reg),
-                                               unsigned (*read_register)
-                                               (struct ni_gpct *counter,
-                                                enum ni_gpct_register reg),
-                                               enum ni_gpct_variant variant,
-                                               unsigned num_counters)
+static uint64_t ni_tio_clock_period_ps(const struct ni_gpct *counter,
+                                      unsigned generic_clock_source)
 {
-       unsigned i;
+       uint64_t clock_period_ps;
 
-       struct ni_gpct_device *counter_dev =
-           kzalloc(sizeof(struct ni_gpct_device), GFP_KERNEL);
-       if (counter_dev == NULL)
-               return NULL;
-       counter_dev->dev = dev;
-       counter_dev->write_register = write_register;
-       counter_dev->read_register = read_register;
-       counter_dev->variant = variant;
-       spin_lock_init(&counter_dev->regs_lock);
-       BUG_ON(num_counters == 0);
-       counter_dev->counters =
-           kzalloc(sizeof(struct ni_gpct) * num_counters, GFP_KERNEL);
-       if (counter_dev->counters == NULL) {
-               kfree(counter_dev);
-               return NULL;
-       }
-       for (i = 0; i < num_counters; ++i) {
-               counter_dev->counters[i].counter_dev = counter_dev;
-               spin_lock_init(&counter_dev->counters[i].lock);
+       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;
        }
-       counter_dev->num_counters = num_counters;
-       return counter_dev;
-}
-EXPORT_SYMBOL_GPL(ni_gpct_device_construct);
 
-void ni_gpct_device_destroy(struct ni_gpct_device *counter_dev)
-{
-       if (counter_dev->counters == NULL)
-               return;
-       kfree(counter_dev->counters);
-       kfree(counter_dev);
-}
-EXPORT_SYMBOL_GPL(ni_gpct_device_destroy);
-
-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;
-       case ni_gpct_variant_m_series:
-       case ni_gpct_variant_660x:
-               return 1;
+       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 0;
+       return clock_period_ps;
 }
 
-static void ni_tio_reset_count_and_disarm(struct ni_gpct *counter)
+static unsigned ni_tio_clock_src_modifiers(const struct ni_gpct *counter)
 {
+       struct ni_gpct_device *counter_dev = counter->counter_dev;
        unsigned cidx = counter->counter_index;
+       const unsigned counting_mode_bits =
+               ni_tio_get_soft_copy(counter, NITIO_CNT_MODE_REG(cidx));
+       unsigned bits = 0;
 
-       write_register(counter, Gi_Reset_Bit(cidx), NITIO_RESET_REG(cidx));
+       if (ni_tio_get_soft_copy(counter, NITIO_INPUT_SEL_REG(cidx)) &
+           GI_SRC_POL_INVERT)
+               bits |= NI_GPCT_INVERT_CLOCK_SRC_BIT;
+       if (counting_mode_bits & GI_PRESCALE_X2(counter_dev->variant))
+               bits |= NI_GPCT_PRESCALE_X2_CLOCK_SRC_BITS;
+       if (counting_mode_bits & GI_PRESCALE_X8(counter_dev->variant))
+               bits |= NI_GPCT_PRESCALE_X8_CLOCK_SRC_BITS;
+       return bits;
 }
 
-void ni_tio_init_counter(struct ni_gpct *counter)
+static unsigned ni_m_series_clock_src_select(const struct ni_gpct *counter)
 {
        struct ni_gpct_device *counter_dev = counter->counter_dev;
        unsigned cidx = counter->counter_index;
+       const unsigned second_gate_reg = NITIO_GATE2_REG(cidx);
+       unsigned clock_source = 0;
+       unsigned src;
+       unsigned i;
 
-       ni_tio_reset_count_and_disarm(counter);
-
-       /* initialize counter registers */
-       counter_dev->regs[NITIO_AUTO_INC_REG(cidx)] = 0x0;
-       write_register(counter, counter_dev->regs[NITIO_AUTO_INC_REG(cidx)],
-                      NITIO_AUTO_INC_REG(cidx));
-
-       ni_tio_set_bits(counter, NITIO_CMD_REG(cidx),
-                       ~0, Gi_Synchronize_Gate_Bit);
-
-       ni_tio_set_bits(counter, NITIO_MODE_REG(cidx), ~0, 0);
-
-       counter_dev->regs[NITIO_LOADA_REG(cidx)] = 0x0;
-       write_register(counter, counter_dev->regs[NITIO_LOADA_REG(cidx)],
-                      NITIO_LOADA_REG(cidx));
+       src = GI_BITS_TO_SRC(ni_tio_get_soft_copy(counter,
+                                                 NITIO_INPUT_SEL_REG(cidx)));
 
-       counter_dev->regs[NITIO_LOADB_REG(cidx)] = 0x0;
-       write_register(counter, counter_dev->regs[NITIO_LOADB_REG(cidx)],
-                      NITIO_LOADB_REG(cidx));
+       switch (src) {
+       case NI_M_TIMEBASE_1_CLK:
+               clock_source = NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS;
+               break;
+       case NI_M_TIMEBASE_2_CLK:
+               clock_source = NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS;
+               break;
+       case NI_M_TIMEBASE_3_CLK:
+               if (counter_dev->regs[second_gate_reg] & GI_SRC_SUBSEL)
+                       clock_source =
+                           NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS;
+               else
+                       clock_source = NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS;
+               break;
+       case NI_M_LOGIC_LOW_CLK:
+               clock_source = NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS;
+               break;
+       case NI_M_NEXT_GATE_CLK:
+               if (counter_dev->regs[second_gate_reg] & GI_SRC_SUBSEL)
+                       clock_source = NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS;
+               else
+                       clock_source = NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS;
+               break;
+       case NI_M_PXI10_CLK:
+               clock_source = NI_GPCT_PXI10_CLOCK_SRC_BITS;
+               break;
+       case NI_M_NEXT_TC_CLK:
+               clock_source = NI_GPCT_NEXT_TC_CLOCK_SRC_BITS;
+               break;
+       default:
+               for (i = 0; i <= NI_M_MAX_RTSI_CHAN; ++i) {
+                       if (src == NI_M_RTSI_CLK(i)) {
+                               clock_source = NI_GPCT_RTSI_CLOCK_SRC_BITS(i);
+                               break;
+                       }
+               }
+               if (i <= NI_M_MAX_RTSI_CHAN)
+                       break;
+               for (i = 0; i <= NI_M_MAX_PFI_CHAN; ++i) {
+                       if (src == NI_M_PFI_CLK(i)) {
+                               clock_source = NI_GPCT_PFI_CLOCK_SRC_BITS(i);
+                               break;
+                       }
+               }
+               if (i <= NI_M_MAX_PFI_CHAN)
+                       break;
+               BUG();
+               break;
+       }
+       clock_source |= ni_tio_clock_src_modifiers(counter);
+       return clock_source;
+}
 
-       ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), ~0, 0);
+static unsigned ni_660x_clock_src_select(const struct ni_gpct *counter)
+{
+       unsigned clock_source = 0;
+       unsigned cidx = counter->counter_index;
+       unsigned src;
+       unsigned i;
 
-       if (ni_tio_counting_mode_registers_present(counter_dev))
-               ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx), ~0, 0);
+       src = GI_BITS_TO_SRC(ni_tio_get_soft_copy(counter,
+                                                 NITIO_INPUT_SEL_REG(cidx)));
 
-       if (ni_tio_second_gate_registers_present(counter_dev)) {
-               counter_dev->regs[NITIO_GATE2_REG(cidx)] = 0x0;
-               write_register(counter,
-                              counter_dev->regs[NITIO_GATE2_REG(cidx)],
-                              NITIO_GATE2_REG(cidx));
+       switch (src) {
+       case NI_660X_TIMEBASE_1_CLK:
+               clock_source = NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS;
+               break;
+       case NI_660X_TIMEBASE_2_CLK:
+               clock_source = NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS;
+               break;
+       case NI_660X_TIMEBASE_3_CLK:
+               clock_source = NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS;
+               break;
+       case NI_660X_LOGIC_LOW_CLK:
+               clock_source = NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS;
+               break;
+       case NI_660X_SRC_PIN_I_CLK:
+               clock_source = NI_GPCT_SOURCE_PIN_i_CLOCK_SRC_BITS;
+               break;
+       case NI_660X_NEXT_GATE_CLK:
+               clock_source = NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS;
+               break;
+       case NI_660X_NEXT_TC_CLK:
+               clock_source = NI_GPCT_NEXT_TC_CLOCK_SRC_BITS;
+               break;
+       default:
+               for (i = 0; i <= NI_660X_MAX_RTSI_CHAN; ++i) {
+                       if (src == NI_660X_RTSI_CLK(i)) {
+                               clock_source = NI_GPCT_RTSI_CLOCK_SRC_BITS(i);
+                               break;
+                       }
+               }
+               if (i <= NI_660X_MAX_RTSI_CHAN)
+                       break;
+               for (i = 0; i <= NI_660X_MAX_SRC_PIN; ++i) {
+                       if (src == NI_660X_SRC_PIN_CLK(i)) {
+                               clock_source =
+                                   NI_GPCT_SOURCE_PIN_CLOCK_SRC_BITS(i);
+                               break;
+                       }
+               }
+               if (i <= NI_660X_MAX_SRC_PIN)
+                       break;
+               BUG();
+               break;
        }
-
-       ni_tio_set_bits(counter, NITIO_DMA_CFG_REG(cidx), ~0, 0x0);
-
-       ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx), ~0, 0x0);
+       clock_source |= ni_tio_clock_src_modifiers(counter);
+       return clock_source;
 }
-EXPORT_SYMBOL_GPL(ni_tio_init_counter);
 
-static unsigned int ni_tio_counter_status(struct ni_gpct *counter)
+static unsigned ni_tio_generic_clock_src_select(const struct ni_gpct *counter)
 {
-       unsigned cidx = counter->counter_index;
-       const unsigned bits = read_register(counter,
-                                           NITIO_SHARED_STATUS_REG(cidx));
-       unsigned int status = 0;
-
-       if (bits & Gi_Armed_Bit(cidx)) {
-               status |= COMEDI_COUNTER_ARMED;
-               if (bits & Gi_Counting_Bit(cidx))
-                       status |= COMEDI_COUNTER_COUNTING;
+       switch (counter->counter_dev->variant) {
+       case ni_gpct_variant_e_series:
+       case ni_gpct_variant_m_series:
+       default:
+               return ni_m_series_clock_src_select(counter);
+       case ni_gpct_variant_660x:
+               return ni_660x_clock_src_select(counter);
        }
-       return status;
 }
 
 static void ni_tio_set_sync_mode(struct ni_gpct *counter, int force_alt_sync)
@@ -400,34 +387,40 @@ static void ni_tio_set_sync_mode(struct ni_gpct *counter, int force_alt_sync)
        unsigned cidx = counter->counter_index;
        const unsigned counting_mode_reg = NITIO_CNT_MODE_REG(cidx);
        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));
+       unsigned mode;
+       uint64_t clock_period_ps;
 
        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:
+       mode = ni_tio_get_soft_copy(counter, counting_mode_reg);
+       switch (mode & GI_CNT_MODE_MASK) {
+       case GI_CNT_MODE_QUADX1:
+       case GI_CNT_MODE_QUADX2:
+       case GI_CNT_MODE_QUADX4:
+       case GI_CNT_MODE_SYNC_SRC:
                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. */
+
+       clock_period_ps = ni_tio_clock_period_ps(counter,
+                               ni_tio_generic_clock_src_select(counter));
+
+       /*
+        * 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));
+                               GI_ALT_SYNC(counter_dev->variant),
+                               GI_ALT_SYNC(counter_dev->variant));
        } else {
                ni_tio_set_bits(counter, counting_mode_reg,
-                               Gi_Alternate_Sync_Bit(counter_dev->variant),
+                               GI_ALT_SYNC(counter_dev->variant),
                                0x0);
        }
 }
@@ -446,18 +439,18 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode)
            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_mask = mode_reg_direct_mask | GI_RELOAD_SRC_SWITCHING;
        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;
+               mode_reg_values |= GI_RELOAD_SRC_SWITCHING;
                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;
+               input_select_bits |= GI_GATE_SEL_LOAD_SRC;
+               mode_reg_mask |= GI_GATING_MODE_MASK;
+               mode_reg_values |= GI_LEVEL_GATING;
                break;
        default:
                break;
@@ -466,33 +459,28 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode)
                        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;
+               unsigned bits = 0;
+
+               bits |= GI_CNT_MODE(mode >> NI_GPCT_COUNTING_MODE_SHIFT);
+               bits |= GI_INDEX_PHASE((mode >> NI_GPCT_INDEX_PHASE_BITSHIFT));
                if (mode & NI_GPCT_INDEX_ENABLE_BIT)
-                       counting_mode_bits |= Gi_Index_Mode_Bit;
+                       bits |= GI_INDEX_MODE;
                ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx),
-                               Gi_Counting_Mode_Mask | Gi_Index_Phase_Mask |
-                               Gi_Index_Mode_Bit, counting_mode_bits);
+                               GI_CNT_MODE_MASK | GI_INDEX_PHASE_MASK |
+                               GI_INDEX_MODE, bits);
                ni_tio_set_sync_mode(counter, 0);
        }
 
-       ni_tio_set_bits(counter, NITIO_CMD_REG(cidx),
-                       Gi_Up_Down_Mask,
-                       (mode >> NI_GPCT_COUNTING_DIRECTION_SHIFT) <<
-                       Gi_Up_Down_Shift);
+       ni_tio_set_bits(counter, NITIO_CMD_REG(cidx), GI_CNT_DIR_MASK,
+                       GI_CNT_DIR(mode >> NI_GPCT_COUNTING_DIRECTION_SHIFT));
 
        if (mode & NI_GPCT_OR_GATE_BIT)
-               input_select_bits |= Gi_Or_Gate_Bit;
+               input_select_bits |= GI_OR_GATE;
        if (mode & NI_GPCT_INVERT_OUTPUT_BIT)
-               input_select_bits |= Gi_Output_Polarity_Bit;
+               input_select_bits |= GI_OUTPUT_POL_INVERT;
        ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx),
-                       Gi_Gate_Select_Load_Source_Bit | Gi_Or_Gate_Bit |
-                       Gi_Output_Polarity_Bit, input_select_bits);
+                       GI_GATE_SEL_LOAD_SRC | GI_OR_GATE |
+                       GI_OUTPUT_POL_INVERT, input_select_bits);
 
        return 0;
 }
@@ -506,16 +494,19 @@ int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger)
        if (arm) {
                switch (start_trigger) {
                case NI_GPCT_ARM_IMMEDIATE:
-                       command_transient_bits |= Gi_Arm_Bit;
+                       command_transient_bits |= GI_ARM;
                        break;
                case NI_GPCT_ARM_PAIRED_IMMEDIATE:
-                       command_transient_bits |= Gi_Arm_Bit | Gi_Arm_Copy_Bit;
+                       command_transient_bits |= GI_ARM | GI_ARM_COPY;
                        break;
                default:
                        break;
                }
                if (ni_tio_counting_mode_registers_present(counter_dev)) {
-                       unsigned counting_mode_bits = 0;
+                       unsigned bits = 0;
+                       unsigned sel_mask;
+
+                       sel_mask = GI_HW_ARM_SEL_MASK(counter_dev->variant);
 
                        switch (start_trigger) {
                        case NI_GPCT_ARM_IMMEDIATE:
@@ -523,29 +514,24 @@ int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger)
                                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;
+                                       /*
+                                        * pass-through the least significant
+                                        * bits so we can figure out what
+                                        * select later
+                                        */
+                                       bits |= GI_HW_ARM_ENA |
+                                               (GI_HW_ARM_SEL(start_trigger) &
+                                                sel_mask);
                                } else {
                                        return -EINVAL;
                                }
                                break;
                        }
                        ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx),
-                                       Gi_HW_Arm_Select_Mask
-                                       (counter_dev->variant) |
-                                       Gi_HW_Arm_Enable_Bit,
-                                       counting_mode_bits);
+                                       GI_HW_ARM_ENA | sel_mask, bits);
                }
        } else {
-               command_transient_bits |= Gi_Disarm_Bit;
+               command_transient_bits |= GI_DISARM;
        }
        ni_tio_set_bits_transient(counter, NITIO_CMD_REG(cidx),
                                  0, 0, command_transient_bits);
@@ -553,487 +539,255 @@ int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger)
 }
 EXPORT_SYMBOL_GPL(ni_tio_arm);
 
-static unsigned ni_660x_source_select_bits(unsigned int clock_source)
+static unsigned ni_660x_clk_src(unsigned int clock_source)
 {
+       unsigned clk_src = clock_source & NI_GPCT_CLOCK_SRC_SELECT_MASK;
        unsigned ni_660x_clock;
        unsigned i;
-       const unsigned clock_select_bits =
-           clock_source & NI_GPCT_CLOCK_SRC_SELECT_MASK;
 
-       switch (clock_select_bits) {
+       switch (clk_src) {
        case NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS:
-               ni_660x_clock = NI_660x_Timebase_1_Clock;
+               ni_660x_clock = NI_660X_TIMEBASE_1_CLK;
                break;
        case NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS:
-               ni_660x_clock = NI_660x_Timebase_2_Clock;
+               ni_660x_clock = NI_660X_TIMEBASE_2_CLK;
                break;
        case NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS:
-               ni_660x_clock = NI_660x_Timebase_3_Clock;
+               ni_660x_clock = NI_660X_TIMEBASE_3_CLK;
                break;
        case NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS:
-               ni_660x_clock = NI_660x_Logic_Low_Clock;
+               ni_660x_clock = NI_660X_LOGIC_LOW_CLK;
                break;
        case NI_GPCT_SOURCE_PIN_i_CLOCK_SRC_BITS:
-               ni_660x_clock = NI_660x_Source_Pin_i_Clock;
+               ni_660x_clock = NI_660X_SRC_PIN_I_CLK;
                break;
        case NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS:
-               ni_660x_clock = NI_660x_Next_Gate_Clock;
+               ni_660x_clock = NI_660X_NEXT_GATE_CLK;
                break;
        case NI_GPCT_NEXT_TC_CLOCK_SRC_BITS:
-               ni_660x_clock = NI_660x_Next_TC_Clock;
+               ni_660x_clock = NI_660X_NEXT_TC_CLK;
                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);
+               for (i = 0; i <= NI_660X_MAX_RTSI_CHAN; ++i) {
+                       if (clk_src == NI_GPCT_RTSI_CLOCK_SRC_BITS(i)) {
+                               ni_660x_clock = NI_660X_RTSI_CLK(i);
                                break;
                        }
                }
-               if (i <= ni_660x_max_rtsi_channel)
+               if (i <= NI_660X_MAX_RTSI_CHAN)
                        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);
+               for (i = 0; i <= NI_660X_MAX_SRC_PIN; ++i) {
+                       if (clk_src == NI_GPCT_SOURCE_PIN_CLOCK_SRC_BITS(i)) {
+                               ni_660x_clock = NI_660X_SRC_PIN_CLK(i);
                                break;
                        }
                }
-               if (i <= ni_660x_max_source_pin)
+               if (i <= NI_660X_MAX_SRC_PIN)
                        break;
                ni_660x_clock = 0;
                BUG();
                break;
        }
-       return Gi_Source_Select_Bits(ni_660x_clock);
+       return GI_SRC_SEL(ni_660x_clock);
 }
 
-static unsigned ni_m_series_source_select_bits(unsigned int clock_source)
+static unsigned ni_m_clk_src(unsigned int clock_source)
 {
+       unsigned clk_src = clock_source & NI_GPCT_CLOCK_SRC_SELECT_MASK;
        unsigned ni_m_series_clock;
        unsigned i;
-       const unsigned clock_select_bits =
-           clock_source & NI_GPCT_CLOCK_SRC_SELECT_MASK;
-       switch (clock_select_bits) {
+
+       switch (clk_src) {
        case NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS:
-               ni_m_series_clock = NI_M_Series_Timebase_1_Clock;
+               ni_m_series_clock = NI_M_TIMEBASE_1_CLK;
                break;
        case NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS:
-               ni_m_series_clock = NI_M_Series_Timebase_2_Clock;
+               ni_m_series_clock = NI_M_TIMEBASE_2_CLK;
                break;
        case NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS:
-               ni_m_series_clock = NI_M_Series_Timebase_3_Clock;
+               ni_m_series_clock = NI_M_TIMEBASE_3_CLK;
                break;
        case NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS:
-               ni_m_series_clock = NI_M_Series_Logic_Low_Clock;
+               ni_m_series_clock = NI_M_LOGIC_LOW_CLK;
                break;
        case NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS:
-               ni_m_series_clock = NI_M_Series_Next_Gate_Clock;
+               ni_m_series_clock = NI_M_NEXT_GATE_CLK;
                break;
        case NI_GPCT_NEXT_TC_CLOCK_SRC_BITS:
-               ni_m_series_clock = NI_M_Series_Next_TC_Clock;
+               ni_m_series_clock = NI_M_NEXT_TC_CLK;
                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;
-               printk(KERN_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,
-                                       unsigned int clock_source)
-{
-       struct ni_gpct_device *counter_dev = counter->counter_dev;
-       unsigned cidx = counter->counter_index;
-       const unsigned second_gate_reg = NITIO_GATE2_REG(cidx);
-
-       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;
-       }
-       write_register(counter, counter_dev->regs[second_gate_reg],
-                      second_gate_reg);
-}
-
-static int ni_tio_set_clock_src(struct ni_gpct *counter,
-                               unsigned int clock_source,
-                               unsigned int period_ns)
-{
-       struct ni_gpct_device *counter_dev = counter->counter_dev;
-       unsigned cidx = counter->counter_index;
-       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_INPUT_SEL_REG(cidx),
-                       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;
-               }
-               ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx),
-                               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 ni_tio_clock_src_modifiers(const struct ni_gpct *counter)
-{
-       struct ni_gpct_device *counter_dev = counter->counter_dev;
-       unsigned cidx = counter->counter_index;
-       const unsigned counting_mode_bits =
-               ni_tio_get_soft_copy(counter, NITIO_CNT_MODE_REG(cidx));
-       unsigned bits = 0;
-
-       if (ni_tio_get_soft_copy(counter, NITIO_INPUT_SEL_REG(cidx)) &
-           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 ni_m_series_clock_src_select(const struct ni_gpct *counter)
-{
-       struct ni_gpct_device *counter_dev = counter->counter_dev;
-       unsigned cidx = counter->counter_index;
-       const unsigned second_gate_reg = NITIO_GATE2_REG(cidx);
-       unsigned clock_source = 0;
-       unsigned i;
-       const unsigned input_select =
-               (ni_tio_get_soft_copy(counter, NITIO_INPUT_SEL_REG(cidx)) &
-                       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 ni_660x_clock_src_select(const struct ni_gpct *counter)
-{
-       unsigned clock_source = 0;
-       unsigned cidx = counter->counter_index;
-       const unsigned input_select =
-               (ni_tio_get_soft_copy(counter, NITIO_INPUT_SEL_REG(cidx)) &
-                       Gi_Source_Select_Mask) >> Gi_Source_Select_Shift;
-       unsigned i;
-
-       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;
+               ni_m_series_clock = NI_M_PXI10_CLK;
                break;
-       case NI_660x_Next_Gate_Clock:
-               clock_source = NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS;
+       case NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS:
+               ni_m_series_clock = NI_M_PXI_STAR_TRIGGER_CLK;
                break;
-       case NI_660x_Next_TC_Clock:
-               clock_source = NI_GPCT_NEXT_TC_CLOCK_SRC_BITS;
+       case NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS:
+               ni_m_series_clock = NI_M_ANALOG_TRIGGER_OUT_CLK;
                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);
+               for (i = 0; i <= NI_M_MAX_RTSI_CHAN; ++i) {
+                       if (clk_src == NI_GPCT_RTSI_CLOCK_SRC_BITS(i)) {
+                               ni_m_series_clock = NI_M_RTSI_CLK(i);
                                break;
                        }
                }
-               if (i <= ni_660x_max_rtsi_channel)
+               if (i <= NI_M_MAX_RTSI_CHAN)
                        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);
+               for (i = 0; i <= NI_M_MAX_PFI_CHAN; ++i) {
+                       if (clk_src == NI_GPCT_PFI_CLOCK_SRC_BITS(i)) {
+                               ni_m_series_clock = NI_M_PFI_CLK(i);
                                break;
                        }
                }
-               if (i <= ni_660x_max_source_pin)
+               if (i <= NI_M_MAX_PFI_CHAN)
                        break;
+               pr_err("invalid clock source 0x%lx\n",
+                      (unsigned long)clock_source);
                BUG();
+               ni_m_series_clock = 0;
                break;
        }
-       clock_source |= ni_tio_clock_src_modifiers(counter);
-       return clock_source;
-}
-
-static unsigned 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);
-       case ni_gpct_variant_660x:
-               return ni_660x_clock_src_select(counter);
-       default:
-               BUG();
-               break;
-       }
-       return 0;
-}
+       return GI_SRC_SEL(ni_m_series_clock);
+};
 
-static uint64_t ni_tio_clock_period_ps(const struct ni_gpct *counter,
-                                      unsigned generic_clock_source)
+static void ni_tio_set_source_subselect(struct ni_gpct *counter,
+                                       unsigned int clock_source)
 {
-       uint64_t clock_period_ps;
+       struct ni_gpct_device *counter_dev = counter->counter_dev;
+       unsigned cidx = counter->counter_index;
+       const unsigned second_gate_reg = NITIO_GATE2_REG(cidx);
 
-       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;
+       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:
-               clock_period_ps = 12500;
+               counter_dev->regs[second_gate_reg] &= ~GI_SRC_SUBSEL;
                break;
-       case NI_GPCT_PXI10_CLOCK_SRC_BITS:
-               clock_period_ps = 100000;
+               /* 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_SRC_SUBSEL;
                break;
+               /* Gi_Source_Subselect doesn't matter */
        default:
-               /* clock period is specified by user with prescaling already taken into account. */
-               return counter->clock_period_ps;
+               return;
        }
+       write_register(counter, counter_dev->regs[second_gate_reg],
+                      second_gate_reg);
+}
 
-       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;
+static int ni_tio_set_clock_src(struct ni_gpct *counter,
+                               unsigned int clock_source,
+                               unsigned int period_ns)
+{
+       struct ni_gpct_device *counter_dev = counter->counter_dev;
+       unsigned cidx = counter->counter_index;
+       unsigned bits = 0;
+
+       /* FIXME: validate clock source */
+       switch (counter_dev->variant) {
+       case ni_gpct_variant_660x:
+               bits |= ni_660x_clk_src(clock_source);
                break;
+       case ni_gpct_variant_e_series:
+       case ni_gpct_variant_m_series:
        default:
-               BUG();
+               bits |= ni_m_clk_src(clock_source);
                break;
        }
-       return clock_period_ps;
+       if (clock_source & NI_GPCT_INVERT_CLOCK_SRC_BIT)
+               bits |= GI_SRC_POL_INVERT;
+       ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx),
+                       GI_SRC_SEL_MASK | GI_SRC_POL_INVERT, bits);
+       ni_tio_set_source_subselect(counter, clock_source);
+
+       if (ni_tio_counting_mode_registers_present(counter_dev)) {
+               bits = 0;
+               switch (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:
+                       bits |= GI_PRESCALE_X2(counter_dev->variant);
+                       break;
+               case NI_GPCT_PRESCALE_X8_CLOCK_SRC_BITS:
+                       bits |= GI_PRESCALE_X8(counter_dev->variant);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx),
+                               GI_PRESCALE_X2(counter_dev->variant) |
+                               GI_PRESCALE_X8(counter_dev->variant), bits);
+       }
+       counter->clock_period_ps = period_ns * 1000;
+       ni_tio_set_sync_mode(counter, 0);
+       return 0;
 }
 
 static void ni_tio_get_clock_src(struct ni_gpct *counter,
                                 unsigned int *clock_source,
                                 unsigned int *period_ns)
 {
-       static const unsigned 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);
+       do_div(temp64, 1000);   /* ps to ns */
        *period_ns = temp64;
 }
 
-static void ni_tio_set_first_gate_modifiers(struct ni_gpct *counter,
-                                           unsigned int gate_source)
-{
-       const unsigned mode_mask = Gi_Gate_Polarity_Bit | Gi_Gating_Mode_Mask;
-       unsigned cidx = counter->counter_index;
-       unsigned 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_MODE_REG(cidx),
-                       mode_mask, mode_values);
-}
-
-static int ni_660x_set_first_gate(struct ni_gpct *counter,
-                                 unsigned int gate_source)
+static int ni_660x_set_gate(struct ni_gpct *counter, unsigned int gate_source)
 {
-       const unsigned selected_gate = CR_CHAN(gate_source);
+       unsigned int chan = CR_CHAN(gate_source);
        unsigned cidx = counter->counter_index;
-       /* bits of selected_gate that may be meaningful to input select register */
-       const unsigned selected_gate_mask = 0x1f;
-       unsigned ni_660x_gate_select;
+       unsigned gate_sel;
        unsigned i;
 
-       switch (selected_gate) {
+       switch (chan) {
        case NI_GPCT_NEXT_SOURCE_GATE_SELECT:
-               ni_660x_gate_select = NI_660x_Next_SRC_Gate_Select;
+               gate_sel = NI_660X_NEXT_SRC_GATE_SEL;
                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;
+               gate_sel = chan & 0x1f;
                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;
+               for (i = 0; i <= NI_660X_MAX_RTSI_CHAN; ++i) {
+                       if (chan == NI_GPCT_RTSI_GATE_SELECT(i)) {
+                               gate_sel = chan & 0x1f;
                                break;
                        }
                }
-               if (i <= ni_660x_max_rtsi_channel)
+               if (i <= NI_660X_MAX_RTSI_CHAN)
                        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;
+               for (i = 0; i <= NI_660X_MAX_GATE_PIN; ++i) {
+                       if (chan == NI_GPCT_GATE_PIN_GATE_SELECT(i)) {
+                               gate_sel = chan & 0x1f;
                                break;
                        }
                }
-               if (i <= ni_660x_max_gate_pin)
+               if (i <= NI_660X_MAX_GATE_PIN)
                        break;
                return -EINVAL;
        }
        ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx),
-                       Gi_Gate_Select_Mask,
-                       Gi_Gate_Select_Bits(ni_660x_gate_select));
+                       GI_GATE_SEL_MASK, GI_GATE_SEL(gate_sel));
        return 0;
 }
 
-static int ni_m_series_set_first_gate(struct ni_gpct *counter,
-                                     unsigned int gate_source)
+static int ni_m_set_gate(struct ni_gpct *counter, unsigned int gate_source)
 {
-       const unsigned selected_gate = CR_CHAN(gate_source);
+       unsigned int chan = CR_CHAN(gate_source);
        unsigned cidx = counter->counter_index;
-       /* 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 gate_sel;
        unsigned i;
 
-       switch (selected_gate) {
+       switch (chan) {
        case NI_GPCT_TIMESTAMP_MUX_GATE_SELECT:
        case NI_GPCT_AI_START2_GATE_SELECT:
        case NI_GPCT_PXI_STAR_TRIGGER_GATE_SELECT:
@@ -1042,118 +796,99 @@ static int ni_m_series_set_first_gate(struct ni_gpct *counter,
        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;
+               gate_sel = chan & 0x1f;
                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;
+               for (i = 0; i <= NI_M_MAX_RTSI_CHAN; ++i) {
+                       if (chan == NI_GPCT_RTSI_GATE_SELECT(i)) {
+                               gate_sel = chan & 0x1f;
                                break;
                        }
                }
-               if (i <= ni_m_series_max_rtsi_channel)
+               if (i <= NI_M_MAX_RTSI_CHAN)
                        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;
+               for (i = 0; i <= NI_M_MAX_PFI_CHAN; ++i) {
+                       if (chan == NI_GPCT_PFI_GATE_SELECT(i)) {
+                               gate_sel = chan & 0x1f;
                                break;
                        }
                }
-               if (i <= ni_m_series_max_pfi_channel)
+               if (i <= NI_M_MAX_PFI_CHAN)
                        break;
                return -EINVAL;
        }
        ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx),
-                       Gi_Gate_Select_Mask,
-                       Gi_Gate_Select_Bits(ni_m_series_gate_select));
+                       GI_GATE_SEL_MASK, GI_GATE_SEL(gate_sel));
        return 0;
 }
 
-static int ni_660x_set_second_gate(struct ni_gpct *counter,
-                                  unsigned int gate_source)
+static int ni_660x_set_gate2(struct ni_gpct *counter, unsigned int gate_source)
 {
        struct ni_gpct_device *counter_dev = counter->counter_dev;
        unsigned cidx = counter->counter_index;
-       const unsigned second_gate_reg = NITIO_GATE2_REG(cidx);
-       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 int chan = CR_CHAN(gate_source);
+       unsigned gate2_reg = NITIO_GATE2_REG(cidx);
+       unsigned gate2_sel;
        unsigned i;
 
-       switch (selected_second_gate) {
+       switch (chan) {
        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;
+               gate2_sel = chan & 0x1f;
                break;
        case NI_GPCT_NEXT_SOURCE_GATE_SELECT:
-               ni_660x_second_gate_select =
-                   NI_660x_Next_SRC_Second_Gate_Select;
+               gate2_sel = NI_660X_NEXT_SRC_GATE2_SEL;
                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;
+               for (i = 0; i <= NI_660X_MAX_RTSI_CHAN; ++i) {
+                       if (chan == NI_GPCT_RTSI_GATE_SELECT(i)) {
+                               gate2_sel = chan & 0x1f;
                                break;
                        }
                }
-               if (i <= ni_660x_max_rtsi_channel)
+               if (i <= NI_660X_MAX_RTSI_CHAN)
                        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;
+               for (i = 0; i <= NI_660X_MAX_UP_DOWN_PIN; ++i) {
+                       if (chan == NI_GPCT_UP_DOWN_PIN_GATE_SELECT(i)) {
+                               gate2_sel = chan & 0x1f;
                                break;
                        }
                }
-               if (i <= ni_660x_max_up_down_pin)
+               if (i <= NI_660X_MAX_UP_DOWN_PIN)
                        break;
                return -EINVAL;
        }
-       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);
+       counter_dev->regs[gate2_reg] |= GI_GATE2_MODE;
+       counter_dev->regs[gate2_reg] &= ~GI_GATE2_SEL_MASK;
+       counter_dev->regs[gate2_reg] |= GI_GATE2_SEL(gate2_sel);
+       write_register(counter, counter_dev->regs[gate2_reg], gate2_reg);
        return 0;
 }
 
-static int ni_m_series_set_second_gate(struct ni_gpct *counter,
-                                      unsigned int gate_source)
+static int ni_m_set_gate2(struct ni_gpct *counter, unsigned int gate_source)
 {
        struct ni_gpct_device *counter_dev = counter->counter_dev;
        unsigned cidx = counter->counter_index;
-       const unsigned second_gate_reg = NITIO_GATE2_REG(cidx);
-       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) {
+       unsigned int chan = CR_CHAN(gate_source);
+       unsigned gate2_reg = NITIO_GATE2_REG(cidx);
+       unsigned gate2_sel;
+
+       /*
+        * FIXME: We don't know what the m-series second gate codes are,
+        * so we'll just pass the bits through for now.
+        */
+       switch (chan) {
        default:
-               ni_m_series_second_gate_select =
-                   selected_second_gate & selected_second_gate_mask;
+               gate2_sel = chan & 0x1f;
                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);
+       counter_dev->regs[gate2_reg] |= GI_GATE2_MODE;
+       counter_dev->regs[gate2_reg] &= ~GI_GATE2_SEL_MASK;
+       counter_dev->regs[gate2_reg] |= GI_GATE2_SEL(gate2_sel);
+       write_register(counter, counter_dev->regs[gate2_reg], gate2_reg);
        return 0;
 }
 
@@ -1162,52 +897,55 @@ int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned gate_index,
 {
        struct ni_gpct_device *counter_dev = counter->counter_dev;
        unsigned cidx = counter->counter_index;
-       const unsigned second_gate_reg = NITIO_GATE2_REG(cidx);
+       unsigned int chan = CR_CHAN(gate_source);
+       unsigned gate2_reg = NITIO_GATE2_REG(cidx);
+       unsigned mode = 0;
 
        switch (gate_index) {
        case 0:
-               if (CR_CHAN(gate_source) == NI_GPCT_DISABLED_GATE_SELECT) {
+               if (chan == NI_GPCT_DISABLED_GATE_SELECT) {
                        ni_tio_set_bits(counter, NITIO_MODE_REG(cidx),
-                                       Gi_Gating_Mode_Mask,
-                                       Gi_Gating_Disabled_Bits);
+                                       GI_GATING_MODE_MASK,
+                                       GI_GATING_DISABLED);
                        return 0;
                }
-               ni_tio_set_first_gate_modifiers(counter, gate_source);
+               if (gate_source & CR_INVERT)
+                       mode |= GI_GATE_POL_INVERT;
+               if (gate_source & CR_EDGE)
+                       mode |= GI_RISING_EDGE_GATING;
+               else
+                       mode |= GI_LEVEL_GATING;
+               ni_tio_set_bits(counter, NITIO_MODE_REG(cidx),
+                               GI_GATE_POL_INVERT | GI_GATING_MODE_MASK,
+                               mode);
                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);
-               case ni_gpct_variant_660x:
-                       return ni_660x_set_first_gate(counter, gate_source);
                default:
-                       BUG();
-                       break;
+                       return ni_m_set_gate(counter, gate_source);
+               case ni_gpct_variant_660x:
+                       return ni_660x_set_gate(counter, gate_source);
                }
                break;
        case 1:
-               if (ni_tio_second_gate_registers_present(counter_dev) == 0)
+               if (!ni_tio_has_gate2_registers(counter_dev))
                        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);
+
+               if (chan == NI_GPCT_DISABLED_GATE_SELECT) {
+                       counter_dev->regs[gate2_reg] &= ~GI_GATE2_MODE;
+                       write_register(counter, counter_dev->regs[gate2_reg],
+                                      gate2_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;
-               }
+               if (gate_source & CR_INVERT)
+                       counter_dev->regs[gate2_reg] |= GI_GATE2_POL_INVERT;
+               else
+                       counter_dev->regs[gate2_reg] &= ~GI_GATE2_POL_INVERT;
                switch (counter_dev->variant) {
                case ni_gpct_variant_m_series:
-                       return ni_m_series_set_second_gate(counter,
-                                                          gate_source);
+                       return ni_m_set_gate2(counter, gate_source);
                case ni_gpct_variant_660x:
-                       return ni_660x_set_second_gate(counter, gate_source);
+                       return ni_660x_set_gate2(counter, gate_source);
                default:
                        BUG();
                        break;
@@ -1225,169 +963,142 @@ static int ni_tio_set_other_src(struct ni_gpct *counter, unsigned index,
 {
        struct ni_gpct_device *counter_dev = counter->counter_dev;
        unsigned cidx = counter->counter_index;
+       unsigned int abz_reg, shift, mask;
 
-       if (counter_dev->variant == ni_gpct_variant_m_series) {
-               unsigned int abz_reg, shift, mask;
+       if (counter_dev->variant != ni_gpct_variant_m_series)
+               return -EINVAL;
 
-               abz_reg = NITIO_ABZ_REG(cidx);
-               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;
-               }
-               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;
+       abz_reg = NITIO_ABZ_REG(cidx);
+       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;
        }
-       return -EINVAL;
+       mask = 0x1f << shift;
+       if (source > 0x1f)
+               source = 0x1f;  /* Disable gate */
+
+       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;
 }
 
-static unsigned ni_660x_first_gate_to_generic_gate_source(unsigned
-                                                         ni_660x_gate_select)
+static unsigned ni_660x_gate_to_generic_gate(unsigned gate)
 {
        unsigned i;
 
-       switch (ni_660x_gate_select) {
-       case NI_660x_Source_Pin_i_Gate_Select:
+       switch (gate) {
+       case NI_660X_SRC_PIN_I_GATE_SEL:
                return NI_GPCT_SOURCE_PIN_i_GATE_SELECT;
-       case NI_660x_Gate_Pin_i_Gate_Select:
+       case NI_660X_GATE_PIN_I_GATE_SEL:
                return NI_GPCT_GATE_PIN_i_GATE_SELECT;
-       case NI_660x_Next_SRC_Gate_Select:
+       case NI_660X_NEXT_SRC_GATE_SEL:
                return NI_GPCT_NEXT_SOURCE_GATE_SELECT;
-       case NI_660x_Next_Out_Gate_Select:
+       case NI_660X_NEXT_OUT_GATE_SEL:
                return NI_GPCT_NEXT_OUT_GATE_SELECT;
-       case NI_660x_Logic_Low_Gate_Select:
+       case NI_660X_LOGIC_LOW_GATE_SEL:
                return NI_GPCT_LOGIC_LOW_GATE_SELECT;
        default:
-               for (i = 0; i <= ni_660x_max_rtsi_channel; ++i) {
-                       if (ni_660x_gate_select == NI_660x_RTSI_Gate_Select(i)) {
+               for (i = 0; i <= NI_660X_MAX_RTSI_CHAN; ++i) {
+                       if (gate == NI_660X_RTSI_GATE_SEL(i))
                                return NI_GPCT_RTSI_GATE_SELECT(i);
-                       }
                }
-               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)) {
+               for (i = 0; i <= NI_660X_MAX_GATE_PIN; ++i) {
+                       if (gate == NI_660X_PIN_GATE_SEL(i))
                                return NI_GPCT_GATE_PIN_GATE_SELECT(i);
-                       }
                }
-               if (i <= ni_660x_max_gate_pin)
-                       break;
                BUG();
                break;
        }
        return 0;
 };
 
-static unsigned ni_m_series_first_gate_to_generic_gate_source(unsigned
-                                                             ni_m_series_gate_select)
+static unsigned ni_m_gate_to_generic_gate(unsigned gate)
 {
        unsigned i;
 
-       switch (ni_m_series_gate_select) {
-       case NI_M_Series_Timestamp_Mux_Gate_Select:
+       switch (gate) {
+       case NI_M_TIMESTAMP_MUX_GATE_SEL:
                return NI_GPCT_TIMESTAMP_MUX_GATE_SELECT;
-       case NI_M_Series_AI_START2_Gate_Select:
+       case NI_M_AI_START2_GATE_SEL:
                return NI_GPCT_AI_START2_GATE_SELECT;
-       case NI_M_Series_PXI_Star_Trigger_Gate_Select:
+       case NI_M_PXI_STAR_TRIGGER_GATE_SEL:
                return NI_GPCT_PXI_STAR_TRIGGER_GATE_SELECT;
-       case NI_M_Series_Next_Out_Gate_Select:
+       case NI_M_NEXT_OUT_GATE_SEL:
                return NI_GPCT_NEXT_OUT_GATE_SELECT;
-       case NI_M_Series_AI_START1_Gate_Select:
+       case NI_M_AI_START1_GATE_SEL:
                return NI_GPCT_AI_START1_GATE_SELECT;
-       case NI_M_Series_Next_SRC_Gate_Select:
+       case NI_M_NEXT_SRC_GATE_SEL:
                return NI_GPCT_NEXT_SOURCE_GATE_SELECT;
-       case NI_M_Series_Analog_Trigger_Out_Gate_Select:
+       case NI_M_ANALOG_TRIG_OUT_GATE_SEL:
                return NI_GPCT_ANALOG_TRIGGER_OUT_GATE_SELECT;
-       case NI_M_Series_Logic_Low_Gate_Select:
+       case NI_M_LOGIC_LOW_GATE_SEL:
                return NI_GPCT_LOGIC_LOW_GATE_SELECT;
        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)) {
+               for (i = 0; i <= NI_M_MAX_RTSI_CHAN; ++i) {
+                       if (gate == NI_M_RTSI_GATE_SEL(i))
                                return NI_GPCT_RTSI_GATE_SELECT(i);
-                       }
                }
-               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)) {
+               for (i = 0; i <= NI_M_MAX_PFI_CHAN; ++i) {
+                       if (gate == NI_M_PFI_GATE_SEL(i))
                                return NI_GPCT_PFI_GATE_SELECT(i);
-                       }
                }
-               if (i <= ni_m_series_max_pfi_channel)
-                       break;
                BUG();
                break;
        }
        return 0;
 };
 
-static unsigned ni_660x_second_gate_to_generic_gate_source(unsigned
-                                                          ni_660x_gate_select)
+static unsigned ni_660x_gate2_to_generic_gate(unsigned gate)
 {
        unsigned i;
 
-       switch (ni_660x_gate_select) {
-       case NI_660x_Source_Pin_i_Second_Gate_Select:
+       switch (gate) {
+       case NI_660X_SRC_PIN_I_GATE2_SEL:
                return NI_GPCT_SOURCE_PIN_i_GATE_SELECT;
-       case NI_660x_Up_Down_Pin_i_Second_Gate_Select:
+       case NI_660X_UD_PIN_I_GATE2_SEL:
                return NI_GPCT_UP_DOWN_PIN_i_GATE_SELECT;
-       case NI_660x_Next_SRC_Second_Gate_Select:
+       case NI_660X_NEXT_SRC_GATE2_SEL:
                return NI_GPCT_NEXT_SOURCE_GATE_SELECT;
-       case NI_660x_Next_Out_Second_Gate_Select:
+       case NI_660X_NEXT_OUT_GATE2_SEL:
                return NI_GPCT_NEXT_OUT_GATE_SELECT;
-       case NI_660x_Selected_Gate_Second_Gate_Select:
+       case NI_660X_SELECTED_GATE2_SEL:
                return NI_GPCT_SELECTED_GATE_GATE_SELECT;
-       case NI_660x_Logic_Low_Second_Gate_Select:
+       case NI_660X_LOGIC_LOW_GATE2_SEL:
                return NI_GPCT_LOGIC_LOW_GATE_SELECT;
        default:
-               for (i = 0; i <= ni_660x_max_rtsi_channel; ++i) {
-                       if (ni_660x_gate_select ==
-                           NI_660x_RTSI_Second_Gate_Select(i)) {
+               for (i = 0; i <= NI_660X_MAX_RTSI_CHAN; ++i) {
+                       if (gate == NI_660X_RTSI_GATE2_SEL(i))
                                return NI_GPCT_RTSI_GATE_SELECT(i);
-                       }
                }
-               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)) {
+               for (i = 0; i <= NI_660X_MAX_UP_DOWN_PIN; ++i) {
+                       if (gate == NI_660X_UD_PIN_GATE2_SEL(i))
                                return NI_GPCT_UP_DOWN_PIN_GATE_SELECT(i);
-                       }
                }
-               if (i <= ni_660x_max_up_down_pin)
-                       break;
                BUG();
                break;
        }
        return 0;
 };
 
-static unsigned ni_m_series_second_gate_to_generic_gate_source(unsigned
-                                                              ni_m_series_gate_select)
+static unsigned ni_m_gate2_to_generic_gate(unsigned gate)
 {
-       /*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) {
+       /*
+        * FIXME: the second gate sources for the m series are undocumented,
+        * so we just return the raw bits for now.
+        */
+       switch (gate) {
        default:
-               return ni_m_series_gate_select;
+               return gate;
        }
        return 0;
 };
@@ -1397,79 +1108,58 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index,
 {
        struct ni_gpct_device *counter_dev = counter->counter_dev;
        unsigned cidx = counter->counter_index;
-       const unsigned mode_bits =
-               ni_tio_get_soft_copy(counter, NITIO_MODE_REG(cidx));
-       const unsigned second_gate_reg = NITIO_GATE2_REG(cidx);
-       unsigned gate_select_bits;
+       unsigned mode = ni_tio_get_soft_copy(counter, NITIO_MODE_REG(cidx));
+       unsigned gate2_reg = NITIO_GATE2_REG(cidx);
+       unsigned gate;
 
        switch (gate_index) {
        case 0:
-               if ((mode_bits & Gi_Gating_Mode_Mask) ==
-                   Gi_Gating_Disabled_Bits) {
+               if ((mode & GI_GATING_MODE_MASK) == GI_GATING_DISABLED) {
                        *gate_source = NI_GPCT_DISABLED_GATE_SELECT;
                        return 0;
-               } else {
-                       gate_select_bits =
-                           (ni_tio_get_soft_copy(counter,
-                                                 NITIO_INPUT_SEL_REG(cidx)) &
-                            Gi_Gate_Select_Mask) >> Gi_Gate_Select_Shift;
                }
+
+               gate = GI_BITS_TO_GATE(ni_tio_get_soft_copy(counter,
+                                               NITIO_INPUT_SEL_REG(cidx)));
+
                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);
+               default:
+                       *gate_source = ni_m_gate_to_generic_gate(gate);
                        break;
                case ni_gpct_variant_660x:
-                       *gate_source =
-                           ni_660x_first_gate_to_generic_gate_source
-                           (gate_select_bits);
-                       break;
-               default:
-                       BUG();
+                       *gate_source = ni_660x_gate_to_generic_gate(gate);
                        break;
                }
-               if (mode_bits & Gi_Gate_Polarity_Bit)
+               if (mode & GI_GATE_POL_INVERT)
                        *gate_source |= CR_INVERT;
-               if ((mode_bits & Gi_Gating_Mode_Mask) != Gi_Level_Gating_Bits)
+               if ((mode & GI_GATING_MODE_MASK) != GI_LEVEL_GATING)
                        *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) {
+               if ((mode & GI_GATING_MODE_MASK) == GI_GATING_DISABLED ||
+                   !(counter_dev->regs[gate2_reg] & GI_GATE2_MODE)) {
                        *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;
                }
+
+               gate = GI_BITS_TO_GATE2(counter_dev->regs[gate2_reg]);
+
                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);
+               default:
+                       *gate_source = ni_m_gate2_to_generic_gate(gate);
                        break;
                case ni_gpct_variant_660x:
-                       *gate_source =
-                           ni_660x_second_gate_to_generic_gate_source
-                           (gate_select_bits);
-                       break;
-               default:
-                       BUG();
+                       *gate_source = ni_660x_gate2_to_generic_gate(gate);
                        break;
                }
-               if (counter_dev->regs[second_gate_reg] &
-                   Gi_Second_Gate_Polarity_Bit) {
+               if (counter_dev->regs[gate2_reg] & GI_GATE2_POL_INVERT)
                        *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)
+               if ((mode & GI_GATING_MODE_MASK) != GI_LEVEL_GATING)
                        *gate_source |= CR_EDGE;
                break;
        default:
@@ -1484,6 +1174,8 @@ int ni_tio_insn_config(struct comedi_device *dev,
                       unsigned int *data)
 {
        struct ni_gpct *counter = s->private;
+       unsigned cidx = counter->counter_index;
+       unsigned status;
 
        switch (data[0]) {
        case INSN_CONFIG_SET_COUNTER_MODE:
@@ -1494,8 +1186,14 @@ int ni_tio_insn_config(struct comedi_device *dev,
                ni_tio_arm(counter, 0, 0);
                return 0;
        case INSN_CONFIG_GET_COUNTER_STATUS:
-               data[1] = ni_tio_counter_status(counter);
-               data[2] = counter_status_mask;
+               data[1] = 0;
+               status = read_register(counter, NITIO_SHARED_STATUS_REG(cidx));
+               if (status & GI_ARMED(cidx)) {
+                       data[1] |= COMEDI_COUNTER_ARMED;
+                       if (status & GI_COUNTING(cidx))
+                               data[1] |= COMEDI_COUNTER_COUNTING;
+               }
+               data[2] = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING;
                return 0;
        case INSN_CONFIG_SET_CLOCK_SRC:
                return ni_tio_set_clock_src(counter, data[1], data[2]);
@@ -1518,6 +1216,33 @@ int ni_tio_insn_config(struct comedi_device *dev,
 }
 EXPORT_SYMBOL_GPL(ni_tio_insn_config);
 
+static unsigned int ni_tio_read_sw_save_reg(struct comedi_device *dev,
+                                           struct comedi_subdevice *s)
+{
+       struct ni_gpct *counter = s->private;
+       unsigned cidx = counter->counter_index;
+       unsigned int val;
+
+       ni_tio_set_bits(counter, NITIO_CMD_REG(cidx), GI_SAVE_TRACE, 0);
+       ni_tio_set_bits(counter, NITIO_CMD_REG(cidx),
+                       GI_SAVE_TRACE, GI_SAVE_TRACE);
+
+       /*
+        * 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.
+        */
+       val = read_register(counter, NITIO_SW_SAVE_REG(cidx));
+       if (val != read_register(counter, NITIO_SW_SAVE_REG(cidx)))
+               val = read_register(counter, NITIO_SW_SAVE_REG(cidx));
+
+       return val;
+}
+
 int ni_tio_insn_read(struct comedi_device *dev,
                     struct comedi_subdevice *s,
                     struct comedi_insn *insn,
@@ -1525,42 +1250,24 @@ int ni_tio_insn_read(struct comedi_device *dev,
 {
        struct ni_gpct *counter = s->private;
        struct ni_gpct_device *counter_dev = counter->counter_dev;
-       const unsigned channel = CR_CHAN(insn->chanspec);
+       unsigned int channel = CR_CHAN(insn->chanspec);
        unsigned cidx = counter->counter_index;
-       unsigned first_read;
-       unsigned second_read;
-       unsigned correct_read;
+       int i;
 
-       if (insn->n < 1)
-               return 0;
-       switch (channel) {
-       case 0:
-               ni_tio_set_bits(counter, NITIO_CMD_REG(cidx),
-                               Gi_Save_Trace_Bit, 0);
-               ni_tio_set_bits(counter, NITIO_CMD_REG(cidx),
-                               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_SW_SAVE_REG(cidx));
-               second_read = read_register(counter, NITIO_SW_SAVE_REG(cidx));
-               if (first_read != second_read)
-                       correct_read =
-                           read_register(counter, NITIO_SW_SAVE_REG(cidx));
-               else
-                       correct_read = first_read;
-               data[0] = correct_read;
-               return 0;
-       case 1:
-               data[0] = counter_dev->regs[NITIO_LOADA_REG(cidx)];
-               break;
-       case 2:
-               data[0] = counter_dev->regs[NITIO_LOADB_REG(cidx)];
-               break;
+       for (i = 0; i < insn->n; i++) {
+               switch (channel) {
+               case 0:
+                       data[i] = ni_tio_read_sw_save_reg(dev, s);
+                       break;
+               case 1:
+                       data[i] = counter_dev->regs[NITIO_LOADA_REG(cidx)];
+                       break;
+               case 2:
+                       data[i] = counter_dev->regs[NITIO_LOADB_REG(cidx)];
+                       break;
+               }
        }
-       return 0;
+       return insn->n;
 }
 EXPORT_SYMBOL_GPL(ni_tio_insn_read);
 
@@ -1570,10 +1277,9 @@ static unsigned ni_tio_next_load_register(struct ni_gpct *counter)
        const unsigned bits =
                read_register(counter, NITIO_SHARED_STATUS_REG(cidx));
 
-       if (bits & Gi_Next_Load_Source_Bit(cidx))
-               return NITIO_LOADB_REG(cidx);
-       else
-               return NITIO_LOADA_REG(cidx);
+       return (bits & GI_NEXT_LOAD_SRC(cidx))
+                       ? NITIO_LOADB_REG(cidx)
+                       : NITIO_LOADA_REG(cidx);
 }
 
 int ni_tio_insn_write(struct comedi_device *dev,
@@ -1591,13 +1297,20 @@ int ni_tio_insn_write(struct comedi_device *dev,
                return 0;
        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. */
+               /*
+                * 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_CMD_REG(cidx),
-                                         0, 0, Gi_Load_Bit);
-               /* restore state of load reg to whatever the user set last set it to */
+                                         0, 0, GI_LOAD);
+               /* restore load reg */
                write_register(counter, counter_dev->regs[load_reg], load_reg);
                break;
        case 1:
@@ -1615,6 +1328,99 @@ int ni_tio_insn_write(struct comedi_device *dev,
 }
 EXPORT_SYMBOL_GPL(ni_tio_insn_write);
 
+void ni_tio_init_counter(struct ni_gpct *counter)
+{
+       struct ni_gpct_device *counter_dev = counter->counter_dev;
+       unsigned cidx = counter->counter_index;
+
+       ni_tio_reset_count_and_disarm(counter);
+
+       /* initialize counter registers */
+       counter_dev->regs[NITIO_AUTO_INC_REG(cidx)] = 0x0;
+       write_register(counter, 0x0, NITIO_AUTO_INC_REG(cidx));
+
+       ni_tio_set_bits(counter, NITIO_CMD_REG(cidx),
+                       ~0, GI_SYNC_GATE);
+
+       ni_tio_set_bits(counter, NITIO_MODE_REG(cidx), ~0, 0);
+
+       counter_dev->regs[NITIO_LOADA_REG(cidx)] = 0x0;
+       write_register(counter, 0x0, NITIO_LOADA_REG(cidx));
+
+       counter_dev->regs[NITIO_LOADB_REG(cidx)] = 0x0;
+       write_register(counter, 0x0, NITIO_LOADB_REG(cidx));
+
+       ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), ~0, 0);
+
+       if (ni_tio_counting_mode_registers_present(counter_dev))
+               ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx), ~0, 0);
+
+       if (ni_tio_has_gate2_registers(counter_dev)) {
+               counter_dev->regs[NITIO_GATE2_REG(cidx)] = 0x0;
+               write_register(counter, 0x0, NITIO_GATE2_REG(cidx));
+       }
+
+       ni_tio_set_bits(counter, NITIO_DMA_CFG_REG(cidx), ~0, 0x0);
+
+       ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx), ~0, 0x0);
+}
+EXPORT_SYMBOL_GPL(ni_tio_init_counter);
+
+struct ni_gpct_device *
+ni_gpct_device_construct(struct comedi_device *dev,
+                        void (*write_register)(struct ni_gpct *counter,
+                                               unsigned bits,
+                                               enum ni_gpct_register reg),
+                        unsigned (*read_register)(struct ni_gpct *counter,
+                                                  enum ni_gpct_register reg),
+                        enum ni_gpct_variant variant,
+                        unsigned num_counters)
+{
+       struct ni_gpct_device *counter_dev;
+       struct ni_gpct *counter;
+       unsigned i;
+
+       if (num_counters == 0)
+               return NULL;
+
+       counter_dev = kzalloc(sizeof(*counter_dev), GFP_KERNEL);
+       if (!counter_dev)
+               return NULL;
+
+       counter_dev->dev = dev;
+       counter_dev->write_register = write_register;
+       counter_dev->read_register = read_register;
+       counter_dev->variant = variant;
+
+       spin_lock_init(&counter_dev->regs_lock);
+
+       counter_dev->counters = kcalloc(num_counters, sizeof(*counter),
+                                       GFP_KERNEL);
+       if (!counter_dev->counters) {
+               kfree(counter_dev);
+               return NULL;
+       }
+
+       for (i = 0; i < num_counters; ++i) {
+               counter = &counter_dev->counters[i];
+               counter->counter_dev = counter_dev;
+               spin_lock_init(&counter->lock);
+       }
+       counter_dev->num_counters = num_counters;
+
+       return counter_dev;
+}
+EXPORT_SYMBOL_GPL(ni_gpct_device_construct);
+
+void ni_gpct_device_destroy(struct ni_gpct_device *counter_dev)
+{
+       if (!counter_dev->counters)
+               return;
+       kfree(counter_dev->counters);
+       kfree(counter_dev);
+}
+EXPORT_SYMBOL_GPL(ni_gpct_device_destroy);
+
 static int __init ni_tio_init_module(void)
 {
        return 0;