Files
PLFM_RADAR/14_RADAR_Old_version/Firmware/Microcontroller/adf4382.c
T
2026-03-19 01:21:46 +00:00

2206 lines
56 KiB
C

/***************************************************************************//**
* @file adf4382.c
* @brief Implementation of adf4382 Driver.
* @authors Ciprian Hegbeli (ciprian.hegbeli@analog.com)
* Jude Osemene (jude.osemene@analog.com)
********************************************************************************
* Copyright 2024(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "adf4382.h"
#include "no_os_alloc.h"
#include "no_os_delay.h"
#include "no_os_error.h"
#include "no_os_print_log.h"
#include "no_os_util.h"
/* Charge pump current values expressed in uA */
static const int adf4382_ci_ua[] = {
700,
900,
1100,
1300,
1400,
1800,
2200,
2500,
2900,
3600,
4300,
5000,
5800,
7200,
8600,
11100
};
/**
* @brief Writes data to ADF4382 over SPI.
* @param dev - The device structure.
* @param reg_addr - The register address.
* @param data - Data value to write.
* @return - 0 in case of success or negative error code otherwise.
*/
int adf4382_spi_write(struct adf4382_dev *dev, uint16_t reg_addr, uint8_t data)
{
uint8_t buff[ADF4382_BUFF_SIZE_BYTES];
uint16_t cmd;
if (!dev)
return -EINVAL;
cmd = ADF4382_SPI_WRITE_CMD | reg_addr;
if (dev->spi_desc->bit_order) {
buff[0] = no_os_bit_swap_constant_8(cmd & 0xFF);
buff[1] = no_os_bit_swap_constant_8(cmd >> 8);
buff[2] = no_os_bit_swap_constant_8(data);
} else {
buff[0] = cmd >> 8;
buff[1] = cmd & 0xFF;
buff[2] = data;
}
return no_os_spi_write_and_read(dev->spi_desc, buff,
ADF4382_BUFF_SIZE_BYTES);
}
/**
* @brief Reads data from ADF4382 over SPI.
* @param dev - The device structure.
* @param reg_addr - The register address.
* @param data - Data read from the device.
* @return - 0 in case of success or negative error code otherwise.
*/
int adf4382_spi_read(struct adf4382_dev *dev, uint16_t reg_addr, uint8_t *data)
{
int ret;
uint8_t buff[ADF4382_BUFF_SIZE_BYTES];
uint16_t cmd;
if (!dev)
return -EINVAL;
cmd = ADF4382_SPI_READ_CMD | reg_addr;
if (dev->spi_desc->bit_order) {
buff[0] = no_os_bit_swap_constant_8(cmd & 0xFF);
buff[1] = no_os_bit_swap_constant_8(cmd >> 8);
buff[2] = no_os_bit_swap_constant_8(ADF4382_SPI_DUMMY_DATA);
} else {
buff[0] = cmd >> 8;
buff[1] = cmd & 0xFF;
buff[2] = ADF4382_SPI_DUMMY_DATA;
}
ret = no_os_spi_write_and_read(dev->spi_desc, buff,
ADF4382_BUFF_SIZE_BYTES);
if (ret)
return ret;
*data = buff[2];
return 0;
}
/**
* @brief Updates the values of the ADF4382 register.
* @param dev - The device structure.
* @param reg_addr - The register address.
* @param mask - Bits to be updated.
* @param data - Update value for the mask.
* @return - 0 in case of success or negative error code otherwise.
*/
int adf4382_spi_update_bits(struct adf4382_dev *dev, uint16_t reg_addr,
uint8_t mask, uint8_t data)
{
uint8_t tmp, orig;
int ret;
ret = adf4382_spi_read(dev, reg_addr, &orig);
if (ret)
return ret;
tmp = orig & ~mask;
tmp |= data & mask;
if (tmp != orig)
return adf4382_spi_write(dev, reg_addr, tmp);
return 0;
}
/**
* @brief Will output on the terminal the values of all the ADF4382 registers.
* @param dev - The device structure.
* @return - 0 in case of success or negative error code.
*/
int adf4382_reg_dump(struct adf4382_dev *dev)
{
uint8_t val;
uint16_t i;
int ret;
for (i = 0; i < 0x68; i++) {
ret = adf4382_spi_read(dev, i, &val);
if (ret)
return ret;
pr_info("0x%X 0x%X\n", i, val);
}
for (i = 0x100; i < 0x112; i++) {
ret = adf4382_spi_read(dev, i, &val);
if (ret)
return ret;
pr_info("0x%X 0x%X\n", i, val);
}
for (i = 0x200; i < 0x274; i++) {
ret = adf4382_spi_read(dev, i, &val);
if (ret)
return ret;
pr_info("0x%X 0x%X\n", i, val);
}
return ret;
}
/**
* @brief Set the desired reference frequency and reset everything over to maximum
* supported value of 5GHz to the max. value and everything under the minimum
* supported value of 10MHz to the min. value.
* @param dev - The device structure.
* @param val - The desired reference frequency in Hz.
* @return - 0 in case of success or negative error code.
*/
int adf4382_set_ref_clk(struct adf4382_dev *dev, uint64_t val)
{
if (!dev)
return -EINVAL;
dev->ref_freq_hz = val;
if (val > ADF4382_REF_CLK_MAX)
dev->ref_freq_hz = ADF4382_REF_CLK_MAX;
if (val < ADF4382_REF_CLK_MIN)
dev->ref_freq_hz = ADF4382_REF_CLK_MIN;
return adf4382_set_freq(dev);
}
/**
* @brief Gets the user proposed reference frequency
* @param dev - The device structure.
* @param val - The set value of the reference frequency in Hz.
* @return - Reference frequency in KHz.
*/
int adf4382_get_ref_clk(struct adf4382_dev *dev, uint64_t *val)
{
if (!dev)
return -EINVAL;
*val = dev->ref_freq_hz;
return 0;
}
/**
* @brief Set the reference doubler to enable or disable based on the passed
* parameter. If the parameter is different then 0 it will set the doubler to
* enable.
* @param dev - The device structure.
* @param en - The enable or disable value of the reference doubler.
* @return - 0 in case of success or negative error code.
*/
int adf4382_set_en_ref_doubler(struct adf4382_dev *dev, bool en)
{
if (!dev)
return -EINVAL;
dev->ref_doubler_en = en;
return adf4382_set_freq(dev);
}
/**
* @brief Gets the value the doubler if it is enabled or disable and stores it
* it the dev structure.
* @param dev - The device structure.
* @param en - The read value of the reference doubler.
* @return - 0 in case of success or negative error code.
*/
int adf4382_get_en_ref_doubler(struct adf4382_dev *dev, bool *en)
{
uint8_t tmp;
int ret;
ret = adf4382_spi_read(dev, 0x20, &tmp);
if (ret)
return ret;
dev->ref_doubler_en = no_os_field_get(tmp, ADF4382_EN_RDBLR_MSK);
*en = dev->ref_doubler_en;
return 0;
}
/**
* @brief Set the reference divider value and reset everything over to maximum
* supported value of 63 to the max. value
* @param dev - The device structure.
* @param div - The reference divider value.
* @return - 0 in case of success or negative error code.
*/
int adf4382_set_ref_div(struct adf4382_dev *dev, int32_t div)
{
if (!dev)
return -EINVAL;
dev->ref_div = div;
if (div > ADF4382_REF_DIV_MAX)
dev->ref_div = ADF4382_REF_DIV_MAX;
return adf4382_set_freq(dev);
}
/**
* @brief Gets the value the reference divider.
* @param dev - The device structure.
* @param div - The read reference divider value.
* @return - Result of the reading procedure, error code otherwise.
*/
int adf4382_get_ref_div(struct adf4382_dev *dev, int32_t *div)
{
uint8_t tmp;
int ret;
ret = adf4382_spi_read(dev, 0x20, &tmp);
if (ret)
return ret;
dev->ref_div = no_os_field_get(ADF4382_R_DIV_MSK, tmp);
*div = dev->ref_div;
return 0;
}
/**
* @brief Set the charge pump value which will be written to the register. The
* value will be between 0 and 15 on 8 bits. For more information please
* consult the Datasheet.
* @param dev - The device structure.
* @param reg_val - The desired charge pump register value.
* @return - 0 in case of success or negative error code.
*/
int adf4382_set_cp_i(struct adf4382_dev *dev, int32_t reg_val)
{
if (!dev)
return -EINVAL;
dev->cp_i = (uint8_t)reg_val;
if (reg_val > ADF4382_CPI_VAL_MAX)
dev->cp_i = ADF4382_CPI_VAL_MAX;
return adf4382_set_freq(dev);
}
/**
* @brief Gets the charge pump value from the register. The value will be
* between 0 and 15 on 8 bits. For more information please consult the
* Datasheet.
* @param dev - The device structure.
* @param reg_val - The read charge pump register value.
* @return - 0 in case of success or negative error code.
*/
int adf4382_get_cp_i(struct adf4382_dev *dev, int32_t *reg_val)
{
uint8_t tmp;
int ret;
ret = adf4382_spi_read(dev, 0x1F, &tmp);
if (ret)
return ret;
dev->cp_i = no_os_field_get(ADF4382_CP_I_MSK, tmp);
*reg_val = dev->cp_i;
return 0;
}
/**
* @brief Set the bleed word, which represents the value of the bleed current
* written to the register space.
* @param dev - The device structure.
* @param word - The bleed current register value.
* @return - 0 in case of success or negative error code.
*/
int adf4382_set_bleed_word(struct adf4382_dev *dev, int32_t word)
{
if (!dev)
return -EINVAL;
dev->bleed_word = (uint16_t)word;
if (word > ADF4382_BLEED_WORD_MAX)
dev->bleed_word = ADF4382_BLEED_WORD_MAX;
return adf4382_set_freq(dev);
}
/**
* @brief Gets the value of the set bleed word.
* @param dev - The device structure.
* @param word - The read bleed current register value.
* @return - Result of the reading procedure, error code otherwise.
*/
int adf4382_get_bleed_word(struct adf4382_dev *dev, int32_t *word)
{
uint8_t upper;
uint8_t lower;
int ret;
ret = adf4382_spi_read(dev, 0x1E, &upper);
if (ret)
return ret;
upper &= (ADF4382_COARSE_BLEED_MSK | ADF4382_FINE_BLEED_MSB_MSK);
ret = adf4382_spi_read(dev, 0x1D, &lower);
if (ret)
return ret;
dev->bleed_word = (upper << 8) | lower;
*word = dev->bleed_word;
return 0;
}
/**
* @brief Set the output power register value of a channel and reset everything
* over to maximum supported value of 15 to the max. value.
* @param dev - The device structure.
* @param ch - The channel to set the power off.
* @param pwr - The output power register value.
* @return - Result of the writing procedure, error code otherwise.
*/
int adf4382_set_out_power(struct adf4382_dev *dev, uint8_t ch, int32_t pwr)
{
uint8_t tmp;
if (pwr > ADF4382_OUT_PWR_MAX)
pwr = ADF4382_OUT_PWR_MAX;
if (!ch) {
tmp = no_os_field_prep(ADF4382_CLK1_OPWR_MSK, pwr);
return adf4382_spi_update_bits(dev, 0x29, ADF4382_CLK1_OPWR_MSK,
tmp);
}
tmp = no_os_field_prep(ADF4382_CLK2_OPWR_MSK, pwr);
return adf4382_spi_update_bits(dev, 0x29, ADF4382_CLK2_OPWR_MSK, tmp);
}
/**
* @brief Gets the output power register value.
* @param dev - The device structure.
* @param ch - The channel to get the power off.
* @param pwr - The output power register value.
* @return - Result of the reading procedure, error code otherwise.
*/
int adf4382_get_out_power(struct adf4382_dev *dev, uint8_t ch, int32_t *pwr)
{
uint8_t tmp;
int ret;
ret = adf4382_spi_read(dev, 0x29, &tmp);
if (ret)
return ret;
if (!ch)
*pwr = no_os_field_get(ADF4382_CLK1_OPWR_MSK, tmp);
else
*pwr = no_os_field_get(ADF4382_CLK2_OPWR_MSK, tmp);
return 0;
}
/**
* @brief Set the output channel to enable or disable based on the passed
* parameter. If the parameter is different then 0 it will set the doubler to
* enable.
* @param dev - The device structure.
* @param ch - The channel to set state.
* @param en - The enable or disable value of the output channel.
* @return - Result of the writing procedure, error code otherwise.
*/
int adf4382_set_en_chan(struct adf4382_dev *dev, uint8_t ch, bool en)
{
uint8_t enable;
if (!ch) {
enable = no_os_field_prep(ADF4382_PD_CLKOUT1_MSK, !en);
return adf4382_spi_update_bits(dev, 0x2B,
ADF4382_PD_CLKOUT1_MSK,
enable);
}
enable = no_os_field_prep(ADF4382_PD_CLKOUT2_MSK, !en);
return adf4382_spi_update_bits(dev, 0x2B, ADF4382_PD_CLKOUT2_MSK,
enable);
}
/**
* @brief Gets the value the output channel if it is enabled or disable.
* @param dev - The device structure.
* @param ch - The channel to get state.
* @param en - The status of the output channel.
* @return - 0 in case of success or negative error code.
*/
int adf4382_get_en_chan(struct adf4382_dev *dev, uint8_t ch, bool *en)
{
uint8_t tmp;
bool enable;
int ret;
ret = adf4382_spi_read(dev, 0x2B, &tmp);
if (ret)
return ret;
if (!ch)
enable = no_os_field_get(tmp, ADF4382_PD_CLKOUT1_MSK);
else
enable = no_os_field_get(tmp, ADF4382_PD_CLKOUT2_MSK);
*en = !enable;
return 0;
}
/**
* @brief Set the desired output frequency and reset everything over to maximum
* supported value of 22GHz (21GHz for ADF4382A) to the max. value and
* everything under the minimum supported value of 687.5MHz (2.875GHz for
* ADF4382A) to the min. value.
* @param dev - The device structure.
* @param val - The desired output frequency in Hz.
* @return - 0 in case of success or negative error code.
*/
int adf4382_set_rfout(struct adf4382_dev *dev, uint64_t val)
{
if (!dev)
return -EINVAL;
dev->freq = val;
if (val > dev->freq_max)
dev->freq = dev->freq_max;
if (val < dev->freq_min)
dev->freq = dev->freq_min;
return adf4382_set_freq(dev);
}
/**
* @brief Computes the PFD frequency and returns the value in Hz.
* @param dev - The device structure.
* @return - PFD value in Hz.
*/
static uint64_t adf4382_pfd_compute(struct adf4382_dev *dev)
{
uint64_t pfd_freq;
pfd_freq = NO_OS_DIV_ROUND_CLOSEST(dev->ref_freq_hz, dev->ref_div);
if (dev->ref_doubler_en)
pfd_freq *= 2;
return pfd_freq;
}
/**
* @brief Gets the user proposed output frequency
* @param dev - The device structure.
* @param val - The set value of the output frequency in Hz.
* @return - 0 in case of success or negative error code.
*/
int adf4382_get_rfout(struct adf4382_dev *dev, uint64_t *val)
{
uint32_t frac1 = 0;
uint32_t frac2 = 0;
uint32_t mod2 = 0;
uint64_t freq;
uint64_t pfd;
uint8_t tmp;
uint16_t n;
int ret;
pfd = adf4382_pfd_compute(dev);
ret = adf4382_spi_read(dev, 0x11, &tmp);
if (ret)
return ret;
n = tmp & ADF4382_N_INT_MSB_MSK;
n = n << 8;
ret = adf4382_spi_read(dev, 0x10, &tmp);
if (ret)
return ret;
n |= tmp;
ret = adf4382_spi_read(dev, 0x15, &tmp);
if (ret)
return ret;
frac1 = tmp & ADF4382_FRAC1WORD_MSB;
frac1 = frac1 << 8;
ret = adf4382_spi_read(dev, 0x14, &tmp);
if (ret)
return ret;
frac1 |= tmp;
frac1 = frac1 << 8;
ret = adf4382_spi_read(dev, 0x13, &tmp);
if (ret)
return ret;
frac1 |= tmp;
frac1 = frac1 << 8;
ret = adf4382_spi_read(dev, 0x12, &tmp);
if (ret)
return ret;
frac1 |= tmp;
ret = adf4382_spi_read(dev, 0x19, &tmp);
if (ret)
return ret;
frac2 = tmp;
frac2 = frac2 << 8;
ret = adf4382_spi_read(dev, 0x18, &tmp);
if (ret)
return ret;
frac2 |= tmp;
frac2 = frac2 << 8;
ret = adf4382_spi_read(dev, 0x17, &tmp);
if (ret)
return ret;
frac2 |= tmp;
ret = adf4382_spi_read(dev, 0x1c, &tmp);
if (ret)
return ret;
mod2 = tmp;
mod2 = mod2 << 8;
ret = adf4382_spi_read(dev, 0x1b, &tmp);
if (ret)
return ret;
mod2 |= tmp;
mod2 = mod2 << 8;
ret = adf4382_spi_read(dev, 0x1a, &tmp);
if (ret)
return ret;
mod2 |= tmp;
freq = frac2 * pfd;
freq = no_os_div_u64(freq, mod2);
freq = freq + (frac1 * pfd);
freq = no_os_div_u64(freq, ADF4382_MOD1WORD);
freq = freq + (n * pfd);
*val = freq;
return 0;
}
/**
* @brief Computes the second fractional part of the feedback divider if needed.
* @param dev - The device structure.
* @param res - Residue from the first fractional part.
* @param pfd_freq - Phase/frequency detector frequency.
* @param frac2_word - Second fractional part of the feedback divider, which
* will be returned.
* @param mod2_word - Modulo for the second fractional part of the feedback
* divider, which will be returned.
* @return - 0 in case of success, negative error code otherwise.
*/
static int adf4382_frac2_compute(struct adf4382_dev *dev, uint64_t res,
uint64_t pfd_freq, uint32_t *frac2_word,
uint32_t *mod2_word)
{
uint32_t channel_spacing;
uint8_t en_phase_resync;
uint32_t chsp_freq;
uint32_t mod2_tmp;
uint32_t mod2_max;
uint32_t mod2_wd;
uint32_t gcd;
uint8_t tmp;
int ret;
channel_spacing = 1;
mod2_wd = 1;
ret = adf4382_spi_read(dev, 0x1E, &tmp);
if (ret)
return ret;
en_phase_resync = no_os_field_get(tmp, ADF4382_EN_PHASE_RESYNC_MSK);
if (en_phase_resync)
mod2_max = ADF4382_PHASE_RESYNC_MOD2WORD_MAX;
else
mod2_max = ADF4382_MOD2WORD_MAX;
do {
chsp_freq = channel_spacing * ADF4382_MOD1WORD;
gcd = no_os_greatest_common_divisor(chsp_freq, pfd_freq);
mod2_tmp = NO_OS_DIV_ROUND_UP(pfd_freq, gcd);
if (mod2_tmp > mod2_max) {
channel_spacing *= 5;
} else {
mod2_wd = mod2_tmp;
break;
}
} while (channel_spacing < ADF4382_CHANNEL_SPACING_MAX);
if (!en_phase_resync) {
mod2_wd *= NO_OS_DIV_U64(mod2_max, mod2_wd);
}
*frac2_word = NO_OS_DIV_ROUND_CLOSEST_ULL(res * mod2_wd, pfd_freq);
*mod2_word = mod2_wd;
return 0;
}
/**
* @brief Computes the feedback divider values for the PLL.
* @param dev - The device structure.
* @param freq - The output frequency.
* @param pfd_freq - Phase/frequency detector frequency.
* @param n_int - Integer part of the feedback divider, which will be
* returned.
* @param frac1_word - First fractional part of the feedback divider, which will
* be returned.
* @param frac2_word - Second fractional part of the feedback divider, which
* will be returned.
* @param mod2_word - Modulo for the second fractional part of the feedback
* divider, which will be returned.
* @return - 0 in case of success, negative error code otherwise.
*/
static int adf4382_pll_fract_n_compute(struct adf4382_dev *dev, uint64_t freq,
uint64_t pfd_freq, uint16_t *n_int,
uint32_t *frac1_word, uint32_t *frac2_word,
uint32_t *mod2_word)
{
uint64_t rem;
uint64_t res;
*n_int = no_os_div64_u64_rem(freq, pfd_freq, &rem);
res = rem * ADF4382_MOD1WORD;
*frac1_word = (uint32_t)no_os_div64_u64_rem(res, pfd_freq, &rem);
*frac2_word = 0;
*mod2_word = 0;
if (rem > 0)
return adf4382_frac2_compute(dev, rem, pfd_freq, frac2_word,
mod2_word);
return 0;
}
/**
* @brief Fast calibration function. Computes Minimum VCO frequency (fmin),
* uses the minimum NDIV value to generate fastcal Lookup table (LUT), and
* finally enables LUT Calibration.
* @param dev - The device structure.
* @param en_fast_cal - Enables the fast calibration routine.
* @return - N_INT value corresponding to minimum VCO frequency for
* fast calibration LUT generation.
*/
int adf4382_set_en_fast_calibration(struct adf4382_dev *dev, bool en_fast_cal)
{
uint64_t min_vco_frequency;
uint64_t compute_frequency;
uint32_t cntr_readback;
uint64_t fclk_max_hz = 11000000000;
uint32_t m_vco_band = 511;
uint64_t ref_freq_khz;
uint8_t t_measure = 9;
uint64_t pfd_freq;
uint32_t cal_div;
uint8_t r_mr_clk = 63;
uint32_t n_value;
uint8_t mr_clk = 8;
uint8_t n_int;
uint8_t fsm_busy;
uint8_t lut_scale = 8;
uint8_t timeout = 0;
uint32_t lut_data = 0;
uint8_t val;
uint8_t tmp;
int ret;
if (!dev)
return -EINVAL;
if (!en_fast_cal)
return 0;
n_value = NO_OS_DIV_ROUND_CLOSEST(fclk_max_hz, dev->ref_freq_hz);
ref_freq_khz = NO_OS_DIV_U64(dev->ref_freq_hz,
KHZ_PER_MHZ);
cal_div = NO_OS_DIV_ROUND_CLOSEST(t_measure * ref_freq_khz,
(r_mr_clk * mr_clk));
ret = adf4382_spi_update_bits(dev, 0x11, ADF4382_CLKOUT_DIV_MSK,
no_os_field_prep
(ADF4382_CLKOUT_DIV_MSK, 0));
if (ret)
return ret;
val = no_os_field_prep(ADF4382_EN_AUTOCAL_MSK, 0) |
no_os_field_prep(ADF4382_EN_RDBLR_MSK, 0) |
no_os_field_prep(ADF4382_R_DIV_MSK, r_mr_clk);
ret = adf4382_spi_write(dev, 0x20, val);
if (ret)
return ret;
val = cal_div & ADF4382_CNTR_DIV_WORD_MSK;
ret = adf4382_spi_write(dev, 0x3C, val);
if (ret)
return ret;
val = (cal_div >> 8) & ADF4382_CNTR_DIV_WORD_MSB_MSK;
ret = adf4382_spi_write(dev, 0x3D, val);
if (ret)
return ret;
val = no_os_field_prep(ADF4382_O_VCO_CORE_MSK, 1) |
no_os_field_prep(ADF4382_O_VCO_BAND_MSK, 1);
ret = adf4382_spi_update_bits(dev, 0x4D, ADF4382_O_VCO_CORE_MSK
| ADF4382_O_VCO_BAND_MSK, val);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x15, ADF4382_M_VCO_CORE_MSK,
no_os_field_prep(
ADF4382_M_VCO_CORE_MSK, 1));
if (ret)
return ret;
val = m_vco_band & ADF4382_M_VCO_BAND_LSB_MSK;
ret = adf4382_spi_update_bits(dev, 0x15, ADF4382_M_VCO_BAND_LSB_MSK,
no_os_field_prep
(ADF4382_M_VCO_BAND_LSB_MSK, val));
if (ret)
return ret;
val = (m_vco_band >> 1) & ADF4382_M_VCO_BAND_MSB_MSK;
ret = adf4382_spi_write(dev, 0x16, val);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_EN_VCAL_MSK,
no_os_field_prep
(ADF4382_EN_VCAL_MSK, 1));
if (ret)
return ret;
val = no_os_field_prep(ADF4382_EN_CPTEST_MSK, 1) |
no_os_field_prep(ADF4382_CP_UP_MSK, 0) |
no_os_field_prep(ADF4382_CP_DOWN_MSK, 0);
ret = adf4382_spi_update_bits(dev, 0x2E, ADF4382_EN_CPTEST_MSK
| ADF4382_CP_UP_MSK
| ADF4382_CP_DOWN_MSK, val);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x1F, ADF4382_EN_BLEED_MSK,
no_os_field_prep
(ADF4382_EN_BLEED_MSK, 0));
if (ret)
return ret;
val = no_os_field_prep(ADF4382_DCLK_DIV_SEL_MSK, 1) |
no_os_field_prep(ADF4382_DNCLK_DIV1_MSK, 0) |
no_os_field_prep(ADF4382_DCLK_DIV1_MSK, 3);
ret = adf4382_spi_update_bits(dev, 0x24, ADF4382_DCLK_DIV_SEL_MSK
| ADF4382_DNCLK_DIV1_MSK
| ADF4382_DCLK_DIV1_MSK, val);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_DCLK_MODE_MSK,
no_os_field_prep
(ADF4382_DCLK_MODE_MSK, 0));
if (ret)
return ret;
val = (n_value >> 8) & ADF4382_N_INT_MSB_MSK;
ret = adf4382_spi_update_bits(dev, 0x11, ADF4382_N_INT_MSB_MSK,
val);
if (ret)
return ret;
val = n_value & ADF4382_N_INT_LSB_MSK;
ret = adf4382_spi_write(dev, 0x10, val);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x3D, ADF4382_READ_MODE_MSK,
no_os_field_prep
(ADF4382_READ_MODE_MSK, 1));
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x34, ADF4382_RST_CNTR_MSK,
no_os_field_prep
(ADF4382_RST_CNTR_MSK, 1));
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x34, ADF4382_RST_CNTR_MSK,
no_os_field_prep
(ADF4382_RST_CNTR_MSK, 0));
if (ret)
return ret;
no_os_mdelay(t_measure + 1);
ret = adf4382_spi_read(dev, 0x57, &tmp);
if (ret)
return ret;
cntr_readback = tmp;
cntr_readback = cntr_readback << 8;
ret = adf4382_spi_read(dev, 0x56, &tmp);
if (ret)
return ret;
cntr_readback |= tmp;
cntr_readback = cntr_readback << 8;
ret = adf4382_spi_read(dev, 0x55, &tmp);
if (ret)
return ret;
cntr_readback |= tmp;
ret = adf4382_spi_update_bits(dev, 0x3D, ADF4382_READ_MODE_MSK,
no_os_field_prep
(ADF4382_READ_MODE_MSK, 0));
if (ret)
return ret;
compute_frequency = dev->ref_freq_hz * n_value * cntr_readback;
min_vco_frequency = NO_OS_DIV_U64(compute_frequency, (r_mr_clk
* 8 * cal_div));
min_vco_frequency /= 8;
pfd_freq = adf4382_pfd_compute(dev);
n_int = NO_OS_DIV_ROUND_UP(min_vco_frequency, pfd_freq);
// Reinitialize registers for accurate LUT generation
val = no_os_field_prep(ADF4382_EN_AUTOCAL_MSK, 1) |
no_os_field_prep(ADF4382_EN_RDBLR_MSK,
dev->ref_doubler_en) |
no_os_field_prep(ADF4382_R_DIV_MSK, dev->ref_div);
ret = adf4382_spi_write(dev, 0x20, val);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x1F, ADF4382_EN_BLEED_MSK,
no_os_field_prep
(ADF4382_EN_BLEED_MSK, 1));
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_EN_VCAL_MSK,
no_os_field_prep
(ADF4382_EN_VCAL_MSK, 0));
if (ret)
return ret;
val = no_os_field_prep(ADF4382_EN_CPTEST_MSK, 0) |
no_os_field_prep(ADF4382_CP_UP_MSK, 0) |
no_os_field_prep(ADF4382_CP_DOWN_MSK, 0);
ret = adf4382_spi_update_bits(dev, 0x2E, ADF4382_EN_CPTEST_MSK
| ADF4382_CP_UP_MSK |
ADF4382_CP_DOWN_MSK, val);
if (ret)
return ret;
val = no_os_field_prep(ADF4382_DCLK_DIV_SEL_MSK, 0) |
no_os_field_prep(ADF4382_DNCLK_DIV1_MSK, 0) |
no_os_field_prep(ADF4382_DCLK_DIV1_MSK, 1);
ret = adf4382_spi_update_bits(dev, 0x24, ADF4382_DCLK_DIV_SEL_MSK
| ADF4382_DNCLK_DIV1_MSK
| ADF4382_DCLK_DIV1_MSK, val);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_DCLK_MODE_MSK,
no_os_field_prep
(ADF4382_DCLK_MODE_MSK, 1));
if (ret)
return ret;
val = no_os_field_prep(ADF4382_O_VCO_CORE_MSK, 0) |
no_os_field_prep(ADF4382_O_VCO_BAND_MSK, 0);
ret = adf4382_spi_update_bits(dev, 0x4D, ADF4382_O_VCO_CORE_MSK
| ADF4382_O_VCO_BAND_MSK, val);
if (ret)
return ret;
val = n_int & ADF4382_N_INT_LSB_MSK;
ret = adf4382_spi_write(dev, 0x10, val);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x44, ADF4382_VPTAT_CALGEN_MSK,
no_os_field_prep
(ADF4382_VPTAT_CALGEN_MSK,
ADF4382_FASTCAL_VPTAT_CALGEN));
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x45, ADF4382_VCTAT_CALGEN_MSK,
no_os_field_prep
(ADF4382_VCTAT_CALGEN_MSK,
ADF4382_FASTCAL_VCTAT_CALGEN));
if (ret)
return ret;
dev->en_lut_gen = en_fast_cal;
ret = adf4382_spi_update_bits(dev, 0x36, ADF4382_EN_LUT_GEN_MSK,
no_os_field_prep
(ADF4382_EN_LUT_GEN_MSK,
dev->en_lut_gen));
if (ret)
return ret;
val = n_int & ADF4382_N_INT_LSB_MSK;
ret = adf4382_spi_write(dev, 0x10, val);
if (ret)
return ret;
ret = adf4382_spi_read(dev, 0x58, &val);
if (ret)
return ret;
fsm_busy = no_os_field_get(val, ADF4382_FSM_BUSY_MSK);
while (fsm_busy == 1) {
no_os_mdelay(10);
ret = adf4382_spi_read(dev, 0x58, &val);
if (ret)
return ret;
fsm_busy = no_os_field_get(val, ADF4382_FSM_BUSY_MSK);
if (timeout++ > 100)
break;
}
val = lut_scale & ADF4382_LUT_SCALE_MSK;
ret = adf4382_spi_write(dev, 0x4F, val);
if (ret)
return ret;
dev->en_lut_gen = 0;
ret = adf4382_spi_update_bits(dev, 0x36, ADF4382_EN_LUT_GEN_MSK,
no_os_field_prep
(ADF4382_EN_LUT_GEN_MSK,
dev->en_lut_gen));
if (ret)
return ret;
// Update LUT for 22GHz step.
dev->freq = 22000000000;
ret = adf4382_set_freq(dev);
if (ret)
return ret;
ret = adf4382_spi_read(dev, 0x11, &tmp);
if (ret)
return ret;
lut_data = no_os_field_get(tmp, ADF4382_N_INT_MSB_MSK);
lut_data = lut_data << 8;
ret = adf4382_spi_read(dev, 0x10, &tmp);
if (ret)
return ret;
lut_data |= tmp;
val = (lut_data >> 6) & ADF4382_M_LUT_N_MSB_MSK;
ret = adf4382_spi_write(dev, 0x203, val);
if (ret)
return ret;
val = lut_data & ADF4382_M_LUT_N_LSB_MSK;
ret = adf4382_spi_update_bits(dev, 0x202, ADF4382_M_LUT_N_LSB_MSK,
no_os_field_prep
(ADF4382_M_LUT_N_LSB_MSK, val));
if (ret)
return ret;
ret = adf4382_spi_read(dev, 0x5F, &tmp);
if (ret)
return ret;
val = no_os_field_get(tmp, ADF4382_VCO_CORE_MSK);
ret = adf4382_spi_update_bits(dev, 0x202, ADF4382_M_LUT_CORE_MSK,
no_os_field_prep
(ADF4382_M_LUT_CORE_MSK, val));
if (ret)
return ret;
ret = adf4382_spi_read(dev, 0x5E, &tmp);
if (ret)
return ret;
val = no_os_field_get(tmp, ADF4382_VCO_BAND_LSB_MSK);
ret = adf4382_spi_write(dev, 0x201, val);
if (ret)
return ret;
ret = adf4382_spi_read(dev, 0x5F, &tmp);
if (ret)
return ret;
val = no_os_field_get(tmp, ADF4382_M_LUT_BAND_MSB_MSK);
ret = adf4382_spi_update_bits(dev, 0x202,
ADF4382_M_LUT_BAND_MSB_MSK,
no_os_field_prep
(ADF4382_M_LUT_BAND_MSB_MSK, val));
if (ret)
return ret;
val = no_os_field_prep(ADF4382_LUT_WR_ADDR_MSK, 31) |
no_os_field_prep(ADF4382_O_VCO_LUT_MSK, 1);
ret = adf4382_spi_write(dev, 0x200, val);
if (ret)
return ret;
dev->en_lut_cal = en_fast_cal;
adf4382_spi_update_bits(dev, 0x36, ADF4382_EN_LUT_CAL_MSK,
no_os_field_prep(ADF4382_EN_LUT_CAL_MSK,
dev->en_lut_cal));
if (ret)
return ret;
return 0;
}
/**
* @brief Gets Fast calibration LUT Calibration status.
* @param dev - The device structure.
* @param en - The set value of LUT Calibration.
* @return - 0 in case of success, negative error code otherwise.
*/
int adf4382_get_en_lut_calibration(struct adf4382_dev *dev, bool *en)
{
uint8_t tmp;
int ret;
ret = adf4382_spi_read(dev, 0x36, &tmp);
if (ret)
return ret;
*en = no_os_field_get(tmp, ADF4382_EN_LUT_CAL_MSK);
return 0;
}
/**
* @brief Sets Fast calibration LUT Calibration. Refer to en_fastcal function to
* first generate fastcal Lookup Table (LUT).
* @param dev - The device structure.
* @param en_lut_cal - Enable/Disable LUT Calibration.
* @return - 0 in case of success, negative error code otherwise.
*/
int adf4382_set_en_lut_calibration(struct adf4382_dev *dev, bool en_lut_cal)
{
int ret;
dev->en_lut_cal = en_lut_cal;
if (dev->en_lut_cal == 0) {
ret = adf4382_spi_update_bits(dev, 0x44, ADF4382_VPTAT_CALGEN_MSK,
no_os_field_prep
(ADF4382_VPTAT_CALGEN_MSK,
ADF4382_VPTAT_CALGEN));
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x45, ADF4382_VCTAT_CALGEN_MSK,
no_os_field_prep
(ADF4382_VCTAT_CALGEN_MSK,
ADF4382_VCTAT_CALGEN));
if (ret)
return ret;
} else {
ret = adf4382_spi_update_bits(dev, 0x44, ADF4382_VPTAT_CALGEN_MSK,
no_os_field_prep
(ADF4382_VPTAT_CALGEN_MSK,
ADF4382_FASTCAL_VPTAT_CALGEN));
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x45, ADF4382_VCTAT_CALGEN_MSK,
no_os_field_prep
(ADF4382_VCTAT_CALGEN_MSK,
ADF4382_FASTCAL_VCTAT_CALGEN));
if (ret)
return ret;
}
return adf4382_spi_update_bits(dev, 0x36, ADF4382_EN_LUT_CAL_MSK,
no_os_field_prep(ADF4382_EN_LUT_CAL_MSK,
dev->en_lut_cal));
}
/**
* @brief Gets the user proposed output frequency from the device tree without
* reading from the device. This is to enable and accurate reading of device
* lock-time.
* @param dev - The device structure.
* @param val - Holds the software value of RFOUT Frequency set.
* @return - Output frequency in KHz.
*/
int adf4382_get_change_rfout(struct adf4382_dev *dev, uint64_t *val)
{
*val = dev->freq;
return 0;
}
/**
* @brief Set the desired output frequency and reset everything over to maximum
* supported value of 22GHz (21GHz for ADF4382A) to the max without starting
* autocalibration. value and everything under the minimum supported value of
* 687.5MHz (2.875GHz for ADF4382A) to the min. value.
* @param dev - The device structure.
* @param val - The desired output frequency in Hz.
* @return - 0 in case of success or negative error code.
*/
int adf4382_set_change_rfout(struct adf4382_dev *dev, uint64_t val)
{
if (!dev)
return -EINVAL;
dev->freq = val;
if (val > dev->freq_max)
dev->freq = dev->freq_max;
if (val < dev->freq_min)
dev->freq = dev->freq_min;
return adf4382_set_change_freq(dev);
}
/**
* @brief Computes the optimized bleed word value for the PLL in fractional mode.
* @param dev - The device structure.
* @param pfd_freq - Phase detector frequency.
* @return - 0 in case of success or negative error code.
*/
static int adf4382_bleed_word_compute(struct adf4382_dev *dev,
uint64_t pfd_freq)
{
uint32_t coars_bleed;
uint16_t bleed_delay = 0;
uint32_t fine_bleed;
uint16_t bleed_word_tmp;
uint64_t bleed_i;
uint64_t rem;
if (!dev)
return -EINVAL;
/* Computes the bleed delay based on rfout frequency in SDM MODE 0.
See Product DataSheet for more details. */
if (dev->freq < 1800000000UL)
bleed_delay = 3600;
else if (dev->freq < 4000000000)
bleed_delay = 1000;
else if (dev->freq < 10000000000UL)
bleed_delay = 625;
else if (dev->freq >= 10000000000UL)
bleed_delay = 300;
bleed_i = bleed_delay * pfd_freq * adf4382_ci_ua[dev->cp_i];
bleed_i = NO_OS_DIV_ROUND_CLOSEST(bleed_i, PS_TO_S);
coars_bleed = no_os_div64_u64_rem(bleed_i, ADF4382_COARSE_BLEED_CONST,
&rem);
fine_bleed = rem * ADF4382_FINE_BLEED_CONST_1;
fine_bleed = NO_OS_DIV_ROUND_UP(fine_bleed, ADF4382_FINE_BLEED_CONST_2);
bleed_word_tmp = coars_bleed << 9 | fine_bleed;
bleed_word_tmp = no_os_clamp(bleed_word_tmp, 1, 8191);
dev->bleed_word = bleed_word_tmp;
return 0;
}
/**
* @brief Set the output frequency. This will set the required registers to
* device but skip NDIV value, to be written separately. This Function will not
* start autocalibration until REG0010 is written.
* @param dev - The device structure.
* @return - 0 in case of success, negative error code otherwise.
*/
int adf4382_set_change_freq(struct adf4382_dev *dev)
{
uint32_t frac2_word;
uint32_t frac1_word;
uint32_t mod2_word;
uint8_t clkout_div;
uint64_t pfd_freq;
uint8_t ldwin_pw = 0;
uint8_t en_bleed;
uint16_t n_int;
uint64_t tmp;
uint64_t vco = 0;
uint8_t val;
int ret;
for (clkout_div = 0; clkout_div <= dev->clkout_div_reg_val_max; clkout_div++) {
tmp = (1 << clkout_div) * dev->freq;
if (tmp < dev->vco_min || tmp > dev->vco_max)
continue;
vco = tmp;
break;
}
if (!vco) {
pr_err("VCO is 0\n");
return -EINVAL;
}
//Calculates the PFD freq. the output will be in Hz
pfd_freq = adf4382_pfd_compute(dev);
ret = adf4382_pll_fract_n_compute(dev, dev->freq, pfd_freq, &n_int,
&frac1_word, &frac2_word, &mod2_word);
if (ret)
return ret;
if (frac1_word || frac2_word) {
en_bleed = 1;
if (pfd_freq <= 40 * MHZ) {
ldwin_pw = 7;
} else if (pfd_freq <= 50 * MHZ) {
ldwin_pw = 6;
} else if (pfd_freq <= 100 * MHZ) {
ldwin_pw = 5;
} else if (pfd_freq <= 200 * MHZ) {
ldwin_pw = 4;
} else if (pfd_freq <= 250 * MHZ) {
if (dev->freq >= 5000U * MHZ &&
dev->freq < 6400U * MHZ) {
ldwin_pw = 3;
} else {
ldwin_pw = 2;
}
}
ret = adf4382_bleed_word_compute(dev, pfd_freq);
if (ret)
return ret;
} else {
en_bleed = 0;
tmp = NO_OS_DIV_ROUND_UP(pfd_freq, MICROAMPER_PER_AMPER);
tmp *= adf4382_ci_ua[dev->cp_i];
tmp = NO_OS_DIV_ROUND_UP(dev->bleed_word, tmp);
if (tmp <= 85)
ldwin_pw = 0;
else
ldwin_pw = 1;
}
if (frac2_word) {
ret = adf4382_spi_update_bits(dev, 0x28, ADF4382_VAR_MOD_EN_MSK,
0xff);
if (ret)
return ret;
} else {
ret = adf4382_spi_update_bits(dev, 0x28, ADF4382_VAR_MOD_EN_MSK,
0x0);
if (ret)
return ret;
}
val = dev->bleed_word & ADF4382_FINE_BLEED_LSB_MSK;
ret = adf4382_spi_write(dev, 0x1D, val);
if (ret)
return ret;
val = (dev->bleed_word >> 8) & ADF4382_BLEED_MSB_MSK;
ret = adf4382_spi_update_bits(dev, 0x1E, ADF4382_BLEED_MSB_MSK,
no_os_field_prep(ADF4382_BLEED_MSB_MSK,
val));
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x1F, ADF4382_EN_BLEED_MSK,
no_os_field_prep(ADF4382_EN_BLEED_MSK,
en_bleed));
if (ret)
return ret;
val = mod2_word & ADF4382_MOD2WORD_LSB_MSK;
ret = adf4382_spi_write(dev, 0x1A, val);
if (ret)
return ret;
val = (mod2_word >> 8) & ADF4382_MOD2WORD_MID_MSK;
ret = adf4382_spi_write(dev, 0x1B, val);
if (ret)
return ret;
val = (mod2_word >> 16) & ADF4382_MOD2WORD_MSB_MSK;
ret = adf4382_spi_write(dev, 0x1C, val);
if (ret)
return ret;
val = frac2_word & ADF4382_FRAC2WORD_LSB_MSK;
ret = adf4382_spi_write(dev, 0x17, val);
if (ret)
return ret;
val = (frac2_word >> 8) & ADF4382_FRAC2WORD_MID_MSK;
ret = adf4382_spi_write(dev, 0x18, val);
if (ret)
return ret;
val = (frac2_word >> 16) & ADF4382_FRAC2WORD_MSB_MSK;
ret = adf4382_spi_write(dev, 0x19, val);
if (ret)
return ret;
val = frac1_word & ADF4382_FRAC1WORD_LSB_MSK;
ret = adf4382_spi_write(dev, 0x12, val);
if (ret)
return ret;
val = (frac1_word >> 8) & ADF4382_FRAC1WORD_MID_MSK;
ret = adf4382_spi_write(dev, 0x13, val);
if (ret)
return ret;
val = (frac1_word >> 16) & ADF4382_FRAC1WORD_MSB_MSK;
ret = adf4382_spi_write(dev, 0x14, val);
if (ret)
return ret;
val = (frac1_word >> 24) & ADF4382_FRAC1WORD_MSB;
ret = adf4382_spi_update_bits(dev, 0x15, ADF4382_FRAC1WORD_MSB, val);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x2C, ADF4382_LDWIN_PW_MSK,
no_os_field_prep(ADF4382_LDWIN_PW_MSK,
ldwin_pw));
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x11, ADF4382_CLKOUT_DIV_MSK,
no_os_field_prep(ADF4382_CLKOUT_DIV_MSK,
clkout_div));
if (ret)
return ret;
val = (n_int >> 8) & ADF4382_N_INT_MSB_MSK;
ret = adf4382_spi_update_bits(dev, 0x11, ADF4382_N_INT_MSB_MSK, val);
if (ret)
return ret;
// Need to store N_INT to trigger an auto-calibration in another function
dev->n_int = n_int;
return 0;
}
/**
* @brief Get the status of start calibration. Will always return zero to allow
* users set it multiple times to trigger autocalibration.
* @param dev - The device structure.
* @param start_cal - Overwrites start calibration attribute to 0.
* @return - 0 in case of success, negative error code otherwise.
*/
int adf4382_get_start_calibration(struct adf4382_dev *dev, bool *start_cal)
{
*start_cal = 0;
return 0;
}
/**
* @brief Set REG0010 value in device structure to the device to start autocal.
* @param dev - The device structure.
* @return - 0 in case of success, negative error code otherwise.
*/
int adf4382_set_start_calibration(struct adf4382_dev *dev)
{
uint8_t n_value;
n_value = dev->n_int & ADF4382_N_INT_LSB_MSK;
return adf4382_spi_write(dev, 0x10, n_value);
}
/**
* @brief Set the output frequency.
* @param dev - The device structure.
* @return - 0 in case of success, negative error code otherwise.
*/
int adf4382_set_freq(struct adf4382_dev *dev)
{
uint32_t frac2_word;
uint32_t frac1_word;
uint32_t mod2_word;
uint8_t clkout_div;
uint8_t dclk_div1;
uint64_t pfd_freq;
uint8_t ldwin_pw = 0;
uint8_t int_mode;
uint8_t en_bleed;
uint8_t locked;
uint16_t n_int;
uint8_t div1;
uint64_t tmp;
uint64_t vco = 0;
uint8_t val;
int ret;
val = no_os_field_prep(ADF4382_EN_RDBLR_MSK, dev->ref_doubler_en) |
no_os_field_prep(ADF4382_R_DIV_MSK, dev->ref_div);
ret = adf4382_spi_update_bits(dev, 0x20,
ADF4382_EN_RDBLR_MSK | ADF4382_R_DIV_MSK,
val);
if (ret)
return ret;
for (clkout_div = 0; clkout_div <= dev->clkout_div_reg_val_max; clkout_div++) {
tmp = (1 << clkout_div) * dev->freq;
if (tmp < dev->vco_min || tmp > dev->vco_max)
continue;
vco = tmp;
break;
}
if (!vco) {
pr_err("VCO is 0\n");
return -EINVAL;
}
//Calculates the PFD freq. the output will be in Hz
pfd_freq = adf4382_pfd_compute(dev);
ret = adf4382_spi_update_bits(dev, 0x1F, ADF4382_CP_I_MSK,
no_os_field_prep(ADF4382_CP_I_MSK,
dev->cp_i));
if (ret)
return ret;
ret = adf4382_pll_fract_n_compute(dev, dev->freq, pfd_freq, &n_int,
&frac1_word, &frac2_word, &mod2_word);
if (ret)
return ret;
if (frac1_word || frac2_word) {
int_mode = 0;
en_bleed = 1;
/*The lock detector pulse window is determined based on the
PFD frequency as described in the datasheet*/
if (pfd_freq <= 40 * MHZ) {
ldwin_pw = 7;
} else if (pfd_freq <= 50 * MHZ) {
ldwin_pw = 6;
} else if (pfd_freq <= 100 * MHZ) {
ldwin_pw = 5;
} else if (pfd_freq <= 200 * MHZ) {
ldwin_pw = 4;
} else if (pfd_freq <= 250 * MHZ) {
if (dev->freq >= 5000U * MHZ &&
dev->freq < 6400U * MHZ) {
ldwin_pw = 3;
} else {
ldwin_pw = 2;
}
}
ret = adf4382_bleed_word_compute(dev, pfd_freq);
if (ret)
return ret;
} else {
int_mode = 1;
en_bleed = 0;
tmp = NO_OS_DIV_ROUND_UP(pfd_freq, MICROAMPER_PER_AMPER);
tmp *= adf4382_ci_ua[dev->cp_i];
tmp = NO_OS_DIV_ROUND_UP(dev->bleed_word, tmp);
if (tmp <= 85)
ldwin_pw = 0;
else
ldwin_pw = 1;
}
if (frac2_word) {
ret = adf4382_spi_update_bits(dev, 0x28, ADF4382_VAR_MOD_EN_MSK,
0xff);
if (ret)
return ret;
} else {
ret = adf4382_spi_update_bits(dev, 0x28, ADF4382_VAR_MOD_EN_MSK,
0x0);
if (ret)
return ret;
}
ret = adf4382_spi_update_bits(dev, 0x15, ADF4382_INT_MODE_MSK,
no_os_field_prep(ADF4382_INT_MODE_MSK,
int_mode));
if (ret)
return ret;
val = dev->bleed_word & ADF4382_FINE_BLEED_LSB_MSK;
ret = adf4382_spi_write(dev, 0x1D, val);
if (ret)
return ret;
val = (dev->bleed_word >> 8) & ADF4382_BLEED_MSB_MSK;
ret = adf4382_spi_update_bits(dev, 0x1E, ADF4382_BLEED_MSB_MSK,
no_os_field_prep(ADF4382_BLEED_MSB_MSK,
val));
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x1F, ADF4382_EN_BLEED_MSK,
no_os_field_prep(ADF4382_EN_BLEED_MSK,
en_bleed));
if (ret)
return ret;
val = mod2_word & ADF4382_MOD2WORD_LSB_MSK;
ret = adf4382_spi_write(dev, 0x1A, val);
if (ret)
return ret;
val = (mod2_word >> 8) & ADF4382_MOD2WORD_MID_MSK;
ret = adf4382_spi_write(dev, 0x1B, val);
if (ret)
return ret;
val = (mod2_word >> 16) & ADF4382_MOD2WORD_MSB_MSK;
ret = adf4382_spi_write(dev, 0x1C, val);
if (ret)
return ret;
val = frac2_word & ADF4382_FRAC2WORD_LSB_MSK;
ret = adf4382_spi_write(dev, 0x17, val);
if (ret)
return ret;
val = (frac2_word >> 8) & ADF4382_FRAC2WORD_MID_MSK;
ret = adf4382_spi_write(dev, 0x18, val);
if (ret)
return ret;
val = (frac2_word >> 16) & ADF4382_FRAC2WORD_MSB_MSK;
ret = adf4382_spi_write(dev, 0x19, val);
if (ret)
return ret;
val = frac1_word & ADF4382_FRAC1WORD_LSB_MSK;
ret = adf4382_spi_write(dev, 0x12, val);
if (ret)
return ret;
val = (frac1_word >> 8) & ADF4382_FRAC1WORD_MID_MSK;
ret = adf4382_spi_write(dev, 0x13, val);
if (ret)
return ret;
val = (frac1_word >> 16) & ADF4382_FRAC1WORD_MSB_MSK;
ret = adf4382_spi_write(dev, 0x14, val);
if (ret)
return ret;
val = (frac1_word >> 24) & ADF4382_FRAC1WORD_MSB;
ret = adf4382_spi_update_bits(dev, 0x15, ADF4382_FRAC1WORD_MSB, val);
if (ret)
return ret;
dclk_div1 = 2;
div1 = 8;
if (pfd_freq <= ADF4382_DCLK_DIV1_0_MAX) {
dclk_div1 = 0;
div1 = 1;
} else if (pfd_freq <= ADF4382_DCLK_DIV1_1_MAX) {
dclk_div1 = 1;
div1 = 2;
}
ret = adf4382_spi_update_bits(dev, 0x24, ADF4382_DCLK_DIV1_MSK,
no_os_field_prep(ADF4382_DCLK_DIV1_MSK,
dclk_div1));
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_DCLK_MODE_MSK, 0xff);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_CAL_CT_SEL_MSK, 0xff);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_EN_ADC_CLK_MSK, 0xff);
if (ret)
return ret;
//Time for VCO calibration based on Vtune
val = ADF4382_VCO_CAL_VTUNE & ADF4382_CAL_VTUNE_TO_LSB_MSK;
ret = adf4382_spi_write(dev, 0x38, val);
if (ret)
return ret;
val = (ADF4382_VCO_CAL_VTUNE >> 8) & ADF4382_CAL_VTUNE_TO_MSB_MSK;
ret = adf4382_spi_update_bits(dev, 0x39, ADF4382_CAL_VTUNE_TO_MSB_MSK,
no_os_field_prep
(ADF4382_CAL_VTUNE_TO_MSB_MSK, val));
if (ret)
return ret;
//VCO automatic level calibration time
ret = adf4382_spi_write(dev, 0x3A, ADF4382_VCO_CAL_ALC);
if (ret)
return ret;
tmp = NO_OS_DIV_ROUND_UP(no_os_div_u64(pfd_freq, div1 * 400000) - 2, 4);
tmp = no_os_clamp(tmp, 0U, 255U);
ret = adf4382_spi_write(dev, 0x3E, tmp);
if (ret)
return ret;
// Set LD COUNT
ret = adf4382_spi_update_bits(dev, 0x2C, ADF4382_LD_COUNT_OPWR_MSK,
dev->ld_count);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x2C, ADF4382_LDWIN_PW_MSK,
no_os_field_prep(ADF4382_LDWIN_PW_MSK,
ldwin_pw));
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x11, ADF4382_CLKOUT_DIV_MSK,
no_os_field_prep(ADF4382_CLKOUT_DIV_MSK,
clkout_div));
if (ret)
return ret;
val = (n_int >> 8) & ADF4382_N_INT_MSB_MSK;
ret = adf4382_spi_update_bits(dev, 0x11, ADF4382_N_INT_MSB_MSK, val);
if (ret)
return ret;
// Need to set N_INT last to trigger an auto-calibration
val = n_int & ADF4382_N_INT_LSB_MSK;
ret = adf4382_spi_write(dev, 0x10, val);
if (ret)
return ret;
no_os_udelay(ADF4382_LKD_DELAY_US);
ret = adf4382_spi_read(dev, 0x58, &val);
if (ret)
return ret;
locked = no_os_field_get(val, ADF4382_LOCKED_MSK);
if (!locked)
return -EIO;
return 0;
}
/**
* @brief Set the phase adjustment in pico-seconds. The phase adjust will
* enable the Bleed current option as well as delay mode to 0.
* @param dev - The device structure.
* @param phase_ps - The phase adjustment in pico-seconds.
* @return - 0 in case of success, negative error code otherwise.
*/
int adf4382_set_phase_adjust(struct adf4382_dev *dev, uint32_t phase_ps)
{
uint64_t phase_reg_value;
uint32_t rfout_deg_ns;
uint32_t phase_deg_ns;
uint64_t rfout_deg_s;
uint64_t phase_bleed;
uint16_t phase_deg;
uint64_t phase_ci;
uint64_t pfd_freq;
int ret;
ret = adf4382_spi_update_bits(dev, 0x1E, ADF4382_EN_PHASE_RESYNC_MSK, 0xff);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x1F, ADF4382_EN_BLEED_MSK, 0xff);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x32, ADF4382_DEL_MODE_MSK, 0x0);
if (ret)
return ret;
dev->phase_adj = phase_ps;
//Determine the output freq. in degrees/s
rfout_deg_s = 360 * dev->freq;
//Convert it to degrees/ns
rfout_deg_ns = no_os_div_u64(rfout_deg_s, S_TO_NS);
//Determine the phase adjustment in degrees relative the output freq.
phase_deg_ns = rfout_deg_ns * phase_ps;
//Convert it to degrees/ps
phase_deg = no_os_div_u64(phase_deg_ns, NS_TO_PS);
if (phase_deg > 360) {
pr_err("Phase Adjustment cannot exceed 360deg per Clock Period\n");
return EINVAL;
}
//Phase adjustment can only be done if bleed is active, and a bleed
//constant needs to be added
phase_bleed = phase_deg * ADF4382_PHASE_BLEED_CNST;
//The charge pump current will also need to be taken in to account
phase_ci = phase_bleed * adf4382_ci_ua[dev->cp_i];
phase_ci = no_os_div_u64(phase_ci, MICROAMPER_PER_AMPER);
//Computation of the register value for the phase adjust
pfd_freq = adf4382_pfd_compute(dev);
phase_reg_value = no_os_div_u64((phase_ci * pfd_freq), (360 * dev->freq));
if (phase_reg_value > 255)
phase_reg_value -= 255;
ret = adf4382_spi_write(dev, 0x33, phase_reg_value);
if (ret)
return ret;
return adf4382_spi_update_bits(dev, 0x34, ADF4382_PHASE_ADJ_MSK, 0xff);
}
/**
* @brief Set the phase polarity. If pol = 0 then it will add the phase value
* otherwise it will subtract the phase value.
* @param dev - The device structure.
* @param polarity - The polarity to be set.
* @return - Result of the writing procedure, error code otherwise.
*/
int adf4382_set_phase_pol(struct adf4382_dev *dev, bool polarity)
{
uint8_t pol;
pol = no_os_field_prep(ADF4382_PHASE_ADJ_POL_MSK, polarity);
return adf4382_spi_update_bits(dev, 0x32, ADF4382_PHASE_ADJ_POL_MSK, pol);
}
/**
uint8_t pol;
* @brief Gets the polarity of the phase adjust.
* @param dev - The device structure.
* @param polarity - The read polarity of the phase.
* @return - Result of the tesint procedure, negative error code
* otherwise.
*/
int adf4382_get_phase_pol(struct adf4382_dev *dev, bool *polarity)
{
uint8_t tmp;
int ret;
ret = adf4382_spi_read(dev, 0x32, &tmp);
if (ret)
return ret;
*polarity = no_os_field_get(tmp, ADF4382_PHASE_ADJ_POL_MSK);
return 0;
}
/**
* @brief Set the EZSYNC features' initial state. Awaits the SW_SYNC toggle.
* @param dev - The device structure.
* @param sync - The enable or disable sync.
* @return - Result of the writing procedure, error code otherwise.
*/
int adf4382_set_ezsync_setup(struct adf4382_dev *dev, bool sync)
{
int ret;
if (!dev)
return -EINVAL;
if (sync == 1) {
ret = adf4382_spi_update_bits(dev, 0x2A, ADF4382_PD_SYNC_MSK, 0);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x53,
ADF4382_SYNC_SEL_MSK, 0xff);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x1E,
ADF4382_TIMED_SYNC_MSK, 0);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x1E,
(ADF4382_EN_REF_RST_MSK |
ADF4382_EN_PHASE_RESYNC_MSK), 0xff);
if (ret)
return ret;
} else {
ret = adf4382_spi_update_bits(dev, 0x2A, ADF4382_PD_SYNC_MSK,
0xff);
if (ret)
return ret;
}
return 0;
}
/**
* @brief Set Timed SYNC features' initial state. Uses SYNC pin.
* @param dev - The device structure.
* @param sync - The enable or disable sync.
* @return - Result of the writing procedure, error code otherwise.
*/
int adf4382_set_timed_sync_setup(struct adf4382_dev *dev, bool sync)
{
uint64_t pfd_freq;
uint8_t delay;
uint8_t val;
int ret;
if (!dev)
return -EINVAL;
if (sync == 1) {
// Timed Sync
ret = adf4382_spi_update_bits(dev, 0x2A, ADF4382_PD_SYNC_MSK, 0);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x53,
ADF4382_SYNC_SEL_MSK, 0);
if (ret)
return ret;
ret = adf4382_spi_update_bits(dev, 0x1E, (ADF4382_EN_REF_RST_MSK
| ADF4382_TIMED_SYNC_MSK
| ADF4382_EN_PHASE_RESYNC_MSK),
0xff);
if (ret)
return ret;
pfd_freq = adf4382_pfd_compute(dev);
if (pfd_freq >= 225 * MHZ) {
delay = 3;
} else if (pfd_freq >= 200 * MHZ) {
delay = 4;
} else if (pfd_freq >= 148 * MHZ) {
delay = 1;
} else if (pfd_freq >= 130 * MHZ) {
delay = 3;
} else if (pfd_freq >= 85 * MHZ) {
delay = 4;
} else if (pfd_freq < 85 * MHZ) {
delay = 0;
}
ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_SYNC_DEL_MSK,
no_os_field_prep
(ADF4382_SYNC_DEL_MSK, delay));
if (ret)
return ret;
val = no_os_field_prep(ADF4382_DRCLK_DEL_MSK, delay) |
no_os_field_prep(ADF4382_DNCLK_DEL_MSK, delay);
ret = adf4382_spi_update_bits(dev, 0x34,
ADF4382_DRCLK_DEL_MSK
| ADF4382_DNCLK_DEL_MSK, val);
if (ret)
return ret;
} else {
ret = adf4382_spi_update_bits(dev, 0x2A, ADF4382_PD_SYNC_MSK,
0xff);
if (ret)
return ret;
}
return 0;
}
/**
* @brief Gets the value of the SYNC powerdown bit.
* @param dev - The device structure.
* @param en - The read status of the sync enable.
* @return - 0 in case of success or negative error code.
*/
int adf4382_get_phase_sync_setup(struct adf4382_dev *dev, bool *en)
{
uint8_t tmp;
int ret;
ret = adf4382_spi_read(dev, 0x2A, &tmp);
if (ret)
return ret;
*en = no_os_field_get(tmp, ADF4382_PD_SYNC_MSK);
return 0;
}
/**
* @brief Set Software SYNC Request. Setting SW_SYNC resets the RF block.
* Clearing SW_SYNC makes ready for a new reference clock.
* @param dev - The device structure.
* @param sw_sync - Set send SW_SYNC request
* @return - 0 in case of success or negative error code.
*/
int adf4382_set_sw_sync(struct adf4382_dev *dev, bool sw_sync)
{
uint8_t tmp;
if (!dev)
return -EINVAL;
tmp = no_os_field_prep(ADF4382_SW_SYNC_MSK, sw_sync);
return adf4382_spi_update_bits(dev, 0x1F, ADF4382_SW_SYNC_MSK, tmp);
}
/**
* @brief Gets the value of the SW_SYNC bit.
* @param dev - The device structure.
* @param sw_sync - The read value of the SW_SYNC.
* @return - 0 in case of success or negative error code.
*/
int adf4382_get_sw_sync(struct adf4382_dev *dev, bool *sw_sync)
{
uint8_t tmp;
int ret;
if (!dev)
return -EINVAL;
ret = adf4382_spi_read(dev, 0x1F, &tmp);
if (ret)
return ret;
*sw_sync = no_os_field_get(tmp, ADF4382_SW_SYNC_MSK);
return 0;
}
/**
* @brief ADF4382 SPI Scratchpad check.
* @param dev - The device structure.
* @return - 0 in case of success or negative error code.
*/
static int adf4382_check_scratchpad(struct adf4382_dev *dev)
{
uint8_t scratchpad;
int ret;
ret = adf4382_spi_write(dev, 0x00A, ADF4382_SPI_SCRATCHPAD_TEST);
if (ret)
return ret;
ret = adf4382_spi_read(dev, 0x00A, &scratchpad);
if (ret)
return ret;
if (scratchpad != ADF4382_SPI_SCRATCHPAD_TEST)
return -EINVAL;
return 0;
}
/**
* @brief Update core bias table for ADF4383.
* @param dev - The device structure.
* @return - 0 in case of success or negative error code.
*/
static int adf4383_update_core_bias_table(struct adf4382_dev *dev)
{
int ret;
ret = adf4382_spi_write(dev, 0x109, 0x3);
if (ret)
return ret;
ret = adf4382_spi_write(dev, 0x10A, 0x7);
if (ret)
return ret;
ret = adf4382_spi_write(dev, 0x10F, 0x7);
if (ret)
return ret;
ret = adf4382_spi_write(dev, 0x110, 0x7);
if (ret)
return ret;
ret = adf4382_spi_write(dev, 0x111, 0x7);
if (ret)
return ret;
return 0;
}
/**
* @brief Initializes the ADF4382.
* @param dev - The device structure.
* @param init_param - The structure containing the device initial parameters.
* @return - 0 in case of success or negative error code.
*/
int adf4382_init(struct adf4382_dev **dev,
struct adf4382_init_param *init_param)
{
struct adf4382_dev *device;
bool en = true;
uint8_t i;
int ret;
device = (struct adf4382_dev *)no_os_calloc(1, sizeof(*device));
if (!device)
return -ENOMEM;
ret = no_os_spi_init(&device->spi_desc, init_param->spi_init);
if (ret)
goto error_dev;
device->spi_3wire_en = init_param->spi_3wire_en;
device->cmos_3v3 = init_param->cmos_3v3;
device->ref_freq_hz = init_param->ref_freq_hz;
device->freq = init_param->freq;
device->ref_doubler_en = init_param->ref_doubler_en;
device->ref_div = init_param->ref_div;
device->cp_i = init_param->cp_i;
device->bleed_word = init_param->bleed_word;
device->ld_count = init_param->ld_count;
device->phase_adj = 0;
switch (init_param->id) {
case ID_ADF4382:
device->freq_max = ADF4382_RFOUT_MAX;
device->freq_min = ADF4382_RFOUT_MIN;
device->vco_max = ADF4382_VCO_FREQ_MAX;
device->vco_min = ADF4382_VCO_FREQ_MIN;
device->clkout_div_reg_val_max = ADF4382_CLKOUT_DIV_REG_VAL_MAX;
break;
case ID_ADF4382A:
device->freq_max = ADF4382A_RFOUT_MAX;
device->freq_min = ADF4382A_RFOUT_MIN;
device->vco_max = ADF4382A_VCO_FREQ_MAX;
device->vco_min = ADF4382A_VCO_FREQ_MIN;
device->clkout_div_reg_val_max = ADF4382A_CLKOUT_DIV_REG_VAL_MAX;
break;
case ID_ADF4383:
device->freq_max = ADF4383_RFOUT_MAX;
device->freq_min = ADF4383_RFOUT_MIN;
device->vco_max = ADF4383_VCO_FREQ_MAX;
device->vco_min = ADF4383_VCO_FREQ_MIN;
device->clkout_div_reg_val_max = ADF4382_CLKOUT_DIV_REG_VAL_MAX;
break;
default:
goto error_spi;
}
ret = adf4382_spi_write(device, 0x00, ADF4382_RESET_CMD);
if (ret)
goto error_spi;
no_os_udelay(ADF4382_POR_DELAY_US);
if (device->spi_3wire_en)
en = false;
/* SPI set to 4 wire */
ret = adf4382_spi_write(device, 0x00, ADF4382_SPI_3W_CFG(en));
if (ret)
goto error_spi;
ret = adf4382_spi_write(device, 0x3D,
no_os_field_prep(ADF4382_CMOS_OV_MSK,
device->cmos_3v3));
if (ret)
goto error_spi;
ret = adf4382_check_scratchpad(device);
if (ret)
goto error_spi;
for (i = 0; i < NO_OS_ARRAY_SIZE(adf4382_reg_defaults); i++) {
ret = adf4382_spi_write(device,
adf4382_reg_defaults[i].reg,
adf4382_reg_defaults[i].val);
if (ret)
goto error_spi;
}
if (ID_ADF4383 == init_param->id) {
ret = adf4383_update_core_bias_table(device);
if (ret)
goto error_spi;
}
ret = adf4382_set_freq(device);
if (ret)
goto error_spi;
ret = adf4382_set_out_power(device, 0, 9);
if (ret)
goto error_spi;
ret = adf4382_set_out_power(device, 1, 9);
if (ret)
goto error_spi;
*dev = device;
return ret;
error_spi:
no_os_spi_remove(device->spi_desc);
error_dev:
no_os_free(device);
return ret;
}
/**
* @brief Free resources allocated for ADF4382
* @param dev - The device structure.
* @return - 0 in case of success or negative error code.
*/
int adf4382_remove(struct adf4382_dev *dev)
{
int ret;
ret = no_os_spi_remove(dev->spi_desc);
if (ret)
no_os_free(dev);
return 0;
}