AD4130 Mbed IIO Firmware
Dependencies: tempsensors sdp_k1_sdram
app/ad413x.c
- Committer:
- MPhalke@MPHALKE-L02.ad.analog.com
- Date:
- 2022-07-15
- Revision:
- 2:871d585d96ee
File content as of revision 2:871d585d96ee:
/***************************************************************************//** * @file ad413x.c * @brief Implementation of AD413X Driver. * @author Andrei Porumb (andrei.porumb@analog.com) ******************************************************************************** * Copyright 2022(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 <stdio.h> #include <stdlib.h> #include "ad413x.h" #include "no_os_error.h" #include "no_os_irq.h" #include "no_os_print_log.h" #include "no_os_delay.h" #include "no_os_crc8.h" #include "no_os_spi.h" NO_OS_DECLARE_CRC8_TABLE(ad413x_crc8); uint32_t timeout = 0xFFFFFF; /******************************************************************************/ /************************** Functions Implementation **************************/ /******************************************************************************/ /***************************************************************************//** * IRQ handler for ADC read. *******************************************************************************/ static void irq_adc_read(struct ad413x_callback_ctx *ctx) { struct ad413x_dev *dev = ctx->dev; timeout = 0xFFFFFF; if(ctx->buffer_size > 0) { ad413x_reg_read(ctx->dev, AD413X_REG_DATA, ctx->buffer); ctx->buffer_size--; ctx->buffer++; no_os_irq_enable(dev->irq_desc, dev->rdy_pin); } else { no_os_irq_disable(dev->irq_desc, dev->rdy_pin); } } /***************************************************************************//** * SPI internal register write to device using a mask. * * @param dev - The device structure. * @param reg_addr - The register address. * @param data - The register data. * @param mask - The mask. * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_reg_write_msk(struct ad413x_dev *dev, uint32_t reg_addr, uint32_t data, uint32_t mask) { int32_t ret; uint32_t reg_data; ret = ad413x_reg_read(dev, reg_addr, ®_data); if (ret) return ret; reg_data &= ~mask; reg_data |= data; return ad413x_reg_write(dev, reg_addr, reg_data); } /***************************************************************************//** * Set the mode of the ADC. * * @param dev - The device structure. * @param mode - The ADC mode * Accepted values: AD4110_CONTINOUS_CONV_MODE * AD4110_SINGLE_CONV_MODE * AD4110_STANDBY_MODE * AD4110_PW_DOWN_MODE * AD4110_SYS_OFFSET_CAL * AD4110_SYS_GAIN_CAL * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_set_adc_mode(struct ad413x_dev *dev, enum ad413x_adc_mode mode) { int32_t ret; ret = ad413x_reg_write_msk(dev, AD413X_REG_ADC_CTRL, AD413X_ADC_MODE(mode), AD413X_ADC_MODE(0xF)); if (ret) return ret; dev->op_mode = mode; return 0; } /***************************************************************************//** * Set the internal reference. * * @param dev - The device structure. * @param int_ref - The internal reference option. * Accepted values: AD413X_INTREF_DISABLED * AD413X_INTREF_2_5V, * AD413X_INTREF_1_25V * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_set_int_ref(struct ad413x_dev *dev, enum ad413x_int_ref int_ref) { int32_t ret; switch (int_ref) { case AD413X_INTREF_DISABLED: ret = ad413x_reg_write_msk(dev, AD413X_REG_ADC_CTRL, 0U, AD413X_ADC_REF_EN); break; case AD413X_INTREF_2_5V: ret = ad413x_reg_write_msk(dev, AD413X_REG_ADC_CTRL, AD413X_ADC_REF_EN, AD413X_ADC_REF_EN); if (ret) return ret; ret = ad413x_reg_write_msk(dev, AD413X_REG_ADC_CTRL, 0U, AD413X_ADC_REF_VAL); break; case AD413X_INTREF_1_25V: ret = ad413x_reg_write_msk(dev, AD413X_REG_ADC_CTRL, AD413X_ADC_REF_EN, AD413X_ADC_REF_EN); if (ret) return ret; ret = ad413x_reg_write_msk(dev, AD413X_REG_ADC_CTRL, AD413X_ADC_REF_VAL, AD413X_ADC_REF_VAL); break; default: return -EINVAL; } if (ret) return ret; dev->int_ref = int_ref; return 0; } /***************************************************************************//** * Enable/disable DATA_STAT field. * * @param dev - The device structure. * @param enable - 0 DISABLE * 1 ENABLE * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_data_stat_en(struct ad413x_dev *dev, uint8_t enable) { int32_t ret; ret = ad413x_reg_write_msk(dev, AD413X_REG_ADC_CTRL, enable ? AD413X_ADC_DATA_STATUS : 0x0U, AD413X_ADC_DATA_STATUS); if (ret) return ret; dev->data_stat = enable; return 0; } /***************************************************************************//** * Set the gain from configuration register. * * @param dev - The device structure. * @param gain - The gain value. * Accepted values: AD413X_GAIN_1 * AD413X_GAIN_2 * AD413X_GAIN_4 * AD413X_GAIN_8 * AD413X_GAIN_16 * AD413X_GAIN_32 * AD413X_GAIN_64 * AD413X_GAIN_128 * @param reg_nb - Number of Configuration Register * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_set_gain(struct ad413x_dev *dev, enum ad413x_gain gain, enum ad413x_preset_nb reg_nb) { int32_t ret; ret = ad413x_reg_write_msk(dev, AD413X_REG_CONFIG(reg_nb), AD413X_PGA_N(gain), AD413X_PGA_N(0xF)); if (ret) return ret; dev->preset[reg_nb].gain = gain; return 0; } /***************************************************************************//** * Select reference from configuration register. * * @param dev - The device structure. * @param ref - The reference value. * Accepted values: AD413X_REFIN1 * AD413X_REFIN2 * AD413X_REFOUT_AVSS * AD413X_AVDD_AVSS * @param reg_nb - Number of Configuration Register * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_set_ref(struct ad413x_dev *dev, enum ad413x_ref_sel ref, enum ad413x_preset_nb reg_nb) { int32_t ret; ret = ad413x_reg_write_msk(dev, AD413X_REG_CONFIG(reg_nb), AD413X_REF_SEL_N(ref), AD413X_REF_SEL_N(0xF)); if (ret) return ret; dev->preset[reg_nb].ref_sel = ref; return 0; } /***************************************************************************//** * Select the reference buffers. * * @param dev - The device structure. * @param ref_buf - The reference buffer status. * @param reg_nb - Number of Configuration Register * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_set_ref_buf(struct ad413x_dev *dev, struct ad413x_ref_buf ref_buf, enum ad413x_preset_nb reg_nb) { int32_t ret; uint32_t reg_val; reg_val = no_os_field_prep(AD413X_REF_BUFP_N, ref_buf.ref_buf_p_en); reg_val |= no_os_field_prep(AD413X_REF_BUFM_N, ref_buf.ref_buf_m_en); ret = ad413x_reg_write_msk(dev, AD413X_REG_CONFIG(reg_nb), reg_val, AD413X_REF_BUF_MSK); if (ret) return ret; dev->preset[reg_nb].ref_buf = ref_buf; return 0; } /***************************************************************************//** * Select filter from filter register. * * @param dev - The device structure. * @param filter - The filter type. * Accepted values: AD413X_SYNC4_STANDALONE * AD413X_SYNC4_SYNC1 * AD413X_SYNC3_STANDALONE * AD413X_SYNC3_REJ60 * AD413X_SYNC3_SYNC1 * AD413X_SYNC3_PF1 * AD413X_SYNC3_PF2 * AD413X_SYNC3_PF3 * AD413X_SYNC3_PF4 * @param reg_nb - Number of Configuration Register * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_set_filter(struct ad413x_dev *dev, enum ad413x_filter filter, enum ad413x_preset_nb reg_nb) { int32_t ret; ret = ad413x_reg_write_msk(dev, AD413X_REG_FILTER(reg_nb), AD413X_FILTER_MODE_N(filter), AD413X_FILTER_MODE_N(0xF)); if (ret) return ret; dev->preset[reg_nb].filter = filter; return 0; } /***************************************************************************//** * Select settle time from filter register. * * @param dev - The device structure. * @param s_time - The settle time value. * Accepted values: AD413X_32_MCLK * AD413X_64_MCLK * AD413X_128_MCLK * AD413X_256_MCLK * AD413X_512_MCLK * AD413X_1024_MCLK * AD413X_2048_MCLK * AD413X_4096_MCLK * @param reg_nb - Number of Configuration Register * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_set_settle_time(struct ad413x_dev *dev, enum ad413x_settle_time s_time, enum ad413x_preset_nb reg_nb) { int32_t ret; ret = ad413x_reg_write_msk(dev, AD413X_REG_FILTER(reg_nb), AD413X_SETTLE_N(s_time), AD413X_SETTLE_N(0xFF)); if (ret) return ret; dev->preset[reg_nb].s_time = s_time; return 0; } /***************************************************************************//** * Select excitation current value from config register. * * @param dev - The device structure. * @param iout0_exc - The Iout0 excitation current value. * @param iout1_exc - The Iout1 excitation current value. * Accepted values: AD413X_EXC_OFF * AD413X_EXC_10UA * AD413X_EXC_20UA * AD413X_EXC_50UA * AD413X_EXC_100UA * AD413X_EXC_150UA * AD413X_EXC_200UA * AD413X_EXC_100NA * @param reg_nb - Number of Configuration Register * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_set_exc_current(struct ad413x_dev *dev, enum ad413x_exc_current iout0_exc, enum ad413x_exc_current iout1_exc, enum ad413x_preset_nb reg_nb) { int32_t ret; ret = ad413x_reg_write_msk(dev, AD413X_REG_CONFIG(reg_nb), AD413X_I_OUT0_N(iout0_exc) | AD413X_I_OUT1_N(iout1_exc), AD413X_I_OUT_MSK); if (ret) return ret; dev->preset[reg_nb].iout0_exc_current = iout0_exc; dev->preset[reg_nb].iout1_exc_current = iout1_exc; return 0; } /***************************************************************************//** * Select preset for adc channel. * * @param dev - The device structure. * @param ch_nb - The channel number. * @param preset_nb - The preset number. * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_set_ch_preset(struct ad413x_dev *dev, uint8_t ch_nb, enum ad413x_preset_nb preset_nb) { int32_t ret; ret = ad413x_reg_write_msk(dev, AD413X_REG_CHN(ch_nb), AD413X_SETUP_M(preset_nb), AD413X_SETUP_M(0xF)); if (ret) return ret; dev->ch[ch_nb].preset = preset_nb; return 0; } /***************************************************************************//** * Select the excitation source pins. * * @param dev - The device structure. * @param ch_nb - The channel number. * @param iout0_exc_inp - IOUT0 excitation input pin. * @param iout1_exc_inp - IOUT1 excitation input pin. * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_ch_exc_input(struct ad413x_dev *dev, uint8_t ch_nb, enum ad413x_input iout0_exc_inp, enum ad413x_input iout1_exc_inp) { int32_t ret; ret = ad413x_reg_write_msk(dev, AD413X_REG_CHN(ch_nb), AD413X_I_OUT0_CH_M(iout0_exc_inp) | AD413X_I_OUT1_CH_M(iout1_exc_inp), AD413X_I_OUT_CH_MSK); if (ret) return ret; dev->ch[ch_nb].iout0_exc_input = iout0_exc_inp; dev->ch[ch_nb].iout1_exc_input = iout1_exc_inp; return 0; } /***************************************************************************//** * Enable/disable channel. * * @param dev - The device structure. * @param ch_nb - The channel number. * @param enable - Channel status. * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_ch_en(struct ad413x_dev *dev, uint8_t ch_nb, uint8_t enable) { int32_t ret; ret = ad413x_reg_write_msk(dev, AD413X_REG_CHN(ch_nb), enable ? AD413X_ENABLE_M : 0x0U, AD413X_ENABLE_M); if (ret) return ret; dev->ch[ch_nb].enable = enable; return 0; } /***************************************************************************//** * Enable/disable Power-Down Switch (PDSW). * * @param dev - The device structure. * @param ch_nb - The channel number. * @param pdsw_en - PDSW status. * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_pdsw_en(struct ad413x_dev *dev, uint8_t ch_nb, bool pdsw_en) { int32_t ret; ret = ad413x_reg_write_msk(dev, AD413X_REG_CHN(ch_nb), pdsw_en ? AD413X_PDSW_M : 0x0U, AD413X_PDSW_M); if (ret) return ret; dev->ch[ch_nb].pdsw_en = pdsw_en; return 0; } /***************************************************************************//** * Enable/disable bipolar data coding. * * @param dev - The device structure. * @param enable - 1 - Bipolar * 0 - Unipolar * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_adc_bipolar(struct ad413x_dev *dev, uint8_t enable) { int32_t ret; ret = ad413x_reg_write_msk(dev, AD413X_REG_ADC_CTRL, enable ? AD413X_ADC_BIPOLAR : 0x0U, AD413X_ADC_BIPOLAR); if (ret) return ret; dev->bipolar = enable; return 0; } /***************************************************************************//** * Set output VBIAS on analog inputs. * * @param dev - The device structure. * @param v_bias_val - V_BIAS control register value * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_set_v_bias(struct ad413x_dev *dev, uint16_t v_bias_val) { int32_t ret; ret = ad413x_reg_write(dev, AD413X_REG_VBIAS_CTRL, v_bias_val); if (ret) return ret; dev->v_bias = v_bias_val; return 0; } /***************************************************************************//** * Set standby control flags. * * @param dev - The device structure. * @param standby_ctrl - Standby control value * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_set_standby_ctrl(struct ad413x_dev *dev, struct ad413x_standby_ctrl standby_ctrl) { int32_t ret; uint32_t reg_val; reg_val = no_os_field_prep(AD413X_STBY_INTREF_EN, standby_ctrl.standby_int_ref_en); reg_val |= no_os_field_prep(AD413X_STBY_REFHOL_EN, standby_ctrl.standby_ref_holder_en); reg_val |= no_os_field_prep(AD413X_STBY_IEXC_EN, standby_ctrl.standby_iexc_en); reg_val |= no_os_field_prep(AD413X_STBY_VBIAS_EN, standby_ctrl.standby_vbias_en); reg_val |= no_os_field_prep(AD413X_STBY_BURNOUT_EN, standby_ctrl.standby_burnout_en); reg_val |= no_os_field_prep(AD413X_STBY_PDSW_EN, standby_ctrl.standby_pdsw_en); reg_val |= no_os_field_prep(AD413X_STBY_GPO_EN, standby_ctrl.standby_gpio_en); reg_val |= no_os_field_prep(AD413X_STBY_DIAGNOSTICS_EN, standby_ctrl.standby_diagn_en); reg_val |= no_os_field_prep(AD413X_STBY_OUT_EN, standby_ctrl.standby_output_en); ret = ad413x_reg_write_msk(dev, AD413X_REG_MISC, reg_val, AD413X_STBY_CTRL_MSK); if (ret) return ret; dev->standby_ctrl = standby_ctrl; return 0; } /***************************************************************************//** * Set ADC master clock mode. * * @param dev - The device structure. * @param clk - The clock mode. * Accepted values: AD413X_INT_76_8_KHZ_OUT_OFF * AD413X_INT_76_8_KHZ_OUT_ON * AD413X_EXT_76_8KHZ * AD413X_EXT_153_6_KHZ_DIV_2 * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_set_mclk(struct ad413x_dev *dev, enum ad413x_mclk_sel clk) { int32_t ret; ret = ad413x_reg_write_msk(dev, AD413X_REG_ADC_CTRL, AD413X_ADC_CNTRL_MCLK(clk), AD413X_ADC_CNTRL_MCLK(0xF)); if(ret) return ret; dev->mclk = clk; return 0; } /***************************************************************************//** * Do a SPI software reset. * * @param dev - The device structure. * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_do_soft_reset(struct ad413x_dev *dev) { int32_t ret; uint8_t buf [ 8 ] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; /* The AD413X can be reset by writing a series of 64 consecutive 1s * to the DIN input */ ret = no_os_spi_write_and_read(dev->spi_dev, buf, 8); if(ret) return ret; no_os_mdelay(5); // TBD return 0; } /***************************************************************************//** * SPI internal register write to device. * * @param dev - The device structure. * @param reg_addr - The register address. * @param reg_data - The register data. * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_reg_write(struct ad413x_dev *dev, uint32_t reg_addr, uint32_t reg_data) { uint8_t buf[5]; uint8_t data_size = AD413X_TRANSF_LEN(reg_addr); buf[0] = AD413X_CMD_WR_COM_REG(reg_addr); switch(data_size) { case 1: buf[1] = (reg_data & 0xFF); break; case 2: buf[1] = (reg_data & 0xFF00) >> 8; buf[2] = (reg_data & 0xFF); break; case 3: buf[1] = (reg_data & 0xFF0000) >> 16; buf[2] = (reg_data & 0xFF00) >> 8; buf[3] = (reg_data & 0xFF); break; default: return -EINVAL; } if (dev->spi_crc_en) buf[data_size] = no_os_crc8(ad413x_crc8, buf, ++data_size, 0); return no_os_spi_write_and_read(dev->spi_dev, buf, data_size + 1); } /***************************************************************************//** * SPI internal register read from device. * * @param dev - The device structure. * @param reg_addr - The register address. * @param reg_data - The register data. * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_reg_read(struct ad413x_dev *dev, uint32_t reg_addr, uint32_t *reg_data) { uint8_t ret; uint8_t buf[] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}; uint32_t data; uint8_t crc; uint8_t data_size = AD413X_TRANSF_LEN(reg_addr); buf[0] = AD413X_CMD_RD_COM_REG(reg_addr); if ((reg_addr == AD413X_REG_DATA) && (dev->data_stat)) data_size++; if (dev->spi_crc_en) data_size++; ret = no_os_spi_write_and_read(dev->spi_dev, buf, data_size + 1); if (ret) return ret; if (dev->spi_crc_en) { buf[0] = AD413X_CMD_RD_COM_REG(reg_addr); crc = no_os_crc8(ad413x_crc8, buf, data_size, 0); if (buf[data_size] != crc) return -EBADMSG; data_size--; } switch (data_size) { case 1: data = buf[1]; break; case 2: data = (buf[1] << 8) | buf[2]; break; case 3: data = (buf[1] << 16) | (buf[2] << 8) | buf[3]; break; case 4: data = (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | buf[4]; break; default: return -EINVAL; } *reg_data = data; return 0; } /***************************************************************************//** * Single conversion of each adc active channel. * * @param dev - The device structure. * @param buffer - Buffer to store read data. Buffer size needs to be at * least equal to the number of active channels. Results will * be stored in consecutive order of the active channels. * @param ch_nb - Number of active channels. * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_single_conv(struct ad413x_dev *dev, uint32_t *buffer, uint8_t ch_nb) { int32_t ret; struct ad413x_callback_ctx ctx = { .dev = dev, .buffer = buffer, .buffer_size = ch_nb }; struct no_os_callback_desc irq_callback = { .callback = &irq_adc_read, .ctx = &ctx }; ret = no_os_irq_trigger_level_set(dev->irq_desc, dev->rdy_pin, NO_OS_IRQ_EDGE_FALLING); if (ret) return ret; ret = no_os_irq_register_callback(dev->irq_desc, dev->rdy_pin, &irq_callback); if (ret) return ret; ret = no_os_irq_enable(dev->irq_desc, dev->rdy_pin); if (ret) return ret; ret = ad413x_set_adc_mode(dev, AD413X_SINGLE_CONV_MODE); if (ret) return ret; while((ctx.buffer_size != 0U) && --timeout) ; if (!timeout) pr_err("Timeout error (%s)\n", __func__); ret = no_os_irq_disable(dev->irq_desc, dev->rdy_pin); if (ret) return ret; return no_os_irq_unregister_callback(dev->irq_desc, dev->rdy_pin, &irq_callback); } /***************************************************************************//** * Continuous conversion of each adc active channel. * * @param dev - The device structure. * @param buffer - Buffer to store read data. Buffer size needs to be at * least equal to the number of active channels * samples number. * Results will be stored in consecutive order of the active * channels. * @param ch_nb - Number of active channels. * @param sample_nb - Samples number. * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_continuous_conv(struct ad413x_dev *dev, uint32_t *buffer, uint8_t ch_nb, uint32_t sample_nb) { int32_t ret; struct ad413x_callback_ctx ctx = { .dev = dev, .buffer = buffer, .buffer_size = ch_nb * sample_nb }; struct no_os_callback_desc irq_callback = { .callback = &irq_adc_read, .ctx = &ctx }; ret = no_os_irq_trigger_level_set(dev->irq_desc, dev->rdy_pin, NO_OS_IRQ_EDGE_FALLING); if (ret) return ret; ret = no_os_irq_register_callback(dev->irq_desc, dev->rdy_pin, &irq_callback); if (ret) return ret; ret = no_os_irq_enable(dev->irq_desc, dev->rdy_pin); if (ret) return ret; ret = ad413x_set_adc_mode(dev, AD413X_CONTINOUS_CONV_MODE); if (ret) return ret; while((ctx.buffer_size != 0U) && --timeout) ; if (!timeout) pr_err("Timeout error (%s)\n", __func__); ret = ad413x_set_adc_mode(dev, AD413X_STANDBY_MODE); if (ret) return ret; return no_os_irq_unregister_callback(dev->irq_desc, dev->rdy_pin, &irq_callback); } /***************************************************************************//** * Store adc channel presets. * * @param dev - The device structure. * @param preset - The structure to be saved as preset. * @param preset_nb - Preset's number. * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_preset_store(struct ad413x_dev *dev, struct ad413x_preset preset, enum ad413x_preset_nb preset_nb) { int32_t ret; ret = ad413x_set_gain(dev, preset.gain, preset_nb); if (ret) return ret; ret = ad413x_set_ref(dev, preset.ref_sel, preset_nb); if (ret) return ret; ret = ad413x_set_ref_buf(dev, preset.ref_buf, preset_nb); if (ret) return ret; ret = ad413x_set_settle_time(dev, preset.s_time, preset_nb); if (ret) return ret; ret = ad413x_set_exc_current(dev, preset.iout0_exc_current, preset.iout1_exc_current, preset_nb); if (ret) return ret; return ad413x_set_filter(dev, preset.filter, preset_nb); } /***************************************************************************//** * Initialize the device. * * @param device - The device structure. * @param init_param - The structure that contains the device initial * parameters. * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_init(struct ad413x_dev **device, struct ad413x_init_param init_param) { struct ad413x_dev *dev; uint32_t reg_data; int32_t ret; int32_t i; no_os_crc8_populate_msb(ad413x_crc8, AD413X_CRC8_POLY); dev = (struct ad413x_dev *)malloc(sizeof(*dev)); if (!dev) return -1; dev->chip_id = init_param.chip_id; dev->irq_desc = init_param.irq_desc; dev->rdy_pin = init_param.rdy_pin; dev->spi_crc_en = 0; /* SPI */ ret = no_os_spi_init(&dev->spi_dev, init_param.spi_init); if (ret) goto err_dev; /* Device Settings */ ret = ad413x_do_soft_reset(dev); if (ret) goto err_spi; /* Reset POR flag */ ret = ad413x_reg_read(dev, AD413X_REG_STATUS, ®_data); if (ret) return -1; /* Change SPI to 4 wire*/ ret = ad413x_reg_write_msk(dev, AD413X_REG_ADC_CTRL, AD413X_ADC_CSB_EN, AD413X_ADC_CSB_EN); if (ret) goto err_spi; /* TBD - chip ID is 0x00 for now */ ret = ad413x_reg_read(dev, AD413X_REG_ID, ®_data); if (ret) goto err_spi; switch(dev->chip_id) { case AD4130_8: if(reg_data != AD4130_8) { goto err_spi; } break; default: goto err_spi; } ret = ad413x_set_adc_mode(dev, AD413X_STANDBY_MODE); if (ret) goto err_spi; if (init_param.spi_crc_en) { ret = ad413x_reg_write_msk(dev, AD413X_REG_ERROR_EN, AD413X_SPI_CRC_ERR_EN, AD413X_SPI_CRC_ERR_EN); if (ret) goto err_spi; dev->spi_crc_en = init_param.spi_crc_en; } /* Preset configured and saved in dev */ for (i = 0; i < 8; i++) { ret = ad413x_preset_store(dev, init_param.preset[i], i); if (ret) goto err_spi; } /* Channel setup */ for (i = 0; i < 16; i++) { ret = ad413x_set_ch_preset(dev, i, init_param.ch[i].preset); if (ret) goto err_spi; ret = ad413x_reg_write_msk(dev, AD413X_REG_CHN(i), AD413X_AINP_M(init_param.ch[i].ain_p), AD413X_AINP_M(0xFF)); if (ret) goto err_spi; dev->ch[i].ain_p = init_param.ch[i].ain_p; ret = ad413x_reg_write_msk(dev, AD413X_REG_CHN(i), AD413X_AINM_M(init_param.ch[i].ain_m), AD413X_AINM_M(0xFF)); if (ret) goto err_spi; dev->ch[i].ain_m = init_param.ch[i].ain_m; ret = ad413x_ch_exc_input(dev, i, init_param.ch[i].iout0_exc_input, init_param.ch[i].iout1_exc_input); if (ret) goto err_spi; ret = ad413x_pdsw_en(dev, i, init_param.ch[i].pdsw_en); if (ret) goto err_spi; ret = ad413x_ch_en(dev, i, init_param.ch[i].enable); if (ret) goto err_spi; } ret = ad413x_set_int_ref(dev, init_param.int_ref); if (ret) goto err_spi; ret = ad413x_adc_bipolar(dev, init_param.bipolar); if (ret) goto err_spi; ret = ad413x_set_v_bias(dev, init_param.v_bias); if (ret) goto err_spi; ret = ad413x_set_standby_ctrl(dev, init_param.standby_ctrl); if (ret) goto err_spi; ret = ad413x_set_mclk(dev, init_param.mclk); if (ret) goto err_spi; ret = ad413x_data_stat_en(dev, init_param.data_stat); if (ret) goto err_spi; *device = dev; pr_info("AD413X successfully initialized\n"); return 0; err_spi: no_os_spi_remove(dev->spi_dev); err_dev: free(dev); pr_err("AD413X initialization error (%d)\n", ret); return ret; } /***************************************************************************//** * @brief Free the resources allocated by ad413x_init(). * * @param dev - The device structure. * * @return 0 in case of success, negative error code otherwise. *******************************************************************************/ int32_t ad413x_remove(struct ad413x_dev *dev) { int32_t ret; ret = no_os_spi_remove(dev->spi_dev); if (ret) return ret; free(dev); return 0; }