![]() |
RTXI 1.3
|
00001 /* 00002 comedi/drivers/s626.c 00003 Sensoray s626 Comedi driver 00004 00005 COMEDI - Linux Control and Measurement Device Interface 00006 Copyright (C) 2000 David A. Schleef <ds@schleef.org> 00007 00008 Based on Sensoray Model 626 Linux driver Version 0.2 00009 Copyright (C) 2002-2004 Sensoray Co., Inc. 00010 00011 This program is free software; you can redistribute it and/or modify 00012 it under the terms of the GNU General Public License as published by 00013 the Free Software Foundation; either version 2 of the License, or 00014 (at your option) any later version. 00015 00016 This program is distributed in the hope that it will be useful, 00017 but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 GNU General Public License for more details. 00020 00021 You should have received a copy of the GNU General Public License 00022 along with this program; if not, write to the Free Software 00023 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00024 00025 */ 00026 00027 /* 00028 Driver: s626 00029 Description: Sensoray 626 driver 00030 Devices: [Sensoray] 626 (s626) 00031 Authors: Gianluca Palli <gpalli@deis.unibo.it>, 00032 Updated: Fri, 15 Feb 2008 10:28:42 +0000 00033 Status: experimental 00034 00035 Configuration options: 00036 [0] - PCI bus of device (optional) 00037 [1] - PCI slot of device (optional) 00038 If bus/slot is not specified, the first supported 00039 PCI device found will be used. 00040 00041 INSN_CONFIG instructions: 00042 analog input: 00043 none 00044 00045 analog output: 00046 none 00047 00048 digital channel: 00049 s626 has 3 dio subdevices (2,3 and 4) each with 16 i/o channels 00050 supported configuration options: 00051 INSN_CONFIG_DIO_QUERY 00052 COMEDI_INPUT 00053 COMEDI_OUTPUT 00054 00055 encoder: 00056 Every channel must be configured before reading. 00057 00058 Example code 00059 00060 insn.insn=INSN_CONFIG; //configuration instruction 00061 insn.n=1; //number of operation (must be 1) 00062 insn.data=&initialvalue; //initial value loaded into encoder 00063 //during configuration 00064 insn.subdev=5; //encoder subdevice 00065 insn.chanspec=CR_PACK(encoder_channel,0,AREF_OTHER); //encoder_channel 00066 //to configure 00067 00068 comedi_do_insn(cf,&insn); //executing configuration 00069 */ 00070 00071 #include <linux/kernel.h> 00072 #include <linux/types.h> 00073 00074 #include <linux/comedidev.h> 00075 00076 #include "comedi_pci.h" 00077 00078 #include "comedi_fc.h" 00079 #include "s626.h" 00080 00081 MODULE_AUTHOR("Gianluca Palli <gpalli@deis.unibo.it>"); 00082 MODULE_DESCRIPTION("Sensoray 626 Comedi driver module"); 00083 MODULE_LICENSE("GPL"); 00084 00085 typedef struct s626_board_struct { 00086 const char *name; 00087 int ai_chans; 00088 int ai_bits; 00089 int ao_chans; 00090 int ao_bits; 00091 int dio_chans; 00092 int dio_banks; 00093 int enc_chans; 00094 } s626_board; 00095 00096 static const s626_board s626_boards[] = { 00097 { 00098 name: "s626", 00099 ai_chans:S626_ADC_CHANNELS, 00100 ai_bits: 14, 00101 ao_chans:S626_DAC_CHANNELS, 00102 ao_bits: 13, 00103 dio_chans:S626_DIO_CHANNELS, 00104 dio_banks:S626_DIO_BANKS, 00105 enc_chans:S626_ENCODER_CHANNELS, 00106 } 00107 }; 00108 00109 #define thisboard ((const s626_board *)dev->board_ptr) 00110 #define PCI_VENDOR_ID_S626 0x1131 00111 #define PCI_DEVICE_ID_S626 0x7146 00112 #define PCI_SUBVENDOR_ID_S626 0x6000 00113 #define PCI_SUBDEVICE_ID_S626 0x0272 00114 00115 static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = { 00116 {PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, 00117 PCI_SUBVENDOR_ID_S626, PCI_SUBDEVICE_ID_S626, 0, 0, 0}, 00118 {0} 00119 }; 00120 00121 MODULE_DEVICE_TABLE(pci, s626_pci_table); 00122 00123 static int s626_attach(comedi_device * dev, comedi_devconfig * it); 00124 static int s626_detach(comedi_device * dev); 00125 00126 static comedi_driver driver_s626 = { 00127 driver_name:"s626", 00128 module:THIS_MODULE, 00129 attach:s626_attach, 00130 detach:s626_detach, 00131 }; 00132 00133 typedef struct { 00134 struct pci_dev *pdev; 00135 void *base_addr; 00136 int got_regions; 00137 short allocatedBuf; 00138 uint8_t ai_cmd_running; // ai_cmd is running 00139 uint8_t ai_continous; // continous aquisition 00140 int ai_sample_count; // number of samples to aquire 00141 unsigned int ai_sample_timer; // time between samples in 00142 // units of the timer 00143 int ai_convert_count; // conversion counter 00144 unsigned int ai_convert_timer; // time between conversion in 00145 // units of the timer 00146 uint16_t CounterIntEnabs; //Counter interrupt enable 00147 //mask for MISC2 register. 00148 uint8_t AdcItems; //Number of items in ADC poll 00149 //list. 00150 DMABUF RPSBuf; //DMA buffer used to hold ADC 00151 //(RPS1) program. 00152 DMABUF ANABuf; //DMA buffer used to receive 00153 //ADC data and hold DAC data. 00154 uint32_t *pDacWBuf; //Pointer to logical adrs of 00155 //DMA buffer used to hold DAC 00156 //data. 00157 uint16_t Dacpol; //Image of DAC polarity 00158 //register. 00159 uint8_t TrimSetpoint[12]; //Images of TrimDAC setpoints. 00160 //registers. 00161 uint16_t ChargeEnabled; //Image of MISC2 Battery 00162 //Charge Enabled (0 or 00163 //WRMISC2_CHARGE_ENABLE). 00164 uint16_t WDInterval; //Image of MISC2 watchdog 00165 //interval control bits. 00166 uint32_t I2CAdrs; //I2C device address for 00167 //onboard EEPROM (board rev 00168 //dependent). 00169 // short I2Cards; 00170 lsampl_t ao_readback[S626_DAC_CHANNELS]; 00171 } s626_private; 00172 00173 typedef struct { 00174 uint16_t RDDIn; 00175 uint16_t WRDOut; 00176 uint16_t RDEdgSel; 00177 uint16_t WREdgSel; 00178 uint16_t RDCapSel; 00179 uint16_t WRCapSel; 00180 uint16_t RDCapFlg; 00181 uint16_t RDIntSel; 00182 uint16_t WRIntSel; 00183 } dio_private; 00184 00185 static dio_private dio_private_A = { 00186 RDDIn:LP_RDDINA, 00187 WRDOut:LP_WRDOUTA, 00188 RDEdgSel:LP_RDEDGSELA, 00189 WREdgSel:LP_WREDGSELA, 00190 RDCapSel:LP_RDCAPSELA, 00191 WRCapSel:LP_WRCAPSELA, 00192 RDCapFlg:LP_RDCAPFLGA, 00193 RDIntSel:LP_RDINTSELA, 00194 WRIntSel:LP_WRINTSELA, 00195 }; 00196 00197 static dio_private dio_private_B = { 00198 RDDIn:LP_RDDINB, 00199 WRDOut:LP_WRDOUTB, 00200 RDEdgSel:LP_RDEDGSELB, 00201 WREdgSel:LP_WREDGSELB, 00202 RDCapSel:LP_RDCAPSELB, 00203 WRCapSel:LP_WRCAPSELB, 00204 RDCapFlg:LP_RDCAPFLGB, 00205 RDIntSel:LP_RDINTSELB, 00206 WRIntSel:LP_WRINTSELB, 00207 }; 00208 00209 static dio_private dio_private_C = { 00210 RDDIn:LP_RDDINC, 00211 WRDOut:LP_WRDOUTC, 00212 RDEdgSel:LP_RDEDGSELC, 00213 WREdgSel:LP_WREDGSELC, 00214 RDCapSel:LP_RDCAPSELC, 00215 WRCapSel:LP_WRCAPSELC, 00216 RDCapFlg:LP_RDCAPFLGC, 00217 RDIntSel:LP_RDINTSELC, 00218 WRIntSel:LP_WRINTSELC, 00219 }; 00220 00221 /* to group dio devices (48 bits mask and data are not allowed ???) 00222 static dio_private *dio_private_word[]={ 00223 &dio_private_A, 00224 &dio_private_B, 00225 &dio_private_C, 00226 }; 00227 */ 00228 00229 #define devpriv ((s626_private *)dev->private) 00230 #define diopriv ((dio_private *)s->private) 00231 00232 COMEDI_PCI_INITCLEANUP_NOMODULE(driver_s626, s626_pci_table); 00233 00234 //ioctl routines 00235 static int s626_ai_insn_config(comedi_device * dev, comedi_subdevice * s, 00236 comedi_insn * insn, lsampl_t * data); 00237 /* static int s626_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data); */ 00238 static int s626_ai_insn_read(comedi_device * dev, comedi_subdevice * s, 00239 comedi_insn * insn, lsampl_t * data); 00240 static int s626_ai_cmd(comedi_device * dev, comedi_subdevice * s); 00241 static int s626_ai_cmdtest(comedi_device * dev, comedi_subdevice * s, 00242 comedi_cmd * cmd); 00243 static int s626_ai_cancel(comedi_device * dev, comedi_subdevice * s); 00244 static int s626_ao_winsn(comedi_device * dev, comedi_subdevice * s, 00245 comedi_insn * insn, lsampl_t * data); 00246 static int s626_ao_rinsn(comedi_device * dev, comedi_subdevice * s, 00247 comedi_insn * insn, lsampl_t * data); 00248 static int s626_dio_insn_bits(comedi_device * dev, comedi_subdevice * s, 00249 comedi_insn * insn, lsampl_t * data); 00250 static int s626_dio_insn_config(comedi_device * dev, comedi_subdevice * s, 00251 comedi_insn * insn, lsampl_t * data); 00252 static int s626_dio_set_irq(comedi_device * dev, unsigned int chan); 00253 static int s626_dio_reset_irq(comedi_device * dev, unsigned int gruop, 00254 unsigned int mask); 00255 static int s626_dio_clear_irq(comedi_device * dev); 00256 static int s626_enc_insn_config(comedi_device * dev, comedi_subdevice * s, 00257 comedi_insn * insn, lsampl_t * data); 00258 static int s626_enc_insn_read(comedi_device * dev, comedi_subdevice * s, 00259 comedi_insn * insn, lsampl_t * data); 00260 static int s626_enc_insn_write(comedi_device * dev, comedi_subdevice * s, 00261 comedi_insn * insn, lsampl_t * data); 00262 static int s626_ns_to_timer(int *nanosec, int round_mode); 00263 static int s626_ai_load_polllist(uint8_t * ppl, comedi_cmd * cmd); 00264 static int s626_ai_inttrig(comedi_device * dev, comedi_subdevice * s, 00265 unsigned int trignum); 00266 static irqreturn_t s626_irq_handler(int irq, void *d PT_REGS_ARG); 00267 static lsampl_t s626_ai_reg_to_uint(int data); 00268 /* static lsampl_t s626_uint_to_reg(comedi_subdevice *s, int data); */ 00269 00270 //end ioctl routines 00271 00272 //internal routines 00273 static void s626_dio_init(comedi_device * dev); 00274 static void ResetADC(comedi_device * dev, uint8_t * ppl); 00275 static void LoadTrimDACs(comedi_device * dev); 00276 static void WriteTrimDAC(comedi_device * dev, uint8_t LogicalChan, 00277 uint8_t DacData); 00278 static uint8_t I2Cread(comedi_device * dev, uint8_t addr); 00279 static uint32_t I2Chandshake(comedi_device * dev, uint32_t val); 00280 static void SetDAC(comedi_device * dev, uint16_t chan, short dacdata); 00281 static void SendDAC(comedi_device * dev, uint32_t val); 00282 static void WriteMISC2(comedi_device * dev, uint16_t NewImage); 00283 static void DEBItransfer(comedi_device * dev); 00284 static uint16_t DEBIread(comedi_device * dev, uint16_t addr); 00285 static void DEBIwrite(comedi_device * dev, uint16_t addr, uint16_t wdata); 00286 static void DEBIreplace(comedi_device * dev, uint16_t addr, uint16_t mask, 00287 uint16_t wdata); 00288 static void CloseDMAB(comedi_device * dev, DMABUF * pdma, size_t bsize); 00289 00290 // COUNTER OBJECT ------------------------------------------------ 00291 typedef struct enc_private_struct { 00292 // Pointers to functions that differ for A and B counters: 00293 uint16_t(*GetEnable) (comedi_device * dev, struct enc_private_struct *); //Return clock enable. 00294 uint16_t(*GetIntSrc) (comedi_device * dev, struct enc_private_struct *); //Return interrupt source. 00295 uint16_t(*GetLoadTrig) (comedi_device * dev, struct enc_private_struct *); //Return preload trigger source. 00296 uint16_t(*GetMode) (comedi_device * dev, struct enc_private_struct *); //Return standardized operating mode. 00297 void (*PulseIndex) (comedi_device * dev, struct enc_private_struct *); //Generate soft index strobe. 00298 void (*SetEnable) (comedi_device * dev, struct enc_private_struct *, uint16_t enab); //Program clock enable. 00299 void (*SetIntSrc) (comedi_device * dev, struct enc_private_struct *, uint16_t IntSource); //Program interrupt source. 00300 void (*SetLoadTrig) (comedi_device * dev, struct enc_private_struct *, uint16_t Trig); //Program preload trigger source. 00301 void (*SetMode) (comedi_device * dev, struct enc_private_struct *, uint16_t Setup, uint16_t DisableIntSrc); //Program standardized operating mode. 00302 void (*ResetCapFlags) (comedi_device * dev, struct enc_private_struct *); //Reset event capture flags. 00303 00304 uint16_t MyCRA; // Address of CRA register. 00305 uint16_t MyCRB; // Address of CRB register. 00306 uint16_t MyLatchLsw; // Address of Latch least-significant-word 00307 // register. 00308 uint16_t MyEventBits[4]; // Bit translations for IntSrc -->RDMISC2. 00309 } enc_private; //counter object 00310 00311 #define encpriv ((enc_private *)(dev->subdevices+5)->private) 00312 00313 //counters routines 00314 static void s626_timer_load(comedi_device * dev, enc_private * k, int tick); 00315 static uint32_t ReadLatch(comedi_device * dev, enc_private * k); 00316 static void ResetCapFlags_A(comedi_device * dev, enc_private * k); 00317 static void ResetCapFlags_B(comedi_device * dev, enc_private * k); 00318 static uint16_t GetMode_A(comedi_device * dev, enc_private * k); 00319 static uint16_t GetMode_B(comedi_device * dev, enc_private * k); 00320 static void SetMode_A(comedi_device * dev, enc_private * k, uint16_t Setup, 00321 uint16_t DisableIntSrc); 00322 static void SetMode_B(comedi_device * dev, enc_private * k, uint16_t Setup, 00323 uint16_t DisableIntSrc); 00324 static void SetEnable_A(comedi_device * dev, enc_private * k, uint16_t enab); 00325 static void SetEnable_B(comedi_device * dev, enc_private * k, uint16_t enab); 00326 static uint16_t GetEnable_A(comedi_device * dev, enc_private * k); 00327 static uint16_t GetEnable_B(comedi_device * dev, enc_private * k); 00328 static void SetLatchSource(comedi_device * dev, enc_private * k, 00329 uint16_t value); 00330 /* static uint16_t GetLatchSource(comedi_device *dev, enc_private *k ); */ 00331 static void SetLoadTrig_A(comedi_device * dev, enc_private * k, uint16_t Trig); 00332 static void SetLoadTrig_B(comedi_device * dev, enc_private * k, uint16_t Trig); 00333 static uint16_t GetLoadTrig_A(comedi_device * dev, enc_private * k); 00334 static uint16_t GetLoadTrig_B(comedi_device * dev, enc_private * k); 00335 static void SetIntSrc_B(comedi_device * dev, enc_private * k, 00336 uint16_t IntSource); 00337 static void SetIntSrc_A(comedi_device * dev, enc_private * k, 00338 uint16_t IntSource); 00339 static uint16_t GetIntSrc_A(comedi_device * dev, enc_private * k); 00340 static uint16_t GetIntSrc_B(comedi_device * dev, enc_private * k); 00341 /* static void SetClkMult(comedi_device *dev, enc_private *k, uint16_t value ) ; */ 00342 /* static uint16_t GetClkMult(comedi_device *dev, enc_private *k ) ; */ 00343 /* static void SetIndexPol(comedi_device *dev, enc_private *k, uint16_t value ); */ 00344 /* static uint16_t GetClkPol(comedi_device *dev, enc_private *k ) ; */ 00345 /* static void SetIndexSrc( comedi_device *dev,enc_private *k, uint16_t value ); */ 00346 /* static uint16_t GetClkSrc( comedi_device *dev,enc_private *k ); */ 00347 /* static void SetIndexSrc( comedi_device *dev,enc_private *k, uint16_t value ); */ 00348 /* static uint16_t GetIndexSrc( comedi_device *dev,enc_private *k ); */ 00349 static void PulseIndex_A(comedi_device * dev, enc_private * k); 00350 static void PulseIndex_B(comedi_device * dev, enc_private * k); 00351 static void Preload(comedi_device * dev, enc_private * k, uint32_t value); 00352 static void CountersInit(comedi_device * dev); 00353 //end internal routines 00354 00356 // Counter objects constructor. 00357 00358 // Counter overflow/index event flag masks for RDMISC2. 00359 #define INDXMASK(C) ( 1 << ( ( (C) > 2 ) ? ( (C) * 2 - 1 ) : ( (C) * 2 + 4 ) ) ) 00360 #define OVERMASK(C) ( 1 << ( ( (C) > 2 ) ? ( (C) * 2 + 5 ) : ( (C) * 2 + 10 ) ) ) 00361 #define EVBITS(C) { 0, OVERMASK(C), INDXMASK(C), OVERMASK(C) | INDXMASK(C) } 00362 00363 // Translation table to map IntSrc into equivalent RDMISC2 event flag 00364 // bits. 00365 //static const uint16_t EventBits[][4] = { EVBITS(0), EVBITS(1), EVBITS(2), EVBITS(3), EVBITS(4), EVBITS(5) }; 00366 00367 /* enc_private; */ 00368 static enc_private enc_private_data[] = { 00369 { 00370 GetEnable:GetEnable_A, 00371 GetIntSrc:GetIntSrc_A, 00372 GetLoadTrig:GetLoadTrig_A, 00373 GetMode: GetMode_A, 00374 PulseIndex:PulseIndex_A, 00375 SetEnable:SetEnable_A, 00376 SetIntSrc:SetIntSrc_A, 00377 SetLoadTrig:SetLoadTrig_A, 00378 SetMode: SetMode_A, 00379 ResetCapFlags:ResetCapFlags_A, 00380 MyCRA: LP_CR0A, 00381 MyCRB: LP_CR0B, 00382 MyLatchLsw:LP_CNTR0ALSW, 00383 MyEventBits:EVBITS(0), 00384 }, 00385 { 00386 GetEnable:GetEnable_A, 00387 GetIntSrc:GetIntSrc_A, 00388 GetLoadTrig:GetLoadTrig_A, 00389 GetMode: GetMode_A, 00390 PulseIndex:PulseIndex_A, 00391 SetEnable:SetEnable_A, 00392 SetIntSrc:SetIntSrc_A, 00393 SetLoadTrig:SetLoadTrig_A, 00394 SetMode: SetMode_A, 00395 ResetCapFlags:ResetCapFlags_A, 00396 MyCRA: LP_CR1A, 00397 MyCRB: LP_CR1B, 00398 MyLatchLsw:LP_CNTR1ALSW, 00399 MyEventBits:EVBITS(1), 00400 }, 00401 { 00402 GetEnable:GetEnable_A, 00403 GetIntSrc:GetIntSrc_A, 00404 GetLoadTrig:GetLoadTrig_A, 00405 GetMode: GetMode_A, 00406 PulseIndex:PulseIndex_A, 00407 SetEnable:SetEnable_A, 00408 SetIntSrc:SetIntSrc_A, 00409 SetLoadTrig:SetLoadTrig_A, 00410 SetMode: SetMode_A, 00411 ResetCapFlags:ResetCapFlags_A, 00412 MyCRA: LP_CR2A, 00413 MyCRB: LP_CR2B, 00414 MyLatchLsw:LP_CNTR2ALSW, 00415 MyEventBits:EVBITS(2), 00416 }, 00417 { 00418 GetEnable:GetEnable_B, 00419 GetIntSrc:GetIntSrc_B, 00420 GetLoadTrig:GetLoadTrig_B, 00421 GetMode: GetMode_B, 00422 PulseIndex:PulseIndex_B, 00423 SetEnable:SetEnable_B, 00424 SetIntSrc:SetIntSrc_B, 00425 SetLoadTrig:SetLoadTrig_B, 00426 SetMode: SetMode_B, 00427 ResetCapFlags:ResetCapFlags_B, 00428 MyCRA: LP_CR0A, 00429 MyCRB: LP_CR0B, 00430 MyLatchLsw:LP_CNTR0BLSW, 00431 MyEventBits:EVBITS(3), 00432 }, 00433 { 00434 GetEnable:GetEnable_B, 00435 GetIntSrc:GetIntSrc_B, 00436 GetLoadTrig:GetLoadTrig_B, 00437 GetMode: GetMode_B, 00438 PulseIndex:PulseIndex_B, 00439 SetEnable:SetEnable_B, 00440 SetIntSrc:SetIntSrc_B, 00441 SetLoadTrig:SetLoadTrig_B, 00442 SetMode: SetMode_B, 00443 ResetCapFlags:ResetCapFlags_B, 00444 MyCRA: LP_CR1A, 00445 MyCRB: LP_CR1B, 00446 MyLatchLsw:LP_CNTR1BLSW, 00447 MyEventBits:EVBITS(4), 00448 }, 00449 { 00450 GetEnable:GetEnable_B, 00451 GetIntSrc:GetIntSrc_B, 00452 GetLoadTrig:GetLoadTrig_B, 00453 GetMode: GetMode_B, 00454 PulseIndex:PulseIndex_B, 00455 SetEnable:SetEnable_B, 00456 SetIntSrc:SetIntSrc_B, 00457 SetLoadTrig:SetLoadTrig_B, 00458 SetMode: SetMode_B, 00459 ResetCapFlags:ResetCapFlags_B, 00460 MyCRA: LP_CR2A, 00461 MyCRB: LP_CR2B, 00462 MyLatchLsw:LP_CNTR2BLSW, 00463 MyEventBits:EVBITS(5), 00464 }, 00465 }; 00466 00467 // enab/disable a function or test status bit(s) that are accessed 00468 // through Main Control Registers 1 or 2. 00469 #define MC_ENABLE( REGADRS, CTRLWORD ) writel( ( (uint32_t)( CTRLWORD ) << 16 ) | (uint32_t)( CTRLWORD ),devpriv->base_addr+( REGADRS ) ) 00470 00471 #define MC_DISABLE( REGADRS, CTRLWORD ) writel( (uint32_t)( CTRLWORD ) << 16 , devpriv->base_addr+( REGADRS ) ) 00472 00473 #define MC_TEST( REGADRS, CTRLWORD ) ( ( readl(devpriv->base_addr+( REGADRS )) & CTRLWORD ) != 0 ) 00474 00475 /* #define WR7146(REGARDS,CTRLWORD) 00476 writel(CTRLWORD,(uint32_t)(devpriv->base_addr+(REGARDS))) */ 00477 #define WR7146(REGARDS,CTRLWORD) writel(CTRLWORD,devpriv->base_addr+(REGARDS)) 00478 00479 /* #define RR7146(REGARDS) 00480 readl((uint32_t)(devpriv->base_addr+(REGARDS))) */ 00481 #define RR7146(REGARDS) readl(devpriv->base_addr+(REGARDS)) 00482 00483 #define BUGFIX_STREG(REGADRS) ( REGADRS - 4 ) 00484 00485 // Write a time slot control record to TSL2. 00486 #define VECTPORT( VECTNUM ) (P_TSL2 + ( (VECTNUM) << 2 )) 00487 #define SETVECT( VECTNUM, VECTVAL ) WR7146(VECTPORT( VECTNUM ), (VECTVAL)) 00488 00489 // Code macros used for constructing I2C command bytes. 00490 #define I2C_B2(ATTR,VAL) ( ( (ATTR) << 6 ) | ( (VAL) << 24 ) ) 00491 #define I2C_B1(ATTR,VAL) ( ( (ATTR) << 4 ) | ( (VAL) << 16 ) ) 00492 #define I2C_B0(ATTR,VAL) ( ( (ATTR) << 2 ) | ( (VAL) << 8 ) ) 00493 00494 static const comedi_lrange s626_range_table = { 2, { 00495 RANGE(-5, 5), 00496 RANGE(-10, 10), 00497 } 00498 }; 00499 00500 static int s626_attach(comedi_device * dev, comedi_devconfig * it) 00501 { 00502 /* uint8_t PollList; */ 00503 /* uint16_t AdcData; */ 00504 /* uint16_t StartVal; */ 00505 /* uint16_t index; */ 00506 /* unsigned int data[16]; */ 00507 int result; 00508 int i; 00509 int ret; 00510 resource_size_t resourceStart; 00511 dma_addr_t appdma; 00512 comedi_subdevice *s; 00513 struct pci_dev *pdev; 00514 00515 if (alloc_private(dev, sizeof(s626_private)) < 0) 00516 return -ENOMEM; 00517 00518 for (pdev = pci_get_subsys(PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, 00519 PCI_SUBVENDOR_ID_S626, PCI_SUBDEVICE_ID_S626, NULL); 00520 pdev != NULL; 00521 pdev = pci_get_subsys(PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, 00522 PCI_SUBVENDOR_ID_S626, PCI_SUBDEVICE_ID_S626, pdev)) { 00523 if (it->options[0] || it->options[1]) { 00524 if (pdev->bus->number == it->options[0] && 00525 PCI_SLOT(pdev->devfn) == it->options[1]) { 00526 /* matches requested bus/slot */ 00527 break; 00528 } 00529 } else { 00530 /* no bus/slot specified */ 00531 break; 00532 } 00533 } 00534 devpriv->pdev = pdev; 00535 00536 if (pdev == NULL) { 00537 printk("s626_attach: Board not present!!!\n"); 00538 return -ENODEV; 00539 } 00540 00541 if ((result = comedi_pci_enable(pdev, "s626")) < 0) { 00542 printk("s626_attach: comedi_pci_enable fails\n"); 00543 return -ENODEV; 00544 } 00545 devpriv->got_regions = 1; 00546 00547 resourceStart = pci_resource_start(devpriv->pdev, 0); 00548 00549 devpriv->base_addr = ioremap(resourceStart, SIZEOF_ADDRESS_SPACE); 00550 if (devpriv->base_addr == NULL) { 00551 printk("s626_attach: IOREMAP failed\n"); 00552 return -ENODEV; 00553 } 00554 00555 if (devpriv->base_addr) { 00556 //disable master interrupt 00557 writel(0, devpriv->base_addr + P_IER); 00558 00559 //soft reset 00560 writel(MC1_SOFT_RESET, devpriv->base_addr + P_MC1); 00561 00562 //DMA FIXME DMA// 00563 DEBUG("s626_attach: DMA ALLOCATION\n"); 00564 00565 //adc buffer allocation 00566 devpriv->allocatedBuf = 0; 00567 00568 if ((devpriv->ANABuf.LogicalBase = 00569 pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE, 00570 &appdma)) == NULL) { 00571 printk("s626_attach: DMA Memory mapping error\n"); 00572 return -ENOMEM; 00573 } 00574 00575 devpriv->ANABuf.PhysicalBase = appdma; 00576 00577 DEBUG("s626_attach: AllocDMAB ADC Logical=%p, bsize=%d, Physical=0x%x\n", devpriv->ANABuf.LogicalBase, DMABUF_SIZE, (uint32_t) devpriv->ANABuf.PhysicalBase); 00578 00579 devpriv->allocatedBuf++; 00580 00581 if ((devpriv->RPSBuf.LogicalBase = 00582 pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE, 00583 &appdma)) == NULL) { 00584 printk("s626_attach: DMA Memory mapping error\n"); 00585 return -ENOMEM; 00586 } 00587 00588 devpriv->RPSBuf.PhysicalBase = appdma; 00589 00590 DEBUG("s626_attach: AllocDMAB RPS Logical=%p, bsize=%d, Physical=0x%x\n", devpriv->RPSBuf.LogicalBase, DMABUF_SIZE, (uint32_t) devpriv->RPSBuf.PhysicalBase); 00591 00592 devpriv->allocatedBuf++; 00593 00594 } 00595 00596 dev->board_ptr = s626_boards; 00597 dev->board_name = thisboard->name; 00598 00599 if (alloc_subdevices(dev, 6) < 0) 00600 return -ENOMEM; 00601 00602 dev->iobase = (unsigned long)devpriv->base_addr; 00603 dev->irq = devpriv->pdev->irq; 00604 00605 //set up interrupt handler 00606 if (dev->irq == 0) { 00607 printk(" unknown irq (bad)\n"); 00608 } else { 00609 if ((ret = comedi_request_irq(dev->irq, s626_irq_handler, 00610 IRQF_SHARED, "s626", dev)) < 0) { 00611 printk(" irq not available\n"); 00612 dev->irq = 0; 00613 } 00614 } 00615 00616 DEBUG("s626_attach: -- it opts %d,%d -- \n", 00617 it->options[0], it->options[1]); 00618 00619 s = dev->subdevices + 0; 00620 /* analog input subdevice */ 00621 dev->read_subdev = s; 00622 /* we support single-ended (ground) and differential */ 00623 s->type = COMEDI_SUBD_AI; 00624 s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_CMD_READ; 00625 s->n_chan = thisboard->ai_chans; 00626 s->maxdata = (0xffff >> 2); 00627 s->range_table = &s626_range_table; 00628 s->len_chanlist = thisboard->ai_chans; /* This is the maximum chanlist 00629 length that the board can 00630 handle */ 00631 s->insn_config = s626_ai_insn_config; 00632 s->insn_read = s626_ai_insn_read; 00633 s->do_cmd = s626_ai_cmd; 00634 s->do_cmdtest = s626_ai_cmdtest; 00635 s->cancel = s626_ai_cancel; 00636 00637 s = dev->subdevices + 1; 00638 /* analog output subdevice */ 00639 s->type = COMEDI_SUBD_AO; 00640 s->subdev_flags = SDF_WRITABLE | SDF_READABLE; 00641 s->n_chan = thisboard->ao_chans; 00642 s->maxdata = (0x3fff); 00643 s->range_table = &range_bipolar10; 00644 s->insn_write = s626_ao_winsn; 00645 s->insn_read = s626_ao_rinsn; 00646 00647 s = dev->subdevices + 2; 00648 /* digital I/O subdevice */ 00649 s->type = COMEDI_SUBD_DIO; 00650 s->subdev_flags = SDF_WRITABLE | SDF_READABLE; 00651 s->n_chan = S626_DIO_CHANNELS; 00652 s->maxdata = 1; 00653 s->io_bits = 0xffff; 00654 s->private = &dio_private_A; 00655 s->range_table = &range_digital; 00656 s->insn_config = s626_dio_insn_config; 00657 s->insn_bits = s626_dio_insn_bits; 00658 00659 s = dev->subdevices + 3; 00660 /* digital I/O subdevice */ 00661 s->type = COMEDI_SUBD_DIO; 00662 s->subdev_flags = SDF_WRITABLE | SDF_READABLE; 00663 s->n_chan = 16; 00664 s->maxdata = 1; 00665 s->io_bits = 0xffff; 00666 s->private = &dio_private_B; 00667 s->range_table = &range_digital; 00668 s->insn_config = s626_dio_insn_config; 00669 s->insn_bits = s626_dio_insn_bits; 00670 00671 s = dev->subdevices + 4; 00672 /* digital I/O subdevice */ 00673 s->type = COMEDI_SUBD_DIO; 00674 s->subdev_flags = SDF_WRITABLE | SDF_READABLE; 00675 s->n_chan = 16; 00676 s->maxdata = 1; 00677 s->io_bits = 0xffff; 00678 s->private = &dio_private_C; 00679 s->range_table = &range_digital; 00680 s->insn_config = s626_dio_insn_config; 00681 s->insn_bits = s626_dio_insn_bits; 00682 00683 s = dev->subdevices + 5; 00684 /* encoder (counter) subdevice */ 00685 s->type = COMEDI_SUBD_COUNTER; 00686 s->subdev_flags = SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL; 00687 s->n_chan = thisboard->enc_chans; 00688 s->private = enc_private_data; 00689 s->insn_config = s626_enc_insn_config; 00690 s->insn_read = s626_enc_insn_read; 00691 s->insn_write = s626_enc_insn_write; 00692 s->maxdata = 0xffffff; 00693 s->range_table = &range_unknown; 00694 00695 //stop ai_command 00696 devpriv->ai_cmd_running = 0; 00697 00698 if (devpriv->base_addr && (devpriv->allocatedBuf == 2)) { 00699 dma_addr_t pPhysBuf; 00700 uint16_t chan; 00701 00702 // enab DEBI and audio pins, enable I2C interface. 00703 MC_ENABLE(P_MC1, MC1_DEBI | MC1_AUDIO | MC1_I2C); 00704 // Configure DEBI operating mode. 00705 WR7146(P_DEBICFG, DEBI_CFG_SLAVE16 // Local bus is 16 00706 // bits wide. 00707 | (DEBI_TOUT << DEBI_CFG_TOUT_BIT) // Declare DEBI 00708 // transfer timeout 00709 // interval. 00710 | DEBI_SWAP // Set up byte lane 00711 // steering. 00712 | DEBI_CFG_INTEL); // Intel-compatible 00713 // local bus (DEBI 00714 // never times out). 00715 DEBUG("s626_attach: %d debi init -- %d\n", 00716 DEBI_CFG_SLAVE16 | (DEBI_TOUT << DEBI_CFG_TOUT_BIT) | 00717 DEBI_SWAP | DEBI_CFG_INTEL, 00718 DEBI_CFG_INTEL | DEBI_CFG_TOQ | DEBI_CFG_INCQ | 00719 DEBI_CFG_16Q); 00720 00721 //DEBI INIT S626 WR7146( P_DEBICFG, DEBI_CFG_INTEL | DEBI_CFG_TOQ 00722 //| DEBI_CFG_INCQ| DEBI_CFG_16Q); //end 00723 00724 // Paging is disabled. 00725 WR7146(P_DEBIPAGE, DEBI_PAGE_DISABLE); // Disable MMU paging. 00726 00727 // Init GPIO so that ADC Start* is negated. 00728 WR7146(P_GPIO, GPIO_BASE | GPIO1_HI); 00729 00730 //IsBoardRevA is a boolean that indicates whether the board is 00731 //RevA. 00732 00733 // VERSION 2.01 CHANGE: REV A & B BOARDS NOW SUPPORTED BY DYNAMIC 00734 // EEPROM ADDRESS SELECTION. Initialize the I2C interface, which 00735 // is used to access the onboard serial EEPROM. The EEPROM's I2C 00736 // DeviceAddress is hardwired to a value that is dependent on the 00737 // 626 board revision. On all board revisions, the EEPROM stores 00738 // TrimDAC calibration constants for analog I/O. On RevB and 00739 // higher boards, the DeviceAddress is hardwired to 0 to enable 00740 // the EEPROM to also store the PCI SubVendorID and SubDeviceID; 00741 // this is the address at which the SAA7146 expects a 00742 // configuration EEPROM to reside. On RevA boards, the EEPROM 00743 // device address, which is hardwired to 4, prevents the SAA7146 00744 // from retrieving PCI sub-IDs, so the SAA7146 uses its built-in 00745 // default values, instead. 00746 00747 // devpriv->I2Cards= IsBoardRevA ? 0xA8 : 0xA0; // Set I2C EEPROM 00748 // DeviceType (0xA0) 00749 // and DeviceAddress<<1. 00750 00751 devpriv->I2CAdrs = 0xA0; // I2C device address for onboard 00752 // eeprom(revb) 00753 00754 // Issue an I2C ABORT command to halt any I2C operation in 00755 //progress and reset BUSY flag. 00756 WR7146(P_I2CSTAT, I2C_CLKSEL | I2C_ABORT); // Write I2C control: 00757 // abort any I2C 00758 // activity. 00759 MC_ENABLE(P_MC2, MC2_UPLD_IIC); // Invoke command 00760 // upload 00761 while ((RR7146(P_MC2) & MC2_UPLD_IIC) == 0) ; // and wait for 00762 // upload to 00763 // complete. 00764 00765 // Per SAA7146 data sheet, write to STATUS reg twice to reset all 00766 // I2C error flags. 00767 for (i = 0; i < 2; i++) { 00768 WR7146(P_I2CSTAT, I2C_CLKSEL); // Write I2C control: reset 00769 // error flags. 00770 MC_ENABLE(P_MC2, MC2_UPLD_IIC); // Invoke command upload 00771 while (!MC_TEST(P_MC2, MC2_UPLD_IIC)) ; // and wait for 00772 // upload to 00773 // complete. 00774 } 00775 00776 // Init audio interface functional attributes: set DAC/ADC serial 00777 // clock rates, invert DAC serial clock so that DAC data setup 00778 // times are satisfied, enable DAC serial clock out. 00779 WR7146(P_ACON2, ACON2_INIT); 00780 00781 // Set up TSL1 slot list, which is used to control the 00782 // accumulation of ADC data: RSD1 = shift data in on SD1. SIB_A1 00783 // = store data uint8_t at next available location in FB BUFFER1 00784 // register. 00785 WR7146(P_TSL1, RSD1 | SIB_A1); // Fetch ADC high data 00786 // uint8_t. 00787 WR7146(P_TSL1 + 4, RSD1 | SIB_A1 | EOS); // Fetch ADC low data 00788 // uint8_t; end of 00789 // TSL1. 00790 00791 // enab TSL1 slot list so that it executes all the time. 00792 WR7146(P_ACON1, ACON1_ADCSTART); 00793 00794 // Initialize RPS registers used for ADC. 00795 00796 //Physical start of RPS program. 00797 WR7146(P_RPSADDR1, (uint32_t) devpriv->RPSBuf.PhysicalBase); 00798 00799 WR7146(P_RPSPAGE1, 0); // RPS program performs no 00800 // explicit mem writes. 00801 WR7146(P_RPS1_TOUT, 0); // Disable RPS timeouts. 00802 00803 // SAA7146 BUG WORKAROUND. Initialize SAA7146 ADC interface to a 00804 // known state by invoking ADCs until FB BUFFER 1 register shows 00805 // that it is correctly receiving ADC data. This is necessary 00806 // because the SAA7146 ADC interface does not start up in a 00807 // defined state after a PCI reset. 00808 00809 /* PollList = EOPL; // Create a simple polling */ 00810 /* // list for analog input */ 00811 /* // channel 0. */ 00812 /* ResetADC( dev, &PollList ); */ 00813 00814 /* s626_ai_rinsn(dev,dev->subdevices,NULL,data); //( &AdcData ); // */ 00815 /* //Get initial ADC */ 00816 /* //value. */ 00817 00818 /* StartVal = data[0]; */ 00819 00820 /* // VERSION 2.01 CHANGE: TIMEOUT ADDED TO PREVENT HANGED EXECUTION. */ 00821 /* // Invoke ADCs until the new ADC value differs from the initial */ 00822 /* // value or a timeout occurs. The timeout protects against the */ 00823 /* // possibility that the driver is restarting and the ADC data is a */ 00824 /* // fixed value resulting from the applied ADC analog input being */ 00825 /* // unusually quiet or at the rail. */ 00826 00827 /* for ( index = 0; index < 500; index++ ) */ 00828 /* { */ 00829 /* s626_ai_rinsn(dev,dev->subdevices,NULL,data); */ 00830 /* AdcData = data[0]; //ReadADC( &AdcData ); */ 00831 /* if ( AdcData != StartVal ) */ 00832 /* break; */ 00833 /* } */ 00834 00835 // end initADC 00836 00837 // init the DAC interface 00838 00839 // Init Audio2's output DMAC attributes: burst length = 1 DWORD, 00840 // threshold = 1 DWORD. 00841 WR7146(P_PCI_BT_A, 0); 00842 00843 // Init Audio2's output DMA physical addresses. The protection 00844 // address is set to 1 DWORD past the base address so that a 00845 // single DWORD will be transferred each time a DMA transfer is 00846 // enabled. 00847 00848 pPhysBuf = 00849 devpriv->ANABuf.PhysicalBase + 00850 (DAC_WDMABUF_OS * sizeof(uint32_t)); 00851 00852 WR7146(P_BASEA2_OUT, (uint32_t) pPhysBuf); // Buffer base adrs. 00853 WR7146(P_PROTA2_OUT, (uint32_t) (pPhysBuf + sizeof(uint32_t))); // Protection address. 00854 00855 // Cache Audio2's output DMA buffer logical address. This is 00856 // where DAC data is buffered for A2 output DMA transfers. 00857 devpriv->pDacWBuf = 00858 (uint32_t *) devpriv->ANABuf.LogicalBase + 00859 DAC_WDMABUF_OS; 00860 00861 // Audio2's output channels does not use paging. The protection 00862 // violation handling bit is set so that the DMAC will 00863 // automatically halt and its PCI address pointer will be reset 00864 // when the protection address is reached. 00865 WR7146(P_PAGEA2_OUT, 8); 00866 00867 // Initialize time slot list 2 (TSL2), which is used to control 00868 // the clock generation for and serialization of data to be sent 00869 // to the DAC devices. Slot 0 is a NOP that is used to trap TSL 00870 // execution; this permits other slots to be safely modified 00871 // without first turning off the TSL sequencer (which is 00872 // apparently impossible to do). Also, SD3 (which is driven by a 00873 // pull-up resistor) is shifted in and stored to the MSB of 00874 // FB_BUFFER2 to be used as evidence that the slot sequence has 00875 // not yet finished executing. 00876 SETVECT(0, XSD2 | RSD3 | SIB_A2 | EOS); // Slot 0: Trap TSL 00877 // execution, shift 0xFF 00878 // into FB_BUFFER2. 00879 00880 // Initialize slot 1, which is constant. Slot 1 causes a DWORD to 00881 // be transferred from audio channel 2's output FIFO to the FIFO's 00882 // output buffer so that it can be serialized and sent to the DAC 00883 // during subsequent slots. All remaining slots are dynamically 00884 // populated as required by the target DAC device. 00885 SETVECT(1, LF_A2); // Slot 1: Fetch DWORD from Audio2's 00886 // output FIFO. 00887 00888 // Start DAC's audio interface (TSL2) running. 00889 WR7146(P_ACON1, ACON1_DACSTART); 00890 00892 00893 // end init DAC interface 00894 00895 // Init Trim DACs to calibrated values. Do it twice because the 00896 // SAA7146 audio channel does not always reset properly and 00897 // sometimes causes the first few TrimDAC writes to malfunction. 00898 00899 LoadTrimDACs(dev); 00900 LoadTrimDACs(dev); // Insurance. 00901 00903 // Manually init all gate array hardware in case this is a soft 00904 // reset (we have no way of determining whether this is a warm or 00905 // cold start). This is necessary because the gate array will 00906 // reset only in response to a PCI hard reset; there is no soft 00907 // reset function. 00908 00909 // Init all DAC outputs to 0V and init all DAC setpoint and 00910 // polarity images. 00911 for (chan = 0; chan < S626_DAC_CHANNELS; chan++) 00912 SetDAC(dev, chan, 0); 00913 00914 // Init image of WRMISC2 Battery Charger Enabled control bit. 00915 // This image is used when the state of the charger control bit, 00916 // which has no direct hardware readback mechanism, is queried. 00917 devpriv->ChargeEnabled = 0; 00918 00919 // Init image of watchdog timer interval in WRMISC2. This image 00920 // maintains the value of the control bits of MISC2 are 00921 // continuously reset to zero as long as the WD timer is disabled. 00922 devpriv->WDInterval = 0; 00923 00924 // Init Counter Interrupt enab mask for RDMISC2. This mask is 00925 // applied against MISC2 when testing to determine which timer 00926 // events are requesting interrupt service. 00927 devpriv->CounterIntEnabs = 0; 00928 00929 // Init counters. 00930 CountersInit(dev); 00931 00932 // Without modifying the state of the Battery Backup enab, disable 00933 // the watchdog timer, set DIO channels 0-5 to operate in the 00934 // standard DIO (vs. counter overflow) mode, disable the battery 00935 // charger, and reset the watchdog interval selector to zero. 00936 WriteMISC2(dev, (uint16_t) (DEBIread(dev, 00937 LP_RDMISC2) & MISC2_BATT_ENABLE)); 00938 00939 // Initialize the digital I/O subsystem. 00940 s626_dio_init(dev); 00941 00942 //enable interrupt test 00943 // writel(IRQ_GPIO3 | IRQ_RPS1,devpriv->base_addr+P_IER); 00944 } 00945 00946 DEBUG("s626_attach: comedi%d s626 attached %04x\n", dev->minor, 00947 (uint32_t) devpriv->base_addr); 00948 00949 return 1; 00950 } 00951 00952 static lsampl_t s626_ai_reg_to_uint(int data) 00953 { 00954 lsampl_t tempdata; 00955 00956 tempdata = (data >> 18); 00957 if (tempdata & 0x2000) 00958 tempdata &= 0x1fff; 00959 else 00960 tempdata += (1 << 13); 00961 00962 return tempdata; 00963 } 00964 00965 /* static lsampl_t s626_uint_to_reg(comedi_subdevice *s, int data){ */ 00966 /* return 0; */ 00967 /* } */ 00968 00969 static irqreturn_t s626_irq_handler(int irq, void *d PT_REGS_ARG) 00970 { 00971 comedi_device *dev = d; 00972 comedi_subdevice *s; 00973 comedi_cmd *cmd; 00974 enc_private *k; 00975 unsigned long flags; 00976 int32_t *readaddr; 00977 uint32_t irqtype, irqstatus; 00978 int i = 0; 00979 sampl_t tempdata; 00980 uint8_t group; 00981 uint16_t irqbit; 00982 00983 DEBUG("s626_irq_handler: interrupt request recieved!!!\n"); 00984 00985 if (dev->attached == 0) 00986 return IRQ_NONE; 00987 // lock to avoid race with comedi_poll 00988 comedi_spin_lock_irqsave(&dev->spinlock, flags); 00989 00990 //save interrupt enable register state 00991 irqstatus = readl(devpriv->base_addr + P_IER); 00992 00993 //read interrupt type 00994 irqtype = readl(devpriv->base_addr + P_ISR); 00995 00996 //disable master interrupt 00997 writel(0, devpriv->base_addr + P_IER); 00998 00999 //clear interrupt 01000 writel(irqtype, devpriv->base_addr + P_ISR); 01001 01002 //do somethings 01003 DEBUG("s626_irq_handler: interrupt type %d\n", irqtype); 01004 01005 switch (irqtype) { 01006 case IRQ_RPS1: // end_of_scan occurs 01007 01008 DEBUG("s626_irq_handler: RPS1 irq detected\n"); 01009 01010 // manage ai subdevice 01011 s = dev->subdevices; 01012 cmd = &(s->async->cmd); 01013 01014 // Init ptr to DMA buffer that holds new ADC data. We skip the 01015 // first uint16_t in the buffer because it contains junk data from 01016 // the final ADC of the previous poll list scan. 01017 readaddr = (int32_t *) devpriv->ANABuf.LogicalBase + 1; 01018 01019 // get the data and hand it over to comedi 01020 for (i = 0; i < (s->async->cmd.chanlist_len); i++) { 01021 // Convert ADC data to 16-bit integer values and copy to application 01022 // buffer. 01023 tempdata = s626_ai_reg_to_uint((int)*readaddr); 01024 readaddr++; 01025 01026 //put data into read buffer 01027 // comedi_buf_put(s->async, tempdata); 01028 if (cfc_write_to_buffer(s, tempdata) == 0) 01029 printk("s626_irq_handler: cfc_write_to_buffer error!\n"); 01030 01031 DEBUG("s626_irq_handler: ai channel %d acquired: %d\n", 01032 i, tempdata); 01033 } 01034 01035 //end of scan occurs 01036 s->async->events |= COMEDI_CB_EOS; 01037 01038 if (!(devpriv->ai_continous)) 01039 devpriv->ai_sample_count--; 01040 if (devpriv->ai_sample_count <= 0) { 01041 devpriv->ai_cmd_running = 0; 01042 01043 // Stop RPS program. 01044 MC_DISABLE(P_MC1, MC1_ERPS1); 01045 01046 //send end of acquisition 01047 s->async->events |= COMEDI_CB_EOA; 01048 01049 //disable master interrupt 01050 irqstatus = 0; 01051 } 01052 01053 if (devpriv->ai_cmd_running && cmd->scan_begin_src == TRIG_EXT) { 01054 DEBUG("s626_irq_handler: enable interrupt on dio channel %d\n", cmd->scan_begin_arg); 01055 01056 s626_dio_set_irq(dev, cmd->scan_begin_arg); 01057 01058 DEBUG("s626_irq_handler: External trigger is set!!!\n"); 01059 } 01060 // tell comedi that data is there 01061 DEBUG("s626_irq_handler: events %d\n", s->async->events); 01062 comedi_event(dev, s); 01063 break; 01064 case IRQ_GPIO3: //check dio and conter interrupt 01065 01066 DEBUG("s626_irq_handler: GPIO3 irq detected\n"); 01067 01068 // manage ai subdevice 01069 s = dev->subdevices; 01070 cmd = &(s->async->cmd); 01071 01072 //s626_dio_clear_irq(dev); 01073 01074 for (group = 0; group < S626_DIO_BANKS; group++) { 01075 irqbit = 0; 01076 //read interrupt type 01077 irqbit = DEBIread(dev, 01078 ((dio_private *) (dev->subdevices + 2 + 01079 group)->private)->RDCapFlg); 01080 01081 //check if interrupt is generated from dio channels 01082 if (irqbit) { 01083 s626_dio_reset_irq(dev, group, irqbit); 01084 DEBUG("s626_irq_handler: check interrupt on dio group %d %d\n", group, i); 01085 if (devpriv->ai_cmd_running) { 01086 //check if interrupt is an ai acquisition start trigger 01087 if ((irqbit >> (cmd->start_arg - 01088 (16 * group))) 01089 == 1 01090 && cmd->start_src == TRIG_EXT) { 01091 DEBUG("s626_irq_handler: Edge capture interrupt recieved from channel %d\n", cmd->start_arg); 01092 01093 // Start executing the RPS program. 01094 MC_ENABLE(P_MC1, MC1_ERPS1); 01095 01096 DEBUG("s626_irq_handler: aquisition start triggered!!!\n"); 01097 01098 if (cmd->scan_begin_src == 01099 TRIG_EXT) { 01100 DEBUG("s626_ai_cmd: enable interrupt on dio channel %d\n", cmd->scan_begin_arg); 01101 01102 s626_dio_set_irq(dev, 01103 cmd-> 01104 scan_begin_arg); 01105 01106 DEBUG("s626_irq_handler: External scan trigger is set!!!\n"); 01107 } 01108 } 01109 if ((irqbit >> (cmd->scan_begin_arg - 01110 (16 * group))) 01111 == 1 01112 && cmd->scan_begin_src == 01113 TRIG_EXT) { 01114 DEBUG("s626_irq_handler: Edge capture interrupt recieved from channel %d\n", cmd->scan_begin_arg); 01115 01116 // Trigger ADC scan loop start by setting RPS Signal 0. 01117 MC_ENABLE(P_MC2, MC2_ADC_RPS); 01118 01119 DEBUG("s626_irq_handler: scan triggered!!! %d\n", devpriv->ai_sample_count); 01120 if (cmd->convert_src == 01121 TRIG_EXT) { 01122 01123 DEBUG("s626_ai_cmd: enable interrupt on dio channel %d group %d\n", cmd->convert_arg - (16 * group), group); 01124 01125 devpriv-> 01126 ai_convert_count 01127 = 01128 cmd-> 01129 chanlist_len; 01130 01131 s626_dio_set_irq(dev, 01132 cmd-> 01133 convert_arg); 01134 01135 DEBUG("s626_irq_handler: External convert trigger is set!!!\n"); 01136 } 01137 01138 if (cmd->convert_src == 01139 TRIG_TIMER) { 01140 k = &encpriv[5]; 01141 devpriv-> 01142 ai_convert_count 01143 = 01144 cmd-> 01145 chanlist_len; 01146 k->SetEnable(dev, k, 01147 CLKENAB_ALWAYS); 01148 } 01149 } 01150 if ((irqbit >> (cmd->convert_arg - 01151 (16 * group))) 01152 == 1 01153 && cmd->convert_src == 01154 TRIG_EXT) { 01155 DEBUG("s626_irq_handler: Edge capture interrupt recieved from channel %d\n", cmd->convert_arg); 01156 01157 // Trigger ADC scan loop start by setting RPS Signal 0. 01158 MC_ENABLE(P_MC2, MC2_ADC_RPS); 01159 01160 DEBUG("s626_irq_handler: adc convert triggered!!!\n"); 01161 01162 devpriv->ai_convert_count--; 01163 01164 if (devpriv->ai_convert_count > 01165 0) { 01166 01167 DEBUG("s626_ai_cmd: enable interrupt on dio channel %d group %d\n", cmd->convert_arg - (16 * group), group); 01168 01169 s626_dio_set_irq(dev, 01170 cmd-> 01171 convert_arg); 01172 01173 DEBUG("s626_irq_handler: External trigger is set!!!\n"); 01174 } 01175 } 01176 } 01177 break; 01178 } 01179 } 01180 01181 //read interrupt type 01182 irqbit = DEBIread(dev, LP_RDMISC2); 01183 01184 //check interrupt on counters 01185 DEBUG("s626_irq_handler: check counters interrupt %d\n", 01186 irqbit); 01187 01188 if (irqbit & IRQ_COINT1A) { 01189 DEBUG("s626_irq_handler: interrupt on counter 1A overflow\n"); 01190 k = &encpriv[0]; 01191 01192 //clear interrupt capture flag 01193 k->ResetCapFlags(dev, k); 01194 } 01195 if (irqbit & IRQ_COINT2A) { 01196 DEBUG("s626_irq_handler: interrupt on counter 2A overflow\n"); 01197 k = &encpriv[1]; 01198 01199 //clear interrupt capture flag 01200 k->ResetCapFlags(dev, k); 01201 } 01202 if (irqbit & IRQ_COINT3A) { 01203 DEBUG("s626_irq_handler: interrupt on counter 3A overflow\n"); 01204 k = &encpriv[2]; 01205 01206 //clear interrupt capture flag 01207 k->ResetCapFlags(dev, k); 01208 } 01209 if (irqbit & IRQ_COINT1B) { 01210 DEBUG("s626_irq_handler: interrupt on counter 1B overflow\n"); 01211 k = &encpriv[3]; 01212 01213 //clear interrupt capture flag 01214 k->ResetCapFlags(dev, k); 01215 } 01216 if (irqbit & IRQ_COINT2B) { 01217 DEBUG("s626_irq_handler: interrupt on counter 2B overflow\n"); 01218 k = &encpriv[4]; 01219 01220 //clear interrupt capture flag 01221 k->ResetCapFlags(dev, k); 01222 01223 if (devpriv->ai_convert_count > 0) { 01224 devpriv->ai_convert_count--; 01225 if (devpriv->ai_convert_count == 0) 01226 k->SetEnable(dev, k, CLKENAB_INDEX); 01227 01228 if (cmd->convert_src == TRIG_TIMER) { 01229 DEBUG("s626_irq_handler: conver timer trigger!!! %d\n", devpriv->ai_convert_count); 01230 01231 // Trigger ADC scan loop start by setting RPS Signal 0. 01232 MC_ENABLE(P_MC2, MC2_ADC_RPS); 01233 } 01234 } 01235 } 01236 if (irqbit & IRQ_COINT3B) { 01237 DEBUG("s626_irq_handler: interrupt on counter 3B overflow\n"); 01238 k = &encpriv[5]; 01239 01240 //clear interrupt capture flag 01241 k->ResetCapFlags(dev, k); 01242 01243 if (cmd->scan_begin_src == TRIG_TIMER) { 01244 DEBUG("s626_irq_handler: scan timer trigger!!!\n"); 01245 01246 // Trigger ADC scan loop start by setting RPS Signal 0. 01247 MC_ENABLE(P_MC2, MC2_ADC_RPS); 01248 } 01249 01250 if (cmd->convert_src == TRIG_TIMER) { 01251 DEBUG("s626_irq_handler: convert timer trigger is set\n"); 01252 k = &encpriv[4]; 01253 devpriv->ai_convert_count = cmd->chanlist_len; 01254 k->SetEnable(dev, k, CLKENAB_ALWAYS); 01255 } 01256 } 01257 } 01258 01259 //enable interrupt 01260 writel(irqstatus, devpriv->base_addr + P_IER); 01261 01262 DEBUG("s626_irq_handler: exit interrupt service routine.\n"); 01263 01264 comedi_spin_unlock_irqrestore(&dev->spinlock, flags); 01265 return IRQ_HANDLED; 01266 } 01267 01268 static int s626_detach(comedi_device * dev) 01269 { 01270 if (devpriv) { 01271 //stop ai_command 01272 devpriv->ai_cmd_running = 0; 01273 01274 if (devpriv->base_addr) { 01275 //interrupt mask 01276 WR7146(P_IER, 0); // Disable master interrupt. 01277 WR7146(P_ISR, IRQ_GPIO3 | IRQ_RPS1); // Clear board's IRQ status flag. 01278 01279 // Disable the watchdog timer and battery charger. 01280 WriteMISC2(dev, 0); 01281 01282 // Close all interfaces on 7146 device. 01283 WR7146(P_MC1, MC1_SHUTDOWN); 01284 WR7146(P_ACON1, ACON1_BASE); 01285 01286 CloseDMAB(dev, &devpriv->RPSBuf, DMABUF_SIZE); 01287 CloseDMAB(dev, &devpriv->ANABuf, DMABUF_SIZE); 01288 } 01289 01290 if (dev->irq) { 01291 comedi_free_irq(dev->irq, dev); 01292 } 01293 01294 if (devpriv->base_addr) { 01295 iounmap(devpriv->base_addr); 01296 } 01297 01298 if (devpriv->pdev) { 01299 if (devpriv->got_regions) { 01300 comedi_pci_disable(devpriv->pdev); 01301 } 01302 pci_dev_put(devpriv->pdev); 01303 } 01304 } 01305 01306 DEBUG("s626_detach: S626 detached!\n"); 01307 01308 return 0; 01309 } 01310 01311 /* 01312 * this functions build the RPS program for hardware driven acquistion 01313 */ 01314 void ResetADC(comedi_device * dev, uint8_t * ppl) 01315 { 01316 register uint32_t *pRPS; 01317 uint32_t JmpAdrs; 01318 uint16_t i; 01319 uint16_t n; 01320 uint32_t LocalPPL; 01321 comedi_cmd *cmd = &(dev->subdevices->async->cmd); 01322 01323 // Stop RPS program in case it is currently running. 01324 MC_DISABLE(P_MC1, MC1_ERPS1); 01325 01326 // Set starting logical address to write RPS commands. 01327 pRPS = (uint32_t *) devpriv->RPSBuf.LogicalBase; 01328 01329 // Initialize RPS instruction pointer. 01330 WR7146(P_RPSADDR1, (uint32_t) devpriv->RPSBuf.PhysicalBase); 01331 01332 // Construct RPS program in RPSBuf DMA buffer 01333 01334 if (cmd != NULL && cmd->scan_begin_src != TRIG_FOLLOW) { 01335 DEBUG("ResetADC: scan_begin pause inserted\n"); 01336 // Wait for Start trigger. 01337 *pRPS++ = RPS_PAUSE | RPS_SIGADC; 01338 *pRPS++ = RPS_CLRSIGNAL | RPS_SIGADC; 01339 } 01340 // SAA7146 BUG WORKAROUND Do a dummy DEBI Write. This is necessary 01341 // because the first RPS DEBI Write following a non-RPS DEBI write 01342 // seems to always fail. If we don't do this dummy write, the ADC 01343 // gain might not be set to the value required for the first slot in 01344 // the poll list; the ADC gain would instead remain unchanged from 01345 // the previously programmed value. 01346 *pRPS++ = RPS_LDREG | (P_DEBICMD >> 2); // Write DEBI Write command 01347 // and address to shadow RAM. 01348 *pRPS++ = DEBI_CMD_WRWORD | LP_GSEL; 01349 *pRPS++ = RPS_LDREG | (P_DEBIAD >> 2); // Write DEBI immediate data 01350 // to shadow RAM: 01351 *pRPS++ = GSEL_BIPOLAR5V; // arbitrary immediate data 01352 // value. 01353 *pRPS++ = RPS_CLRSIGNAL | RPS_DEBI; // Reset "shadow RAM 01354 // uploaded" flag. 01355 *pRPS++ = RPS_UPLOAD | RPS_DEBI; // Invoke shadow RAM upload. 01356 *pRPS++ = RPS_PAUSE | RPS_DEBI; // Wait for shadow upload to finish. 01357 01358 // Digitize all slots in the poll list. This is implemented as a 01359 // for loop to limit the slot count to 16 in case the application 01360 // forgot to set the EOPL flag in the final slot. 01361 for (devpriv->AdcItems = 0; devpriv->AdcItems < 16; devpriv->AdcItems++) { 01362 // Convert application's poll list item to private board class 01363 // format. Each app poll list item is an uint8_t with form 01364 // (EOPL,x,x,RANGE,CHAN<3:0>), where RANGE code indicates 0 = 01365 // +-10V, 1 = +-5V, and EOPL = End of Poll List marker. 01366 LocalPPL = 01367 (*ppl << 8) | (*ppl & 0x10 ? GSEL_BIPOLAR5V : 01368 GSEL_BIPOLAR10V); 01369 01370 // Switch ADC analog gain. 01371 *pRPS++ = RPS_LDREG | (P_DEBICMD >> 2); // Write DEBI command 01372 // and address to 01373 // shadow RAM. 01374 *pRPS++ = DEBI_CMD_WRWORD | LP_GSEL; 01375 *pRPS++ = RPS_LDREG | (P_DEBIAD >> 2); // Write DEBI 01376 // immediate data to 01377 // shadow RAM. 01378 *pRPS++ = LocalPPL; 01379 *pRPS++ = RPS_CLRSIGNAL | RPS_DEBI; // Reset "shadow RAM uploaded" 01380 // flag. 01381 *pRPS++ = RPS_UPLOAD | RPS_DEBI; // Invoke shadow RAM upload. 01382 *pRPS++ = RPS_PAUSE | RPS_DEBI; // Wait for shadow upload to 01383 // finish. 01384 01385 // Select ADC analog input channel. 01386 *pRPS++ = RPS_LDREG | (P_DEBICMD >> 2); // Write DEBI command 01387 // and address to 01388 // shadow RAM. 01389 *pRPS++ = DEBI_CMD_WRWORD | LP_ISEL; 01390 *pRPS++ = RPS_LDREG | (P_DEBIAD >> 2); // Write DEBI 01391 // immediate data to 01392 // shadow RAM. 01393 *pRPS++ = LocalPPL; 01394 *pRPS++ = RPS_CLRSIGNAL | RPS_DEBI; // Reset "shadow RAM uploaded" 01395 // flag. 01396 *pRPS++ = RPS_UPLOAD | RPS_DEBI; // Invoke shadow RAM upload. 01397 *pRPS++ = RPS_PAUSE | RPS_DEBI; // Wait for shadow upload to 01398 // finish. 01399 01400 // Delay at least 10 microseconds for analog input settling. 01401 // Instead of padding with NOPs, we use RPS_JUMP instructions 01402 // here; this allows us to produce a longer delay than is 01403 // possible with NOPs because each RPS_JUMP flushes the RPS' 01404 // instruction prefetch pipeline. 01405 JmpAdrs = 01406 (uint32_t) devpriv->RPSBuf.PhysicalBase + 01407 (uint32_t) ((unsigned long)pRPS - 01408 (unsigned long)devpriv->RPSBuf.LogicalBase); 01409 for (i = 0; i < (10 * RPSCLK_PER_US / 2); i++) { 01410 JmpAdrs += 8; // Repeat to implement time delay: 01411 *pRPS++ = RPS_JUMP; // Jump to next RPS instruction. 01412 *pRPS++ = JmpAdrs; 01413 } 01414 01415 if (cmd != NULL && cmd->convert_src != TRIG_NOW) { 01416 DEBUG("ResetADC: convert pause inserted\n"); 01417 // Wait for Start trigger. 01418 *pRPS++ = RPS_PAUSE | RPS_SIGADC; 01419 *pRPS++ = RPS_CLRSIGNAL | RPS_SIGADC; 01420 } 01421 // Start ADC by pulsing GPIO1. 01422 *pRPS++ = RPS_LDREG | (P_GPIO >> 2); // Begin ADC Start pulse. 01423 *pRPS++ = GPIO_BASE | GPIO1_LO; 01424 *pRPS++ = RPS_NOP; 01425 // VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE. 01426 *pRPS++ = RPS_LDREG | (P_GPIO >> 2); // End ADC Start pulse. 01427 *pRPS++ = GPIO_BASE | GPIO1_HI; 01428 01429 // Wait for ADC to complete (GPIO2 is asserted high when ADC not 01430 // busy) and for data from previous conversion to shift into FB 01431 // BUFFER 1 register. 01432 *pRPS++ = RPS_PAUSE | RPS_GPIO2; // Wait for ADC done. 01433 01434 // Transfer ADC data from FB BUFFER 1 register to DMA buffer. 01435 *pRPS++ = RPS_STREG | (BUGFIX_STREG(P_FB_BUFFER1) >> 2); 01436 *pRPS++ = 01437 (uint32_t) devpriv->ANABuf.PhysicalBase + 01438 (devpriv->AdcItems << 2); 01439 01440 // If this slot's EndOfPollList flag is set, all channels have 01441 // now been processed. 01442 if (*ppl++ & EOPL) { 01443 devpriv->AdcItems++; // Adjust poll list item count. 01444 break; // Exit poll list processing loop. 01445 } 01446 } 01447 DEBUG("ResetADC: ADC items %d \n", devpriv->AdcItems); 01448 01449 // VERSION 2.01 CHANGE: DELAY CHANGED FROM 250NS to 2US. Allow the 01450 // ADC to stabilize for 2 microseconds before starting the final 01451 // (dummy) conversion. This delay is necessary to allow sufficient 01452 // time between last conversion finished and the start of the dummy 01453 // conversion. Without this delay, the last conversion's data value 01454 // is sometimes set to the previous conversion's data value. 01455 for (n = 0; n < (2 * RPSCLK_PER_US); n++) 01456 *pRPS++ = RPS_NOP; 01457 01458 // Start a dummy conversion to cause the data from the last 01459 // conversion of interest to be shifted in. 01460 *pRPS++ = RPS_LDREG | (P_GPIO >> 2); // Begin ADC Start pulse. 01461 *pRPS++ = GPIO_BASE | GPIO1_LO; 01462 *pRPS++ = RPS_NOP; 01463 // VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE. 01464 *pRPS++ = RPS_LDREG | (P_GPIO >> 2); // End ADC Start pulse. 01465 *pRPS++ = GPIO_BASE | GPIO1_HI; 01466 01467 // Wait for the data from the last conversion of interest to arrive 01468 // in FB BUFFER 1 register. 01469 *pRPS++ = RPS_PAUSE | RPS_GPIO2; // Wait for ADC done. 01470 01471 // Transfer final ADC data from FB BUFFER 1 register to DMA buffer. 01472 *pRPS++ = RPS_STREG | (BUGFIX_STREG(P_FB_BUFFER1) >> 2); // 01473 *pRPS++ = 01474 (uint32_t) devpriv->ANABuf.PhysicalBase + 01475 (devpriv->AdcItems << 2); 01476 01477 // Indicate ADC scan loop is finished. 01478 // *pRPS++= RPS_CLRSIGNAL | RPS_SIGADC ; // Signal ReadADC() that scan is done. 01479 01480 //invoke interrupt 01481 if (devpriv->ai_cmd_running == 1) { 01482 DEBUG("ResetADC: insert irq in ADC RPS task\n"); 01483 *pRPS++ = RPS_IRQ; 01484 } 01485 // Restart RPS program at its beginning. 01486 *pRPS++ = RPS_JUMP; // Branch to start of RPS program. 01487 *pRPS++ = (uint32_t) devpriv->RPSBuf.PhysicalBase; 01488 01489 // End of RPS program build 01490 // ------------------------------------------------------------ 01491 } 01492 01493 /* TO COMPLETE, IF NECESSARY */ 01494 static int s626_ai_insn_config(comedi_device * dev, comedi_subdevice * s, 01495 comedi_insn * insn, lsampl_t * data) 01496 { 01497 01498 return -EINVAL; 01499 } 01500 01501 /* static int s626_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data) */ 01502 /* { */ 01503 /* register uint8_t i; */ 01504 /* register int32_t *readaddr; */ 01505 01506 /* DEBUG("as626_ai_rinsn: ai_rinsn enter \n"); */ 01507 01508 /* // Trigger ADC scan loop start by setting RPS Signal 0. */ 01509 /* MC_ENABLE( P_MC2, MC2_ADC_RPS ); */ 01510 01511 /* // Wait until ADC scan loop is finished (RPS Signal 0 reset). */ 01512 /* while ( MC_TEST( P_MC2, MC2_ADC_RPS ) ); */ 01513 01514 /* // Init ptr to DMA buffer that holds new ADC data. We skip the */ 01515 /* // first uint16_t in the buffer because it contains junk data from */ 01516 /* // the final ADC of the previous poll list scan. */ 01517 /* readaddr = (uint32_t *)devpriv->ANABuf.LogicalBase + 1; */ 01518 01519 /* // Convert ADC data to 16-bit integer values and copy to application */ 01520 /* // buffer. */ 01521 /* for ( i = 0; i < devpriv->AdcItems; i++ ) { */ 01522 /* *data = s626_ai_reg_to_uint( *readaddr++ ); */ 01523 /* DEBUG("s626_ai_rinsn: data %d \n",*data); */ 01524 /* data++; */ 01525 /* } */ 01526 01527 /* DEBUG("s626_ai_rinsn: ai_rinsn escape \n"); */ 01528 /* return i; */ 01529 /* } */ 01530 01531 static int s626_ai_insn_read(comedi_device * dev, comedi_subdevice * s, 01532 comedi_insn * insn, lsampl_t * data) 01533 { 01534 uint16_t chan = CR_CHAN(insn->chanspec); 01535 uint16_t range = CR_RANGE(insn->chanspec); 01536 uint16_t AdcSpec = 0; 01537 uint32_t GpioImage; 01538 int n; 01539 01540 /* //interrupt call test */ 01541 /* writel(IRQ_GPIO3,devpriv->base_addr+P_PSR); //Writing a logical 1 */ 01542 /* //into any of the RPS_PSR */ 01543 /* //bits causes the */ 01544 /* //corresponding interrupt */ 01545 /* //to be generated if */ 01546 /* //enabled */ 01547 01548 DEBUG("s626_ai_insn_read: entering\n"); 01549 01550 // Convert application's ADC specification into form 01551 // appropriate for register programming. 01552 if (range == 0) 01553 AdcSpec = (chan << 8) | (GSEL_BIPOLAR5V); 01554 else 01555 AdcSpec = (chan << 8) | (GSEL_BIPOLAR10V); 01556 01557 // Switch ADC analog gain. 01558 DEBIwrite(dev, LP_GSEL, AdcSpec); // Set gain. 01559 01560 // Select ADC analog input channel. 01561 DEBIwrite(dev, LP_ISEL, AdcSpec); // Select channel. 01562 01563 for (n = 0; n < insn->n; n++) { 01564 01565 // Delay 10 microseconds for analog input settling. 01566 comedi_udelay(10); 01567 01568 // Start ADC by pulsing GPIO1 low. 01569 GpioImage = RR7146(P_GPIO); 01570 // Assert ADC Start command 01571 WR7146(P_GPIO, GpioImage & ~GPIO1_HI); 01572 // and stretch it out. 01573 WR7146(P_GPIO, GpioImage & ~GPIO1_HI); 01574 WR7146(P_GPIO, GpioImage & ~GPIO1_HI); 01575 // Negate ADC Start command. 01576 WR7146(P_GPIO, GpioImage | GPIO1_HI); 01577 01578 // Wait for ADC to complete (GPIO2 is asserted high when 01579 // ADC not busy) and for data from previous conversion to 01580 // shift into FB BUFFER 1 register. 01581 01582 // Wait for ADC done. 01583 while (!(RR7146(P_PSR) & PSR_GPIO2)) ; 01584 01585 // Fetch ADC data. 01586 if (n != 0) 01587 data[n - 1] = s626_ai_reg_to_uint(RR7146(P_FB_BUFFER1)); 01588 01589 // Allow the ADC to stabilize for 4 microseconds before 01590 // starting the next (final) conversion. This delay is 01591 // necessary to allow sufficient time between last 01592 // conversion finished and the start of the next 01593 // conversion. Without this delay, the last conversion's 01594 // data value is sometimes set to the previous 01595 // conversion's data value. 01596 comedi_udelay(4); 01597 } 01598 01599 // Start a dummy conversion to cause the data from the 01600 // previous conversion to be shifted in. 01601 GpioImage = RR7146(P_GPIO); 01602 01603 //Assert ADC Start command 01604 WR7146(P_GPIO, GpioImage & ~GPIO1_HI); 01605 // and stretch it out. 01606 WR7146(P_GPIO, GpioImage & ~GPIO1_HI); 01607 WR7146(P_GPIO, GpioImage & ~GPIO1_HI); 01608 // Negate ADC Start command. 01609 WR7146(P_GPIO, GpioImage | GPIO1_HI); 01610 01611 // Wait for the data to arrive in FB BUFFER 1 register. 01612 01613 // Wait for ADC done. 01614 while (!(RR7146(P_PSR) & PSR_GPIO2)) ; 01615 01616 // Fetch ADC data from audio interface's input shift 01617 // register. 01618 01619 // Fetch ADC data. 01620 if (n != 0) 01621 data[n - 1] = s626_ai_reg_to_uint(RR7146(P_FB_BUFFER1)); 01622 01623 DEBUG("s626_ai_insn_read: samples %d, data %d\n", n, data[n - 1]); 01624 01625 return n; 01626 } 01627 01628 static int s626_ai_load_polllist(uint8_t * ppl, comedi_cmd * cmd) 01629 { 01630 01631 int n; 01632 01633 for (n = 0; n < cmd->chanlist_len; n++) { 01634 if (CR_RANGE((cmd->chanlist)[n]) == 0) 01635 ppl[n] = (CR_CHAN((cmd->chanlist)[n])) | (RANGE_5V); 01636 else 01637 ppl[n] = (CR_CHAN((cmd->chanlist)[n])) | (RANGE_10V); 01638 } 01639 ppl[n - 1] |= EOPL; 01640 01641 return n; 01642 } 01643 01644 static int s626_ai_inttrig(comedi_device * dev, comedi_subdevice * s, 01645 unsigned int trignum) 01646 { 01647 if (trignum != 0) 01648 return -EINVAL; 01649 01650 DEBUG("s626_ai_inttrig: trigger adc start..."); 01651 01652 // Start executing the RPS program. 01653 MC_ENABLE(P_MC1, MC1_ERPS1); 01654 01655 s->async->inttrig = NULL; 01656 01657 DEBUG(" done\n"); 01658 01659 return 1; 01660 } 01661 01662 /* TO COMPLETE */ 01663 static int s626_ai_cmd(comedi_device * dev, comedi_subdevice * s) 01664 { 01665 01666 uint8_t ppl[16]; 01667 comedi_cmd *cmd = &s->async->cmd; 01668 enc_private *k; 01669 int tick; 01670 01671 DEBUG("s626_ai_cmd: entering command function\n"); 01672 01673 if (devpriv->ai_cmd_running) { 01674 printk("s626_ai_cmd: Another ai_cmd is running %d\n", 01675 dev->minor); 01676 return -EBUSY; 01677 } 01678 //disable interrupt 01679 writel(0, devpriv->base_addr + P_IER); 01680 01681 //clear interrupt request 01682 writel(IRQ_RPS1 | IRQ_GPIO3, devpriv->base_addr + P_ISR); 01683 01684 //clear any pending interrupt 01685 s626_dio_clear_irq(dev); 01686 // s626_enc_clear_irq(dev); 01687 01688 //reset ai_cmd_running flag 01689 devpriv->ai_cmd_running = 0; 01690 01691 // test if cmd is valid 01692 if (cmd == NULL) { 01693 DEBUG("s626_ai_cmd: NULL command\n"); 01694 return -EINVAL; 01695 } else { 01696 DEBUG("s626_ai_cmd: command recieved!!!\n"); 01697 } 01698 01699 if (dev->irq == 0) { 01700 comedi_error(dev, 01701 "s626_ai_cmd: cannot run command without an irq"); 01702 return -EIO; 01703 } 01704 01705 s626_ai_load_polllist(ppl, cmd); 01706 devpriv->ai_cmd_running = 1; 01707 devpriv->ai_convert_count = 0; 01708 01709 switch (cmd->scan_begin_src) { 01710 case TRIG_FOLLOW: 01711 break; 01712 case TRIG_TIMER: 01713 // set a conter to generate adc trigger at scan_begin_arg interval 01714 k = &encpriv[5]; 01715 tick = s626_ns_to_timer((int *)&cmd->scan_begin_arg, 01716 cmd->flags & TRIG_ROUND_MASK); 01717 01718 //load timer value and enable interrupt 01719 s626_timer_load(dev, k, tick); 01720 k->SetEnable(dev, k, CLKENAB_ALWAYS); 01721 01722 DEBUG("s626_ai_cmd: scan trigger timer is set with value %d\n", 01723 tick); 01724 01725 break; 01726 case TRIG_EXT: 01727 // set the digital line and interrupt for scan trigger 01728 if (cmd->start_src != TRIG_EXT) 01729 s626_dio_set_irq(dev, cmd->scan_begin_arg); 01730 01731 DEBUG("s626_ai_cmd: External scan trigger is set!!!\n"); 01732 01733 break; 01734 } 01735 01736 switch (cmd->convert_src) { 01737 case TRIG_NOW: 01738 break; 01739 case TRIG_TIMER: 01740 // set a conter to generate adc trigger at convert_arg interval 01741 k = &encpriv[4]; 01742 tick = s626_ns_to_timer((int *)&cmd->convert_arg, 01743 cmd->flags & TRIG_ROUND_MASK); 01744 01745 //load timer value and enable interrupt 01746 s626_timer_load(dev, k, tick); 01747 k->SetEnable(dev, k, CLKENAB_INDEX); 01748 01749 DEBUG("s626_ai_cmd: convert trigger timer is set with value %d\n", tick); 01750 break; 01751 case TRIG_EXT: 01752 // set the digital line and interrupt for convert trigger 01753 if (cmd->scan_begin_src != TRIG_EXT 01754 && cmd->start_src == TRIG_EXT) 01755 s626_dio_set_irq(dev, cmd->convert_arg); 01756 01757 DEBUG("s626_ai_cmd: External convert trigger is set!!!\n"); 01758 01759 break; 01760 } 01761 01762 switch (cmd->stop_src) { 01763 case TRIG_COUNT: 01764 // data arrives as one packet 01765 devpriv->ai_sample_count = cmd->stop_arg; 01766 devpriv->ai_continous = 0; 01767 break; 01768 case TRIG_NONE: 01769 // continous aquisition 01770 devpriv->ai_continous = 1; 01771 devpriv->ai_sample_count = 0; 01772 break; 01773 } 01774 01775 ResetADC(dev, ppl); 01776 01777 switch (cmd->start_src) { 01778 case TRIG_NOW: 01779 // Trigger ADC scan loop start by setting RPS Signal 0. 01780 // MC_ENABLE( P_MC2, MC2_ADC_RPS ); 01781 01782 // Start executing the RPS program. 01783 MC_ENABLE(P_MC1, MC1_ERPS1); 01784 01785 DEBUG("s626_ai_cmd: ADC triggered\n"); 01786 s->async->inttrig = NULL; 01787 break; 01788 case TRIG_EXT: 01789 //configure DIO channel for acquisition trigger 01790 s626_dio_set_irq(dev, cmd->start_arg); 01791 01792 DEBUG("s626_ai_cmd: External start trigger is set!!!\n"); 01793 01794 s->async->inttrig = NULL; 01795 break; 01796 case TRIG_INT: 01797 s->async->inttrig = s626_ai_inttrig; 01798 break; 01799 } 01800 01801 //enable interrupt 01802 writel(IRQ_GPIO3 | IRQ_RPS1, devpriv->base_addr + P_IER); 01803 01804 DEBUG("s626_ai_cmd: command function terminated\n"); 01805 01806 return 0; 01807 } 01808 01809 static int s626_ai_cmdtest(comedi_device * dev, comedi_subdevice * s, 01810 comedi_cmd * cmd) 01811 { 01812 int err = 0; 01813 int tmp; 01814 01815 /* cmdtest tests a particular command to see if it is valid. Using 01816 * the cmdtest ioctl, a user can create a valid cmd and then have it 01817 * executes by the cmd ioctl. 01818 * 01819 * cmdtest returns 1,2,3,4 or 0, depending on which tests the 01820 * command passes. */ 01821 01822 /* step 1: make sure trigger sources are trivially valid */ 01823 01824 tmp = cmd->start_src; 01825 cmd->start_src &= TRIG_NOW | TRIG_INT | TRIG_EXT; 01826 if (!cmd->start_src || tmp != cmd->start_src) 01827 err++; 01828 01829 tmp = cmd->scan_begin_src; 01830 cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW; 01831 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 01832 err++; 01833 01834 tmp = cmd->convert_src; 01835 cmd->convert_src &= TRIG_TIMER | TRIG_EXT | TRIG_NOW; 01836 if (!cmd->convert_src || tmp != cmd->convert_src) 01837 err++; 01838 01839 tmp = cmd->scan_end_src; 01840 cmd->scan_end_src &= TRIG_COUNT; 01841 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 01842 err++; 01843 01844 tmp = cmd->stop_src; 01845 cmd->stop_src &= TRIG_COUNT | TRIG_NONE; 01846 if (!cmd->stop_src || tmp != cmd->stop_src) 01847 err++; 01848 01849 if (err) 01850 return 1; 01851 01852 /* step 2: make sure trigger sources are unique and mutually 01853 compatible */ 01854 01855 /* note that mutual compatiblity is not an issue here */ 01856 if (cmd->scan_begin_src != TRIG_TIMER && 01857 cmd->scan_begin_src != TRIG_EXT 01858 && cmd->scan_begin_src != TRIG_FOLLOW) 01859 err++; 01860 if (cmd->convert_src != TRIG_TIMER && 01861 cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) 01862 err++; 01863 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) 01864 err++; 01865 01866 if (err) 01867 return 2; 01868 01869 /* step 3: make sure arguments are trivially compatible */ 01870 01871 if (cmd->start_src != TRIG_EXT && cmd->start_arg != 0) { 01872 cmd->start_arg = 0; 01873 err++; 01874 } 01875 01876 if (cmd->start_src == TRIG_EXT && cmd->start_arg < 0) { 01877 cmd->start_arg = 0; 01878 err++; 01879 } 01880 01881 if (cmd->start_src == TRIG_EXT && cmd->start_arg > 39) { 01882 cmd->start_arg = 39; 01883 err++; 01884 } 01885 01886 if (cmd->scan_begin_src == TRIG_EXT && cmd->scan_begin_arg < 0) { 01887 cmd->scan_begin_arg = 0; 01888 err++; 01889 } 01890 01891 if (cmd->scan_begin_src == TRIG_EXT && cmd->scan_begin_arg > 39) { 01892 cmd->scan_begin_arg = 39; 01893 err++; 01894 } 01895 01896 if (cmd->convert_src == TRIG_EXT && cmd->convert_arg < 0) { 01897 cmd->convert_arg = 0; 01898 err++; 01899 } 01900 01901 if (cmd->convert_src == TRIG_EXT && cmd->convert_arg > 39) { 01902 cmd->convert_arg = 39; 01903 err++; 01904 } 01905 #define MAX_SPEED 200000 /* in nanoseconds */ 01906 #define MIN_SPEED 2000000000 /* in nanoseconds */ 01907 01908 if (cmd->scan_begin_src == TRIG_TIMER) { 01909 if (cmd->scan_begin_arg < MAX_SPEED) { 01910 cmd->scan_begin_arg = MAX_SPEED; 01911 err++; 01912 } 01913 if (cmd->scan_begin_arg > MIN_SPEED) { 01914 cmd->scan_begin_arg = MIN_SPEED; 01915 err++; 01916 } 01917 } else { 01918 /* external trigger */ 01919 /* should be level/edge, hi/lo specification here */ 01920 /* should specify multiple external triggers */ 01921 /* if(cmd->scan_begin_arg>9){ */ 01922 /* cmd->scan_begin_arg=9; */ 01923 /* err++; */ 01924 /* } */ 01925 } 01926 if (cmd->convert_src == TRIG_TIMER) { 01927 if (cmd->convert_arg < MAX_SPEED) { 01928 cmd->convert_arg = MAX_SPEED; 01929 err++; 01930 } 01931 if (cmd->convert_arg > MIN_SPEED) { 01932 cmd->convert_arg = MIN_SPEED; 01933 err++; 01934 } 01935 } else { 01936 /* external trigger */ 01937 /* see above */ 01938 /* if(cmd->convert_arg>9){ */ 01939 /* cmd->convert_arg=9; */ 01940 /* err++; */ 01941 /* } */ 01942 } 01943 01944 if (cmd->scan_end_arg != cmd->chanlist_len) { 01945 cmd->scan_end_arg = cmd->chanlist_len; 01946 err++; 01947 } 01948 if (cmd->stop_src == TRIG_COUNT) { 01949 if (cmd->stop_arg > 0x00ffffff) { 01950 cmd->stop_arg = 0x00ffffff; 01951 err++; 01952 } 01953 } else { 01954 /* TRIG_NONE */ 01955 if (cmd->stop_arg != 0) { 01956 cmd->stop_arg = 0; 01957 err++; 01958 } 01959 } 01960 01961 if (err) 01962 return 3; 01963 01964 /* step 4: fix up any arguments */ 01965 01966 if (cmd->scan_begin_src == TRIG_TIMER) { 01967 tmp = cmd->scan_begin_arg; 01968 s626_ns_to_timer((int *)&cmd->scan_begin_arg, 01969 cmd->flags & TRIG_ROUND_MASK); 01970 if (tmp != cmd->scan_begin_arg) 01971 err++; 01972 } 01973 if (cmd->convert_src == TRIG_TIMER) { 01974 tmp = cmd->convert_arg; 01975 s626_ns_to_timer((int *)&cmd->convert_arg, 01976 cmd->flags & TRIG_ROUND_MASK); 01977 if (tmp != cmd->convert_arg) 01978 err++; 01979 if (cmd->scan_begin_src == TRIG_TIMER && 01980 cmd->scan_begin_arg < 01981 cmd->convert_arg * cmd->scan_end_arg) { 01982 cmd->scan_begin_arg = 01983 cmd->convert_arg * cmd->scan_end_arg; 01984 err++; 01985 } 01986 } 01987 01988 if (err) 01989 return 4; 01990 01991 return 0; 01992 } 01993 01994 static int s626_ai_cancel(comedi_device * dev, comedi_subdevice * s) 01995 { 01996 // Stop RPS program in case it is currently running. 01997 MC_DISABLE(P_MC1, MC1_ERPS1); 01998 01999 //disable master interrupt 02000 writel(0, devpriv->base_addr + P_IER); 02001 02002 devpriv->ai_cmd_running = 0; 02003 02004 return 0; 02005 } 02006 02007 /* This function doesn't require a particular form, this is just what 02008 * happens to be used in some of the drivers. It should convert ns 02009 * nanoseconds to a counter value suitable for programming the device. 02010 * Also, it should adjust ns so that it cooresponds to the actual time 02011 * that the device will use. */ 02012 static int s626_ns_to_timer(int *nanosec, int round_mode) 02013 { 02014 int divider, base; 02015 02016 base = 500; //2MHz internal clock 02017 02018 switch (round_mode) { 02019 case TRIG_ROUND_NEAREST: 02020 default: 02021 divider = (*nanosec + base / 2) / base; 02022 break; 02023 case TRIG_ROUND_DOWN: 02024 divider = (*nanosec) / base; 02025 break; 02026 case TRIG_ROUND_UP: 02027 divider = (*nanosec + base - 1) / base; 02028 break; 02029 } 02030 02031 *nanosec = base * divider; 02032 return divider - 1; 02033 } 02034 02035 static int s626_ao_winsn(comedi_device * dev, comedi_subdevice * s, 02036 comedi_insn * insn, lsampl_t * data) 02037 { 02038 02039 int i; 02040 uint16_t chan = CR_CHAN(insn->chanspec); 02041 int16_t dacdata; 02042 02043 for (i = 0; i < insn->n; i++) { 02044 dacdata = (int16_t) data[i]; 02045 devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[i]; 02046 dacdata -= (0x1fff); 02047 02048 SetDAC(dev, chan, dacdata); 02049 } 02050 02051 return i; 02052 } 02053 02054 static int s626_ao_rinsn(comedi_device * dev, comedi_subdevice * s, 02055 comedi_insn * insn, lsampl_t * data) 02056 { 02057 int i; 02058 02059 for (i = 0; i < insn->n; i++) { 02060 data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; 02061 } 02062 02063 return i; 02064 } 02065 02069 // All DIO functions address a group of DIO channels by means of 02070 // "group" argument. group may be 0, 1 or 2, which correspond to DIO 02071 // ports A, B and C, respectively. 02073 02074 static void s626_dio_init(comedi_device * dev) 02075 { 02076 uint16_t group; 02077 comedi_subdevice *s; 02078 02079 // Prepare to treat writes to WRCapSel as capture disables. 02080 DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP); 02081 02082 // For each group of sixteen channels ... 02083 for (group = 0; group < S626_DIO_BANKS; group++) { 02084 s = dev->subdevices + 2 + group; 02085 DEBIwrite(dev, diopriv->WRIntSel, 0); // Disable all interrupts. 02086 DEBIwrite(dev, diopriv->WRCapSel, 0xFFFF); // Disable all event 02087 // captures. 02088 DEBIwrite(dev, diopriv->WREdgSel, 0); // Init all DIOs to 02089 // default edge 02090 // polarity. 02091 DEBIwrite(dev, diopriv->WRDOut, 0); // Program all outputs 02092 // to inactive state. 02093 } 02094 DEBUG("s626_dio_init: DIO initialized \n"); 02095 } 02096 02097 /* DIO devices are slightly special. Although it is possible to 02098 * implement the insn_read/insn_write interface, it is much more 02099 * useful to applications if you implement the insn_bits interface. 02100 * This allows packed reading/writing of the DIO channels. The comedi 02101 * core can convert between insn_bits and insn_read/write */ 02102 02103 static int s626_dio_insn_bits(comedi_device * dev, comedi_subdevice * s, 02104 comedi_insn * insn, lsampl_t * data) 02105 { 02106 02107 /* Length of data must be 2 (mask and new data, see below) */ 02108 if (insn->n == 0) { 02109 return 0; 02110 } 02111 if (insn->n != 2) { 02112 printk("comedi%d: s626: s626_dio_insn_bits(): Invalid instruction length\n", dev->minor); 02113 return -EINVAL; 02114 } 02115 02116 /* 02117 * The insn data consists of a mask in data[0] and the new data in 02118 * data[1]. The mask defines which bits we are concerning about. 02119 * The new data must be anded with the mask. Each channel 02120 * corresponds to a bit. 02121 */ 02122 if (data[0]) { 02123 /* Check if requested ports are configured for output */ 02124 if ((s->io_bits & data[0]) != data[0]) 02125 return -EIO; 02126 02127 s->state &= ~data[0]; 02128 s->state |= data[0] & data[1]; 02129 02130 /* Write out the new digital output lines */ 02131 02132 DEBIwrite(dev, diopriv->WRDOut, s->state); 02133 } 02134 data[1] = DEBIread(dev, diopriv->RDDIn); 02135 02136 return 2; 02137 } 02138 02139 static int s626_dio_insn_config(comedi_device * dev, comedi_subdevice * s, 02140 comedi_insn * insn, lsampl_t * data) 02141 { 02142 02143 switch (data[0]) { 02144 case INSN_CONFIG_DIO_QUERY: 02145 data[1] = 02146 (s->io_bits & (1 << CR_CHAN(insn-> 02147 chanspec))) ? COMEDI_OUTPUT : 02148 COMEDI_INPUT; 02149 return insn->n; 02150 break; 02151 case COMEDI_INPUT: 02152 s->io_bits &= ~(1 << CR_CHAN(insn->chanspec)); 02153 break; 02154 case COMEDI_OUTPUT: 02155 s->io_bits |= 1 << CR_CHAN(insn->chanspec); 02156 break; 02157 default: 02158 return -EINVAL; 02159 break; 02160 } 02161 DEBIwrite(dev, diopriv->WRDOut, s->io_bits); 02162 02163 return 1; 02164 } 02165 02166 static int s626_dio_set_irq(comedi_device * dev, unsigned int chan) 02167 { 02168 unsigned int group; 02169 unsigned int bitmask; 02170 unsigned int status; 02171 02172 //select dio bank 02173 group = chan / 16; 02174 bitmask = 1 << (chan - (16 * group)); 02175 DEBUG("s626_dio_set_irq: enable interrupt on dio channel %d group %d\n", 02176 chan - (16 * group), group); 02177 02178 //set channel to capture positive edge 02179 status = DEBIread(dev, 02180 ((dio_private *) (dev->subdevices + 2 + 02181 group)->private)->RDEdgSel); 02182 DEBIwrite(dev, 02183 ((dio_private *) (dev->subdevices + 2 + 02184 group)->private)->WREdgSel, bitmask | status); 02185 02186 //enable interrupt on selected channel 02187 status = DEBIread(dev, 02188 ((dio_private *) (dev->subdevices + 2 + 02189 group)->private)->RDIntSel); 02190 DEBIwrite(dev, 02191 ((dio_private *) (dev->subdevices + 2 + 02192 group)->private)->WRIntSel, bitmask | status); 02193 02194 //enable edge capture write command 02195 DEBIwrite(dev, LP_MISC1, MISC1_EDCAP); 02196 02197 //enable edge capture on selected channel 02198 status = DEBIread(dev, 02199 ((dio_private *) (dev->subdevices + 2 + 02200 group)->private)->RDCapSel); 02201 DEBIwrite(dev, 02202 ((dio_private *) (dev->subdevices + 2 + 02203 group)->private)->WRCapSel, bitmask | status); 02204 02205 return 0; 02206 } 02207 02208 static int s626_dio_reset_irq(comedi_device * dev, unsigned int group, 02209 unsigned int mask) 02210 { 02211 DEBUG("s626_dio_reset_irq: disable interrupt on dio channel %d group %d\n", mask, group); 02212 02213 //disable edge capture write command 02214 DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP); 02215 02216 //enable edge capture on selected channel 02217 DEBIwrite(dev, 02218 ((dio_private *) (dev->subdevices + 2 + 02219 group)->private)->WRCapSel, mask); 02220 02221 return 0; 02222 } 02223 02224 static int s626_dio_clear_irq(comedi_device * dev) 02225 { 02226 unsigned int group; 02227 02228 //disable edge capture write command 02229 DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP); 02230 02231 for (group = 0; group < S626_DIO_BANKS; group++) { 02232 //clear pending events and interrupt 02233 DEBIwrite(dev, 02234 ((dio_private *) (dev->subdevices + 2 + 02235 group)->private)->WRCapSel, 0xffff); 02236 } 02237 02238 return 0; 02239 } 02240 02241 /* Now this function initializes the value of the counter (data[0]) 02242 and set the subdevice. To complete with trigger and interrupt 02243 configuration */ 02244 static int s626_enc_insn_config(comedi_device * dev, comedi_subdevice * s, 02245 comedi_insn * insn, lsampl_t * data) 02246 { 02247 uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) | // Preload upon 02248 // index. 02249 (INDXSRC_SOFT << BF_INDXSRC) | // Disable hardware index. 02250 (CLKSRC_COUNTER << BF_CLKSRC) | // Operating mode is Counter. 02251 (CLKPOL_POS << BF_CLKPOL) | // Active high clock. 02252 //( CNTDIR_UP << BF_CLKPOL ) | // Count direction is Down. 02253 (CLKMULT_1X << BF_CLKMULT) | // Clock multiplier is 1x. 02254 (CLKENAB_INDEX << BF_CLKENAB); 02255 /* uint16_t DisableIntSrc=TRUE; */ 02256 // uint32_t Preloadvalue; //Counter initial value 02257 uint16_t valueSrclatch = LATCHSRC_AB_READ; 02258 uint16_t enab = CLKENAB_ALWAYS; 02259 enc_private *k = &encpriv[CR_CHAN(insn->chanspec)]; 02260 02261 DEBUG("s626_enc_insn_config: encoder config\n"); 02262 02263 // (data==NULL) ? (Preloadvalue=0) : (Preloadvalue=data[0]); 02264 02265 k->SetMode(dev, k, Setup, TRUE); 02266 Preload(dev, k, *(insn->data)); 02267 k->PulseIndex(dev, k); 02268 SetLatchSource(dev, k, valueSrclatch); 02269 k->SetEnable(dev, k, (uint16_t) (enab != 0)); 02270 02271 return insn->n; 02272 } 02273 02274 static int s626_enc_insn_read(comedi_device * dev, comedi_subdevice * s, 02275 comedi_insn * insn, lsampl_t * data) 02276 { 02277 02278 int n; 02279 enc_private *k = &encpriv[CR_CHAN(insn->chanspec)]; 02280 02281 DEBUG("s626_enc_insn_read: encoder read channel %d \n", 02282 CR_CHAN(insn->chanspec)); 02283 02284 for (n = 0; n < insn->n; n++) 02285 data[n] = ReadLatch(dev, k); 02286 02287 DEBUG("s626_enc_insn_read: encoder sample %d\n", data[n]); 02288 02289 return n; 02290 } 02291 02292 static int s626_enc_insn_write(comedi_device * dev, comedi_subdevice * s, 02293 comedi_insn * insn, lsampl_t * data) 02294 { 02295 02296 enc_private *k = &encpriv[CR_CHAN(insn->chanspec)]; 02297 02298 DEBUG("s626_enc_insn_write: encoder write channel %d \n", 02299 CR_CHAN(insn->chanspec)); 02300 02301 // Set the preload register 02302 Preload(dev, k, data[0]); 02303 02304 // Software index pulse forces the preload register to load 02305 // into the counter 02306 k->SetLoadTrig(dev, k, 0); 02307 k->PulseIndex(dev, k); 02308 k->SetLoadTrig(dev, k, 2); 02309 02310 DEBUG("s626_enc_insn_write: End encoder write\n"); 02311 02312 return 1; 02313 } 02314 02315 static void s626_timer_load(comedi_device * dev, enc_private * k, int tick) 02316 { 02317 uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) | // Preload upon 02318 // index. 02319 (INDXSRC_SOFT << BF_INDXSRC) | // Disable hardware index. 02320 (CLKSRC_TIMER << BF_CLKSRC) | // Operating mode is Timer. 02321 (CLKPOL_POS << BF_CLKPOL) | // Active high clock. 02322 (CNTDIR_DOWN << BF_CLKPOL) | // Count direction is Down. 02323 (CLKMULT_1X << BF_CLKMULT) | // Clock multiplier is 1x. 02324 (CLKENAB_INDEX << BF_CLKENAB); 02325 uint16_t valueSrclatch = LATCHSRC_A_INDXA; 02326 // uint16_t enab=CLKENAB_ALWAYS; 02327 02328 k->SetMode(dev, k, Setup, FALSE); 02329 02330 // Set the preload register 02331 Preload(dev, k, tick); 02332 02333 // Software index pulse forces the preload register to load 02334 // into the counter 02335 k->SetLoadTrig(dev, k, 0); 02336 k->PulseIndex(dev, k); 02337 02338 //set reload on counter overflow 02339 k->SetLoadTrig(dev, k, 1); 02340 02341 //set interrupt on overflow 02342 k->SetIntSrc(dev, k, INTSRC_OVER); 02343 02344 SetLatchSource(dev, k, valueSrclatch); 02345 // k->SetEnable(dev,k,(uint16_t)(enab != 0)); 02346 } 02347 02351 02352 // Slot 0 base settings. 02353 #define VECT0 ( XSD2 | RSD3 | SIB_A2 ) // Slot 0 always shifts in 02354 // 0xFF and store it to 02355 // FB_BUFFER2. 02356 02357 // TrimDac LogicalChan-to-PhysicalChan mapping table. 02358 static uint8_t trimchan[] = { 10, 9, 8, 3, 2, 7, 6, 1, 0, 5, 4 }; 02359 02360 // TrimDac LogicalChan-to-EepromAdrs mapping table. 02361 static uint8_t trimadrs[] = 02362 { 0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63 }; 02363 02364 static void LoadTrimDACs(comedi_device * dev) 02365 { 02366 register uint8_t i; 02367 02368 // Copy TrimDac setpoint values from EEPROM to TrimDacs. 02369 for (i = 0; i < (sizeof(trimchan) / sizeof(trimchan[0])); i++) 02370 WriteTrimDAC(dev, i, I2Cread(dev, trimadrs[i])); 02371 } 02372 02373 static void WriteTrimDAC(comedi_device * dev, uint8_t LogicalChan, 02374 uint8_t DacData) 02375 { 02376 uint32_t chan; 02377 02378 // Save the new setpoint in case the application needs to read it back later. 02379 devpriv->TrimSetpoint[LogicalChan] = (uint8_t) DacData; 02380 02381 // Map logical channel number to physical channel number. 02382 chan = (uint32_t) trimchan[LogicalChan]; 02383 02384 // Set up TSL2 records for TrimDac write operation. All slots shift 02385 // 0xFF in from pulled-up SD3 so that the end of the slot sequence 02386 // can be detected. 02387 SETVECT(2, XSD2 | XFIFO_1 | WS3); // Slot 2: Send high uint8_t 02388 // to target TrimDac. 02389 SETVECT(3, XSD2 | XFIFO_0 | WS3); // Slot 3: Send low uint8_t to 02390 // target TrimDac. 02391 SETVECT(4, XSD2 | XFIFO_3 | WS1); // Slot 4: Send NOP high 02392 // uint8_t to DAC0 to keep 02393 // clock running. 02394 SETVECT(5, XSD2 | XFIFO_2 | WS1 | EOS); // Slot 5: Send NOP low 02395 // uint8_t to DAC0. 02396 02397 // Construct and transmit target DAC's serial packet: ( 0000 AAAA 02398 // ),( DDDD DDDD ),( 0x00 ),( 0x00 ) where A<3:0> is the DAC 02399 // channel's address, and D<7:0> is the DAC setpoint. Append a WORD 02400 // value (that writes a channel 0 NOP command to a non-existent main 02401 // DAC channel) that serves to keep the clock running after the 02402 // packet has been sent to the target DAC. 02403 02404 SendDAC(dev, ((uint32_t) chan << 8) // Address the DAC channel 02405 // within the trimdac device. 02406 | (uint32_t) DacData); // Include DAC setpoint data. 02407 } 02408 02412 02414 // Read uint8_t from EEPROM. 02415 02416 static uint8_t I2Cread(comedi_device * dev, uint8_t addr) 02417 { 02418 uint8_t rtnval; 02419 02420 // Send EEPROM target address. 02421 if (I2Chandshake(dev, I2C_B2(I2C_ATTRSTART, I2CW) // Byte2 = I2C 02422 // command: 02423 // write to 02424 // I2C EEPROM 02425 // device. 02426 | I2C_B1(I2C_ATTRSTOP, addr) // Byte1 = EEPROM 02427 // internal target 02428 // address. 02429 | I2C_B0(I2C_ATTRNOP, 0))) // Byte0 = Not 02430 // sent. 02431 { 02432 // Abort function and declare error if handshake failed. 02433 DEBUG("I2Cread: error handshake I2Cread a\n"); 02434 return 0; 02435 } 02436 // Execute EEPROM read. 02437 if (I2Chandshake(dev, I2C_B2(I2C_ATTRSTART, I2CR) // Byte2 = I2C 02438 // command: read 02439 // from I2C EEPROM 02440 // device. 02441 | I2C_B1(I2C_ATTRSTOP, 0) // Byte1 receives 02442 // uint8_t from 02443 // EEPROM. 02444 | I2C_B0(I2C_ATTRNOP, 0))) // Byte0 = Not 02445 // sent. 02446 { 02447 // Abort function and declare error if handshake failed. 02448 DEBUG("I2Cread: error handshake I2Cread b\n"); 02449 return 0; 02450 } 02451 // Return copy of EEPROM value. 02452 rtnval = (uint8_t) (RR7146(P_I2CCTRL) >> 16); 02453 return rtnval; 02454 } 02455 02456 static uint32_t I2Chandshake(comedi_device * dev, uint32_t val) 02457 { 02458 // Write I2C command to I2C Transfer Control shadow register. 02459 WR7146(P_I2CCTRL, val); 02460 02461 // Upload I2C shadow registers into working registers and wait for 02462 // upload confirmation. 02463 02464 MC_ENABLE(P_MC2, MC2_UPLD_IIC); 02465 while (!MC_TEST(P_MC2, MC2_UPLD_IIC)) ; 02466 02467 // Wait until I2C bus transfer is finished or an error occurs. 02468 while ((RR7146(P_I2CCTRL) & (I2C_BUSY | I2C_ERR)) == I2C_BUSY) ; 02469 02470 // Return non-zero if I2C error occured. 02471 return RR7146(P_I2CCTRL) & I2C_ERR; 02472 02473 } 02474 02475 // Private helper function: Write setpoint to an application DAC channel. 02476 02477 static void SetDAC(comedi_device * dev, uint16_t chan, short dacdata) 02478 { 02479 register uint16_t signmask; 02480 register uint32_t WSImage; 02481 02482 // Adjust DAC data polarity and set up Polarity Control Register 02483 // image. 02484 signmask = 1 << chan; 02485 if (dacdata < 0) { 02486 dacdata = -dacdata; 02487 devpriv->Dacpol |= signmask; 02488 } else 02489 devpriv->Dacpol &= ~signmask; 02490 02491 // Limit DAC setpoint value to valid range. 02492 if ((uint16_t) dacdata > 0x1FFF) 02493 dacdata = 0x1FFF; 02494 02495 // Set up TSL2 records (aka "vectors") for DAC update. Vectors V2 02496 // and V3 transmit the setpoint to the target DAC. V4 and V5 send 02497 // data to a non-existent TrimDac channel just to keep the clock 02498 // running after sending data to the target DAC. This is necessary 02499 // to eliminate the clock glitch that would otherwise occur at the 02500 // end of the target DAC's serial data stream. When the sequence 02501 // restarts at V0 (after executing V5), the gate array automatically 02502 // disables gating for the DAC clock and all DAC chip selects. 02503 WSImage = (chan & 2) ? WS1 : WS2; // Choose DAC chip select to 02504 // be asserted. 02505 SETVECT(2, XSD2 | XFIFO_1 | WSImage); // Slot 2: Transmit high 02506 // data byte to target DAC. 02507 SETVECT(3, XSD2 | XFIFO_0 | WSImage); // Slot 3: Transmit low data 02508 // byte to target DAC. 02509 SETVECT(4, XSD2 | XFIFO_3 | WS3); // Slot 4: Transmit to 02510 // non-existent TrimDac 02511 // channel to keep clock 02512 SETVECT(5, XSD2 | XFIFO_2 | WS3 | EOS); // Slot 5: running after 02513 // writing target DAC's 02514 // low data byte. 02515 02516 // Construct and transmit target DAC's serial packet: ( A10D DDDD 02517 // ),( DDDD DDDD ),( 0x0F ),( 0x00 ) where A is chan<0>, and D<12:0> 02518 // is the DAC setpoint. Append a WORD value (that writes to a 02519 // non-existent TrimDac channel) that serves to keep the clock 02520 // running after the packet has been sent to the target DAC. 02521 SendDAC(dev, 0x0F000000 //Continue clock after target DAC 02522 //data (write to non-existent 02523 //trimdac). 02524 | 0x00004000 // Address the two main dual-DAC 02525 // devices (TSL's chip select enables 02526 // target device). 02527 | ((uint32_t) (chan & 1) << 15) // Address the DAC 02528 // channel within the 02529 // device. 02530 | (uint32_t) dacdata); // Include DAC setpoint data. 02531 02532 } 02533 02535 // Private helper function: Transmit serial data to DAC via Audio 02536 // channel 2. Assumes: (1) TSL2 slot records initialized, and (2) 02537 // Dacpol contains valid target image. 02538 02539 static void SendDAC(comedi_device * dev, uint32_t val) 02540 { 02541 02542 // START THE SERIAL CLOCK RUNNING ------------- 02543 02544 // Assert DAC polarity control and enable gating of DAC serial clock 02545 // and audio bit stream signals. At this point in time we must be 02546 // assured of being in time slot 0. If we are not in slot 0, the 02547 // serial clock and audio stream signals will be disabled; this is 02548 // because the following DEBIwrite statement (which enables signals 02549 // to be passed through the gate array) would execute before the 02550 // trailing edge of WS1/WS3 (which turns off the signals), thus 02551 // causing the signals to be inactive during the DAC write. 02552 DEBIwrite(dev, LP_DACPOL, devpriv->Dacpol); 02553 02554 // TRANSFER OUTPUT DWORD VALUE INTO A2'S OUTPUT FIFO ---------------- 02555 02556 // Copy DAC setpoint value to DAC's output DMA buffer. 02557 02558 //WR7146( (uint32_t)devpriv->pDacWBuf, val ); 02559 *devpriv->pDacWBuf = val; 02560 02561 // enab the output DMA transfer. This will cause the DMAC to copy 02562 // the DAC's data value to A2's output FIFO. The DMA transfer will 02563 // then immediately terminate because the protection address is 02564 // reached upon transfer of the first DWORD value. 02565 MC_ENABLE(P_MC1, MC1_A2OUT); 02566 02567 // While the DMA transfer is executing ... 02568 02569 // Reset Audio2 output FIFO's underflow flag (along with any other 02570 // FIFO underflow/overflow flags). When set, this flag will 02571 // indicate that we have emerged from slot 0. 02572 WR7146(P_ISR, ISR_AFOU); 02573 02574 // Wait for the DMA transfer to finish so that there will be data 02575 // available in the FIFO when time slot 1 tries to transfer a DWORD 02576 // from the FIFO to the output buffer register. We test for DMA 02577 // Done by polling the DMAC enable flag; this flag is automatically 02578 // cleared when the transfer has finished. 02579 while ((RR7146(P_MC1) & MC1_A2OUT) != 0) ; 02580 02581 // START THE OUTPUT STREAM TO THE TARGET DAC -------------------- 02582 02583 // FIFO data is now available, so we enable execution of time slots 02584 // 1 and higher by clearing the EOS flag in slot 0. Note that SD3 02585 // will be shifted in and stored in FB_BUFFER2 for end-of-slot-list 02586 // detection. 02587 SETVECT(0, XSD2 | RSD3 | SIB_A2); 02588 02589 // Wait for slot 1 to execute to ensure that the Packet will be 02590 // transmitted. This is detected by polling the Audio2 output FIFO 02591 // underflow flag, which will be set when slot 1 execution has 02592 // finished transferring the DAC's data DWORD from the output FIFO 02593 // to the output buffer register. 02594 while ((RR7146(P_SSR) & SSR_AF2_OUT) == 0) ; 02595 02596 // Set up to trap execution at slot 0 when the TSL sequencer cycles 02597 // back to slot 0 after executing the EOS in slot 5. Also, 02598 // simultaneously shift out and in the 0x00 that is ALWAYS the value 02599 // stored in the last byte to be shifted out of the FIFO's DWORD 02600 // buffer register. 02601 SETVECT(0, XSD2 | XFIFO_2 | RSD2 | SIB_A2 | EOS); 02602 02603 // WAIT FOR THE TRANSACTION TO FINISH ----------------------- 02604 02605 // Wait for the TSL to finish executing all time slots before 02606 // exiting this function. We must do this so that the next DAC 02607 // write doesn't start, thereby enabling clock/chip select signals: 02608 // 1. Before the TSL sequence cycles back to slot 0, which disables 02609 // the clock/cs signal gating and traps slot // list execution. If 02610 // we have not yet finished slot 5 then the clock/cs signals are 02611 // still gated and we have // not finished transmitting the stream. 02612 // 2. While slots 2-5 are executing due to a late slot 0 trap. In 02613 // this case, the slot sequence is currently // repeating, but with 02614 // clock/cs signals disabled. We must wait for slot 0 to trap 02615 // execution before setting // up the next DAC setpoint DMA transfer 02616 // and enabling the clock/cs signals. To detect the end of slot 5, 02617 // we test for the FB_BUFFER2 MSB contents to be equal to 0xFF. If 02618 // the TSL has not yet finished executing slot 5 ... 02619 if ((RR7146(P_FB_BUFFER2) & 0xFF000000) != 0) { 02620 // The trap was set on time and we are still executing somewhere 02621 // in slots 2-5, so we now wait for slot 0 to execute and trap 02622 // TSL execution. This is detected when FB_BUFFER2 MSB changes 02623 // from 0xFF to 0x00, which slot 0 causes to happen by shifting 02624 // out/in on SD2 the 0x00 that is always referenced by slot 5. 02625 while ((RR7146(P_FB_BUFFER2) & 0xFF000000) != 0) ; 02626 } 02627 // Either (1) we were too late setting the slot 0 trap; the TSL 02628 // sequencer restarted slot 0 before we could set the EOS trap flag, 02629 // or (2) we were not late and execution is now trapped at slot 0. 02630 // In either case, we must now change slot 0 so that it will store 02631 // value 0xFF (instead of 0x00) to FB_BUFFER2 next time it executes. 02632 // In order to do this, we reprogram slot 0 so that it will shift in 02633 // SD3, which is driven only by a pull-up resistor. 02634 SETVECT(0, RSD3 | SIB_A2 | EOS); 02635 02636 // Wait for slot 0 to execute, at which time the TSL is setup for 02637 // the next DAC write. This is detected when FB_BUFFER2 MSB changes 02638 // from 0x00 to 0xFF. 02639 while ((RR7146(P_FB_BUFFER2) & 0xFF000000) == 0) ; 02640 } 02641 02642 static void WriteMISC2(comedi_device * dev, uint16_t NewImage) 02643 { 02644 DEBIwrite(dev, LP_MISC1, MISC1_WENABLE); // enab writes to 02645 // MISC2 register. 02646 DEBIwrite(dev, LP_WRMISC2, NewImage); // Write new image to MISC2. 02647 DEBIwrite(dev, LP_MISC1, MISC1_WDISABLE); // Disable writes to MISC2. 02648 } 02649 02651 // Initialize the DEBI interface for all transfers. 02652 02653 static uint16_t DEBIread(comedi_device * dev, uint16_t addr) 02654 { 02655 uint16_t retval; 02656 02657 // Set up DEBI control register value in shadow RAM. 02658 WR7146(P_DEBICMD, DEBI_CMD_RDWORD | addr); 02659 02660 // Execute the DEBI transfer. 02661 DEBItransfer(dev); 02662 02663 // Fetch target register value. 02664 retval = (uint16_t) RR7146(P_DEBIAD); 02665 02666 // Return register value. 02667 return retval; 02668 } 02669 02670 // Execute a DEBI transfer. This must be called from within a 02671 // critical section. 02672 static void DEBItransfer(comedi_device * dev) 02673 { 02674 // Initiate upload of shadow RAM to DEBI control register. 02675 MC_ENABLE(P_MC2, MC2_UPLD_DEBI); 02676 02677 // Wait for completion of upload from shadow RAM to DEBI control 02678 // register. 02679 while (!MC_TEST(P_MC2, MC2_UPLD_DEBI)) ; 02680 02681 // Wait until DEBI transfer is done. 02682 while (RR7146(P_PSR) & PSR_DEBI_S) ; 02683 } 02684 02685 // Write a value to a gate array register. 02686 static void DEBIwrite(comedi_device * dev, uint16_t addr, uint16_t wdata) 02687 { 02688 02689 // Set up DEBI control register value in shadow RAM. 02690 WR7146(P_DEBICMD, DEBI_CMD_WRWORD | addr); 02691 WR7146(P_DEBIAD, wdata); 02692 02693 // Execute the DEBI transfer. 02694 DEBItransfer(dev); 02695 } 02696 02698 // Replace the specified bits in a gate array register. Imports: mask 02699 // specifies bits that are to be preserved, wdata is new value to be 02700 // or'd with the masked original. 02701 static void DEBIreplace(comedi_device * dev, uint16_t addr, uint16_t mask, 02702 uint16_t wdata) 02703 { 02704 02705 // Copy target gate array register into P_DEBIAD register. 02706 WR7146(P_DEBICMD, DEBI_CMD_RDWORD | addr); // Set up DEBI control 02707 // reg value in shadow 02708 // RAM. 02709 DEBItransfer(dev); // Execute the DEBI 02710 // Read transfer. 02711 02712 // Write back the modified image. 02713 WR7146(P_DEBICMD, DEBI_CMD_WRWORD | addr); // Set up DEBI control 02714 // reg value in shadow 02715 // RAM. 02716 02717 WR7146(P_DEBIAD, wdata | ((uint16_t) RR7146(P_DEBIAD) & mask)); // Modify the register image. 02718 DEBItransfer(dev); // Execute the DEBI Write transfer. 02719 } 02720 02721 static void CloseDMAB(comedi_device * dev, DMABUF * pdma, size_t bsize) 02722 { 02723 void *vbptr; 02724 dma_addr_t vpptr; 02725 02726 DEBUG("CloseDMAB: Entering S626DRV_CloseDMAB():\n"); 02727 if (pdma == NULL) 02728 return; 02729 //find the matching allocation from the board struct 02730 02731 vbptr = pdma->LogicalBase; 02732 vpptr = pdma->PhysicalBase; 02733 if (vbptr) { 02734 pci_free_consistent(devpriv->pdev, bsize, vbptr, vpptr); 02735 pdma->LogicalBase = 0; 02736 pdma->PhysicalBase = 0; 02737 02738 DEBUG("CloseDMAB(): Logical=%p, bsize=%d, Physical=0x%x\n", 02739 vbptr, bsize, (uint32_t) vpptr); 02740 } 02741 } 02742 02746 // All counter functions address a specific counter by means of the 02747 // "Counter" argument, which is a logical counter number. The Counter 02748 // argument may have any of the following legal values: 0=0A, 1=1A, 02749 // 2=2A, 3=0B, 4=1B, 5=2B. 02751 02752 // Forward declarations for functions that are common to both A and B 02753 // counters: 02754 02758 02760 // Read a counter's output latch. 02761 02762 static uint32_t ReadLatch(comedi_device * dev, enc_private * k) 02763 { 02764 register uint32_t value; 02765 //DEBUG FIXME DEBUG("ReadLatch: Read Latch enter\n"); 02766 02767 // Latch counts and fetch LSW of latched counts value. 02768 value = (uint32_t) DEBIread(dev, k->MyLatchLsw); 02769 02770 // Fetch MSW of latched counts and combine with LSW. 02771 value |= ((uint32_t) DEBIread(dev, k->MyLatchLsw + 2) << 16); 02772 02773 // DEBUG FIXME DEBUG("ReadLatch: Read Latch exit\n"); 02774 02775 // Return latched counts. 02776 return value; 02777 } 02778 02780 // Reset a counter's index and overflow event capture flags. 02781 02782 static void ResetCapFlags_A(comedi_device * dev, enc_private * k) 02783 { 02784 DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL), 02785 CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A); 02786 } 02787 02788 static void ResetCapFlags_B(comedi_device * dev, enc_private * k) 02789 { 02790 DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL), 02791 CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B); 02792 } 02793 02795 // Return counter setup in a format (COUNTER_SETUP) that is consistent 02796 // for both A and B counters. 02797 02798 static uint16_t GetMode_A(comedi_device * dev, enc_private * k) 02799 { 02800 register uint16_t cra; 02801 register uint16_t crb; 02802 register uint16_t setup; 02803 02804 // Fetch CRA and CRB register images. 02805 cra = DEBIread(dev, k->MyCRA); 02806 crb = DEBIread(dev, k->MyCRB); 02807 02808 // Populate the standardized counter setup bit fields. Note: 02809 // IndexSrc is restricted to ENC_X or IndxPol. 02810 setup = ((cra & STDMSK_LOADSRC) // LoadSrc = LoadSrcA. 02811 | ((crb << (STDBIT_LATCHSRC - CRBBIT_LATCHSRC)) & STDMSK_LATCHSRC) // LatchSrc = LatchSrcA. 02812 | ((cra << (STDBIT_INTSRC - CRABIT_INTSRC_A)) & STDMSK_INTSRC) // IntSrc = IntSrcA. 02813 | ((cra << (STDBIT_INDXSRC - (CRABIT_INDXSRC_A + 1))) & STDMSK_INDXSRC) // IndxSrc = IndxSrcA<1>. 02814 | ((cra >> (CRABIT_INDXPOL_A - STDBIT_INDXPOL)) & STDMSK_INDXPOL) // IndxPol = IndxPolA. 02815 | ((crb >> (CRBBIT_CLKENAB_A - STDBIT_CLKENAB)) & STDMSK_CLKENAB)); // ClkEnab = ClkEnabA. 02816 02817 // Adjust mode-dependent parameters. 02818 if (cra & (2 << CRABIT_CLKSRC_A)) // If Timer mode (ClkSrcA<1> == 1): 02819 setup |= ((CLKSRC_TIMER << STDBIT_CLKSRC) // Indicate Timer mode. 02820 | ((cra << (STDBIT_CLKPOL - CRABIT_CLKSRC_A)) & STDMSK_CLKPOL) // Set ClkPol to indicate count direction (ClkSrcA<0>). 02821 | (MULT_X1 << STDBIT_CLKMULT)); // ClkMult must be 1x in Timer mode. 02822 02823 else // If Counter mode (ClkSrcA<1> == 0): 02824 setup |= ((CLKSRC_COUNTER << STDBIT_CLKSRC) // Indicate Counter mode. 02825 | ((cra >> (CRABIT_CLKPOL_A - STDBIT_CLKPOL)) & STDMSK_CLKPOL) // Pass through ClkPol. 02826 | (((cra & CRAMSK_CLKMULT_A) == (MULT_X0 << CRABIT_CLKMULT_A)) ? // Force ClkMult to 1x if not legal, else pass through. 02827 (MULT_X1 << STDBIT_CLKMULT) : 02828 ((cra >> (CRABIT_CLKMULT_A - 02829 STDBIT_CLKMULT)) & 02830 STDMSK_CLKMULT))); 02831 02832 // Return adjusted counter setup. 02833 return setup; 02834 } 02835 02836 static uint16_t GetMode_B(comedi_device * dev, enc_private * k) 02837 { 02838 register uint16_t cra; 02839 register uint16_t crb; 02840 register uint16_t setup; 02841 02842 // Fetch CRA and CRB register images. 02843 cra = DEBIread(dev, k->MyCRA); 02844 crb = DEBIread(dev, k->MyCRB); 02845 02846 // Populate the standardized counter setup bit fields. Note: 02847 // IndexSrc is restricted to ENC_X or IndxPol. 02848 setup = (((crb << (STDBIT_INTSRC - CRBBIT_INTSRC_B)) & STDMSK_INTSRC) // IntSrc = IntSrcB. 02849 | ((crb << (STDBIT_LATCHSRC - CRBBIT_LATCHSRC)) & STDMSK_LATCHSRC) // LatchSrc = LatchSrcB. 02850 | ((crb << (STDBIT_LOADSRC - CRBBIT_LOADSRC_B)) & STDMSK_LOADSRC) // LoadSrc = LoadSrcB. 02851 | ((crb << (STDBIT_INDXPOL - CRBBIT_INDXPOL_B)) & STDMSK_INDXPOL) // IndxPol = IndxPolB. 02852 | ((crb >> (CRBBIT_CLKENAB_B - STDBIT_CLKENAB)) & STDMSK_CLKENAB) // ClkEnab = ClkEnabB. 02853 | ((cra >> ((CRABIT_INDXSRC_B + 1) - STDBIT_INDXSRC)) & STDMSK_INDXSRC)); // IndxSrc = IndxSrcB<1>. 02854 02855 // Adjust mode-dependent parameters. 02856 if ((crb & CRBMSK_CLKMULT_B) == (MULT_X0 << CRBBIT_CLKMULT_B)) // If Extender mode (ClkMultB == MULT_X0): 02857 setup |= ((CLKSRC_EXTENDER << STDBIT_CLKSRC) // Indicate Extender mode. 02858 | (MULT_X1 << STDBIT_CLKMULT) // Indicate multiplier is 1x. 02859 | ((cra >> (CRABIT_CLKSRC_B - STDBIT_CLKPOL)) & STDMSK_CLKPOL)); // Set ClkPol equal to Timer count direction (ClkSrcB<0>). 02860 02861 else if (cra & (2 << CRABIT_CLKSRC_B)) // If Timer mode (ClkSrcB<1> == 1): 02862 setup |= ((CLKSRC_TIMER << STDBIT_CLKSRC) // Indicate Timer mode. 02863 | (MULT_X1 << STDBIT_CLKMULT) // Indicate multiplier is 1x. 02864 | ((cra >> (CRABIT_CLKSRC_B - STDBIT_CLKPOL)) & STDMSK_CLKPOL)); // Set ClkPol equal to Timer count direction (ClkSrcB<0>). 02865 02866 else // If Counter mode (ClkSrcB<1> == 0): 02867 setup |= ((CLKSRC_COUNTER << STDBIT_CLKSRC) // Indicate Timer mode. 02868 | ((crb >> (CRBBIT_CLKMULT_B - STDBIT_CLKMULT)) & STDMSK_CLKMULT) // Clock multiplier is passed through. 02869 | ((crb << (STDBIT_CLKPOL - CRBBIT_CLKPOL_B)) & STDMSK_CLKPOL)); // Clock polarity is passed through. 02870 02871 // Return adjusted counter setup. 02872 return setup; 02873 } 02874 02876 // Set the operating mode for the specified counter. The setup 02877 // parameter is treated as a COUNTER_SETUP data type. The following 02878 // parameters are programmable (all other parms are ignored): ClkMult, 02879 // ClkPol, ClkEnab, IndexSrc, IndexPol, LoadSrc. 02880 02881 static void SetMode_A(comedi_device * dev, enc_private * k, uint16_t Setup, 02882 uint16_t DisableIntSrc) 02883 { 02884 register uint16_t cra; 02885 register uint16_t crb; 02886 register uint16_t setup = Setup; // Cache the Standard Setup. 02887 02888 // Initialize CRA and CRB images. 02889 cra = ((setup & CRAMSK_LOADSRC_A) // Preload trigger is passed through. 02890 | ((setup & STDMSK_INDXSRC) >> (STDBIT_INDXSRC - (CRABIT_INDXSRC_A + 1)))); // IndexSrc is restricted to ENC_X or IndxPol. 02891 02892 crb = (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A // Reset any pending CounterA event captures. 02893 | ((setup & STDMSK_CLKENAB) << (CRBBIT_CLKENAB_A - STDBIT_CLKENAB))); // Clock enable is passed through. 02894 02895 // Force IntSrc to Disabled if DisableIntSrc is asserted. 02896 if (!DisableIntSrc) 02897 cra |= ((setup & STDMSK_INTSRC) >> (STDBIT_INTSRC - 02898 CRABIT_INTSRC_A)); 02899 02900 // Populate all mode-dependent attributes of CRA & CRB images. 02901 switch ((setup & STDMSK_CLKSRC) >> STDBIT_CLKSRC) { 02902 case CLKSRC_EXTENDER: // Extender Mode: Force to Timer mode 02903 // (Extender valid only for B counters). 02904 02905 case CLKSRC_TIMER: // Timer Mode: 02906 cra |= ((2 << CRABIT_CLKSRC_A) // ClkSrcA<1> selects system clock 02907 | ((setup & STDMSK_CLKPOL) >> (STDBIT_CLKPOL - CRABIT_CLKSRC_A)) // with count direction (ClkSrcA<0>) obtained from ClkPol. 02908 | (1 << CRABIT_CLKPOL_A) // ClkPolA behaves as always-on clock enable. 02909 | (MULT_X1 << CRABIT_CLKMULT_A)); // ClkMult must be 1x. 02910 break; 02911 02912 default: // Counter Mode: 02913 cra |= (CLKSRC_COUNTER // Select ENC_C and ENC_D as clock/direction inputs. 02914 | ((setup & STDMSK_CLKPOL) << (CRABIT_CLKPOL_A - STDBIT_CLKPOL)) // Clock polarity is passed through. 02915 | (((setup & STDMSK_CLKMULT) == (MULT_X0 << STDBIT_CLKMULT)) ? // Force multiplier to x1 if not legal, otherwise pass through. 02916 (MULT_X1 << CRABIT_CLKMULT_A) : 02917 ((setup & STDMSK_CLKMULT) << (CRABIT_CLKMULT_A - 02918 STDBIT_CLKMULT)))); 02919 } 02920 02921 // Force positive index polarity if IndxSrc is software-driven only, 02922 // otherwise pass it through. 02923 if (~setup & STDMSK_INDXSRC) 02924 cra |= ((setup & STDMSK_INDXPOL) << (CRABIT_INDXPOL_A - 02925 STDBIT_INDXPOL)); 02926 02927 // If IntSrc has been forced to Disabled, update the MISC2 interrupt 02928 // enable mask to indicate the counter interrupt is disabled. 02929 if (DisableIntSrc) 02930 devpriv->CounterIntEnabs &= ~k->MyEventBits[3]; 02931 02932 // While retaining CounterB and LatchSrc configurations, program the 02933 // new counter operating mode. 02934 DEBIreplace(dev, k->MyCRA, CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B, cra); 02935 DEBIreplace(dev, k->MyCRB, 02936 (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A)), crb); 02937 } 02938 02939 static void SetMode_B(comedi_device * dev, enc_private * k, uint16_t Setup, 02940 uint16_t DisableIntSrc) 02941 { 02942 register uint16_t cra; 02943 register uint16_t crb; 02944 register uint16_t setup = Setup; // Cache the Standard Setup. 02945 02946 // Initialize CRA and CRB images. 02947 cra = ((setup & STDMSK_INDXSRC) << ((CRABIT_INDXSRC_B + 1) - STDBIT_INDXSRC)); // IndexSrc field is restricted to ENC_X or IndxPol. 02948 02949 crb = (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B // Reset event captures and disable interrupts. 02950 | ((setup & STDMSK_CLKENAB) << (CRBBIT_CLKENAB_B - STDBIT_CLKENAB)) // Clock enable is passed through. 02951 | ((setup & STDMSK_LOADSRC) >> (STDBIT_LOADSRC - CRBBIT_LOADSRC_B))); // Preload trigger source is passed through. 02952 02953 // Force IntSrc to Disabled if DisableIntSrc is asserted. 02954 if (!DisableIntSrc) 02955 crb |= ((setup & STDMSK_INTSRC) >> (STDBIT_INTSRC - 02956 CRBBIT_INTSRC_B)); 02957 02958 // Populate all mode-dependent attributes of CRA & CRB images. 02959 switch ((setup & STDMSK_CLKSRC) >> STDBIT_CLKSRC) { 02960 case CLKSRC_TIMER: // Timer Mode: 02961 cra |= ((2 << CRABIT_CLKSRC_B) // ClkSrcB<1> selects system clock 02962 | ((setup & STDMSK_CLKPOL) << (CRABIT_CLKSRC_B - STDBIT_CLKPOL))); // with direction (ClkSrcB<0>) obtained from ClkPol. 02963 crb |= ((1 << CRBBIT_CLKPOL_B) // ClkPolB behaves as always-on clock enable. 02964 | (MULT_X1 << CRBBIT_CLKMULT_B)); // ClkMultB must be 1x. 02965 break; 02966 02967 case CLKSRC_EXTENDER: // Extender Mode: 02968 cra |= ((2 << CRABIT_CLKSRC_B) // ClkSrcB source is OverflowA (same as "timer") 02969 | ((setup & STDMSK_CLKPOL) << (CRABIT_CLKSRC_B - STDBIT_CLKPOL))); // with direction obtained from ClkPol. 02970 crb |= ((1 << CRBBIT_CLKPOL_B) // ClkPolB controls IndexB -- always set to active. 02971 | (MULT_X0 << CRBBIT_CLKMULT_B)); // ClkMultB selects OverflowA as the clock source. 02972 break; 02973 02974 default: // Counter Mode: 02975 cra |= (CLKSRC_COUNTER << CRABIT_CLKSRC_B); // Select ENC_C and ENC_D as clock/direction inputs. 02976 crb |= (((setup & STDMSK_CLKPOL) >> (STDBIT_CLKPOL - CRBBIT_CLKPOL_B)) // ClkPol is passed through. 02977 | (((setup & STDMSK_CLKMULT) == (MULT_X0 << STDBIT_CLKMULT)) ? // Force ClkMult to x1 if not legal, otherwise pass through. 02978 (MULT_X1 << CRBBIT_CLKMULT_B) : 02979 ((setup & STDMSK_CLKMULT) << (CRBBIT_CLKMULT_B - 02980 STDBIT_CLKMULT)))); 02981 } 02982 02983 // Force positive index polarity if IndxSrc is software-driven only, 02984 // otherwise pass it through. 02985 if (~setup & STDMSK_INDXSRC) 02986 crb |= ((setup & STDMSK_INDXPOL) >> (STDBIT_INDXPOL - 02987 CRBBIT_INDXPOL_B)); 02988 02989 // If IntSrc has been forced to Disabled, update the MISC2 interrupt 02990 // enable mask to indicate the counter interrupt is disabled. 02991 if (DisableIntSrc) 02992 devpriv->CounterIntEnabs &= ~k->MyEventBits[3]; 02993 02994 // While retaining CounterA and LatchSrc configurations, program the 02995 // new counter operating mode. 02996 DEBIreplace(dev, k->MyCRA, 02997 (uint16_t) (~(CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B)), cra); 02998 DEBIreplace(dev, k->MyCRB, CRBMSK_CLKENAB_A | CRBMSK_LATCHSRC, crb); 02999 } 03000 03002 // Return/set a counter's enable. enab: 0=always enabled, 1=enabled by index. 03003 03004 static void SetEnable_A(comedi_device * dev, enc_private * k, uint16_t enab) 03005 { 03006 DEBUG("SetEnable_A: SetEnable_A enter 3541\n"); 03007 DEBIreplace(dev, k->MyCRB, 03008 (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A)), 03009 (uint16_t) (enab << CRBBIT_CLKENAB_A)); 03010 } 03011 03012 static void SetEnable_B(comedi_device * dev, enc_private * k, uint16_t enab) 03013 { 03014 DEBIreplace(dev, k->MyCRB, 03015 (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_B)), 03016 (uint16_t) (enab << CRBBIT_CLKENAB_B)); 03017 } 03018 03019 static uint16_t GetEnable_A(comedi_device * dev, enc_private * k) 03020 { 03021 return (DEBIread(dev, k->MyCRB) >> CRBBIT_CLKENAB_A) & 1; 03022 } 03023 03024 static uint16_t GetEnable_B(comedi_device * dev, enc_private * k) 03025 { 03026 return (DEBIread(dev, k->MyCRB) >> CRBBIT_CLKENAB_B) & 1; 03027 } 03028 03030 // Return/set a counter pair's latch trigger source. 0: On read 03031 // access, 1: A index latches A, 2: B index latches B, 3: A overflow 03032 // latches B. 03033 03034 static void SetLatchSource(comedi_device * dev, enc_private * k, uint16_t value) 03035 { 03036 DEBUG("SetLatchSource: SetLatchSource enter 3550 \n"); 03037 DEBIreplace(dev, k->MyCRB, 03038 (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_LATCHSRC)), 03039 (uint16_t) (value << CRBBIT_LATCHSRC)); 03040 03041 DEBUG("SetLatchSource: SetLatchSource exit \n"); 03042 } 03043 03044 /* static uint16_t GetLatchSource(comedi_device *dev, enc_private *k ) */ 03045 /* { */ 03046 /* return ( DEBIread( dev, k->MyCRB) >> CRBBIT_LATCHSRC ) & 3; */ 03047 /* } */ 03048 03050 // Return/set the event that will trigger transfer of the preload 03051 // register into the counter. 0=ThisCntr_Index, 1=ThisCntr_Overflow, 03052 // 2=OverflowA (B counters only), 3=disabled. 03053 03054 static void SetLoadTrig_A(comedi_device * dev, enc_private * k, uint16_t Trig) 03055 { 03056 DEBIreplace(dev, k->MyCRA, (uint16_t) (~CRAMSK_LOADSRC_A), 03057 (uint16_t) (Trig << CRABIT_LOADSRC_A)); 03058 } 03059 03060 static void SetLoadTrig_B(comedi_device * dev, enc_private * k, uint16_t Trig) 03061 { 03062 DEBIreplace(dev, k->MyCRB, 03063 (uint16_t) (~(CRBMSK_LOADSRC_B | CRBMSK_INTCTRL)), 03064 (uint16_t) (Trig << CRBBIT_LOADSRC_B)); 03065 } 03066 03067 static uint16_t GetLoadTrig_A(comedi_device * dev, enc_private * k) 03068 { 03069 return (DEBIread(dev, k->MyCRA) >> CRABIT_LOADSRC_A) & 3; 03070 } 03071 03072 static uint16_t GetLoadTrig_B(comedi_device * dev, enc_private * k) 03073 { 03074 return (DEBIread(dev, k->MyCRB) >> CRBBIT_LOADSRC_B) & 3; 03075 } 03076 03078 // Return/set counter interrupt source and clear any captured 03079 // index/overflow events. IntSource: 0=Disabled, 1=OverflowOnly, 03080 // 2=IndexOnly, 3=IndexAndOverflow. 03081 03082 static void SetIntSrc_A(comedi_device * dev, enc_private * k, 03083 uint16_t IntSource) 03084 { 03085 // Reset any pending counter overflow or index captures. 03086 DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL), 03087 CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A); 03088 03089 // Program counter interrupt source. 03090 DEBIreplace(dev, k->MyCRA, ~CRAMSK_INTSRC_A, 03091 (uint16_t) (IntSource << CRABIT_INTSRC_A)); 03092 03093 // Update MISC2 interrupt enable mask. 03094 devpriv->CounterIntEnabs = 03095 (devpriv->CounterIntEnabs & ~k->MyEventBits[3]) | k-> 03096 MyEventBits[IntSource]; 03097 } 03098 03099 static void SetIntSrc_B(comedi_device * dev, enc_private * k, 03100 uint16_t IntSource) 03101 { 03102 uint16_t crb; 03103 03104 // Cache writeable CRB register image. 03105 crb = DEBIread(dev, k->MyCRB) & ~CRBMSK_INTCTRL; 03106 03107 // Reset any pending counter overflow or index captures. 03108 DEBIwrite(dev, k->MyCRB, 03109 (uint16_t) (crb | CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B)); 03110 03111 // Program counter interrupt source. 03112 DEBIwrite(dev, k->MyCRB, 03113 (uint16_t) ((crb & ~CRBMSK_INTSRC_B) | (IntSource << 03114 CRBBIT_INTSRC_B))); 03115 03116 // Update MISC2 interrupt enable mask. 03117 devpriv->CounterIntEnabs = 03118 (devpriv->CounterIntEnabs & ~k->MyEventBits[3]) | k-> 03119 MyEventBits[IntSource]; 03120 } 03121 03122 static uint16_t GetIntSrc_A(comedi_device * dev, enc_private * k) 03123 { 03124 return (DEBIread(dev, k->MyCRA) >> CRABIT_INTSRC_A) & 3; 03125 } 03126 03127 static uint16_t GetIntSrc_B(comedi_device * dev, enc_private * k) 03128 { 03129 return (DEBIread(dev, k->MyCRB) >> CRBBIT_INTSRC_B) & 3; 03130 } 03131 03133 // Return/set the clock multiplier. 03134 03135 /* static void SetClkMult(comedi_device *dev, enc_private *k, uint16_t value ) */ 03136 /* { */ 03137 /* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKMULT ) | ( value << STDBIT_CLKMULT ) ), FALSE ); */ 03138 /* } */ 03139 03140 /* static uint16_t GetClkMult(comedi_device *dev, enc_private *k ) */ 03141 /* { */ 03142 /* return ( k->GetMode(dev, k ) >> STDBIT_CLKMULT ) & 3; */ 03143 /* } */ 03144 03145 /* ////////////////////////////////////////////////////////////////////////// */ 03146 /* // Return/set the clock polarity. */ 03147 03148 /* static void SetClkPol( comedi_device *dev,enc_private *k, uint16_t value ) */ 03149 /* { */ 03150 /* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKPOL ) | ( value << STDBIT_CLKPOL ) ), FALSE ); */ 03151 /* } */ 03152 03153 /* static uint16_t GetClkPol(comedi_device *dev, enc_private *k ) */ 03154 /* { */ 03155 /* return ( k->GetMode(dev, k ) >> STDBIT_CLKPOL ) & 1; */ 03156 /* } */ 03157 03158 /* /////////////////////////////////////////////////////////////////////// */ 03159 /* // Return/set the clock source. */ 03160 03161 /* static void SetClkSrc( comedi_device *dev,enc_private *k, uint16_t value ) */ 03162 /* { */ 03163 /* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKSRC ) | ( value << STDBIT_CLKSRC ) ), FALSE ); */ 03164 /* } */ 03165 03166 /* static uint16_t GetClkSrc( comedi_device *dev,enc_private *k ) */ 03167 /* { */ 03168 /* return ( k->GetMode(dev, k ) >> STDBIT_CLKSRC ) & 3; */ 03169 /* } */ 03170 03171 /* //////////////////////////////////////////////////////////////////////// */ 03172 /* // Return/set the index polarity. */ 03173 03174 /* static void SetIndexPol(comedi_device *dev, enc_private *k, uint16_t value ) */ 03175 /* { */ 03176 /* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_INDXPOL ) | ( (value != 0) << STDBIT_INDXPOL ) ), FALSE ); */ 03177 /* } */ 03178 03179 /* static uint16_t GetIndexPol(comedi_device *dev, enc_private *k ) */ 03180 /* { */ 03181 /* return ( k->GetMode(dev, k ) >> STDBIT_INDXPOL ) & 1; */ 03182 /* } */ 03183 03184 /* //////////////////////////////////////////////////////////////////////// */ 03185 /* // Return/set the index source. */ 03186 03187 /* static void SetIndexSrc(comedi_device *dev, enc_private *k, uint16_t value ) */ 03188 /* { */ 03189 /* DEBUG("SetIndexSrc: set index src enter 3700\n"); */ 03190 /* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_INDXSRC ) | ( (value != 0) << STDBIT_INDXSRC ) ), FALSE ); */ 03191 /* } */ 03192 03193 /* static uint16_t GetIndexSrc(comedi_device *dev, enc_private *k ) */ 03194 /* { */ 03195 /* return ( k->GetMode(dev, k ) >> STDBIT_INDXSRC ) & 1; */ 03196 /* } */ 03197 03199 // Generate an index pulse. 03200 03201 static void PulseIndex_A(comedi_device * dev, enc_private * k) 03202 { 03203 register uint16_t cra; 03204 03205 DEBUG("PulseIndex_A: pulse index enter\n"); 03206 03207 cra = DEBIread(dev, k->MyCRA); // Pulse index. 03208 DEBIwrite(dev, k->MyCRA, (uint16_t) (cra ^ CRAMSK_INDXPOL_A)); 03209 DEBUG("PulseIndex_A: pulse index step1\n"); 03210 DEBIwrite(dev, k->MyCRA, cra); 03211 } 03212 03213 static void PulseIndex_B(comedi_device * dev, enc_private * k) 03214 { 03215 register uint16_t crb; 03216 03217 crb = DEBIread(dev, k->MyCRB) & ~CRBMSK_INTCTRL; // Pulse index. 03218 DEBIwrite(dev, k->MyCRB, (uint16_t) (crb ^ CRBMSK_INDXPOL_B)); 03219 DEBIwrite(dev, k->MyCRB, crb); 03220 } 03221 03223 // Write value into counter preload register. 03224 03225 static void Preload(comedi_device * dev, enc_private * k, uint32_t value) 03226 { 03227 DEBUG("Preload: preload enter\n"); 03228 DEBIwrite(dev, (uint16_t) (k->MyLatchLsw), (uint16_t) value); // Write value to preload register. 03229 DEBUG("Preload: preload step 1\n"); 03230 DEBIwrite(dev, (uint16_t) (k->MyLatchLsw + 2), 03231 (uint16_t) (value >> 16)); 03232 } 03233 03234 static void CountersInit(comedi_device * dev) 03235 { 03236 int chan; 03237 enc_private *k; 03238 uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) | // Preload upon 03239 // index. 03240 (INDXSRC_SOFT << BF_INDXSRC) | // Disable hardware index. 03241 (CLKSRC_COUNTER << BF_CLKSRC) | // Operating mode is counter. 03242 (CLKPOL_POS << BF_CLKPOL) | // Active high clock. 03243 (CNTDIR_UP << BF_CLKPOL) | // Count direction is up. 03244 (CLKMULT_1X << BF_CLKMULT) | // Clock multiplier is 1x. 03245 (CLKENAB_INDEX << BF_CLKENAB); // Enabled by index 03246 03247 // Disable all counter interrupts and clear any captured counter events. 03248 for (chan = 0; chan < S626_ENCODER_CHANNELS; chan++) { 03249 k = &encpriv[chan]; 03250 k->SetMode(dev, k, Setup, TRUE); 03251 k->SetIntSrc(dev, k, 0); 03252 k->ResetCapFlags(dev, k); 03253 k->SetEnable(dev, k, CLKENAB_ALWAYS); 03254 } 03255 DEBUG("CountersInit: counters initialized \n"); 03256 03257 }