AD7768-1 MBED IIO Application Example

Dependencies:   platform_drivers

app/ad77681.c

Committer:
epena
Date:
2021-09-24
Revision:
1:c0429edee15b

File content as of revision 1:c0429edee15b:

/***************************************************************************//**
 *   @file   ad77681.c
 *   @brief  Implementation of AD7768-1 Driver.
 *   @author SPopa (stefan.popa@analog.com)
********************************************************************************
 * Copyright 2017(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 "stdbool.h"
#include <string.h>
#include "ad77681.h"
#include "error.h"
#include "delay.h"

/******************************************************************************/
/************************** Functions Implementation **************************/
/******************************************************************************/
/**
 * Compute CRC8 checksum.
 * @param data - The data buffer.
 * @param data_size - The size of the data buffer.
 * @param init_val - CRC initial value.
 * @return CRC8 checksum.
 */
uint8_t ad77681_compute_crc8(uint8_t *data,
			     uint8_t data_size,
			     uint8_t init_val)
{
	uint8_t i;
	uint8_t crc = init_val;

	while (data_size) {
		for (i = 0x80; i != 0; i >>= 1) {
			if (((crc & 0x80) != 0) != ((*data & i) != 0)) {
				crc <<= 1;
				crc ^= AD77681_CRC8_POLY;
			} else
				crc <<= 1;
		}
		data++;
		data_size--;
	}
	return crc;
}

/**
 * Compute XOR checksum.
 * @param data - The data buffer.
 * @param data_size - The size of the data buffer.
 * @param init_val - CRC initial value.
 * @return XOR checksum.
 */
uint8_t ad77681_compute_xor(uint8_t *data,
			    uint8_t data_size,
			    uint8_t init_val)
{
	uint8_t crc = init_val;
	uint8_t buf[3];
	uint8_t i;

	for (i = 0; i < data_size; i++) {
		buf[i] = *data;
		crc ^= buf[i];
		data++;
	}
	return crc;
}

/**
 * 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 ad77681_spi_reg_read(struct ad77681_dev *dev,
			     uint8_t reg_addr,
			     uint8_t *reg_data)
{
	int32_t ret;
	uint8_t crc;
	uint8_t buf[3], crc_buf[2];
	uint8_t buf_len = (dev->crc_sel == AD77681_NO_CRC) ? 2 : 3;

	buf[0] = AD77681_REG_READ(reg_addr);
	buf[1] = 0x00;

	ret = spi_write_and_read(dev->spi_desc, buf, buf_len);
	if (ret < 0)
		return ret;

	/* XOR or CRC checksum for read transactions */
	if (dev->crc_sel != AD77681_NO_CRC) {
		crc_buf[0] = AD77681_REG_READ(reg_addr);
		crc_buf[1] = buf[1];

		if (dev->crc_sel == AD77681_XOR)
			/* INITIAL_CRC is 0, when ADC is not in continuous-read mode */
			crc = ad77681_compute_xor(crc_buf, 2, INITIAL_CRC);
		else if(dev->crc_sel == AD77681_CRC)
			/* INITIAL_CRC is 0, when ADC is not in continuous-read mode */
			crc = ad77681_compute_crc8(crc_buf, 2, INITIAL_CRC);

		/* In buf[2] is CRC from the ADC */
		if (crc != buf[2])
			ret = FAILURE;
#ifdef CRC_DEBUG
		printf("\n%x\t%x\tCRC/XOR: %s\n", crc,
		       buf[2], ((crc !=  buf[2]) ? "FAULT" : "OK"));
#endif /* CRC_DEBUG */
	}

	reg_data[0] = AD77681_REG_READ(reg_addr);
	memcpy(reg_data + 1, buf + 1, ARRAY_SIZE(buf) - 1);

	return ret;
}

/**
 * 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 ad77681_spi_reg_write(struct ad77681_dev *dev,
			      uint8_t reg_addr,
			      uint8_t reg_data)
{
	uint8_t buf[3];
	/* Buffer length in case of checksum usage */
	uint8_t buf_len = (dev->crc_sel == AD77681_NO_CRC) ? 2 : 3;

	buf[0] = AD77681_REG_WRITE(reg_addr);
	buf[1] = reg_data;

	/* CRC only for read transactions, CRC and XOR for write transactions*/
	if (dev->crc_sel != AD77681_NO_CRC)
		buf[2] = ad77681_compute_crc8(buf, 2, INITIAL_CRC);

	return spi_write_and_read(dev->spi_desc, buf, buf_len);
}

/**
 * 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 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_spi_read_mask(struct ad77681_dev *dev,
			      uint8_t reg_addr,
			      uint8_t mask,
			      uint8_t *data)
{
	uint8_t reg_data[3];
	int32_t ret;

	ret = ad77681_spi_reg_read(dev, reg_addr, reg_data);
	*data = (reg_data[1] & 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 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_spi_write_mask(struct ad77681_dev *dev,
			       uint8_t reg_addr,
			       uint8_t mask,
			       uint8_t data)
{
	uint8_t reg_data[3];
	int32_t ret;

	ret = ad77681_spi_reg_read(dev, reg_addr, reg_data);
	reg_data[1] &= ~mask;
	reg_data[1] |= data;
	ret |= ad77681_spi_reg_write(dev, reg_addr, reg_data[1]);

	return ret;
}

/**
 * Helper function to get the number of rx bytes
 * @param dev - The device structure.
 * @return rx_buf_len - the number of rx bytes
 */
uint8_t ad77681_get_rx_buf_len(struct ad77681_dev *dev)
{
	uint8_t rx_buf_len = 0;
	uint8_t data_len = 0;
	uint8_t crc = 0;
	uint8_t status_bit = 0;

	data_len = 3;
	crc = (dev->crc_sel == AD77681_NO_CRC) ? 0 : 1; // 1 byte for crc
	status_bit = dev->status_bit; // one byte for status

	rx_buf_len = data_len + crc + status_bit;

	return rx_buf_len;
}

/**
 * Helper function to get the number of SPI 16bit frames for INTERRUPT ADC DATA READ
 * @param dev - The device structure.
 * @return frame_16bit - the number of 16 bit SPI frames
 */
uint8_t ad77681_get_frame_byte(struct ad77681_dev *dev)
{
	/* number of 8bit frames */
	uint8_t frame_bytes;
	if (dev->conv_len == AD77681_CONV_24BIT)
		frame_bytes = 3;
	else
		frame_bytes = 2;
	if (dev->crc_sel != AD77681_NO_CRC)
		frame_bytes++;
	if (dev->status_bit)
		frame_bytes++;

	dev->data_frame_byte = frame_bytes;

	return frame_bytes;
}

/**
 * Read conversion result from device.
 * @param dev - The device structure.
 * @param adc_data - The conversion result data
 * @param mode - Data read mode
 * 		Accepted values: AD77681_REGISTER_DATA_READ
 *				 AD77681_CONTINUOUS_DATA_READ
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_spi_read_adc_data(struct ad77681_dev *dev,
				  uint8_t *adc_data,
				  enum ad77681_data_read_mode mode)
{
	uint8_t buf[6], crc_xor, add_buff;
	int32_t ret;

	if (mode == AD77681_REGISTER_DATA_READ) {
		buf[0] = AD77681_REG_READ(AD77681_REG_ADC_DATA);
		add_buff = 1;
	} else {
		buf[0] = 0x00;
		add_buff = 0;
	}
	buf[1] = 0x00; /* added 2 more array places for max data length read */
	buf[2] = 0x00; /* For register data read */
	buf[3] = 0x00; /* register address + 3 bytes of data (24bit format) + Status bit + CRC */
	buf[4] = 0x00; /* For continuous data read */
	buf[5] = 0x00; /* 3 bytes of data (24bit format) + Status bit + CRC */


	ret = spi_write_and_read(dev->spi_desc, buf, dev->data_frame_byte + add_buff);
	if (ret < 0)
		return ret;

	if (dev->crc_sel != AD77681_NO_CRC) {
		if (dev->crc_sel == AD77681_CRC)
			crc_xor = ad77681_compute_crc8(buf + add_buff, dev->data_frame_byte - 1,
						       INITIAL_CRC_CRC8);
		else
			crc_xor = ad77681_compute_xor(buf + add_buff, dev->data_frame_byte - 1,
						      INITIAL_CRC_XOR);

		if (crc_xor != buf[dev->data_frame_byte - (1 - add_buff)]) {
			printf("%s: CRC Error.\n", __func__);
			ret = FAILURE;
		}
#ifdef CRC_DEBUG
		printf("\n%x\t%x\tCRC/XOR: %s\n", crc_xor,
		       buf[dev->data_frame_byte - (1 - add_buff)],
		       ((crc_xor != buf[dev->data_frame_byte - (1 - add_buff)]) ? "FAULT" : "OK"));
#endif /* CRC_DEBUG */
	}

	/* Fill the adc_data buffer */
	memcpy(adc_data, buf, ARRAY_SIZE(buf));

	return ret;
}

/**
 * CRC and status bit handling after each readout form the ADC
 * @param dev - The device structure.
 * @param *data_buffer - 16-bit buffer readed from the ADC containing the CRC,
 * data and the stattus bit.
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_CRC_status_handling(struct ad77681_dev *dev,
				    uint16_t *data_buffer)
{
	int32_t ret = 0;
	uint8_t status_byte = 0, checksum = 0, checksum_byte = 0, checksum_buf[5],
		checksum_length = 0, i;
	char print_buf[50];

	/* Status bit handling */
	if (dev->status_bit) {
		/* 24bit ADC data + 8bit of status = 2 16bit frames */
		if (dev->conv_len == AD77681_CONV_24BIT)
			status_byte = data_buffer[1] & 0xFF;
		/* 16bit ADC data + 8bit of status = 2 16bit frames */
		else
			status_byte = data_buffer[1] >> 8;
	}

	/* Checksum bit handling */
	if (dev->crc_sel != AD77681_NO_CRC) {
		if ((dev->status_bit == true) & (dev->conv_len == AD77681_CONV_24BIT)) {
			/* 24bit ADC data + 8bit of status + 8bit of CRC = 3 16bit frames */
			checksum_byte = data_buffer[2] >> 8;
			checksum_length = 4;
		} else if ((dev->status_bit == true) & (dev->conv_len == AD77681_CONV_16BIT)) {
			/* 16bit ADC data + 8bit of status + 8bit of CRC = 2 16bit frames */
			checksum_byte = data_buffer[1] & 0xFF;
			checksum_length = 3;
		} else if ((dev->status_bit == false) & (dev->conv_len == AD77681_CONV_24BIT)) {
			/* 24bit ADC data + 8bit of CRC = 2 16bit frames */
			checksum_byte = data_buffer[1] & 0xFF;
			checksum_length = 3;
		} else if ((dev->status_bit == false) & (dev->conv_len == AD77681_CONV_16BIT)) {
			/* 16bit ADC data + 8bit of CRC = 2 16bit frames */
			checksum_byte = data_buffer[1] >> 8;
			checksum_length = 2;
		}

		for (i = 0; i < checksum_length; i++) {
			if (i % 2)
				checksum_buf[i] = data_buffer[i / 2] & 0xFF;
			else
				checksum_buf[i] = data_buffer[i / 2] >> 8;
		}

		if (dev->crc_sel == AD77681_CRC)
			checksum = ad77681_compute_crc8(checksum_buf, checksum_length,
							INITIAL_CRC_CRC8);
		else if (dev->crc_sel == AD77681_XOR)
			checksum = ad77681_compute_xor(checksum_buf, checksum_length, INITIAL_CRC_XOR);

		if (checksum != checksum_byte)
			ret = FAILURE;

#ifdef CRC_DEBUG

		char ok[3] = { 'O', 'K' }, fault[6] = { 'F', 'A', 'U', 'L', 'T' };
		sprintf(print_buf, "\n%x\t%x\t%x\tCRC %s", checksum_byte, checksum, status_byte,
			((ret == FAILURE) ? (fault) : (ok)));
		printf(print_buf);

#endif /* CRC_DEBUG */
	}

	return ret;
}

/**
 * Conversion from measured data to voltage
 * @param dev - The device structure.
 * @param raw_code - ADC raw code measurements
 * @param voltage - Converted ADC code to voltage
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_data_to_voltage(struct ad77681_dev *dev,
				uint32_t *raw_code,
				double *voltage)
{
	int32_t converted_data;

	if (*raw_code & 0x800000)
		converted_data = (int32_t)((0xFF << 24) | *raw_code);
	else
		converted_data = (int32_t)((0x00 << 24) | *raw_code);

	/* ((2*Vref)*code)/2^24	*/
	*voltage = (double)(((2.0 * (((double)(dev->vref)) / 1000.0)) /
			     AD7768_FULL_SCALE) * converted_data);

	return SUCCESS;
}

/**
 * Update ADCs sample rate depending on MCLK, MCLK_DIV and filter settings
 * @param dev - The device structure.
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_update_sample_rate(struct ad77681_dev *dev)
{
	uint8_t mclk_div;
	uint16_t osr;

	/* Finding out MCLK divider */
	switch (dev->mclk_div) {
	case AD77681_MCLK_DIV_16:
		mclk_div = 16;
		break;
	case AD77681_MCLK_DIV_8:
		mclk_div = 8;
		break;
	case AD77681_MCLK_DIV_4:
		mclk_div = 4;
		break;
	case AD77681_MCLK_DIV_2:
		mclk_div = 2;
		break;
	default:
		return FAILURE;
		break;
	}

	/* Finding out decimation ratio */
	switch (dev->filter) {
	case (AD77681_SINC5 | AD77681_FIR):
		/* Decimation ratio of FIR or SINC5 (x32 to x1024) */
		switch (dev->decimate) {
		case AD77681_SINC5_FIR_DECx32:
			osr = 32;
			break;
		case AD77681_SINC5_FIR_DECx64:
			osr = 64;
			break;
		case AD77681_SINC5_FIR_DECx128:
			osr = 128;
			break;
		case AD77681_SINC5_FIR_DECx256:
			osr = 256;
			break;
		case AD77681_SINC5_FIR_DECx512:
			osr = 512;
			break;
		case AD77681_SINC5_FIR_DECx1024:
			osr = 1024;
			break;
		default:
			return FAILURE;
			break;
		}
		break;
	/* Decimation ratio of SINC5 x8 */
	case AD77681_SINC5_DECx8:
		osr = 8;
		break;
	/* Decimation ratio of SINC5 x16 */
	case AD77681_SINC5_DECx16:
		osr = 16;
		break;
	/* Decimation ratio of SINC3 */
	case AD77681_SINC3:
		osr = (dev->sinc3_osr + 1) * 32;
		break;
	default:
		return FAILURE;
		break;
	}

	/* Sample rate to Hz */
	dev->sample_rate = (dev->mclk / (osr*mclk_div)) * 1000;

	return SUCCESS;
}

/**
 * Get SINC3 filter oversampling ratio register value based on user's inserted
 * output data rate ODR
 * @param dev - The device structure.
 * @param sinc3_dec_reg - Returned closest value of SINC3 register
 * @param sinc3_odr - Desired output data rage
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_SINC3_ODR(struct ad77681_dev *dev,
			  uint16_t *sinc3_dec_reg,
			  float sinc3_odr)
{
	uint8_t mclk_div;
	float	odr;

	if (sinc3_odr < 0)
		return FAILURE;

	switch (dev->mclk_div) {
	case AD77681_MCLK_DIV_16:
		mclk_div = 16;
		break;
	case AD77681_MCLK_DIV_8:
		mclk_div = 8;
		break;
	case AD77681_MCLK_DIV_4:
		mclk_div = 4;
		break;
	case AD77681_MCLK_DIV_2:
		mclk_div = 2;
		break;
	default:
		return FAILURE;
		break;
	}

	odr = ((float)(dev->mclk * 1000.0) / (sinc3_odr * (float)(32 * mclk_div))) - 1;

	/* Sinc3 oversamplig register has 13 bits, biggest value = 8192 */
	if (odr < 8193)
		*sinc3_dec_reg = (uint16_t)(odr);
	else
		return FAILURE;

	return SUCCESS;
}

/**
 * Set the power consumption mode of the ADC core.
 * @param dev - The device structure.
 * @param mode - The power mode.
 * 					Accepted values: AD77681_ECO
 *									 AD77681_MEDIAN
 *									 AD77681_FAST
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_set_power_mode(struct ad77681_dev *dev,
			       enum ad77681_power_mode mode)
{
	int32_t ret;

	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_POWER_CLOCK,
				     AD77681_POWER_CLK_PWRMODE_MSK,
				     AD77681_POWER_CLK_PWRMODE(mode));

	if (ret == SUCCESS)
		dev->power_mode = mode;

	return ret;
}

/**
 * Set the MCLK divider.
 * @param dev - The device structure.
 * @param clk_div - The MCLK divider.
 * 					Accepted values: AD77681_MCLK_DIV_16
 *									 AD77681_MCLK_DIV_8
 *									 AD77681_MCLK_DIV_4
 *									 AD77681_MCLK_DIV_2
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_set_mclk_div(struct ad77681_dev *dev,
			     enum ad77681_mclk_div clk_div)
{
	int32_t ret;

	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_POWER_CLOCK,
				     AD77681_POWER_CLK_MCLK_DIV_MSK,
				     AD77681_POWER_CLK_MCLK_DIV(clk_div));

	if (ret == SUCCESS)
		dev->mclk_div = clk_div;

	return ret;
}

/**
 * Set the VCM output.
 * @param dev - The device structure.
 * @param VCM_out - The VCM output voltage.
 * 			Accepted values: AD77681_VCM_HALF_VCC
 *					 AD77681_VCM_2_5V
 *	  				 AD77681_VCM_2_05V
 *					 AD77681_VCM_1_9V
 *					 AD77681_VCM_1_65V
 *					 AD77681_VCM_1_1V
 *					 AD77681_VCM_0_9V
 *					 AD77681_VCM_OFF
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_set_VCM_output(struct ad77681_dev *dev,
			       enum ad77681_VCM_out VCM_out)
{
	int32_t ret;

	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_ANALOG2,
				     AD77681_ANALOG2_VCM_MSK,
				     AD77681_ANALOG2_VCM(VCM_out));

	if (ret == SUCCESS)
		dev->VCM_out = VCM_out;

	return ret;
}

/**
 * Set the AIN- precharge buffer.
 * @param dev - The device structure.
 * @param AINn - The negative analog input precharge buffer selector
 * 		 Accepted values: AD77681_AINn_ENABLED
 *				  AD77681_AINn_DISABLED
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_set_AINn_buffer(struct ad77681_dev *dev,
				enum ad77681_AINn_precharge AINn)
{
	int32_t ret;

	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_ANALOG,
				     AD77681_ANALOG_AIN_BUF_NEG_OFF_MSK,
				     AD77681_ANALOG_AIN_BUF_NEG_OFF(AINn));

	if (ret == SUCCESS)
		dev->AINn = AINn;

	return ret;
}

/**
 * Set the AIN+ precharge buffer.
 * @param dev - The device structure.
 * @param AINp - The positive analog input precharge buffer selector
 * 		 Accepted values: AD77681_AINp_ENABLED
 *				  AD77681_AINp_DISABLED
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_set_AINp_buffer(struct ad77681_dev *dev,
				enum ad77681_AINp_precharge AINp)
{
	int32_t ret;

	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_ANALOG,
				     AD77681_ANALOG_AIN_BUF_POS_OFF_MSK,
				     AD77681_ANALOG_AIN_BUF_POS_OFF(AINp));

	if (ret == SUCCESS)
		dev->AINp = AINp;

	return ret;
}

/**
 * Set the REF- reference buffer
 * @param dev - The device structure.
 * @param REFn - The negative reference buffer selector
 * 		 Accepted values: AD77681_BUFn_DISABLED
 *				  AD77681_BUFn_ENABLED
 *				  AD77681_BUFn_FULL_BUFFER_ON
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_set_REFn_buffer(struct ad77681_dev *dev,
				enum ad77681_REFn_buffer REFn)
{
	int32_t ret;

	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_ANALOG,
				     AD77681_ANALOG_REF_BUF_NEG_MSK,
				     AD77681_ANALOG_REF_BUF_NEG(REFn));

	if (ret == SUCCESS)
		dev->REFn = REFn;

	return ret;
}

/**
 * Set the REF+ reference buffer
 * @param dev -  The device structure.
 * @param REFp - The positive reference buffer selector
 * 		 Accepted values: AD77681_BUFp_DISABLED
 *				  AD77681_BUFp_ENABLED
 *				  AD77681_BUFp_FULL_BUFFER_ON
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_set_REFp_buffer(struct ad77681_dev *dev,
				enum ad77681_REFp_buffer REFp)
{
	int32_t ret;

	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_ANALOG,
				     AD77681_ANALOG_REF_BUF_POS_MSK,
				     AD77681_ANALOG_REF_BUF_POS(REFp));

	if (ret == SUCCESS)
		dev->REFp = REFp;
	else
		return FAILURE;

	return ret;
}

/**
 * Set filter type and decimation ratio
 * @param dev -	The device structure.
 * @param decimate - Decimation ratio of filter
 *			Accepted values: AD77681_SINC5_FIR_DECx32
 *					 AD77681_SINC5_FIR_DECx64
 *					 AD77681_SINC5_FIR_DECx128
 *					 AD77681_SINC5_FIR_DECx256
 *					 AD77681_SINC5_FIR_DECx512
 *					 AD77681_SINC5_FIR_DECx1024
 * @param filter - Select filter type
 *			Accepted values: AD77681_SINC5
 *					 AD77681_SINC5_DECx8
 *					 AD77681_SINC5_DECx16
 *					 AD77681_SINC3
 *					 AD77681_FIR
 * @param sinc3_osr - Select decimation ratio for SINC3 filter separately as
 *			integer from 0 to 8192.
 *			See the AD7768-1 datasheet for more info
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_set_filter_type(struct ad77681_dev *dev,
				enum ad77681_sinc5_fir_decimate decimate,
				enum ad77681_filter_type filter,
				uint16_t sinc3_osr)
{
	int32_t ret;

	ret = ad77681_spi_reg_write(dev, AD77681_REG_DIGITAL_FILTER, 0x00);

	/* SINC5 for OSR 8x and 16x*/
	if ((filter == AD77681_SINC5_DECx8) || (filter == AD77681_SINC5_DECx16)) {
		ret |= ad77681_spi_write_mask(dev,
					      AD77681_REG_DIGITAL_FILTER,
					      AD77681_DIGI_FILTER_FILTER_MSK,
					      AD77681_DIGI_FILTER_FILTER(filter));
		/* SINC5 and FIR for osr 32x to 1024x */
	} else if ((filter == AD77681_SINC5) || (filter == AD77681_FIR)) {
		ret |= ad77681_spi_write_mask(dev,
					      AD77681_REG_DIGITAL_FILTER,
					      AD77681_DIGI_FILTER_FILTER_MSK,
					      AD77681_DIGI_FILTER_FILTER(filter));

		ret |= ad77681_spi_write_mask(dev,
					      AD77681_REG_DIGITAL_FILTER,
					      AD77681_DIGI_FILTER_DEC_RATE_MSK,
					      AD77681_DIGI_FILTER_DEC_RATE(decimate));
		/* SINC3*/
	} else {
		uint8_t sinc3_LSB = 0, sinc3_MSB = 0;

		sinc3_MSB = sinc3_osr >> 8;
		sinc3_LSB = sinc3_osr & 0x00FF;

		ret |= ad77681_spi_write_mask(dev,
					      AD77681_REG_DIGITAL_FILTER,
					      AD77681_DIGI_FILTER_FILTER_MSK,
					      AD77681_DIGI_FILTER_FILTER(filter));

		ret |= ad77681_spi_write_mask(dev,
					      AD77681_REG_SINC3_DEC_RATE_MSB,
					      AD77681_SINC3_DEC_RATE_MSB_MSK,
					      AD77681_SINC3_DEC_RATE_MSB(sinc3_MSB));

		ret |= ad77681_spi_write_mask(dev,
					      AD77681_REG_SINC3_DEC_RATE_LSB,
					      AD77681_SINC3_DEC_RATE_LSB_MSK,
					      AD77681_SINC3_DEC_RATE_LSB(sinc3_LSB));
	}

	if ( ret == SUCCESS) {
		dev->decimate = decimate;
		dev->filter = filter;
		/* Sync pulse after each filter change */
		ret |= ad77681_initiate_sync(dev);
	}

	return ret;
}

/**
 * Enable 50/60 Hz rejection
 * @param dev -	The device structure.
 * @param enable - The positive reference buffer selector
 * 		   Accepted values: true
 *				    false
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_set_50HZ_rejection(struct ad77681_dev *dev,
				   uint8_t enable)
{
	int32_t ret;

	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_DIGITAL_FILTER,
				     AD77681_DIGI_FILTER_60HZ_REJ_EN_MSK,
				     AD77681_DIGI_FILTER_60HZ_REJ_EN(enable));

	return ret;
}

/**
 * Set the REF- reference buffer
 * @param dev - The device structure.
 * @param continuous_enable - Continous read enable
 * 		 Accepted values: AD77681_CONTINUOUS_READ_ENABLE
 *				  AD77681_CONTINUOUS_READ_DISABLE
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_set_continuos_read(struct ad77681_dev *dev,
				   enum ad77681_continuous_read continuous_enable)
{
	int32_t ret;

	if (continuous_enable) {
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_INTERFACE_FORMAT,
					     AD77681_INTERFACE_CONT_READ_MSK,
					     AD77681_INTERFACE_CONT_READ_EN(continuous_enable));
	} else {
		/* To exit the continuous read mode, a key 0x6C must be
		written into the device over the SPI*/
		uint8_t end_key = EXIT_CONT_READ;
		ret = spi_write_and_read(dev->spi_desc, &end_key, 1);
	}

	return ret;
}

/**
 * Power down / power up the device
 * @param dev -	The device structure.
 * @param sleep_wake - Power down, or power up the ADC
 * 			Accepted values: AD77681_SLEEP
 *					 AD77681_WAKE
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_power_down(struct ad77681_dev *dev,
			   enum ad77681_sleep_wake sleep_wake)
{
	int32_t ret;

	if (sleep_wake == AD77681_SLEEP) {
		ret = ad77681_spi_reg_write(dev, AD77681_REG_POWER_CLOCK,
					    AD77681_POWER_CLK_POWER_DOWN);
	} else {
		/* Wake up the ADC over SPI, by sending a wake-up sequence:
		1 followed by 63 zeroes and CS hold low*/
		uint8_t wake_sequence[8] = { 0 };
		/* Insert '1' to the beginning of the wake_sequence*/
		wake_sequence[0] = 0x80;
		ret = spi_write_and_read(dev->spi_desc, wake_sequence,
					 ARRAY_SIZE(wake_sequence));
	}

	return ret;
}

/**
 * Conversion mode and source select
 * @param dev - The device structure.
 * @param conv_mode - Sets the conversion mode of the ADC
 * 					  Accepted values: AD77681_CONV_CONTINUOUS
 *									   AD77681_CONV_ONE_SHOT
 *									   AD77681_CONV_SINGLE
 *									   AD77681_CONV_PERIODIC
 * @param diag_mux_sel - Selects which signal to route through diagnostic mux
 * 					  Accepted values: AD77681_TEMP_SENSOR
 *									   AD77681_AIN_SHORT
 *									   AD77681_POSITIVE_FS
 *									   AD77681_NEGATIVE_FS
 * @param conv_diag_sel - Select the input for conversion as AIN or diagnostic mux
 * 					  Accepted values: true
 *									   false
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_set_conv_mode(struct ad77681_dev *dev,
			      enum ad77681_conv_mode conv_mode,
			      enum ad77681_conv_diag_mux diag_mux_sel,
			      bool conv_diag_sel)
{
	int32_t ret;

	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_CONVERSION,
				     AD77681_CONVERSION_MODE_MSK,
				     AD77681_CONVERSION_MODE(conv_mode));

	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_CONVERSION,
				      AD77681_CONVERSION_DIAG_MUX_MSK,
				      AD77681_CONVERSION_DIAG_MUX_SEL(diag_mux_sel));

	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_CONVERSION,
				      AD77681_CONVERSION_DIAG_SEL_MSK,
				      AD77681_CONVERSION_DIAG_SEL(conv_diag_sel));

	if (ret == SUCCESS) {
		dev->conv_mode = conv_mode;
		dev->diag_mux_sel = diag_mux_sel;
		dev->conv_diag_sel = conv_diag_sel;
	}

	return ret;
}

/**
 * Set the Conversion Result Output Length.
 * @param dev - The device structure.
 * @param conv_len - The MCLK divider.
 * 					Accepted values: AD77681_CONV_24BIT
 *									 AD77681_CONV_16BIT
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_set_convlen(struct ad77681_dev *dev,
			    enum ad77681_conv_len conv_len)
{
	int32_t ret;

	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_INTERFACE_FORMAT,
				     AD77681_INTERFACE_CONVLEN_MSK,
				     AD77681_INTERFACE_CONVLEN(conv_len));

	if (ret == SUCCESS) {
		dev->conv_len = conv_len;
		ad77681_get_frame_byte(dev);
	}

	return ret;
}

/**
 * Activates CRC on all SPI transactions and
 * Selects CRC method as XOR or 8-bit polynomial
 * @param dev - The device structure.
 * @param crc_sel - The CRC type.
 * 					Accepted values: AD77681_CRC
 *									 AD77681_XOR
 *									 AD77681_NO_CRC
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_set_crc_sel(struct ad77681_dev *dev,
			    enum ad77681_crc_sel crc_sel)
{
	int32_t ret;

	if (crc_sel == AD77681_NO_CRC) {
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_INTERFACE_FORMAT,
					     AD77681_INTERFACE_CRC_EN_MSK,
					     AD77681_INTERFACE_CRC_EN(0));
	} else {
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_INTERFACE_FORMAT,
					     AD77681_INTERFACE_CRC_EN_MSK,
					     AD77681_INTERFACE_CRC_EN(1));

		ret |= ad77681_spi_write_mask(dev,
					      AD77681_REG_INTERFACE_FORMAT,
					      AD77681_INTERFACE_CRC_TYPE_MSK,
					      AD77681_INTERFACE_CRC_TYPE(crc_sel));
	}

	if (ret == SUCCESS) {
		dev->crc_sel = crc_sel;
		ad77681_get_frame_byte(dev);
	}

	return ret;
}

/**
 * Enables Status bits output
 * @param dev - The device structure.
 * @param status_bit - enable or disable status bit
 * 					Accepted values: true
 *									 false
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_set_status_bit(struct ad77681_dev *dev,
			       bool status_bit)
{
	int32_t ret;

	// Set status bit
	ret = 	ad77681_spi_write_mask(dev,
				       AD77681_REG_INTERFACE_FORMAT,
				       AD77681_INTERFACE_STATUS_EN_MSK,
				       AD77681_INTERFACE_STATUS_EN(status_bit));

	if (ret == SUCCESS) {
		dev->status_bit = status_bit;
		ad77681_get_frame_byte(dev);
	}

	return ret;
}

/**
 * Device reset over SPI.
 * @param dev - The device structure.
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_soft_reset(struct ad77681_dev *dev)
{
	int32_t ret = 0;

	// Two writes are required to initialize the reset
	ret |= 	ad77681_spi_write_mask(dev,
				       AD77681_REG_SYNC_RESET,
				       AD77681_SYNC_RST_SPI_RESET_MSK,
				       AD77681_SYNC_RST_SPI_RESET(0x3));

	ret |= 	ad77681_spi_write_mask(dev,
				       AD77681_REG_SYNC_RESET,
				       AD77681_SYNC_RST_SPI_RESET_MSK,
				       AD77681_SYNC_RST_SPI_RESET(0x2));

	return ret;
}

/**
 * Initiate a SYNC_OUT pulse over spi
 * @param dev - The device structure.
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_initiate_sync(struct ad77681_dev *dev)
{
	return ad77681_spi_write_mask(dev,
				      AD77681_REG_SYNC_RESET,
				      AD77681_SYNC_RST_SPI_STARTB_MSK,
				      AD77681_SYNC_RST_SPI_STARTB(0));
}

/**
 * Write to offset registers
 * @param dev 			The device structure.
 * @param value			The desired value of the whole 24-bit offset register
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_apply_offset(struct ad77681_dev *dev,
			     uint32_t value)
{
	int32_t ret;
	uint8_t offset_HI = 0, offset_MID = 0, offset_LO = 0;

	offset_HI = (value & 0x00FF0000) >> 16;
	offset_MID = (value & 0x0000FF00) >> 8;
	offset_LO = (value & 0x000000FF);

	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_OFFSET_HI,
				     AD77681_OFFSET_HI_MSK,
				     AD77681_OFFSET_HI(offset_HI));

	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_OFFSET_MID,
				      AD77681_OFFSET_MID_MSK,
				      AD77681_OFFSET_MID(offset_MID));

	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_OFFSET_LO,
				      AD77681_OFFSET_LO_MSK,
				      AD77681_OFFSET_LO(offset_LO));

	return ret;
}

/**
 * Write to gain registers
 * @param dev - The device structure.
 * @param value - The desired value of the whole 24-bit gain register
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_apply_gain(struct ad77681_dev *dev,
			   uint32_t value)
{
	int32_t ret;
	uint8_t gain_HI = 0, gain_MID = 0, gain_LO = 0;

	gain_HI = (value & 0x00FF0000) >> 16;
	gain_MID = (value & 0x0000FF00) >> 8;
	gain_LO = (value & 0x000000FF);

	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_GAIN_HI,
				     AD77681_GAIN_HI_MSK,
				     AD77681_GAIN_HI(gain_HI));

	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_GAIN_MID,
				      AD77681_GAIN_MID_MSK,
				      AD77681_GAIN_MID(gain_MID));

	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_GAIN_LO,
				      AD77681_GAIN_LOW_MSK,
				      AD77681_GAIN_LOW(gain_LO));

	return ret;
}

/**
 * Upload sequence for Programmamble FIR filter
 * @param dev - The device structure.
 * @param coeffs - Pointer to the desired filter coefficients array to be written
 * @param num_coeffs - Count of active filter coeffs
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_programmable_filter(struct ad77681_dev *dev,
				    const float *coeffs,
				    uint8_t num_coeffs)
{
	uint8_t coeffs_buf[4], coeffs_index, check_back = 0, i, address;
	uint32_t twait;
	int32_t twos_complement, ret;
	const uint8_t coeff_reg_length = 56;

	/* Specific keys in the upload sequence */
	const uint8_t key1 = 0xAC, key2 = 0x45, key3 = 0x55;
	/* Scaling factor for all coefficients 2^22 */
	const float coeff_scale_factor = (1 << 22);
	/* Wait time in uS necessary to access the COEFF_CONTROL and */
	/* COEFF_DATA registers. Twait = 512/MCLK */
	twait = (uint32_t)(((512.0) / ((float)(dev->mclk))) * 1000.0) + 1;

	/* Set Filter to FIR */
	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_DIGITAL_FILTER,
				     AD77681_DIGI_FILTER_FILTER_MSK,
				     AD77681_DIGI_FILTER_FILTER(AD77681_FIR));

	/* Check return value before proceeding */
	if (ret < 0)
		return ret;

	/* Write the first access key to the ACCESS_KEY register */
	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_ACCESS_KEY,
				     AD77681_ACCESS_KEY_MSK,
				     AD77681_ACCESS_KEY(key1));

	/* Check return value before proceeding */
	if (ret < 0)
		return ret;

	/* Write the second access key to the ACCESS_KEY register */
	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_ACCESS_KEY,
				     AD77681_ACCESS_KEY_MSK,
				     AD77681_ACCESS_KEY(key2));

	/* Check return value before proceeding */
	if (ret < 0)
		return ret;

	/* Read the the ACCESS_KEY register bit 0, the key bit */
	ret = ad77681_spi_read_mask(dev,
				    AD77681_REG_ACCESS_KEY,
				    AD77681_ACCESS_KEY_CHECK_MSK,
				    &check_back);

	/* Checks ret and key bit, return FAILURE in case key bit not equal to 1 */
	if ((ret < 0) || (check_back != 1))
		return FAILURE;

	/* Set the initial adress to 0 and enable the  write and coefficient access bits */
	address = AD77681_COEF_CONTROL_COEFFACCESSEN_MSK
		  | AD77681_COEF_CONTROL_COEFFWRITEEN_MSK;

	/* The COEFF_DATA register has to be filled with 56 coeffs.*/
	/* In case the number of active filter coefficient is less */
	/* than 56, zeros will be padded before the desired coeff. */
	for (i = 0; i < coeff_reg_length; i++) {
		/* Set the coeff address */
		ret = ad77681_spi_reg_write(dev,
					    AD77681_REG_COEFF_CONTROL,
					    address);

		/* Check return value before proceeding */
		if (ret < 0)
			return ret;

		/* Wait for Twait uSeconds*/
		udelay(twait);

		/* Padding of zeros before the desired coef in case the coef count in less than 56 */
		if((num_coeffs + i) < coeff_reg_length) {
			/* wirte zeroes to COEFF_DATA, in case of less coeffs than 56*/
			coeffs_buf[0] = AD77681_REG_WRITE(AD77681_REG_COEFF_DATA);
			coeffs_buf[1] = 0;
			coeffs_buf[2] = 0;
			coeffs_buf[3] = 0;
		} else {/* Writting of desired filter coefficients */
			/* Computes the index of coefficients to be uploaded */
			coeffs_index = (num_coeffs + i) - coeff_reg_length;
			/* Scaling the coefficient value and converting it to 2's complement */
			twos_complement = (int32_t)(coeffs[coeffs_index] * coeff_scale_factor);

			/* Write coefficients to COEFF_DATA */
			coeffs_buf[0] = AD77681_REG_WRITE(AD77681_REG_COEFF_DATA);
			coeffs_buf[1] = (twos_complement & 0xFF0000) >> 16;
			coeffs_buf[2] = (twos_complement & 0x00FF00) >> 8;
			coeffs_buf[3] = (twos_complement & 0x0000FF);
		}

		ret = spi_write_and_read(dev->spi_desc, coeffs_buf, 4);

		/* Check return value before proceeding */
		if (ret < 0)
			return ret;

		/* Increment the address*/
		address++;
		/* Wait for Twait uSeconds*/
		udelay(twait);
	}

	/* Disable coefficient write */
	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_COEFF_CONTROL,
				     AD77681_COEF_CONTROL_COEFFWRITEEN_MSK,
				     AD77681_COEF_CONTROL_COEFFWRITEEN(0x00));

	/* Check return value before proceeding */
	if (ret < 0)
		return ret;

	udelay(twait);

	/* Disable coefficient access */
	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_COEFF_CONTROL,
				     AD77681_COEF_CONTROL_COEFFACCESSEN_MSK,
				     AD77681_COEF_CONTROL_COEFFACCESSEN(0x00));

	/* Check return value before proceeding */
	if (ret < 0)
		return ret;

	/* Toggle the synchronization pulse and to begin reading data */
	/* Write 0x800000 to COEFF_DATA */
	coeffs_buf[0] = AD77681_REG_WRITE(AD77681_REG_COEFF_DATA);
	coeffs_buf[1] = 0x80;
	coeffs_buf[2] = 0x00;
	coeffs_buf[3] = 0x00;

	ret = spi_write_and_read(dev->spi_desc, coeffs_buf, 4);

	/* Check return value before proceeding */
	if (ret < 0)
		return ret;

	/* Exit filter upload by wirting specific access key 0x55*/
	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_ACCESS_KEY,
				     AD77681_ACCESS_KEY_MSK,
				     AD77681_ACCESS_KEY(key3));

	/* Check return value before proceeding */
	if (ret < 0)
		return ret;

	/* Send synchronization pulse */
	ad77681_initiate_sync(dev);

	return ret;
}

/**
 * Read value from GPIOs present in AD7768-1 separately, or all GPIOS at once.
 * @param dev - The device structure.
 * @param value	- Readed value.
 * @param gpio_number - Number of GPIO, the value will be written into
 *			Accepted values: AD77681_GPIO0
 *					 AD77681_GPIO1
 *					 AD77681_GPIO2
 *					 AD77681_GPIO3
 *					 AD77681_ALL_GPIOS
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_gpio_read(struct ad77681_dev *dev,
			  uint8_t *value,
			  enum ad77681_gpios gpio_number)
{
	int32_t ret;

	switch (gpio_number) {
	case AD77681_GPIO0:	/* Read to GPIO0 */
		ret = ad77681_spi_read_mask(dev,
					    AD77681_REG_GPIO_READ,
					    AD77681_GPIO_READ_0_MSK,
					    value);
		break;
	case AD77681_GPIO1:	/* Read to GPIO1 */
		ret = ad77681_spi_read_mask(dev,
					    AD77681_REG_GPIO_READ,
					    AD77681_GPIO_READ_1_MSK,
					    value);
		break;
	case AD77681_GPIO2:	/* Read to GPIO2 */
		ret = ad77681_spi_read_mask(dev,
					    AD77681_REG_GPIO_READ,
					    AD77681_GPIO_READ_2_MSK,
					    value);
		break;
	case AD77681_GPIO3:	/* Read to GPIO3 */
		ret = ad77681_spi_read_mask(dev,
					    AD77681_REG_GPIO_READ,
					    AD77681_GPIO_READ_3_MSK,
					    value);
		break;
	case AD77681_ALL_GPIOS: /* Read to all GPIOs */
		ret = ad77681_spi_read_mask(dev,
					    AD77681_REG_GPIO_READ,
					    AD77681_GPIO_READ_ALL_MSK,
					    value);
		break;
	default:
		return FAILURE;
		break;
	}

	return ret;
}

/**
 * Write value to GPIOs present in AD7768-1 separately, or all GPIOS at once.
 * @param dev - The device structure.
 * @param value - Value to be written into GPIO
 *		  Accepted values: GPIO_HIGH
 *				   GPIO_LOW
 *				   4-bit value for all gpios
 * @param gpio_number - Number of GPIO, the value will be written into
 *			Accepted values: AD77681_GPIO0
 *					 AD77681_GPIO1
 *					 AD77681_GPIO2
 *					 AD77681_GPIO3
 *					 AD77681_ALL_GPIOS
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_gpio_write(struct ad77681_dev *dev,
			   uint8_t value,
			   enum ad77681_gpios gpio_number)
{
	int32_t ret;

	switch (gpio_number) {
	case AD77681_GPIO0:	/* Write to GPIO0 */
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_GPIO_WRITE,
					     AD77681_GPIO_WRITE_0_MSK,
					     AD77681_GPIO_WRITE_0(value));
		break;
	case AD77681_GPIO1:	/* Write to GPIO1 */
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_GPIO_WRITE,
					     AD77681_GPIO_WRITE_1_MSK,
					     AD77681_GPIO_WRITE_1(value));
		break;
	case AD77681_GPIO2: /* Write to GPIO2 */
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_GPIO_WRITE,
					     AD77681_GPIO_WRITE_2_MSK,
					     AD77681_GPIO_WRITE_2(value));
		break;
	case AD77681_GPIO3: /* Write to GPIO3 */
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_GPIO_WRITE,
					     AD77681_GPIO_WRITE_3_MSK,
					     AD77681_GPIO_WRITE_3(value));
		break;
	case AD77681_ALL_GPIOS: /* Write to all GPIOs */
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_GPIO_WRITE,
					     AD77681_GPIO_WRITE_ALL_MSK,
					     AD77681_GPIO_WRITE_ALL(value));
		break;
	default:
		return FAILURE;
		break;
	}

	return ret;
}

/**
 * Set AD7768-1s GPIO as input or output.
 * @param dev - The device structure.
 * @param direction - Direction of the GPIO
 *			Accepted values: GPIO_INPUT
 *					 GPIO_OUTPUT
 *					 4-bit value for all gpios
 * @param gpio_number - Number of GPIO, which will be affected
 *			Accepted values: AD77681_GPIO0
 *					 AD77681_GPIO1
 *					 AD77681_GPIO2
 *					 AD77681_GPIO3
 *					 AD77681_ALL_GPIOS
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_gpio_inout(struct ad77681_dev *dev,
			   uint8_t direction,
			   enum ad77681_gpios gpio_number)
{
	int32_t ret;

	switch (gpio_number) {
	case AD77681_GPIO0:	/* Set direction of GPIO0 */
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_GPIO_CONTROL,
					     AD77681_GPIO_CNTRL_GPIO0_OP_EN_MSK,
					     AD77681_GPIO_CNTRL_GPIO0_OP_EN(direction));
		break;
	case AD77681_GPIO1:	/* Set direction of GPIO1 */
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_GPIO_CONTROL,
					     AD77681_GPIO_CNTRL_GPIO1_OP_EN_MSK,
					     AD77681_GPIO_CNTRL_GPIO1_OP_EN(direction));
		break;
	case AD77681_GPIO2:	/* Set direction of GPIO2 */
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_GPIO_CONTROL,
					     AD77681_GPIO_CNTRL_GPIO2_OP_EN_MSK,
					     AD77681_GPIO_CNTRL_GPIO2_OP_EN(direction));
		break;
	case AD77681_GPIO3:	/* Set direction of GPIO3 */
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_GPIO_CONTROL,
					     AD77681_GPIO_CNTRL_GPIO3_OP_EN_MSK,
					     AD77681_GPIO_CNTRL_GPIO3_OP_EN(direction));
		break;
	case AD77681_ALL_GPIOS:	/* Set direction of all GPIOs */
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_GPIO_CONTROL,
					     AD77681_GPIO_CNTRL_ALL_GPIOS_OP_EN_MSK,
					     AD77681_GPIO_CNTRL_ALL_GPIOS_OP_EN(direction));
		break;
	default:
		return FAILURE;
		break;
	}

	return ret;
}

/**
 * Enable global GPIO bit.
 * This bit must be set high to change GPIO settings.
 * @param dev - The device structure.
 * @param gpio_enable - Enable or diable the global GPIO pin
 *			Accepted values: AD77681_GLOBAL_GPIO_ENABLE
 *					 AD77681_GLOBAL_GPIO_DISABLE
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_global_gpio(struct ad77681_dev *dev,
			    enum ad77681_gobal_gpio_enable gpio_enable)
{
	return ad77681_spi_write_mask(dev,
				      AD77681_REG_GPIO_CONTROL,
				      AD77681_GPIO_CNTRL_UGPIO_EN_MSK,
				      AD77681_GPIO_CNTRL_UGPIO_EN(gpio_enable));
}

/**
 * Read and write from ADC scratchpad register to check SPI Communication in
 * the very beginning, during inicialization.
 * @param dev - The device structure.
 * @param sequence - The sequence which will be written into scratchpad and the
 * 		      readed sequence will be returned
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_scratchpad(struct ad77681_dev *dev,
			   uint8_t *sequence)
{
	int32_t ret;
	const uint8_t check = *sequence;/* Save the original sequence */
	uint8_t ret_sequence = 0;/* Return sequence */

	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_SCRATCH_PAD,
				     AD77681_SCRATCHPAD_MSK,
				     AD77681_SCRATCHPAD(check));

	ret |= ad77681_spi_read_mask(dev,
				     AD77681_REG_SCRATCH_PAD,
				     AD77681_SCRATCHPAD_MSK,
				     &ret_sequence);

	if (check != ret_sequence)/* Compare original an returned sequence */
		return FAILURE;

	return ret;
}

/**
 * Set AD7768-1s GPIO output type between strong driver and open drain.
 * GPIO3 can not be accessed!
 * @param dev - The device structure.
 * @param gpio_number - AD7768-1s GPIO to be affected (Only GPIO0, GPIO1 and GPIO2)
 *			Accepted values: AD77681_GPIO0
 *					 AD77681_GPIO1
 *					 AD77681_GPIO2
 *					 AD77681_ALL_GPIOS
 *
 * @param output_type - Output type of the GPIO
 *			Accepted values: AD77681_GPIO_STRONG_DRIVER
 *					 AD77681_GPIO_OPEN_DRAIN
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_gpio_open_drain(struct ad77681_dev *dev,
				enum ad77681_gpios gpio_number,
				enum ad77681_gpio_output_type output_type)
{
	int32_t ret;

	switch (gpio_number) {
	case AD77681_GPIO0: /* Set ouptut type of GPIO0 */
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_GPIO_CONTROL,
					     AD77681_GPIO_CNTRL_GPIO0_OD_EN_MSK,
					     AD77681_GPIO_CNTRL_GPIO0_OD_EN(output_type));
		break;
	case AD77681_GPIO1: /* Set ouptut type of GPIO1 */
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_GPIO_CONTROL,
					     AD77681_GPIO_CNTRL_GPIO1_OD_EN_MSK,
					     AD77681_GPIO_CNTRL_GPIO1_OD_EN(output_type));
		break;
	case AD77681_GPIO2: /* Set ouptut type of GPIO2 */
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_GPIO_CONTROL,
					     AD77681_GPIO_CNTRL_GPIO2_OD_EN_MSK,
					     AD77681_GPIO_CNTRL_GPIO2_OD_EN(output_type));
		break;
	case AD77681_ALL_GPIOS: /* Set ouptut type of all GPIOs */
		ret = ad77681_spi_write_mask(dev,
					     AD77681_REG_GPIO_CONTROL,
					     AD77681_GPIO_CNTRL_ALL_GPIOS_OD_EN_MSK,
					     AD77681_GPIO_CNTRL_ALL_GPIOS_OD_EN(output_type));
		break;
	default:
		return FAILURE;
		break;
	}

	return ret;
}

/**
 * Clear all error flags at once
 * @param dev - The device structure.
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_clear_error_flags(struct ad77681_dev *dev)
{
	int32_t ret;

	/* SPI ignore error CLEAR */
	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_SPI_DIAG_STATUS,
				     AD77681_SPI_IGNORE_ERROR_MSK,
				     AD77681_SPI_IGNORE_ERROR_CLR(ENABLE));
	/* SPI read error CLEAR */
	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_SPI_DIAG_STATUS,
				      AD77681_SPI_READ_ERROR_MSK,
				      AD77681_SPI_READ_ERROR_CLR(ENABLE));
	/* SPI write error CLEAR */
	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_SPI_DIAG_STATUS,
				      AD77681_SPI_WRITE_ERROR_MSK,
				      AD77681_SPI_WRITE_ERROR_CLR(ENABLE));
	/* SPI CRC error CLEAR */
	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_SPI_DIAG_STATUS,
				      AD77681_SPI_CRC_ERROR_MSK,
				      AD77681_SPI_CRC_ERROR_CLR(ENABLE));

	return ret;
}

/**
 * Enabling error flags. All error flags enabled by default
 * @param dev - The device structure.
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_error_flags_enabe(struct ad77681_dev *dev)
{
	int32_t ret;

	/* SPI ERRORS ENABLE */
	/* SPI ignore error enable */
	ret = ad77681_spi_write_mask(dev,
				     AD77681_REG_SPI_DIAG_ENABLE,
				     AD77681_SPI_DIAG_ERR_SPI_IGNORE_MSK,
				     AD77681_SPI_DIAG_ERR_SPI_IGNORE(ENABLE));
	/*  SPI Clock count error enable */
	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_SPI_DIAG_ENABLE,
				      AD77681_SPI_DIAG_ERR_SPI_CLK_CNT_MSK,
				      AD77681_SPI_DIAG_ERR_SPI_CLK_CNT(ENABLE));
	/* SPI Read error enable */
	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_SPI_DIAG_ENABLE,
				      AD77681_SPI_DIAG_ERR_SPI_RD_MSK,
				      AD77681_SPI_DIAG_ERR_SPI_RD(ENABLE));
	/* SPI Write error enable */
	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_SPI_DIAG_ENABLE,
				      AD77681_SPI_DIAG_ERR_SPI_WR_MSK,
				      AD77681_SPI_DIAG_ERR_SPI_WR(ENABLE));

	/* ADC DIAG ERRORS ENABLE */
	/* DLDO PSM error enable */
	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_ADC_DIAG_ENABLE,
				      AD77681_ADC_DIAG_ERR_DLDO_PSM_MSK,
				      AD77681_ADC_DIAG_ERR_DLDO_PSM(ENABLE));
	/* ALDO PSM error enable */
	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_ADC_DIAG_ENABLE,
				      AD77681_ADC_DIAG_ERR_ALDO_PSM_MSK,
				      AD77681_ADC_DIAG_ERR_ALDO_PSM(ENABLE));
	/* Filter saturated error enable */
	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_ADC_DIAG_ENABLE,
				      AD77681_ADC_DIAG_ERR_FILT_SAT_MSK,
				      AD77681_ADC_DIAG_ERR_FILT_SAT(ENABLE));
	/* Filter not settled error enable */
	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_ADC_DIAG_ENABLE,
				      AD77681_ADC_DIAG_ERR_FILT_NOT_SET_MSK,
				      AD77681_ADC_DIAG_ERR_FILT_NOT_SET(ENABLE));
	/* External clock check error enable */
	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_ADC_DIAG_ENABLE,
				      AD77681_ADC_DIAG_ERR_EXT_CLK_QUAL_MSK,
				      AD77681_ADC_DIAG_ERR_EXT_CLK_QUAL(ENABLE));

	/* DIG DIAG ENABLE */
	/* Memory map CRC error enabled */
	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_DIG_DIAG_ENABLE,
				      AD77681_DIG_DIAG_ERR_MEMMAP_CRC_MSK,
				      AD77681_DIG_DIAG_ERR_MEMMAP_CRC(ENABLE));
	/* RAM CRC error enabled */
	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_DIG_DIAG_ENABLE,
				      AD77681_DIG_DIAG_ERR_RAM_CRC_MSK,
				      AD77681_DIG_DIAG_ERR_RAM_CRC(ENABLE));
	/* FUSE CRC error enabled */
	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_DIG_DIAG_ENABLE,
				      AD77681_DIG_DIAG_ERR_FUSE_CRC_MSK,
				      AD77681_DIG_DIAG_ERR_FUSE_CRC(ENABLE));
	/* Enable MCLK Counter */
	ret |= ad77681_spi_write_mask(dev,
				      AD77681_REG_DIG_DIAG_ENABLE,
				      AD77681_DIG_DIAG_FREQ_COUNT_EN_MSK,
				      AD77681_DIG_DIAG_FREQ_COUNT_EN(ENABLE));

	return ret;
}

/**
 * Read from all ADC status registers
 * @param dev - The device structure.
 * @param status - Structure with all satuts bits
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_status(struct ad77681_dev *dev,
		       struct ad77681_status_registers *status)
{
	int32_t ret;
	uint8_t buf[3];

	/* Master status register */
	ret = ad77681_spi_reg_read(dev, AD77681_REG_MASTER_STATUS,buf);
	status->master_error = buf[1] & AD77681_MASTER_ERROR_MSK;
	status->adc_error = buf[1] & AD77681_MASTER_ADC_ERROR_MSK;
	status->dig_error = buf[1] & AD77681_MASTER_DIG_ERROR_MSK;
	status->adc_err_ext_clk_qual = buf[1] & AD77681_MASTER_DIG_ERR_EXT_CLK_MSK;
	status->adc_filt_saturated = buf[1] & AD77681_MASTER_FILT_SAT_MSK;
	status->adc_filt_not_settled = buf[1] & AD77681_MASTER_FILT_NOT_SET_MSK;
	status->spi_error = buf[1] & AD77681_MASTER_SPI_ERROR_MSK;
	status->por_flag = buf[1] & AD77681_MASTER_POR_FLAG_MSK;
	/* SPI diag status register */
	ret |= ad77681_spi_reg_read(dev, AD77681_REG_SPI_DIAG_STATUS, buf);
	status->spi_ignore = buf[1] & AD77681_SPI_IGNORE_ERROR_MSK;
	status->spi_clock_count = buf[1] & AD77681_SPI_CLK_CNT_ERROR_MSK;
	status->spi_read_error = buf[1] & AD77681_SPI_READ_ERROR_MSK;
	status->spi_write_error = buf[1] & AD77681_SPI_WRITE_ERROR_MSK;
	status->spi_crc_error = buf[1] & AD77681_SPI_CRC_ERROR_MSK;
	/* ADC diag status register */
	ret |= ad77681_spi_reg_read(dev, AD77681_REG_ADC_DIAG_STATUS,buf);
	status->dldo_psm_error = buf[1] & AD77681_ADC_DLDO_PSM_ERROR_MSK;
	status->aldo_psm_error = buf[1] & AD77681_ADC_ALDO_PSM_ERROR_MSK;
	status->ref_det_error = buf[1] & AD77681_ADC_REF_DET_ERROR_MSK;
	status->filt_sat_error = buf[1] & AD77681_ADC_FILT_SAT_MSK;
	status->filt_not_set_error = buf[1] & AD77681_ADC_FILT_NOT_SET_MSK;
	status->ext_clk_qual_error = buf[1] & AD77681_ADC_DIG_ERR_EXT_CLK_MSK;
	/* DIG diag status register */
	ret |= ad77681_spi_reg_read(dev, AD77681_REG_DIG_DIAG_STATUS,buf);
	status->memoy_map_crc_error = buf[1] & AD77681_DIG_MEMMAP_CRC_ERROR_MSK;
	status->ram_crc_error = buf[1] & AD77681_DIG_RAM_CRC_ERROR_MSK;
	status->fuse_crc_error = buf[1] & AD77681_DIG_FUS_CRC_ERROR_MSK;

	return ret;
}

/**
 * Initialize the device.
 * @param device - The device structure.
 * @param init_param - The structure that contains the device initial
 * 					   parameters.
 * @param status - The structure that will contains the ADC status
 * @return 0 in case of success, negative error code otherwise.
 */
int32_t ad77681_setup(struct ad77681_dev **device,
		      struct ad77681_init_param init_param,
		      struct ad77681_status_registers **status)
{
	struct ad77681_dev *dev;
	struct ad77681_status_registers *stat;
	int32_t ret;
	uint8_t scratchpad_check = 0xAD;

	dev = (struct ad77681_dev *)malloc(sizeof(*dev));
	if (!dev) {
		return -1;
	}

	stat = (struct ad77681_status_registers *)malloc(sizeof(*stat));
	if (!stat) {
		free(dev);
		return -1;
	}

	dev->power_mode = init_param.power_mode;
	dev->mclk_div = init_param.mclk_div;
	dev->conv_diag_sel = init_param.conv_diag_sel;
	dev->conv_mode = init_param.conv_mode;
	dev->diag_mux_sel = init_param.diag_mux_sel;
	dev->conv_len = init_param.conv_len;
	dev->crc_sel = AD77681_NO_CRC;
	dev->status_bit = init_param.status_bit;
	dev->VCM_out = init_param.VCM_out;
	dev->AINn = init_param.AINn;
	dev->AINp = init_param.AINp;
	dev->REFn = init_param.REFn;
	dev->REFp = init_param.REFp;
	dev->filter = init_param.filter;
	dev->decimate = init_param.decimate;
	dev->sinc3_osr = init_param.sinc3_osr;
	dev->vref = init_param.vref;
	dev->mclk = init_param.mclk;
	dev->sample_rate = init_param.sample_rate;
	dev->data_frame_byte = init_param.data_frame_byte;

	ret = spi_init(&dev->spi_desc, &init_param.spi_eng_dev_init);
	if (ret < 0) {
		free(dev);
		free(stat);
		return ret;
	}

	ret |= ad77681_soft_reset(dev);

	udelay(200);

	/* Check physical connection using scratchpad*/
	if (ad77681_scratchpad(dev, &scratchpad_check) == FAILURE) {
		scratchpad_check = 0xAD;/* If failure, second try */
		ret |= (ad77681_scratchpad(dev, &scratchpad_check));
		if(ret == FAILURE) {
			free(dev);
			free(stat);
			return ret;
		}
	}
	ret |= ad77681_set_power_mode(dev, dev->power_mode);
	ret |= ad77681_set_mclk_div(dev, dev->mclk_div);
	ret |= ad77681_set_conv_mode(dev,
				     dev->conv_mode,
				     dev->diag_mux_sel,
				     dev->conv_diag_sel);
	ret |= ad77681_set_convlen(dev, dev->conv_len);
	ret |= ad77681_set_status_bit(dev, dev->status_bit);
	ret |= ad77681_set_crc_sel(dev, init_param.crc_sel);
	ret |= ad77681_set_VCM_output(dev, dev->VCM_out);
	ret |= ad77681_set_AINn_buffer(dev, dev->AINn);
	ret |= ad77681_set_AINp_buffer(dev, dev->AINp);
	ret |= ad77681_set_REFn_buffer(dev, dev->REFn);
	ret |= ad77681_set_REFp_buffer(dev, dev->REFp);
	ret |= ad77681_set_filter_type(dev, dev->decimate, dev->filter, dev->sinc3_osr);
	ret |= ad77681_error_flags_enabe(dev);
	ret |= ad77681_clear_error_flags(dev);
	ret |= ad77681_status(dev, stat);
	ad77681_get_frame_byte(dev);
	ad77681_update_sample_rate(dev);
	*status = stat;
	*device = dev;

	if (!ret)
		printf("ad77681 successfully initialized\n");

	return ret;
}