Pratyush Mallick
/
testing
this is testing
app/noos_mbed/drivers/adc/ad713x/ad713x.c
- Committer:
- pmallick
- Date:
- 2021-01-14
- Revision:
- 0:3afcd581558d
File content as of revision 0:3afcd581558d:
/***************************************************************************//** * @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; }