/** * \file talise.c * \brief Contains top level functions to support initialization and ctrol of * the Talise transceiver device. * * Talise API version: 3.5.0.2 * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. */ /** * \mainpage Overview * * This document is intended for use by software engineering professionals * and includes detailed information regarding the data types and * function calls which comprise the Talise ANSI C API * * Copyright 2015-2017 Analog Devices Inc. * Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file. * */ /** * \page Suggested Use * The purpose of the Talise Application Programming Interface (API) is to abstract the low-level * SPI configuration, control, and related calculations required for the Talise family of transceiver devices * * Add the included source code as required to your baseband processor software build. Please reference the integration document * as well for further instructions. */ /** * \page Architecture Talise API Software Architecture * \image html software_architecture.png */ /** * \page Folders Talise API Folder Structure * \image html folder_structure.png */ #include #include "talise.h" #include "talise_reg_addr_macros.h" #include "talise_arm.h" #include "talise_hal.h" #include "talise_user.h" #include "talise_error.h" #include "talise_version.h" #include "talise_rx.h" #include "talise_tx.h" #include "talise_jesd204.h" #include "talise_cals.h" #include "talise.h" #define DBG_TALISE_SPI_PR (1) uint32_t TALISE_openHw(taliseDevice_t *device) { talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; ADIHAL_setLogLevel(device->devHalInfo, TALISE_LOGGING); halError = ADIHAL_openHw(device->devHalInfo, 100); if (halError != ADIHAL_OK) { switch(halError) { case ADIHAL_SPI_FAIL: return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); case ADIHAL_GPIO_FAIL: return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_HAL_GPIO, halError, retVal, TALACT_ERR_RESET_GPIO); case ADIHAL_TIMER_FAIL: return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_HAL_WAIT, halError, retVal, TALACT_ERR_CHECK_TIMER); case ADIHAL_GEN_SW: default: return (uint32_t)TALACT_ERR_CHECK_PARAM; } } return (uint32_t)retVal; } uint32_t TALISE_closeHw(taliseDevice_t *device) { talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; halError = ADIHAL_closeHw(device->devHalInfo); if (halError != ADIHAL_OK) { switch(halError) { case ADIHAL_SPI_FAIL: return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); case ADIHAL_GPIO_FAIL: return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_HAL_GPIO, halError, retVal, TALACT_ERR_RESET_GPIO); case ADIHAL_TIMER_FAIL: return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_HAL_WAIT, halError, retVal, TALACT_ERR_CHECK_TIMER); case ADIHAL_GEN_SW: default: return (uint32_t)TALACT_ERR_CHECK_PARAM; } } return (uint32_t)retVal; } uint32_t TALISE_resetDevice(taliseDevice_t *device) { talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; #if TALISE_VERBOSE halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_resetDevice()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif /* toggle RESETB on device with matching spi chip select index */ halError = ADIHAL_resetHw(device->devHalInfo); if (halError == ADIHAL_WAIT_TIMEOUT) { /*Retry*/ halError = ADIHAL_resetHw(device->devHalInfo); } if (halError != ADIHAL_OK) { retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_GPIO, halError, retVal, TALACT_ERR_RESET_GPIO); } /* Power down deserializers */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_DES_PHY_PWR_DWN_0, 0xF0); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_DES_PHY_PWR_DWN_4, 0x2F); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); device->devStateInfo.devState = TAL_STATE_POWERONRESET; return (uint32_t)retVal; } static talRecoveryActions_t talInitializeDdc(taliseDevice_t *device, taliseInit_t *init) { uint8_t totalFramerM = 0; uint8_t combineBands = 0; uint8_t pfirOutDecimation = 0; uint8_t ncoPhaseAccumDivideRatio = 0; uint8_t rxNco1PhaseAccumDivideRatio = 0; uint8_t rxNco2PhaseAccumDivideRatio = 0; uint8_t registerValue = 0; uint8_t rxNcoControl = 0; adiHalErr_t halError = ADIHAL_OK; talRecoveryActions_t retVal = TALACT_NO_ACTION; static const uint8_t RX_DUALBAND_ENABLED = 1; static const uint8_t RX_DUALBAND_DISABLED = 0; static const uint8_t ENABLE_NCO1 = 0x01; static const uint8_t ENABLE_NCO2 = 0x40; static const uint8_t ENABLE_NCO1_REALIF = 0x20; static const uint8_t ENABLE_NCO2_REALIF = 0x80; static const uint8_t DDC_DEC2 = 0x04; /* Set DDC Mode and enable bit */ static const uint8_t DDC_INT2 = 0x14; /* Set DDC Mode and enable bit */ static const uint8_t DDC_LOWPASS = 0x0C; /* Set DDC Mode and enable bit */ /* Verify Null pointer to *init */ if (init == NULL) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_INITIALIZE_DDC_NULL_PARAM, retVal, TALACT_ERR_CHECK_PARAM); } if ((device->devStateInfo.profilesValid & RX_PROFILE_VALID) && (init->rx.rxChannels != TAL_RXOFF)) { /* Phase accumulator calculation for NCO : FLOGB2(Decimation at PFIR out) - 2 */ /* The -2 is because NCO clock is divided version of the div4/5 clock */ /* For TAL_RXDDC_ZIF_TO_RIF_INT2 mode, Decimation at PFIR should be more than 8 since it is going to be interpolated */ pfirOutDecimation = init->rx.rxProfile.rxDec5Decimation * init->rx.rxProfile.rhb1Decimation * init->rx.rxProfile.rxFirDecimation; if (((pfirOutDecimation < 4) && (init->rx.rxProfile.rxDdcMode != TAL_RXDDC_INT2)) || ((pfirOutDecimation < 8) && (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_INT2_REALIF)) || (pfirOutDecimation > 40)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_INITIALIZE_DDC_INV_DEC_AT_PFIR, retVal, TALACT_ERR_CHECK_PARAM); } else { pfirOutDecimation >>= 3; for (ncoPhaseAccumDivideRatio = 0; ncoPhaseAccumDivideRatio < 3; ncoPhaseAccumDivideRatio++) { if (pfirOutDecimation == 0) { break; } else { pfirOutDecimation >>= 1; } } } device->devStateInfo.rxDualBandEnabled = RX_DUALBAND_DISABLED; device->devStateInfo.rxOutputRate_kHz = init->rx.rxProfile.rxOutputRate_kHz; /* Dualband mode */ if ((init->rx.rxProfile.rxNcoShifterCfg.bandAInputBandWidth_kHz != 0) && (init->rx.rxProfile.rxNcoShifterCfg.bandBInputBandWidth_kHz != 0)) { /* Total number of converters */ totalFramerM = (((init->rx.framerSel == TAL_FRAMER_A) || (init->rx.framerSel == TAL_FRAMER_A_AND_B)) ? init->jesd204Settings.framerA.M : 0) + (((init->rx.framerSel == TAL_FRAMER_B) || (init->rx.framerSel == TAL_FRAMER_A_AND_B)) ? init->jesd204Settings.framerB.M : 0); /* If one Rx enabled and M = 2, combine two bands. If M = 4, separate them */ /* If two Rx enabled and M = 4, combine two bands. If M = 8, separate them */ if ((init->rx.rxChannels == TAL_RX1) || (init->rx.rxChannels == TAL_RX2)) { if ((totalFramerM != 2) && (totalFramerM != 4)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_INITIALIZE_DDC_INV_TOTAL_M_2OR4, retVal, TALACT_ERR_CHECK_PARAM); } combineBands = (totalFramerM == 2) ? 1 : 0; } else /* TAL_RX1RX2 */ { if ((totalFramerM != 4) && (totalFramerM != 8)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_INITIALIZE_DDC_INV_TOTAL_M_4OR8, retVal, TALACT_ERR_CHECK_PARAM); } combineBands = (totalFramerM == 4) ? 1 : 0; } /* Phase accumulator calculation for NCO1 : FLOGB2(Decimation at PFIR out) - 2 */ rxNco1PhaseAccumDivideRatio = ncoPhaseAccumDivideRatio; /* Phase accumulator calculation for NCO2 : NCO1 + 1 */ rxNco2PhaseAccumDivideRatio = rxNco1PhaseAccumDivideRatio + 1; /* Setup value of NCO1 and NCO2 */ registerValue = (rxNco2PhaseAccumDivideRatio << 4) | rxNco1PhaseAccumDivideRatio; halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_7, registerValue, 0x73, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN(retVal); /* NCO configuration: NCO1 enable, DDC HB enable, DDC mode = Dec2, NCO2 enable */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_RX_NCO_CONTROL_0, 0x45, 0xFD, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN(retVal); /* Band configuration : Band A enable, Band B enable, Combine bands */ registerValue = (combineBands << 2) | 0x3; halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_RX_BAND_CONTROL, registerValue); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN(retVal); /* Select Real IF output for NCO2 */ if (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_DEC2_REALIF) { halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_RX_NCO_CONTROL_0, 0x80, 0x80, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN(retVal); } /* Initialize Dual Band Settings */ retVal = talSetDualBandSettings(device, init); IF_ERR_RETURN(retVal); device->devStateInfo.rxDualBandEnabled = RX_DUALBAND_ENABLED; }/* end dualband */ /* Not Dualband */ else { /* Phase accumulator calculation for NCO1 : FLOGB2(Decimation at PFIR out) - 2 */ rxNco1PhaseAccumDivideRatio = ncoPhaseAccumDivideRatio; rxNcoControl = 0; switch(init->rx.rxProfile.rxDdcMode) { case TAL_RXDDC_BYPASS: case TAL_RXDDC_BYPASS_REALIF: rxNco2PhaseAccumDivideRatio = ncoPhaseAccumDivideRatio; /* Leave rxNcoControl = 0 to bypass DDC HB */ break; case TAL_RXDDC_FILTERONLY: case TAL_RXDDC_FILTERONLY_REALIF: rxNco2PhaseAccumDivideRatio = ncoPhaseAccumDivideRatio; rxNcoControl |= DDC_LOWPASS; break; case TAL_RXDDC_DEC2: case TAL_RXDDC_DEC2_REALIF: rxNco2PhaseAccumDivideRatio = ncoPhaseAccumDivideRatio + 1; rxNcoControl |= DDC_DEC2; break; case TAL_RXDDC_INT2: case TAL_RXDDC_INT2_REALIF: rxNco2PhaseAccumDivideRatio = ncoPhaseAccumDivideRatio - 1; rxNcoControl |= DDC_INT2; break; default: return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_INITIALIZE_DDC_INV_RXDDCMODE, retVal, TALACT_ERR_CHECK_PARAM); } /* if nco1 shift */ if (init->rx.rxProfile.rxNcoShifterCfg.bandANco1Freq_kHz != 0) { rxNcoControl |= ENABLE_NCO1; if ((init->rx.rxProfile.rxDdcMode == TAL_RXDDC_DEC2_REALIF) || (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_INT2_REALIF) || (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_FILTERONLY_REALIF) || (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_BYPASS_REALIF)) { rxNcoControl |= ENABLE_NCO1_REALIF; } } /* if nco2 shift */ if (init->rx.rxProfile.rxNcoShifterCfg.bandANco2Freq_kHz != 0) { rxNcoControl |= ENABLE_NCO2; if ((init->rx.rxProfile.rxDdcMode == TAL_RXDDC_DEC2_REALIF) || (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_INT2_REALIF) || (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_FILTERONLY_REALIF) || (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_BYPASS_REALIF)) { rxNcoControl &= ~ENABLE_NCO1_REALIF; rxNcoControl |= ENABLE_NCO2_REALIF; } } /* Setup value of NCO2 phase accum clock */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_7, ((rxNco2PhaseAccumDivideRatio << 4) | rxNco1PhaseAccumDivideRatio), 0x73, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN(retVal); /* Set DDC HB mode, and NCO1/2 enable/disable bits */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_RX_NCO_CONTROL_0, rxNcoControl, 0xFD, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN(retVal); /* Initialize single band shift Settings */ retVal = talSetupNcoShifter(device, init); IF_ERR_RETURN(retVal); } /* end Not Dualband */ } return retVal; } int check_err_state(uint32_t err_ret) { return ((err_ret>TALACT_WARN_RESET_GPIO)?1:0); } char str_err[2][6]={"-----","error"}; uint32_t TALISE_initialize(taliseDevice_t *device, taliseInit_t *init) { //printf("[%s,%d] \n", __FUNCTION__, __LINE__); talRecoveryActions_t retVal = TALACT_NO_ACTION; talRecoveryActions_t retValWarn = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; uint8_t txChannelSettings = 0; uint8_t rxChannelSettings = 0; uint8_t orxChannelSettings = 0; uint8_t dacClockRateSelect = 0; uint8_t rxFirDecBitField = 0; uint8_t orxFirDecBitField = 0; uint8_t digDeviceClockDiv = 0; uint32_t digRefClock_MHz = 0; taliseInfo_t clearInfo = {(taliseStates_t)0,0,0,0,0,{0,0,(taliseHsDiv_t)0,0,0}, (taliseGainMode_t)0,{0,0,0,0,0,0,0,0},(taliseTxAttenStepSize_t)0, 0,0,0,0,0,0,0,(taliseRxDdc_t)0,0,0,0}; uint32_t agcClock_Hz = 0; uint32_t gainUpdateCount = 0; taliseAdcSampleXbar_t adcXbar = {(taliseAdcSampleXbarSelect_t)0,(taliseAdcSampleXbarSelect_t)0,(taliseAdcSampleXbarSelect_t)0,(taliseAdcSampleXbarSelect_t)0,(taliseAdcSampleXbarSelect_t)0,(taliseAdcSampleXbarSelect_t)0,(taliseAdcSampleXbarSelect_t)0,(taliseAdcSampleXbarSelect_t)0}; taliseDacSampleXbar_t dacXbar = {(taliseDacSampleXbarSelect_t)0,(taliseDacSampleXbarSelect_t)0}; uint8_t deframerSyncPadCfg = 0; uint16_t syncbPadCfgAddr = 0; uint8_t framerSyncPadCfg = 0; uint8_t sysrefCfg = 0; uint8_t regData = 0; int err_flg=0; static const uint8_t ULB_THRESHOLD = 0x27; static const uint8_t ULB2_THRESHOLD = 0x37; static const uint8_t LLB_THRESHOLD = 0x1b; static const uint8_t LLB2_THRESHOLD = 0x27; static const uint8_t GPINT_MASK_AUXPLL = 1; static const uint8_t MIN_SUPPORTED_SIREV = 0xB1; static const uint8_t TPC_MODE_TX1_SPI = 0x01; static const uint8_t TPC_MODE_TX2_SPI = 0x04; /* Verify pointers to *device and *init are not NULL */ if (device == NULL) { /* Can not write to log since log function requires device data structure */ return (uint32_t)TALACT_ERR_CHECK_PARAM; } if (init == NULL) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_INIT_NULLPARAM, retVal, TALACT_ERR_CHECK_PARAM); } printf("[%s,%d] \n", __FUNCTION__, __LINE__); #if TALISE_VERBOSE halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_initialize()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif //printf("[%s,%d] retVal=%d\n", __FUNCTION__, __LINE__,retVal); retValWarn = retVal; /* clear memory of Talise API state container */ device->devStateInfo = clearInfo; device->devStateInfo.txAttenStepSize = init->tx.txAttenStepSize; /* Calculate digital clocks based on information in init structure */ retVal = (talRecoveryActions_t)TALISE_calculateDigitalClocks(device, &init->clocks); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] \n", __FUNCTION__, __LINE__); /* Verify Rx/Tx and ObsRx profiles are valid combinations * and set device->devStateInfo.profilesValid member based on init struct settings */ retVal = (talRecoveryActions_t)TALISE_verifyProfiles(device, init); err_flg = check_err_state(retVal); printf("retVal=0x%x (%s) [TALISE_verifyProfiles]\n",retVal, str_err[err_flg]); IF_ERR_RETURN_U32(retVal); /* Set 3 or 4-wire SPI mode, MSBFirst/LSBfirst in device, pushes CPOL=0, CPHA=0, longInstWord=1 into device->spiSettings */ retVal = (talRecoveryActions_t)TALISE_setSpiSettings(device, &init->spiSettings); err_flg = check_err_state(retVal); printf("retVal=0x%x (%s) [TALISE_setSpiSettings]\n",retVal, str_err[err_flg]); printf("msb=%d,en=%d,auto=%d,four=%d,cmos=%d\n",init->spiSettings.MSBFirst,init->spiSettings.enSpiStreaming, init->spiSettings.fourWireMode,init->spiSettings.cmosPadDrvStrength); IF_ERR_RETURN_U32(retVal); /* Read device silicon revision */ retVal = (talRecoveryActions_t)TALISE_getDeviceRev(device, &device->devStateInfo.deviceSiRev); err_flg = check_err_state(retVal); printf("deviceSiRev=0x%x (%s) [TALISE_getDeviceRev]\n",device->devStateInfo.deviceSiRev, str_err[err_flg]); IF_ERR_RETURN_U32(retVal); /* Make sure Silicon is at least B1 silicon. API supports B1, C0 silicon and should work with any future silicon */ if (device->devStateInfo.deviceSiRev < MIN_SUPPORTED_SIREV) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_API_FAIL, TAL_ERR_INV_SIREV, retVal, TALACT_ERR_RESET_FULL); } printf("[%s,%d] retVal=%d\n", __FUNCTION__, __LINE__,retVal); /* Disable stream processor TxEnable/RxEnable pin control mode */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_RADIO_CONTROL_CONFIG1, 0x00); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] retVal=%d\n", __FUNCTION__, __LINE__,retVal); /* Enable Reference clock - Set REFCLK pad common mode voltage */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_REF_PAD_CONFIG2, 0x07); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Set Master bias trim and reset bandgap */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_MASTERBIAS_CONFIG1, 0x0F); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_MASTERBIAS_CONFIG0, 0x30); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_MASTERBIAS_CONFIG0, 0x10); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] retVal=%d\n", __FUNCTION__, __LINE__,retVal); sysrefCfg = (((init->jesd204Settings.sysrefLvdsMode > 0) ? 1 : 0) << 1) | /* Set SYSREF PAD for LVDS mode = 1, or CMOS mode = 0 */ (((init->jesd204Settings.sysrefLvdsPnInvert > 0) ? 1 : 0) << 2) | (((init->jesd204Settings.sysrefLvdsMode > 0) ? 1 : 0) << 4); /* Set LVDS 100 ohm input termination */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_SYSREF_PAD_CONFIG, sysrefCfg); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] \n", __FUNCTION__, __LINE__); /* mask the RF PLL GP Interrupt */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_GP_INTERRUPT_MASK_1, GPINT_MASK_AUXPLL, 0x04, 2); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); if (init->jesd204Settings.deframerA.deserializerLanesEnabled == 0) { /* If no lanes used for deframer A, do not enable SYNCB pad */ } else { if (init->jesd204Settings.deframerA.syncbOutSelect == 0) { syncbPadCfgAddr = TALISE_ADDR_TX1_SYNC_PAD_CONFIG; } else { syncbPadCfgAddr = TALISE_ADDR_TX2_SYNC_PAD_CONFIG; } /* Valid range 0-3 */ if (init->jesd204Settings.deframerA.syncbOutCmosSlewRate > 3) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_INV_DEFA_SLEWRATE, retVal, TALACT_ERR_CHECK_PARAM); } deframerSyncPadCfg = (init->jesd204Settings.deframerA.syncbOutCmosSlewRate << 5) | (((init->jesd204Settings.deframerA.syncbOutCmosDriveLevel > 0) ? 1 : 0) << 4) | (0x01 << 3) /* Set tx_sync_pad_lvds_low_cm */ | (((init->jesd204Settings.deframerA.syncbOutLvdsPnInvert > 0) ? 1 : 0) << 2) | (((init->jesd204Settings.deframerA.syncbOutLvdsMode > 0) ? 1 : 0) << 1); halError = talSpiWriteByte(device->devHalInfo, syncbPadCfgAddr, deframerSyncPadCfg); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } if (init->jesd204Settings.deframerB.deserializerLanesEnabled == 0) { /* If no lanes used for deframer B, do not enable SYNCB pad */ } else { if (init->jesd204Settings.deframerB.syncbOutSelect == 0) { syncbPadCfgAddr = TALISE_ADDR_TX1_SYNC_PAD_CONFIG; } else { syncbPadCfgAddr = TALISE_ADDR_TX2_SYNC_PAD_CONFIG; } /* Valid range 0-3 */ if (init->jesd204Settings.deframerB.syncbOutCmosSlewRate > 3) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_INV_DEFB_SLEWRATE, retVal, TALACT_ERR_CHECK_PARAM); } deframerSyncPadCfg = (init->jesd204Settings.deframerB.syncbOutCmosSlewRate << 5) | (((init->jesd204Settings.deframerB.syncbOutCmosDriveLevel > 0) ? 1 : 0) << 4) | (0x01 << 3) /* Set tx_sync_pad_lvds_low_cm */ | (((init->jesd204Settings.deframerB.syncbOutLvdsPnInvert > 0) ? 1 : 0) << 2) | (((init->jesd204Settings.deframerB.syncbOutLvdsMode > 0) ? 1 : 0) << 1); halError = talSpiWriteByte(device->devHalInfo, syncbPadCfgAddr, deframerSyncPadCfg); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } printf("[%s,%d] \n", __FUNCTION__, __LINE__); /* Look at each framer and enable the RXSYNCB used for each framer. It is possible that they use the same RXSYNCB pin */ if (init->jesd204Settings.framerA.serializerLanesEnabled == 0) { /* framer A disabled, do not enable SYNCB pad */ } else { if (init->jesd204Settings.framerA.syncbInSelect == 0) { syncbPadCfgAddr = TALISE_ADDR_RX1_SYNC_PAD_CONFIG; } else { syncbPadCfgAddr = TALISE_ADDR_RX2_SYNC_PAD_CONFIG; } framerSyncPadCfg = (((init->jesd204Settings.framerA.syncbInLvdsPnInvert > 0) ? 1 : 0) << 2) | (((init->jesd204Settings.framerA.syncbInLvdsMode > 0) ? 1 : 0) << 1) | (((init->jesd204Settings.framerA.syncbInLvdsMode > 0) ? 1 : 0) << 4); /* if LVDS mode, enable internal 100ohm termination */ halError = talSpiWriteByte(device->devHalInfo, syncbPadCfgAddr, framerSyncPadCfg); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } printf("[%s,%d] \n", __FUNCTION__, __LINE__); if (init->jesd204Settings.framerB.serializerLanesEnabled == 0) { /* framer B disabled, do not enable SYNCB pad */ } else { if (init->jesd204Settings.framerB.syncbInSelect == 0) { syncbPadCfgAddr = TALISE_ADDR_RX1_SYNC_PAD_CONFIG; } else { syncbPadCfgAddr = TALISE_ADDR_RX2_SYNC_PAD_CONFIG; } framerSyncPadCfg = (((init->jesd204Settings.framerB.syncbInLvdsPnInvert > 0) ? 1 : 0) << 2) | (((init->jesd204Settings.framerB.syncbInLvdsMode > 0) ? 1 : 0) << 1) | (((init->jesd204Settings.framerB.syncbInLvdsMode > 0) ? 1 : 0) << 4); /* if LVDS mode, enable internal 100ohm termination */ halError = talSpiWriteByte(device->devHalInfo, syncbPadCfgAddr, framerSyncPadCfg); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } printf("[%s,%d] \n", __FUNCTION__, __LINE__); /* Set Digital device clock divider - provides clock to 1us timer logic, and some other blocks */ if (init->clocks.deviceClock_kHz <= 200000) { digDeviceClockDiv = 0; /* Device clock / 1 */ digRefClock_MHz = (init->clocks.deviceClock_kHz / 1000); } else if ((init->clocks.deviceClock_kHz <= 400000) && (init->clocks.deviceClock_kHz > 200000)) { digDeviceClockDiv = 1; /* Device clock / 2 */ digRefClock_MHz = (((init->clocks.deviceClock_kHz / 1000) + 1) >> 1); /* /2 with round to nearest */ } else if ((init->clocks.deviceClock_kHz <= 800000) && (init->clocks.deviceClock_kHz > 400000)) { digDeviceClockDiv = 2; /* Device clock / 4 */ digRefClock_MHz = (((init->clocks.deviceClock_kHz / 1000) + 2) >> 2); /* /4 with round to nearest */ } else if ((init->clocks.deviceClock_kHz <= 1600000) && (init->clocks.deviceClock_kHz > 800000)) { digDeviceClockDiv = 3; /* Device clock / 8 */ digRefClock_MHz = (((init->clocks.deviceClock_kHz / 1000) + 4) >> 3); /* /8 with round to nearest */ } else { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_INIT_INV_DEVCLK, retVal, TALACT_ERR_CHECK_PARAM); } /* Set Digital device clock divider */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_0, digDeviceClockDiv, 0xE0, 5); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Set number of divided device clock cycles per microsecond */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_REFERENCE_CLOCK_CYCLES, (uint8_t)(digRefClock_MHz - 1)); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Negate Rx2 so phase matches Rx1 */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_RX_DATAPATH_INVERSION, 0x0C); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] \n", __FUNCTION__, __LINE__); /* Tx Settings */ if (device->devStateInfo.profilesValid & TX_PROFILE_VALID) { if (init->tx.txProfile.thb3Interpolation == 2) { txChannelSettings |= 0x10; } if (init->tx.txProfile.thb2Interpolation == 2) { txChannelSettings |= 0x04; } if (init->tx.txProfile.thb1Interpolation == 2) { txChannelSettings |= 0x08; } switch (init->tx.txProfile.txFirInterpolation) { case 1: txChannelSettings |= 0x01; break; case 2: txChannelSettings |= 0x02; break; case 4: txChannelSettings |= 0x03; break; } /* Set Rx Dec5 if Int5 is enabled */ if (init->tx.txProfile.txInt5Interpolation == 5) { rxChannelSettings |= 0x02; } if (init->tx.txProfile.dacDiv == 2) { dacClockRateSelect = 1; /* DAC Clock = hsDigClk/2 */ } } /* Rx settings */ if (device->devStateInfo.profilesValid & RX_PROFILE_VALID) { if (init->rx.rxProfile.rxDec5Decimation == 5) { rxChannelSettings |= 0x02; } if ( init->rx.rxProfile.rhb1Decimation == 2) { rxChannelSettings |= 0x10; } switch (init->rx.rxProfile.rxFirDecimation) { case 1: rxFirDecBitField |= 0x01; break; case 2: rxFirDecBitField |= 0x02; break; case 4: rxFirDecBitField |= 0x03; break; } } printf("[%s,%d] \n", __FUNCTION__, __LINE__); /* Determine ORx channel settings */ if (device->devStateInfo.profilesValid & ORX_PROFILE_VALID) { if ( init->obsRx.orxProfile.rxDec5Decimation == 5) { rxChannelSettings |= 0x02; } /* Enable ORX RHB2 Wideband */ orxChannelSettings = 0x10; if (init->obsRx.orxProfile.rhb1Decimation == 2) { orxChannelSettings |= 0x04; } switch (init->obsRx.orxProfile.rxFirDecimation) { case 1: orxFirDecBitField |= 0x01; break; case 2: orxFirDecBitField |= 0x02; break; case 4: orxFirDecBitField |= 0x03; break; } } printf("[%s,%d] \n", __FUNCTION__, __LINE__); /************************************************************************ * Set channel config settings for Rx/Tx/ and ORx channels ************************************************************************/ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CONFIGURATION_CONTROL_2, txChannelSettings); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CONFIGURATION_CONTROL_4, rxChannelSettings); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CONFIGURATION_CONTROL_ORX, orxChannelSettings); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_RX_PFIR_BANK_A_SETTINGS, rxFirDecBitField, 0x03, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_RX_PFIR_BANK_B_SETTINGS, orxFirDecBitField, 0x03, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_RX_PFIR_BANK_C_SETTINGS, orxFirDecBitField, 0x03, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] \n", __FUNCTION__, __LINE__); /* Enable SPI Tx Atten mode and set Atten step size. Only write bottom 6 bits */ regData = 0; regData |= TPC_MODE_TX1_SPI; regData |= TPC_MODE_TX2_SPI; regData |= (init->tx.txAttenStepSize << 4); halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_TX_TPC_CONFIG, regData, 0x3F, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Set DAC divider */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_1, dacClockRateSelect, 0x01, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Set ADC Flash bias */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_ADC_BIAS_FLASH_VISB, 0x7D); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] \n", __FUNCTION__, __LINE__); /* Set the CLKPLL with the frequency from the device data structure */ retVal = (talRecoveryActions_t)TALISE_initDigitalClocks(device, &init->clocks); IF_ERR_RETURN_U32(retVal); halError = ADIHAL_wait_us(device->devHalInfo, CLKPLL_LOCK_US); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_CHECK_TIMER); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] \n", __FUNCTION__, __LINE__); halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_0, 0, 0x01, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_0, 1, 0x01, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Enable digital clocks - this is gated by the CLKPLL being locked */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_0, 1, 0x04, 2); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] \n", __FUNCTION__, __LINE__); /* Wait for CLKPLL CP Cal done and CLKPLL Lock or throw error message */ retVal = (talRecoveryActions_t)TALISE_waitForEvent(device, TAL_CLKPLLCP, CLKPLL_CPCAL_TIMEOUT_US, CLKPLL_CPCAL_INTERVAL_US); IF_ERR_RETURN_U32(retVal); retVal = (talRecoveryActions_t)TALISE_waitForEvent(device, TAL_CLKPLL_LOCK, CLKPLL_LOCK_TIMEOUT_US, CLKPLL_LOCK_INTERVAL_US); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] \n", __FUNCTION__, __LINE__); /* Toggle DEC5 divider reset bit */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_0, 0, 0x01, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] \n", __FUNCTION__, __LINE__); /* Program FIR filters after CLKPLL locked */ if (device->devStateInfo.profilesValid & TX_PROFILE_VALID) { retVal = (talRecoveryActions_t)TALISE_setTxPfirSyncClk(device, &init->tx.txProfile); IF_ERR_RETURN_U32(retVal); if (init->tx.txProfile.txFir.numFirCoefs > 0) { retVal = (talRecoveryActions_t)TALISE_programFir(device, TAL_TX1TX2_FIR, &init->tx.txProfile.txFir); IF_ERR_RETURN_U32(retVal); } } printf("[%s,%d] \n", __FUNCTION__, __LINE__); if (((device->devStateInfo.profilesValid & RX_PROFILE_VALID) > 0) || ((device->devStateInfo.profilesValid & ORX_PROFILE_VALID) > 0)) { retVal = (talRecoveryActions_t)TALISE_setRxPfirSyncClk(device, &init->rx.rxProfile, &init->obsRx.orxProfile); IF_ERR_RETURN_U32(retVal); } printf("[%s,%d] !\n", __FUNCTION__, __LINE__); if (device->devStateInfo.profilesValid & RX_PROFILE_VALID) { printf("[%s,%d] \n", __FUNCTION__, __LINE__); if (init->rx.rxProfile.rxFir.numFirCoefs > 0) { printf("[%s,%d] \n", __FUNCTION__, __LINE__); retVal = (talRecoveryActions_t)TALISE_programFir(device, TAL_RX1RX2_FIR, &init->rx.rxProfile.rxFir); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] \n", __FUNCTION__, __LINE__); /* Load Rx gain table */ retVal = (talRecoveryActions_t)TALISE_programRxGainTable(device, &rxGainTable[0], (sizeof(rxGainTable) / sizeof(taliseRxGainTable_t)), TAL_RX1RX2); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] \n", __FUNCTION__, __LINE__); retVal = (talRecoveryActions_t)TALISE_setRxManualGain(device, TAL_RX1, init->rx.rxGainCtrl.rx1GainIndex); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] \n", __FUNCTION__, __LINE__); retVal = (talRecoveryActions_t)TALISE_setRxManualGain(device, TAL_RX2, init->rx.rxGainCtrl.rx2GainIndex); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] \n", __FUNCTION__, __LINE__); /* Enable Digital gain for Rx and ObsRx gain tables */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_DIGITAL_GAIN_CONFIG, 0x80); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); printf("[%s,%d] \n", __FUNCTION__, __LINE__); } } printf("[%s,%d] \n", __FUNCTION__, __LINE__); if (device->devStateInfo.profilesValid & ORX_PROFILE_VALID) { if (init->obsRx.orxProfile.rxFir.numFirCoefs > 0) {/* if pointer to orx rxFIR is valid */ retVal = (talRecoveryActions_t)TALISE_programFir(device, TAL_OBSRX1RX2_LOOPBACK_FIR, &init->obsRx.orxProfile.rxFir); IF_ERR_RETURN_U32(retVal); /* Load ORx gain table */ retVal = (talRecoveryActions_t)TALISE_programOrxGainTable(device, &orxGainTable[0], (sizeof(orxGainTable) / sizeof(taliseOrxGainTable_t)), TAL_ORX1ORX2); IF_ERR_RETURN_U32(retVal); retVal = (talRecoveryActions_t)TALISE_setObsRxManualGain(device, TAL_ORX1, init->obsRx.orxGainCtrl.orx1GainIndex); IF_ERR_RETURN_U32(retVal); retVal = (talRecoveryActions_t)TALISE_setObsRxManualGain(device, TAL_ORX2, init->obsRx.orxGainCtrl.orx2GainIndex); IF_ERR_RETURN_U32(retVal); /* Enable Digital gain for Rx and ObsRx gain tables */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_DIGITAL_GAIN_CONFIG, 0x80); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } } printf("[%s,%d] \n", __FUNCTION__, __LINE__); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_RCAL_CONTROL, 0x07); /* Set RCAL code to nominal */ retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* If Valid Rx Profile or valid ObsRx profile, setup serializers */ if ((device->devStateInfo.profilesValid & RX_PROFILE_VALID) || (device->devStateInfo.profilesValid & ORX_PROFILE_VALID)) { retVal = (talRecoveryActions_t)TALISE_setupSerializers(device, init); IF_ERR_RETURN_U32(retVal); } if ((device->devStateInfo.profilesValid & RX_PROFILE_VALID) && (init->rx.rxChannels != TAL_RXOFF)) { /* save the Np states for use in slicer gain compensation management */ if ((init->rx.framerSel == TAL_FRAMER_A) || (init->rx.framerSel == TAL_FRAMER_A_AND_B)) { device->devStateInfo.rxFramerNp = init->jesd204Settings.framerA.Np; } else { device->devStateInfo.rxFramerNp = init->jesd204Settings.framerB.Np; } retVal = (talRecoveryActions_t)TALISE_setupJesd204bFramer(device, init, init->rx.framerSel); IF_ERR_RETURN_U32(retVal); /* set the ADC crossbar: Q/I data assigned to even/odd converters to account for I/Q swap in DUT */ if (init->rx.rxChannels == TAL_RX2) { /* In real IF mode, send Rx2 I data to converter 0 */ if ((init->rx.rxProfile.rxDdcMode == TAL_RXDDC_INT2_REALIF) || (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_DEC2_REALIF) || (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_FILTERONLY_REALIF) || (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_BYPASS_REALIF)) { adcXbar.conv0 = TAL_ADC_RX2_I; adcXbar.conv1 = TAL_ADC_RX2_Q; adcXbar.conv2 = TAL_ADC_DUALBAND_RX2_BAND_B_I; adcXbar.conv3 = TAL_ADC_DUALBAND_RX2_BAND_B_Q; adcXbar.conv4 = TAL_ADC_RX1_I; adcXbar.conv5 = TAL_ADC_RX1_Q; adcXbar.conv6 = TAL_ADC_DUALBAND_RX1_BAND_B_I; adcXbar.conv7 = TAL_ADC_DUALBAND_RX1_BAND_B_Q; } else { adcXbar.conv0 = TAL_ADC_RX2_Q; adcXbar.conv1 = TAL_ADC_RX2_I; adcXbar.conv2 = TAL_ADC_DUALBAND_RX2_BAND_B_Q; adcXbar.conv3 = TAL_ADC_DUALBAND_RX2_BAND_B_I; adcXbar.conv4 = TAL_ADC_RX1_Q; adcXbar.conv5 = TAL_ADC_RX1_I; adcXbar.conv6 = TAL_ADC_DUALBAND_RX1_BAND_B_Q; adcXbar.conv7 = TAL_ADC_DUALBAND_RX1_BAND_B_I; } } else if (init->rx.rxChannels == TAL_RX1) { /* In real IF mode, send Rx1 I data to converter 0 */ if ((init->rx.rxProfile.rxDdcMode == TAL_RXDDC_INT2_REALIF) || (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_DEC2_REALIF) || (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_FILTERONLY_REALIF) || (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_BYPASS_REALIF)) { adcXbar.conv0 = TAL_ADC_RX1_I; adcXbar.conv1 = TAL_ADC_RX1_Q; adcXbar.conv2 = TAL_ADC_DUALBAND_RX1_BAND_B_I; adcXbar.conv3 = TAL_ADC_DUALBAND_RX1_BAND_B_Q; adcXbar.conv4 = TAL_ADC_RX2_I; adcXbar.conv5 = TAL_ADC_RX2_Q; adcXbar.conv6 = TAL_ADC_DUALBAND_RX2_BAND_B_I; adcXbar.conv7 = TAL_ADC_DUALBAND_RX2_BAND_B_Q; } else { adcXbar.conv0 = TAL_ADC_RX1_Q; adcXbar.conv1 = TAL_ADC_RX1_I; adcXbar.conv2 = TAL_ADC_DUALBAND_RX1_BAND_B_Q; adcXbar.conv3 = TAL_ADC_DUALBAND_RX1_BAND_B_I; adcXbar.conv4 = TAL_ADC_RX2_Q; adcXbar.conv5 = TAL_ADC_RX2_I; adcXbar.conv6 = TAL_ADC_DUALBAND_RX2_BAND_B_Q; adcXbar.conv7 = TAL_ADC_DUALBAND_RX2_BAND_B_I; } } else { /* In real IF mode, send Rx1 I data to converter 0, Rx2 I data on converter 1 */ if ((init->rx.rxProfile.rxDdcMode == TAL_RXDDC_INT2_REALIF) || (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_DEC2_REALIF) || (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_FILTERONLY_REALIF) || (init->rx.rxProfile.rxDdcMode == TAL_RXDDC_BYPASS_REALIF)) { adcXbar.conv0 = TAL_ADC_RX1_I; adcXbar.conv1 = TAL_ADC_RX2_I; adcXbar.conv2 = TAL_ADC_RX1_Q; adcXbar.conv3 = TAL_ADC_RX2_Q; adcXbar.conv4 = TAL_ADC_DUALBAND_RX1_BAND_B_I; adcXbar.conv5 = TAL_ADC_DUALBAND_RX2_BAND_B_I; adcXbar.conv6 = TAL_ADC_DUALBAND_RX1_BAND_B_Q; adcXbar.conv7 = TAL_ADC_DUALBAND_RX2_BAND_B_Q; } else { adcXbar.conv0 = TAL_ADC_RX1_Q; adcXbar.conv1 = TAL_ADC_RX1_I; adcXbar.conv2 = TAL_ADC_RX2_Q; adcXbar.conv3 = TAL_ADC_RX2_I; adcXbar.conv4 = TAL_ADC_DUALBAND_RX1_BAND_B_Q; adcXbar.conv5 = TAL_ADC_DUALBAND_RX1_BAND_B_I; adcXbar.conv6 = TAL_ADC_DUALBAND_RX2_BAND_B_Q; adcXbar.conv7 = TAL_ADC_DUALBAND_RX2_BAND_B_I; } } retVal = (talRecoveryActions_t)TALISE_setupAdcSampleXbar(device, init->rx.framerSel, adcXbar); IF_ERR_RETURN_U32(retVal); /* Initialize DDC modes */ retVal = talInitializeDdc(device, init); IF_ERR_RETURN(retVal); } if (device->devStateInfo.profilesValid & ORX_PROFILE_VALID) { /* save the Np states for use in slicer gain compensation management */ if ((init->obsRx.framerSel == TAL_FRAMER_A) || (init->obsRx.framerSel == TAL_FRAMER_A_AND_B)) { /* Only Setup JESD Framer if serializer Lanes are enabled for Framer A ORx path */ if (init->jesd204Settings.framerA.serializerLanesEnabled > 0) { device->devStateInfo.orxFramerNp = init->jesd204Settings.framerA.Np; retVal = (talRecoveryActions_t)TALISE_setupJesd204bFramer(device, init, init->obsRx.framerSel); IF_ERR_RETURN_U32(retVal); } } else { /* Only Setup JESD Framer if serializer Lanes are enabled for Framer B ORx path */ if (init->jesd204Settings.framerB.serializerLanesEnabled > 0) { device->devStateInfo.orxFramerNp = init->jesd204Settings.framerB.Np; retVal = (talRecoveryActions_t)TALISE_setupJesd204bFramer(device, init, init->obsRx.framerSel); IF_ERR_RETURN_U32(retVal); } } /* set the ADC crossbar: Q/I data assigned to even/odd converters to account for I/Q swap in DUT */ if ((device->devStateInfo.orxAdcStitchingEnabled == 0 ) && (init->obsRx.obsRxChannelsEnable == TAL_ORX2)) { adcXbar.conv0 = TAL_ADC_RX2_Q; adcXbar.conv1 = TAL_ADC_RX2_I; adcXbar.conv2 = TAL_ADC_RX1_Q; adcXbar.conv3 = TAL_ADC_RX1_I; adcXbar.conv4 = TAL_ADC_DUALBAND_RX2_BAND_B_Q; adcXbar.conv5 = TAL_ADC_DUALBAND_RX2_BAND_B_I; adcXbar.conv6 = TAL_ADC_DUALBAND_RX1_BAND_B_Q; adcXbar.conv7 = TAL_ADC_DUALBAND_RX1_BAND_B_I; } else { adcXbar.conv0 = TAL_ADC_RX1_Q; adcXbar.conv1 = TAL_ADC_RX1_I; adcXbar.conv2 = TAL_ADC_RX2_Q; adcXbar.conv3 = TAL_ADC_RX2_I; adcXbar.conv4 = TAL_ADC_DUALBAND_RX1_BAND_B_Q; adcXbar.conv5 = TAL_ADC_DUALBAND_RX1_BAND_B_I; adcXbar.conv6 = TAL_ADC_DUALBAND_RX2_BAND_B_Q; adcXbar.conv7 = TAL_ADC_DUALBAND_RX2_BAND_B_I; } retVal = (talRecoveryActions_t)TALISE_setupAdcSampleXbar(device, init->obsRx.framerSel, adcXbar); IF_ERR_RETURN_U32(retVal); } if ((device->devStateInfo.profilesValid & TX_PROFILE_VALID) && (init->tx.txChannels != TAL_TXOFF)) { retVal = (talRecoveryActions_t)TALISE_setupDeserializers(device, init); IF_ERR_RETURN_U32(retVal); /* set the DAC sample crossbars */ if (init->tx.deframerSel == TAL_DEFRAMER_A) { if ((init->tx.txChannels == TAL_TX1) || (init->tx.txChannels == TAL_TX1TX2)) { dacXbar.dacChanI = TAL_DEFRAMERA_OUT0; dacXbar.dacChanQ = TAL_DEFRAMERA_OUT1; retVal = (talRecoveryActions_t)TALISE_setupDacSampleXbar(device, TAL_TX1, dacXbar); IF_ERR_RETURN_U32(retVal); dacXbar.dacChanI = TAL_DEFRAMERA_OUT2; dacXbar.dacChanQ = TAL_DEFRAMERA_OUT3; retVal = (talRecoveryActions_t)TALISE_setupDacSampleXbar(device, TAL_TX2, dacXbar); IF_ERR_RETURN_U32(retVal); } if (init->tx.txChannels == TAL_TX2) { dacXbar.dacChanI = TAL_DEFRAMERA_OUT2; dacXbar.dacChanQ = TAL_DEFRAMERA_OUT3; retVal = (talRecoveryActions_t)TALISE_setupDacSampleXbar(device, TAL_TX1, dacXbar); IF_ERR_RETURN_U32(retVal); dacXbar.dacChanI = TAL_DEFRAMERA_OUT0; dacXbar.dacChanQ = TAL_DEFRAMERA_OUT1; retVal = (talRecoveryActions_t)TALISE_setupDacSampleXbar(device, TAL_TX2, dacXbar); IF_ERR_RETURN_U32(retVal); } } if (init->tx.deframerSel == TAL_DEFRAMER_B) { if ((init->tx.txChannels == TAL_TX1) || (init->tx.txChannels == TAL_TX1TX2)) { dacXbar.dacChanI = TAL_DEFRAMERB_OUT0; dacXbar.dacChanQ = TAL_DEFRAMERB_OUT1; retVal = (talRecoveryActions_t)TALISE_setupDacSampleXbar(device, TAL_TX1, dacXbar); IF_ERR_RETURN_U32(retVal); dacXbar.dacChanI = TAL_DEFRAMERB_OUT2; dacXbar.dacChanQ = TAL_DEFRAMERB_OUT3; retVal = (talRecoveryActions_t)TALISE_setupDacSampleXbar(device, TAL_TX2, dacXbar); IF_ERR_RETURN_U32(retVal); } if (init->tx.txChannels == TAL_TX2) { dacXbar.dacChanI = TAL_DEFRAMERB_OUT2; dacXbar.dacChanQ = TAL_DEFRAMERB_OUT3; retVal = (talRecoveryActions_t)TALISE_setupDacSampleXbar(device, TAL_TX1, dacXbar); IF_ERR_RETURN_U32(retVal); dacXbar.dacChanI = TAL_DEFRAMERB_OUT0; dacXbar.dacChanQ = TAL_DEFRAMERB_OUT1; retVal = (talRecoveryActions_t)TALISE_setupDacSampleXbar(device, TAL_TX2, dacXbar); IF_ERR_RETURN_U32(retVal); } } if (init->tx.deframerSel == TAL_DEFRAMER_A_AND_B) { if ((init->jesd204Settings.deframerA.M == 4) || (init->jesd204Settings.deframerB.M == 4)) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_FRAMER_A_AND_B_INV_M_PARM, retVal, TALACT_ERR_CHECK_PARAM); } else if ((init->tx.txChannels == TAL_TX1TX2) && (init->jesd204Settings.deframerA.M == 2) && (init->jesd204Settings.deframerB.M == 2)) { dacXbar.dacChanI = TAL_DEFRAMERA_OUT0; dacXbar.dacChanQ = TAL_DEFRAMERA_OUT1; retVal = (talRecoveryActions_t)TALISE_setupDacSampleXbar(device, TAL_TX1, dacXbar); IF_ERR_RETURN_U32(retVal); dacXbar.dacChanI = TAL_DEFRAMERB_OUT0; dacXbar.dacChanQ = TAL_DEFRAMERB_OUT1; retVal = (talRecoveryActions_t)TALISE_setupDacSampleXbar(device, TAL_TX2, dacXbar); IF_ERR_RETURN_U32(retVal); } } if ((init->tx.deframerSel == TAL_DEFRAMER_A) || (init->tx.deframerSel == TAL_DEFRAMER_A_AND_B)) { retVal = (talRecoveryActions_t)TALISE_setupJesd204bDeframer(device, init, TAL_DEFRAMER_A); IF_ERR_RETURN_U32(retVal); } if ((init->tx.deframerSel == TAL_DEFRAMER_B) || (init->tx.deframerSel == TAL_DEFRAMER_A_AND_B)) { retVal = (talRecoveryActions_t)TALISE_setupJesd204bDeframer(device, init, TAL_DEFRAMER_B); IF_ERR_RETURN_U32(retVal); } halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_GAIN_VALID_OVERRIDES, 0x88); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); retVal = (talRecoveryActions_t)TALISE_setTxAttenuation(device, TAL_TX1, init->tx.tx1Atten_mdB); IF_ERR_RETURN_U32(retVal); retVal = (talRecoveryActions_t)TALISE_setTxAttenuation(device, TAL_TX2, init->tx.tx2Atten_mdB); IF_ERR_RETURN_U32(retVal); } /* Set RxFE LO Common mode */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_RXFE1_LOCM, 0x30); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_RXFE2_LOCM, 0x30); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Setup thresholds needed by ARM calibrations */ /* ULB threshold is set to 3db below full scale of ADC */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_UPPER_LEVEL_BLOCKER_THRESHOLD, ULB_THRESHOLD); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* ULB2 is 3db above ULB threshold */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_UPPER_LEVEL_BLOCKER_THRESHOLD2, ULB2_THRESHOLD); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* LLB is 3db below ULB threshold */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_LOWER_LEVEL_BLOCKER_THRESHOLD, LLB_THRESHOLD); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* LLB2 is 3db above LLB threshold */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_LOWER_LEVEL_BLOCKER_THRESHOLD2, LLB2_THRESHOLD); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_ULB_COUNT_THRESHOLD, 0x06); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_DEC_OVERLOAD_CONFIG1, 0x91); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_DEC_OVERLOAD_UPPER_THRESHOLD, 0xB5); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_ADC_HIGH_OVRG_COUNT_THRESHOLD, 0x06); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_AGC_CONFIG1, 0x04, 0x3F, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_DEC_OVERLOAD_CONFIG2, 0x03, 0x03, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Set gain update counter for 1ms. */ /* Calculate AGC clock rate - Use same equation as used for txAttenClock_Hz in TALISE_initDigitalClocks*/ if (device->devStateInfo.clocks.hsDigClkDiv4or5_Hz > 500000000) { agcClock_Hz = (device->devStateInfo.clocks.hsDigClkDiv4or5_Hz / 4); /* div 4 */ } else if (device->devStateInfo.clocks.hsDigClkDiv4or5_Hz > 250000000) { agcClock_Hz = (device->devStateInfo.clocks.hsDigClkDiv4or5_Hz / 2); /* div 2 */ } else { agcClock_Hz = device->devStateInfo.clocks.hsDigClkDiv4or5_Hz; /* div 1 */ } gainUpdateCount = (agcClock_Hz / 1000); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_GAIN_UPDATE_COUNTER1, (gainUpdateCount & 0xFF)); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_GAIN_UPDATE_COUNTER2, ((gainUpdateCount >> 8) & 0xFF)); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_GAIN_UPDATE_COUNTER3, ((gainUpdateCount >> 16) & 0x3F)); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_SLOWLOOP_SETTLING_DELAY, 0x10); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_SLOWLOOP_CONFIG, 0x00); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_AGC_UNDERRANGE1, 0x02); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_AGC_MANUAL_GAIN_CONTROL_CONFIG_RX1, 1, 0x02, 1); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_AGC_MANUAL_GAIN_CONTROL_CONFIG_RX2, 1, 0x02, 1); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Options to disable Tx data if PLL unlocks */ if ((init->tx.disTxDataIfPllUnlock != TAL_TXDIS_TX_NOT_DISABLED) && (init->tx.disTxDataIfPllUnlock != TAL_TXDIS_TX_ZERO_DATA) && (init->tx.disTxDataIfPllUnlock != TAL_TXDIS_TX_RAMP_DOWN_TO_ZERO)) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERTXPFILE_INV_DISONPLLUNLOCK, retVal, TALACT_ERR_CHECK_PARAM); } halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_TX_DP_MASK_CH1, (uint8_t)init->tx.disTxDataIfPllUnlock, 0x06, 1); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_TX_DP_MASK_CH2, (uint8_t)init->tx.disTxDataIfPllUnlock, 0x06, 1); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Set Talise API state container information */ device->devStateInfo.devState = (taliseStates_t)(device->devStateInfo.devState | TAL_STATE_INITIALIZED); device->devStateInfo.initializedChannels = (init->rx.rxChannels & 3); device->devStateInfo.initializedChannels |= ((init->obsRx.obsRxChannelsEnable & 3) << 2); device->devStateInfo.initializedChannels |= ((init->tx.txChannels & 3) << 6); device->devStateInfo.txInputRate_kHz = init->tx.txProfile.txInputRate_kHz; device->devStateInfo.rxDdcMode = init->rx.rxProfile.rxDdcMode; /* Find the Rx Framer and save the Rx Framer M value */ if (init->rx.framerSel == TAL_FRAMER_A) { device->devStateInfo.rxTotalM = init->jesd204Settings.framerA.M; } else if (init->rx.framerSel == TAL_FRAMER_B) { device->devStateInfo.rxTotalM = init->jesd204Settings.framerB.M; } else if (init->rx.framerSel == TAL_FRAMER_A_AND_B) { device->devStateInfo.rxTotalM = init->jesd204Settings.framerA.M + init->jesd204Settings.framerB.M; } device->devStateInfo.rxBandwidth_Hz = init->rx.rxProfile.rfBandwidth_Hz; device->devStateInfo.txBandwidth_Hz = init->tx.txProfile.rfBandwidth_Hz; device->devStateInfo.orxBandwidth_Hz = init->obsRx.orxProfile.rfBandwidth_Hz; /* If higher priority retVal has no error, allow possible lower priority warning to be returned */ if (retVal == TALACT_NO_ACTION) { retVal = (talRecoveryActions_t)retValWarn; } return (uint32_t)retVal; } uint32_t TALISE_shutdown(taliseDevice_t *device) { talRecoveryActions_t retVal = TALACT_NO_ACTION; retVal = (talRecoveryActions_t)TALISE_resetDevice(device); IF_ERR_RETURN_U32(retVal); return (uint32_t)retVal; } uint32_t TALISE_getMultiChipSyncStatus(taliseDevice_t *device, uint8_t *mcsStatus) { talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; #if TALISE_VERBOSE halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getMultiChipSyncStatus()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif /* null pointer check */ if (mcsStatus == NULL) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_CHECKGETMCS_STATUS_NULL_PARM, retVal, TALACT_ERR_CHECK_PARAM); } else { halError = talSpiReadByte(device->devHalInfo, TALISE_ADDR_MCS_STATUS, mcsStatus); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } return (uint32_t)retVal; } uint32_t TALISE_enableMultichipSync(taliseDevice_t *device, uint8_t enableMcs, uint8_t *mcsStatus) { talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; uint8_t clkPllSdmBypass = 0; uint8_t mcsEnable = 0x9B; /* Keeps RF LO divider enabled[7] Enable MCS[4] reset Device Clock divider[3] Digital clocks[1] JESD204 SYSREF[0] */ int err_flg; #if TALISE_VERBOSE halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_enableMultichipSync()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif if (enableMcs > 0) { /* If CLKPLL SDM not bypassed, reset CLKPLL SDM as well. */ halError = ADIHAL_spiReadField(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_DIVIDER_INT_BYTE1, &clkPllSdmBypass, 0x40, 6); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); err_flg = check_err_state(retVal); printf("retVal=0x%x (%s) [line %d]\n",retVal, str_err[err_flg], __LINE__); IF_ERR_RETURN_U32(retVal); if (clkPllSdmBypass == 0) { mcsEnable |= 0x04; /* enable MCS for CLKPLL SDM */ } halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_MCS_CONTROL, mcsEnable); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); err_flg = check_err_state(retVal); printf("retVal=0x%x (%s) [line %d]\n",retVal, str_err[err_flg], __LINE__); IF_ERR_RETURN_U32(retVal); /* Prime the K1 input sync (clear bit 4, then set bit 4) */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_MCS_CONTROL_2, 0, 0x10, 4); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); err_flg = check_err_state(retVal); printf("retVal=0x%x (%s) [line %d]\n",retVal, str_err[err_flg], __LINE__); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_MCS_CONTROL_2, 1, 0x10, 4); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); err_flg = check_err_state(retVal); printf("retVal=0x%x (%s) [line %d]\n",retVal, str_err[err_flg], __LINE__); IF_ERR_RETURN_U32(retVal); } else { /* If enableMcs = 0 (MCS complete), reset JESD204 serializer */ /* Toggle Serializer SRESET */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_JESD_FRAMER_SRST_CFG, 0xFF); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); err_flg = check_err_state(retVal); printf("retVal=0x%x (%s) [line %d]\n",retVal, str_err[err_flg], __LINE__); IF_ERR_RETURN_U32(retVal); /* Allow framer data to output to serializer (clear reset)*/ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_JESD_FRAMER_SRST_CFG, 0x0F); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); err_flg = check_err_state(retVal); printf("retVal=0x%x (%s) [line %d]\n",retVal, str_err[err_flg], __LINE__); IF_ERR_RETURN_U32(retVal); } /* if mcsStatus is a valid pointer, return the MCS status */ if (mcsStatus != NULL) { /* 位 (Bit) 名称 (Bit Name) 描述 (Description) 7 (保留) 未定义。 6 (保留) 未定义。 5 (保留) 未定义。 4 (保留) 未定义。 3 Device clock divider sync 此位置1表示多芯片同步设备时钟分频器同步已完成。 1 2 CLKPLL SDM sync 此位置1表示多芯片同步时钟PLL Σ-Δ调制器(分数模式)同步已完成。 0 1 Digital clocks sync 此位置1表示多芯片同步数字时钟分频器同步已完成。 1 0 JESD SYSREF sync 此位置1表示多芯片同步JESD204B SYSREF同步已完成。 1 */ halError = talSpiReadByte(device->devHalInfo, TALISE_ADDR_MCS_STATUS, mcsStatus); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); err_flg = check_err_state(retVal); printf("retVal=0x%x (%s) [line %d] mcsStatus=0x%x\n\n",retVal, str_err[err_flg], __LINE__, (*mcsStatus)); IF_ERR_RETURN_U32(retVal); } return (uint32_t)retVal; } uint32_t TALISE_programFir(taliseDevice_t *device, talisefirName_t filterToProgram, taliseFir_t *firFilter) { talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; uint8_t firBankSel = 0; uint8_t i = 0; uint8_t numTapsReg = 0; uint8_t nTapMul = 24; uint8_t maxNumTaps = 80; uint8_t filterGain = 0; uint32_t addrIndex = 0; uint32_t spiBufferSize = ((HAL_SPIWRITEARRAY_BUFFERSIZE / 6) * 6); /* Make buffer size a multiple of 6 */ uint16_t addrArray[HAL_SPIWRITEARRAY_BUFFERSIZE] = {0}; uint8_t dataArray[HAL_SPIWRITEARRAY_BUFFERSIZE] = {0}; static const uint8_t COEF_WRITE_EN = 0x40; static const uint8_t PROGRAM_CLK_EN = 0x80; static const uint8_t TXFIR_BANKA = 0x01; static const uint8_t TXFIR_BANKB = 0x02; static const uint8_t RXFIR_BANKA = 0x04; static const uint8_t RXFIR_BANKB = 0x08; static const uint8_t RXFIR_BANKC = 0x10; #if TALISE_VERBOSE halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_programFir()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif /* Error checking, #taps less than max number of taps allowed.*/ if (firFilter->numFirCoefs == 0) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_PROGRAMFIR_COEFS_NULL, retVal, TALACT_ERR_CHECK_PARAM); } /* firBankSelect and assignment of maxNumTaps, nTapMul and address firAddr.*/ switch(filterToProgram) { case TAL_TX1_FIR: maxNumTaps = 80; firBankSel = TXFIR_BANKA; nTapMul = 20; break; case TAL_TX2_FIR: maxNumTaps = 80; firBankSel = TXFIR_BANKB; nTapMul = 20; break; case TAL_TX1TX2_FIR: maxNumTaps = 80; firBankSel = (TXFIR_BANKA | TXFIR_BANKB); nTapMul = 20; break; case TAL_RX1_FIR: /*check for valid cases and shares the exact same code as case RX1RX2_FIR */ case TAL_RX2_FIR: /*check for valid cases and shares the exact same code as case RX1RX2_FIR */ case TAL_RX1RX2_FIR: maxNumTaps = 72; firBankSel = RXFIR_BANKA; nTapMul = 24; break; case TAL_OBSRX1_FIR: /*check for valid cases and shares the exact same code as case OBSRX1RX2_FIR */ case TAL_OBSRX2_FIR: /*check for valid cases and shares the exact same code as case OBSRX1RX2_FIR */ case TAL_OBSRX1RX2_FIR: maxNumTaps = 72; firBankSel = RXFIR_BANKB; nTapMul = 24; break; case TAL_LOOPBACK_FIR: maxNumTaps = 72; firBankSel = RXFIR_BANKC; nTapMul = 24; break; case TAL_RX1RX2_LOOPBACK_FIR: maxNumTaps = 72; firBankSel = (RXFIR_BANKA | RXFIR_BANKC); nTapMul = 24; break; case TAL_OBSRX1RX2_LOOPBACK_FIR: maxNumTaps = 72; firBankSel = (RXFIR_BANKB | RXFIR_BANKC); nTapMul = 24; break; default: return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_PROGRAMFIR_INV_FIRNAME_PARM, retVal, TALACT_ERR_CHECK_PARAM); } /* Verification for the structure numFirCoefs */ if (firFilter->numFirCoefs > maxNumTaps) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_PROGRAMFIR_INV_NUMTAPS_PARM, retVal, TALACT_ERR_CHECK_PARAM); } /* Calculate register value for number of Taps */ if (((firFilter->numFirCoefs % nTapMul) == 0) && (firFilter->numFirCoefs > 0)) { numTapsReg = (firFilter->numFirCoefs / nTapMul) - 1; } else { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_PROGRAMFIR_INV_NUMTAPS_PARM, retVal, TALACT_ERR_CHECK_PARAM); } /* Select which FIR filter to program coeffs for and enable the programming clock*/ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_PFIR_COEFF_CTL, (PROGRAM_CLK_EN | firBankSel)); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* write filter coefficients */ addrIndex = 0; for (i = 0; i < firFilter->numFirCoefs; i++) { addrArray[addrIndex] = TALISE_ADDR_PFIR_COEFF_ADDR; dataArray[addrIndex++] = (i * 2); addrArray[addrIndex] = TALISE_ADDR_PFIR_COEFF_DATA; dataArray[addrIndex++] = (firFilter->coefs[i] & 0xFF); addrArray[addrIndex] = TALISE_ADDR_PFIR_COEFF_CTL; dataArray[addrIndex++] = (PROGRAM_CLK_EN | COEF_WRITE_EN | firBankSel); addrArray[addrIndex] = TALISE_ADDR_PFIR_COEFF_ADDR; dataArray[addrIndex++] = ((i * 2) + 1); addrArray[addrIndex] = TALISE_ADDR_PFIR_COEFF_DATA; dataArray[addrIndex++] = ((firFilter->coefs[i] >> 8) & 0xFF); addrArray[addrIndex] = TALISE_ADDR_PFIR_COEFF_CTL; dataArray[addrIndex++] = (PROGRAM_CLK_EN | COEF_WRITE_EN | firBankSel); /* Send full buffer size when possible */ /* spiBufferSize set to multiple of 6 at top of function */ if (addrIndex >= spiBufferSize) { halError = talSpiWriteBytes(device->devHalInfo, &addrArray[0], &dataArray[0], addrIndex); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); addrIndex = 0; } } if (addrIndex > 0) { halError = talSpiWriteBytes(device->devHalInfo, &addrArray[0], &dataArray[0], addrIndex); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } /* clear Program clock enable */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_PFIR_COEFF_CTL, firBankSel); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Set filter gain to be used */ switch (firFilter->gain_dB) { case TAL_FIR_GAIN_NEG12_DB: filterGain = 0x00; break; case TAL_FIR_GAIN_NEG6_DB: filterGain = 0x01; break; case TAL_FIR_GAIN_0_DB: filterGain = 0x02; break; case TAL_FIR_GAIN_POS6_DB: filterGain = 0x03; break; default: return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_RXFIR_INV_GAIN_PARM, retVal, TALACT_ERR_CHECK_PARAM); } /* write filter gain and #taps if TX, else is RX */ if ((filterToProgram == TAL_TX1_FIR) || (filterToProgram == TAL_TX2_FIR) || (filterToProgram == TAL_TX1TX2_FIR)) { /* Write number of Taps , Tx Filter gain*/ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_TX_FILTER_CONFIGURATION, (((numTapsReg & 0x3) << 5) | (filterGain & 0x3))); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } else { if ((firBankSel & RXFIR_BANKA) == RXFIR_BANKA) { /* Write FIR #taps and gain */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_RX_PFIR_BANK_A_SETTINGS, (((numTapsReg & 0x3) << 4) | ((filterGain & 0x03) << 2)), 0x3C, 0); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } if ((firBankSel & RXFIR_BANKB) == RXFIR_BANKB) { /* Write FIR #taps and gain */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_RX_PFIR_BANK_B_SETTINGS, (((numTapsReg & 0x3) << 4) | ((filterGain & 0x03) << 2)), 0x3C, 0); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } if ((firBankSel & RXFIR_BANKC) == RXFIR_BANKC) { /* Write FIR #taps and gain */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_RX_PFIR_BANK_C_SETTINGS, (((numTapsReg & 0x3) << 4) | ((filterGain & 0x03) << 2)), 0x3C, 0); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } } /* Set Mode mapping for RX, OBSRX or LOOPBACK */ if ((filterToProgram == TAL_RX1_FIR) || (filterToProgram == TAL_RX2_FIR) || (filterToProgram == TAL_RX1RX2_FIR) || (filterToProgram == TAL_RX1RX2_LOOPBACK_FIR)) { if (filterToProgram == TAL_RX1RX2_LOOPBACK_FIR) { /* Set Mode mapping for RX1 Rx2 and Loopback FIR Bank A */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_RX_PFIR_MODE_MAPPING1, 0x00); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } else { /* Set Mode mapping for RX1 Rx2 FIR Bank A */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_RX_PFIR_MODE_MAPPING1, 0x00, 0x0F, 0); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } } else if ((filterToProgram == TAL_OBSRX1_FIR) || (filterToProgram == TAL_OBSRX2_FIR) || (filterToProgram == TAL_OBSRX1RX2_FIR) || (filterToProgram == TAL_OBSRX1RX2_LOOPBACK_FIR)) { if (filterToProgram == TAL_OBSRX1RX2_LOOPBACK_FIR) { /* Set Mode mapping for Loopback FIR Bank B */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_RX_PFIR_MODE_MAPPING1, 0x01, 0xC0, 6); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } /* Set Mode mapping for Obs RxA and Obs RxA FIR Bank B */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_RX_PFIR_MODE_MAPPING2, 0x05); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } else if (filterToProgram == TAL_LOOPBACK_FIR) { /* Set Mode mapping for Loopback FIR Bank C */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_RX_PFIR_MODE_MAPPING1, 0x02, 0xC0, 6); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } return (uint32_t)retVal; } uint32_t TALISE_calculateDigitalClocks(taliseDevice_t *device, taliseDigClocks_t *digClocks) { talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; uint8_t hsDivTimes10 = 25; uint8_t hsClkDivHsDigClk4or5 = 20; uint32_t localHsDigClkDiv2_Hz = 0; uint32_t localHsDigClk4or5_Hz = 0; #if TALISE_VERBOSE halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_calculateDigitalClocks()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif device->devStateInfo.clocks.clkPllVcoFreq_kHz = digClocks->clkPllVcoFreq_kHz; device->devStateInfo.clocks.clkPllHsDiv = digClocks->clkPllHsDiv; device->devStateInfo.clocks.deviceClock_kHz = digClocks->deviceClock_kHz; switch(digClocks->clkPllHsDiv) { case TAL_HSDIV_2: hsDivTimes10 = 20; hsClkDivHsDigClk4or5 = 10; break; case TAL_HSDIV_2P5: hsDivTimes10 = 25; hsClkDivHsDigClk4or5 = 10; break; case TAL_HSDIV_3: hsDivTimes10 = 30; hsClkDivHsDigClk4or5 = 15; break; case TAL_HSDIV_4: hsDivTimes10 = 40; hsClkDivHsDigClk4or5 = 20; break; case TAL_HSDIV_5: hsDivTimes10 = 50; hsClkDivHsDigClk4or5 = 20; break; default: return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_CLKPLL_INV_HSDIV, retVal, TALACT_ERR_CHECK_PARAM ); } localHsDigClkDiv2_Hz = (uint32_t)((((((uint64_t)(digClocks->clkPllVcoFreq_kHz) * 1000) >> 1) / hsDivTimes10) * 10) >> 1); device->devStateInfo.clocks.hsDigClkDiv2_Hz = localHsDigClkDiv2_Hz; localHsDigClk4or5_Hz = (uint32_t)((((uint64_t)(digClocks->clkPllVcoFreq_kHz) * 1000) >> 1) / hsClkDivHsDigClk4or5); device->devStateInfo.clocks.hsDigClkDiv4or5_Hz = localHsDigClk4or5_Hz; return (uint32_t)retVal; } /** * \brief Verifies the Rx profile members are valid (in range) and calculates HS Dig Clock require for the Rx Profile * * Private helper function to verify the Rx profile members are valid (in range) * and calculates HS Dig Clock require for the Rx Profile * If the Rx profile IQ data rate = 0, it is assumed that the Rx profile is * not used. If Rx IQ data rate > 0, and Rx profile members are out of range, * the function stores the error code describing the error, and returns a * Recovery action to check the configuration settings. * * \pre This function is private and is not called directly by the user. * * \dep_begin * \dep{device->devHalInfo} * \dep_end * * \param device Structure pointer to Talise device data structure * \param rxProfile rxProfile settings to be verified * \param rxHsDigClk_kHz Return value of the calculated HS Dig Clock required by the Rx profile * * \retval TALACT_ERR_CHECK_PARAM Recovery action for bad parameter check * \retval TALACT_NO_ACTION Function completed successfully, no action required */ static talRecoveryActions_t talVerifyRxProfile(taliseDevice_t *device, taliseRxProfile_t *rxProfile, uint32_t *rxHsDigClk_kHz) { talRecoveryActions_t retVal = TALACT_NO_ACTION; uint8_t ddcMultiply = 1; uint8_t ddcDivide = 1; *rxHsDigClk_kHz = 0; /********************************/ /* Check for a valid Rx profile */ /********************************/ if ((rxProfile->rxOutputRate_kHz < 15000) || (rxProfile->rxOutputRate_kHz > 370000)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERRXPFILE_INV_IQRATE, retVal, TALACT_ERR_CHECK_PARAM); } if ((rxProfile->rfBandwidth_Hz < 15000000) || (rxProfile->rfBandwidth_Hz > 250000000)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERRXPFILE_INV_RFBW, retVal, TALACT_ERR_CHECK_PARAM); } if ((rxProfile->rhb1Decimation != 1) && (rxProfile->rhb1Decimation != 2)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERRXPFILE_INV_RHB1, retVal, TALACT_ERR_CHECK_PARAM); } if ((rxProfile->rxDec5Decimation != 4) && (rxProfile->rxDec5Decimation != 5)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERRXPFILE_INV_DEC5, retVal, TALACT_ERR_CHECK_PARAM); } if ((rxProfile->rxFirDecimation != 1) && (rxProfile->rxFirDecimation != 2) && (rxProfile->rxFirDecimation != 4)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERRXPFILE_INV_FIR, retVal, TALACT_ERR_CHECK_PARAM); } if ((rxProfile->rxFir.coefs == NULL) && (rxProfile->rxFirDecimation != 1)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERRXPFILE_INV_COEF, retVal, TALACT_ERR_CHECK_PARAM); } switch(rxProfile->rxDdcMode) { case TAL_RXDDC_BYPASS_REALIF: case TAL_RXDDC_BYPASS: ddcMultiply = 1; ddcDivide = 1; break; case TAL_RXDDC_DEC2_REALIF: case TAL_RXDDC_DEC2: ddcMultiply = 2; ddcDivide = 1; break; case TAL_RXDDC_INT2_REALIF: case TAL_RXDDC_INT2: ddcMultiply = 1; ddcDivide = 2; break; case TAL_RXDDC_FILTERONLY_REALIF: case TAL_RXDDC_FILTERONLY: ddcMultiply = 1; ddcDivide = 1; break; default: return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERRXPFILE_INV_DDC, retVal, TALACT_ERR_CHECK_PARAM ); } *rxHsDigClk_kHz = ( rxProfile->rxOutputRate_kHz * rxProfile->rxFirDecimation * rxProfile->rhb1Decimation * rxProfile->rxDec5Decimation * ddcMultiply ) / ddcDivide; return retVal; } /** * \brief Verifies the ORx profile members are valid (in range) in the init structure * * If the ORx profile IQ data rate = 0, it is assumed that the ORx profile is * not used. If ORx IQ data rate > 0, and ORx profile members are out of range, * the function stores the error code describing the error, and returns a * Recovery action to check the configuration settings. * * \pre This function is private and is not called directly by the user. * * \dep_begin * \dep{device->devHalInfo} * \dep_end * * \param device Structure pointer to Talise device data structure * \param orxProfile orxProfile settings to be verified * \param orxHsDigClk_kHz Return value of the calculated HS Dig Clock required by the ORx profile * * \retval TALACT_ERR_CHECK_PARAM Recovery action for bad parameter check * \retval TALACT_NO_ACTION Function completed successfully, no action required */ static talRecoveryActions_t talVerifyOrxProfile(taliseDevice_t *device, taliseORxProfile_t *orxProfile, uint32_t *orxHsDigClk_kHz) { talRecoveryActions_t retVal = TALACT_NO_ACTION; uint8_t ddcMultiply = 1; uint8_t ddcDivide = 1; *orxHsDigClk_kHz = 0; /********************************/ /* Check for a valid ORx profile */ /********************************/ if ((orxProfile->orxOutputRate_kHz < 15000) || (orxProfile->orxOutputRate_kHz > 500000)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERORXPFILE_INV_IQRATE, retVal, TALACT_ERR_CHECK_PARAM); } if ((orxProfile->rfBandwidth_Hz < 15000000) || (orxProfile->rfBandwidth_Hz > 460000000)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERORXPFILE_INV_RFBW, retVal, TALACT_ERR_CHECK_PARAM); } device->devStateInfo.orxAdcStitchingEnabled = (orxProfile->rfBandwidth_Hz > 200000000) ? 1 : 0; if ((orxProfile->rhb1Decimation != 1) && (orxProfile->rhb1Decimation != 2)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERORXPFILE_INV_RHB1, retVal, TALACT_ERR_CHECK_PARAM); } if ((orxProfile->rxDec5Decimation != 4) && (orxProfile->rxDec5Decimation != 5)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERORXPFILE_INV_DEC5, retVal, TALACT_ERR_CHECK_PARAM); } if ((orxProfile->rxFirDecimation != 1) && (orxProfile->rxFirDecimation != 2) && (orxProfile->rxFirDecimation != 4)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERORXPFILE_INV_FIR, retVal, TALACT_ERR_CHECK_PARAM); } if ((orxProfile->rxFir.coefs == NULL) && (orxProfile->rxFirDecimation != 1)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERORXPFILE_INV_COEF, retVal, TALACT_ERR_CHECK_PARAM); } switch(orxProfile->orxDdcMode) { case TAL_ORXDDC_DISABLED: ddcMultiply = 1; ddcDivide = 1; break; case TAL_ORXDDC_SUBSAMPLE_BY2: ddcMultiply = 2; ddcDivide = 1; break; default: return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERORXPFILE_INV_DDC, retVal, TALACT_ERR_CHECK_PARAM ); } *orxHsDigClk_kHz = (orxProfile->orxOutputRate_kHz * orxProfile->rxFirDecimation * orxProfile->rhb1Decimation * orxProfile->rxDec5Decimation * ddcMultiply) / ddcDivide; return retVal; } /** * \brief Verifies the Tx profile members are valid (in range) in the init structure * * If the Tx profile IQ data rate = 0, it is assumed that the Tx profile is * not used. If Tx IQ data rate > 0, and Tx profile members are out of range, * the function stores the error code describing the error, and returns a * Recovery action to check the configuration settings. * * \pre This function is private and is not called directly by the user. * * \dep_begin * \dep{device->devHalInfo} * \dep_end * * \param device Structure pointer to Talise device data structure * \param txProfile txProfile settings to be verified * \param txHsDigClk_kHz Return value of the calculated HS Dig Clock required by the Tx profile * * \retval TALACT_ERR_CHECK_PARAM Recovery action for bad parameter check * \retval TALACT_NO_ACTION Function completed successfully, no action required */ static talRecoveryActions_t talVerifyTxProfile(taliseDevice_t *device, taliseTxProfile_t *txProfile, uint32_t *txHsDigClk_kHz) { talRecoveryActions_t retVal = TALACT_NO_ACTION; *txHsDigClk_kHz = 0; /********************************/ /* Check for a valid Tx profile */ /********************************/ if ((txProfile->txInputRate_kHz < 15000) || (txProfile->txInputRate_kHz > 500000)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERTXPFILE_INV_IQRATE, retVal, TALACT_ERR_CHECK_PARAM); } if ((txProfile->rfBandwidth_Hz < 15000000) || (txProfile->rfBandwidth_Hz > 460000000)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERTXPFILE_INV_RFBW, retVal, TALACT_ERR_CHECK_PARAM); } if ((txProfile->thb1Interpolation != 1) && (txProfile->thb1Interpolation != 2)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERTXPFILE_INV_THB1, retVal, TALACT_ERR_CHECK_PARAM); } if ((txProfile->thb2Interpolation != 1) && (txProfile->thb2Interpolation != 2)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERTXPFILE_INV_THB2, retVal, TALACT_ERR_CHECK_PARAM); } if ((txProfile->thb3Interpolation != 1) && (txProfile->thb3Interpolation != 2)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERTXPFILE_INV_THB3, retVal, TALACT_ERR_CHECK_PARAM); } if ((txProfile->txInt5Interpolation != 1) && (txProfile->txInt5Interpolation != 5)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERTXPFILE_INV_INT5, retVal, TALACT_ERR_CHECK_PARAM); } /* Int5 and thb1/2/3 should be mutually exclusive */ if (((txProfile->txInt5Interpolation == 5) && ((txProfile->thb1Interpolation != 1) || (txProfile->thb2Interpolation != 1) || (txProfile->thb3Interpolation != 1))) || ((txProfile->txInt5Interpolation == 1) && (txProfile->thb1Interpolation == 1) && (txProfile->thb2Interpolation == 1) && (txProfile->thb3Interpolation == 1))) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERTXPFILE_INV_HBMUTEX, retVal, TALACT_ERR_CHECK_PARAM); } if ((txProfile->txFirInterpolation != 1) && (txProfile->txFirInterpolation != 2) && (txProfile->txFirInterpolation != 4)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERTXPFILE_INV_FIRIPL, retVal, TALACT_ERR_CHECK_PARAM); } if ((txProfile->txFir.coefs == NULL) && (txProfile->txFirInterpolation != 1)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERTXPFILE_INV_COEF, retVal, TALACT_ERR_CHECK_PARAM); } if((txProfile->dacDiv != 1) && (txProfile->dacDiv != 2)) { return talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERTXPFILE_INV_DACDIV, retVal, TALACT_ERR_CHECK_PARAM); } *txHsDigClk_kHz = (txProfile->txInputRate_kHz * txProfile->txFirInterpolation * txProfile->thb1Interpolation * txProfile->thb2Interpolation * txProfile->thb3Interpolation * txProfile->txInt5Interpolation * txProfile->dacDiv); return retVal; } uint32_t TALISE_verifyProfiles(taliseDevice_t *device, taliseInit_t *init) { talRecoveryActions_t retVal = TALACT_NO_ACTION; uint32_t rxHsDigClk_kHz = 0; uint32_t orxHsDigClk_kHz = 0; uint32_t txHsDigClk_kHz = 0; uint32_t hsDigClkDiv2_Hz = 0; uint32_t hsDigClk_kHz = 0; taliseRxProfile_t *rxProfile = NULL; taliseTxProfile_t *txProfile = NULL; taliseORxProfile_t *orxProfile = NULL; if (device == NULL) { /* Can not write to log since log function requires device data structure */ return (uint32_t)TALACT_ERR_CHECK_PARAM; } if (init == NULL) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_INV_NULL_INIT_PARAM, retVal, TALACT_ERR_CHECK_PARAM); } device->devStateInfo.profilesValid = 0; if(init->tx.txChannels != TAL_TXOFF) { txProfile = &init->tx.txProfile; retVal = talVerifyTxProfile(device, txProfile, &txHsDigClk_kHz); IF_ERR_RETURN_U32(retVal); } if(init->rx.rxChannels != TAL_RXOFF) { rxProfile = &init->rx.rxProfile; retVal = talVerifyRxProfile(device, rxProfile, &rxHsDigClk_kHz); IF_ERR_RETURN_U32(retVal); } if((init->obsRx.obsRxChannelsEnable != TAL_ORXOFF) || (init->tx.txChannels != TAL_TXOFF)) { orxProfile = &init->obsRx.orxProfile; retVal = talVerifyOrxProfile(device, orxProfile, &orxHsDigClk_kHz); IF_ERR_RETURN_U32(retVal); } if ((init->clocks.rfPllPhaseSyncMode != TAL_RFPLLMCS_NOSYNC) && (init->clocks.rfPllPhaseSyncMode != TAL_RFPLLMCS_INIT_AND_SYNC) && (init->clocks.rfPllPhaseSyncMode != TAL_RFPLLMCS_INIT_AND_1TRACK) && (init->clocks.rfPllPhaseSyncMode != TAL_RFPLLMCS_INIT_AND_CONTTRACK)) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERPFILE_INV_RFPLLMCSMODE, retVal, TALACT_ERR_CHECK_PARAM); } /* Verify HsDigClk needed by Rx/Tx/Orx profiles is possible based on CLKPLL * settings */ hsDigClkDiv2_Hz = device->devStateInfo.clocks.hsDigClkDiv2_Hz; hsDigClk_kHz = (hsDigClkDiv2_Hz / 500); /* time 2 and convert from Hz to kHz */ /* Verify Tx profile is valid */ if (txHsDigClk_kHz > 0) { if ((rxHsDigClk_kHz > 0) && (txHsDigClk_kHz != rxHsDigClk_kHz)) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERPFILE_TXHSCLK, retVal, TALACT_ERR_CHECK_PARAM); } if ((orxHsDigClk_kHz > 0) && (txHsDigClk_kHz != orxHsDigClk_kHz)) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERPFILE_TXHSCLK, retVal, TALACT_ERR_CHECK_PARAM); } if (hsDigClk_kHz != txHsDigClk_kHz) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERPFILE_TXHSCLK, retVal, TALACT_ERR_CHECK_PARAM); } device->devStateInfo.profilesValid |= TX_PROFILE_VALID; } /* Verify Rx profile is valid */ if (rxHsDigClk_kHz > 0) { if ((txHsDigClk_kHz > 0) && (rxHsDigClk_kHz != txHsDigClk_kHz)) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERPFILE_RXHSCLK, retVal, TALACT_ERR_CHECK_PARAM); } if ((orxHsDigClk_kHz > 0) && (rxHsDigClk_kHz != orxHsDigClk_kHz)) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERPFILE_RXHSCLK, retVal, TALACT_ERR_CHECK_PARAM); } if (hsDigClk_kHz != rxHsDigClk_kHz) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERPFILE_RXHSCLK, retVal, TALACT_ERR_CHECK_PARAM); } device->devStateInfo.profilesValid |= RX_PROFILE_VALID; } /* Verify ORx profile is valid */ if (orxHsDigClk_kHz > 0) { if ((txHsDigClk_kHz > 0) && (orxHsDigClk_kHz != txHsDigClk_kHz)) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERPFILE_ORXHSCLK, retVal, TALACT_ERR_CHECK_PARAM); } if ((rxHsDigClk_kHz > 0) && (orxHsDigClk_kHz != rxHsDigClk_kHz)) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERPFILE_ORXHSCLK, retVal, TALACT_ERR_CHECK_PARAM); } if (hsDigClk_kHz != orxHsDigClk_kHz) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERPFILE_ORXHSCLK, retVal, TALACT_ERR_CHECK_PARAM); } device->devStateInfo.profilesValid |= ORX_PROFILE_VALID; } return (uint32_t)retVal; } uint32_t TALISE_setSpiSettings(taliseDevice_t *device, taliseSpiSettings_t *spi) { talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; uint8_t spiReg = 0; #if TALISE_VERBOSE halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_setSpiSettings()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif if (spi->MSBFirst == 0) { spiReg |= 0x42; /* SPI bit is 1 = LSB first */ } if (spi->autoIncAddrUp > 0) { spiReg |= 0x24; } if (spi->fourWireMode > 0) { spiReg |= 0x18; } halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_SPI_INTERFACE_CONFIG_A, spiReg); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); printf("retVal=%d,[ talSpiWriteByte ]-TALISE_ADDR_SPI_INTERFACE_CONFIG_A\n",retVal); IF_ERR_RETURN_U32(retVal); if (( spi->cmosPadDrvStrength != TAL_CMOSPAD_DRV_1X) && ( spi->cmosPadDrvStrength != TAL_CMOSPAD_DRV_2X) && ( spi->cmosPadDrvStrength != TAL_CMOSPAD_DRV_3X) && ( spi->cmosPadDrvStrength != TAL_CMOSPAD_DRV_4X) && ( spi->cmosPadDrvStrength != TAL_CMOSPAD_DRV_5X) && ( spi->cmosPadDrvStrength != TAL_CMOSPAD_DRV_6X) && ( spi->cmosPadDrvStrength != TAL_CMOSPAD_DRV_8X) && ( spi->cmosPadDrvStrength != TAL_CMOSPAD_DRV_10X)) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_SETSPI_INV_CMOS_DRV_STR, retVal, TALACT_ERR_CHECK_PARAM); } else { /* Extract fields from this encoding when writing: {non_gpio_drv , spi_cmos_drv_select[3:0]} */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_GPIO_SLEW_CONTROL_BYTE3, (((uint8_t)spi->cmosPadDrvStrength) & 0x0F), 0xF0, 4); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_DIGITAL_IO_CONTROL, (((uint8_t)spi->cmosPadDrvStrength) >> 4), 0x10, 4); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } if (spi->enSpiStreaming > 0) { /* Allow SPI streaming mode: SPI message ends when chip select de-asserts */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_SPI_INTERFACE_CONFIG_B, 0x00); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } else { /* Force single instruction mode */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_SPI_INTERFACE_CONFIG_B, 0x80); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } printf("retVal=%d,before [TALISE_verifySpiReadWrite]\n",retVal); /* Check if SPI reads and writes work after changing settings */ retVal = (talRecoveryActions_t)TALISE_verifySpiReadWrite (device); printf("retVal=%d,after [TALISE_verifySpiReadWrite]\n",retVal); IF_ERR_RETURN_U32(retVal); return (uint32_t)retVal; } uint32_t TALISE_verifySpiReadWrite (taliseDevice_t *device) { talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; uint8_t spiReg = 0; int err_flg; #if TALISE_VERBOSE halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_verifySpiReadWrite()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif /* Check SPI read - VENDOR_ID_0 */ halError = talSpiReadByte(device->devHalInfo, TALISE_ADDR_VENDOR_ID_0, &spiReg); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); #if DBG_TALISE_SPI_PR err_flg = check_err_state(retVal); printf("ck_spi_rd ret=%d (%s) VENDOR_ID_0=0x%x [0x56]\n", retVal, str_err[retVal], spiReg); #endif IF_ERR_RETURN_U32(retVal); if (spiReg != 0x56) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERIFYSPI_READ_LOW_ADDR_ERROR, retVal, TALACT_ERR_RESET_FULL); } /* Check SPI read - VENDOR_ID_1 */ spiReg = 0; halError = talSpiReadByte(device->devHalInfo, TALISE_ADDR_VENDOR_ID_1, &spiReg); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); #if DBG_TALISE_SPI_PR err_flg = check_err_state(retVal); printf("ck_spi_rd ret=%d (%s) VENDOR_ID_1=0x%x [0x04]\n", retVal, str_err[retVal], spiReg); #endif IF_ERR_RETURN_U32(retVal); if (spiReg != 0x04) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERIFYSPI_READ_LOW_ADDR_ERROR, retVal, TALACT_ERR_RESET_FULL); } /* Check SPI write - SCRATCHPAD : Data = 10110110 */ spiReg = 0; halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_SCRATCH_PAD, 0xB6); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); #if DBG_TALISE_SPI_PR err_flg = check_err_state(retVal); printf("ck_spi_wr ret=%d (%s) SCRATCHPAD\n", retVal, str_err[retVal]); #endif IF_ERR_RETURN_U32(retVal); halError = talSpiReadByte(device->devHalInfo, TALISE_ADDR_SCRATCH_PAD, &spiReg); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); #if DBG_TALISE_SPI_PR err_flg = check_err_state(retVal); printf("ck_spi_rd ret=%d (%s) SCRATCHPAD=0x%x [0xB6]\n", retVal, str_err[retVal], spiReg); #endif IF_ERR_RETURN_U32(retVal); if (spiReg != 0xB6) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERIFYSPI_WRITE_LOW_ADDR_ERROR, retVal, TALACT_ERR_RESET_FULL); } /* Check SPI write - SCRATCHPAD : Data = 01001001 */ spiReg = 0; halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_SCRATCH_PAD, 0x49); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiReadByte(device->devHalInfo, TALISE_ADDR_SCRATCH_PAD, &spiReg); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); if (spiReg != 0x49) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERIFYSPI_WRITE_LOW_ADDR_ERROR, retVal, TALACT_ERR_RESET_FULL); } /* Check SPI read - SCRATCH_PAD_READ_ONLY_UPPER_ADDRESS_SPACE */ spiReg = 0; halError = talSpiReadByte(device->devHalInfo, TALISE_ADDR_SCRATCH_PAD_READ_ONLY_UPPER_ADDRESS_SPACE, &spiReg); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); if (spiReg != 0xA5) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERIFYSPI_READ_HIGH_ADDR_ERROR, retVal, TALACT_ERR_RESET_FULL); } /* Check SPI write - SCRATCH_PAD_UPPER_ADDRESS_SPACE : Data = 10110110 */ spiReg = 0; halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_SCRATCH_PAD_UPPER_ADDRESS_SPACE, 0xB6); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiReadByte(device->devHalInfo, TALISE_ADDR_SCRATCH_PAD_UPPER_ADDRESS_SPACE, &spiReg); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); if (spiReg != 0xB6) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERIFYSPI_WRITE_HIGH_ADDR_ERROR, retVal, TALACT_ERR_RESET_FULL); } /* Check SPI write - SCRATCH_PAD_UPPER_ADDRESS_SPACE : Data = 01001001 */ spiReg = 0; halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_SCRATCH_PAD_UPPER_ADDRESS_SPACE, 0x49); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiReadByte(device->devHalInfo, TALISE_ADDR_SCRATCH_PAD_UPPER_ADDRESS_SPACE, &spiReg); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); if (spiReg != 0x49) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_VERIFYSPI_WRITE_HIGH_ADDR_ERROR, retVal, TALACT_ERR_RESET_FULL); } return (uint32_t)retVal; } uint32_t TALISE_initDigitalClocks(taliseDevice_t *device, taliseDigClocks_t *clockSettings) { talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; /* RF Synth variables */ /* pull Synth and Loop filter values from a Look Up Table */ uint8_t vcoOutLvl; uint8_t vcoVaractor; /* [3:0] */ uint8_t vcoBiasRef; /* [2:0] */ uint8_t vcoBiasTcf; /* [1:0] */ uint8_t vcoCalOffset; /* [3:0] */ uint8_t vcoVaractorRef; /* [3:0] */ uint8_t loopFilterIcp; /* Icp[5:0] */ uint8_t loopFilterC2C1; /* C2[3:0],C1[3:0] */ uint8_t loopFilterR1C3; /* R1[3:0],C3[3:0] */ uint8_t loopFilterR3; /* R3[3:0] */ uint8_t vcoIndex; uint8_t i; /* RF PLL variables */ uint16_t integerWord; uint32_t fractionalWord; uint32_t fractionalRemainder; uint32_t scaledRefClk_Hz; /* common */ uint32_t hsDigClk_Hz_div2 = 0; uint32_t scaledRefClk_kHz = 0; uint8_t deviceClkDiv = 0; uint8_t clkPllRefClkDiv = 0; uint8_t clockControl2 = 0; uint8_t clockControl5 = 0x40; uint8_t sdmSettings = 0; uint8_t hsDivTimes10 = 25; uint32_t txAttenClock_Hz = 0; uint8_t txAttenClockDiv = 0; /******************RF Synth Section************************/ static const uint8_t icp_46p08[53] = {15, 15, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 27, 27, 28, 29, 30, 31, 32, 33, 32, 33, 32, 33, 33, 34, 27, 28, 29, 29, 30, 39, 29, 30, 31, 31, 30, 31, 31, 32, 30, 31, 31, 32, 32, 31, 31, 32, 32, 33}; static const uint8_t icp_61p44[53] = {13, 13, 13, 14, 15, 16, 16, 17, 18, 19, 20, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 28, 29, 28, 29, 28, 29, 29, 30, 24, 25, 25, 26, 26, 35, 33, 34, 35, 35, 26, 27, 27, 28, 27, 27, 27, 28, 28, 27, 27, 28, 28, 29}; static const uint8_t icp_76p8[53] = { 7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 16, 15, 16, 15, 16, 16, 17, 13, 14, 14, 14, 15, 19, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 15, 15, 15, 16, 16}; static const uint32_t vcoFreqArray_kHz [53] = { 12605000UL, 12245000UL, 11906000UL, 11588000UL, 11288000UL, 11007000UL, 10742000UL, 10492000UL, 10258000UL, 10036000UL, 9827800UL, 9631100UL, 9445300UL, 9269800UL, 9103600UL, 8946300UL, 8797000UL, 8655300UL, 8520600UL, 8392300UL, 8269900UL, 8153100UL, 8041400UL, 7934400UL, 7831800UL, 7733200UL, 7638400UL, 7547100UL, 7459000UL, 7374000UL, 7291900UL, 7212400UL, 7135500UL, 7061000UL, 6988700UL, 6918600UL, 6850600UL, 6784600UL, 6720500UL, 6658200UL, 6597800UL, 6539200UL, 6482300UL, 6427000UL, 6373400UL, 6321400UL, 6270900UL, 6222000UL, 6174500UL, 6128400UL, 6083600UL, 6040100UL, 5997700UL }; #if TALISE_VERBOSE halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_initDigitalClocks()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif /* Scaled Ref Clock at input to CLKPLL should be in range 40-80MHz. * Slightly lower frequencies allowed for lab testing - not suggested for * production */ if (clockSettings->deviceClock_kHz > 15000 && clockSettings->deviceClock_kHz <= 40000) { /* Do not use doubler because multichip sync is not valid when doubler enabled */ scaledRefClk_kHz = clockSettings->deviceClock_kHz; /* total div 1 */ deviceClkDiv = 0; /* div 1 */ clkPllRefClkDiv = 0; /* div 1 */ } else if (clockSettings->deviceClock_kHz > 40000 && clockSettings->deviceClock_kHz <= 80000) { scaledRefClk_kHz = clockSettings->deviceClock_kHz; /* total div 1 */ deviceClkDiv = 0; /* div 1 */ clkPllRefClkDiv = 0; /* div 1 */ } else if (clockSettings->deviceClock_kHz > 80000 && clockSettings->deviceClock_kHz <= 160000) { scaledRefClk_kHz = clockSettings->deviceClock_kHz >> 1; /* total div 2 */ deviceClkDiv = 0; /* div 1 */ clkPllRefClkDiv = 1; /* div 2 */ } else if (clockSettings->deviceClock_kHz > 160000 && clockSettings->deviceClock_kHz <= 320000) { scaledRefClk_kHz = clockSettings->deviceClock_kHz >> 2; /* total div 4 */ deviceClkDiv = 0; /* div 1 */ clkPllRefClkDiv = 2; /* div 4 */ } else if (clockSettings->deviceClock_kHz > 320000 && clockSettings->deviceClock_kHz <= 640000) { scaledRefClk_kHz = clockSettings->deviceClock_kHz >> 3; /* total div 8 */ deviceClkDiv = 1; /* div 2 */ clkPllRefClkDiv = 2; /* div 4 */ } else if (clockSettings->deviceClock_kHz > 640000 && clockSettings->deviceClock_kHz <= 1280000) { scaledRefClk_kHz = clockSettings->deviceClock_kHz >> 4; /* total div 16 */ deviceClkDiv = 2; /* div 4 */ clkPllRefClkDiv = 2; /* div 4 */ } else { return (uint32_t)talApiErrHandler(device,TAL_ERRHDL_INVALID_PARAM, TAL_ERR_INV_SCALEDDEVCLK_PARAM, retVal, TALACT_ERR_CHECK_PARAM); } switch(clockSettings->clkPllHsDiv) { case TAL_HSDIV_2: hsDivTimes10 = 20; break; case TAL_HSDIV_2P5: hsDivTimes10 = 25; break; case TAL_HSDIV_3: hsDivTimes10 = 30; break; case TAL_HSDIV_4: hsDivTimes10 = 40; break; case TAL_HSDIV_5: hsDivTimes10 = 50; break; default: return (uint32_t)talApiErrHandler(device,TAL_ERRHDL_INVALID_PARAM, TAL_ERR_CLKPLL_INV_HSDIV, retVal, TALACT_ERR_CHECK_PARAM); } clockControl2 = ((clkPllRefClkDiv & 0x7) << 4) | (((uint8_t)clockSettings->clkPllHsDiv) & 0x7); /* Set TxAtten / AGC clock divider */ if (device->devStateInfo.clocks.hsDigClkDiv4or5_Hz > 500000000) { txAttenClockDiv = 2; /* div 4 */ txAttenClock_Hz = (device->devStateInfo.clocks.hsDigClkDiv4or5_Hz / 4); } else if (device->devStateInfo.clocks.hsDigClkDiv4or5_Hz > 250000000) { txAttenClockDiv = 1; /* div 2 */ txAttenClock_Hz = (device->devStateInfo.clocks.hsDigClkDiv4or5_Hz / 2); } else { txAttenClockDiv = 0; /* div 1 */ txAttenClock_Hz = device->devStateInfo.clocks.hsDigClkDiv4or5_Hz; } /* TxAtten clock should be less than 250Mhz by design */ if (txAttenClock_Hz > 250000000) { return (uint32_t)talApiErrHandler(device,TAL_ERRHDL_INVALID_PARAM, TAL_ERR_SETCLKPLL_INV_TXATTENDIV, retVal, TALACT_ERR_CHECK_PARAM); } /* Tx Atten clock divider, bits [3:2], is same as AGC clock divider bits[1:0] * bit [6] is resetb for device clock divider */ clockControl5 = 0x40 | ((deviceClkDiv & 0x3) << 4) | ((txAttenClockDiv & 0x3) << 2) | (txAttenClockDiv & 0x3); /* find vco table index based on vco frequency and then break out of loop to assign value */ for (i = 0; clockSettings->clkPllVcoFreq_kHz < vcoFreqArray_kHz[i]; i++) {} vcoIndex = i + 1; if (vcoIndex < 1 || vcoIndex > 53) { /* vco index out of range */ return (uint32_t)talApiErrHandler(device,TAL_ERRHDL_INVALID_PARAM, TAL_ERR_SETCLKPLL_INV_VCOINDEX, retVal, TALACT_ERR_CHECK_PARAM); } /* valid for all refclk frequencies */ vcoOutLvl = (vcoIndex <= 16) ? 13 : (vcoIndex <= 23) ? 12 : (vcoIndex <= 25) ? 11 : (vcoIndex <= 35) ? 10 : (vcoIndex <= 39) ? 9 : (vcoIndex <= 43) ? 8 : (vcoIndex <= 48) ? 7 : 6; vcoVaractor = (vcoIndex <= 29 || vcoIndex == 35) ? 1 : 2; vcoBiasRef = (vcoIndex <= 7 ) ? 4 : (vcoIndex <= 16) ? 6 : 7; vcoBiasTcf = (vcoIndex <= 25 || (vcoIndex > 26 && vcoIndex <= 29) || (vcoIndex > 37 && vcoIndex <= 39)) || (vcoIndex > 40 && vcoIndex <= 43) ? 2 : 3; vcoVaractorRef = (vcoIndex <= 29) ? 12 : (vcoIndex == 35) ? 14 : 13; if (scaledRefClk_kHz >= 15000 && scaledRefClk_kHz < 53760) { /* scaledRefClkMhz = 46.08 MHz */ vcoCalOffset = (vcoIndex == 11 || (vcoIndex > 35 && vcoIndex <= 37) || (vcoIndex > 29 && vcoIndex <= 34)|| vcoIndex == 40 || vcoIndex == 44) ? 14 :(vcoIndex <= 10 || vcoIndex > 44) ? 15 : ((vcoIndex > 12 && vcoIndex <= 22) || (vcoIndex > 23 && vcoIndex <= 23) || (vcoIndex > 26 && vcoIndex <= 29) || (vcoIndex > 23 && vcoIndex <= 25) || vcoIndex == 35) ? 12 : 13; loopFilterIcp = icp_46p08[vcoIndex-1]; loopFilterC2C1 = 0xF9; /* C2=0xF0 */ loopFilterR1C3 = 0xD5; loopFilterR3 = 0x0E; } else if (scaledRefClk_kHz >= 53760 && scaledRefClk_kHz < 69120) { /* scaledRefClkMhz = 61.44 MHz */ vcoCalOffset = (vcoIndex == 11 || (vcoIndex > 29 && vcoIndex <= 34) || vcoIndex == 40 || vcoIndex == 44) ? 14 :(vcoIndex <= 10 || vcoIndex > 44) ? 15 : ((vcoIndex > 12 && vcoIndex <= 22) || (vcoIndex > 23 && vcoIndex <= 25) || (vcoIndex > 26 && vcoIndex <= 29) || (vcoIndex > 34 && vcoIndex <= 37)) ? 12 : (vcoIndex > 37 && vcoIndex <= 39) ? 11 : 13; vcoVaractor = (vcoIndex > 35 && vcoIndex <= 39) ? 1 : vcoVaractor; vcoBiasRef = (vcoIndex > 4 && vcoIndex <= 7) ? 5 : vcoBiasRef; vcoVaractorRef = (vcoIndex > 35 && vcoIndex <= 39) ? 14 : vcoVaractorRef; loopFilterIcp = icp_61p44[vcoIndex-1]; loopFilterC2C1 = ((vcoIndex > 2 && vcoIndex <= 6) || (vcoIndex > 8 && vcoIndex <= 13) || (vcoIndex > 14)) ? 0xFD : 0xFC; /* C2=0xF0 */ loopFilterR1C3 = 0xC5; loopFilterR3 = (vcoIndex <= 2 || (vcoIndex > 6 && vcoIndex <= 8) || vcoIndex == 14) ? 14 : 13 ; } else if (scaledRefClk_kHz >= 69120 && scaledRefClk_kHz < 80000) { /* scaledRefClkMhz = 76.8 MHz */ vcoCalOffset = (vcoIndex == 11 || (vcoIndex > 35 && vcoIndex <= 37) || (vcoIndex > 29 && vcoIndex <= 34)|| vcoIndex == 40 || vcoIndex == 44) ? 14 :(vcoIndex <= 10 || vcoIndex > 44) ? 15 : ((vcoIndex > 12 && vcoIndex <= 22) || (vcoIndex > 23 && vcoIndex <= 23) || (vcoIndex > 26 && vcoIndex <= 29) || (vcoIndex > 23 && vcoIndex <= 25) || vcoIndex == 35) ? 12 : 13; loopFilterIcp = icp_76p8[vcoIndex-1]; loopFilterC2C1 = (vcoIndex == 20 ) ? 0xF7 : (vcoIndex == 4 || vcoIndex == 6 || vcoIndex == 8 ) ? 0xE6: 0xF6; /*C2=0xF0, C1=6 or 7 */ loopFilterR1C3 = (vcoIndex == 4 ) ? 0xE4 : 0xD5; loopFilterR3 = 0x0E; } else { return (uint32_t)talApiErrHandler(device,TAL_ERRHDL_INVALID_PARAM, TAL_ERR_SETRFPLL_INV_REFCLK, retVal, TALACT_ERR_CHECK_PARAM); } /* Hold CLKPLL digital logic in reset */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_4, 0x00); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Set Device clock divider */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_5, clockControl5); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Set reference clock scaler + HSdiv */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_2, clockControl2); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /*Set VCO cal time */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_CAL_CONTROL, 0x02); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Write Synth Setting regs */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_F_VCOTN_BYTE1, ((vcoCalOffset & 0x0F) << 3)); /* Set VCO Cal offset[3:0] */ retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_BYTE1, (0xC0 | (vcoVaractor & 0x0F))); /* Init ALC[3:0], VCO varactor[3:0] */ retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_BYTE2, (0x40 | (vcoOutLvl & 0x0F))); /* VCO output level */ retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_BYTE9, (((vcoBiasTcf & 0x03) << 3) | (vcoBiasRef & 0x07))); /* Set VCO Bias Tcf[1:0] and VCO Bias Ref[2:0] */ retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_VCO_CAL_REF, 0x30); /* Set VCO cal time (compare length) + Set VCO Cal Ref Tcf[2:0]=0 */ retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_VCO_VAR_CTR1, 0x70); /* Set VCO Varactor Ref Tcf[2:0] and VCO Varactor Offset[3:0] */ retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_VCO_VAR_CTR2, (vcoVaractorRef & 0x0F)); /* Set VCO Varactor Reference[3:0] */ retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Write Loop filter */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_BYTE3, (loopFilterIcp & 0x03F)); /* Set Loop Filter Icp[5:0] */ retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_BYTE6, loopFilterC2C1); /* Set Loop Filter C2[3:0] and C1[3:0] */ retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_BYTE7, loopFilterR1C3); /* Set Loop Filter R1[3:0] and C3[3:0] */ retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_LF_R3, (loopFilterR3 & 0x0F)); /*Set Loop Filter R3[3:0] */ retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Calculate PLL integer and fractional words with integer math */ scaledRefClk_Hz = scaledRefClk_kHz * 1000; hsDigClk_Hz_div2 = (uint32_t)((((((uint64_t)(clockSettings->clkPllVcoFreq_kHz) * 1000) >> 1) / hsDivTimes10) * 10) >> 1); integerWord = (uint16_t)(hsDigClk_Hz_div2 / scaledRefClk_Hz); fractionalRemainder = hsDigClk_Hz_div2 % scaledRefClk_Hz; /* +1 >>1 is rounding (add .5) */ fractionalWord = (uint32_t)(((uint64_t)fractionalRemainder * 4177920 / (uint64_t)scaledRefClk_Hz) + 1 ) >> 1; /* if fractionalWord rounded up and == PLL modulus, fix it */ if (fractionalWord == 2088960) { fractionalWord = 0; integerWord = integerWord + 1; } if (fractionalWord > 0) { /* in normal case, the fractional word should be zero and SDM bypassed */ sdmSettings = 0x20; if (integerWord < 9) { /* Ndivider too small for PLL design */ return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_SETCLKPLL_INV_NDIV, retVal, TALACT_ERR_CHECK_PARAM); } } else { /* Bypass SDM */ sdmSettings = 0xE0; if (integerWord < 6) { /* Ndivider too small for PLL design */ return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_SETCLKPLL_INV_NDIV, retVal, TALACT_ERR_CHECK_PARAM); } } /* Set PLL fractional word[22:0] */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE0, (fractionalWord & 0xFF)); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE1, ((fractionalWord >> 8) & 0xFF)); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE2, ((fractionalWord >> 16) & 0x7F)); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Write PLL integer word [7:0] */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_DIVIDER_INT_BYTE1, (sdmSettings | ((integerWord >> 8) & 0x7))); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_DIVIDER_INT_BYTE0, (integerWord & 0xFF)); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Release PLL from reset, and set start VCO cal bit to 0 */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_4, 0x80); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Power up CLKPLL */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTHESIZER_POWER_DOWN, 0x00); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = ADIHAL_wait_us(device->devHalInfo, CLKPLL_POWERUP_US); /* Allow PLL time to power up */ retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_WAIT, halError, retVal, TALACT_ERR_CHECK_TIMER); IF_ERR_RETURN_U32(retVal); /* Enable Charge pump cal after Charge Pump current set (Icp[5:0]) */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLK_SYNTH_BYTE5, 0x84); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); /* Start VCO Cal */ halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_4, 0x80); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); halError = talSpiWriteByte(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_4, 0x81); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); return (uint32_t)retVal; } uint32_t TALISE_setTxPfirSyncClk(taliseDevice_t *device, taliseTxProfile_t *txProfile) { talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; static const uint8_t NUM_MULT_PER_ROW = 20; static const uint8_t MAX_NUM_TAPS = 80; uint8_t effectiveRows = 0; uint8_t numRows = 0; uint32_t dpClk_kHz = 0; uint32_t syncClk_kHz = 0; uint32_t hsDigClkDiv4or5_kHz = 0; uint8_t syncDiv = 0; if ((device->devStateInfo.profilesValid & TX_PROFILE_VALID) > 0) { /* Calculate number of FIR rows for number of Taps */ if ((txProfile->txFir.numFirCoefs % NUM_MULT_PER_ROW == 0) && (txProfile->txFir.numFirCoefs > 0) && (txProfile->txFir.numFirCoefs <= MAX_NUM_TAPS)) { numRows = (txProfile->txFir.numFirCoefs / NUM_MULT_PER_ROW); } else { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TALISE_ERR_TXFIR_INV_NUMTAPS_PARM, retVal, TALACT_ERR_CHECK_PARAM); } effectiveRows = ((numRows + (txProfile->txFirInterpolation - 1)) / txProfile->txFirInterpolation); /* round up to next power of 2 */ switch (effectiveRows) { case 1: effectiveRows = 1; break; case 2: effectiveRows = 2; break; case 3: /* fall through */ case 4: effectiveRows = 4; break; default: { /* invalid number of FIR taps */ return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TALISE_ERR_TXFIR_INV_NUMROWS, retVal, TALACT_ERR_CHECK_PARAM); } } dpClk_kHz = (txProfile->txInputRate_kHz * txProfile->txFirInterpolation * effectiveRows); /* FIR DPCLK can only run at max of 500MHz */ if (dpClk_kHz > 500000) { /* Max number of Tx PFIR taps exceeded for Tx Profile */ return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TALISE_ERR_TXFIR_TAPSEXCEEDED, retVal, TALACT_ERR_CHECK_PARAM); } /* SYNC CLOCK is the PFIR output rate / 2 */ syncClk_kHz = txProfile->txInputRate_kHz * txProfile->txFirInterpolation / 2; hsDigClkDiv4or5_kHz = device->devStateInfo.clocks.hsDigClkDiv4or5_Hz / 1000; /* Select correct divider setting for SYNCCLK - must be == syncClk_kHz or slower */ for (syncDiv = 0; syncDiv < 5; syncDiv++) { if ((hsDigClkDiv4or5_kHz / (4 << syncDiv)) <= syncClk_kHz) { break; } } /* Write Tx PFIR SYNC Clock divider */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_6, syncDiv, 0x38, 3); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); } return (uint32_t)retVal; } uint32_t TALISE_setRxPfirSyncClk(taliseDevice_t *device, taliseRxProfile_t *rxProfile, taliseORxProfile_t *orxProfile) { talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; static const uint8_t NUM_MULT_PER_ROW = 24; static const uint8_t MAX_NUM_TAPS = 72; uint8_t ddcMultiply = 1; uint8_t ddcDivide = 1; uint32_t rxOutClk_kHz = 0; uint8_t rxNumRows = 0; uint8_t rxEffectiveNumRows = 0; uint32_t rxDpClk_kHz = 0; uint8_t orxDdcDecRatio = 1; uint32_t orxOutClk_kHz = 0; uint8_t orxNumRows = 0; uint8_t orxEffectiveNumRows = 0; uint32_t orxDpClk_kHz = 0; uint32_t slowestOutputRate_kHz = 0; uint32_t syncClk_kHz = 0; uint32_t hsDigClkDiv4or5_kHz = 0; uint8_t syncDiv = 0; /** * Calculate Rx SYNC Clock divider for Rx PFIR. Same Rx SYNC Clock is used * for Rx and ORx PFIRs, and must be slow enough to handle the slowest * PFIR rate. **/ /* Calculate clocks for Rx Profile */ if ((device->devStateInfo.profilesValid & RX_PROFILE_VALID) > 0) { /* Calculate decimation in DDC */ switch (rxProfile->rxDdcMode) { case TAL_RXDDC_BYPASS_REALIF: case TAL_RXDDC_BYPASS: ddcMultiply = 1; ddcDivide = 1; break; case TAL_RXDDC_DEC2_REALIF: case TAL_RXDDC_DEC2: ddcMultiply = 2; ddcDivide = 1; break; case TAL_RXDDC_INT2_REALIF: case TAL_RXDDC_INT2: ddcMultiply = 1; ddcDivide = 2; break; case TAL_RXDDC_FILTERONLY_REALIF: case TAL_RXDDC_FILTERONLY: ddcMultiply = 1; ddcDivide = 1; break; default: { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TALISE_ERR_RXFIR_INV_DDC, retVal, TALACT_ERR_CHECK_PARAM); } } /* Calculate Rx PFIR output from Rx output and decimation */ rxOutClk_kHz = (rxProfile->rxOutputRate_kHz * ddcMultiply ) / ddcDivide; /* Set slowestOutputRate_kHz to the Rx PFIR output rate */ slowestOutputRate_kHz = rxOutClk_kHz; /* Calculate number of rows in Rx FIR based on taps */ if ((rxProfile->rxFir.numFirCoefs % NUM_MULT_PER_ROW == 0) && (rxProfile->rxFir.numFirCoefs > 0) && (rxProfile->rxFir.numFirCoefs <= MAX_NUM_TAPS)) { rxNumRows = (rxProfile->rxFir.numFirCoefs / NUM_MULT_PER_ROW); } else { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TALISE_ERR_RXFIR_INV_NUMTAPS_PARM, retVal, TALACT_ERR_CHECK_PARAM); } /* Effective number of rows is the power of 2 that's >= rows */ switch(rxNumRows) { case 1: rxEffectiveNumRows = 1; break; case 2: rxEffectiveNumRows = 2; break; case 3: rxEffectiveNumRows = 4; break; default: { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TALISE_ERR_RXFIR_INV_NUMROWS, retVal, TALACT_ERR_CHECK_PARAM); } } /* Calculate DP clock */ rxDpClk_kHz = rxOutClk_kHz * rxEffectiveNumRows; /* DP clock is a max of 500Mhz in Talise */ if (rxDpClk_kHz > 500000) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TALISE_ERR_RXFIR_TAPSEXCEEDED, retVal, TALACT_ERR_CHECK_PARAM); } } /* Calculate clocks for Orx Profile */ if ((device->devStateInfo.profilesValid & ORX_PROFILE_VALID) > 0) { /* Calculate decimation in DDC */ switch (orxProfile->orxDdcMode) { case TAL_ORXDDC_SUBSAMPLE_BY2: orxDdcDecRatio = 2; break; case TAL_ORXDDC_DISABLED: orxDdcDecRatio = 1; break; default: { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TALISE_ERR_ORXFIR_INV_DDC, retVal, TALACT_ERR_CHECK_PARAM); } } /* Calculate ORx PFIR output from Rx output and decimation */ orxOutClk_kHz = orxProfile->orxOutputRate_kHz * orxDdcDecRatio; /* Check if the ORx PFIR output is the slowest among all output clocks */ if ((slowestOutputRate_kHz == 0) || (slowestOutputRate_kHz > orxOutClk_kHz)) { slowestOutputRate_kHz = orxOutClk_kHz; } /* Calculate number of rows in ORx FIR based on taps */ if ((orxProfile->rxFir.numFirCoefs % NUM_MULT_PER_ROW == 0) && (orxProfile->rxFir.numFirCoefs > 0) && (orxProfile->rxFir.numFirCoefs <= MAX_NUM_TAPS)) { orxNumRows = (orxProfile->rxFir.numFirCoefs / NUM_MULT_PER_ROW); } else { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TALISE_ERR_ORXFIR_INV_NUMTAPS_PARM, retVal, TALACT_ERR_CHECK_PARAM); } /* Effective number of rows is the power of 2 that's >= rows */ switch(orxNumRows) { case 1: orxEffectiveNumRows = 1; break; case 2: orxEffectiveNumRows = 2; break; case 3: orxEffectiveNumRows = 4; break; default: { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TALISE_ERR_ORXFIR_INV_NUMROWS, retVal, TALACT_ERR_CHECK_PARAM); } } /* Calculate DP clock */ orxDpClk_kHz = orxOutClk_kHz * orxEffectiveNumRows; /* DP clock is a max of 500Mhz in Talise */ if (orxDpClk_kHz > 500000) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TALISE_ERR_ORXFIR_TAPSEXCEEDED, retVal, TALACT_ERR_CHECK_PARAM); } } /* SYNC CLOCK should be FIR output rate / 2 */ syncClk_kHz = (slowestOutputRate_kHz / 2); /* Get hsDigClkDiv4or5_kHz from profile */ hsDigClkDiv4or5_kHz = device->devStateInfo.clocks.hsDigClkDiv4or5_Hz / 1000; /* Select correct divider setting for SYNCCLK - must be == syncClk_kHz or slower */ for (syncDiv = 0; syncDiv < 5; syncDiv++) { if ((hsDigClkDiv4or5_kHz / (4 << syncDiv)) <= syncClk_kHz) { break; } } /* Write Rx/Orx PFIR SYNC Clock divider */ halError = talSpiWriteField(device->devHalInfo, TALISE_ADDR_CLOCK_CONTROL_6, syncDiv, 0x7, 0); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); IF_ERR_RETURN_U32(retVal); return (uint32_t)retVal; } uint32_t TALISE_getApiVersion (taliseDevice_t *device, uint32_t *siVer, uint32_t *majorVer, uint32_t *minorVer, uint32_t *buildVer) { talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; #if TALISE_VERBOSE halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getApiVersion()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif if ((siVer == NULL) || (majorVer == NULL) || (minorVer == NULL) || (buildVer == NULL)) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_GETAPIVERSION_NULLPARAM, retVal, TALACT_ERR_CHECK_PARAM); } *siVer = TAL_CURRENT_SI_VERSION; *majorVer = TAL_CURRENT_MAJOR_VERSION; *minorVer = TAL_CURRENT_MINOR_VERSION; *buildVer = TAL_CURRENT_BUILD_VERSION; return (uint32_t)retVal; } uint32_t TALISE_getDeviceRev(taliseDevice_t *device, uint8_t *revision) { talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; #if TALISE_VERBOSE halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getDeviceRev()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif if (revision == NULL) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_GETDEVICEREV_NULLPARAM, retVal, TALACT_ERR_CHECK_PARAM); } halError = talSpiReadByte(device->devHalInfo, TALISE_ADDR_PRODUCT_ID_1, revision); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); return (uint32_t)retVal; } uint32_t TALISE_getProductId(taliseDevice_t *device, uint8_t *productId) { talRecoveryActions_t retVal = TALACT_NO_ACTION; adiHalErr_t halError = ADIHAL_OK; #if TALISE_VERBOSE halError = talWriteToLog(device->devHalInfo, ADIHAL_LOG_MSG, TAL_ERR_OK, "TALISE_getProductId()\n"); retVal = talApiErrHandler(device, TAL_ERRHDL_HAL_LOG, halError, retVal, TALACT_WARN_RESET_LOG); #endif if (productId == NULL) { return (uint32_t)talApiErrHandler(device, TAL_ERRHDL_INVALID_PARAM, TAL_ERR_GETPRODUCTID_NULLPARAM, retVal, TALACT_ERR_CHECK_PARAM); } halError = talSpiReadByte(device->devHalInfo, TALISE_ADDR_PRODUCT_ID_0, productId); retVal = talApiErrHandler(device,TAL_ERRHDL_HAL_SPI, halError, retVal, TALACT_ERR_RESET_SPI); return (uint32_t)retVal; }