diff --git a/drivers/frequency/admfm2000/README.rst b/drivers/frequency/admfm2000/README.rst new file mode 100644 index 00000000000..3152f5374bd --- /dev/null +++ b/drivers/frequency/admfm2000/README.rst @@ -0,0 +1,446 @@ +ADMFM2000 no-OS driver +==================== + +Supported Devices +----------------- + +`ADMFM2000 `_ + +Overview +-------- + +The `ADMFM2000 `_ is a dual-channel +microwave downconverter, with +input RF and local oscillator (LO) frequency ranges covering 5 GHz +to 32 GHz, with an output intermediate frequency (IF) frequency +range from 0.5 GHz to 8 GHz. The downconverting mixer can +also be bypassed allowing direct access to the 0.5 to 8 GHz IF +path. A common LO input signal is split to feed two separate +buffer amplifiers to drive the mixer in each channel. Each down +conversion path consists of a low noise amplifier (LNA), a mixer, an +IF filter, a digital step attenuator (DSA), and an IF amplifier + +Fabricated using a combination of surface mount and bare die +components, the `ADMFM2000 `_ +provides precise gain adjustment capabilities with low distortion performance. +The ADMFM2000 comes in a compact, shielded 20.00 mm × 14.00 mm, 179-ball +chip scale package ball grid array (CSP_BGA) and operates over a temperature +range of −40°C to +85°C. + +Applications +------------ + +* Phased array radar receivers +* Satellite communications (satcom) receivers +* Electronic warfare +* Electronic test and measurement equipment +* Automatic test equipmen + +ADMFM2000 Device Configuration +---------------------------- + +Driver Initialization +--------------------- + +In order to be able to use the device, you will have to provide the gpios +connected in order to control the device. + +The first API to be called is **admfm2000_init**. Make sure that it returns 0, +which means that the driver was initialized correctly. This function will also +set the channel to mixer_mode/direct if and set the gain for both channels +according to the initialization parameter. + +Switch configutation +----------------------------- + +The ADMFM2000 has a broadband SPDT RF switch in each channel that can be used to +bypass the mixer. epending on the logic level applied to those control pins, the +IF path is either connected to the mixer or to the RF_BYPASS_IN pin. This can be +done using **admfm2000_set_channel_mode**. The current configuration can be read +out using **admfm2000_get_channel_mode**.The channels can only be set +simultaneously, meaning when one channel is set to mixer mode, the other one will +be set to bypass mode. + +ADMFM2000 Driver Initialization Example +------------------------------------- + +Platform Communication Example +------------------------- + +.. code-block:: bash + + struct admfm2000_dev *dev; + int ret; + + struct no_os_uart_init_param admfm2000_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, + .platform_ops = UART_OPS, + .extra = &xuip, + }; + + struct no_os_gpio_init_param admfm2000_gpio_c0_ip[2] = { + { + .port = 0, + .number = 12, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 0, + .number = 14, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + }; + + struct no_os_gpio_init_param admfm2000_gpio_c1_ip[2] = { + { + .port = 2, + .number = 10, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 2, + .number = 6, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + }; + + struct no_os_gpio_init_param admfm2000_gpio_dsa0_ip[5] = { + { + .port = 2, + .number = 1, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 0, + .number = 11, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 2, + .number = 7, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 2, + .number = 8, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 2, + .number = 9, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + }; + + struct no_os_gpio_init_param admfm2000_gpio_dsa1_ip[5] = { + { + .port = 2, + .number = 20, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 2, + .number = 21, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 3, + .number = 8, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 4, + .number = 1, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 0, + .number = 13, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + }; + + struct admfm2000_init_param admfm2000_ip = { + .mixer_mode = ADMFM2000_DIRECT_IF_MODE, + .dsa_gain = 0, + .gpio_sw0_param = { + [0] = &admfm2000_gpio_c0_ip[0], + [1] = &admfm2000_gpio_c0_ip[1], + }, + .gpio_sw1_param = { + [0] = &admfm2000_gpio_c1_ip[0], + [1] = &admfm2000_gpio_c1_ip[1], + }, + .gpio_dsa0_param = { + [0] = &admfm2000_gpio_dsa0_ip[0], + [1] = &admfm2000_gpio_dsa0_ip[1], + [2] = &admfm2000_gpio_dsa0_ip[2], + [3] = &admfm2000_gpio_dsa0_ip[3], + [4] = &admfm2000_gpio_dsa0_ip[4], + }, + .gpio_dsa1_param = { + [0] = &admfm2000_gpio_dsa1_ip[0], + [1] = &admfm2000_gpio_dsa1_ip[1], + [2] = &admfm2000_gpio_dsa1_ip[2], + [3] = &admfm2000_gpio_dsa1_ip[3], + [4] = &admfm2000_gpio_dsa1_ip[4], + }, + }; + + ret = admfm2000_init(&dev, &admfm2000_ip); + if (ret) + goto error; + + ret = admfm2000_set_channel_config(dev, ADMFM2000_MIXER_MODE); + if (ret) + goto error; + + ret = admfm2000_set_gain(dev, 0, 24); + if (ret) + goto error; + +ADMFM2000 no-OS IIO support +------------------------- + +The ADMFM2000 IIO driver comes on top of ADMFM2000 driver and offers support for +interfacing IIO clients through IIO lib. + +ADMFM2000 IIO Device Configuration +-------------------------------- + +Device Attributes +----------------- + +The ADMFM2000 only has two channels, each having a configurable gain. + +Device Channels +--------------- + +ADMFM2000 IIO device has 2 output channels. + +The channels are: + +* output voltage0 - corresponding to channel 1 on the device +* output voltage1 - corresponding to channel 2 on the device + +Each channel has 1 individual attribute: + +* hardwaregain - is the dsa gain of the channel. The gain can be set between 0 + (reference) and 31. + +ADMFM2000 IIO Driver Initialization Example +----------------------------------------- + +.. code-block:: bash + + struct admfm2000_iio_dev *admfm2000_iio_dev; + struct admfm2000_iio_dev_init_param admfm2000_iio_ip; + struct iio_app_desc *app; + struct iio_app_init_param app_init_param = { 0 }; + int ret; + + struct no_os_uart_init_param admfm2000_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, + .platform_ops = UART_OPS, + .extra = &xuip, + }; + + struct no_os_gpio_init_param admfm2000_gpio_c0_ip[2] = { + { + .port = 0, + .number = 12, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 0, + .number = 14, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + }; + + struct no_os_gpio_init_param admfm2000_gpio_c1_ip[2] = { + { + .port = 2, + .number = 10, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 2, + .number = 6, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + }; + + struct no_os_gpio_init_param admfm2000_gpio_dsa0_ip[5] = { + { + .port = 2, + .number = 1, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 0, + .number = 11, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 2, + .number = 7, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 2, + .number = 8, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 2, + .number = 9, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + }; + + struct no_os_gpio_init_param admfm2000_gpio_dsa1_ip[5] = { + { + .port = 2, + .number = 20, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 2, + .number = 21, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 3, + .number = 8, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 4, + .number = 1, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + { + .port = 0, + .number = 13, + .pull = NO_OS_PULL_NONE, + .platform_ops = GPIO_OPS, + .extra = GPIO_EXTRA, + }, + }; + + struct admfm2000_init_param admfm2000_ip = { + .mixer_mode = ADMFM2000_DIRECT_IF_MODE, + .dsa_gain = 0, + .gpio_sw0_param = { + [0] = &admfm2000_gpio_c0_ip[0], + [1] = &admfm2000_gpio_c0_ip[1], + }, + .gpio_sw1_param = { + [0] = &admfm2000_gpio_c1_ip[0], + [1] = &admfm2000_gpio_c1_ip[1], + }, + .gpio_dsa0_param = { + [0] = &admfm2000_gpio_dsa0_ip[0], + [1] = &admfm2000_gpio_dsa0_ip[1], + [2] = &admfm2000_gpio_dsa0_ip[2], + [3] = &admfm2000_gpio_dsa0_ip[3], + [4] = &admfm2000_gpio_dsa0_ip[4], + }, + .gpio_dsa1_param = { + [0] = &admfm2000_gpio_dsa1_ip[0], + [1] = &admfm2000_gpio_dsa1_ip[1], + [2] = &admfm2000_gpio_dsa1_ip[2], + [3] = &admfm2000_gpio_dsa1_ip[3], + [4] = &admfm2000_gpio_dsa1_ip[4], + }, + }; + + admfm2000_iio_ip.admfm2000_dev_init = &admfm2000_ip; + ret = admfm2000_iio_init(&admfm2000_iio_dev, &admfm2000_iio_ip); + if (ret) + return ret; + + struct iio_app_device iio_devices[] = { + { + .name = "admfm2000", + .dev = admfm2000_iio_dev, + .dev_descriptor = admfm2000_iio_dev->iio_dev, + } + }; + + app_init_param.devices = iio_devices; + app_init_param.nb_devices = NO_OS_ARRAY_SIZE(iio_devices); + app_init_param.uart_init_params = admfm2000_uart_ip; + + ret = iio_app_init(&app, app_init_param); + if (ret) + return ret; + + return iio_app_run(app); diff --git a/drivers/frequency/admfm2000/admfm2000.c b/drivers/frequency/admfm2000/admfm2000.c new file mode 100644 index 00000000000..ca3dd759a48 --- /dev/null +++ b/drivers/frequency/admfm2000/admfm2000.c @@ -0,0 +1,217 @@ +/***************************************************************************//** + * @file admfm2000.c + * @brief Implementation of admfm2000 Driver. + * @author Ramona Nechita (ramona.nechita@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 "admfm2000.h" +#include "no_os_alloc.h" +#include "no_os_error.h" +#include "no_os_print_log.h" + + +int32_t admfm2000_get_gain(struct admfm2000_dev *dev, uint8_t chan, + int32_t *gain) +{ + int32_t ret; + uint8_t i; + uint8_t bit; + int32_t tmp = 0; + + if (chan > 1) + return -EINVAL; + + if (chan) + for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) { + ret = no_os_gpio_get_value(dev->gpio_dsa1[i], &bit); + if (ret != 0) + return ret; + tmp |= (bit << i); + } else + for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) { + ret = no_os_gpio_get_value(dev->gpio_dsa0[i], &bit); + if (ret != 0) + return ret; + tmp |= (bit << i); + } + *gain = tmp; + + return 0; +} + +int32_t admfm2000_set_gain(struct admfm2000_dev *dev, uint8_t chan, + int32_t gain) +{ + int32_t ret; + uint8_t i; + + if (gain > ADMFM2000_MAX_GAIN_RAW || gain < ADMFM2000_MIN_GAIN_RAW) + return -EINVAL; + + if (chan) + for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) { + ret = no_os_gpio_set_value(dev->gpio_dsa1[i], + (gain & (1 << i)) >> i); + if (ret != 0) + return ret; + } else + for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) { + ret = no_os_gpio_set_value(dev->gpio_dsa0[i], + (gain & (1 << i)) >> i); + if (ret != 0) + return ret; + } + + return 0; +} + +int32_t admfm2000_set_channel_config(struct admfm2000_dev *dev, uint8_t config) +{ + int32_t ret; + int32_t i; + + if (config > 1) + return -EINVAL; + + if (config) { + ret = no_os_gpio_set_value(dev->gpio_sw0[0], 0); + ret = no_os_gpio_set_value(dev->gpio_sw0[1], 1); + ret = no_os_gpio_set_value(dev->gpio_sw1[0], 1); + ret = no_os_gpio_set_value(dev->gpio_sw1[1], 0); + } else { + ret = no_os_gpio_set_value(dev->gpio_sw0[0], 1); + ret = no_os_gpio_set_value(dev->gpio_sw0[1], 0); + ret = no_os_gpio_set_value(dev->gpio_sw1[0], 0); + ret = no_os_gpio_set_value(dev->gpio_sw1[1], 1); + } + + return ret; +} + +int32_t admfm2000_init(struct admfm2000_dev **device, + struct admfm2000_init_param *init_param) +{ + int32_t ret; + uint8_t i; + struct admfm2000_dev *dev; + + dev = (struct admfm2000_dev *)no_os_calloc(1, sizeof(*dev)); + if (!dev) + return -ENOMEM; + + for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) { + ret = no_os_gpio_get(&dev->gpio_sw0[i], + init_param->gpio_sw0_param[i]); + if (ret) + goto error; + ret = no_os_gpio_direction_output(dev->gpio_sw0[i], + NO_OS_GPIO_HIGH); + if (ret) + goto error; + } + + for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) { + ret = no_os_gpio_get(&dev->gpio_sw1[i], + init_param->gpio_sw1_param[i]); + if (ret) + goto error; + ret = no_os_gpio_direction_output(dev->gpio_sw1[i], + NO_OS_GPIO_HIGH); + if (ret) + goto error; + } + + for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) { + ret = no_os_gpio_get(&dev->gpio_dsa0[i], + init_param->gpio_dsa0_param[i]); + if (ret) + goto error; + ret = no_os_gpio_direction_output(dev->gpio_dsa0[i], + NO_OS_GPIO_HIGH); + if (ret) + goto error; + } + + for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) { + ret = no_os_gpio_get(&dev->gpio_dsa1[i], + init_param->gpio_dsa1_param[i]); + if (ret) + goto error; + ret = no_os_gpio_direction_output(dev->gpio_dsa1[i], + NO_OS_GPIO_HIGH); + if (ret) + goto error; + } + + ret = admfm2000_set_channel_config(dev, init_param->mixer_mode); + if (ret) + goto error; + + ret = admfm2000_set_gain(dev, 0, init_param->dsa_gain); + if (ret) + goto error; + + ret = admfm2000_set_gain(dev, 1, init_param->dsa_gain); + if (ret) + goto error; + + *device = dev; + + return 0; + +error: + no_os_free(dev); + + return ret; +} + +int32_t admfm2000_remove(struct admfm2000_dev *dev) +{ + uint8_t i; + + for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) + no_os_gpio_remove(dev->gpio_sw0[i]); + + for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) + no_os_gpio_remove(dev->gpio_sw1[i]); + + for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) + no_os_gpio_remove(dev->gpio_dsa0[i]); + + for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) + no_os_gpio_remove(dev->gpio_dsa1[i]); + + no_os_free(dev); + + return 0; +} diff --git a/drivers/frequency/admfm2000/admfm2000.h b/drivers/frequency/admfm2000/admfm2000.h new file mode 100644 index 00000000000..de3c72d4607 --- /dev/null +++ b/drivers/frequency/admfm2000/admfm2000.h @@ -0,0 +1,141 @@ +/***************************************************************************//** + * @file admfm2000.h + * @brief Header file for admfm2000 Driver. + * @author Ramona Nechita (ramona.nechita@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 SRC_ADMFM2000_H_ +#define SRC_ADMFM2000_H_ + +/******************************************************************************/ +/***************************** Include Files **********************************/ +/******************************************************************************/ +#include +#include "no_os_gpio.h" + +/******************************************************************************/ +/********************** Macros and Constants Definitions **********************/ +/******************************************************************************/ +#define ADMFM2000_MIXER_MODE 0 +#define ADMFM2000_DIRECT_IF_MODE 1 +#define ADMFM2000_DSA_GPIOS 5 +#define ADMFM2000_MODE_GPIOS 2 +#define ADMFM2000_MAX_GAIN 0 +#define ADMFM2000_MIN_GAIN -31000 +#define ADMFM2000_MAX_GAIN_RAW 31 +#define ADMFM2000_MIN_GAIN_RAW 0 +#define ADMFM2000_DEFAULT_GAIN -0x20 + +/******************************************************************************/ +/*************************** Types Declarations *******************************/ +/******************************************************************************/ + +struct admfm2000_init_param { + /* Mixer Mode */ + uint8_t mixer_mode; + /* GAIN */ + int32_t dsa_gain; + /* GPIO Control Switch chan 0 */ + struct no_os_gpio_init_param *gpio_sw0_param[2]; + /* GPIO Control Switch chan 1 */ + struct no_os_gpio_init_param *gpio_sw1_param[2]; + /* GPIO Control DSA chan 0 */ + struct no_os_gpio_init_param *gpio_dsa0_param[5]; + /* GPIO Control DSA chan 1 */ + struct no_os_gpio_init_param *gpio_dsa1_param[5]; +}; + +struct admfm2000_dev { + /* GPIO Control Switch chan 0 */ + struct no_os_gpio_desc *gpio_sw0[2]; + /* GPIO Control Switch chan 1 */ + struct no_os_gpio_desc *gpio_sw1[2]; + /* GPIO Control DSA chan 0 */ + struct no_os_gpio_desc *gpio_dsa0[5]; + /* GPIO Control DSA chan 1 */ + struct no_os_gpio_desc *gpio_dsa1[5]; +}; + +/******************************************************************************/ +/************************ Functions Declarations ******************************/ +/******************************************************************************/ + +/** + * @brief Initialize the admfm2000 device. + * @param device - The device structure. + * @param init_param - The structure that contains the device initial parameters. + * @return Returns 0 in case of success or negative error code otherwise. + */ +int32_t admfm2000_init(struct admfm2000_dev **device, + struct admfm2000_init_param *init_param); + +/** + * @brief Free the resources allocated by admfm2000_init(). + * @param dev - The device structure. + * @return ret - Result of the remove procedure. + */ +int32_t admfm2000_remove(struct admfm2000_dev *dev); + +/** + * @brief Set the gain of the device. + * @param dev - The device structure. + * @param chan - The channel for which the gain is set. + * @param gain - The gain value. + * @return Returns 0 in case of success or negative error code otherwise. + */ +int32_t admfm2000_set_gain(struct admfm2000_dev *dev, uint8_t chan, + int32_t gain); + +/** + * @brief Get the gain of the device. + * @param dev - The device structure. + * @param chan - The channel for which the gain is read. + * @param gain - The gain value. + * @return Returns 0 in case of success or negative error code otherwise. + */ +int32_t admfm2000_get_gain(struct admfm2000_dev *dev, uint8_t chan, + int32_t *gain); + +/** + * @brief Set the channel mode. + * @param dev - The device structure. + * @param mode - The mode value. + * @return Returns 0 in case of success or negative error code otherwise. + */ +int32_t admfm2000_get_channel_mode(struct admfm2000_dev *dev, uint8_t mode); +/** + * @brief Set the channel configuration. + * @param dev - The device structure. + * @param config - The config + * @return Returns 0 in case of success or negative error code otherwise. + */ +int32_t admfm2000_set_channel_mode(struct admfm2000_dev *dev, uint8_t config); + +#endif /* SRC_ADMFM2000_H_ */ \ No newline at end of file diff --git a/drivers/frequency/admfm2000/iio_admfm2000.c b/drivers/frequency/admfm2000/iio_admfm2000.c new file mode 100644 index 00000000000..61df5ad5a99 --- /dev/null +++ b/drivers/frequency/admfm2000/iio_admfm2000.c @@ -0,0 +1,209 @@ +/***************************************************************************//** + * @file iio_admfm2000.c + * @brief Implementation of admfm2000 IIO Driver. + * @author Ramona Nechita (ramona.nechita@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 +#include +#include +#include "no_os_error.h" +#include "no_os_util.h" +#include "iio_admfm2000.h" +#include "no_os_alloc.h" + +/** + * @brief Get the channel gain. + * @param dev - The iio device structure. + * @param buf - Command buffer to be filled with the data to be written. + * @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 admfm2000_iio_read_gain(void *dev, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv) +{ + struct admfm2000_iio_dev *iio_admfm2000 = (struct admfm2000_iio_dev *)dev; + struct admfm2000_dev *admfm2000_dev; + int32_t gain; + int32_t vals[2]; + int32_t tmp; + int32_t ret; + + if (!iio_admfm2000) + return -EINVAL; + + admfm2000_dev = iio_admfm2000->admfm2000_dev; + + if (!admfm2000_dev) + return -EINVAL; + + ret = admfm2000_get_gain(admfm2000_dev, channel->ch_num, &gain); + if (ret) + return ret; + tmp = ~(gain) * -1000; + vals[0] = tmp / 1000; + vals[1] = (tmp % 1000) * 1000; + return iio_format_value(buf, len, IIO_VAL_INT_PLUS_MICRO_DB, 1, + (int32_t *)vals); +} + +/** + * @brief Set the channel gain. + * @param dev - The iio device structure. + * @param buf - Command buffer to be filled with the data to be written. + * @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 admfm2000_iio_write_gain(void *dev, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv) +{ + struct admfm2000_iio_dev *iio_admfm2000 = (struct admfm2000_iio_dev *)dev; + struct admfm2000_dev *admfm2000_dev; + int32_t val, val2; + int32_t gain, tmp; + int32_t ret; + + if (!iio_admfm2000) + return -EINVAL; + + admfm2000_dev = iio_admfm2000->admfm2000_dev; + + if (!admfm2000_dev) + return -EINVAL; + + ret = iio_parse_value(buf, IIO_VAL_INT_PLUS_MICRO_DB, &val, &val2); + if (ret) + return ret; + + if (val < 0) + tmp = (val * 1000) - (val2 / 1000); + else + tmp = (val * 1000) + (val2 / 1000); + gain = ~((abs(tmp) / 1000)) & 0x1F; + ret = admfm2000_set_gain(admfm2000_dev, channel->ch_num, gain); + if (ret) + return ret; + + return len; +} + +static struct iio_attribute admfm2000_iio_ch_attrs[] = { + { + .name = "hardwaregain", + .shared = IIO_SEPARATE, + .show = admfm2000_iio_read_gain, + .store = admfm2000_iio_write_gain, + }, + END_ATTRIBUTES_ARRAY +}; + +static struct iio_channel admfm2000_channels[] = { + { + .ch_type = IIO_VOLTAGE, + .channel = 0, + .ch_out = true, + .indexed = true, + .attributes = admfm2000_iio_ch_attrs, + .scan_type = NULL, + }, + { + .ch_type = IIO_VOLTAGE, + .channel = 1, + .ch_out = true, + .indexed = true, + .attributes = admfm2000_iio_ch_attrs, + .scan_type = NULL, + }, +}; + +static struct iio_device admfm2000_iio_dev = { + .num_ch = NO_OS_ARRAY_SIZE(admfm2000_channels), + .channels = admfm2000_channels, +}; + +/** + * @brief Initialize the iio device. + * @param iio_dev - The iio device structure. + * @param init_param - The iio device initialization structure. + * @return SUCCESS in case of success, FAILURE otherwise. + */ +int admfm2000_iio_init(struct admfm2000_iio_dev **iio_dev, + struct admfm2000_iio_dev_init_param *init_param) +{ + struct admfm2000_iio_dev *iio_admfm2000; + struct admfm2000_dev *admfm2000_dev; + int32_t ret; + + iio_admfm2000 = (struct admfm2000_iio_dev *)no_os_calloc(1, + sizeof(*iio_admfm2000)); + if (!iio_admfm2000) + return -ENOMEM; + + iio_admfm2000->iio_dev = &admfm2000_iio_dev; + + ret = admfm2000_init(&iio_admfm2000->admfm2000_dev, + init_param->admfm2000_dev_init); + if (ret) + return ret; + + *iio_dev = iio_admfm2000; + + return 0; +} + +/** + * @brief Free the resources allocated by admfm2000_iio_init(). + * @param desc - The iio device structure. + * @return SUCCESS in case of success, FAILURE otherwise. + */ +int admfm2000_iio_remove(struct admfm2000_iio_dev *desc) +{ + int32_t ret; + + ret = admfm2000_remove(desc->admfm2000_dev); + if (ret) + return ret; + + no_os_free(desc->admfm2000_dev); + no_os_free(desc); + + return 0; +} diff --git a/drivers/frequency/admfm2000/iio_admfm2000.h b/drivers/frequency/admfm2000/iio_admfm2000.h new file mode 100644 index 00000000000..c06a232bbf4 --- /dev/null +++ b/drivers/frequency/admfm2000/iio_admfm2000.h @@ -0,0 +1,62 @@ +/***************************************************************************//** + * @file iio_admfm2000.h + * @brief Header file for admfm2000 IIO Driver. + * @author Ramona Nechita (ramona.nechita@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 SRC_IIO_ADMFM2000_H_ +#define SRC_IIO_ADMFM2000_H_ + +/******************************************************************************/ +/***************************** Include Files **********************************/ +/******************************************************************************/ +#include +#include "admfm2000.h" +#include "iio.h" + +/******************************************************************************/ +/*************************** Types Declarations *******************************/ +/******************************************************************************/ + +struct admfm2000_iio_dev { + struct admfm2000_dev *admfm2000_dev; + struct iio_device *iio_dev; +}; + +struct admfm2000_iio_dev_init_param { + struct admfm2000_init_param *admfm2000_dev_init; +}; + +int admfm2000_iio_init(struct admfm2000_iio_dev **iio_dev, + struct admfm2000_iio_dev_init_param *init_param); + +int admfm2000_iio_remove(struct admfm2000_iio_dev *desc); + +#endif /* SRC_IIO_ADMFM2000_H_ */