/***************************************************************************//** * @brief Waits for the AD9122 to sync. * * @return Returns negative error code or 0 in case of success. *******************************************************************************/ int32_t ad9122_sync() { int32_t ret, timeout; timeout = 255; do { delay_us(1000); ret = ad9122_read(AD9122_REG_FIFO_STATUS_1); if (ret < 0) return ret; } while (timeout-- && !(ret & AD9122_FIFO_STATUS_1_FIFO_SOFT_ALIGN_ACK)); ad9122_write(AD9122_REG_FIFO_STATUS_1, 0x0); ad9122_write(AD9122_REG_SYNC_CTRL_1, AD9122_SYNC_CTRL_1_SYNC_EN | AD9122_SYNC_CTRL_1_RISING_EDGE_SYNC); timeout = 255; do { delay_us(1000); ret = ad9122_read(AD9122_REG_SYNC_STATUS_1); if (ret < 0) return ret; } while (timeout-- && !(ret & AD9122_SYNC_STATUS_1_SYNC_LOCKED)); return 0; }
/***************************************************************************//** * @brief Gets the AD9122 FIFO status. * * @return Returns negative error code in case of FIFO warning * or 0 in case of success. *******************************************************************************/ int32_t ad9122_get_fifo_status(struct cf_axi_converter *conv) { uint32_t stat; stat = ad9122_read(AD9122_REG_SYNC_STATUS_1); if (!(stat & AD9122_SYNC_STATUS_1_SYNC_LOCKED)) return -1; stat = ad9122_read(AD9122_REG_FIFO_STATUS_1); if (stat & (AD9122_FIFO_STATUS_1_FIFO_WARNING_1 | AD9122_FIFO_STATUS_1_FIFO_WARNING_2)) return -1; return 0; }
/***************************************************************************//** * @brief Writes interpolation data to the AD9122. * * @return Returns negative error code or the written data in case of success. *******************************************************************************/ uint32_t ad9122_interpolation_store(uint32_t address, int32_t readin) { struct cf_axi_converter *conv = &dds_conv; unsigned pwr; int32_t ret; pwr = ad9122_read(AD9122_REG_POWER_CTRL); ad9122_write(AD9122_REG_POWER_CTRL, pwr | AD9122_POWER_CTRL_PD_I_DAC | AD9122_POWER_CTRL_PD_Q_DAC); switch (address) { case 0: ret = ad9122_set_interpol_freq(conv, readin); break; case 1: ret = ad9122_set_interpol_fcent_freq(conv, readin); break; default: ret = -1; } if (conv->pcore_sync) conv->pcore_sync(); ad9122_write(AD9122_REG_POWER_CTRL, pwr); return ret ? ret : readin; }
/***************************************************************************//** * @brief Reads data from the AD9122. * * @return Returns negative error code or 0 in case of success. *******************************************************************************/ uint32_t ad9122_show(uint32_t address, int32_t* val) { int32_t ret = 0; ret = ad9122_read((uint32_t)address); if (ret < 0) goto out; *val = ret << 8; ret = ad9122_read((uint32_t)address - 1); if (ret < 0) goto out; *val |= ret & 0xFF; switch ((uint32_t)address) { case AD9122_REG_I_PHA_ADJ_MSB: case AD9122_REG_Q_PHA_ADJ_MSB: *val = sign_extend32(*val, 9); break; } out: return ret; }
/***************************************************************************//** * @brief Sets the full-scale current for I DAC. * * @param fs_adj - Full scale current value. If the value equals INT32_MAX then * the function returns the current set value. * * @return Returns the set full-scale current. *******************************************************************************/ int32_t ad9122_fs_adj_I_DAC(int32_t fs_adj) { uint8_t sleepBit = 0; uint8_t regData1 = 0; uint8_t regData2 = 0; if(fs_adj != INT32_MAX) { /* Read the current state of the sleep bit */ sleepBit = (ad9122_read(AD9122_REG_I_DAC_CTRL) & AD9122_I_DAC_CTRL_I_DAC_SLEEP); /* Set the full-scale value and keep the state of the sleep bit. */ regData1 = AD9122_I_DAC_CTRL_I_DAC_FS_ADJ_9_8((fs_adj & 0x0300) >> 8); ad9122_write(AD9122_REG_I_DAC_CTRL, (sleepBit | regData1)); regData2 = AD9122_I_DAC_FS_ADJ_I_DAC_FS_ADJ_7_0((fs_adj & 0x00FF) >> 0); ad9122_write(AD9122_REG_I_DAC_FS_ADJ, regData2); /* Compute the set full scale current */ fs_adj = ((regData1 & 0x3) << 8) + (regData2 << 0); }
/***************************************************************************//** * @brief Sets the interpolation factor and the center shift frequency. * * @param conv - Pointer to a cf_axi_converter struct. * @param interp - Interpolation factor * @param fcent_shift - Center frequency shift as a multiplier of fData / 2. * The shift values should be in the range [0, 15] * @param data_rate - Data rate in Hz * * @return Returns negative error code or 0 in case of success. *******************************************************************************/ static int32_t ad9122_set_interpol(struct cf_axi_converter *conv, uint32_t interp, uint32_t fcent_shift, uint32_t data_rate) { uint32_t hb1, hb2, hb3, tmp; int32_t ret, cached; hb1 = AD9122_HB1_CTRL_BYPASS_HB1; hb2 = AD9122_HB2_CTRL_BYPASS_HB2; hb3 = AD9122_HB3_CTRL_BYPASS_HB3; switch (interp) { case 1: break; case 2: if (fcent_shift > 3) return -1; hb1 = AD9122_HB1_INTERP(fcent_shift); break; case 4: if (fcent_shift > 7) return -1; hb1 = AD9122_HB1_INTERP(fcent_shift % 4); hb2 = AD9122_HB23_INTERP(fcent_shift); break; case 8: if (fcent_shift > 15) return -1; hb1 = AD9122_HB1_INTERP(fcent_shift % 4); hb2 = AD9122_HB23_INTERP(fcent_shift % 8); hb3 = AD9122_HB23_INTERP(fcent_shift / 2); break; default: return -1; } cached = conv->interp_factor; conv->interp_factor = interp; ret = ad9122_set_data_clk(conv, data_rate ? data_rate : ad9122_get_data_clk(conv)); if (ret < 0) { conv->interp_factor = cached; return ret; } tmp = ad9122_read(AD9122_REG_DATAPATH_CTRL); switch (hb1) { case AD9122_HB1_INTERP(1): case AD9122_HB1_INTERP(3): tmp &= ~AD9122_DATAPATH_CTRL_BYPASS_PREMOD; break; default: tmp |= AD9122_DATAPATH_CTRL_BYPASS_PREMOD; } ad9122_write(AD9122_REG_DATAPATH_CTRL, tmp); ad9122_write(AD9122_REG_HB1_CTRL, hb1); ad9122_write(AD9122_REG_HB2_CTRL, hb2); ad9122_write(AD9122_REG_HB3_CTRL, hb3); conv->fcenter_shift = fcent_shift; return 0; }
/***************************************************************************//** * @brief Calibrates the AD9122 DCI. * * @return Returns negative error code or 0 in case of success. *******************************************************************************/ int32_t ad9122_tune_dci(struct cf_axi_converter *conv) { uint32_t reg; int32_t i = 0, dci; uint32_t err_bfield = 0; for (dci = 0; dci < 4; dci++) { ad9122_write(AD9122_REG_DCI_DELAY, dci); for (i = 0; i < ARRAY_SIZE(dac_sed_pattern); i++) { ad9122_write(AD9122_REG_SED_CTRL, 0); if(conv->pcore_set_sed_pattern) { conv->pcore_set_sed_pattern(0, dac_sed_pattern[i].i0, dac_sed_pattern[i].i1); conv->pcore_set_sed_pattern(1, dac_sed_pattern[i].q0, dac_sed_pattern[i].q1); } ad9122_write(AD9122_REG_COMPARE_I0_LSBS, dac_sed_pattern[i].i0 & 0xFF); ad9122_write(AD9122_REG_COMPARE_I0_MSBS, dac_sed_pattern[i].i0 >> 8); ad9122_write(AD9122_REG_COMPARE_Q0_LSBS, dac_sed_pattern[i].q0 & 0xFF); ad9122_write(AD9122_REG_COMPARE_Q0_MSBS, dac_sed_pattern[i].q0 >> 8); ad9122_write(AD9122_REG_COMPARE_I1_LSBS, dac_sed_pattern[i].i1 & 0xFF); ad9122_write(AD9122_REG_COMPARE_I1_MSBS, dac_sed_pattern[i].i1 >> 8); ad9122_write(AD9122_REG_COMPARE_Q1_LSBS, dac_sed_pattern[i].q1 & 0xFF); ad9122_write(AD9122_REG_COMPARE_Q1_MSBS, dac_sed_pattern[i].q1 >> 8); ad9122_write(AD9122_REG_SED_CTRL, AD9122_SED_CTRL_SED_COMPARE_EN); ad9122_write(AD9122_REG_EVENT_FLAG_2, AD9122_EVENT_FLAG_2_AED_COMPARE_PASS | AD9122_EVENT_FLAG_2_AED_COMPARE_FAIL | AD9122_EVENT_FLAG_2_SED_COMPARE_FAIL); ad9122_write(AD9122_REG_SED_CTRL, AD9122_SED_CTRL_SED_COMPARE_EN | AD9122_SED_CTRL_AUTOCLEAR_EN); msleep(100); reg = ad9122_read(AD9122_REG_SED_CTRL); if(!(reg & (AD9122_SED_CTRL_SAMPLE_ERR_DETECTED | AD9122_SED_CTRL_COMPARE_PASS))) { return -1; } if (reg & AD9122_SED_CTRL_SAMPLE_ERR_DETECTED) set_bit(dci, &err_bfield); } } dci = ad9122_find_dci(&err_bfield, 4); if(dci < 0) { return -1; } ad9122_write(AD9122_REG_DCI_DELAY, dci); ad9122_write(AD9122_REG_SED_CTRL, 0); return 0; }
/***************************************************************************//** * @brief Calibrates the AD9122 DCI. * * @return Returns negative error code or 0 in case of success. *******************************************************************************/ int32_t ad9122_tune_dci(struct cf_axi_converter *conv) { uint32_t reg, err_mask, pwr; int32_t i = 0, dci; uint32_t err_bfield = 0; pwr = ad9122_read(AD9122_REG_POWER_CTRL); ad9122_write(AD9122_REG_POWER_CTRL, pwr | AD9122_POWER_CTRL_PD_I_DAC | AD9122_POWER_CTRL_PD_Q_DAC); for (dci = 0; dci < 4; dci++) { ad9122_write(AD9122_REG_DCI_DELAY, dci); for (i = 0; i < ARRAY_SIZE(dac_sed_pattern); i++) { ad9122_write(AD9122_REG_SED_CTRL, 0); #ifdef CF_AXI_DDS if(conv->pcore_set_sed_pattern) conv->pcore_set_sed_pattern( (dac_sed_pattern[i].i1 << 16) | dac_sed_pattern[i].i0, (dac_sed_pattern[i].q1 << 16) | dac_sed_pattern[i].q0); #endif ad9122_write(AD9122_REG_COMPARE_I0_LSBS, dac_sed_pattern[i].i0 & 0xFF); ad9122_write(AD9122_REG_COMPARE_I0_MSBS, dac_sed_pattern[i].i0 >> 8); ad9122_write(AD9122_REG_COMPARE_Q0_LSBS, dac_sed_pattern[i].q0 & 0xFF); ad9122_write(AD9122_REG_COMPARE_Q0_MSBS, dac_sed_pattern[i].q0 >> 8); ad9122_write(AD9122_REG_COMPARE_I1_LSBS, dac_sed_pattern[i].i1 & 0xFF); ad9122_write(AD9122_REG_COMPARE_I1_MSBS, dac_sed_pattern[i].i1 >> 8); ad9122_write(AD9122_REG_COMPARE_Q1_LSBS, dac_sed_pattern[i].q1 & 0xFF); ad9122_write(AD9122_REG_COMPARE_Q1_MSBS, dac_sed_pattern[i].q1 >> 8); ad9122_write(AD9122_REG_SED_CTRL, AD9122_SED_CTRL_SED_COMPARE_EN); ad9122_write(AD9122_REG_EVENT_FLAG_2, AD9122_EVENT_FLAG_2_AED_COMPARE_PASS | AD9122_EVENT_FLAG_2_AED_COMPARE_FAIL | AD9122_EVENT_FLAG_2_SED_COMPARE_FAIL); ad9122_write(AD9122_REG_SED_CTRL, AD9122_SED_CTRL_SED_COMPARE_EN); msleep(100); reg = ad9122_read(AD9122_REG_SED_CTRL); err_mask = ad9122_read(AD9122_REG_SED_I_LSBS); err_mask |= ad9122_read(AD9122_REG_SED_I_MSBS); err_mask |= ad9122_read(AD9122_REG_SED_Q_LSBS); err_mask |= ad9122_read(AD9122_REG_SED_Q_MSBS); if (err_mask || (reg & AD9122_SED_CTRL_SAMPLE_ERR_DETECTED)) set_bit(dci, &err_bfield); } } ad9122_write(AD9122_REG_DCI_DELAY, ad9122_find_dci(&err_bfield, 4)); ad9122_write(AD9122_REG_SED_CTRL, 0); ad9122_write(AD9122_REG_POWER_CTRL, pwr); return 0; }