Forked repository for pushing changes to EVAL-AD4696
Dependencies: platform_drivers
app/ad469x.c
- Committer:
- pmallick
- Date:
- 2021-09-30
- Revision:
- 1:8792acb5a039
File content as of revision 1:8792acb5a039:
/***************************************************************************//** * @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; }