Pratyush Mallick
/
nano_dac
this is testing
Diff: noos_mbed/drivers/adc/ad713x/ad713x.c
- Revision:
- 0:e8a1ba50c46b
diff -r 000000000000 -r e8a1ba50c46b noos_mbed/drivers/adc/ad713x/ad713x.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/noos_mbed/drivers/adc/ad713x/ad713x.c Thu Jan 14 19:12:57 2021 +0530 @@ -0,0 +1,603 @@ +/***************************************************************************//** + * @file ad713x.c + * @brief Implementation of ad713x Driver. + * @author SPopa (stefan.popa@analog.com) + * @author Andrei Drimbarean (andrei.drimbarean@analog.com) +******************************************************************************** + * Copyright 2020(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 <stdlib.h> +#include "ad713x.h" + +/******************************************************************************/ +/***************************** Variable definition ****************************/ +/******************************************************************************/ + +static const int ad713x_output_data_frame[3][9][2] = { + { + {ADC_16_BIT_DATA, CRC_6}, + {ADC_24_BIT_DATA, CRC_6}, + {ADC_32_BIT_DATA, NO_CRC}, + {ADC_32_BIT_DATA, CRC_6}, + {ADC_16_BIT_DATA, NO_CRC}, + {ADC_24_BIT_DATA, NO_CRC}, + {ADC_24_BIT_DATA, CRC_8}, + {ADC_32_BIT_DATA, CRC_8}, + {INVALID} + }, + { + {ADC_16_BIT_DATA, NO_CRC}, + {ADC_16_BIT_DATA, CRC_6}, + {ADC_24_BIT_DATA, NO_CRC}, + {ADC_24_BIT_DATA, CRC_6}, + {ADC_16_BIT_DATA, CRC_8}, + {ADC_24_BIT_DATA, CRC_8}, + {INVALID} + }, + { + {ADC_16_BIT_DATA, NO_CRC}, + {ADC_16_BIT_DATA, CRC_6}, + {ADC_16_BIT_DATA, CRC_8}, + {INVALID} + }, +}; + +/******************************************************************************/ +/************************** Functions Implementation **************************/ +/******************************************************************************/ + +/** + * @brief Read from device. + * @param dev - The device structure. + * @param reg_addr - The register address. + * @param reg_data - The register data. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad713x_spi_reg_read(struct ad713x_dev *dev, + uint8_t reg_addr, + uint8_t *reg_data) +{ + int32_t ret; + uint8_t buf[2]; + + buf[0] = AD713X_REG_READ(reg_addr); + buf[1] = 0x00; + + ret = spi_write_and_read(dev->spi_desc, buf, 2); + if(IS_ERR_VALUE(ret)) + return FAILURE; + *reg_data = buf[1]; + + return SUCCESS; +} + +/** + * @brief Write to device. + * @param dev - The device structure. + * @param reg_addr - The register address. + * @param reg_data - The register data. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad713x_spi_reg_write(struct ad713x_dev *dev, + uint8_t reg_addr, + uint8_t reg_data) +{ + uint8_t buf[2]; + + buf[0] = reg_addr; + buf[1] = reg_data; + + return spi_write_and_read(dev->spi_desc, buf, 2); +} + +/** + * @brief 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 \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad713x_spi_write_mask(struct ad713x_dev *dev, + uint8_t reg_addr, + uint32_t mask, + uint8_t data) +{ + uint8_t reg_data; + int32_t ret; + + ret = ad713x_spi_reg_read(dev, reg_addr, ®_data); + if(IS_ERR_VALUE(ret)) + return FAILURE; + reg_data &= ~mask; + reg_data |= data; + + return ad713x_spi_reg_write(dev, reg_addr, reg_data); +} + +/** + * @brief Device power mode control. + * @param dev - The device structure. + * @param mode - Type of power mode + * Accepted values: LOW_POWER + * HIGH_POWER + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad713x_set_power_mode(struct ad713x_dev *dev, + enum ad713x_power_mode mode) +{ + if (mode == LOW_POWER) + return ad713x_spi_write_mask(dev, AD713X_REG_DEVICE_CONFIG, + AD713X_DEV_CONFIG_PWR_MODE_MSK, 0); + else if (mode == HIGH_POWER) + return ad713x_spi_write_mask(dev, AD713X_REG_DEVICE_CONFIG, + AD713X_DEV_CONFIG_PWR_MODE_MSK, + 1); + + return FAILURE; +} + +/** + * @brief ADC conversion data output frame control. + * @param dev - The device structure. + * @param adc_data_len - Data conversion length + * Accepted values: ADC_16_BIT_DATA + * ADC_24_BIT_DATA + * ADC_32_BIT_DATA + * @param crc_header - CRC header + * Accepted values: NO_CRC + * CRC_6 + * CRC_8 + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad713x_set_out_data_frame(struct ad713x_dev *dev, + enum ad713x_adc_data_len adc_data_len, + enum ad713x_crc_header crc_header) +{ + uint8_t id; + uint8_t i = 0; + + id = dev->dev_id; + + while (ad713x_output_data_frame[id][i][0] != INVALID) { + if((adc_data_len == ad713x_output_data_frame[id][i][0]) && + (crc_header == ad713x_output_data_frame[id][i][1])) { + return ad713x_spi_write_mask(dev, + AD713X_REG_DATA_PACKET_CONFIG, + AD713X_DATA_PACKET_CONFIG_FRAME_MSK, + AD713X_DATA_PACKET_CONFIG_FRAME_MODE(i)); + } + i++; + } + + return FAILURE; +} + +/** + * @brief DOUTx output format configuration. + * @param dev - The device structure. + * @param format - Single channel daisy chain mode. Dual channel daisy chain mode. + * Quad channel parallel output mode. Channel data averaging mode. + * Accepted values: SINGLE_CH_DC + * DUAL_CH_DC + * QUAD_CH_PO + * CH_AVG_MODE + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad713x_dout_format_config(struct ad713x_dev *dev, + enum ad713x_doutx_format format) +{ + return ad713x_spi_write_mask(dev, AD713X_REG_DIGITAL_INTERFACE_CONFIG, + AD713X_DIG_INT_CONFIG_FORMAT_MSK, + AD713X_DIG_INT_CONFIG_FORMAT_MODE(format)); +} + +/** + * @brief Magnitude and phase matching calibration clock delay enable for all + * channels at 2 clock delay. + * This function is kept for backwards compatibility with the current + * application source, but it is deprecated. Use + * ad713x_mag_phase_clk_delay_chan(). + * @param dev - The device structure. + * @param clk_delay_en - Enable or disable Mag/Phase clock delay. + * Accepted values: true + * false + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad713x_mag_phase_clk_delay(struct ad713x_dev *dev, + bool clk_delay_en) +{ + int32_t ret; + int8_t i; + int8_t temp_clk_delay; + + if (clk_delay_en) + temp_clk_delay = DELAY_2_CLOCKS; + else + temp_clk_delay = DELAY_NONE; + + for (i = CH3; i >= 0; i--) { + ret = ad713x_spi_write_mask(dev, AD713X_REG_MPC_CONFIG, + AD713X_MPC_CLKDEL_EN_CH_MSK(i), + AD713X_MPC_CLKDEL_EN_CH_MODE(temp_clk_delay, i)); + if (IS_ERR_VALUE(ret)) + return FAILURE; + } + + return SUCCESS; +} + +/** + * @brief Change magnitude and phase calibration clock delay mode for a specific + * channel. + * @param dev - The device structure. + * @param chan - ID of the channel to be changed. + * Accepted values: CH0, CH1, CH2, CH3 + * @param mode - Delay in clock periods. + * Accepted values: DELAY_NONE, + * DELAY_1_CLOCKS, + * DELAY_2_CLOCKS + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad713x_mag_phase_clk_delay_chan(struct ad713x_dev *dev, + enum ad713x_channels chan, + enum ad717x_mpc_clkdel mode) +{ + return ad713x_spi_write_mask(dev, AD713X_REG_MPC_CONFIG, + AD713X_MPC_CLKDEL_EN_CH_MSK(chan), + AD713X_MPC_CLKDEL_EN_CH_MODE(mode, chan)); +} + +/** + * @brief Digital filter type selection for each channel + * @param dev - The device structure. + * @param filter - Type of filter: Wideband, Sinc6, Sinc3, + * Sinc3 filter with simultaneous 50Hz and 60Hz rejection. + * Accepted values: FIR + * SINC6 + * SINC3 + * SINC3_50_60_REJ + * @param ch - Channel to apply the filter to + * Accepted values: CH0 + * CH1 + * CH2 + * CH3 + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad713x_dig_filter_sel_ch(struct ad713x_dev *dev, + enum ad713x_dig_filter_sel filter, + enum ad713x_channels ch) +{ + return ad713x_spi_write_mask(dev, AD713X_REG_CHAN_DIG_FILTER_SEL, + AD713X_DIGFILTER_SEL_CH_MSK(ch), + AD713X_DIGFILTER_SEL_CH_MODE(filter, ch)); +} + +/** + * @brief Enable/Disable CLKOUT output. + * @param [in] dev - The device structure. + * @param [in] enable - true to enable the clkout output; + * false to disable the clkout output. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad713x_clkout_output_en(struct ad713x_dev *dev, bool enable) +{ + return ad713x_spi_write_mask(dev, AD713X_REG_DEVICE_CONFIG1, + AD713X_DEV_CONFIG1_CLKOUT_EN_MSK, + enable ? AD713X_DEV_CONFIG1_CLKOUT_EN_MSK : 0); +} + +/** + * @brief Enable/Disable reference gain correction. + * @param [in] dev - The device structure. + * @param [in] enable - true to enable the reference gain correction; + * false to disable the reference gain correction. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad713x_ref_gain_correction_en(struct ad713x_dev *dev, bool enable) +{ + return ad713x_spi_write_mask(dev, AD713X_REG_DEVICE_CONFIG1, + AD713X_DEV_CONFIG1_REF_GAIN_CORR_EN_MSK, + enable ? AD713X_DEV_CONFIG1_REF_GAIN_CORR_EN_MSK : 0); +} + +/** + * @brief Select the wideband filter bandwidth for a channel. + * The option is relative to ODR, so it's a fraction of it. + * @param [in] dev - The device structure. + * @param [in] ch - Number of the channel to which to set the wideband filter + * option. + * @param [in] wb_opt - Option to set the wideband filter: + * Values are: + * 0 - bandwidth of 0.443 * ODR; + * 1 - bandwidth of 0.10825 * ODR. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad713x_wideband_bw_sel(struct ad713x_dev *dev, + enum ad713x_channels ch, uint8_t wb_opt) +{ + return ad713x_spi_write_mask(dev, AD713X_REG_FIR_BW_SEL, + AD713X_FIR_BW_SEL_CH_MSK(ch), + wb_opt ? AD713X_FIR_BW_SEL_CH_MSK(ch) : 0); +} + +/** + * @brief Initialize GPIO driver handlers for the GPIOs in the system. + * ad713x_init() helper function. + * @param [out] dev - AD713X device handler. + * @param [in] init_param - Pointer to the initialization structure. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +static int32_t ad713x_init_gpio(struct ad713x_dev *dev, + struct ad713x_init_param *init_param) +{ + + int32_t ret; + + ret = gpio_get_optional(&dev->gpio_mode, init_param->gpio_mode); + if (IS_ERR_VALUE(ret)) + return FAILURE; + + ret = gpio_get_optional(&dev->gpio_dclkmode, init_param->gpio_dclkmode); + if (IS_ERR_VALUE(ret)) + return FAILURE; + + ret = gpio_get_optional(&dev->gpio_dclkio, init_param->gpio_dclkio); + if (IS_ERR_VALUE(ret)) + return FAILURE; + + ret = gpio_get_optional(&dev->gpio_resetn, init_param->gpio_resetn); + if (IS_ERR_VALUE(ret)) + return FAILURE; + + ret = gpio_get_optional(&dev->gpio_pnd, init_param->gpio_pnd); + if (IS_ERR_VALUE(ret)) + return FAILURE; + + /** Tie this pin to IOVDD for master mode operation, tie this pin to + * IOGND for slave mode operation. */ + if (init_param->gpio_mode) { + ret = gpio_direction_output(dev->gpio_mode, + init_param->mode_master_nslave); + if (IS_ERR_VALUE(ret)) + return FAILURE; + } + + /* Tie this pin low to ground to make DLCK operating in gated mode */ + if (init_param->gpio_dclkmode) { + ret = gpio_direction_output(dev->gpio_dclkmode, + init_param->dclkmode_free_ngated); + if (IS_ERR_VALUE(ret)) + return FAILURE; + } + + /** Tie this pin high to make DCLK an output, tie this pin low to make + * DLCK an input. */ + if (init_param->gpio_dclkio) { + ret = gpio_direction_output(dev->gpio_dclkio, + init_param->dclkio_out_nin); + if (IS_ERR_VALUE(ret)) + return FAILURE; + } + + /** Get the ADCs out of power down state */ + if (init_param->gpio_pnd) { + ret = gpio_direction_output(dev->gpio_pnd, init_param->pnd); + if (IS_ERR_VALUE(ret)) + return FAILURE; + } + + /** Reset to configure pins */ + if (init_param->gpio_resetn) { + ret = gpio_direction_output(dev->gpio_resetn, false); + if (IS_ERR_VALUE(ret)) + return FAILURE; + mdelay(100); + ret = gpio_set_value(dev->gpio_resetn, true); + if (IS_ERR_VALUE(ret)) + return FAILURE; + mdelay(100); + } + + return SUCCESS; +} + +/** + * @brief Free the resources allocated by ad713x_init_gpio(). + * @param dev - The device structure. + * @return SUCCESS in case of success, negative error code otherwise. + */ +static int32_t ad713x_remove_gpio(struct ad713x_dev *dev) +{ + int32_t ret; + + if (dev->gpio_dclkio) { + ret = gpio_remove(dev->gpio_dclkio); + if(IS_ERR_VALUE(ret)) + return FAILURE; + } + if (dev->gpio_dclkio) { + ret = gpio_remove(dev->gpio_dclkmode); + if(IS_ERR_VALUE(ret)) + return FAILURE; + } + if (dev->gpio_mode) { + ret = gpio_remove(dev->gpio_mode); + if(IS_ERR_VALUE(ret)) + return FAILURE; + } + if (dev->gpio_pnd) { + ret = gpio_remove(dev->gpio_pnd); + if(IS_ERR_VALUE(ret)) + return FAILURE; + } + if (dev->gpio_resetn) { + ret = gpio_remove(dev->gpio_resetn); + if(IS_ERR_VALUE(ret)) + return FAILURE; + } + + return SUCCESS; +} + +/** + * @brief Initialize the wideband filter bandwidth for every channel. + * ad713x_init() helper function. + * @param [in] dev - AD713X device handler. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +static int32_t ad713x_init_chan_bw(struct ad713x_dev *dev) +{ + int8_t i; + int32_t ret; + + for (i = CH3; i >= 0; i--) { + ret = ad713x_wideband_bw_sel(dev, i, 0); + if (IS_ERR_VALUE(ret)) + return FAILURE; + } + + return SUCCESS; +} + +/** + * @brief Initialize the device. + * @param device - The device structure. + * @param init_param - The structure that contains the device initial + * parameters. + * @return \ref SUCCESS in case of success, \ref FAILURE otherwise. + */ +int32_t ad713x_init(struct ad713x_dev **device, + struct ad713x_init_param *init_param) +{ + struct ad713x_dev *dev; + int32_t ret; + uint8_t data; + + dev = (struct ad713x_dev *)calloc(1, sizeof(*dev)); + if (!dev) + return FAILURE; + + if (!init_param->spi_common_dev) { + ret = spi_init(&dev->spi_desc, &init_param->spi_init_prm); + if (IS_ERR_VALUE(ret)) + goto error_dev; + } else { + dev->spi_desc = calloc(1, sizeof *dev->spi_desc); + dev->spi_desc->chip_select = init_param->spi_init_prm.chip_select; + dev->spi_desc->extra = init_param->spi_common_dev->extra; + dev->spi_desc->max_speed_hz = init_param->spi_init_prm.max_speed_hz; + dev->spi_desc->mode = init_param->spi_init_prm.mode; + } + + ret = ad713x_init_gpio(dev, init_param); + if(IS_ERR_VALUE(ret)) + goto error_gpio; + + dev->dev_id = init_param->dev_id; + + ret = ad713x_spi_reg_read(dev, AD713X_REG_DEVICE_CONFIG, &data); + if (IS_ERR_VALUE(ret)) + goto error_gpio; + data |= AD713X_DEV_CONFIG_PWR_MODE_MSK; + ret = ad713x_spi_reg_write(dev, AD713X_REG_DEVICE_CONFIG, data); + if (IS_ERR_VALUE(ret)) + goto error_gpio; + + ret = ad713x_clkout_output_en(dev, true); + if (IS_ERR_VALUE(ret)) + goto error_gpio; + + ret = ad713x_ref_gain_correction_en(dev, true); + if (IS_ERR_VALUE(ret)) + goto error_gpio; + + ret = ad713x_set_out_data_frame(dev, init_param->adc_data_len, + init_param->crc_header); + if (IS_ERR_VALUE(ret)) + goto error_gpio; + + ret = ad713x_dout_format_config(dev, init_param->format); + if (IS_ERR_VALUE(ret)) + goto error_gpio; + + ret = ad713x_mag_phase_clk_delay(dev, init_param->clk_delay_en); + if (IS_ERR_VALUE(ret)) + goto error_gpio; + + ret = ad713x_init_chan_bw(dev); + if (IS_ERR_VALUE(ret)) + goto error_gpio; + + *device = dev; + + return SUCCESS; + +error_gpio: + ad713x_remove_gpio(dev); +error_dev: + ad713x_remove(dev); + + return FAILURE; +} + +/** + * @brief Free the resources allocated by ad713x_init(). + * @param dev - The device structure. + * @return SUCCESS in case of success, negative error code otherwise. + */ +int32_t ad713x_remove(struct ad713x_dev *dev) +{ + int32_t ret; + + if(!dev) + return FAILURE; + + ret = spi_remove(dev->spi_desc); + if(IS_ERR_VALUE(ret)) + return FAILURE; + + ret = ad713x_remove_gpio(dev); + if(IS_ERR_VALUE(ret)) + return FAILURE; + + free(dev); + + return SUCCESS; +}