Beispiel #1
0
/***************************************************************************//**
 * @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;
}
Beispiel #2
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;
}
Beispiel #3
0
/***************************************************************************//**
 * @brief Initializes the AD9122.
 *
 * @param pfnSetDataClock - Pointer to a function which sets the data clock
 * @param pfnSetDacClock - Pointer to a function which sets the DAC clock
 * @param pfnRoundRateDataClock - Pointer to a function which computes the
 * 								  actual data clock for a desired clock value
 * @param pfnRoundRateDacClock - Pointer to a function which computes the
 * 								 actual DAC clock for a desired clock value
 *
 * @return Returns negative error code or 0 in case of success.
*******************************************************************************/
int32_t ad9122_setup(void* pfnSetDataClock,
                     void* pfnSetDacClock,
                     void* pfnSetRefClock,
                     void* pfnRoundRateDataClock,
                     void* pfnRoundRateDacClock,
                     void* pfnRoundRateRefClock)
{
	int32_t ret;
	int32_t i;
	uint32_t datapath_ctrl, rate;
	struct cf_axi_converter *conv = &dds_conv;

	if(ad9122_reset() < 0)
		return -1;

	pfnSetDataClk = pfnSetDataClock;
	pfnSetDacClk  = pfnSetDacClock;
	pfnSetRefClk  = pfnSetRefClock;
	pfnRoundRateDataClk = pfnRoundRateDataClock;
	pfnRoundRateDacClk  = pfnRoundRateDacClock;
	pfnRoundRateRefClk  = pfnRoundRateRefClock;

	conv->write 		= ad9122_write;
	conv->read 			= ad9122_read;
	conv->setup = ad9122_tune_dci;
	conv->get_fifo_status = ad9122_get_fifo_status;
	conv->get_data_clk 	= ad9122_get_data_clk;
	conv->write_raw = ad9122_write_raw;
	conv->read_raw = ad9122_read_raw;

	for (i = 0; i < ARRAY_SIZE(ad9122_reg_defaults); i++)
	{
		ad9122_write(ad9122_reg_defaults[i][0],
					 ad9122_reg_defaults[i][1]);
	}

	if(ad9122_sync() < 0)
		return -1;

	conv->interp_factor = 1;
	conv->interp_factor = ad9122_validate_interp_factor(conv->interp_factor);

	conv->fcenter_shift = 0;

	datapath_ctrl = AD9122_DATAPATH_CTRL_BYPASS_PREMOD |
					AD9122_DATAPATH_CTRL_BYPASS_NCO |
					AD9122_DATAPATH_CTRL_BYPASS_INV_SINC;
	ad9122_write(AD9122_REG_DATAPATH_CTRL, datapath_ctrl);

	rate = 491520000;
	ret = ad9122_set_interpol(conv, conv->interp_factor,
			  	  	  	  	  conv->fcenter_shift, rate);

	cf_axi_dds_of_probe();

	return ret;
}
Beispiel #4
0
/***************************************************************************//**
 * @brief Resets the device.
 *
 * @return Returns negative error code or 0 in case of success.
*******************************************************************************/
int32_t ad9122_reset(void)
{
	int32_t ret;

    ret = ad9122_write(AD9122_REG_COMM, AD9122_COMM_RESET);
    if(ret < 0)
        return ret;

	ret = ad9122_write(AD9122_REG_COMM, 0x00);

    return ret;
}
Beispiel #5
0
/***************************************************************************//**
 * @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);
	}
Beispiel #6
0
/***************************************************************************//**
 * @brief Writes data to the AD9122.
 *
 * @return Returns negative error code or the written value in case of success.
*******************************************************************************/
uint32_t ad9122_store(uint32_t address, int32_t readin)
{
	int32_t ret = 0;

	switch (address) {
	case AD9122_REG_I_DAC_OFFSET_MSB:
	case AD9122_REG_Q_DAC_OFFSET_MSB:
		if (readin < 0 || readin > 0xFFFF) {
			ret = -1;
			goto out;
		}
		break;
	case AD9122_REG_I_PHA_ADJ_MSB:
	case AD9122_REG_Q_PHA_ADJ_MSB:
		if (readin < -512 || readin > 511) {
			ret = -1;
			goto out;
		}
		break;
	default:
		if (readin < 0 || readin > 0x3FF) {
			ret = -1;
			goto out;
		}
		break;
	}

	ret = ad9122_write((uint32_t)address, readin >> 8);
	if (ret < 0)
		goto out;

	ret = ad9122_write((uint32_t)address - 1, readin & 0xFF);
	if (ret < 0)
		goto out;

out:

	return ret ? ret : readin;
}
Beispiel #7
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;
}
Beispiel #8
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;
}
Beispiel #9
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;
}