Patch from terry1@beam.ltd.uk (Terry Barnaby):
authorFrank Mori Hess <fmhess@speakeasy.net>
Fri, 3 Mar 2006 00:58:47 +0000 (00:58 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Fri, 3 Mar 2006 00:58:47 +0000 (00:58 +0000)
This patch adds support to comedi for the NI PCI-6143 DAQ card.
It also adds support for the NI RTSI trigger bus used to synchronise multiple
cards to any ni_pcimio supported card.
The patch also requires a patch to the comedilib to support the RTSI.
More info on the patch is at: http://www.beam.org.uk/opensource/pci-6143/

comedi/drivers/ni_mio_common.c
comedi/drivers/ni_pcimio.c
comedi/drivers/ni_stc.h
include/linux/comedi.h

index 5eebad0ba90788ff483cfd93fe7e195ddd184a48..ca276cacc4371e76824bae0749845255a29dd80b 100644 (file)
@@ -53,6 +53,9 @@
 
         - the interrupt routine needs to be cleaned up
         - many printk's need to be changed to rt_printk()
+
+       2006-02-07: S-Series PCI-6143: Support has been added but is not
+               fully tested as yet. Terry Barnaby, BEAM Ltd.
 */
 
 //#define DEBUG_INTERRUPT
@@ -88,7 +91,9 @@ static short ni_gainlkup[][16]={
        /* ai_gain_622x */
        { 0, 1, 4, 5},
        /* ai_gain_628x */
-       { 1, 2, 3, 4, 5, 6, 7}
+       { 1, 2, 3, 4, 5, 6, 7},
+       /* ai_gain_6143 */
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
 };
 
 static comedi_lrange range_ni_E_ai={   16, {
@@ -166,6 +171,9 @@ static comedi_lrange range_ni_M_ai_628x={ 7, {
        RANGE( -0.2,    0.2     ),
        RANGE( -0.1,    0.1     ),
 }};
+static comedi_lrange range_ni_S_ai_6143 = { 1, {
+       RANGE( -5,      +5      ),
+}};
 static comedi_lrange range_ni_E_ao_ext = { 4, {
        RANGE( -10,     10      ),
        RANGE( 0,       10      ),
@@ -180,7 +188,8 @@ static comedi_lrange *ni_range_lkup[]={
        &range_ni_E_ai_bipolar4,
        &range_ni_E_ai_611x,
        &range_ni_M_ai_622x,
-       &range_ni_M_ai_628x
+       &range_ni_M_ai_628x,
+       &range_ni_S_ai_6143
 };
 
 
@@ -212,6 +221,12 @@ static int ni_pfi_insn_bits(comedi_device *dev,comedi_subdevice *s,
 static int ni_pfi_insn_config(comedi_device *dev,comedi_subdevice *s,
        comedi_insn *insn,lsampl_t *data);
 
+static void ni_rtsi_init(comedi_device *dev);
+static int ni_rtsi_insn_bits(comedi_device *dev,comedi_subdevice *s,
+       comedi_insn *insn,lsampl_t *data);
+static int ni_rtsi_insn_config(comedi_device *dev,comedi_subdevice *s,
+       comedi_insn *insn,lsampl_t *data);
+
 static void caldac_setup(comedi_device *dev,comedi_subdevice *s);
 static int ni_read_eeprom(comedi_device *dev,int addr);
 
@@ -276,6 +291,8 @@ static void cs5529_config_write(comedi_device *dev, unsigned int value, unsigned
 
 static int ni_m_series_pwm_config(comedi_device *dev, comedi_subdevice *s,
        comedi_insn *insn,lsampl_t *data);
+static int ni_6143_pwm_config(comedi_device *dev, comedi_subdevice *s,
+       comedi_insn *insn, lsampl_t *data);
        
 enum aimodes
 {
@@ -297,11 +314,24 @@ static void handle_a_interrupt(comedi_device *dev,unsigned short status,
 static void handle_b_interrupt(comedi_device *dev,unsigned short status,
        unsigned int m_status);
 static void get_last_sample_611x( comedi_device *dev );
+static void get_last_sample_6143( comedi_device *dev );
 #ifdef PCIDMA
 //static void mite_handle_interrupt(comedi_device *dev,unsigned int status);
 static int ni_ai_drain_dma(comedi_device *dev );
 #endif
 
+static void ni_flush_ai_fifo(comedi_device *dev){
+       if(boardtype.reg_type == ni_reg_6143){
+               // Flush the 6143 data FIFO
+               ni_writel(0x10, AIFIFO_Control_6143);           // Flush fifo
+               ni_writel(0x00, AIFIFO_Control_6143);           // Flush fifo
+               while(ni_readl(AIFIFO_Status_6143) & 0x10);     // Wait for complete
+       }
+       else {
+               devpriv->stc_writew(dev, 1,ADC_FIFO_Clear);
+       }
+}
+
 static void win_out2(comedi_device *dev, uint32_t data, int reg)
 {
        devpriv->stc_writew(dev, data >> 16, reg);
@@ -563,6 +593,7 @@ static void shutdown_ai_command( comedi_device *dev )
 #endif
        ni_handle_fifo_dregs(dev);
        get_last_sample_611x(dev);
+       get_last_sample_6143(dev);
 
        ni_set_bits(dev, Interrupt_A_Enable_Register,
                AI_SC_TC_Interrupt_Enable | AI_START1_Interrupt_Enable|
@@ -931,7 +962,26 @@ static void ni_ai_fifo_read(comedi_device *dev,comedi_subdevice *s,
                        data[0] = dl & 0xffff;
                        cfc_write_to_buffer(s, data[0]);
                }
-       }else{
+       } else if(boardtype.reg_type == ni_reg_6143){
+               sampl_t data[2];
+               u32     dl;
+
+               // This just reads the FIFO assuming the data is present, no checks on the FIFO status are performed
+               for(i = 0; i < n / 2; i++){
+                       dl = ni_readl(AIFIFO_Data_6143);
+
+                       data[0] = (dl >> 16) & 0xffff;
+                       data[1] = dl & 0xffff;
+                       cfc_write_array_to_buffer(s, data, sizeof(data));
+               }
+               if(n % 2){
+                       /* Assume there is a single sample stuck in the FIFO */
+                       ni_writel(0x01, AIFIFO_Control_6143);   // Get stranded sample into FIFO
+                       dl = ni_readl(AIFIFO_Data_6143);
+                       data[0] = (dl >> 16) & 0xffff;
+                       cfc_write_to_buffer(s, data[0]);
+               }
+       } else{
                if( n > sizeof(devpriv->ai_fifo_buffer) / sizeof(devpriv->ai_fifo_buffer[0]))
                {
                        comedi_error( dev, "bug! ai_fifo_buffer too small" );
@@ -1004,6 +1054,25 @@ static void ni_handle_fifo_dregs(comedi_device *dev)
                        data[1] = (dl&0xffff);
                        cfc_write_array_to_buffer(s, data, sizeof(data));
                }
+       }else if(boardtype.reg_type == ni_reg_6143){
+               i = 0;
+               while(ni_readl(AIFIFO_Status_6143) & 0x04){
+                       dl = ni_readl(AIFIFO_Data_6143);
+
+                       /* This may get the hi/lo data in the wrong order */
+                       data[0] = (dl >> 16);
+                       data[1] = (dl & 0xffff);
+                       cfc_write_array_to_buffer(s, data, sizeof(data));
+                       i += 2;
+               }
+               // Check if stranded sample is present
+               if(ni_readl(AIFIFO_Status_6143) & 0x01){
+                       ni_writel(0x01, AIFIFO_Control_6143);   // Get stranded sample into FIFO
+                       dl = ni_readl(AIFIFO_Data_6143);
+                       data[0] = (dl >> 16) & 0xffff;
+                       cfc_write_to_buffer(s, data[0]);
+               }
+
        }else{
                fifo_empty = devpriv->stc_readw(dev, AI_Status_1_Register) & AI_FIFO_Empty_St;
                while(fifo_empty == 0)
@@ -1036,6 +1105,25 @@ static void get_last_sample_611x( comedi_device *dev )
        }
 }
 
+static void get_last_sample_6143(comedi_device* dev)
+{
+       comedi_subdevice*       s = dev->subdevices + 0;
+       sampl_t                 data;
+       u32                     dl;
+
+       if(boardtype.reg_type != ni_reg_6143) return;
+
+       /* Check if there's a single sample stuck in the FIFO */
+       if(ni_readl(AIFIFO_Status_6143) & 0x01){
+               ni_writel(0x01, AIFIFO_Control_6143);   // Get stranded sample into FIFO
+               dl = ni_readl(AIFIFO_Data_6143);
+
+               /* This may get the hi/lo data in the wrong order */
+               data = (dl >> 16) & 0xffff;
+               cfc_write_to_buffer(s, data);
+       }
+}
+
 static void ni_ai_munge(comedi_device *dev, comedi_subdevice *s,
        void *data, unsigned int num_bytes, unsigned int chan_index )
 {
@@ -1078,6 +1166,7 @@ static void ni_ai_setup_MITE_dma(comedi_device *dev,comedi_cmd *cmd)
        switch(boardtype.reg_type)
        {
        case ni_reg_611x:
+       case ni_reg_6143:
                mite_prep_dma(mite, AI_DMA_CHAN, 32, 16);
                break;
        case ni_reg_m_series:
@@ -1135,9 +1224,10 @@ static int ni_ai_reset(comedi_device *dev,comedi_subdevice *s)
                AI_STOP_Interrupt_Enable|   AI_Error_Interrupt_Enable|
                AI_FIFO_Interrupt_Enable,0);
 
-       devpriv->stc_writew(dev, 1,ADC_FIFO_Clear);
+       ni_flush_ai_fifo(dev);
 
-       ni_writeb(0, Misc_Command);
+       if(boardtype.reg_type != ni_reg_6143)
+               ni_writeb(0, Misc_Command);
 
        devpriv->stc_writew(dev, AI_Disarm, AI_Command_1_Register); /* reset pulses */
        devpriv->stc_writew(dev, AI_Start_Stop | AI_Mode_1_Reserved /*| AI_Trigger_Once */,
@@ -1154,6 +1244,15 @@ static int ni_ai_reset(comedi_device *dev,comedi_subdevice *s)
                        AI_LOCALMUX_CLK_Output_Select(2) |
                        AI_SC_TC_Output_Select(3) |
                        AI_CONVERT_Output_Select(3),AI_Output_Control_Register);
+       }else if(boardtype.reg_type == ni_reg_6143){
+               devpriv->stc_writew(dev, AI_SHIFTIN_Pulse_Width |
+                       AI_SOC_Polarity |
+                       AI_LOCALMUX_CLK_Pulse_Width, AI_Personal_Register);
+               devpriv->stc_writew(dev, AI_SCAN_IN_PROG_Output_Select(3) |
+                       AI_EXTMUX_CLK_Output_Select(0) |
+                       AI_LOCALMUX_CLK_Output_Select(2) |
+                       AI_SC_TC_Output_Select(3) |
+                       AI_CONVERT_Output_Select(2),AI_Output_Control_Register);
        }else{
                devpriv->stc_writew(dev, AI_SHIFTIN_Pulse_Width |
                        AI_SOC_Polarity |
@@ -1210,10 +1309,11 @@ static int ni_ai_insn_read(comedi_device *dev,comedi_subdevice *s,comedi_insn *i
        unsigned int mask;
        unsigned signbits;
        unsigned short d;
+       unsigned long dl;
 
        ni_load_channelgain_list(dev,1,&insn->chanspec);
 
-       devpriv->stc_writew(dev, 1,ADC_FIFO_Clear);
+       ni_flush_ai_fifo(dev);
 
        mask=(1<<boardtype.adbits)-1;
        signbits=devpriv->ai_offset[0];
@@ -1245,6 +1345,26 @@ static int ni_ai_insn_read(comedi_device *dev,comedi_subdevice *s,comedi_insn *i
                        d += signbits;
                        data[ n ] = d;
                }
+       }else if(boardtype.reg_type == ni_reg_6143){
+               for(n = 0; n < insn->n; n++){
+                       devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register);
+
+                       /* The 6143 has 32-bit FIFOs. You need to strobe a bit to move a single 16bit stranded sample into the FIFO */
+                       dl = 0;
+                       for(i = 0; i < NI_TIMEOUT; i++){
+                               if(ni_readl(AIFIFO_Status_6143) & 0x01)
+                               {
+                                       ni_writel(0x01, AIFIFO_Control_6143);   // Get stranded sample into FIFO
+                                       dl = ni_readl(AIFIFO_Data_6143);
+                                       break;
+                               }
+                       }
+                       if(i == NI_TIMEOUT){
+                               rt_printk("ni_mio_common: timeout in 6143 ni_ai_insn_read\n");
+                               return -ETIME;
+                       }
+                       data[n] = (((dl >> 16) & 0xFFFF) + signbits) & 0xFFFF;
+               }
        }else{
                for(n=0;n<insn->n;n++){
                        devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register);
@@ -1401,7 +1521,7 @@ static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan,
                ni_m_series_load_channelgain_list(dev, n_chan, list);
                return;
        }
-       if(n_chan == 1 && boardtype.reg_type != ni_reg_611x){
+       if(n_chan == 1 && (boardtype.reg_type != ni_reg_611x) && (boardtype.reg_type != ni_reg_6143)){
                if(devpriv->changain_state && devpriv->changain_spec==list[0]){
                        // ready to go.
                        return;
@@ -1414,9 +1534,27 @@ static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan,
 
        devpriv->stc_writew(dev, 1,Configuration_Memory_Clear);
 
+       // Set up Calibration mode if required
+       if(boardtype.reg_type == ni_reg_6143){
+               if((list[0] & CR_ALT_SOURCE) && !devpriv->ai_calib_source_enabled){
+                       // Strobe Relay enable bit
+                       ni_writew(devpriv->ai_calib_source | Calibration_Channel_6143_RelayOn, Calibration_Channel_6143);
+                       ni_writew(devpriv->ai_calib_source, Calibration_Channel_6143);
+                       devpriv->ai_calib_source_enabled = 1;
+                       msleep_interruptible(100);      // Allow relays to change
+               }
+               else if(!(list[0] & CR_ALT_SOURCE) && devpriv->ai_calib_source_enabled){
+                       // Strobe Relay disable bit
+                       ni_writew(devpriv->ai_calib_source | Calibration_Channel_6143_RelayOff, Calibration_Channel_6143);
+                       ni_writew(devpriv->ai_calib_source, Calibration_Channel_6143);
+                       devpriv->ai_calib_source_enabled = 0;
+                       msleep_interruptible(100);      // Allow relays to change
+               }
+       }
+
        offset=1<<(boardtype.adbits-1);
        for(i=0;i<n_chan;i++){
-               if(list[i]&CR_ALT_SOURCE){
+               if((boardtype.reg_type != ni_reg_6143) && (list[i] & CR_ALT_SOURCE)){
                        chan=devpriv->ai_calib_source;
                }else{
                        chan=CR_CHAN(list[i]);
@@ -1441,6 +1579,8 @@ static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan,
                {
                        if(boardtype.reg_type == ni_reg_611x)
                                aref = AREF_DIFF;
+                       else if(boardtype.reg_type == ni_reg_6143)
+                               aref = AREF_OTHER;
                        switch( aref )
                        {
                                case AREF_DIFF:
@@ -1460,15 +1600,17 @@ static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan,
 
                ni_writew(hi,Configuration_Memory_High);
 
-               lo = range;
-               if(i == n_chan - 1) lo |= AI_LAST_CHANNEL;
-               if( dither ) lo |= AI_DITHER;
+               if(boardtype.reg_type != ni_reg_6143){
+                       lo = range;
+                       if(i == n_chan - 1) lo |= AI_LAST_CHANNEL;
+                       if( dither ) lo |= AI_DITHER;
 
-               ni_writew(lo,Configuration_Memory_Low);
+                       ni_writew(lo,Configuration_Memory_Low);
+               }
        }
 
        /* prime the channel/gain list */
-       if(boardtype.reg_type != ni_reg_611x){
+       if((boardtype.reg_type != ni_reg_611x) && (boardtype.reg_type != ni_reg_6143)){
                ni_prime_channelgain_list(dev);
        }
 }
@@ -1553,7 +1695,7 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
                /* external trigger */
                unsigned int tmp = CR_CHAN(cmd->start_arg);
 
-               if(tmp > 9) tmp = 9;
+               if(tmp > 16) tmp = 16;
                tmp |= (cmd->start_arg & (CR_INVERT | CR_EDGE));
                if(cmd->start_arg != tmp){
                        cmd->start_arg = tmp;
@@ -1579,7 +1721,7 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
                /* external trigger */
                unsigned int tmp = CR_CHAN(cmd->scan_begin_arg);
 
-               if(tmp>9)tmp=9;
+               if(tmp>16)tmp=16;
                tmp |= (cmd->scan_begin_arg & (CR_INVERT | CR_EDGE));
                if(cmd->scan_begin_arg!=tmp){
                        cmd->scan_begin_arg = tmp;
@@ -1611,7 +1753,7 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
                /* external trigger */
                unsigned int tmp = CR_CHAN(cmd->convert_arg);
 
-               if(tmp>9)tmp=9;
+               if(tmp>16)tmp=16;
                tmp |= (cmd->convert_arg&(CR_ALT_FILTER|CR_INVERT));
                if(cmd->convert_arg!=tmp){
                        cmd->convert_arg = tmp;
@@ -1692,7 +1834,7 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s)
                comedi_error(dev, "cannot run command without an irq");
                return -EIO;
        }
-       devpriv->stc_writew(dev, 1,ADC_FIFO_Clear);
+       ni_flush_ai_fifo(dev);
 
        ni_load_channelgain_list(dev,cmd->chanlist_len,cmd->chanlist);
 
@@ -1732,7 +1874,7 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s)
        mode2 &= ~AI_SC_Reload_Mode;
        devpriv->stc_writew(dev, mode2, AI_Mode_2_Register);
 
-       if(cmd->chanlist_len == 1 || boardtype.reg_type == ni_reg_611x){
+       if(cmd->chanlist_len == 1 || (boardtype.reg_type == ni_reg_611x) || (boardtype.reg_type == ni_reg_6143)){
                start_stop_select |= AI_STOP_Polarity;
                start_stop_select |= AI_STOP_Select( 31 ); // logic low
                start_stop_select |= AI_STOP_Sync;
@@ -1989,6 +2131,18 @@ static int ni_ai_insn_config(comedi_device *dev,comedi_subdevice *s,
                                return -EINVAL;
                        }
                        devpriv->ai_calib_source = data[1];
+               } else if(boardtype.reg_type == ni_reg_6143)
+               {
+                       unsigned int calib_source;
+
+                       calib_source = data[1] & 0xf;
+       
+       
+                       if(calib_source > 0xF)
+                               return -EINVAL;
+                       
+                       devpriv->ai_calib_source = calib_source;
+                       ni_writew(calib_source, Calibration_Channel_6143);
                }else
                {
                        unsigned int calib_source;
@@ -2875,7 +3029,7 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
                return -EINVAL;
        }
        
-       if(alloc_subdevices(dev, 10) < 0)
+       if(alloc_subdevices(dev, 11) < 0)
                return -ENOMEM;
 
        /* analog input subdevice */
@@ -2903,7 +3057,7 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
        }else{
                s->type=COMEDI_SUBD_UNUSED;
        }
-
+               
        /* analog output subdevice */
 
        s=dev->subdevices+1;
@@ -2986,6 +3140,13 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
                s->n_chan = 1;
                s->maxdata = 0;
                ni_writel(0x0, M_Offset_Cal_PWM);
+       } else if(boardtype.reg_type == ni_reg_6143)
+       {
+               // internal PWM analog output used for AI nonlinearity calibration
+               s->subdev_flags = SDF_INTERNAL;
+               s->insn_config = &ni_6143_pwm_config;
+               s->n_chan = 1;
+               s->maxdata = 0;
        }else
        {
                s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
@@ -3046,9 +3207,20 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
        devpriv->serial_interval_ns = 0;
        devpriv->serial_hw_mode = 0;
 
+       /* RTSI */
+       s=dev->subdevices+10;
+       s->type=COMEDI_SUBD_DIO;
+       s->subdev_flags=SDF_READABLE|SDF_WRITABLE|SDF_INTERNAL;
+       s->n_chan=8;
+       s->maxdata=1;
+       s->insn_bits = ni_rtsi_insn_bits;
+       s->insn_config = ni_rtsi_insn_config;
+       ni_rtsi_init(dev);
+
        /* ai configuration */
        ni_ai_reset(dev,dev->subdevices+0);
        if((boardtype.reg_type & ni_reg_6xxx_mask) == 0){
+               // BEAM is this needed for PCI-6143 ??
                devpriv->clock_and_fout =
                        Slow_Internal_Time_Divide_By_2 |
                        Slow_Internal_Timebase |
@@ -3211,6 +3383,49 @@ static int ni_m_series_pwm_config(comedi_device *dev, comedi_subdevice *s,
        return 0;
 }
 
+static int ni_6143_pwm_config(comedi_device *dev, comedi_subdevice *s,
+       comedi_insn *insn, lsampl_t *data)
+{
+       unsigned up_count, down_count;
+       switch(data[0])
+       {
+       case INSN_CONFIG_PWM_OUTPUT:
+               switch(data[1])
+               {
+               case TRIG_ROUND_NEAREST:
+                       up_count = (data[2] + TIMER_BASE / 2) / TIMER_BASE; 
+                       down_count = (data[3] + TIMER_BASE / 2) / TIMER_BASE;
+                       break;
+               case TRIG_ROUND_DOWN:
+                       up_count = data[2] / TIMER_BASE;
+                       down_count = data[3] / TIMER_BASE;
+                       break;
+               case TRIG_ROUND_UP:
+                       up_count = (data[2] + TIMER_BASE - 1) / TIMER_BASE;
+                       down_count = (data[3] + TIMER_BASE - 1) / TIMER_BASE;
+                       break;
+               default:
+                       return -EINVAL;
+                       break;
+               }
+               if(up_count * TIMER_BASE != data[2] ||
+                       down_count * TIMER_BASE != data[3])
+               {
+                       data[2] = up_count * TIMER_BASE;
+                       data[3] = down_count * TIMER_BASE;
+                       return -EAGAIN;
+               }
+               ni_writel(up_count, Calibration_HighTime_6143);
+               ni_writel(down_count, Calibration_LowTime_6143);
+               return 4;
+               break;
+       default:
+               return -EINVAL;
+               break;
+       }
+       return 0;
+}
+
 static void ni_write_caldac(comedi_device *dev,int addr,int val);
 /*
        calibration subdevice
@@ -3968,7 +4183,7 @@ static int ni_pfi_insn_config(comedi_device *dev,comedi_subdevice *s,
 {
        unsigned int chan;
 
-       if(insn->n!=1)return -EINVAL;
+       if(insn->n < 1)return -EINVAL;
 
        chan = CR_CHAN(insn->chanspec);
        if(chan>10)return -EINVAL;
@@ -3991,6 +4206,79 @@ static int ni_pfi_insn_config(comedi_device *dev,comedi_subdevice *s,
        return 1;
 }
 
+/*
+ *
+ *  NI RTSI Bus Functions
+ *
+ */
+static void ni_rtsi_init(comedi_device *dev)
+{
+       // Initialises the RTSI bus signal switch to a default state
+       
+       // Set clock mode to internal
+       devpriv->stc_writew(dev, COMEDI_RTSI_CLOCK_MODE_INTERNAL, RTSI_Trig_Direction_Register);
+
+       // Standard internal lines are routed to standard RTSI bus lines
+       devpriv->stc_writew(dev, 0x3210, RTSI_Trig_A_Output_Register);
+       devpriv->stc_writew(dev, 0x0654, RTSI_Trig_B_Output_Register);
+       
+       // Sets the source and direction of the 4 on board lines
+//     devpriv->stc_writew(dev, 0x0000, RTSI_Board_Register);
+}
+
+static int ni_rtsi_insn_bits(comedi_device *dev,comedi_subdevice *s,
+       comedi_insn *insn,lsampl_t *data)
+{
+       if(insn->n != 2) return -EINVAL;
+
+       data[1] = 0;
+
+       return 2;
+}
+
+static int ni_rtsi_insn_config(comedi_device *dev,comedi_subdevice *s,
+       comedi_insn *insn,lsampl_t *data)
+{
+       unsigned int chan;
+       unsigned int bit;
+
+       if(insn->n < 1) return -EINVAL;
+
+       if(data[0] == INSN_CONFIG_SET_RTSI_CLOCK_MODE){
+               if(data[1] > 3)
+                       return -EINVAL;
+
+               devpriv->rtsi_trig_direction_reg &= ~0x03;
+               devpriv->rtsi_trig_direction_reg |= data[1];
+               devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
+       }
+       else {
+               chan = CR_CHAN(insn->chanspec);
+               if(chan > 6) return -EINVAL;
+               
+               bit = 9 + chan;
+
+               switch(data[0]){
+               case INSN_CONFIG_DIO_OUTPUT:
+                       devpriv->rtsi_trig_direction_reg |= (1 << bit);
+                       devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
+                       break;
+               case INSN_CONFIG_DIO_INPUT:
+                       devpriv->rtsi_trig_direction_reg &= ~(1 << bit);
+                       devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
+                       break;
+               case INSN_CONFIG_DIO_QUERY:
+                       data[1] = (devpriv->rtsi_trig_direction_reg & (1<<bit)) ? INSN_CONFIG_DIO_OUTPUT : INSN_CONFIG_DIO_INPUT;
+                       return 2;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       return 1;
+}
+
 static int cs5529_wait_for_idle(comedi_device *dev)
 {
        unsigned short status;
index 0e302584fca2ca82e9b659769e48464cab7a36c7..1aeed1158553634805fe9710e7d6a1e767c3833a 100644 (file)
@@ -35,6 +35,7 @@ Devices: [National Instruments] PCI-MIO-16XE-50 (ni_pcimio),
   PCI-6711, PXI-6711, PCI-6713, PXI-6713,
   PXI-6071E, PXI-6070E,
   PXI-6052E, PCI-6036E, PCI-6731, PCI-6733, PXI-6733
+  PCI-6143
 Updated: Mon Jan 19 11:00:27 EST 2004
 
 These boards are almost identical to the AT-MIO E series, except that
@@ -54,6 +55,9 @@ Information (number of channels, bits, etc.) for some devices may be
 incorrect.  Please check this and submit a bug if there are problems
 for your device.
 
+2006-02-07: S-Series PCI-6143: Support has been added but is not
+       fully tested as yet. Terry Barnaby, BEAM Ltd.
+
 Bugs:
  - When DMA is enabled, COMEDI_EV_SCAN_END and COMEDI_EV_CONVERT do
    not work correctly.
@@ -158,6 +162,7 @@ static struct pci_device_id ni_pci_table[] __devinitdata = {
        { PCI_VENDOR_ID_NATINST, 0x70f2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { PCI_VENDOR_ID_NATINST, 0x716c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { PCI_VENDOR_ID_NATINST, 0x71bc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VENDOR_ID_NATINST, 0x70C0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { 0 }
 };
 MODULE_DEVICE_TABLE(pci, ni_pci_table);
@@ -958,6 +963,21 @@ static ni_board ni_boards[]={
                .caldac = {caldac_none},
                has_8255:       0,
        },
+       {       device_id:      0x70C0,
+               name:           "pci-6143",
+               n_adchan:       8,
+               adbits:         16,
+               ai_fifo_depth:  1024,
+               alwaysdither:   0,
+               gainlkup:       ai_gain_6143,
+               ai_speed:       4000,
+               n_aochan:       0,
+               aobits:         0,
+               reg_type:       ni_reg_6143,
+               ao_unipolar:    0,
+               ao_fifo_depth:  0,
+               caldac:         {ad8804,ad8804},
+       },
 };
 #define n_pcimio_boards ((sizeof(ni_boards)/sizeof(ni_boards[0])))
 
@@ -1261,6 +1281,24 @@ static void m_series_init_eeprom_buffer(comedi_device *dev)
        writel(0x0, devpriv->mite->mite_io_addr + 0x30);
 }
 
+static void init_6143(comedi_device *dev)
+{
+       // Disable interrupts
+       devpriv->stc_writew(dev, 0, Interrupt_Control_Register);
+
+       // Initialise 6143 AI specific bits
+       ni_writeb(0x00, Magic_6143);            // Set G0,G1 DMA mode to E series version
+       ni_writeb(0x80, PipelineDelay_6143);    // Set EOCMode, ADCMode and pipelinedelay
+       ni_writeb(0x00, EOC_Set_6143);          // Set EOC Delay
+       
+       ni_writel(boardtype.ai_fifo_depth / 2, AIFIFO_Flag_6143);       // Set the FIFO half full level
+
+       // Strobe Relay disable bit
+       devpriv->ai_calib_source_enabled = 0;
+       ni_writew(devpriv->ai_calib_source | Calibration_Channel_6143_RelayOff, Calibration_Channel_6143);
+       ni_writew(devpriv->ai_calib_source, Calibration_Channel_6143);
+}
+
 /* cleans up allocated resources */
 static int pcimio_detach(comedi_device *dev)
 {
@@ -1309,8 +1347,11 @@ static int pcimio_attach(comedi_device *dev,comedi_devconfig *it)
                printk(" error setting up mite\n");
                return ret;
        }
+
        if(boardtype.reg_type == ni_reg_m_series)
                m_series_init_eeprom_buffer(dev);
+       if(boardtype.reg_type == ni_reg_6143)
+               init_6143(dev);
 
        dev->irq=mite_irq(devpriv->mite);
 
index b63b229ba686825e769498a5feeebf1ffa1fe4c6..0d98b8d702d27232540dd28dde45b2c749f613e7 100644 (file)
@@ -304,6 +304,7 @@ enum AO_FIFO_Mode_Bits
 #define FOUT_Divider(x)                                (((x) & 0xf) << 0)
 
 #define IO_Bidirection_Pin_Register    57
+#define        RTSI_Trig_Direction_Register    58
 
 #define Interrupt_Control_Register     59
 #define Interrupt_B_Enable                     _bit15
@@ -440,6 +441,9 @@ enum AO_Personal_Bits
        AO_TMRDACWR_Pulse_Width = 1 << 12,
        AO_Number_Of_DAC_Packages = 1 << 14,    // 1 for "single" mode, 0 for "dual"
 };
+#define        RTSI_Trig_A_Output_Register     79
+#define        RTSI_Trig_B_Output_Register     80
+#define        RTSI_Board_Register             81
 #define Write_Strobe_0_Register                82
 #define Write_Strobe_1_Register                83
 #define Write_Strobe_2_Register                84
@@ -664,6 +668,36 @@ static inline unsigned int AI_CONFIG_CHANNEL( unsigned int channel )
 #define AO_Window_Address_611x         0x18
 #define AO_Window_Data_611x            0x1e
 
+/* 6143 registers */
+#define Magic_6143                     0x19 /* w8 */
+#define G0G1_DMA_Select_6143           0x0B /* w8 */
+#define PipelineDelay_6143             0x1f /* w8 */
+#define EOC_Set_6143                   0x1D /* w8 */
+#define AIDMA_Select_6143              0x09 /* w8 */
+#define AIFIFO_Data_6143               0x8C /* w32 */
+#define AIFIFO_Flag_6143               0x84 /* w32 */
+#define AIFIFO_Control_6143            0x88 /* w32 */
+#define AIFIFO_Status_6143             0x88 /* w32 */
+#define AIFIFO_DMAThreshold_6143       0x90 /* w32 */
+#define AIFIFO_Words_Available_6143    0x94 /* w32 */
+
+#define Calibration_Channel_6143       0x42 /* w16 */
+#define Calibration_LowTime_6143       0x20 /* w16 */
+#define Calibration_HighTime_6143      0x22 /* w16 */
+#define Relay_Counter_Load_Val__6143   0x4C /* w32 */
+#define Signature_6143                 0x50 /* w32 */
+#define Release_Date_6143              0x54 /* w32 */
+#define Release_Oldest_Date_6143       0x58 /* w32 */
+
+#define Calibration_Channel_6143_RelayOn       0x8000  /* Calibration relay switch On */
+#define Calibration_Channel_6143_RelayOff      0x4000  /* Calibration relay switch Off */
+#define Calibration_Channel_Gnd_Gnd    0x00    /* Offset Calibration */
+#define Calibration_Channel_2v5_Gnd    0x02    /* 2.5V Reference */
+#define Calibration_Channel_Pwm_Gnd    0x05    /* +/- 5V Self Cal */
+#define Calibration_Channel_2v5_Pwm    0x0a    /* PWM Calibration */
+#define Calibration_Channel_Pwm_Pwm    0x0d    /* CMRR */
+#define Calibration_Channel_Gnd_Pwm    0x0e    /* PWM Calibration */
+
 /* 671x, 611x registers */
 
 /* 671xi, 611x windowed ao registers */
@@ -757,7 +791,7 @@ enum mite_dma_channel{
        GPC1_DMA_CHAN = 3,
 };
 
-enum{ ai_gain_16=0, ai_gain_8, ai_gain_14, ai_gain_4, ai_gain_611x, ai_gain_622x, ai_gain_628x };
+enum{ ai_gain_16=0, ai_gain_8, ai_gain_14, ai_gain_4, ai_gain_611x, ai_gain_622x, ai_gain_628x,  ai_gain_6143};
 enum caldac_enum { caldac_none=0, mb88341, dac8800, dac8043, ad8522,
        ad8804, ad8842, ad8804_debug };
 enum ni_reg_type {
@@ -767,7 +801,8 @@ enum ni_reg_type {
        ni_reg_6713 = 0x4,
        ni_reg_67xx_mask = 0x6,
        ni_reg_6xxx_mask = 0x7,
-       ni_reg_m_series = 0x8
+       ni_reg_m_series = 0x8,
+       ni_reg_6143 = 0x10
 };
 
 static comedi_lrange range_ni_E_ao_ext;
@@ -1069,6 +1104,7 @@ static ni_board ni_boards[];
        int blocksize;                                          \
        int n_left;                                             \
        unsigned int ai_calib_source;                           \
+       unsigned int ai_calib_source_enabled;                   \
        spinlock_t window_lock; \
                                                                \
        int changain_state;                                     \
@@ -1104,6 +1140,7 @@ static ni_board ni_boards[];
        volatile unsigned short int_a_enable_reg;                       \
        volatile unsigned short int_b_enable_reg;                       \
        unsigned short io_bidirection_pin_reg;                  \
+       unsigned short rtsi_trig_direction_reg;                 \
                                                                \
        unsigned short atrig_mode;                              \
        unsigned short atrig_high;                              \
index 3a69261f34e556b5f3a83d82c8462e7297c7d249..698ad1e006122096f653f6c71d7000ec9c865c6e 100644 (file)
@@ -246,9 +246,11 @@ enum configuration_ids
        INSN_CONFIG_SET_CLOCK_SRC = 2003,       // Set CTR clock source
        INSN_CONFIG_GET_CLOCK_SRC = 2004,       // Get CTR clock source
        INSN_CONFIG_8254_SET_MODE = 4097,
-       INSN_CONFIG_8254_READ_STATUS = 4098
+       INSN_CONFIG_8254_READ_STATUS = 4098,
+       INSN_CONFIG_SET_RTSI_CLOCK_MODE = 5000  // Set RTSI bus clock mode
 };
 
+
 /* ioctls */
 
 #define CIO 'd'
@@ -516,6 +518,54 @@ enum i8254_mode
        I8254_BCD = 1, /* use binary-coded decimal instead of binary (pretty useless) */
        I8254_BINARY = 0
 };
+
+/* RTSI Clock mode */
+#define COMEDI_RTSI_CLOCK_MODE_INTERNAL        0x00    // Internal clock mode
+#define COMEDI_RTSI_CLOCK_MODE_OUTPUT  0x01    // Outputs clock to RTSI
+#define COMEDI_RTSI_CLOCK_MODE_SLAVE   0x02    // Runs from RTSI clock
+#define COMEDI_RTSI_CLOCK_MODE_MASTER  0x03    // Outputs clock to RTSI and runs from this external clock
+
+/* RTSI BUS pins */
+#define NI_RTSI_0              0
+#define NI_RTSI_1              1
+#define NI_RTSI_2              2
+#define NI_RTSI_3              3
+#define NI_RTSI_4              4
+#define NI_RTSI_5              5
+#define NI_RTSI_6              6
+#define NI_RTSI_7              7
+
+/* RTSI BUS pin usage in standard configuration */
+#define NI_RTSI_STD_AI_START1          0
+#define NI_RTSI_STD_AI_START2          1
+#define NI_RTSI_STD_AI_CONV            2
+#define NI_RTSI_STD_CT1_SRC            3
+#define NI_RTSI_STD_CT1_GATE           4
+#define NI_RTSI_STD_AO_SAMP_CLOCK      5
+#define NI_RTSI_STD_AO_START_TRIG      6
+#define NI_RTSI_STD_AI_SAMP_CLOCK      7
+#define NI_RTSI_STD_CTR0_SRC           8
+#define NI_RTSI_STD_CTR0_GATE          9
+
+/* NI External Trigger lines */
+#define NI_EXT_PFI_0                   0
+#define NI_EXT_PFI_1                   1
+#define NI_EXT_PFI_2                   2
+#define NI_EXT_PFI_3                   3
+#define NI_EXT_PFI_4                   4
+#define NI_EXT_PFI_5                   5
+#define NI_EXT_PFI_6                   6
+#define NI_EXT_PFI_7                   7
+#define NI_EXT_PFI_8                   8
+#define NI_EXT_PFI_9                   9
+#define NI_EXT_RTSI_0                  10
+#define NI_EXT_RTSI_1                  11
+#define NI_EXT_RTSI_2                  12
+#define NI_EXT_RTSI_3                  13
+#define NI_EXT_RTSI_4                  14
+#define NI_EXT_RTSI_5                  15
+#define NI_EXT_RTSI_6                  16
+
 #ifdef __cplusplus
 }
 #endif