diff --git a/src/include/drv/gsc18ai32.c b/src/include/drv/gsc18ai32.c new file mode 100644 index 0000000000000000000000000000000000000000..88aa85424a8e6e083f20dd53efbfdb5ad947302d --- /dev/null +++ b/src/include/drv/gsc18ai32.c @@ -0,0 +1,272 @@ +/// \file gsc16ai64.c +/// \brief File contains the initialization routine and various register read/write +///< operations for the General Standards 16bit, 32 channel ADC modules. \n +///< For board info, see +///< <a href="http://www.generalstandards.com/view-products2.php?BD_family=16ai64ssc">GSC 16AI64SSC Manual</a> + +#include "gsc18ai32.h" + + +// ***************************************************************************** +/// \brief Routine to initialize GSC 16bit, 32 channel ADC modules +/// @param[in,out] *pHardware Pointer to global data structure for storing I/O +///< register mapping information. +/// @param[in] *adcdev PCI address information passed by the mapping code in map.c +/// @return Status from board enable command. +// ***************************************************************************** +int gsc18ai32Init(CDS_HARDWARE *pHardware, struct pci_dev *adcdev) +{ + static unsigned int pci_io_addr; /// @param pci_io_addr Bus address of PCI card I/O register. + int devNum; /// @param devNum Index into CDS_HARDWARE struct for adding board info. + char *_adc_add; /// @param *_adc_add ADC register address space + int pedStatus; /// @param pedStatus Status return from call to enable device. + volatile GSA_ADC_18BIT_REG *adc18Ptr; + + + /// Get index into CDS_HARDWARE struct based on total number of ADC cards found by mapping routine + /// in map.c + devNum = pHardware->adcCount; + /// Enable the module. + pedStatus = pci_enable_device(adcdev); + /// Enable device to be DMA master. + pci_set_master(adcdev); + /// Get the PLX chip address + pci_read_config_dword(adcdev,PCI_BASE_ADDRESS_0,&pci_io_addr); + printk("pci0 = 0x%x\n",pci_io_addr); + /// Map module DMA space directly to computer memory space. + _adc_add = ioremap_nocache((unsigned long)pci_io_addr, 0x200); + /// Map the module DMA control registers via PLX chip registers + adcDma[devNum] = (PLX_9056_DMA *)_adc_add; + if(devNum == 0) plxIcr = (PLX_9056_INTCTRL *)_adc_add; + + /// Get the ADC register address + pci_read_config_dword(adcdev,PCI_BASE_ADDRESS_2,&pci_io_addr); + printk("pci2 = 0x%x\n",pci_io_addr); + /// Map the module control register so local memory space. + _adc_add = ioremap_nocache((unsigned long)pci_io_addr, 0x200); + printk("ADC 18 I/O address=0x%x 0x%lx\n", pci_io_addr,(long)_adc_add); + /// Set global ptr to control register memory space. + adc18Ptr = (GSA_ADC_18BIT_REG *)_adc_add; + adcPtr[devNum] = (GSA_ADC_REG *)_adc_add; + printk("ADC pointer init at 0x%lx\n",(long)adcPtr[devNum]); + + printk("BCR = 0x%x\n",adc18Ptr->BCR); + /// Reset the ADC board + adc18Ptr->BCR |= GSAF_RESET; + do{ + }while((adc18Ptr->BCR & GSAF_RESET) != 0); + + /// Write in a sync word + adc18Ptr->SMUW = 0x0000; + adc18Ptr->SMLW = 0x0000; + + /// Set ADC to 64 channel = 32 differential channels + // Don't need this for this board + + #ifdef ADC_EXTERNAL_SYNC + // This is for the external connector use + adc18Ptr->BCR |= (GSAF_ENABLE_X_SYNC); // 0x80 + adc18Ptr->AUX_SIO |= 0x80; + #endif + + + /// Set sample rate close to 16384Hz + /// Unit runs with external clock, so this probably not necessary + adc18Ptr->RAG = 0x117D8; + printk("RAG = 0x%x\n",adc18Ptr->RAG); + printk("BCR = 0x%x\n",adc18Ptr->BCR); + adc18Ptr->RAG &= ~(GSAF_SAMPLE_START); // 0x10000 + /// Initiate board calibration + adc18Ptr->BCR |= GSAF_AUTO_CAL; + /// Wait for internal calibration to complete. + do { + }while((adc18Ptr->BCR & GSAF_AUTO_CAL) != 0); // 0x2000 + adc18Ptr->RAG |= GSAF_SAMPLE_START; // 0x10000 + adc18Ptr->IDBC = (GSAF_CLEAR_BUFFER | GSAF_THRESHOLD); // 0x40000 | 0x001f + adc18Ptr->SSC = (GSAF_32_CHANNEL); // 0x5 Sets 32 channels and external clock + printk("SSC = 0x%x\n",adc18Ptr->SSC); + printk("IDBC = 0x%x\n",adc18Ptr->IDBC); + /// Fill in CDS_HARDWARE structure with ADC information. + pHardware->pci_adc[devNum] = (long) pci_alloc_consistent(adcdev,0x2000,&adc_dma_handle[devNum]); + pHardware->adcType[devNum] = GSC_18AI32SSC1M; + pHardware->adcConfig[devNum] = adc18Ptr->ASSC; + pHardware->adcCount ++; + /// Return board enable status. + return(pedStatus); + + +/* +SSC Register + - Byte 0 = Active channels + lower sample source bit + - 0x5 + - Byte 1 = upper sample source + enable clocking + enable clock divider + burst busy + - 0x20 +*/ + +} + +// ***************************************************************************** +/// \brief Function checks status of DMA DONE bit for an ADC module. +/// @param[in] module ID of ADC board to read. +/// @return Status of ADC module DMA DONE bit (0=not complete, 1= complete) +// ***************************************************************************** +int gsc18ai32CheckDmaDone(int module) +{ + // Return 0 if DMA not complete + if((adcDma[module]->DMA_CSR & GSAF_DMA_DONE) == 0) return(0); + // Return 1 if DMA is complete + else return(1); +} +// ***************************************************************************** +/// \brief Function if DMA from ADC module is complete. +///< Code will remain in loop until DMA is complete. +/// @param[in] module ID of ADC board to read. +/// @param[out] data Status of DMA DONE bit. +/// @return ADC DMA Status (0=not complete, 16=complete +/// Note: This function not presently used. +// ***************************************************************************** +int gsc18ai32WaitDmaDone(int module, int *data) +{ + do{ + }while((adcDma[module]->DMA_CSR & GSAF_DMA_DONE) == 0); + // First channel should be marked with an upper bit set + if (*data == 0) return 0; else return 16; +} + + +// ***************************************************************************** +/// \brief Function clears ADC buffer and starts acquisition via external clock. +///< Also sets up ADC for Demand DMA mode and set GO bit in DMA Mode Register. +///< NOTE: In normal operation, this code should only be called while the clocks from +///< the timing slave are turned OFF ie during initialization process. +/// @param[in] adcCount Total number of ADC modules to start DMA. +// ***************************************************************************** +int gsc18ai32Enable(CDS_HARDWARE *pHardware) +{ + int ii; + volatile GSA_ADC_18BIT_REG *adc18Ptr; + for(ii=0;ii<pHardware->adcCount;ii++) + { + if(pHardware->adcType[ii] == GSC_18AI32SSC1M) + { + adc18Ptr = (volatile GSA_ADC_18BIT_REG *) adcPtr[ii]; + /// Enable demand DMA mode ie auto DMA data to computer memory when + ///< GSAI_THRESHOLD data points in ADC FIFO. + adc18Ptr->BCR &= ~(GSAF_DMA_DEMAND_MODE); + /// Set DMA mode and direction in PLX controller chip on module. + adcDma[ii]->DMA0_MODE = GSAF_DMA_MODE_NO_INTR | 0x1000; + /// Enable DMA + adcDma[ii]->DMA_CSR = GSAF_DMA_START; + /// Clear the FIFO and set demand DMA to start after all 32 channels have 1 sample + adc18Ptr->IDBC = (GSAF_CLEAR_BUFFER | GSAF_THRESHOLD); + /// Enable sync via external clock input. + adc18Ptr->SSC |= GSAF_ENABLE_CLOCK; + } + } + return(0); +} + +#if 0 +// ***************************************************************************** +int gsc18ai32Enable1PPS(CDS_HARDWARE *pHardware, int ii) +{ +/// Enable demand DMA mode ie auto DMA data to computer memory when +///< GSAI_THRESHOLD data points in ADC FIFO. + volatile GSA_ADC_18BIT_REG *adc18Ptr; + if(pHardware->adcType[ii] == GSC_18AI32SSC1M) + { + adc18Ptr = (volatile GSA_ADC_18BIT_REG *) adcPtr[ii]; + adc18Ptr->BCR &= ~(GSAF_DMA_DEMAND_MODE); + /// Set DMA mode and direction in PLX controller chip on module. + adcDma->DMA0_MODE = GSAF_DMA_MODE_NO_INTR | 0x1000; + /// Enable DMA + adcDma->DMA_CSR = GSAF_DMA_START; + /// Clear the FIFO and set demand DMA to start after all 32 channels have 1 sample + adc18Ptr->IDBC = (GSAF_CLEAR_BUFFER | GSAF_THRESHOLD); + /// Enable sync via external clock input. + adc18Ptr->BCR |= GSAF_ENABLE_X_SYNC; + } + return(0); +} + +// ***************************************************************************** +/// \brief Function stops ADC acquisition by removing the clocking signal. +// ***************************************************************************** +int gsc18ai32AdcStop() +{ + adc18Ptr[0]->BCR &= ~(GSAF_ENABLE_X_SYNC); + return(0); +} +#endif + +// ***************************************************************************** +/// \brief Routine reads number of samples in ADC FIFO. +/// @param[in] numAdc The ID number of the ADC module to read. +/// @return The number of samples presently in the ADC FIFO. +// ***************************************************************************** +int gsc18ai32CheckAdcBuffer(CDS_HARDWARE *pHardware, int numAdc) +{ + volatile GSA_ADC_18BIT_REG *adc18Ptr; + int dataCount = 0; + + if(pHardware->adcType[numAdc] == GSC_18AI32SSC1M) + { + adc18Ptr = (volatile GSA_ADC_18BIT_REG *) adcPtr[numAdc]; + dataCount = adc18Ptr->BUF_SIZE; + } + return(dataCount); + +} + + +// ***************************************************************************** +/// \brief This routine sets up the ADC DMA registers once on code initialization. +/// @param[in] modNum The ID number of the ADC module to read. +// ***************************************************************************** +int gsc18ai32DmaSetup(int modNum) +{ + /// Set DMA mode such that completion does not cause interrupt on bus. + adcDma[modNum]->DMA0_MODE = GSAF_DMA_MODE_NO_INTR; + /// Load PCI address (remapped local memory) to which data is to be delivered. + adcDma[modNum]->DMA0_PCI_ADD = (int)adc_dma_handle[modNum]; + /// Set the PCI address of board where data will be transferred from. + adcDma[modNum]->DMA0_LOC_ADD = GSAF_DMA_LOCAL_ADDR; + /// Set the number of bytes to be transferred. + adcDma[modNum]->DMA0_BTC = GSAF_DMA_BYTE_COUNT; + /// Set the DMA direction ie ADC to computer memory. + adcDma[modNum]->DMA0_DESC = GSAF_DMA_TO_PCI; + return(1); +} + +// ***************************************************************************** +/// \brief This routine sets up the ADC DMA registers once on code initialization. +/// @param[in] modNum The ID number of the ADC module to read. +// ***************************************************************************** +#if 0 +int gsc18ai32DmaSetup32(int modNum) +{ + /// Set DMA mode such that completion does not cause interrupt on bus. + adcDma[modNum]->DMA0_MODE = GSAF_DMA_MODE_NO_INTR; + /// Load PCI address (remapped local memory) to which data is to be delivered. + adcDma[modNum]->DMA0_PCI_ADD = (int)adc_dma_handle[modNum]; + /// Set the PCI address of board where data will be transferred from. + adcDma[modNum]->DMA0_LOC_ADD = GSAF_DMA_LOCAL_ADDR; + /// Set the number of bytes to be transferred. + adcDma[modNum]->DMA0_BTC = 0x100; + /// Set the DMA direction ie ADC to computer memory. + adcDma[modNum]->DMA0_DESC = GSAF_DMA_TO_PCI; + return(1); +} +#endif + + +// ***************************************************************************** +/// \brief This routine starts an ADC DMA operation. It must first be setup by +///< the gsc16ai64DmaSetup routine. +/// @param[in] modNum The ID number of the ADC module to read. +// ***************************************************************************** +void gsc18ai32DmaEnable(int modNum) +{ + adcDma[modNum]->DMA_CSR = GSAF_DMA_START; +} + diff --git a/src/include/drv/gsc18ai32.h b/src/include/drv/gsc18ai32.h new file mode 100644 index 0000000000000000000000000000000000000000..d505059eb35290c59c81a8b8b0d4ce114688d78d --- /dev/null +++ b/src/include/drv/gsc18ai32.h @@ -0,0 +1,78 @@ +// \file gsc16ai64.h +/// \brief GSC 16bit, 32 channel ADC Module Definitions. See +///< <a href="http://www.generalstandards.com/view-products2.php?BD_family=16ai64ssc">GSC 16AI64SSC Manual</a> +///< for more info on board registers. + +#define ADC_18AI32_SS_ID 0x3431 ///< Subsystem ID to identify and locate module on PCI bus + +int gsc18ai32Init(CDS_HARDWARE *, struct pci_dev *); +int gsc18ai32CheckDmaDone(int); +int gsc18ai32WaitDmaDone(int, int *); +int gsc18ai32Enable(CDS_HARDWARE *); +int gsc18ai32Enable1PPS(CDS_HARDWARE *,int); +// int gsc18ai32AdcStop(void); + + +/// Structure defining ADC module PCI register layout as per user manual +typedef struct GSA_ADC_18BIT_REG{ + unsigned int BCR; ///< Board Control Register at 0x0 + unsigned int INTCR; ///< Interrupt Control Register at 0x4 + unsigned int IDB; ///< Input Data Buffer at 0x8 + unsigned int IDBC; ///< Input Buffer Control at 0xc */ + unsigned int RAG; ///< Rate A Generator at 0x10 + unsigned int RBG; ///< Rate B Generator at 0x14 + unsigned int BUF_SIZE; ///< Buffer Size at 0x18 + unsigned int BRT_SIZE; ///< Burst Size at 0x1c + unsigned int SSC; ///< Scan and Sync Control at 0x20 + unsigned int ACA; ///< Active Channel Assignment Register at 0x24 + unsigned int ASSC; ///< Board Configuration Register at 0x28 + unsigned int AC_VAL; ///< Autocal Values register at 0x2c + unsigned int AUX_RWR; ///< Auxillary Read/Write Register at 0x30 + unsigned int AUX_SIO; ///< Auxillary Sync Control Register at 0x34 + unsigned int SMUW; ///< Scan Marker Upper Word 0x38 + unsigned int SMLW; ///< Scan Maker Lower Word at 0x3c + unsigned int TUR; ///< Test utility register at 0x40 + unsigned int PTCL; ///< Pretrigger counter low at 0x44 + unsigned int PTCH; ///< Pretrigger counter high at 0x48 + unsigned int RSV1; ///< Reserved 1 at 0x4C + unsigned int RSV2; ///< Reserved 2 at 0x50 + unsigned int ECD; ///< External Clock Divisor at 0x54 +}GSA_ADC_18BIT_REG; + +#define GSAF_FULL_DIFFERENTIAL 0x200 +#define GSAF_64_CHANNEL 0x6 +#define GSAF_32_CHANNEL 0x5 +#define GSAF_8_CHANNEL 0x3 +#define GSAF_8_OFFSET (8 * UNDERSAMPLE - 1) +#define GSAF_SOFT_TRIGGER 0x1000 +#define GSAF_ENABLE_CLOCK 0x20 +#define GSAF_RESET 0x8000 +#define GSAF_DATA_PACKING 0x40000 +#define GSAF_DMA_MODE_NO_INTR 0x10943 +#define GSAF_DMA_MODE_NO_INTR_DEMAND 0x20943 +#define GSAF_DMA_MODE_INTR 0x10D43 +#define GSAF_DMA_LOCAL_ADDR 0x8 +#define GSAF_DMA_TO_PCI 0xA +#define GSAF_DMA_START 0x3 +#define GSAF_DMA1_START 0x300 +#define GSAF_DMA_DONE 0x10 +// #define GSAF_DMA_BYTE_COUNT 0x80 +// #define GSAF_DMA_BYTE_COUNT 0x100 +#define GSAF_DMA_BYTE_COUNT (32 * UNDERSAMPLE) +#define GSAF_ISR_ON_SAMPLE 0x3 +// #define PLX_INT_ENABLE 0x900 +// #define PLX_INT_DISABLE 0x800 +#define GSAF_SAMPLE_START 0x10000 +#define GSAF_SET_2S_COMP 0x40 +#define GSAF_EXTERNAL_SYNC 0x10 +#define GSAF_ENABLE_X_SYNC 0x80 +#define GSAF_CLEAR_BUFFER 0x40000 +#define GSAF_THRESHOLD 0x001f +#define GSAF_AUTO_CAL 0x2000 +#define GSAF_DMA_DEMAND_MODE 0x80000 +#define GSAF_18BIT_DATA 0x100000 +#define GSAF_DATA_CODE_OFFSET 0x8000 +#define GSAF_DATA_MASK 0xffff +#define GSAF_CHAN_COUNT 32 +#define GSAF_CHAN_COUNT_M1 31 +