diff --git a/doc/sphinx/source/drivers/adf5611.rst b/doc/sphinx/source/drivers/adf5611.rst new file mode 100644 index 00000000000..c96d8c5431e --- /dev/null +++ b/doc/sphinx/source/drivers/adf5611.rst @@ -0,0 +1 @@ +.. include:: ../../../../drivers/frequency/adf5611/README.rst \ No newline at end of file diff --git a/doc/sphinx/source/drivers_doc.rst b/doc/sphinx/source/drivers_doc.rst index abf7b202770..9136c2571d2 100644 --- a/doc/sphinx/source/drivers_doc.rst +++ b/doc/sphinx/source/drivers_doc.rst @@ -55,6 +55,7 @@ FREQUENCY GENERATORS drivers/adf4382 drivers/adf4368 + drivers/adf5611 INERTIAL MEASUREMENT UNITS ========================== diff --git a/doc/sphinx/source/projects/adf5611.rst b/doc/sphinx/source/projects/adf5611.rst new file mode 100644 index 00000000000..cba6a842b32 --- /dev/null +++ b/doc/sphinx/source/projects/adf5611.rst @@ -0,0 +1 @@ +.. include:: ../../../../projects/adf5611/README.rst \ No newline at end of file diff --git a/doc/sphinx/source/projects_doc.rst b/doc/sphinx/source/projects_doc.rst index c70368033d9..05182c7da49 100644 --- a/doc/sphinx/source/projects_doc.rst +++ b/doc/sphinx/source/projects_doc.rst @@ -23,6 +23,7 @@ FREQUENCY GENERATORS projects/adf4382 projects/adf4368 + projects/adf5611 INERTIAL MEASUREMENT UNITS ========================== diff --git a/drivers/frequency/adf5611/README.rst b/drivers/frequency/adf5611/README.rst new file mode 100644 index 00000000000..248c00265d8 --- /dev/null +++ b/drivers/frequency/adf5611/README.rst @@ -0,0 +1,398 @@ +ADF5611 no-OS driver +==================== + +Supported Devices +----------------- + +* `ADF5611 `_ +* `ADF5612 `_ + +Overview +-------- + +The `ADF5611 `_ and `ADF5612 `_ +allows implementation of fractional-N or Integer N phase-locked loop (PLL) frequency +synthesizers when used with an external loop filter and an external reference source. +The wideband microwave voltage controlled oscillator (VCO) design permits frequency operation +from 7300 MHz to 14600 MHz for `ADF5611 `_ and from 7300 +MHz to 8500 MHz for `ADF5612 `_ at a single radio +frequency (RF) output. A series of frequency dividers with a differential frequency output +allows operation from 57 MHz to 14600MHz for `ADF5611 `_, +while `ADF5612 `_ is limited to 57MHz to 8500MHz. +Analog and digital power supplies for the PLL circuitry range from 3.15 V to 3.45 V, and +the VCO supplies are between 4.75 V and 5.25 V. +Both `ADF5611 `_ and `ADF5612 `_ +has an integrated VCO with a fundamental frequency of 3650 MHz to 7300 MHz. These frequencies +are internally doubled and routed to the RFOUT pin. An additional differential output allows +the doubled VCO frequency to be divided by 1, 2, 4, 8, 16, 32, 64, or 128, allowing the user +to generate RF output frequencies as low as 57 MHz. A simple 3 or 4 wire serial port interface +(SPI) provides control of all on-chip registers. To conserve power, this divider block can be disabled +when not needed through the SPI interface. Likewise, the output power for both the single- +ended output and the differential output are programmable. Their integrated phase detector +(PD) and delta-sigma (Δ-Σ) modulator, capable of operating at up to 100 MHz, permit wide +loop bandwidths and fast frequency tuning with a typical spurious level of −100 dBc. +With phase noise levels from −115 dBc/Hz at 7.3 GHz to −109 dBc/Hz at 14.6 GHz and −112 dBc/Hz +at 8.5 GHz RFOUT respectively, both synthesizers are equipped to minimize blocker effects, +and to improve receiver sensitivity and transmitter spectral purity. The low phase noise floor +eliminates any contribution to modulator and mixer noise floor in transmitter applications. + +Applications +------------ + +* Military and Defense +* Test equipment +* Clock generation +* Wireless infrastructure +* Satellite and very small aperture terminal (VSAT) +* Microwave radio + +ADF5611 Device Configuration +---------------------------- + +Driver Initialization +--------------------- + +Communicating with the device will require the driver to support Serial Peripheral Interface +(SPI). + +The first API to be called is the **adf5611_init**. Ensure that the function call returns 0, +which means that the driver was initialized correctly. This function also performs a soft reset, +putting the device in a known state. + +Reference Clock Configuration +----------------------------- + +By default, the device is set to use a 122.88MHz clock. This can be changed to any +value, which is supported by the device, by using the function +**adf5611_set_ref_clk**. The current configuration can be read out using +**adf5612_get_ref_clk**.The input reference clock value for the function will +have to be expressed in KHz. + +Reference Divider Configuration +------------------------------- + +On the reference input path there is a divider, allowing the input reference +frequency to be divided by up to 16383. Default this is set to 2 and can be changed +using **adf5611_set_ref_div**. The current configuration can be read out using +**adf5611_get_ref_div**. + +Together with the reference doubler this feature will determine the PFD frequency. + +Charge Pump Current Configuration +--------------------------------- + +The ADF5611 has the option for 16 preset charge pump currents, ranging from 0.2 +mA to 3.2 mA. By default the charge pump current is set to 3.2 mA. The +supported currents can be configured using **adf5611_set_cp_i** API, which will +expect the register value, ranging form 0 to 15, as inputs. The current +configuration can be read out using **adf5611_get_cp_i**, which will also return +the value in the same range. + +In order to determine which value corresponds to your design charge pump +current, please refer to the datasheet `ADF5611 `_ +in the register details section for register REG0021h. + + +Output Frequency Configuration +------------------------------ + +The `ADF5611 `_ and `ADF5612 `_ +each has a main RF output and a differential divider RF output. +The main RF output range from 7300MHz to 14600MHz, and the differential divided +output is between 57MHz to 14600MHz for `ADF5611 `_, +while `ADF5612 `_ has a similar minimum main RF output +frequency but has maximum main RF output as well as divided output of 8500MHz. +The main RF output can be reconfigured by using the **adf5611_set_rfout** API. +The output frequency set by the API is expressed in Hz. The previously configured output +frequency can be read out using **adf5611_get_rfout**. + +This attribute will only set the main RFOUT frequency. While the differential output depends +on this attribute settings, its output is determined by the Ouput divider settings. + +Output Power Configuration +-------------------------- + +The output power of the RFOUT frequency can be configured using **adf5611_set_output_power** +API. The current configuration can be read out using **adf5611_get_output_power**. + +The Power of the RFOUT frequency is between 0 to 3 with 3 being the default. + +Reference Divider Configuration +------------------------------- + +On the differential ouput path there is a divider, allowing the main RFOUT frequency to be +divided evenly up to 128. By default, this is set to 1, which is equal to the RFOUT frequency +and can be changed using **adf5611_set_rfoutdiv_divider**. The current configuration can be +read out using **adf5611_get_rfoutdiv_divider**. + +Differential Divider Output Power Configuration +----------------------------------------------- + +The differential divider output power can be configured using **adf5611_set_rfoutdiv_power** API. +The current configuration can also be read out using **adf5611_get_rfoutdiv_power**. + +The Power of differential output is between 0 to 3 with 3 being the default. + +Differential Output Enable Configuration +---------------------------------------- + +The differential ouput path can be activated independently without affecting the main RF output +using **adf5611_set_en_rfoutdiv** API. +The API expects a boolean value to enable or disable the path. The current status can be +determined using the **adf5611_get_en_rfoutdiv** API. + +By default the path is disabled. 0 is disabled and 1 is enabled. + +ADF5611 Frequency Generation +---------------------------- + +Frequency Setting +----------------- + +As mentioned above, using the default values the generated frequency will be of +12 GHz. This frequency depends on all of the previous configurations and is +recalculated based on them using the **adf5611_set_rfout** API. When the API is +called, it will calculate the VCO frequency, the integer and fractional parts of +the feedback loop for the PLL while trying to obtain the configured output frequency. +The API will also write the corresponding registers with the computed values. + +ADF5611 Driver Initialization Example +------------------------------------- + +SPI Communication Example +------------------------- + +.. code-block:: bash + + struct adf5611_dev *dev; + int ret; + + struct no_os_uart_init_param adf5611_uart_ip = { + .device_id = UART_DEVICE_ID, + .irq_id = UART_IRQ_ID, + .asynchronous_rx = true, + .baud_rate = UART_BAUDRATE, + .size = NO_OS_UART_CS_8, + .parity = NO_OS_UART_PAR_NO, + .stop = NO_OS_UART_STOP_1_BIT, + .extra = UART_EXTRA, + .platform_ops = UART_OPS, + }; + + struct no_os_spi_init_param adf5611_spi_ip = { + .device_id = SPI_DEVICE_ID, + .max_speed_hz = 1500000, + .bit_order = NO_OS_SPI_BIT_ORDER_MSB_FIRST, + .mode = NO_OS_SPI_MODE_0, + .platform_ops = SPI_OPS, + .chip_select = SPI_CS, + .extra = SPI_EXTRA, + }; + + struct no_os_i2c_init_param adf5611_i2c_ip = { + .device_id = I2C_DEVICE_ID, + .platform_ops = I2C_OPS, + .max_speed_hz = 100000, + .extra = I2C_EXTRA, + .slave_address = 0x54 + }; + + struct eeprom_24xx32a_init_param adf5611_eeprom_init_param = { + .i2c_init = &adf5611_i2c_ip, + }; + + struct no_os_eeprom_init_param adf5611_eeprom_ip = { + .device_id = 5, + .platform_ops = &eeprom_24xx32a_ops, + .extra = &adf5611_eeprom_init_param, + }; + + struct adf4368_init_param adf5611_ip = { + .spi_init = &adf5611_spi_ip, + .spi4wire = true, + .cmos_3v3 = false, + .ref_clk_freq = 122880000, + .rfout_freq = 12000000000, + .ref_div = 2, + .cp_i = 15, + .bleed_word = 17, + .ld_count = 12, + .id = ID_ADF5611, + }; + + + ret = adf5611_init(&dev, &adf5611_ip); + if (ret) + goto error; + + ret = adf5611_set_freq(dev, 12000000000); + if (ret) + goto error; + + +ADF5611 no-OS IIO support +------------------------- + +The ADF5611 IIO driver comes on top of ADF5611 driver and offers support for +interfacing IIO clients through IIO lib. + +ADF5611 IIO Device Configuration +-------------------------------- + +Device Attributes +----------------- + +ADF5611 and ADF5612 has only one channel for the the RF output frequency, which makes most +of the attributes, device attributes. + +The attributes are: + +* reference_frequency - Sets the current Reference Frequency. +* reference_divider - Sets the current Reference Divider ratio. +* charge_pump_current - Sets the current Charge Pump Configuration. +* charge_pump_current_available - Returns the available Charge Pump Currents. +* rfoutdiv_power - Sets the current Differential Divider Output Power. +* rfoutdiv_divider - Sets the current Differential Divider ratio. +* rfoutdiv_divider_available - Returns the available Differential Divider Ratios. +* en_rfoutdiv - Enables or Disables the Differential Output path. + +Device Channels +--------------- + +ADF5611 and ADF5612 IIO device has 1 output channel which corresponds to the RF output +frequency. + +Which is represented as: + +* output altvoltage0 - corresponding to channel 1 on the device + +The channel has 2 attributes: + +* rfout_frequency - Sets the current RF Output Frequency. +* rfout_power - Sets the current RF Output Power. + +ADF5611 IIO Driver Initialization Example +----------------------------------------- + +.. code-block:: bash + + struct adf5611_iio_dev *adf5611_iio_dev; + struct adf5611_iio_dev_init_param adf5611_iio_ip; + struct iio_app_desc *app; + struct iio_app_init_param app_init_param = { 0 }; + struct iio_ctx_attr *context_attributes; + int ret; + + struct no_os_uart_init_param adf5611_uart_ip = { + .device_id = UART_DEVICE_ID, + .irq_id = UART_IRQ_ID, + .asynchronous_rx = true, + .baud_rate = UART_BAUDRATE, + .size = NO_OS_UART_CS_8, + .parity = NO_OS_UART_PAR_NO, + .stop = NO_OS_UART_STOP_1_BIT, + .extra = UART_EXTRA, + .platform_ops = UART_OPS, + }; + + struct no_os_spi_init_param adf5611_spi_ip = { + .device_id = SPI_DEVICE_ID, + .max_speed_hz = 1500000, + .bit_order = NO_OS_SPI_BIT_ORDER_MSB_FIRST, + .mode = NO_OS_SPI_MODE_0, + .platform_ops = SPI_OPS, + .chip_select = SPI_CS, + .extra = SPI_EXTRA, + }; + + struct no_os_i2c_init_param adf5611_i2c_ip = { + .device_id = I2C_DEVICE_ID, + .platform_ops = I2C_OPS, + .max_speed_hz = 100000, + .extra = I2C_EXTRA, + .slave_address = 0x54 + }; + + struct eeprom_24xx32a_init_param adf5611_eeprom_init_param = { + .i2c_init = &adf5611_i2c_ip, + }; + + struct no_os_eeprom_init_param adf5611_eeprom_ip = { + .device_id = 5, + .platform_ops = &eeprom_24xx32a_ops, + .extra = &adf5611_eeprom_init_param, + }; + + struct adf5611_init_param adf5611_ip = { + .spi_init = &adf5611_spi_ip, + .spi4wire = true, + .cmos_3v3 = false, + .ref_clk_freq = 122880000, + .rfout_freq = 12000000000, + .ref_div = 2, + .cp_i = 15, + .bleed_word = 17, + .ld_count = 12, + .id = ID_ADF5611, + }; + + adf5611_iio_ip.adf5611_dev_init = &adf5611_ip; + ret = adf5611_iio_init(&adf5611_iio_dev, &adf5611_iio_ip); + if (ret) + return ret; + + struct iio_app_device iio_devices[] = { + { + .name = "adf5611", + .dev = adf5611_iio_dev, + .dev_descriptor = adf5611_iio_dev->iio_dev, + } + }; + + struct no_os_eeprom_desc *eeprom_dev; + ret = eeprom_24xx32a_ops.init(&eeprom_dev, &adf5611_eeprom_ip); + if(ret) + return ret; + char board_name[17] ={0}; + char hw_mezz[25]; + uint32_t eeprom_address = 0x1B; + + ret = eeprom_24xx32a_ops.read(eeprom_dev, eeprom_address, + (uint8_t *)board_name, sizeof(board_name)); + if(ret) + return ret; + int i, index = 0; + for (i = 0; board_name[i] != '\0'; i++) + { + if (isalnum((unsigned char)board_name[i]) || board_name[i] == '-') { + hw_mezz[index++] = board_name[i]; + } + } + hw_mezz[index] = '\0'; + + ret = eeprom_24xx32a_ops.remove(eeprom_dev); + if(ret){ + return ret; + } + + context_attributes = (struct iio_ctx_attr *)calloc(NUM_CTX_ATTR, + sizeof(*context_attributes)); + context_attributes[0].name = "hw_mezzanine"; + context_attributes[0].value = hw_mezz; + context_attributes[1].name = "hw_carrier"; + context_attributes[1].value = HW_CARRIER; + context_attributes[2].name = "hw_name"; + context_attributes[2].value = ACTIVE_DEVICE_NAME; + context_attributes[3].name = "hw_vendor"; + context_attributes[3].value = ACTIVE_DEVICE_VENDOR; + + app_init_param.devices = iio_devices; + app_init_param.nb_devices = NO_OS_ARRAY_SIZE(iio_devices); + app_init_param.uart_init_params = adf5611_uart_ip; + app_init_param.ctx_attrs = context_attributes; + app_init_param.nb_ctx_attr = NUM_CTX_ATTR; + + ret = iio_app_init(&app, app_init_param); + if (ret) + goto exit; + iio_app_run(app); diff --git a/drivers/frequency/adf5611/adf5611.c b/drivers/frequency/adf5611/adf5611.c new file mode 100644 index 00000000000..87e105c38af --- /dev/null +++ b/drivers/frequency/adf5611/adf5611.c @@ -0,0 +1,971 @@ +/** + * @file adf5611.c + * @brief Implementation of adf5611 Driver. + * @author 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 "adf5611.h" +#include "no_os_alloc.h" +#include "no_os_error.h" +#include "no_os_print_log.h" +#include "no_os_delay.h" + +//Charge pump current values expressed in uA +static const int adf5611_cp_ua[] = { + 200, + 400, + 600, + 800, + 1000, + 1200, + 1400, + 1600, + 1800, + 2000, + 2200, + 2400, + 2600, + 2800, + 3000, + 3200, +}; + +/** + * @brief Writes data to ADF5611 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 adf5611_spi_write(struct adf5611_dev *dev, uint16_t reg_addr, uint8_t data) +{ + uint8_t buff[ADF5611_BUFF_SIZE_BYTES]; + uint16_t cmd; + + cmd = ADF5611_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, + ADF5611_BUFF_SIZE_BYTES); +} + +/** + * @brief Reads data from ADF5611 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 adf5611_spi_read(struct adf5611_dev *dev, uint16_t reg_addr, uint8_t *data) +{ + int ret; + uint8_t buff[ADF5611_BUFF_SIZE_BYTES]; + uint16_t cmd; + + cmd = ADF5611_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(ADF5611_SPI_DUMMY_DATA); + } else { + buff[0] = cmd >> 8; + buff[1] = cmd & 0xFF; + buff[2] = ADF5611_SPI_DUMMY_DATA; + } + + ret = no_os_spi_write_and_read(dev->spi_desc, buff, + ADF5611_BUFF_SIZE_BYTES); + if (ret) + return ret; + + *data = buff[2]; + + return 0; +} + +/** + * @brief Updates the values of the ADF5611 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 adf5611_spi_update_bits(struct adf5611_dev *dev, uint16_t reg_addr, + uint8_t mask, uint8_t data) +{ + uint8_t tmp, orig; + int ret; + + ret = adf5611_spi_read(dev, reg_addr, &orig); + if (ret) + return ret; + + tmp = orig & ~mask; + tmp |= data & mask; + + if (tmp != orig) + return adf5611_spi_write(dev, reg_addr, tmp); + + return 0; +} + +/** + * @brief Set the desired reference frequency and reset everything over to + * maximum supported value of 300MHz to the max. value and everything under the + * minimum supported value of 50MHz 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 adf5611_set_ref_clk(struct adf5611_dev *dev, uint64_t val) +{ + if (!dev) + return -EINVAL; + + dev->ref_clk_freq = val; + + if (val > ADF5611_REF_CLK_MAX) + dev->ref_clk_freq = ADF5611_REF_CLK_MAX; + + if (val < ADF5611_REF_CLK_MIN) + dev->ref_clk_freq = ADF5611_REF_CLK_MIN; + + return adf5611_set_freq(dev); +} + +/** + * @brief Gets the user proposed reference frequency + * @param dev - The device structure. + * @param val - The reference frequency in Hz. + * @return 0 in case of success or negative error code. + */ +int adf5611_get_ref_clk(struct adf5611_dev *dev, uint64_t *val) +{ + if (!dev) + return -EINVAL; + + *val = dev->ref_clk_freq; + return 0; +} + +/** + * @brief Set the reference divider value and reset everything over to maximum + * supported value of 60 to the max value + * @param dev - The device structure. + * @param div - The reference divider value. + * @return set frequency function in case of success or negative error code. + */ +int adf5611_set_ref_div(struct adf5611_dev *dev, int32_t div) +{ + if (!dev) + return -EINVAL; + + dev->ref_div = div; + + if (div > ADF5611_REF_DIV_MAX) + dev->ref_div = ADF5611_REF_DIV_MAX; + + return adf5611_set_freq(dev); +} + +/** + * @brief Gets the value the reference divider. + * @param dev - The device structure. + * @param div - The reference divider value. + * @return 0 in case of success or negative error code. + */ +int adf5611_get_ref_div(struct adf5611_dev *dev, int32_t *div) +{ + uint8_t tmp_lsb; + uint8_t tmp_msb; + uint8_t ret; + + ret = adf5611_spi_read(dev, 0x1F, &tmp_lsb); + if (ret) + return ret; + + ret = adf5611_spi_read(dev, 0x20, &tmp_msb); + if (ret) + return ret; + + dev->ref_div = no_os_field_get(ADF5611_R_DIV_MSB_MSK, tmp_msb) << 8 + | no_os_field_get(ADF5611_R_DIV_LSB_MSK, tmp_lsb); + *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 set frequency function in case of success or negative + * error code. + */ +int adf5611_set_cp_i(struct adf5611_dev *dev, int32_t reg_val) +{ + dev->cp_i = (uint8_t)reg_val; + + if (reg_val > ADF5611_CPI_VAL_MAX) + dev->cp_i = ADF5611_CPI_VAL_MAX; + + return adf5611_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 charge pump register value. + * @return 0 in case of success or negative error code. + */ +int adf5611_get_cp_i(struct adf5611_dev *dev, int32_t *reg_val) +{ + uint8_t tmp_cp_i; + uint8_t ret; + + ret = adf5611_spi_read(dev, 0x21, &tmp_cp_i); + if (ret) + return ret; + + dev->cp_i = no_os_field_get(ADF5611_CP_I_MSK, tmp_cp_i); + *reg_val = dev->cp_i; + + return 0; +} + +/** + * @brief Computes the PFD frequency and returns the value in Hz. + * @param dev - The device structure. + * @return Returns PFD value in Hz. + */ +static uint64_t adf5611_pfd_compute(struct adf5611_dev *dev) +{ + uint64_t pfd_freq; + + pfd_freq = NO_OS_DIV_U64(dev->ref_clk_freq, dev->ref_div); + + return pfd_freq; +} + +/** + * @brief Set the rfoutput power register value and reset everything over to + * maximum supported value of 3 to the max. value. + * @param dev - The device structure. + * @param pwr - The output power register value. + * @return Result of the writing procedure, error code otherwise. + */ +int adf5611_set_output_power(struct adf5611_dev *dev, int8_t pwr) +{ + uint8_t tmp; + + if (pwr > ADF5611_RFOUT_PWR_MAX) + pwr = ADF5611_RFOUT_PWR_MAX; + + tmp = no_os_field_prep(ADF5611_RFOUT_PWR_MSK, pwr); + return adf5611_spi_update_bits(dev, 0x22, ADF5611_RFOUT_PWR_MSK, tmp); +} + +/** + * @brief Gets the rfoutput power register value. + * @param dev - The device structure. + * @param pwr - The output power register value. + * @return 0 in case of success or negative error code. + */ +int adf5611_get_output_power(struct adf5611_dev *dev, int8_t *pwr) +{ + uint8_t tmp; + int ret; + + ret = adf5611_spi_read(dev, 0x22, &tmp); + if (ret) + return ret; + + *pwr = no_os_field_get(ADF5611_RFOUT_PWR_MSK, tmp); + + return 0; +} + +/** + * @brief Set the rfoutdiv power register value and reset everything over to + * maximum supported value of 3 to the max. value. + * @param dev - The device structure. + * @param pwr - The rfoutdiv power register value. + * @return Result of the writing procedure, error code otherwise. + */ +int adf5611_set_rfoutdiv_power(struct adf5611_dev *dev, int32_t pwr) +{ + uint8_t tmp; + + if (pwr > ADF5611_RFOUTDIV_PWR_MAX) + pwr = ADF5611_RFOUTDIV_PWR_MAX; + + tmp = no_os_field_prep(ADF5611_DIV_PWR_MSK, pwr); + return adf5611_spi_update_bits(dev, 0x22, ADF5611_DIV_PWR_MSK, tmp); +} + +/** + * @brief Gets the rfoutdiv power register value. + * @param dev - The device structure. + * @param pwr - The rfoutdiv power register value. + * @return 0 in case of success or negative error code. + */ +int adf5611_get_rfoutdiv_power(struct adf5611_dev *dev, int32_t *pwr) +{ + + uint8_t tmp; + int ret; + + ret = adf5611_spi_read(dev, 0x22, &tmp); + if (ret) + return ret; + + *pwr = no_os_field_get(ADF5611_DIV_PWR_MSK, tmp); + + return 0; +} + +/** + * @brief Set the rfoutdiv frequency divider register value and reset everything + * over to maximum supported value of 128 to the max. value. + * @param dev - The device structure. + * @param div_val - The rfoutdiv divider register value. + * @return Result of the writing procedure, error code otherwise. + */ +int adf5611_set_rfoutdiv_divider(struct adf5611_dev *dev, uint8_t div_val) +{ + uint8_t tmp; + if (!dev) + return -EINVAL; + + dev->rfoutdiv_div = (uint8_t) div_val; + + if (div_val > ADF5611_RFOUTDIV_DIV_MAX) + dev->rfoutdiv_div = ADF5611_RFOUTDIV_DIV_MAX; + + tmp = no_os_field_prep(ADF5611_RFOUT_DIV_MSK, dev->rfoutdiv_div); + return adf5611_spi_update_bits(dev, 0x22, ADF5611_RFOUT_DIV_MSK, tmp); +} + +/** + * @brief Gets the rfoutdiv divider register value. + * @param dev - The device structure. + * @param div - The rfoutdiv divider register value. + * @return 0 in case of success or negative error code. + */ +int adf5611_get_rfoutdiv_divider(struct adf5611_dev *dev, int8_t *div) +{ + + uint8_t tmp; + int ret; + + ret = adf5611_spi_read(dev, 0x22, &tmp); + if (ret) + return ret; + + dev->rfoutdiv_div = no_os_field_get(ADF5611_RFOUT_DIV_MSK, tmp); + *div = dev->rfoutdiv_div; + + return 0; +} + +/** + * @brief Sets the rfoutdiv output block to enable or disable. 1 means the block + * is powered down else block is powered up. + * @param dev - The device structure. + * @param en - Enable/Disable rfoutdiv output. + * @return Result of the writing procedure, error code otherwise. + */ +int adf5611_set_en_rfoutdiv(struct adf5611_dev *dev, bool en) +{ + uint8_t enable; + + enable = no_os_field_prep(ADF5611_PD_ODIV_MSK, en); + return adf5611_spi_update_bits(dev, 0x28, ADF5611_PD_ODIV_MSK, enable); +} + +/** + * @brief Gets the value of rfoutdiv output block if enable or disable. + * @param dev - The device structure. + * @param en - The status of rfoutdiv output block. + * @return 0 in case of success, negative error code otherwise. + */ +int adf5611_get_en_rfoutdiv(struct adf5611_dev *dev, bool *en) +{ + uint8_t tmp; + bool enable; + int ret; + + ret = adf5611_spi_read(dev, 0x28, &tmp); + if (ret) + return ret; + + enable = no_os_field_get(tmp, ADF5611_PD_ODIV_MSK); + *en = enable; + + return 0; +} + +/** + * @brief ADF5611 SPI Scratchpad check. + * @param dev - The device structure. + * @return 0 in case of success or negative error code. + */ +static int adf5611_check_scratchpad(struct adf5611_dev *dev) +{ + uint8_t scratchpad; + int ret; + + ret = adf5611_spi_write(dev, 0x00A, ADF5611_SPI_SCRATCHPAD_TEST); + if (ret) + return ret; + + ret = adf5611_spi_read(dev, 0x00A, &scratchpad); + if (ret) + return ret; + + if (scratchpad != ADF5611_SPI_SCRATCHPAD_TEST) + return -EINVAL; + + return 0; +} + +/** + * @brief Set the desired output frequency and reset everything over to maximum + * supported value of 14.6GHz to the max. value and everything under the minimum + * supported value of 7.3GHz to the min. value. + * @param dev - The device structure. + * @param val - The desired output frequency in Hz. + * @return set frequency function in case of success or negative + * error code. + */ +int adf5611_set_rfout(struct adf5611_dev *dev, uint64_t val) +{ + dev->rfout_freq = val; + + if (val > ADF5611_RFOUT_MAX) + dev->rfout_freq = ADF5611_RFOUT_MAX; + + if (val < ADF5611_RFOUT_MIN) + dev->rfout_freq = ADF5611_RFOUT_MIN; + + return adf5611_set_freq(dev); +} + +/** + * @brief Gets the user proposed output frequency + * @param dev - The device structure. + * @param val - The output frequency in Hz. + * @return 0 in case of success or negative error code. + */ +int adf5611_get_rfout(struct adf5611_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; + uint32_t n; + int ret; + + pfd = adf5611_pfd_compute(dev); + + ret = adf5611_spi_read(dev, 0x12, &tmp); + if (ret) + return ret; + + n = tmp & ADF5611_N_INT_MSB_MSK; + n = n << 8; + + ret = adf5611_spi_read(dev, 0x11, &tmp); + if (ret) + return ret; + n |= tmp & ADF5611_N_INT_MID_MSK; + n = n << 8; + + ret = adf5611_spi_read(dev, 0x10, &tmp); + if (ret) + return ret; + n |= tmp & ADF5611_N_INT_LSB_MSK; + + // Get FRAC1WORD + ret = adf5611_spi_read(dev, 0x15, &tmp); + if (ret) + return ret; + frac1 = tmp & ADF5611_FRAC1WORD_MSB_MSK; + frac1 = frac1 << 8; + + ret = adf5611_spi_read(dev, 0x14, &tmp); + if (ret) + return ret; + frac1 |= tmp; + frac1 = frac1 << 8; + + ret = adf5611_spi_read(dev, 0x13, &tmp); + if (ret) + return ret; + frac1 |= tmp; + frac1 = frac1 << 4; + + ret = adf5611_spi_read(dev, 0x12, &tmp); + if (ret) + return ret; + frac1 |= tmp & ADF5611_FRAC1WORD_LSB_MSK; + + // Get FRAC2WORD + ret = adf5611_spi_read(dev, 0x19, &tmp); + if (ret) + return ret; + frac2 = tmp; + frac2 = frac2 << 8; + + ret = adf5611_spi_read(dev, 0x18, &tmp); + if (ret) + return ret; + frac2 |= tmp; + frac2 = frac2 << 8; + + ret = adf5611_spi_read(dev, 0x17, &tmp); + if (ret) + return ret; + frac2 |= tmp; + + // get MOD2WORD + ret = adf5611_spi_read(dev, 0x1c, &tmp); + if (ret) + return ret; + mod2 = tmp; + mod2 = mod2 << 8; + + ret = adf5611_spi_read(dev, 0x1b, &tmp); + if (ret) + return ret; + mod2 |= tmp; + mod2 = mod2 << 8; + + ret = adf5611_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, ADF5611_MOD1WORD); + freq = (freq + (n * pfd)) * ADF5611_OUTPUT_DOUBLER; + + *val = freq; + return 0; +} + +/** + * @brief Compute the output frequency register values. + * @param f_vco - The vco frequency. + * @param pfd_freq - The pfd frequency. + * @param n_int - The N integer value. + * @param frac1_word - The frac1word value . + * @param frac2_word - The frac2word value. + * @param mod2_word - mod2_word value + * @return 0 in case of success, negative error code otherwise. + */ +static int adf5611_frac_compute(uint64_t f_vco, 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; + uint32_t mod2_max; + uint64_t mod2_wd; + uint32_t mod2_tmp; + uint32_t channel_spacing; + uint32_t chsp_freq; + uint32_t gcd; + channel_spacing = 1; + mod2_wd = 1; + + mod2_max = ADF5611_MOD2WORD_MAX; + + do { + chsp_freq = channel_spacing * ADF5611_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 < ADF5611_CHANNEL_SPACING_MAX); + + *n_int = no_os_div64_u64_rem(f_vco, pfd_freq, &rem); + + res = rem * ADF5611_MOD1WORD; + *frac1_word = (uint32_t)no_os_div64_u64_rem(res, pfd_freq, &rem); + *frac2_word = 0; + *mod2_word = 0; + + if (rem > 0) { + 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 Set the output frequency. + * @param dev - The device structure. + * @return 0 in case of success, negative error code otherwise. + */ +int adf5611_set_freq(struct adf5611_dev *dev) +{ + uint64_t tmp_bleedtime; + uint16_t cal_vtune_to; + uint16_t cal_count_to; + uint16_t cal_vco_to; + uint32_t frac2_word; + uint32_t frac1_word; + uint32_t mod2_word; + uint64_t pfd_freq; + uint8_t ldwin_pw; + uint8_t int_mode; + uint8_t en_bleed; + uint64_t tmp_div; + uint8_t locked; + uint16_t n_int; + uint64_t f_vco; + uint64_t freq; + uint8_t val; + int ret; + + freq = dev->rfout_freq; + val = dev->ref_div & ADF5611_R_DIV_LSB_MSK; + ret = adf5611_spi_write(dev, 0x1F, val); + + // write R_DIV Register + val = (dev->ref_div >> 8) & ADF5611_R_DIV_MSB_MSK; + ret = adf5611_spi_update_bits(dev, 0x20, ADF5611_R_DIV_MSB_MSK, val); + if (ret) + return ret; + + f_vco = NO_OS_DIV_U64(freq, ADF5611_OUTPUT_DOUBLER); + + if (f_vco == 0) { + pr_err("VCO is 0\n"); + } + + // Compute the PFD Frequency + pfd_freq = adf5611_pfd_compute(dev); + + // Write Charge pump value + ret = adf5611_spi_update_bits(dev, 0x21, ADF5611_CP_I_MSK, + no_os_field_prep(ADF5611_CP_I_MSK, + dev->cp_i)); + if (ret) + return ret; + + // adf5611_frac_compute function to be continued + ret = adf5611_frac_compute(f_vco, 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; + ldwin_pw = 3; + + // Bleed Calculation + tmp_bleedtime = ADF5611_BLEED_TIME_CONST * pfd_freq * + adf5611_cp_ua[dev->cp_i] * KHZ; + tmp_div = freq * ADF5611_BLEED_CURRENT; + val = ADF5611_BLEED_I_MSK & NO_OS_DIV_ROUND_CLOSEST_ULL(tmp_bleedtime, + tmp_div); + ret = adf5611_spi_write(dev, 0x1D, val); + if (ret) + return ret; + } else { + int_mode = 1; + en_bleed = 0; + ldwin_pw = 1; + } + if (frac2_word) { + ret = adf5611_spi_update_bits(dev, 0x26, ADF5611_VAR_MOD_EN_MSK, 0xff); + if (ret) + return ret; + } else { + ret = adf5611_spi_update_bits(dev, 0x26, ADF5611_VAR_MOD_EN_MSK, 0x0); + if (ret) + return ret; + } + // Write INT_MODE value + ret = adf5611_spi_update_bits(dev, 0x21, ADF5611_INTMODE_EN_MSK, + no_os_field_prep(ADF5611_INTMODE_EN_MSK, + int_mode)); // monitor this behavior + if (ret) + return ret; + // Write EN_BLEED value + ret = adf5611_spi_update_bits(dev, 0x1E, ADF5611_EN_BLEED_MSK, + no_os_field_prep(ADF5611_EN_BLEED_MSK, + en_bleed)); + if (ret) + return ret; + // Write MOD2_WORD to register + val = mod2_word & ADF5611_MOD2WORD_LSB_MSK; + ret = adf5611_spi_write(dev, 0x1A, val); + if (ret) + return ret; + val = (mod2_word >> 8) & ADF5611_MOD2WORD_MID_MSK; + ret = adf5611_spi_write(dev, 0x1B, val); + if (ret) + return ret; + val = (mod2_word >> 16) & ADF5611_MOD2WORD_MSB_MSK; + ret = adf5611_spi_write(dev, 0x1C, val); + if (ret) + return ret; + + // Write FRAC2_WORD to register + val = frac2_word & ADF5611_FRAC2WORD_LSB_MSK; + ret = adf5611_spi_write(dev, 0x17, val); + if (ret) + return ret; + val = (frac2_word >> 8) & ADF5611_FRAC2WORD_MID_MSK; + ret = adf5611_spi_write(dev, 0x18, val); + if (ret) + return ret; + val = (frac2_word >> 16) & ADF5611_FRAC2WORD_MSB_MSK; + ret = adf5611_spi_write(dev, 0x19, val); + if (ret) + return ret; + + // Write FRAC1_WORD to register + val = frac1_word & ADF5611_FRAC1WORD_LSB_MSK; + ret = adf5611_spi_write(dev, 0x12, val); + if (ret) + return ret; + val = (frac1_word >> 4) & ADF5611_FRAC1WORD_MID_MSK; + ret = adf5611_spi_write(dev, 0x13, val); + if (ret) + return ret; + val = (frac1_word >> 12) & ADF5611_FRAC1WORD_MID_MSB_MSK; + ret = adf5611_spi_write(dev, 0x14, val); + if (ret) + return ret; + val = (frac1_word >> 20) & ADF5611_FRAC1WORD_MSB_MSK; + ret = adf5611_spi_write(dev, 0x15, val); + if (ret) + return ret; + + // Write LD_COUNT value + ret = adf5611_spi_update_bits(dev, 0x29, ADF5611_LD_COUNT_MSK, + dev->ld_count); + if (ret) + return ret; + + // Write LD_WINDOW value + ret = adf5611_spi_update_bits(dev, 0x29, ADF5611_LDWIN_PW_MSK, + no_os_field_prep(ADF5611_LDWIN_PW_MSK, + ldwin_pw)); + if (ret) + return ret; + + // VCO Calibration data write + cal_vtune_to = NO_OS_DIV_ROUND_UP(pfd_freq, MHZ); + val = cal_vtune_to & ADF5611_CAL_VTUNE_TO_LSB_MSK; + ret = adf5611_spi_write(dev, 0x30, val); + if (ret) + return ret; + val = (cal_vtune_to >> 8) & ADF5611_CAL_VTUNE_TO_MSB_MSK; + ret = adf5611_spi_update_bits(dev, 0x31, ADF5611_CAL_VTUNE_TO_MSB_MSK, + val); + if (ret) + return ret; + + cal_count_to = NO_OS_DIV_ROUND_UP(pfd_freq, 2 * MHZ); + val = cal_count_to & ADF5611_CAL_COUNT_TO_MSK; + ret = adf5611_spi_update_bits(dev, 0x2f, ADF5611_CAL_COUNT_TO_MSK, val); + if (ret) + return ret; + + cal_vco_to = NO_OS_DIV_ROUND_UP(2 * pfd_freq, MHZ); + val = cal_vco_to & ADF5611_CAL_VCO_TO_LSB_MSK; + ret = adf5611_spi_write(dev, 0x32, val); + if (ret) + return ret; + val = (cal_vco_to >> 8) & ADF5611_CAL_VCO_TO_MSB_MSK; + ret = adf5611_spi_update_bits(dev, 0x33, ADF5611_CAL_VCO_TO_MSB_MSK, + val); + if (ret) + return ret; + + // Handle N_INT values + val = (n_int >> 16) & ADF5611_N_INT_MSB_MSK; + ret = adf5611_spi_update_bits(dev, 0x12, ADF5611_N_INT_MSB_MSK, val); + if (ret) + return ret; + + val = (n_int >> 8) & ADF5611_N_INT_MID_MSK; + ret = adf5611_spi_update_bits(dev, 0x11, ADF5611_N_INT_MID_MSK, val); + if (ret) + return ret; + + // Write Register 0x10 to trigger auto calibration + val = n_int & ADF5611_N_INT_LSB_MSK; + ret = adf5611_spi_write(dev, 0x10, val); + if (ret) + return ret; + + no_os_udelay(ADF5611_LKD_DELAY_US); + ret = adf5611_spi_read(dev, 0x48, &val); + if (ret) + return ret; + + locked = no_os_field_get(val, ADF5611_LOCKED_MSK); + if (!locked) + return -EIO; + + return 0; +} + +/** + * @brief Initialize the ADF5611. + * @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 adf5611_init(struct adf5611_dev **dev, + struct adf5611_init_param *init_param) +{ + struct adf5611_dev *device; + uint8_t i; + int ret; + + device = (struct adf5611_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->spi4wire = init_param->spi4wire; + device->cmos_3v3 = init_param->cmos_3v3; + device->ref_clk_freq = init_param->ref_clk_freq; + device->rfout_freq = init_param->rfout_freq; + device->ref_div = init_param->ref_div; + device->cp_i = init_param->cp_i; + device->ld_count = init_param->ld_count; + device->rfoutdiv_div = init_param->rfoutdiv_div; + + switch (init_param->id) { + case ID_ADF5611: + device->freq_max = ADF5611_RFOUT_MAX; + device->freq_min = ADF5611_RFOUT_MIN; + break; + case ID_ADF5612: + device->freq_max = ADF5612_RFOUT_MAX; + device->freq_min = ADF5612_RFOUT_MIN; + break; + default: + goto error_spi; + } + + ret = adf5611_spi_write(device, 0x00, ADF5611_RESET_CMD); + if (ret) + goto error_spi; + + no_os_udelay(ADF5611_POR_DELAY_US); + + /* Setup SPI for 4 Wire */ + ret = adf5611_spi_write(device, 0x00, ADF5611_SPI_4W_CFG(device->spi4wire)); + if (ret) + goto error_spi; + + ret = adf5611_spi_write(device, 0x35, ADF5611_CMOS_OV(device->cmos_3v3)); + if (ret) + goto error_spi; + + /* Run test to confirm SPI works by checking Scratchpad */ + ret = adf5611_check_scratchpad(device); + if (ret) + goto error_spi; + + /* Write Default Registers */ + for (i = 0; i < NO_OS_ARRAY_SIZE(adf5611_reg_defaults); i++) { + ret = adf5611_spi_write(device, adf5611_reg_defaults[i].reg, + adf5611_reg_defaults[i].val); + if (ret) + goto error_spi; + } + + ret = adf5611_set_freq(device); + 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 ADF5611 + * @param dev - The device structure. + * @return 0 in case of success or negative error code. + */ +int adf5611_remove(struct adf5611_dev *dev) +{ + int ret; + + ret = no_os_spi_remove(dev->spi_desc); + if (ret) + no_os_free(dev); + + return 0; +} diff --git a/drivers/frequency/adf5611/adf5611.h b/drivers/frequency/adf5611/adf5611.h new file mode 100644 index 00000000000..1ce516bf7e7 --- /dev/null +++ b/drivers/frequency/adf5611/adf5611.h @@ -0,0 +1,600 @@ +/***************************************************************************//** + * @file adf5611.h + * @brief Implementation of adf5611 Driver. + * @author 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 +#include +#include "no_os_util.h" +#include "no_os_spi.h" + +/* ADF5611 REG0000 Map */ +#define ADF5611_SOFT_REST_R_MSK NO_OS_BIT(7) +#define ADF5611_LSB_FIRST_R_MSK NO_OS_BIT(6) +#define ADF5611_ADDRESS_ASC_R_MSK NO_OS_BIT(5) +#define ADF5611_SDO_ACTIVE_R_MSK NO_OS_BIT(4) +#define ADF5611_SDO_ACTIVE_MSK NO_OS_BIT(3) +#define ADF5611_ADDRESS_ASC_MSK NO_OS_BIT(2) +#define ADF5611_LSB_FIRST_MSK NO_OS_BIT(1) +#define ADF5611_SOFT_RESET_MSK NO_OS_BIT(0) +#define ADF5611_RESET_CMD 0x81 + +/* ADF5611 REG0000 NO_OS_BIT DEFINITION */ +#define ADF5611_SDO_ACTIVE_SPI_3WIRE 0x0 +#define ADF5611_SDO_ACTIVE_SPI_4WIRE 0x1 + +#define ADF5611_ADDRESS_ASC_AUTO_DECR 0x0 +#define ADF5611_ADDRESS_ASC_AUTO_INCR 0x1 + +#define ADF5611_LSB_FIRST_MSB 0x0 +#define ADF5611_LSB_FIRST_LSB 0x1 + +#define ADF5611_SOFT_RESET_NORMAL_OP 0x0 +#define ADF5611_SOFT_RESET_EN 0x1 + +/* ADF5611 REG0001 MAP */ +#define ADF5611_SINGLE_INSTR_MSK NO_OS_BIT(7) +#define ADF5611_MASTER_READBACK_CTRL_MSK NO_OS_BIT(5) + +/* ADF5611 REG0001 NO_OS_BIT DEFINITION */ +#define ADF5611_SPI_STREAM_EN 0x0 +#define ADF5611_SPI_STREAM_DIS 0x1 + +#define ADF5611_RB_SLAVE_REG 0x0 +#define ADF5611_RB_MASTER_REG 0x1 + +/* ADF5611 REG0003 NO_OS_BIT DEFINITION */ +#define ADF5611_CHIP_TYPE 0x06 + +/* ADF5611 REG0004 NO_OS_BIT DEFINITION */ +#define ADF5611_PRODUCT_ID_LSB 0x0005 + +/* ADF5611 REG0005 NO_OS_BIT DEFINITION */ +#define ADF5611_PRODUCT_ID_MSB 0x0005 + +/* ADF5611 REG000A Map */ +#define ADF5611_SCRATCHPAD_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG000C NO_OS_BIT DEFINITION */ +#define ADF5611_VENDOR_ID_LSB 0x56 + +/* ADF5611 REG000D NO_OS_BIT DEFINITION */ +#define ADF5611_VENDOR_ID_MSB 0x04 + +/* ADF5611 REG0010 MAP*/ +#define ADF5611_N_INT_LSB_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0011 MAP*/ +#define ADF5611_N_INT_MID_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0012 MAP */ +#define ADF5611_FRAC1WORD_LSB_MSK NO_OS_GENMASK(7, 4) +#define ADF5611_N_INT_MSB_MSK NO_OS_GENMASK(3, 0) + +/* ADF5611 REG0013 MAP */ +#define ADF5611_FRAC1WORD_MID_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0014 MAP */ +#define ADF5611_FRAC1WORD_MID_MSB_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0015 MAP */ +#define ADF5611_M_VCO_BIAS_MSK NO_OS_GENMASK(7, 5) +#define ADF5611_FRAC1WORD_MSB_MSK NO_OS_GENMASK(4, 0) + +/* ADF5611 REG0016 MAP */ +#define ADF5611_M_VCO_BAND_MSK NO_OS_GENMASK(7, 1) +#define ADF5611_M_VCO_CORE_MSK NO_OS_BIT(0) + +/* ADF5611 REG0016 NO_OS_BIT DEFINITION */ +#define ADF5611_VCO_0_HIGHEST_FREQUENCY 0x0 +#define ADF5611_VCO_1_LOWEST_FREQUENCY 0x1 + +/* ADF5611 REG0017 MAP */ +#define ADF5611_FRAC2WORD_LSB_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0018 MAP */ +#define ADF5611_FRAC2WORD_MID_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0019 MAP */ +#define ADF5611_FRAC2WORD_MSB_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG001A MAP */ +#define ADF5611_MOD2WORD_LSB_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG001B MAP */ +#define ADF5611_MOD2WORD_MID_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG001C MAP */ +#define ADF5611_MOD2WORD_MSB_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG001D MAP */ +#define ADF5611_BLEED_I_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG001E MAP */ +#define ADF5611_EN_AUTOCAL_MSK NO_OS_BIT(7) +#define ADF5611_EN_BLEED_MSK NO_OS_BIT(6) +#define ADF5611_EN_DCLK_MODE_MSK NO_OS_BIT(5) +#define ADF5611_EN_DNCLK_MSK NO_OS_BIT(4) +#define ADF5611_DNCLK_DIV1_MSK NO_OS_GENMASK(3, 2) +#define ADF5611_PFD_POL_MSK NO_OS_BIT(1) +#define ADF5611_BLEED_POL_MSK NO_OS_BIT(0) + +/* ADF5611 REG001E NO_OS_BIT DEFINITION */ +#define ADF5611_VCO_CALIBRATION_DIS 0x0 +#define ADF5611_VCO_CALIBRATION_EN 0x1 + +#define ADF5611_BLEED_CURRENT_DIS 0x0 +#define ADF5611_BLEED_CURRENT_EN 0x1 + +#define ADF5611_FREQUENCY_REDUCTION_DIS 0x0 +#define ADF5611_FREQUENCY_REDUCTION_EN 0x1 + +#define ADF5611_DIV_NCLK_OFF 0x0 +#define ADF5611_DIV_NCLK_ON 0x1 + +#define ADF5611_CURRENT_SINK 0x0 +#define ADF5611_CURRENT_SOURCE 0x1 + +/* ADF5611 REG001F MAP */ +#define ADF5611_R_DIV_LSB_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0020 MAP */ +#define ADF5611_R_DIV_MSB_MSK NO_OS_GENMASK(5, 0) + + +/* ADF5611 REG0021 MAP */ +#define ADF5611_INTMODE_EN_MSK NO_OS_BIT(6) +#define ADF5611_RST_RDIV_MSK NO_OS_BIT(5) +#define ADF5611_EN_RCNTR_MSK NO_OS_BIT(4) +#define ADF5611_CP_I_MSK NO_OS_GENMASK(3, 0) + +/* ADF5611 REG0021 NO_OS_BIT DEFINITION */ +#define ADF5611_FRAC_MODE 0x0 +#define ADF5611_INTEGER_MODE 0x1 + +/* ADF5611 REG0022 MAP */ +#define ADF5611_RFOUT_DIV_MSK NO_OS_GENMASK(7, 5) +#define ADF5611_RFOUT_PWR_MSK NO_OS_GENMASK(4, 3) +#define ADF5611_DIV_PWR_MSK NO_OS_GENMASK(1, 0) + +/* ADF5611 REG0023 MAP*/ +#define ADF5611_PHASE_WORD_LSB_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0024 MAP*/ +#define ADF5611_PHASE_WORD_MID_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0025 MAP*/ +#define ADF5611_PHASE_WORD_MSB_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0026 MAP */ +#define ADF5611_LSB_P1_MSK NO_OS_BIT(6) +#define ADF5611_VAR_MOD_EN_MSK NO_OS_BIT(5) +#define ADF5611_DITHER1_SCALE_MSK NO_OS_GENMASK(4, 2) +#define ADF5611_EN_DITHER2_MSK NO_OS_BIT(1) +#define ADF5611_EN_DITHER1_MSK NO_OS_BIT(0) + +/* ADF5611 REG0027 MAP */ +#define ADF5611_PD_ALL_MSK NO_OS_BIT(7) +#define ADF5611_PD_RDIV_MSK NO_OS_BIT(6) +#define ADF5611_PD_NDIV_MSK NO_OS_BIT(5) +#define ADF5611_PD_VCO_MSK NO_OS_BIT(4) +#define ADF5611_PD_LD_MSK NO_OS_BIT(3) +#define ADF5611_PD_PFDCP_MSK NO_OS_BIT(2) +#define ADF5611_PD_ADC_MSK NO_OS_BIT(1) +#define ADF5611_PD_CALGEN_MSK NO_OS_BIT(0) + +/* ADF5611 REG0028 MAP */ +#define ADF5611_PD_PFDNCLK_MSK NO_OS_BIT(1) +#define ADF5611_PD_ODIV_MSK NO_OS_BIT(0) + +/* ADF5611 REG0029 MAP */ +#define ADF5611_LDWIN_PW_MSK NO_OS_GENMASK(7, 5) +#define ADF5611_LD_COUNT_MSK NO_OS_GENMASK(4, 0) + +/* ADF5611 REG002A MAP*/ +#define ADF5611_EN_CP_IBX_MSK NO_OS_GENMASK(7, 6) +#define ADF5611_EN_LOL_MSK NO_OS_BIT(5) +#define ADF5611_EN_LDWIN_MSK NO_OS_BIT(4) +#define ADF5611_SPARE_2A_MSK NO_OS_BIT(3) +#define ADF5611_RST_LD_MSK NO_OS_BIT(2) +#define ADF5611_ABPW_WD_MSK NO_OS_BIT(1) +#define ADF5611_RST_CNTR_MSK NO_OS_BIT(0) + +/* ADF5611 REG002B MAP */ +#define ADF5611_MUXOUT_MSK NO_OS_GENMASK(7, 4) +#define ADF5611_EN_MUXOUT_MSK NO_OS_BIT(3) +#define ADF5611_EN_CPTEST_MSK NO_OS_BIT(2) +#define ADF5611_CP_DOWN_MSK NO_OS_BIT(1) +#define ADF5611_CP_UP_MSK NO_OS_BIT(0) + +/* ADF5611 REG002C MAP */ +#define ADF5611_CLKODIV_DB_MSK NO_OS_BIT(7) +#define ADF5611_DCLK_DIV_DB_MSK NO_OS_BIT(6) +#define ADF5611_SPARE_2C_MSK NO_OS_BIT(5) +#define ADF5611_RST_SYS_MSK NO_OS_BIT(4) +#define ADF5611_EN_ADC_CLK_MSK NO_OS_BIT(3) +#define ADF5611_EN_VCAL_MSK NO_OS_BIT(2) +#define ADF5611_CAL_CT_SEL_MSK NO_OS_BIT(1) +#define ADF5611_EN_NOTCH_MSK NO_OS_BIT(0) + +/* ADF5611 REG002D Map */ +#define ADF5611_VCO_FSM_TEST_MUX_MSK NO_OS_GENMASK(7, 5) +#define ADF5611_SPARE_2D_MSK NO_OS_GENMASK(4, 3) +#define ADF5611_O_VCO_BIAS_MSK NO_OS_BIT(2) +#define ADF5611_O_VCO_BAND_MSK NO_OS_BIT(1) +#define ADF5611_O_VCO_CORE_MSK NO_OS_BIT(0) + + +/* ADF5611 REG002F MAP */ +#define ADF5611_CAL_COUNT_TO_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0030 MAP */ +#define ADF5611_CAL_VTUNE_TO_LSB_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0031 MAP */ +#define ADF5611_0_VCO_DB_MSK NO_OS_BIT(7) +#define ADF5611_CAL_VTUNE_TO_MSB_MSK NO_OS_GENMASK(6, 0) + +/* ADF5611 REG0032 MAP */ +#define ADF5611_CAL_VCO_TO_LSB_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0033 MAP */ +#define ADF5611_DEL_CTRL_DB_MSK NO_OS_BIT(7) +#define ADF5611_CAL_VCO_TO_MSB_MSK NO_OS_GENMASK(6, 0) + +/* ADF5611 REG0034 MAP */ +#define ADF5611_CNTR_DIV_WORD_LSB_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0035 MAP */ +#define ADF5611_SPARE_35_MSK NO_OS_GENMASK(7, 6) +#define ADF5611_CMOS_OV_MSK NO_OS_BIT(5) +#define ADF5611_CMOS_OV(x) no_os_field_prep(ADF5611_CMOS_OV_MSK, x) +#define ADF5611_READ_MODE_MSK NO_OS_BIT(4) +#define ADF5611_CNTR_DIV_WORD_MSB_MSK NO_OS_GENMASK(3, 0) + +/* ADF5611 REG0036 MAP */ +#define ADF5611_ADC_CLK_DIV_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0037 MAP */ +#define ADF5611_EN_ADC_CNV_MSK NO_OS_BIT(7) +#define ADF5611_EN_ADC_VTEST_MSK NO_OS_BIT(6) +#define ADF5611_ADC_VTEST_SEL_MSK NO_OS_BIT(5) +#define ADF5611_ADC_MUX_SEL_MSK NO_OS_BIT(4) +#define ADF5611_ADC_F_CONV_MSK NO_OS_BIT(3) +#define ADF5611_ADC_C_CONV_MSK NO_OS_BIT(2) +#define ADF5611_EN_ADC_MSK NO_OS_BIT(1) +#define ADF5611_ADC_CLK_TEST_SEL_MSK NO_OS_BIT(0) + +/* ADF5611 REG0038 MAP */ +#define ADF5611_SPARE_38_MSK NO_OS_BIT(7) +#define ADF5611_VPTAT_CALGEN_MSK NO_OS_GENMASK(6, 0) + +/* ADF5611 REG0039 MAP */ +#define ADF5611_SPARE_39_MSK NO_OS_BIT(7) +#define ADF5611_VCTAT_CALGEN_MSK NO_OS_GENMASK(6, 0) + +/* ADF5611 REG003A MAP */ +#define ADF5611_NVMDIN_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG003B MAP */ +#define ADF5611_SPARE_3B_MSK NO_OS_BIT(7) +#define ADF5611_NVMADDR_MSK NO_OS_GENMASK(6, 3) +#define ADF5611_NVMNO_OS_BIT_SEL_MSK NO_OS_GENMASK(2, 0) + +/* ADF5611 REG003C MAP */ +#define ADF5611_TRIM_LATCH_MSK NO_OS_BIT(7) +#define ADF5611_NVMTEST_MSK NO_OS_BIT(6) +#define ADF5611_NVMPROG_MSK NO_OS_BIT(5) +#define ADF5611_NVMRD_MSK NO_OS_BIT(4) +#define ADF5611_NVMSTART_MSK NO_OS_BIT(3) +#define ADF5611_NVMON_MSK NO_OS_BIT(2) +#define ADF5611_MARGIN_MSK NO_OS_GENMASK(1, 0) + +/* ADF5611 REG003D MAP */ +#define ADF5611_NVMDOUT_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG003E MAP */ +#define ADF5611_SCAN_MODE_CODE_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG003F MAP */ +#define ADF5611_TEMP_OFFSET_MSK NO_OS_GENMASK(7, 0) + +/* ADF5611 REG0040 MAP */ +#define ADF5611_SPARE_40_MSK NO_OS_GENMASK(7, 6) +#define ADF5611_TEMP_SLOPE_MSK NO_OS_GENMASK(5, 0) + +/* ADF5611 REG0044 MAP */ +#define ADF5611_ADC_ST_CNV_MSK NO_OS_BIT(0) + +/* ADF5611 REG0048 MAP */ +#define ADF5611_ADC_BUSY_MSK NO_OS_BIT(2) +#define ADF5611_FSM_BUSY_MSK NO_OS_BIT(1) +#define ADF5611_LOCKED_MSK NO_OS_BIT(0) + +/* ADF5611 REG0100 MAP*/ +#define ADF5611_CORE0_BIAS_TABLE_1_MSK NO_OS_GENMASK(5, 3) +#define ADF5611_CORE0_BIAS_TABLE_0_MSK NO_OS_GENMASK(2, 0) + +/* ADF5611 REG0101 MAP*/ +#define ADF5611_CORE0_BIAS_TABLE_3_MSK NO_OS_GENMASK(5, 3) +#define ADF5611_CORE0_BIAS_TABLE_2_MSK NO_OS_GENMASK(2, 0) + +/* ADF5611 REG0102 MAP*/ +#define ADF5611_CORE0_BIAS_TABLE_5_MSK NO_OS_GENMASK(5, 3) +#define ADF5611_CORE0_BIAS_TABLE_4_MSK NO_OS_GENMASK(2, 0) + +/* ADF5611 REG0103 MAP*/ +#define ADF5611_CORE0_BIAS_TABLE_7_MSK NO_OS_GENMASK(5, 3) +#define ADF5611_CORE0_BIAS_TABLE_6_MSK NO_OS_GENMASK(2, 0) + +/* ADF5611 REG0104 MAP*/ +#define ADF5611_CORE1_BIAS_TABLE_1_MSK NO_OS_GENMASK(5, 3) +#define ADF5611_CORE1_BIAS_TABLE_0_MSK NO_OS_GENMASK(2, 0) + +/* ADF5611 REG0105 MAP*/ +#define ADF5611_CORE1_BIAS_TABLE_3_MSK NO_OS_GENMASK(5, 3) +#define ADF5611_CORE1_BIAS_TABLE_2_MSK NO_OS_GENMASK(2, 0) + +/* ADF5611 REG0106 MAP*/ +#define ADF5611_CORE1_BIAS_TABLE_5_MSK NO_OS_GENMASK(5, 3) +#define ADF5611_CORE1_BIAS_TABLE_4_MSK NO_OS_GENMASK(2, 0) + +/* ADF5611 REG0107 MAP*/ +#define ADF5611_CORE1_BIAS_TABLE_7_MSK NO_OS_GENMASK(5, 3) +#define ADF5611_CORE1_BIAS_TABLE_6_MSK NO_OS_GENMASK(2, 0) + + +#define ADF5611_SPI_4W_CFG(x) (no_os_field_prep(ADF5611_SDO_ACTIVE_MSK, x) | \ + no_os_field_prep(ADF5611_SDO_ACTIVE_R_MSK, x)) + +#define ADF5611_SPI_SCRATCHPAD_TEST 0x2A + +/* ADF5611 SPECIFICATIONS */ +#define ADF5611_SPI_WRITE_CMD 0x0 +#define ADF5611_SPI_READ_CMD 0x8000 +#define ADF5611_SPI_DUMMY_DATA 0x00 +#define ADF5611_BUFF_SIZE_BYTES 3 +#define ADF5611_VCO_FREQ_MIN 3650000000U // 3.65MHz +#define ADF5611_VCO_FREQ_MAX 7300000000U // 7.3MHz +#define ADF5611_MOD1WORD 0x2000000U // 2^25 +#define ADF5611_MOD2WORD_MAX 0xFFFFFFU // 2^24 - 1 +#define ADF5611_CHANNEL_SPACING_MAX 78125U +#define ADF5611_CPI_VAL_MAX 15 +#define ADF5611_REF_DIV_MAX 16383 +#define ADF5611_BLEED_TIME_CONST 4 +#define ADF5611_BLEED_CURRENT 3125 +#define ADF5611_RFOUT_PWR_MAX 3 +#define ADF5611_RFOUTDIV_PWR_MAX ADF5611_RFOUT_PWR_MAX +#define ADF5611_RFOUTDIV_DIV_MAX 7U +#define ADF5611_POR_DELAY_US 200 +#define ADF5611_LKD_DELAY_US 500 +#define ADF5611_RFOUT_MAX 14600000000U //14.6GHz +#define ADF5611_RFOUT_MIN 7300000000U //7.3GHz +#define ADF5611_REF_CLK_MAX 300000000000U //300MHz +#define ADF5611_REF_CLK_MIN 50000000U //50MHz +#define ADF5611_OUTPUT_DOUBLER 0x2U +#define ADF5611_PFD_FREQ_MAX 100000000U //100MHz +#define ADF5612_RFOUT_MAX 8500000000U //8.5GHz +#define ADF5612_RFOUT_MIN 7300000000U //7.3GHz +#define ADF5612_VCO_FREQ_MAX 7300000000U //7.3GHz +#define KHZ 1000 +#define MHZ KHZ * KHZ +#define GHZ KHZ * KHZ * KHZ +#define s_TO_ns 1000000000U +#define ns_TO_ps 1000 +#define uA_TO_A 1000000 + +/** + * @brief Supported device ids +*/ +enum adf5611_device_id { + ID_ADF5611, + ID_ADF5612, +}; + +/** + * @struct adf5611_init_param + * @brief ADF5611 Inintialization Parameters Structure. +*/ +struct adf5611_init_param { + /** SPI Initialization Parameters*/ + struct no_os_spi_init_param *spi_init; + /** SPI 4-Wire */ + bool spi4wire; + bool cmos_3v3; + uint64_t ref_clk_freq; + uint64_t rfout_freq; + uint8_t ref_div; + uint8_t cp_i; + uint16_t bleed_word; + uint8_t ld_count; + uint8_t rfoutdiv_div; + enum adf5611_device_id id; +}; + +/** + * @struct adf5611_dev + * @brief ADF5611 Device Descriptor. +*/ +struct adf5611_dev { + /** SPI Descriptor */ + struct no_os_spi_desc *spi_desc; + /** SPI 3-Wire */ + bool spi4wire; + bool cmos_3v3; + /** Input Reference Clock */ + uint64_t ref_clk_freq; + /** Input Reference Clock */ + uint64_t rfout_freq; + uint32_t ref_div; + uint8_t cp_i; + uint16_t bleed_word; + uint8_t ld_count; + uint8_t rfoutdiv_div; + uint64_t freq_max; + uint64_t freq_min; + uint64_t vco_max; + uint64_t vco_min; +}; + +/** + * @struct reg_sequence + * @brief ADF5611 Register Format Structure for Default Values +*/ +struct reg_sequence { + uint16_t reg; + uint8_t val; +}; + +/** + * @struct adf5611_reg_defaults + * @brief ADF5611 register initialization + */ +static const struct reg_sequence adf5611_reg_defaults[] = { + { 0x0000, 0x18 }, + { 0x001F, 0x02 }, + { 0x0020, 0x00 }, + { 0x001E, 0xE2 }, + { 0x002C, 0x08 }, + { 0x001F, 0xF3 }, + { 0x0104, 0x24 }, + { 0x0105, 0x24 }, + { 0x0106, 0x24 }, + { 0x0107, 0x24 }, + { 0x0040, 0x2B }, + { 0x003F, 0x5D }, + { 0x0039, 0x22 }, + { 0x0038, 0x4E }, + { 0x0037, 0x82 }, + { 0x0036, 0x3E }, + { 0x0035, 0x00 }, + { 0x0033, 0x00 }, + { 0x0032, 0x64 }, + { 0x0031, 0x00 }, + { 0x0030, 0x32 }, + { 0x002F, 0x19 }, + { 0x002D, 0x00 }, + { 0x002C, 0x08 }, + { 0x002B, 0x00 }, + { 0x002A, 0x70 }, + { 0x0029, 0x2C }, + { 0x0028, 0x01 }, + { 0x0027, 0x00 }, + { 0x0026, 0x00 }, + { 0x0025, 0x7f }, + { 0x0024, 0xff }, + { 0x0023, 0xff }, + { 0x0022, 0x18 }, + { 0x0021, 0x5f }, + { 0x0020, 0x00 }, + { 0x001F, 0x02 }, + { 0x001E, 0x92 }, + { 0x001D, 0x11 }, + { 0x001C, 0x00 }, + { 0x001B, 0x00 }, + { 0x001A, 0x01 }, + { 0x0019, 0x00 }, + { 0x0018, 0x00 }, + { 0x0017, 0x00 }, + { 0x0016, 0x00 }, + { 0x0015, 0x00 }, + { 0x0014, 0x00 }, + { 0x0013, 0x00 }, + { 0x0012, 0x00 }, + { 0x0010, 0x78 }, +}; + +/** ADF5611 SPI write */ +int adf5611_spi_write(struct adf5611_dev *dev, uint16_t reg_addr, uint8_t data); + +/** ADF5611 SPI Read */ +int adf5611_spi_read(struct adf5611_dev *dev, uint16_t reg_addr, uint8_t *data); + +/** ADF5611 updates a bit in the register space over SPI */ +int adf5611_spi_update_bits(struct adf5611_dev *dev, uint16_t reg_addr, + uint8_t mask, uint8_t data); + +/** ADF5611 Set reference frequency attribute */ +int adf5611_set_ref_clk(struct adf5611_dev *dev, uint64_t val); + +/** ADF5611 Get reference frequency attribute */ +int adf5611_get_ref_clk(struct adf5611_dev *dev, uint64_t *val); + +/** ADF5611 Set reference divider attribute */ +int adf5611_set_ref_div(struct adf5611_dev *dev, int32_t div); + +/** ADF5611 Get reference divider attribute */ +int adf5611_get_ref_div(struct adf5611_dev *dev, int32_t *div); + +/** ADF5611 Set the charge pump current attribute */ +int adf5611_set_cp_i(struct adf5611_dev *dev, int32_t reg_val); + +/** ADF5611 Get the charge pump current attribute */ +int adf5611_get_cp_i(struct adf5611_dev *dev, int32_t *reg_val); + +/** ADF5611 Set the output power attribute */ +int adf5611_set_output_power(struct adf5611_dev *dev, int8_t pwr); + +/** ADF5611 Get the output power attribute */ +int adf5611_get_output_power(struct adf5611_dev *dev, int8_t *pwr); + +/** ADF5611 Set the rfoutdiv power attribute */ +int adf5611_set_rfoutdiv_power(struct adf5611_dev *dev, int32_t pwr); + +/** ADF5611 Get the rfoutdiv power attribute */ +int adf5611_get_rfoutdiv_power(struct adf5611_dev *dev, int32_t *pwr); + +/** ADF5611 Set the rfoutdiv divider attribute */ +int adf5611_set_rfoutdiv_divider(struct adf5611_dev *dev, uint8_t div_val); + +/** ADF5611 Get the rfoutdiv divider attribute */ +int adf5611_get_rfoutdiv_divider(struct adf5611_dev *dev, int8_t *div); + +/** ADF5611 Set the enable/disable rfoutdiv */ +int adf5611_set_en_rfoutdiv(struct adf5611_dev *dev, bool en); + +/** ADF5611 Get the enable/disable rfoutdiv */ +int adf5611_get_en_rfoutdiv(struct adf5611_dev *dev, bool *en); + +/** ADF5611 Set output frequency attribute */ +int adf5611_set_rfout(struct adf5611_dev *dev, uint64_t val); + +/** ADF5611 Get output frequency attribute */ +int adf5611_get_rfout(struct adf5611_dev *dev, uint64_t *val); + +/** ADF5611 Sets frequency */ +int adf5611_set_freq(struct adf5611_dev *dev); + +/** ADF5611 Initialization */ +int adf5611_init(struct adf5611_dev **device, + struct adf5611_init_param *init_param); + +/** ADF5611 Remove */ +int adf5611_remove(struct adf5611_dev *dev); diff --git a/drivers/frequency/adf5611/iio_adf5611.c b/drivers/frequency/adf5611/iio_adf5611.c new file mode 100644 index 00000000000..f853d5eebfb --- /dev/null +++ b/drivers/frequency/adf5611/iio_adf5611.c @@ -0,0 +1,579 @@ +/***************************************************************************//** + * @file iio_adf5611.c + * @brief Implementation of IIO ADF5611 Driver. + * @author JOsemene (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 +#include +#include +#include "no_os_error.h" +#include "no_os_util.h" +#include "iio_adf5611.h" +#include "adf5611.h" +#include "no_os_alloc.h" +#include "no_os_delay.h" + +/** + * @brief Supported charge pump currents + */ +static const int ci_table[16][2] = { + {0, 200000}, + {0, 400000}, + {0, 600000}, + {0, 800000}, + {1, 000000}, + {1, 200000}, + {1, 400000}, + {1, 600000}, + {1, 800000}, + {2, 000000}, + {2, 200000}, + {2, 400000}, + {2, 600000}, + {2, 800000}, + {3, 000000}, + {3, 200000} +}; + +/** + * @brief Supported rfoutdiv_divider_values + */ +static const int rfoutdiv_div_table[8] = { + 1, 2, 4, 8, + 16, 32, 64, 128 +}; + +/** + * @brief Helper function to read a pair of values in a table with 2 elements. + * @param tb - Input table. + * @param size - Size of the table. + * @param val1 - The first value to be found. + * @param val2 - The second value to be found. + * @return i - The index of the pair if found or an error if there is no + * pair of values in the table. + */ +static int adf5611_iio_find_2d_row(const int (*tbl)[2], const int size, + const int val1, const int val2) +{ + int i; + + for (i = 0; i < size; i++) { + if (tbl[i][0] == val1 && tbl[i][1] == val2) + return i; + } + return -EINVAL; +} + +/** + * @brief Helper function to read an element in a table . + * @param tbl - Input table. + * @param size - Size of the table. + * @param val - The value to be found. + * @return i - The index of element if found or an error if element is not + * found in the table. + */ +static int adf5611_iio_find_element_in_tbl(const int *tbl, const int size, + const int val) +{ + int i; + for (i = 0; i < size; i++) { + if (tbl[i] == val) + return i; + } + return -EINVAL; +} + +/** + * @brief IIO Wrapper for reading ADF5611 frequency. + * @param dev - The iio device structure. + * @param reg - Address of the register to be read from. + * @param readval - Read data. + * @return - Result of the reading procedure. +*/ +static int adf5611_iio_read_reg(struct adf5611_iio_dev *dev, uint32_t reg, + uint32_t *readval) +{ + uint8_t tmp; + int ret; + ret = adf5611_spi_read(dev->adf5611_dev, (uint16_t)reg, &tmp); + if (ret) + return ret; + *readval = tmp; + return 0; +} + +/** + * @brief IIO Wrapper for writing adf5611 register. + * @param dev - The iio device structure. + * @param reg - Address of the register to be written to. + * @param writeval - Data to be written. + * @return - Result of the writing procedure. + */ +static int adf5611_iio_write_reg(struct adf5611_iio_dev *dev, uint32_t reg, + uint32_t writeval) +{ + return adf5611_spi_write(dev->adf5611_dev, (uint16_t)reg, + (uint8_t)writeval); +} + +/** + * @brief Handles the read request for the device attributes. + * @param dev - The iio device structure. + * @param buf - Command buffer to be filled with requested data. + * @param len - Length of the received command buffer in bytes. + * @param channel - Command channel info. + * @param priv - Command attribute id. + * @return - The size of the read data in case of success, error code + * otherwise. + */ +static int adf5611_iio_read_device_attr(void *dev, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv) +{ + struct adf5611_iio_dev *iio_adf5611 = (struct adf5611_iio_dev *)dev; + struct adf5611_dev *adf5611; + int32_t val = -EINVAL; + uint64_t val_64 = 0; + int32_t val_b[2]; + char buffer[5]; + int32_t cp_i; + int8_t div; + uint8_t i; + bool en; + int ret; + + if (!iio_adf5611) + return -EINVAL; + + adf5611 = iio_adf5611->adf5611_dev; + + if (!adf5611) + return -EINVAL; + + switch (priv) { + case ADF5611_IIO_DEV_ATTR_CP_I: + ret = adf5611_get_cp_i(adf5611, &cp_i); + if (ret) + return ret; + + val_b[0] = ci_table[cp_i][0]; + val_b[1] = ci_table[cp_i][1]; + ret = iio_format_value(buf, len, IIO_VAL_INT_PLUS_MICRO, 2, val_b); + break; + case ADF5611_IIO_DEV_ATTR_CP_AVAIL: + strcpy(buf, ""); + for (i = 0; i < NO_OS_ARRAY_SIZE(ci_table); i++) { + val_b[0] = ci_table[i][0]; + val_b[1] = ci_table[i][1]; + iio_format_value(buffer, len, IIO_VAL_INT_PLUS_MICRO, 2, val_b); + strcat(buf, buffer); + if (i < NO_OS_ARRAY_SIZE(ci_table) - 1) + strcat(buf, " "); + } + ret = strlen(buf); + break; + case ADF5611_IIO_DEV_ATTR_REF_DIV: + ret = adf5611_get_ref_div(adf5611, &val); + if (ret) + return ret; + ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val); + break; + case ADF5611_IIO_DEV_ATTR_REF_CLK: + ret = adf5611_get_ref_clk(adf5611, &val_64); + if (ret) + return ret; + ret = snprintf(buf, len, "%"PRIu64, val_64); + break; + case ADF5611_IIO_DEV_ATTR_RFOUTDIV_PWR: + ret = adf5611_get_rfoutdiv_power(adf5611, &val); + if (ret) + return ret; + ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val); + break; + case ADF5611_IIO_DEV_ATTR_EN_RFOUTDIV: + ret = adf5611_get_en_rfoutdiv(adf5611, &en); + if (ret) + return ret; + val = en; + ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val); + break; + case ADF5611_IIO_DEV_ATTR_RFOUTDIV_DIV: + ret = adf5611_get_rfoutdiv_divider(adf5611, &div); + if (ret) + return ret; + val = rfoutdiv_div_table[div]; + ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val); + break; + case ADF5611_IIO_DEV_ATTR_RFOUTDIV_DIV_AVAIL: + strcpy(buf, ""); + for (i = 0; i < NO_OS_ARRAY_SIZE(rfoutdiv_div_table); i++) { + val = rfoutdiv_div_table[i]; + iio_format_value(buffer, len, IIO_VAL_INT, 1, &val); + strcat(buf, buffer); + if (i < NO_OS_ARRAY_SIZE(rfoutdiv_div_table) - 1) + strcat(buf, " "); + } + ret = strlen(buf); + break; + default: + return -EINVAL; + }; + return ret; +} + +/** + * @brief Handles the write request for the device attributes. + * @param dev - The iio device structure. + * @param buf - Command buffer to be filled with requested data. + * @param len - Length of the received command buffer in bytes. + * @param channel - Command channel info. + * @param priv - Command attribute id. + * @return - The size of the read data in case of success, error code + * otherwise. + */ +static int adf5611_iio_write_device_attr(void *dev, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv) +{ + struct adf5611_iio_dev *iio_adf5611 = (struct adf5611_iio_dev *)dev; + struct adf5611_dev *adf5611; + int32_t val = -EINVAL; + uint64_t val_64 = 0; + int32_t val_b[2]; + int8_t index; + bool en; + int ret; + + if (!iio_adf5611) + return -EINVAL; + adf5611 = iio_adf5611->adf5611_dev; + + if (!adf5611) + return -EINVAL; + + switch (priv) { + case ADF5611_IIO_DEV_ATTR_CP_I: + ret = iio_parse_value(buf, IIO_VAL_INT_PLUS_MICRO, &val_b[0], + &val_b[1]); + if (ret) + return ret; + + index = adf5611_iio_find_2d_row(ci_table, NO_OS_ARRAY_SIZE(ci_table), + val_b[0], val_b[1]); + if (index < 0) + return index; + val = index; + ret = adf5611_set_cp_i(adf5611, val); + break; + case ADF5611_IIO_DEV_ATTR_REF_DIV: + ret = iio_parse_value(buf, IIO_VAL_INT, &val, NULL); + if (ret) + return ret; + ret = adf5611_set_ref_div(adf5611, val); + break; + case ADF5611_IIO_DEV_ATTR_REF_CLK: + sscanf(buf, "%"PRIu64, &val_64); + ret = adf5611_set_ref_clk(adf5611, val_64); + break; + case ADF5611_IIO_DEV_ATTR_RFOUTDIV_PWR: + ret = iio_parse_value(buf, IIO_VAL_INT, &val, NULL); + if (ret) + return ret; + ret = adf5611_set_ref_div(adf5611, val); + break; + case ADF5611_IIO_DEV_ATTR_EN_RFOUTDIV: + ret = iio_parse_value(buf, IIO_VAL_INT, &val, NULL); + if (ret) + return ret; + en = val; + ret = adf5611_set_en_rfoutdiv(adf5611, en); + break; + case ADF5611_IIO_DEV_ATTR_RFOUTDIV_DIV: + ret = iio_parse_value(buf, IIO_VAL_INT, &val, NULL); + if (ret) + return ret; + index = adf5611_iio_find_element_in_tbl(rfoutdiv_div_table, + NO_OS_ARRAY_SIZE + (rfoutdiv_div_table), val); + if (index < 0) + return index; + ret = adf5611_set_rfoutdiv_divider(adf5611, index); + break; + default: + return -EINVAL; + } + return ret; +} + +/** + * @brief Handles the read request for the channel attributes. + * @param dev - The iio device structure. + * @param buf - Command buffer to be filled with requested data. + * @param len - Length of the received command buffer in bytes. + * @param channel - Command channel info. + * @param priv - Command attribute id. + * @return - The size of the read data in case of success, error code + * otherwise. + */ +static int adf5611_iio_read_channel_attr(void *dev, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv) +{ + struct adf5611_iio_dev *iio_adf5611 = (struct adf5611_iio_dev *)dev; + struct adf5611_dev *adf5611; + uint64_t val = -EINVAL; + int8_t opwr; + int32_t val_32; + int ret; + + if (!iio_adf5611) + return -EINVAL; + + adf5611 = iio_adf5611->adf5611_dev; + + if (!adf5611) + return -EINVAL; + + switch (priv) { + case ADF5611_IIO_CH_ATTR_FREQ: + ret = adf5611_get_rfout(adf5611, &val); + if (ret) + return ret; + ret = snprintf(buf, len, "%"PRIu64, val); + break; + case ADF5611_IIO_CH_ATTR_OPWR: + ret = adf5611_get_output_power(adf5611, &opwr); + if (ret) + return ret; + val_32 = opwr; + ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val_32); + break; + default: + return -EINVAL; + } + return ret; +} + +/** + * @brief Handles the write request for the channel attributes. + * @param dev - The iio device structure. + * @param buf - Command buffer to be filled with requested data. + * @param len - Length of the received command buffer in bytes. + * @param channel - Command channel info. + * @param priv - Command attribute id. + * @return - The size of the read data in case of success, error code + * otherwise. + */ +static int adf5611_iio_write_channel_attr(void *dev, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv) +{ + struct adf5611_iio_dev *iio_adf5611 = (struct adf5611_iio_dev *)dev; + struct adf5611_dev *adf5611; + int64_t val = -EINVAL; + int32_t val_32; + int8_t opwr; + + int ret; + + if (!iio_adf5611) + return -EINVAL; + + adf5611 = iio_adf5611->adf5611_dev; + + if (!adf5611) + return -EINVAL; + + switch (priv) { + case ADF5611_IIO_CH_ATTR_FREQ: + sscanf(buf, "%"PRIu64, &val); + ret = adf5611_set_rfout(adf5611, val); + break; + case ADF5611_IIO_CH_ATTR_OPWR: + ret = iio_parse_value(buf, IIO_VAL_INT, &val_32, NULL); + if (ret) + return ret; + opwr = val_32; + ret = adf5611_set_output_power(adf5611, opwr); + break; + default: + return -EINVAL; + } + if (ret) + return ret; + + return 0; +} + +static struct iio_attribute adf5611_iio_attrs[] = { + { + .name = "reference_frequency", + .shared = IIO_SHARED_BY_ALL, + .priv = ADF5611_IIO_DEV_ATTR_REF_CLK, + .show = adf5611_iio_read_device_attr, + .store = adf5611_iio_write_device_attr, + }, + { + .name = "reference_divider", + .shared = IIO_SHARED_BY_ALL, + .priv = ADF5611_IIO_DEV_ATTR_REF_DIV, + .show = adf5611_iio_read_device_attr, + .store = adf5611_iio_write_device_attr, + }, + { + .name = "charge_pump_current", + .shared = IIO_SHARED_BY_ALL, + .priv = ADF5611_IIO_DEV_ATTR_CP_I, + .show = adf5611_iio_read_device_attr, + .store = adf5611_iio_write_device_attr, + }, + { + .name = "charge_pump_current_available", + .shared = IIO_SHARED_BY_ALL, + .priv = ADF5611_IIO_DEV_ATTR_CP_AVAIL, + .show = adf5611_iio_read_device_attr, + }, + { + .name = "rfoutdiv_power", + .shared = IIO_SHARED_BY_ALL, + .priv = ADF5611_IIO_DEV_ATTR_RFOUTDIV_PWR, + .show = adf5611_iio_read_device_attr, + .store = adf5611_iio_write_device_attr, + }, + { + .name = "rfoutdiv_divider", + .shared = IIO_SHARED_BY_ALL, + .priv = ADF5611_IIO_DEV_ATTR_RFOUTDIV_DIV, + .show = adf5611_iio_read_device_attr, + .store = adf5611_iio_write_device_attr, + }, + { + .name = "rfoutdiv_divider_available", + .shared = IIO_SHARED_BY_ALL, + .priv = ADF5611_IIO_DEV_ATTR_RFOUTDIV_DIV_AVAIL, + .show = adf5611_iio_read_device_attr, + }, + { + .name = "en_rfoutdiv", + .shared = IIO_SHARED_BY_ALL, + .priv = ADF5611_IIO_DEV_ATTR_EN_RFOUTDIV, + .show = adf5611_iio_read_device_attr, + .store = adf5611_iio_write_device_attr, + }, + END_ATTRIBUTES_ARRAY +}; + +static struct iio_attribute adf5611_iio_ch_attrs[] = { + { + .name = "rfout_frequency", + .shared = IIO_SHARED_BY_TYPE, + .priv = ADF5611_IIO_CH_ATTR_FREQ, + .show = adf5611_iio_read_channel_attr, + .store = adf5611_iio_write_channel_attr, + }, + { + .name = "rfout_power", + .shared = IIO_SHARED_BY_TYPE, + .priv = ADF5611_IIO_CH_ATTR_OPWR, + .show = adf5611_iio_read_channel_attr, + .store = adf5611_iio_write_channel_attr, + }, + END_ATTRIBUTES_ARRAY +}; + +static struct iio_channel adf5611_channels[] = { + { + .ch_type = IIO_ALTVOLTAGE, + .channel = 0, + .ch_out = true, + .indexed = true, + .attributes = adf5611_iio_ch_attrs, + .scan_type = NULL, + } +}; + +static struct iio_device adf5611_iio_dev = { + .num_ch = NO_OS_ARRAY_SIZE(adf5611_channels), + .channels = adf5611_channels, + .attributes = adf5611_iio_attrs, + .debug_reg_read = (int32_t (*)())adf5611_iio_read_reg, + .debug_reg_write = (int32_t (*)())adf5611_iio_write_reg +}; + + +/** + * @brief Initializes the ADF5611 IIO driver + * @param iio_dev - The iio device structure. + * @param init_param - The structure that contains the device initial parameters. + * @return ret - Result of the initialization procedure. + */ +int adf5611_iio_init(struct adf5611_iio_dev **iio_dev, + struct adf5611_iio_dev_init_param *init_param) +{ + struct adf5611_iio_dev *dev; + int ret; + + dev = (struct adf5611_iio_dev *)no_os_calloc(1, sizeof(*dev)); + if (!dev) + return -ENOMEM; + + dev->iio_dev = &adf5611_iio_dev; + + ret = adf5611_init(&dev->adf5611_dev, init_param->adf5611_dev_init); + + if (ret) + goto error; + + *iio_dev = dev; + + return ret; + +error: + no_os_free(dev); + return ret; +} + +/** + * @brief Free the resources allocated by adf5611_iio_init(). + * @param dev - The IIO device structure. + * @return ret - Result of the remove procedure. +*/ +int adf5611_iio_remove(struct adf5611_iio_dev *dev) +{ + int ret; + + ret = adf5611_remove(dev->adf5611_dev); + if (ret) + return ret; + + no_os_free(dev); + + return 0; +} diff --git a/drivers/frequency/adf5611/iio_adf5611.h b/drivers/frequency/adf5611/iio_adf5611.h new file mode 100644 index 00000000000..a00b0eb7e56 --- /dev/null +++ b/drivers/frequency/adf5611/iio_adf5611.h @@ -0,0 +1,69 @@ +/***************************************************************************//** + * @file iio_adf5611.h + * @brief Implementation of IIO ADF5611 Driver. + * @author josemene (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. +*******************************************************************************/ +#ifndef IIO_ADF5611_H +#define IIO_ADF5611_H + +#include "iio_types.h" +#include "iio.h" + +struct adf5611_iio_dev { + struct adf5611_dev *adf5611_dev; + struct iio_device *iio_dev; +}; + +struct adf5611_iio_dev_init_param { + struct adf5611_init_param *adf5611_dev_init; +}; + +enum adf5611_iio_ch_attr_id { + ADF5611_IIO_CH_ATTR_FREQ, + ADF5611_IIO_CH_ATTR_OPWR, +}; + +enum adf5611_iio_dev_attr_id { + ADF5611_IIO_DEV_ATTR_REF_CLK, + ADF5611_IIO_DEV_ATTR_REF_DIV, + ADF5611_IIO_DEV_ATTR_CP_I, + ADF5611_IIO_DEV_ATTR_CP_AVAIL, + ADF5611_IIO_DEV_ATTR_RFOUTDIV_PWR, + ADF5611_IIO_DEV_ATTR_RFOUTDIV_DIV, + ADF5611_IIO_DEV_ATTR_EN_RFOUTDIV, + ADF5611_IIO_DEV_ATTR_RFOUTDIV_DIV_AVAIL, +}; + +int adf5611_iio_init(struct adf5611_iio_dev **iio_dev, + struct adf5611_iio_dev_init_param *init_param); + +int adf5611_iio_remove(struct adf5611_iio_dev *desc); + +#endif diff --git a/projects/adf5611/Makefile b/projects/adf5611/Makefile new file mode 100644 index 00000000000..609099cd822 --- /dev/null +++ b/projects/adf5611/Makefile @@ -0,0 +1,13 @@ +PLATFORM = mbed + +# Choose the default example to build +EXAMPLE ?= iio_example + + +include ../../tools/scripts/generic_variables.mk + +include ../../tools/scripts/examples.mk + +include src.mk + +include ../../tools/scripts/generic.mk diff --git a/projects/adf5611/README.rst b/projects/adf5611/README.rst new file mode 100644 index 00000000000..94034ef916f --- /dev/null +++ b/projects/adf5611/README.rst @@ -0,0 +1,234 @@ +Evaluating the ADF5611 +====================== + +Contents +-------- + +.. contents:: Table of Contents + :depth: 3 + +Supported Evaluation Boards +--------------------------- + +* `EVAL-ADF5611 `_ + +Overview +-------- + +The EV-ADF5611SD1Z evaluates the performance of the ADF5611 fractional +frequency synthesizer with an integrated voltage controlled oscillator +(VCO) for phase-locked loops (PLLs). The EVADF5611SD1Z contains the ADF5611 +frequency synthesizer with an integrated VCO, a USB interface, power supply +connectors, on-board reference oscillator, propagation delay calibration paths, +and Subminiature Version A (SMA) connectors. The output is AC-coupled with +50 Ω transmission lines making the outputs suitable to drive 50 Ω impedance +instruments. + +The above also applies to the ADF5612 frequency synthesizers. + +Full specifications on the ADF5611 and ADF5612 frequency synthesizer are +available in the ADF5611 and ADF5612 data sheet available from +Analog Devices Inc. and must be consulted with their user guide when using +the EV-ADF5611SD1Z and ADF5612SD1Z evaluation boards. + + +Applications +------------ + +* Military and Defense +* Test equipment +* Clock generation +* Wireless infrastructure +* Satellite and very small aperture terminal (VSAT) +* Microwave radio + +Hardware Specifications +----------------------- + +Power Supply Requirements +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The EV-ADF5612D1Z and ADF5612SD1Z are both powered by a 6 V power supply +connected to the J4 SMA connector. + +Reference Input Requirements +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The EV-ADF5611SD1Z and ADF5612SD1Z has an on-board, 122.88 MHz, ultra low phase noise, +sine-wave oscillator to drive the ADF5611 and ADF5612 reference input respectively. +Single-ended oscillator output is connected to the REFP pin, and the REFN pin is AC +grounded. This oscillator is used by default on the board. + +The reference input can also be driven externally via a pair of SMA connectors, +REFIN (J5). When using the external reference, disconnect the on-board oscillator path. +This will require board modifications, please refer to the `EVAL-ADF5611 `_ or `EVAL-ADF5612 `_ +for details. + +Pin Description +^^^^^^^^^^^^^^^ + +Please see the following table for the pin assignments for the Arduino interface +connectors (P2 and P4). + + P1: ANALOG IN + + +-----+-------------------+------------------------------------------+ + | Pin | Name | Description | + +-----+-------------------+------------------------------------------+ + | 1 | A0 | Not connected | + +-----+-------------------+------------------------------------------+ + | 2 | A1 | Not connected | + +-----+-------------------+------------------------------------------+ + | 3 | A2 | Not connected | + +-----+-------------------+------------------------------------------+ + | 4 | A3 | Not connected | + +-----+-------------------+------------------------------------------+ + | 5 | A4 | Not connected | + +-----+-------------------+------------------------------------------+ + | 6 | A5 | Not connected | + +-----+-------------------+------------------------------------------+ + + P2: POWER + +-----+-------------------+------------------------------------------+ + | 1 | NC | Not connected | + +-----+-------------------+------------------------------------------+ + | 2 | IOREF | Connected to VIO | + +-----+-------------------+------------------------------------------+ + | 3 | RESET | Not connected | + +-----+-------------------+------------------------------------------+ + | 4 | +3V3 | Not connected | + +-----+-------------------+------------------------------------------+ + | 5 | +5V | Not connected | + +-----+-------------------+------------------------------------------+ + | 6 | GND | Connected to Ground | + +-----+-------------------+------------------------------------------+ + | 7 | GND | Connected to Ground | + +-----+-------------------+------------------------------------------+ + | 8 | VIN | Not connected | + +-----+-------------------+------------------------------------------+ + + P4: DIGITAL 1 + +-----+-------------------+------------------------------------------+ + | 1 | 8 | Not connected | + +-----+-------------------+------------------------------------------+ + | 2 | 9/PWM | Connected to CEN | + +-----+-------------------+------------------------------------------+ + | 3 | 10/PWM/CS | Connected to CSB | + +-----+-------------------+------------------------------------------+ + | 4 | 11/PWM/MOSI | Connected to STD_SPI_MOSI | + +-----+-------------------+------------------------------------------+ + | 5 | 12/MISO | Connected to STD_SPI_MISO | + +-----+-------------------+------------------------------------------+ + | 6 | 13/SCK | Connected to STD_SPI_CLK | + +-----+-------------------+------------------------------------------+ + | 7 | GND | Connected to Ground | + +-----+-------------------+------------------------------------------+ + | 8 | AREF | Not connected | + +-----+-------------------+------------------------------------------+ + | 9 | SDA | Connected to EEPROM_SDA | + +-----+-------------------+------------------------------------------+ + | 10 | SCL | Connected to EEPROM_SCL | + +-----+-------------------+------------------------------------------+ + + P5: DIGITAL 0 + +-----+-------------------+------------------------------------------+ + | 1 | RX + 0 | Not connected | + +-----+-------------------+------------------------------------------+ + | 2 | TX + 1 | Not connected | + +-----+-------------------+------------------------------------------+ + | 3 | 2 | Not connected | + +-----+-------------------+------------------------------------------+ + | 4 | 3/PWM | Not connected | + +-----+-------------------+------------------------------------------+ + | 5 | 4 | Not connected | + +-----+-------------------+------------------------------------------+ + | 6 | 5/PWM | Not connected | + +-----+-------------------+------------------------------------------+ + | 7 | 6/PWM | Not connected | + +-----+-------------------+------------------------------------------+ + | 8 | 7 | Not connected | + +-----+-------------------+------------------------------------------+ + +No-OS Build Setup +----------------- + +Please see: https://wiki.analog.com/resources/no-os/build + +No-OS Supported Examples +------------------------ + +The initialization data used in the examples is taken out from: +`Project Common Data Path `_ + +The macros used in Common Data are defined in platform specific files found in: +`Project Platform Configuration Path `_ + +Basic example +^^^^^^^^^^^^^ + +This example initializes the ADF5611 or ADF5612 with the configurations +provided in the above mentioned common files and applies them to the IC. +By default reference frequency is provided by the local oscillator of the +board, the differential output path is powered down and the RF Output power +level is set to 3. Subsequently the example sets a test frequency of 12 GHz. + + +In order to build the basic example make sure you are using this command: + +.. code-block:: bash + + make EXAMPLE=basic + +IIO example +^^^^^^^^^^^ + +This project provide an IIOD demo for the ADF5611 and ADF5612. It launches an +IIOD server on the mother platform it runs on allowing the user to connect +via an IIOD client. Using IIO-Oscilloscope, the user can configure the ADF5611 +or ADF5612. + +If you are not familiar with ADI IIO Application, please take a look at: +`IIO No-OS `_ + +The No-OS IIO Application together with the No-OS IIO ADF5611 driver take care +of all the back-end logic needed to setup the IIO server. + +This example initializes the IIO device and calls the IIO app as shown in: +`IIO Example `_ + +In order to build the IIO project make sure you are using this command: + +.. code-block:: bash + + make EXAMPLE=iio_example + +No-OS Supported Platforms +------------------------- + +Mbed Platform +^^^^^^^^^^^^^ + +**Used hardware** + +* `EVAL-ADF5611 `_ or `EVAL-ADF5612 `_ +* `SDP-K1 `_ + +**Connections**: + +The Arduino of the SDP-K1 needs to be connected to Arduino header of the +Evaluation board. +Additionally a 6V power supply needs to be connected to either J4 +(the SMA interface). + +**Build Command** + +.. code-block:: bash + + # to delete current build + make reset + # to build the basic project + make EXAMPLE=basic + # to build the IIO project + make EXAMPLE=iio_example + # copy the adf5611.bin to the mounted SDP-K1 + cp build/adf5611.bin diff --git a/projects/adf5611/build.json b/projects/adf5611/build.json new file mode 100644 index 00000000000..c56ad7ab04a --- /dev/null +++ b/projects/adf5611/build.json @@ -0,0 +1,10 @@ +{ + "mbed": { + "basic_example": { + "flags" : "EXAMPLE=basic" + }, + "iio": { + "flags": "EXAMPLE=iio_example" + } + } +} diff --git a/projects/adf5611/src.mk b/projects/adf5611/src.mk new file mode 100644 index 00000000000..9f15c50fc32 --- /dev/null +++ b/projects/adf5611/src.mk @@ -0,0 +1,47 @@ +################################################################################ +# # +# Shared variables: # +# - PROJECT # +# - DRIVERS # +# - INCLUDE # +# - PLATFORM_DRIVERS # +# - NO-OS # +# # +################################################################################ + +SRCS += $(DRIVERS)/api/no_os_uart.c \ + $(DRIVERS)/api/no_os_gpio.c \ + $(DRIVERS)/api/no_os_spi.c \ + $(DRIVERS)/api/no_os_irq.c \ + $(DRIVERS)/api/no_os_timer.c \ + $(DRIVERS)/api/no_os_i2c.c \ + $(DRIVERS)/api/no_os_eeprom.c \ + $(NO-OS)/util/no_os_fifo.c \ + $(NO-OS)/util/no_os_lf256fifo.c \ + $(NO-OS)/util/no_os_mutex.c \ + $(NO-OS)/util/no_os_list.c \ + $(NO-OS)/util/no_os_util.c \ + $(NO-OS)/util/no_os_alloc.c + +INCS += $(INCLUDE)/no_os_delay.h \ + $(INCLUDE)/no_os_error.h \ + $(INCLUDE)/no_os_gpio.h \ + $(INCLUDE)/no_os_spi.h \ + $(INCLUDE)/no_os_i2c.h \ + $(INCLUDE)/no_os_eeprom.h \ + $(INCLUDE)/no_os_mutex.h \ + $(INCLUDE)/no_os_fifo.h \ + $(INCLUDE)/no_os_irq.h \ + $(INCLUDE)/no_os_lf256fifo.h \ + $(INCLUDE)/no_os_list.h \ + $(INCLUDE)/no_os_print_log.h \ + $(INCLUDE)/no_os_timer.h \ + $(INCLUDE)/no_os_uart.h \ + $(INCLUDE)/no_os_util.h \ + $(INCLUDE)/no_os_alloc.h + +INCS += $(DRIVERS)/frequency/adf5611/adf5611.h +SRCS += $(DRIVERS)/frequency/adf5611/adf5611.c + +INCS += $(DRIVERS)/eeprom/24xx32a/24xx32a.h +SRCS += $(DRIVERS)/eeprom/24xx32a/24xx32a.c diff --git a/projects/adf5611/src/common/common_data.c b/projects/adf5611/src/common/common_data.c new file mode 100644 index 00000000000..815a2793650 --- /dev/null +++ b/projects/adf5611/src/common/common_data.c @@ -0,0 +1,87 @@ +/***************************************************************************//** + * @file common_data.c + * @brief Defines common data to be used by adf5611 examples. + * @author Josemene (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 "common_data.h" + +struct no_os_uart_init_param adf5611_uart_ip = { + .device_id = UART_DEVICE_ID, + .irq_id = UART_IRQ_ID, + .asynchronous_rx = true, + .baud_rate = UART_BAUDRATE, + .size = NO_OS_UART_CS_8, + .parity = NO_OS_UART_PAR_NO, + .stop = NO_OS_UART_STOP_1_BIT, + .extra = UART_EXTRA, + .platform_ops = UART_OPS, +}; + +struct no_os_spi_init_param adf5611_spi_ip = { + .device_id = SPI_DEVICE_ID, + .max_speed_hz = 1500000, + .bit_order = NO_OS_SPI_BIT_ORDER_MSB_FIRST, + .mode = NO_OS_SPI_MODE_0, + .platform_ops = SPI_OPS, + .chip_select = SPI_CS, + .extra = SPI_EXTRA, +}; + +struct no_os_i2c_init_param adf5611_i2c_ip = { + .device_id = I2C_DEVICE_ID, + .platform_ops = I2C_OPS, + .max_speed_hz = 100000, + .extra = I2C_EXTRA, + .slave_address = 0x54 +}; + +struct eeprom_24xx32a_init_param adf5611_eeprom_init_param = { + .i2c_init = &adf5611_i2c_ip, +}; + +struct no_os_eeprom_init_param adf5611_eeprom_ip = { + .device_id = 5, + .platform_ops = &eeprom_24xx32a_ops, + .extra = &adf5611_eeprom_init_param, +}; + +struct adf5611_init_param adf5611_ip = { + .spi_init = &adf5611_spi_ip, + .spi4wire = true, + .cmos_3v3 = false, + .ref_clk_freq = 122880000, + .rfout_freq = 12000000000, + .ref_div = 2, + .cp_i = 15, + .bleed_word = 17, + .ld_count = 12, + .id = ID_ADF5611, +}; diff --git a/projects/adf5611/src/common/common_data.h b/projects/adf5611/src/common/common_data.h new file mode 100644 index 00000000000..e6a7f2ec519 --- /dev/null +++ b/projects/adf5611/src/common/common_data.h @@ -0,0 +1,59 @@ +/***************************************************************************//** + * @file common_data.h + * @brief Defines common data to be used by adf5611 examples. + * @author Josemene (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. +*******************************************************************************/ +#ifndef __COMMON_DATA_H__ +#define __COMMON_DATA_H__ + +#include "parameters.h" +#include "adf5611.h" +#include "no_os_spi.h" +#include "no_os_uart.h" +#include "no_os_util.h" +#include "no_os_i2c.h" +#include "no_os_eeprom.h" +#include "24xx32a.h" + +#define HW_MEZZANINE_NAME "EVAL-ADF5611-SD1Z" +#define HW_CARRIER "SDP_K1" +#define ACTIVE_DEVICE_NAME "DEV_ADF5611" +#define ACTIVE_DEVICE_ID "ID_ADF5611" +#define ACTIVE_DEVICE_VENDOR "Analog Devices" +#define NUM_CTX_ATTR 4 + +extern struct no_os_uart_init_param adf5611_uart_ip; +extern struct no_os_spi_init_param adf5611_spi_ip; +extern struct adf5611_init_param adf5611_ip; +extern struct no_os_i2c_init_param adf5611_i2c_ip; +extern struct no_os_eeprom_init_param adf5611_eeprom_ip; +extern struct eeprom_24xx32a_init_param adf5611_eeprom_init_param; + +#endif /* __COMMON_DATA_H__ */ diff --git a/projects/adf5611/src/examples/basic/basic_example.c b/projects/adf5611/src/examples/basic/basic_example.c new file mode 100644 index 00000000000..a66f47e4d8d --- /dev/null +++ b/projects/adf5611/src/examples/basic/basic_example.c @@ -0,0 +1,66 @@ +/***************************************************************************//** + * @file basic_example.c + * @brief Basic example eval-adf5611 project + * @author Josemene (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 +#include +#include +#include "common_data.h" +#include "no_os_delay.h" +#include "no_os_print_log.h" + +/** + * @brief Basic example main execution. + * + * @return ret - Result of the example execution. If working correctly, will + * execute continuously the while(1) loop and will not return. + */ +int example_main() +{ + struct adf5611_dev *dev; + int ret; + + pr_info("Enter basic example \n"); + + ret = adf5611_init(&dev, &adf5611_ip); + if (ret) + goto error; + + ret = adf5611_set_rfout(dev, 12000000000); + if (ret) + goto error; + + return ret; +error: + pr_info("Error!\n"); + return ret; +} diff --git a/projects/adf5611/src/examples/iio_example/example.mk b/projects/adf5611/src/examples/iio_example/example.mk new file mode 100644 index 00000000000..7c3b6239a95 --- /dev/null +++ b/projects/adf5611/src/examples/iio_example/example.mk @@ -0,0 +1,3 @@ +IIOD=y +INCS += $(DRIVERS)/frequency/adf5611/iio_adf5611.h +SRCS += $(DRIVERS)/frequency/adf5611/iio_adf5611.c diff --git a/projects/adf5611/src/examples/iio_example/iio_example.c b/projects/adf5611/src/examples/iio_example/iio_example.c new file mode 100644 index 00000000000..436fb9dedd0 --- /dev/null +++ b/projects/adf5611/src/examples/iio_example/iio_example.c @@ -0,0 +1,128 @@ +/***************************************************************************//** + * @file iio_example.c + * @brief Implementation of IIO example for adf5611 project. + * @author Josemene (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 +#include +#include +#include "iio_adf5611.h" +#include "common_data.h" +#include "no_os_print_log.h" +#include "iio_app.h" + +#define BOARD_NAME_SUPPORT 1 + +/** + * @brief IIO example main execution. + * + * @return ret - Result of the example execution. If working correctly, will + * execute continuously function iio_app_run and will not return. + */ +int example_main() +{ + struct adf5611_iio_dev *adf5611_iio_dev; + struct adf5611_iio_dev_init_param adf5611_iio_ip; + struct iio_app_desc *app; + struct iio_app_init_param app_init_param = { 0 }; + struct iio_ctx_attr *context_attributes; + int ret; + + + adf5611_iio_ip.adf5611_dev_init = &adf5611_ip; + ret = adf5611_iio_init(&adf5611_iio_dev, &adf5611_iio_ip); + if (ret) + return ret; + + struct iio_app_device iio_devices[] = { + { + .name = "adf5611", + .dev = adf5611_iio_dev, + .dev_descriptor = adf5611_iio_dev->iio_dev, + } + }; +#if BOARD_NAME_SUPPORT + struct no_os_eeprom_desc *eeprom_dev; + ret = eeprom_24xx32a_ops.init(&eeprom_dev, &adf5611_eeprom_ip); + if (ret) + return ret; + char board_name[17] = {0}; + char hw_mezz[25]; + uint32_t eeprom_address = 0x1B; + + ret = eeprom_24xx32a_ops.read(eeprom_dev, eeprom_address, + (uint8_t *)board_name, sizeof(board_name)); + if (ret) + return ret; + int i, index = 0; + for (i = 0; board_name[i] != '\0'; i++) { + if (isalnum((unsigned char)board_name[i]) + || board_name[i] == '-') { + hw_mezz[index++] = board_name[i]; + } + } + hw_mezz[index] = '\0'; + + ret = eeprom_24xx32a_ops.remove(eeprom_dev); + if (ret) + return ret; + +#endif + context_attributes = (struct iio_ctx_attr *)calloc(NUM_CTX_ATTR, + sizeof(*context_attributes)); + context_attributes[0].name = "hw_mezzanine"; + context_attributes[0].value = hw_mezz; + context_attributes[1].name = "hw_carrier"; + context_attributes[1].value = HW_CARRIER; + context_attributes[2].name = "hw_name"; + context_attributes[2].value = ACTIVE_DEVICE_NAME; + context_attributes[3].name = "hw_vendor"; + context_attributes[3].value = ACTIVE_DEVICE_VENDOR; + + app_init_param.devices = iio_devices; + app_init_param.nb_devices = NO_OS_ARRAY_SIZE(iio_devices); + app_init_param.uart_init_params = adf5611_uart_ip; + app_init_param.ctx_attrs = context_attributes; + app_init_param.nb_ctx_attr = NUM_CTX_ATTR; + + ret = iio_app_init(&app, app_init_param); + if (ret) + goto exit; + iio_app_run(app); + + iio_app_remove(app); +exit: + adf5611_iio_remove(adf5611_iio_dev); + + if (ret) + pr_info("Error!\n"); + return ret; +} diff --git a/projects/adf5611/src/platform/mbed/main.c b/projects/adf5611/src/platform/mbed/main.c new file mode 100644 index 00000000000..23ffbd0e13c --- /dev/null +++ b/projects/adf5611/src/platform/mbed/main.c @@ -0,0 +1,65 @@ +/***************************************************************************//** + * @file main.c + * @brief Main file for Mbed platform of ADF5611 project. + * @author Josemene (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 Files **********************************/ +/******************************************************************************/ +#include "parameters.h" +#include "common_data.h" +#include "no_os_error.h" + +extern int example_main(); + +/** + * @brief Main function execution for mbed platform. + * @return ret - Result of the enabled examples execution. + */ +int main() +{ + int ret = -EINVAL; + struct no_os_uart_desc *uart_desc; + + // Initialize UART Interface + ret = no_os_uart_init(&uart_desc, &adf5611_uart_ip); + if (ret) + return ret; + + no_os_uart_stdio(uart_desc); + + // Execute the example main function + ret = example_main(); + if (ret) + return ret; + + return ret; +} diff --git a/projects/adf5611/src/platform/mbed/parameters.c b/projects/adf5611/src/platform/mbed/parameters.c new file mode 100644 index 00000000000..1bc27ba976a --- /dev/null +++ b/projects/adf5611/src/platform/mbed/parameters.c @@ -0,0 +1,50 @@ +/***************************************************************************//** + * @file parameters.c + * @brief Definition of Mbed platform data used by ADF5611 project. + * @author Josemene (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 "parameters.h" + +struct mbed_uart_init_param adf5611_uart_extra_ip = { + .uart_tx_pin = UART_TX_PIN, + .uart_rx_pin = UART_RX_PIN +}; + +struct mbed_spi_init_param adf5611_spi_extra = { + .spi_miso_pin = ARDUINO_UNO_D12, + .spi_mosi_pin = ARDUINO_UNO_D11, + .spi_clk_pin = ARDUINO_UNO_D13, + .use_sw_csb = false +}; + +struct mbed_i2c_init_param adf5611_i2c_extra_param = { + .i2c_scl_pin = ARDUINO_UNO_D15, + .i2c_sda_pin = ARDUINO_UNO_D14 +}; diff --git a/projects/adf5611/src/platform/mbed/parameters.h b/projects/adf5611/src/platform/mbed/parameters.h new file mode 100644 index 00000000000..536d2939c4c --- /dev/null +++ b/projects/adf5611/src/platform/mbed/parameters.h @@ -0,0 +1,65 @@ +/***************************************************************************//** + * @file parameters.h + * @brief Definitions specific to Mbed platform used by ADF5611 project. + * @author Josemene (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. +*******************************************************************************/ +#ifndef __PARAMETERS_H__ +#define __PARAMETERS_H__ + +#include +#include "mbed_uart.h" +#include "mbed_spi.h" +#include "no_os_uart.h" +#include "mbed_i2c.h" +#include "no_os_i2c.h" + +#define UART_TX_PIN CONSOLE_TX +#define UART_RX_PIN CONSOLE_RX +#define UART_DEVICE_ID 5 +#define UART_IRQ_ID 53 +#define UART_BAUDRATE 230400 +#define UART_EXTRA &adf5611_uart_extra_ip +#define UART_OPS &mbed_uart_ops + +#define SPI_BAUDRATE 4000000 +#define SPI_OPS &mbed_spi_ops +#define SPI_EXTRA &adf5611_spi_extra +#define SPI_DEVICE_ID 5 +#define SPI_CS ARDUINO_UNO_D10 + +#define I2C_OPS &mbed_i2c_ops +#define I2C_EXTRA &adf5611_i2c_extra_param +#define I2C_DEVICE_ID 0 + +extern struct mbed_uart_init_param adf5611_uart_extra_ip; +extern struct mbed_spi_init_param adf5611_spi_extra; +extern struct mbed_i2c_init_param adf5611_i2c_extra_param; + +#endif /* __PARAMETERS_H__ */ diff --git a/projects/adf5611/src/platform/mbed/platform_src.mk b/projects/adf5611/src/platform/mbed/platform_src.mk new file mode 100644 index 00000000000..eb230f82e61 --- /dev/null +++ b/projects/adf5611/src/platform/mbed/platform_src.mk @@ -0,0 +1,14 @@ +INCS += $(PLATFORM_DRIVERS)/mbed_uart.h \ + $(PLATFORM_DRIVERS)/mbed_gpio.h \ + $(PLATFORM_DRIVERS)/mbed_irq.h \ + $(PLATFORM_DRIVERS)/mbed_gpio_irq.h \ + $(PLATFORM_DRIVERS)/mbed_spi.h \ + $(PLATFORM_DRIVERS)/mbed_i2c.h + +SRCS += $(PLATFORM_DRIVERS)/mbed_uart.cpp \ + $(PLATFORM_DRIVERS)/mbed_gpio.cpp \ + $(PLATFORM_DRIVERS)/mbed_irq.cpp \ + $(PLATFORM_DRIVERS)/mbed_gpio_irq.cpp \ + $(PLATFORM_DRIVERS)/mbed_spi.cpp \ + $(PLATFORM_DRIVERS)/mbed_delay.cpp \ + $(PLATFORM_DRIVERS)/mbed_i2c.cpp \ No newline at end of file