Forked repository for pushing changes to EVAL-AD4696
Dependencies: platform_drivers
Diff: app/ad469x.c
- Revision:
- 1:8792acb5a039
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/ad469x.c Thu Sep 30 11:01:05 2021 +0530 @@ -0,0 +1,937 @@ +/***************************************************************************//** + * @file ad469x.c + * @brief Implementation of ad469x Driver. + * @author Cristian Pop (cristian.pop@analog.com) +******************************************************************************** + * Copyright 2021(c) Analog Devices, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * - 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. + * - The use of this software may or may not infringe the patent rights + * of one or more patent holders. This license does not release you + * from the requirement that you obtain separate licenses from these + * patent holders to use this software. + * - Use of the software either in source or binary form, must be run + * on or directly connected to an Analog Devices Inc. component. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 <string.h> +#include <stdio.h> +#include <stdlib.h> +#include "ad469x.h" +#include "delay.h" +#include "error.h" +#include "util.h" +#include "gpio.h" + +#define AD469x_TEST_DATA 0xEA +/******************************************************************************/ +/********************** Macros and Constants Definitions **********************/ +/******************************************************************************/ + +/** + * @brief Device resolution + */ +const uint8_t ad469x_device_resol[] = { + [AD469x_OSR_1] = 16, + [AD469x_OSR_4] = 17, + [AD469x_OSR_16] = 18, + [AD469x_OSR_64] = 19 +}; + +/******************************************************************************/ +/************************** Functions Implementation **************************/ +/******************************************************************************/ + +/** + * Read from device. + * @param dev - The device structure. + * @param reg_addr - The register address. + * @param reg_data - The register data. + * @return SUCCESS in case of success, negative error code otherwise. + */ +int32_t ad469x_spi_reg_read(struct ad469x_dev *dev, + uint16_t reg_addr, + uint8_t *reg_data) +{ + int32_t ret; + uint8_t buf[3]; + +#if defined (ENABLE_SPI_ENGINE) + ret = spi_engine_set_transfer_width(dev->spi_desc, dev->reg_data_width); + if (ret != SUCCESS) + return ret; + + spi_engine_set_speed(dev->spi_desc, dev->reg_access_speed); +#endif + + buf[0] = (1 << 7) | ((reg_addr >> 8) & 0x7F); + buf[1] = 0xFF & reg_addr; + buf[2] = 0xFF; + + ret = spi_write_and_read(dev->spi_desc, buf, 3); + *reg_data = buf[2]; + +#if defined (ENABLE_SPI_ENGINE) + ret = spi_engine_set_transfer_width(dev->spi_desc, dev->capture_data_width); + if (ret != SUCCESS) + return ret; + + spi_engine_set_speed(dev->spi_desc, dev->spi_desc->max_speed_hz); +#endif + + return ret; +} + +/** + * Write to device. + * @param dev - The device structure. + * @param reg_addr - The register address. + * @param reg_data - The register data. + * @@eturn SUCCESS in case of success, negative error code otherwise. + */ +int32_t ad469x_spi_reg_write(struct ad469x_dev *dev, + uint16_t reg_addr, + uint8_t reg_data) +{ + int32_t ret; + uint8_t buf[3]; + +#if defined (ENABLE_SPI_ENGINE) + ret = spi_engine_set_transfer_width(dev->spi_desc, dev->reg_data_width); + if (ret != SUCCESS) + return ret; + + spi_engine_set_speed(dev->spi_desc, dev->reg_access_speed); +#endif + + buf[0] = ((reg_addr >> 8) & 0x7F); + buf[1] = 0xFF & reg_addr; + buf[2] = reg_data; + + ret = spi_write_and_read(dev->spi_desc, buf, 3); + +#if defined (ENABLE_SPI_ENGINE) + ret = spi_engine_set_transfer_width(dev->spi_desc, + dev->capture_data_width); + if (ret != SUCCESS) + return ret; + + spi_engine_set_speed(dev->spi_desc, dev->spi_desc->max_speed_hz); +#endif + + return ret; +} + +/** + * SPI read from device using a mask. + * @param dev - The device structure. + * @param reg_addr - The register address. + * @param mask - The mask. + * @param data - The register data. + * @return SUCCESS in case of success, negative error code otherwise. + */ +int32_t ad469x_spi_read_mask(struct ad469x_dev *dev, + uint16_t reg_addr, + uint8_t mask, + uint8_t *data) +{ + uint8_t reg_data[3]; + int32_t ret; + + ret = ad469x_spi_reg_read(dev, reg_addr, reg_data); + if (ret != SUCCESS) + return ret; + + *data = (reg_data[0] & mask); + + return ret; +} + +/** + * SPI write to device using a mask. + * @param dev - The device structure. + * @param reg_addr - The register address. + * @param mask - The mask. + * @param data - The register data. + * @return SUCCESS in case of success, negative error code otherwise. + */ +int32_t ad469x_spi_write_mask(struct ad469x_dev *dev, + uint16_t reg_addr, + uint8_t mask, + uint8_t data) +{ + uint8_t reg_data; + int32_t ret; + + ret = ad469x_spi_reg_read(dev, reg_addr, ®_data); + if (ret != SUCCESS) + return ret; + + reg_data &= ~mask; + reg_data |= data; + + return ad469x_spi_reg_write(dev, reg_addr, reg_data); +} + +/** + * @brief Configure register access mode + * @param [in] dev - ad469x_dev device handler. + * @param [in] access - Access mode + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad469x_set_reg_access_mode(struct ad469x_dev *dev, + enum ad469x_reg_access access) +{ + return ad469x_spi_write_mask(dev, + AD469x_REG_IF_CONFIG_C, + AD469x_REG_IF_CONFIG_C_MB_STRICT_MASK, + AD469x_REG_IF_CONFIG_C_MB_STRICT(access)); +} + +/** + * @brief Initialize GPIO driver handlers for the GPIOs in the system. + * ad469x_init() helper function. + * @param [out] dev - ad469x_dev device handler. + * @param [in] init_param - Pointer to the initialization structure. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +static int32_t ad469x_init_gpio(struct ad469x_dev *dev, + struct ad469x_init_param *init_param) +{ + int32_t ret; + + do + { + ret = gpio_get_optional(&dev->gpio_resetn, init_param->gpio_resetn); + if (ret != SUCCESS) + break; + + /** Reset to configure pins */ + if (init_param->gpio_resetn) { + ret = gpio_direction_output(dev->gpio_resetn, GPIO_LOW); + if (ret != SUCCESS) + break; + + mdelay(100); + ret = gpio_set_value(dev->gpio_resetn, GPIO_HIGH); + if (ret != SUCCESS) + break; + + mdelay(100); + } + + /** Initialize the BUSY GPIO descriptor **/ + ret = gpio_get_optional(&dev->gpio_busy, init_param->gpio_busy); + if (ret != SUCCESS) + break; + + if (init_param->gpio_busy) { + if (gpio_direction_input(dev->gpio_busy) != SUCCESS) + break; + } + + return SUCCESS; + } while (0); + + return FAILURE; +} + +/** + * @brief Configure over sampling ratio in advanced sequencer mode + * @param [in] dev - ad469x_dev device handler. + * @param [in] ch - Channel to configure. + * @param [in] ratio - OSR ratio. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad469x_adv_seq_osr(struct ad469x_dev *dev, + uint16_t ch, + enum ad469x_osr_ratios ratio) +{ + int32_t ret; + + if (dev->ch_sequence == AD469x_single_cycle || + dev->ch_sequence == AD469x_two_cycle) + return FAILURE; + + if (ch >= AD469x_CHANNEL_NO) + return FAILURE; + + ret = ad469x_spi_write_mask(dev, + AD469x_REG_CONFIG_IN(ch), + AD469x_REG_CONFIG_IN_OSR_MASK, + AD469x_REG_CONFIG_IN_OSR(ratio)); + if (ret != SUCCESS) + return ret; + + dev->adv_seq_osr_resol[ch] = ad469x_device_resol[ratio]; + /* Set storage to maximum data width */ + dev->capture_data_width = ad469x_device_resol[AD469x_OSR_64]; + + return SUCCESS; +} + +/** + * @brief Configure over sampling ratio to 1 in single and two cycle modes. + * @param [in] dev - ad469x_dev device handler. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +static int32_t ad469x_seq_osr_clear(struct ad469x_dev *dev) +{ + int32_t ret; + uint8_t i = 0; + + for (i = 0; i < AD469x_CHANNEL_NO; i++) { + ret = ad469x_spi_write_mask(dev, + AD469x_REG_CONFIG_IN(i), + AD469x_REG_CONFIG_IN_OSR_MASK, + AD469x_REG_CONFIG_IN_OSR(AD469x_OSR_1)); + if (ret != SUCCESS) + return ret; + dev->adv_seq_osr_resol[i] = ad469x_device_resol[AD469x_OSR_1]; + } + /* Set storage to minimum data width */ + dev->capture_data_width = ad469x_device_resol[AD469x_OSR_1]; + + return SUCCESS; +} + +/** + * @brief Configure over sampling ratio in standard sequencer mode + * @param [in] dev - ad469x_dev device handler. + * @param [in] ratio - OSR ratio. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad469x_std_seq_osr(struct ad469x_dev *dev, enum ad469x_osr_ratios ratio) +{ + int ret; + + if (dev->ch_sequence == AD469x_single_cycle || + dev->ch_sequence == AD469x_two_cycle) + return FAILURE; + + ret = ad469x_spi_write_mask(dev, + AD469x_REG_CONFIG_IN(0), + AD469x_REG_CONFIG_IN_OSR_MASK, + AD469x_REG_CONFIG_IN_OSR(ratio)); + if (ret != SUCCESS) + return ret; + + dev->capture_data_width = ad469x_device_resol[ratio]; + + return ret; +} + +/** + * @brief Set channel sequence. + * @param [in] dev - ad469x_dev device handler. + * @param [in] seq - Channel sequence. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad469x_set_channel_sequence(struct ad469x_dev *dev, + enum ad469x_channel_sequencing seq) +{ + int32_t ret; + + switch (seq) { + case AD469x_single_cycle: + ret = ad469x_spi_write_mask(dev, + AD469x_REG_SEQ_CTRL, + AD469x_SEQ_CTRL_STD_SEQ_EN_MASK, + AD469x_SEQ_CTRL_STD_SEQ_EN(0)); + if (ret != SUCCESS) + return ret; + + ret = ad469x_spi_write_mask(dev, + AD469x_REG_SEQ_CTRL, + AD469x_SEQ_CTRL_NUM_SLOTS_AS_MASK, + AD469x_SEQ_CTRL_NUM_SLOTS_AS(0)); + if (ret != SUCCESS) + return ret; + + ret = ad469x_spi_write_mask(dev, + AD469x_REG_SETUP, + AD469x_SETUP_CYC_CTRL_MASK, + AD469x_SETUP_CYC_CTRL_SINGLE(0)); + if (ret != SUCCESS) + return ret; + + ret = ad469x_seq_osr_clear(dev); + if (ret != SUCCESS) + return ret; + + break; + + case AD469x_two_cycle: + ret = ad469x_spi_write_mask(dev, + AD469x_REG_SEQ_CTRL, + AD469x_SEQ_CTRL_STD_SEQ_EN_MASK, + AD469x_SEQ_CTRL_STD_SEQ_EN(0)); + if (ret != SUCCESS) + return ret; + + ret = ad469x_spi_write_mask(dev, + AD469x_REG_SEQ_CTRL, + AD469x_SEQ_CTRL_NUM_SLOTS_AS_MASK, + AD469x_SEQ_CTRL_NUM_SLOTS_AS(0)); + if (ret != SUCCESS) + return ret; + + ret = ad469x_spi_write_mask(dev, + AD469x_REG_SETUP, + AD469x_SETUP_CYC_CTRL_MASK, + AD469x_SETUP_CYC_CTRL_SINGLE(1)); + if (ret != SUCCESS) + return ret; + + ret = ad469x_seq_osr_clear(dev); + if (ret != SUCCESS) + return ret; + + break; + + case AD469x_standard_seq: + ret = ad469x_spi_write_mask(dev, + AD469x_REG_SEQ_CTRL, + AD469x_SEQ_CTRL_STD_SEQ_EN_MASK, + AD469x_SEQ_CTRL_STD_SEQ_EN(1)); + if (ret != SUCCESS) + return ret; + + break; + + case AD469x_advanced_seq: + ret = ad469x_spi_write_mask(dev, + AD469x_REG_SEQ_CTRL, + AD469x_SEQ_CTRL_STD_SEQ_EN_MASK, + AD469x_SEQ_CTRL_STD_SEQ_EN(0)); + if (ret != SUCCESS) + return ret; + + break; + + default: + return FAILURE; + break; + } + + dev->ch_sequence = seq; + + return ret; +} + +/** + * @brief Configure advanced sequencer number of slots, temp channel not + * included + * @param [in] dev - ad469x_dev device handler. + * @param [in] num_slots - Number of slots, max value = 0x7f + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad469x_adv_sequence_set_num_slots(struct ad469x_dev *dev, + uint8_t num_slots) +{ + int32_t ret; + uint8_t write_num_slots = 0; + + if (num_slots) + write_num_slots = num_slots - 1; + + ret = ad469x_spi_write_mask(dev, + AD469x_REG_SEQ_CTRL, + AD469x_SEQ_CTRL_NUM_SLOTS_AS_MASK, + AD469x_SEQ_CTRL_NUM_SLOTS_AS(write_num_slots)); + if (ret != SUCCESS) + return ret; + + dev->num_slots = num_slots; + + return SUCCESS; +} + +/** + * @brief Advanced sequencer, assign channel to a slot + * @param [in] dev - ad469x_dev device handler. + * @param [in] slot - Slot number [0x00, 0x7f] + * @param [in] channel - Assigned channel [0x00, 0x0f]. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad469x_adv_sequence_set_slot(struct ad469x_dev *dev, + uint8_t slot, + uint8_t channel) +{ + int32_t ret; + ret = ad469x_spi_reg_write(dev, + AD469x_REG_AS_SLOT(slot), + AD469x_REG_AS_SLOT_INX(channel)); + if (ret != SUCCESS) + return ret; + + dev->ch_slots[slot] = channel; + + return SUCCESS; +} + +/** + * @brief Configure standard sequencer channels + * @param [in] dev - ad469x_dev device handler. + * @param [in] ch_mask - Extra channels to activate. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad469x_std_sequence_ch(struct ad469x_dev *dev, uint32_t ch_mask) +{ + int32_t ret; + + ret = ad469x_spi_reg_write(dev, + AD469x_REG_STD_SEQ_CONFIG, + 0xff & ch_mask); + if (ret != SUCCESS) + return ret; + + ret = ad469x_spi_reg_write(dev, + AD469x_REG_STD_SEQ_CONFIG + 1, + ch_mask >> 8); + if (ret != SUCCESS) + return ret; + + dev->num_slots = hweight8(ch_mask); + + return ret; +} + +/** + * @brief Enable temperature read at the end of the sequence, for standard and + * advanced sequencer + * @param [in] dev - ad469x_dev device handler. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad469x_sequence_enable_temp(struct ad469x_dev *dev) +{ + int32_t ret; + + ret = ad469x_spi_write_mask(dev, + AD469x_REG_TEMP_CTRL, + AD469x_REG_TEMP_CTRL_TEMP_EN_MASK, + AD469x_REG_TEMP_CTRL_TEMP_EN(1)); + if (ret != SUCCESS) + return ret; + + dev->temp_enabled = true; + + return ret; +} + +/** + * @brief Disable temperature read at the end of the sequence, for standard and + * advanced sequencer + * @param [in] dev - ad469x_dev device handler. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad469x_sequence_disable_temp(struct ad469x_dev *dev) +{ + int32_t ret; + + ret = ad469x_spi_write_mask(dev, + AD469x_REG_TEMP_CTRL, + AD469x_REG_TEMP_CTRL_TEMP_EN_MASK, + AD469x_REG_TEMP_CTRL_TEMP_EN(0)); + if (ret != SUCCESS) + return ret; + + dev->temp_enabled = false; + + return ret; +} + +/** + * @brief Configure converter busy indicator to the output of the specified port + * @param [in] dev - ad469x_dev device handler. + * @param [in] gp_sel - Port. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad469x_set_busy(struct ad469x_dev *dev, + enum ad469x_busy_gp_sel gp_sel) +{ + int32_t ret; + + ret = ad469x_spi_write_mask(dev, + AD469x_REG_GP_MODE, + AD469x_GP_MODE_BUSY_GP_EN_MASK, + AD469x_GP_MODE_BUSY_GP_EN(1)); + if (ret != SUCCESS) + return ret; + + + ret = ad469x_spi_write_mask(dev, + AD469x_REG_GP_MODE, + AD469x_GP_MODE_BUSY_GP_SEL_MASK, + AD469x_GP_MODE_BUSY_GP_SEL(gp_sel)); + if (ret != SUCCESS) + return ret; + + + return ret; +} + +/** + * @brief Enter conversion mode. + * To exit conversion mode send a 5 bit conversion mode command + * AD469x_CMD_REG_CONFIG_MODE + * @param [in] dev - ad469x_dev device handler. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad469x_enter_conversion_mode(struct ad469x_dev *dev) +{ + return ad469x_spi_write_mask(dev, + AD469x_REG_SETUP, + AD469x_SETUP_IF_MODE_MASK, + AD469x_SETUP_IF_MODE_CONV); +} + +/** + * @brief Exit conversion mode. + * Enter register mode to read/write registers + * @param [in] dev - ad469x_dev device handler. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad469x_exit_conversion_mode(struct ad469x_dev *dev) +{ + int32_t ret ; + +#if defined(ENABLE_SPI_ENGINE) + uint32_t commands_data[1], buf; + struct spi_engine_offload_message msg; + uint32_t spi_eng_msg_cmds[3] = { + CS_LOW, + WRITE_READ(1), + CS_HIGH + }; + + pwm_enable(dev->trigger_pwm_desc); + + commands_data[0] = AD469x_CMD_REG_CONFIG_MODE << 8; + + ret = spi_engine_offload_init(dev->spi_desc, dev->offload_init_param); + if (ret != SUCCESS) + return ret; + + msg.commands = spi_eng_msg_cmds; + msg.no_commands = ARRAY_SIZE(spi_eng_msg_cmds); + msg.rx_addr = (uint32_t)&buf; + msg.commands_data = commands_data; + + ret = spi_engine_offload_transfer(dev->spi_desc, msg, 1); + if (ret != SUCCESS) + return ret; + + pwm_disable(dev->trigger_pwm_desc); + if (ret != SUCCESS) + return ret; +#else + uint8_t cmd = AD469x_CMD_REG_CONFIG_MODE; + + ret = spi_write_and_read(dev->spi_desc, &cmd, 1); + if (ret != SUCCESS) + return ret; +#endif + + return SUCCESS; +} + +/** + * @brief Advanced sequencer, get util data bits in a sample + * @param [in] dev - ad469x_dev device handler. + * @param [in] cur_sample - Current sample number + * @param [in] sample - Sample data + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +static int32_t ad469x_adv_seq_osr_get_util_data(struct ad469x_dev *dev, + uint16_t cur_sample, + uint32_t *sample) +{ + uint8_t cur_slot, cur_ch; + + cur_slot = cur_sample % (dev->num_slots + dev->temp_enabled); + cur_ch = dev->ch_slots[cur_slot]; + + /* Temperature channel sample */ + if (dev->temp_enabled && cur_slot == dev->num_slots) + return SUCCESS; + + *sample = (*sample) >> (dev->capture_data_width - + dev->adv_seq_osr_resol[cur_ch]); + + return SUCCESS; +} + +/** + * @brief Read from device when converter has the channel sequencer activated. + * Enter register mode to read/write registers + * @param [in] dev - ad469x_dev device handler. + * @param [out] buf - data buffer. + * @param [in] samples - Number of samples per channel. For example, if with + * ad469x_std_sequence_ch 2 channel where activated, buf will be filled with + * 10 samples for each of them. If temp is enable, the there will be an other 10 + * samples for temperature + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad469x_seq_read_data(struct ad469x_dev *dev, + uint32_t *buf, + uint16_t samples) +{ + int32_t ret; + uint16_t i; + uint32_t total_samples; + + total_samples = samples * (dev->num_slots + dev->temp_enabled); + ret = ad469x_read_data(dev, 0, buf, total_samples); + if (ret != SUCCESS) + return ret; + + if (dev->ch_sequence != AD469x_advanced_seq) + return SUCCESS; + + for (i = 0; i < total_samples; i++) { + ret = ad469x_adv_seq_osr_get_util_data(dev, i, &buf[i]); + if (ret != SUCCESS) + return ret; + } + + return SUCCESS; +} + +/** + * @brief Read from device. + * Enter register mode to read/write registers + * @param [in] dev - ad469x_dev device handler. + * @param [in] channel - ad469x selected channel. + * @param [out] buf - data buffer. + * @param [in] samples - sample number. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad469x_read_data(struct ad469x_dev *dev, + uint8_t channel, + uint32_t *buf, + uint16_t samples) +{ + int32_t ret; + +#if defined(ENABLE_SPI_ENGINE) + uint32_t commands_data[1]; + struct spi_engine_offload_message msg; + uint32_t spi_eng_msg_cmds[3] = { + CS_LOW, + WRITE_READ(1), + CS_HIGH + }; + if (channel < AD469x_CHANNEL_NO) + commands_data[0] = AD469x_CMD_CONFIG_CH_SEL(channel) << 8; + else if (channel == AD469x_CHANNEL_TEMP) + commands_data[0] = AD469x_CMD_SEL_TEMP_SNSOR_CH << 8; + else + return FAILURE; + + pwm_enable(dev->trigger_pwm_desc); + + ret = spi_engine_offload_init(dev->spi_desc, dev->offload_init_param); + if (ret != SUCCESS) + return ret; + + msg.commands = spi_eng_msg_cmds; + msg.no_commands = ARRAY_SIZE(spi_eng_msg_cmds); + msg.rx_addr = (uint32_t)buf; + msg.commands_data = commands_data; + + ret = spi_engine_offload_transfer(dev->spi_desc, msg, samples * 2); + if (ret != SUCCESS) + return ret; + + if (dev->dcache_invalidate_range) + dev->dcache_invalidate_range(msg.rx_addr, samples * 4); +#else + // Dummy Data + dev->data[0] = 0x0; + dev->data[1] = 0x0; + ret = spi_write_and_read(dev->spi_desc, dev->data, (samples * 2)); + if (ret != SUCCESS) + return FAILURE; + + *buf = (uint16_t)(dev->data[0] << 8) | dev->data[1]; + +#endif + + return ret; +} + +/** + * Initialize the device. + * @param [out] device - The device structure. + * @param [in] init_param - The structure that contains the device initial + * parameters. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad469x_init(struct ad469x_dev **device, + struct ad469x_init_param *init_param) +{ + struct ad469x_dev *dev; + int32_t ret; + uint8_t data = 0; + + dev = (struct ad469x_dev *)malloc(sizeof(*dev)); + if (!dev) + return FAILURE; + +#if defined(SPI_ENGINE) + ret = axi_clkgen_init(&dev->clkgen, init_param->clkgen_init); + if (ret != SUCCESS) { + printf("error: %s: axi_clkgen_init() failed\n", + init_param->clkgen_init->name); + goto error_dev; + } + + ret = axi_clkgen_set_rate(dev->clkgen, init_param->axi_clkgen_rate); + if (ret != SUCCESS) { + printf("error: %s: axi_clkgen_set_rate() failed\n", + init_param->clkgen_init->name); + goto error_clkgen; + } + +#endif + + ret = ad469x_init_gpio(dev, init_param); + if (ret != SUCCESS) + goto error_gpio; + + ret = spi_init(&dev->spi_desc, init_param->spi_init); + if (ret != SUCCESS) + goto error_gpio; + + dev->offload_init_param = init_param->offload_init_param; + + dev->reg_access_speed = init_param->reg_access_speed; + dev->reg_data_width = init_param->reg_data_width; + dev->capture_data_width = init_param->capture_data_width; + dev->dev_id = init_param->dev_id; + dev->dcache_invalidate_range = init_param->dcache_invalidate_range; + dev->ch_sequence = AD469x_standard_seq; + dev->num_slots = 0; + dev->temp_enabled = false; + memset(dev->ch_slots, 0, sizeof(dev->ch_slots)); + + ret = ad469x_spi_reg_write(dev, AD469x_REG_SCRATCH_PAD, AD469x_TEST_DATA); + if (ret != SUCCESS) + goto error_spi; + + ret = ad469x_spi_reg_read(dev, AD469x_REG_SCRATCH_PAD, &data); + if (ret != SUCCESS) + goto error_spi; + + if (data != AD469x_TEST_DATA) + goto error_spi; + + ret = ad469x_set_reg_access_mode(dev, AD469x_BYTE_ACCESS); + if (ret != SUCCESS) + goto error_spi; + + ret = ad469x_set_busy(dev, AD469x_busy_gp0); + if (ret != SUCCESS) + goto error_spi; + + ret = ad469x_seq_osr_clear(dev); + if (ret != SUCCESS) + goto error_spi; + +#if defined(SPI_ENGINE) + ret = pwm_init(&dev->trigger_pwm_desc, init_param->trigger_pwm_init); + if (ret != SUCCESS) + goto error_spi; +#endif + + + *device = dev; + + return ret; + +error_spi: + spi_remove(dev->spi_desc); +error_gpio: + gpio_remove(dev->gpio_resetn); + +#if defined(SPI_ENGINE) +error_clkgen: + axi_clkgen_remove(dev->clkgen); +error_dev: +#endif + + free(dev); + + return FAILURE; + +} + +/** + * @brief Free the memory allocated by ad469x_init(). + * @param [in] dev - Pointer to the device handler. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise + */ +int32_t ad469x_remove(struct ad469x_dev *dev) +{ + int32_t ret; + + if (!dev) + return FAILURE; + + ret = spi_remove(dev->spi_desc); + if (ret != SUCCESS) + return ret; + + ret = gpio_remove(dev->gpio_resetn); + if (ret != SUCCESS) + return ret; + + ret = gpio_remove(dev->gpio_convst); + if (ret != SUCCESS) + return ret; + + ret = gpio_remove(dev->gpio_busy); + if (ret != SUCCESS) + return ret; + +#if defined(SPI_ENGINE) + ret = pwm_remove(dev->trigger_pwm_desc); + if (ret != SUCCESS) + return ret; + + ret = axi_clkgen_remove(dev->clkgen); + if (ret != SUCCESS) + return ret; +#endif + + free(dev); + + return ret; +} \ No newline at end of file