/******************************************************************************
 *
 * 2017 (c) Lattice Semiconductor Corporation
 * 
 * This program is free software; you can redistribute it and/or
 * modify it only under the terms of version 2 of the GNU General Public License
 * as published by the Free Software Foundation, and not any later version.
 * 
 * This program is distributed "AS IS" WITHOUT ANY WARRANTY of any kind,
 * whether express or implied, including without limitation the implied warranty
 * of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 
 * You may contact Lattice Semiconductor Corporation at 
 * 111 SW 5th Ave, Suite 700, Portland, OR 97204.
 *
 *****************************************************************************/

/**
 * @file sii9438.c
 *
 * @brief Driver for sii9438 (eARC/ARC transmitter)
 *
 *****************************************************************************/
 #define SII_DEBUG	3

/***** #include statements ***************************************************/
#include "sii9438_drv.h"
#include "sii9438_api.h"
#include "sii_sys_log_api.h"
#include "sii_drv_cra_api.h"
#include "sii9438_regs.h"
#include "sii_sys_time_api.h"
#include "sii_system_api.h"
#include "sii_lib_data.h"

/***** Register Module name **************************************************/
SII_MODULE_NAME_SET(9438TxHal);


/***** local macro definitions ***********************************************/

/* Timer scale and counts used for 1ms resolution */
/* Timer scale needed as per formula:
 * Required time = 50ns * (timer_count + 1) * (timer_scale + 1)
 * For 1ms timer: (timer_count + 1) * (timer_scale + 1) = 20000
 *	for which timer scale can be 9999 = 0x270F
 *	and timer count (2 - 1) = 1
 * Timer count ref is taken as 2 so that for n ms timer the timer count
 * will be (n*2 - 1)
 */
#define	SII943X_TIMER_SCALE		0x270F
#define	SII943X_TIMER_COUNT_VALUE_REF	0x0002

#define SII943X_ECC_MASK		0x3A
#define SII943X_ECC_PATTERN		0x02

#define SII9438_TX_TIMEOUT		0x1DB /* 475ms */

/***** local type definitions ************************************************/


/***** local prototypes ******************************************************/
static void s_int_mask_init(uint32_t dev_id);
static bool_t s_is_caps_ds_avail(uint32_t dev_id);
static void caps_ds_audio_data_print(char *pName, uint8_t *p_caps_ds,
		uint16_t size);

/***** local data objects ****************************************************/


/***** call-back functions ***************************************************/


/***** public functions ******************************************************/
uint32_t sii9438_hal_initialize(uint32_t dev_id,
				const struct sii9438_config *p_config)
{
	uint8_t chip_id = 0;

	/* override i2c address */
	/* Override I2C address for eARC TX SW TPI*/
	sii_drv_cra_write8(dev_id, REG_ADDR__I2C_ADDR0,
			p_config->i2c_addr_page1);
	/* Override I2C address for eARC TX HW TPI*/
	sii_drv_cra_write8(dev_id, REG_ADDR__I2C_ADDR1,
			p_config->i2c_addr_page2);
	/* Override I2C address for eARC TX core registers*/
	sii_drv_cra_write8(dev_id, REG_ADDR__I2C_ADDR2,
			p_config->i2c_addr_page3);
	/* Override Unused address*/
	sii_drv_cra_write8(dev_id, REG_ADDR__I2C_ADDR3, 0x00);
	/* Override I2C address for PHY registers*/
	sii_drv_cra_write8(dev_id, REG_ADDR__I2C_ADDR4,
			p_config->i2c_addr_page4);
	/* Expose the other slave addresses beside slave address 0x60*/
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__I2C_CONFIG,
				BIT_MSK__I2C_CONFIG__REG_EXPOSE_SLAVE_ADDR,
				TRUE);

	/* Disable IDLE2 state */
	sii9438_hal_idle2_enable(dev_id, TRUE);

	/* set to tx chip */
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__CHIP_ID_I2C,
					BIT_MASK__CHIP_ID_I2C_TX, TRUE);

	chip_id = sii_drv_cra_read8(dev_id,
			REG_ADDR__DEV_IDL);

	sii_drv_cra_write8(dev_id, REG_ADDR__EARC_CFG_1,
			(BIT_MSK__EARC_CFG1__CM_LEVEL_CTRL_300MV |
			BIT_MSK__EARC_CFG1__ARC_MODE_CTRL_CM));
	if (chip_id == 0x3A) {
		/**p_chip_version = 1;*/
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_SLEW_N_SWING, 0x52);
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_FEM_CFG, 0x64);
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_SPRX, 0x21);
	} else if (chip_id == 0x38) {
		/**p_chip_version = 0;*/
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_SLEW_N_SWING, 0x56);
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_SPRX, 0xA3);
	}

	/* Set N_eARC_Tx_Comma_Count to 3, number of commas monitor before
	 * starting heartbeat */
	sii_drv_cra_write8(dev_id, REG_ADDR__COMMA_DET13, 0x03);

	/* Set Tx timeout vlaue */
	sii9438_hal_tx_timeout_set(dev_id, SII9438_TX_TIMEOUT);

	sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_CM_BW_CTL, 0x08);

	sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_PLL_1, 0x84);
	/* choose eArc mode */
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__VIOLA_MODE,
			BIT_MSK__VIOLA_MODE__REG_ARC_DIR |
			BIT_MSK__VIOLA_MODE__REG_AUTO_CFG, FALSE);

	/* disable test mode */
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__TEST_CTRL,
				BIT_MSK__TEST_CTRL__REG_TEST_EN,
				FALSE);
	/* i2s enables, set sd0-sd4 */
	sii_drv_cra_write8(dev_id, REG_ADDR__AUD_MODE, 0xFB);
	/* cfg i2s clk edge */
	sii_drv_cra_write8(dev_id, REG_ADDR__I2S_IN_CTRL, 0x40);


	/* BSYNC Preample value */
	sii_drv_cra_write8(dev_id, REG_ADDR__BSYNC_VAL, 0xE8);
	/* enable Capability Data Structure */
	sii_drv_cra_write8(dev_id, REG_ADDR__EDID_CTRL, 0x51);

	/* Override SPDIF Channel Status */
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__TX_SPDIF_CS_CTRL,
			BIT_MSK__TX_SPDIF_CS_CTRL__REG_CBIT_OVERRIDE, TRUE);

	sii_drv_cra_write8(dev_id, REG_ADDR__TX_MUTE_CTRL_3, 0x80);
	/* "2" to enable check of mute_in pin (on Tx)
	   "6" to enable zero of the data if mute is triggered
	 * */
	sii_drv_cra_write8(dev_id, REG_ADDR__TX_MUTE_CTRL_2, 0x44);
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__IO_OEN,
			BIT_MSK__IO_OEN__REG_MUTE_OEN,
			TRUE);

	/* Debug registers. Should be programmed to 0x00. */
	sii_drv_cra_write8(dev_id, REG_ADDR__TX_CS_DEBUG1, 0x00);
	sii_drv_cra_write8(dev_id, REG_ADDR__TX_CS_DEBUG2, 0x00);
	sii_drv_cra_write8(dev_id, REG_ADDR__TX_CS_DEBUG3, 0x00);

	/* Enable GPIO4 as HPD-IN  */
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__GPIO_OEN_CTRL, BIT__GPIO_NUM_4,
				TRUE);

	/* Enable GPIO5 as HPD-OUT
	 * First make TX_HPD_OUT low and enable it as output */
	sii9438_hal_hpd_out_set(dev_id, FALSE);
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__GPIO_OEN_CTRL, BIT__GPIO_NUM_5,
						FALSE);

	/* Virtual HDMI HPD Override enable to send hpd over
	 * heartbeat when eARC is connected */
	sii9438_hal_virtual_hdmi_hpd_enable_set(dev_id, TRUE);

	/* STAT_CHNG_CONF override enable to send over heartbeat */
	sii9438_hal_stat_chng_conf_enable_set(dev_id, TRUE);

	/* CAP_CHNG_CONF override enable to send over heartbeat */
	sii9438_hal_cap_chng_conf_enable_set(dev_id, TRUE);

	/* Enable timer in one shot mode */
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__TIMER_CTRL,
			BIT_MASK__TIMER_CTRL__REG_TIMER_CONFIG_ENABLE,
			TRUE);
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__TIMER_CTRL,
			BIT_MASK__TIMER_CTRL__REG_TIMER_CONFIG_MODE,
			FALSE);

	/* Timer scale */
	sii_drv_cra_write16(dev_id, REG_ADDR__TIMER_SCALE1,
			SII943X_TIMER_SCALE);

	/* Initialize ECC Mask */
	sii9438_hal_ecc_mask_init(dev_id);

	/* Disable ECC by default.
	 * Will be enabled for non-lpcm during channel status update */
	sii9438_hal_ecc_enable(dev_id, FALSE);

	/* Set offset of extra byte 1 in channel status : byte 17
	 * (from bit 136) */
	sii_drv_cra_write8(dev_id, REG_ADDR__I2S_CS_PTR,
			BIT_MSK__I2S_CS_PTR__REG_CS_OFFSET);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_timer_value_set(uint32_t dev_id, uint16_t time_value_ms)
{
	uint16_t timer_count = 0;

	if (time_value_ms)
		timer_count = (time_value_ms *
			SII943X_TIMER_COUNT_VALUE_REF) - 1;

	sii_drv_cra_write16(dev_id, REG_ADDR__TIMER_VAL0, timer_count);

	if (!time_value_ms) {
		uint16_t wait_count = 10;
		while (0 == (sii_drv_cra_read8(dev_id, REG_ADDR__TOP_INTR1) &
				BIT_MASK__TOP_INTR1_MASK__TOP_TIMER)) {
			SII_LOG3A("", NULL, ("Waiting for Timer Interrupt"));
			wait_count--;
			if (wait_count <= 0)
				break;
		}
		sii_drv_cra_write8(dev_id, REG_ADDR__TOP_INTR1,
				BIT_MASK__TOP_INTR1_MASK__TOP_TIMER);
	}

	/* First get will be always 0. So a dummy read*/
	sii9438_hal_timer_value_get(dev_id, &timer_count);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_timer_value_get(uint32_t dev_id, uint16_t *time_value_ms)
{
	uint16_t timer_count = 0;
	timer_count = sii_drv_cra_read16(dev_id, REG_ADDR__TIMER_VAL0);

	/* Use ceil[timer_count/timer_count_ref] to round off sub millisecond
	 * timer value */
	if (timer_count) {
		timer_count++;
		if (timer_count % SII943X_TIMER_COUNT_VALUE_REF) {
			timer_count /= SII943X_TIMER_COUNT_VALUE_REF;
			timer_count++;
		} else {
			timer_count /= SII943X_TIMER_COUNT_VALUE_REF;
		}
	}

	*time_value_ms = timer_count;

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_gpio_query(uint32_t dev_id, uint16_t *p_gpio_pin_mask)
{
	*p_gpio_pin_mask = sii_drv_cra_read8(dev_id, REG_ADDR__GPIO_C_CTRL);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_gpio_config(uint32_t dev_id, uint16_t *gpio_pin_io_config)
{
	/* Enable output registers: 0 - enables output */
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__GPIO_OEN_CTRL,
		(BIT_MSK__GPIO_OEN_CTRL__REG_GPIO_OEN & *gpio_pin_io_config),
		FALSE);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_gpio_output_update(uint32_t dev_id,
		uint16_t *p_gpio_pin_mask, bool_t b_set)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__GPIO_I_CTRL,
			(BIT_MSK__GPIO_I_CTRL__REG_GPIO_I & *p_gpio_pin_mask),
			b_set);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_chip_reset(uint32_t dev_id)
{
	uint32_t milli_to;
	sii_sys_time_out_milli_set(&milli_to, 100);

	/* Trigger reset */
	sii_drv_cra_write8(dev_id, REG_ADDR__TOP_SWHRST, 0x80);
	/* wait for reset done or time out */
	while (sii_drv_cra_read8(dev_id, REG_ADDR__TOP_SWHRST) &&
		(!sii_sys_time_out_milli_is(&milli_to)))
		;

	SII_LOG2A("", NULL, ("Tx Reset Done"));

	return SII_RETURN_VALUE__SUCCESS;
}

bool_t s_is_read_next_block(uint8_t *p_caps_ds)
{
	uint8_t caps_ds_byte;
	uint16_t index = 0;
	uint16_t raw_block_length = 0;
	bool_t status = FALSE;

	if (p_caps_ds[index++] != SII_EARC_CAP_DATA_STRUCT_VERSION)
		return FALSE;

	caps_ds_byte = p_caps_ds[index++];
	while (caps_ds_byte) {
		raw_block_length = p_caps_ds[index++];
		if ((index + raw_block_length) > 127) {
			status = TRUE;
			break;
		} else {
			index += raw_block_length;
		}
		caps_ds_byte = p_caps_ds[index++];
	}

	return status;
}

uint32_t sii9438_hal_caps_ds_get(uint32_t dev_id, uint8_t *p_caps_ds)
{
	/* Device Address for Capability Data Structure Segment 0 */
	sii_drv_cra_write8(dev_id, REG_ADDR__EDID_DEV_ADDR, 0xA0);
	sii_drv_cra_write8(dev_id, REG_ADDR__EDID_RST, 0x01);
	/* Set Downstream-retrived Caps data to be written into FIFO
	 * from 0x000 - 0x07F (1st half) */
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__EDID_CTRL,
			BIT_MSK__EDID_CTRL__REG_EDID_FIFO_B_SEL, FALSE);
	/* Start to get Caps DS block 0. Self-resetting to 0*/
	sii_drv_cra_bits_set8(dev_id,
			REG_ADDR__EDID_START_EXT0,
			BIT_MSK__EDID_START_EXT0__REG_GET_EDID_START_0,
			TRUE);
	if (s_is_caps_ds_avail(dev_id)) {
		sii_drv_cra_write8(dev_id,
				REG_ADDR__EDID_FIFO_ADDR, 0);
		sii_drv_cra_fifo_read8(dev_id,
				REG_ADDR__EDID_FIFO_DATA,
				p_caps_ds,
				SII_CAPS_DS_BLOCK_SIZE);
		caps_ds_audio_data_print("eARCRxCapsDataStructBlock0",
				p_caps_ds,
				SII_CAPS_DS_BLOCK_SIZE);
	}

	if (s_is_read_next_block(p_caps_ds)) {
		sii_drv_cra_write8(dev_id, REG_ADDR__EDID_DEV_ADDR, 0xA0);
		sii_drv_cra_write8(dev_id, REG_ADDR__EDID_RST, 0x01);
		/* Set Downstream-retrieved Caps data to be written into FIFO
		 * from 0x000 - 0x07F (1st half) */
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__EDID_CTRL,
				BIT_MSK__EDID_CTRL__REG_EDID_FIFO_B_SEL, TRUE);
		/* Start to get Caps DS block 1. Self-resetting to 0*/
		sii_drv_cra_bits_set8(dev_id,
				REG_ADDR__EDID_START_EXT1,
				BIT_MSK__EDID_START_EXT1__REG_GET_EDID_START_1,
				TRUE);
		if (s_is_caps_ds_avail(dev_id)) {
			sii_drv_cra_write8(dev_id,
					REG_ADDR__EDID_FIFO_ADDR,
					SII_CAPS_DS_BLOCK_SIZE);
			sii_drv_cra_fifo_read8(dev_id,
					REG_ADDR__EDID_FIFO_DATA,
					(p_caps_ds + SII_CAPS_DS_BLOCK_SIZE),
					SII_CAPS_DS_BLOCK_SIZE);
			caps_ds_audio_data_print("eARCRxCapsDataStructBlock0",
					(p_caps_ds + SII_CAPS_DS_BLOCK_SIZE),
					SII_CAPS_DS_BLOCK_SIZE);
		}
	}

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_ecc_mask_init(uint32_t dev_id)
{
	/* pointer to starting bit of cs byte w/ compressed bit (cs #0)
	 * 0x0 * 8 = 0x00 (0th bit) */
	sii_drv_cra_write8(dev_id, REG_ADDR__TX_CS_ECC_PTR, 0x00);

	/* mask - compare bits 1, 3, 4 & 5 */
	sii_drv_cra_write8(dev_id, REG_ADDR__TX_CS_ECC_MASK, SII943X_ECC_MASK);

	/* bits 1, 3, 4 & 5 value to match for ecc on: 1, 0, 0, 0 */
	sii_drv_cra_write8(dev_id, REG_ADDR__TX_CS_ECC_PATTERN,
			SII943X_ECC_PATTERN);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_ecc_enable(uint32_t dev_id, bool_t b_en)
{
	/* enable ecc if ecc=on and enable BCH interleaving */
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__BCH_CTRL,
			(BIT_MSK__BCH_CTRL__REG_ECC_ENABLE |
			BIT_MSK__BCH_CTRL__REG_BCHINTV_EN), b_en);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_ecc_status(uint32_t dev_id, bool_t *p_b_on)
{
	if (p_b_on) {
		*p_b_on = sii_drv_cra_read8(dev_id, REG_ADDR__BCH_STAT) &
			BIT_MSK__BCH_STAT__ECC_ENC_ON ? TRUE : FALSE;
	}

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_ecc_err_cnt_get(uint32_t dev_id, uint16_t *p_err_cnt)
{
	if (p_err_cnt)
		*p_err_cnt = sii_drv_cra_read16(dev_id, REG_ADDR__PKT_TOP_TX13);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_ecc_err_cnt_clear(uint32_t dev_id)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__PKT_TOP_TX12,
		BIT_MSK__PKT_TOP_TX12__REG_CMC_TX_PKT_ECC_ERR_CLR, TRUE);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_ecc_err_fixed_cnt_get(uint32_t dev_id,
		uint16_t *p_err_fixed_cnt)
{
	if (p_err_fixed_cnt)
		*p_err_fixed_cnt = sii_drv_cra_read16(dev_id,
				REG_ADDR__PKT_TOP_TX16);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_ecc_err_fixed_cnt_clear(uint32_t dev_id)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__PKT_TOP_TX15,
		BIT_MSK__PKT_TOP_TX15__REG_CMC_TX_PKT_ECC_FIX_CLR, TRUE);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii_hal_channel_status_update(uint32_t dev_id,
				 uint8_t *p_ch_stat,
				 uint16_t size)
{
	/*s_aud_info_set(p_ch_stat, p_aif);*/

	sii_drv_cra_block_write8(dev_id, REG_ADDR__I2S_CHST0,
				p_ch_stat, size);
	/* Set offset of extra byte 1 in channel status : byte 17
	 * (from bit 136) */
	sii_drv_cra_write8(dev_id, REG_ADDR__I2S_CS_PTR,
			BIT_MSK__I2S_CS_PTR__REG_CS_UPDATE_EN |
			BIT_MSK__I2S_CS_PTR__REG_CS_OFFSET);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii_hal_freq_zone_set(uint32_t dev_id,
			enum  sii9438_freq_zone freq_zone)
{
	uint8_t zone = freq_zone << BIT_MSK__VIOLA_MODE__REG_TX_ZONE_SHIFT;

	/* b6.5: set 4x zone, b7: zone override */
	sii_drv_cra_bits_mod8(dev_id,
			REG_ADDR__VIOLA_VCO_CAL,
			BIT_MSK__VIOLA_MODE__REG_TX_ZONE |
			BIT_MSK__VIOLA_VCO_CAL__REG_ZONE_OVR,
			BIT_MSK__VIOLA_VCO_CAL__REG_ZONE_OVR | zone);
	SII_LOG3A("", NULL,
			("Freq Zone: %d\n", freq_zone));

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii_hal_audio_mode_set(uint32_t dev_id,
			enum  sii9438_insertion_mode ins_mode)
{
	switch (ins_mode) {
	case SII9438_INSERTION_MODE__SPDIF2:
	case SII9438_INSERTION_MODE__SPDIF8:
		/* b1: enable spdif input */
		sii_drv_cra_write8(dev_id,
				REG_ADDR__TX_SPDIF_MODE,
				(BIT_MSK__TX_SPDIF_MODE__REG_TX_SPDIF_EN |
				BIT_MSK__TX_SPDIF_MODE__REG_TX_BYP_SAMPLER |
				BIT_MSK__TX_SPDIF_MODE__REG_F_PREAMBLE_EN));

		/* b0: enable audio input, b7.0: disable i2s audio */
		sii_drv_cra_write8(dev_id,
				REG_ADDR__AUD_MODE, 0x01);

		/* clk sel */
		sii_drv_cra_write8(dev_id,
				REG_ADDR__CLK_SEL, BIT_MSK__BY_PASS_CLK_EXT);

		SII_LOG2A("", NULL, ("Audio Insertion Mode: SPDIF\n"));
		break;
	case SII9438_INSERTION_MODE__I2S2:
	case SII9438_INSERTION_MODE__I2S8:
		/* b1: enable spdif input */
		sii_drv_cra_write8(dev_id,
				REG_ADDR__TX_SPDIF_MODE, 0x00);

		/* b0: enable audio input, b7.0: disable i2s audio */
		sii_drv_cra_write8(dev_id,
				REG_ADDR__AUD_MODE, 0xF3);

		/* clk sel */
		sii_drv_cra_write8(dev_id,
				REG_ADDR__CLK_SEL, 0x00);

		SII_LOG2A("", NULL, ("Audio Insertion Mode: I2S\n"));

		break;
	case SII9438_INSERTION_MODE__NONE:
		/* b0: enable audio input, b7.0: disable i2s audio */
		sii_drv_cra_write8(dev_id,
				REG_ADDR__AUD_MODE, 0x00);
		/* b1: enable spdif input */
		sii_drv_cra_write8(dev_id,
				REG_ADDR__TX_SPDIF_MODE, 0x00);

		SII_LOG2A("", NULL, ("Audio Insertion Mode: NONE\n"));
		break;
	default:
		/* b0: enable audio input, b7.0: disable i2s audio */
		sii_drv_cra_write8(dev_id,
				REG_ADDR__AUD_MODE, 0x00);
		/* b1: enable spdif input */
		sii_drv_cra_write8(dev_id,
				REG_ADDR__TX_SPDIF_MODE, 0x00);
		SII_LOG2A("", NULL, ("Audio Insertion Mode: Error\n"));
		SII_LOG2A("", NULL, ("Audio Insertion Mode: Set to NONE\n"));
		break;
	}

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii_hal_bsync_count_set(uint32_t dev_id, uint8_t bsync_count)
{
	sii_drv_cra_write8(dev_id, REG_ADDR__BSYNC_CTRL, bsync_count);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_top_int_get(uint32_t dev_id,
				 uint8_t *p_top_int)
{
	*p_top_int = sii_drv_cra_read8(dev_id, REG_ADDR__TOP_INTR_STATE);
	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_enable_all_int(uint32_t dev_id,
					bool_t en)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__TOP_INT_CTRL,
			BIT_MSK__TOP_INT_CTRL__REG_GLOBAL_INTR_MASK, en);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_top_int_status_get(uint32_t dev_id,
				 uint8_t *p_int_top_regs,
				 uint16_t num_regs)
{
	uint16_t i;
	sii_drv_cra_block_read8(dev_id, REG_ADDR__TOP_INTR1,
					p_int_top_regs, num_regs);
	/* Clear all interrupts */
	for (i = 0; i < num_regs; i++) {
		if (p_int_top_regs[i])
			sii_drv_cra_write8(dev_id, (REG_ADDR__TOP_INTR1 + i),
						p_int_top_regs[i]);
	}

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_earc_block_int_get(uint32_t dev_id,
				 uint8_t *p_int)
{
	*p_int = sii_drv_cra_read8(dev_id,
			REG_ADDR__INTR_STATE);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_gpio_event_mask_set(uint32_t dev_id,
		uint8_t *gpio_pin_event_mask)
{
	uint8_t intr2_reg_value = 0, intr3_reg_value = 0;

	if (*gpio_pin_event_mask & BIT__GPIO_NUM_0)
		intr2_reg_value |= (BIT_MSK__TOP_INTR2__REG_TOP_INTR_STAT6 |
				BIT_MSK__TOP_INTR2__REG_TOP_INTR_STAT12);

	if (*gpio_pin_event_mask & BIT__GPIO_NUM_1)
		intr2_reg_value |= (BIT_MSK__TOP_INTR2__REG_TOP_INTR_STAT7 |
				BIT_MSK__TOP_INTR2__REG_TOP_INTR_STAT13);

	if (*gpio_pin_event_mask & BIT__GPIO_NUM_2) {
		intr2_reg_value |= BIT_MSK__TOP_INTR2__REG_TOP_INTR_STAT8;
		intr3_reg_value |= BIT_MSK__TOP_INTR3__REG_TOP_INTR_STAT14;
	}

	if (*gpio_pin_event_mask & BIT__GPIO_NUM_3) {
		intr2_reg_value |= BIT_MSK__TOP_INTR2__REG_TOP_INTR_STAT9;
		intr3_reg_value |= BIT_MSK__TOP_INTR3__REG_TOP_INTR_STAT15;
	}

	if (*gpio_pin_event_mask & BIT__GPIO_NUM_4) {
		intr2_reg_value |= BIT_MSK__TOP_INTR2__REG_TOP_INTR_STAT10;
		intr3_reg_value |= BIT_MSK__TOP_INTR3__REG_TOP_INTR_STAT16;

	}

	if (*gpio_pin_event_mask & BIT__GPIO_NUM_5) {
		intr2_reg_value |= BIT_MSK__TOP_INTR2__REG_TOP_INTR_STAT11;
		intr3_reg_value |= BIT_MSK__TOP_INTR3__REG_TOP_INTR_STAT17;
	}

	sii_drv_cra_write8(dev_id, REG_ADDR__TOP_INTR2_MASK, intr2_reg_value);

	sii_drv_cra_bits_set8(dev_id, REG_ADDR__TOP_INTR3_MASK,
			BIT_MSK__TOP_INTR3_MASK__REG_INTR_MASK_B17_B14 &
			intr3_reg_value, TRUE);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_earc_int_status_get(uint32_t dev_id,
				 uint8_t *p_int_regs,
				 uint16_t num_regs)
{
	uint8_t i;
	sii_drv_cra_block_read8(dev_id,
			REG_ADDR__INTR0,
				p_int_regs,
				num_regs);
	/* Clear all interrupts except INTR1*/
	for (i = 0; i < num_regs; i++) {
		if (p_int_regs[i] && (i != 1)) {
			sii_drv_cra_write8(dev_id,
				(REG_ADDR__INTR0 + i),
				p_int_regs[i]);
		}
	}
	/* Do not clear Mute Exception detected interrupt*/
	sii_drv_cra_write8(dev_id,
			(REG_ADDR__INTR0 + 1),
			p_int_regs[1] & ~BIT_MASK__INTR1_MASK__MUTE_EXCEP_DET);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_i2s_clk_status_get(uint32_t dev_id,
			bool_t *p_i2s_clock_status)
{
	*p_i2s_clock_status = (sii_drv_cra_read8(dev_id,
			REG_ADDR__AUD_MODE) &
			BIT_MSK__AUD_MODE__I2S_CLK_STATUS) ?
			TRUE : FALSE;

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_earc_conn_status_get(uint32_t dev_id,
					bool_t *p_earc_stat)
{
	*p_earc_stat = (sii_drv_cra_read8(dev_id,
		REG_ADDR__DISC_DISCONN_TX7) &
		BIT_MSK__DISC_DISCONN_TX7__REG_TX_EARC_CONNECTION_STATUS) ?
		TRUE : FALSE;

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_norm_phase_set(uint32_t dev_id,
					bool_t norm_phase_en)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__EARC_CFG0,
			BIT_MASK__EARC_CFG0__TX_DATA_POL_MASK,
			norm_phase_en);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_caps_ds_read_status_get(uint32_t dev_id,
					uint8_t *p_caps_ds_stat)
{
	*p_caps_ds_stat = sii_drv_cra_read8(dev_id,
			REG_ADDR__EDID_INTR);
	/* Clear caps ds interupt status */
	sii_drv_cra_write8(dev_id,
			REG_ADDR__EDID_INTR,
			*p_caps_ds_stat);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_sw_access_status_get(uint32_t dev_id,
					uint8_t *p_stat)
{
	*p_stat = sii_drv_cra_read8(dev_id,
			REG_ADDR__CMC_MASTER_TX25);
	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_reset_aud_fifo(uint32_t dev_id)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__SRST2,
			BIT_MSK__SRST2__REG_RST_TX_FIFO_N, FALSE);
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__SRST2,
			BIT_MSK__SRST2__REG_RST_TX_FIFO_N, TRUE);
	/* the aud fifo full is trigger again after resetting the fifo;
	 * therefore clear the fifo interrupt again; otherwise it'll go into
	 * infinite loop */
	sii_drv_cra_write8(dev_id,
			REG_ADDR__INTR0,  BIT_MASK_TX__FIFO_FULL_ERR);
	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_aud_mute_set(uint32_t dev_id,
				 bool_t en)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__MUTE_CTRL,
			BIT_MSK__MUTE_CTRL__REG_MUTE_EN, en);

	/* Set Mute bit in Channel Status*/
	sii_drv_cra_bits_set8(dev_id, REG_ADDR_I2S_CS_EXTRA2,
			BIT_MASK__I2S_CS_EXTRA2__EARC_MUTE, en);

	sii_drv_cra_bits_set8(dev_id, REG_ADDR__I2S_CS_PTR,
			BIT_MSK__I2S_CS_PTR__REG_CS_UPDATE_EN, TRUE);

	SII_LOG2A("", NULL, ("Audio Output: %s\n",
					(en ? "MUTED" : "UNMUTED")));

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_vbit_set(uint32_t dev_id,
				enum sii9438_vbit vbit_value,
				bool_t b_spdif_in)
{

	sii_drv_cra_bits_set8(dev_id, REG_ADDR__I2S_IN_CTRL,
			BIT_MSK__I2S_IN_CTRL__REG_VBIT,
			(vbit_value == SII9438_VBIT_1) ? TRUE : FALSE);

	if (b_spdif_in) {
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__TX_SPDIF_CS_CTRL,
				BIT_MSK__TX_SPDIF_CS_CTRL__REG_VBIT_OVERRIDE,
				(vbit_value == SII9438_VBIT_BYPASS) ?
						FALSE : TRUE);
	} else {
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__TX_SPDIF_CS_CTRL,
				BIT_MSK__TX_SPDIF_CS_CTRL__REG_VBIT_OVERRIDE,
				FALSE);
	}

	SII_LOG2A("", NULL, ("V-Bit Value: %s\n",
			((vbit_value == SII9438_VBIT_BYPASS) ? "Bypass" :
			(vbit_value == SII9438_VBIT_1) ? "1" : "0")));

	return SII_RETURN_VALUE__SUCCESS;
}

bool_t sii9438_hal_earc_hpd_query(uint32_t dev_id, bool_t *hpd)
{
	*hpd = sii_drv_cra_read8(dev_id, REG_ADDR__CMC_MASTER_TX19) &
			BIT_MSK__CMC_MASTER_TX19___EARC_HPD ? TRUE : FALSE;

	return SII_RETURN_VALUE__SUCCESS;
}

bool_t sii9438_hal_rx_stat_chng_query(uint32_t dev_id, bool_t *stat_chng)
{
	*stat_chng = sii_drv_cra_read8(dev_id, REG_ADDR__CMC_MASTER_TX19) &
			BIT_MSK__CMC_MASTER_TX19___STAT_CHNG ? TRUE : FALSE;

	return SII_RETURN_VALUE__SUCCESS;
}

bool_t sii9438_hal_rx_cap_chng_query(uint32_t dev_id,
						bool_t *re_read_caps_ds)
{
	*re_read_caps_ds = sii_drv_cra_read8(dev_id,
				REG_ADDR__CMC_MASTER_TX19) &
			BIT_MSK__CMC_MASTER_TX19___CAP_CHNG ? TRUE : FALSE;

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_virtual_hdmi_hpd_enable_set(uint32_t dev_id,
		bool_t b_enable)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__CMC_MASTER_TX8,
		BIT_MASK__CMC_MASTER_TX8__REG_TX_HDMI_HPD_STAT_OVERRIDE,
		b_enable);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_stat_chng_conf_enable_set(uint32_t dev_id,
		bool_t b_enable)
{
	/* Override enable*/
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__CMC_MASTER_TX8,
		BIT_MASK__CMC_MASTER_TX8__REG_TX_STAT_CHNG_CONF_OVR,
		b_enable);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_stat_chng_conf_set(uint32_t dev_id,
		bool_t b_enable)
{
	/* override value*/
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__CMC_MASTER_TX7,
		BIT_MASK__CMC_MASTER_TX7__REG_TX_HB_STATUS_OVERRIDE_B4,
		b_enable);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_cap_chng_conf_enable_set(uint32_t dev_id,
		bool_t b_enable)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__CMC_MASTER_TX8,
		BIT_MASK__CMC_MASTER_TX8__REG_TX_CAP_CNG_CONF_OVR,
		b_enable);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_cap_chng_conf_set(uint32_t dev_id,
		bool_t b_set)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__CMC_MASTER_TX7,
			BIT_MASK__CMC_MASTER_TX7__REG_TX_HB_STATUS_OVERRIDE_B3,
			b_set);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_virtual_hdmi_hpd_set(uint32_t dev_id,
		bool_t b_hdmi_hpd_val)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__CMC_MASTER_TX7,
			BIT_MASK__CMC_MASTER_TX7__REG_TX_HB_STATUS_OVERRIDE_B0,
			b_hdmi_hpd_val);
	SII_LOG2A("", NULL,
		("Virtual HDMI HPD set in eARC Tx/Source status: %s\n",
		b_hdmi_hpd_val ? "hi" : "lo"));

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_hpd_out_set(uint32_t dev_id, bool_t b_hpd_out_val)
{
	/* For GPIO5 (TX HPD OUT) - 0 - HPD high, 1 - HPD low */
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__GPIO_I_CTRL,
		BIT__GPIO_NUM_5, !b_hpd_out_val);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_arc_mode_set(uint32_t dev_id,
				enum sii_arc_mode arc_mode)
{
	switch (arc_mode) {
	case SII_ARC_MODE__ARC:
		/* Legacy ARC Mode */
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_MODE,
					(BIT_MSK__VIOLA_MODE__REG_AUTO_CFG |
					BIT_MSK__VIOLA_MODE__PLL_EN));
		sii_drv_cra_write8(dev_id, REG_ADDR__EARC_CFG_1,
				(BIT_MSK__EARC_CFG1__RTERM_30OHM |
				BIT_MSK__EARC_CFG1__CM_LEVEL_CTRL_SM));
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_SLEW_N_SWING,
				0x2B);
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_SPRX, 0x04);
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_TERM60, 0x0F);
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_TERM300, 0x0C);
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_CM_BW_CTL, 0x00);

		sii_drv_cra_bits_set8(dev_id, REG_ADDR__TEST_CTRL,
				BIT_MSK__TEST_CTRL__REG_TEST_EN,
				FALSE);

		sii9438_hal_ecc_enable(dev_id, FALSE);

		break;

	case SII_ARC_MODE__EARC:
		/* eARC Mode */
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__TEST_CTRL,
				BIT_MSK__TEST_CTRL__REG_TEST_EN,
				FALSE);
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_MODE,
			BIT_MSK__VIOLA_MODE__REG_ARC_MODE |
			BIT_MSK__VIOLA_MODE__PLL_EN);
		sii_drv_cra_write8(dev_id, REG_ADDR__EARC_CFG_1,
				(BIT_MSK__EARC_CFG1__CM_LEVEL_CTRL_300MV |
				BIT_MSK__EARC_CFG1__ARC_MODE_CTRL_CM));
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_SLEW_N_SWING, 0x52);
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_SPRX, 0x21);
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_TERM60, 0x0C);
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_TERM300, 0x0C);
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_CM_BW_CTL, 0x08);

		break;

	case SII_ARC_MODE__NONE:
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_MODE,
				BIT_MSK__VIOLA_MODE__REG_ARC_MODE);
		sii_drv_cra_write8(dev_id, REG_ADDR__VIOLA_CM_BW_CTL, 0x00);
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__TEST_CTRL,
				BIT_MSK__TEST_CTRL__REG_TEST_EN,
				TRUE);

		sii9438_hal_ecc_enable(dev_id, FALSE);

		break;

	default:

		break;
	}

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_tx_pll_enable(uint32_t dev_id, bool_t pll_enable)
{
	if (pll_enable) {
		SII_LOG1A("", NULL, ("Enabling PLL\n"));
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__VIOLA_MODE,
						BIT_MSK__VIOLA_MODE__PLL_EN,
						pll_enable);
		if (sii_drv_cra_read8(dev_id, REG_ADDR__INTR0) &
				BIT_MASK_TX__FIFO_FULL_ERR) {
			SII_LOG1A("", NULL,
				("Clearing FIFO full intr on PLL Enable\n"));
			/* Clear FIFO Full error interrupt */
			sii_drv_cra_write8(dev_id, REG_ADDR__INTR0,
					BIT_MASK_TX__FIFO_FULL_ERR);
			/* Reset Audio FIFO error */
			sii9438_hal_reset_aud_fifo(dev_id);
		}
		/* Enable FIFO Full error interrupt */
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__INTR0_MASK,
				BIT_MASK_TX__FIFO_FULL_ERR, TRUE);
	} else {
		/* Disable FIFO Full error interrupt */
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__INTR0_MASK,
				BIT_MASK_TX__FIFO_FULL_ERR, FALSE);

		SII_LOG1A("", NULL, ("Disabling PLL\n"));
		/* Disable PLL */
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__VIOLA_MODE,
						BIT_MSK__VIOLA_MODE__PLL_EN,
						pll_enable);
		if (sii_drv_cra_read8(dev_id, REG_ADDR__INTR0) &
						BIT_MASK_TX__FIFO_FULL_ERR) {
			SII_LOG1A("", NULL,
				("Clearing FIFO full intr on PLL Disable\n"));
			/* Clear FIFO Full error interrupt */
			sii_drv_cra_write8(dev_id, REG_ADDR__INTR0,
					BIT_MASK_TX__FIFO_FULL_ERR);
			/* Reset Audio FIFO error */
			sii9438_hal_reset_aud_fifo(dev_id);
		}
	}

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_tx_out_clk_en(uint32_t dev_id, bool_t b_en)
{
	if (b_en) {
		SII_LOG1A("", NULL, ("Enabling TX Output Clk\n"));
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__EARC_CFG0,
					BIT_MASK__EARC_CFG0__TX_DATA_POL_MASK,
					b_en);
		sii_sys_time_milli_delay(1);
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__EARC_CFG0,
				BIT_MASK__EARC_CFG0__TX_PLL_CLK_TO_TX_DP,
				b_en);

		if (sii_drv_cra_read8(dev_id, REG_ADDR__INTR0) &
				BIT_MASK_TX__FIFO_FULL_ERR) {
			SII_LOG1A("", NULL,
			("Clearing FIFO full intr on TX output clk enable\n"));
			/* Clear FIFO Full error interrupt */
			sii_drv_cra_write8(dev_id, REG_ADDR__INTR0,
					BIT_MASK_TX__FIFO_FULL_ERR);
		}

		/* Reset Audio FIFO error */
		sii9438_hal_reset_aud_fifo(dev_id);

		/* Enable FIFO Full error interrupt */
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__INTR0_MASK,
				BIT_MASK_TX__FIFO_FULL_ERR, TRUE);
	} else {
		/* Disable FIFO Full error interrupt */
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__INTR0_MASK,
				BIT_MASK_TX__FIFO_FULL_ERR, FALSE);

		SII_LOG1A("", NULL, ("Disabling TX Output Clk\n"));
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__EARC_CFG0,
				BIT_MASK__EARC_CFG0__TX_DATA_POL_MASK,
				b_en);
		sii_sys_time_milli_delay(1);
		/* Disable output */
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__EARC_CFG0,
				BIT_MASK__EARC_CFG0__TX_PLL_CLK_TO_TX_DP,
				b_en);
		if (sii_drv_cra_read8(dev_id, REG_ADDR__INTR0) &
						BIT_MASK_TX__FIFO_FULL_ERR) {
			SII_LOG1A("", NULL,
			("Clearing FIFO full intr on TX output clk disable\n"));
			/* Clear FIFO Full error interrupt */
			sii_drv_cra_write8(dev_id, REG_ADDR__INTR0,
					BIT_MASK_TX__FIFO_FULL_ERR);
		}
		/* Reset Audio FIFO error */
		sii9438_hal_reset_aud_fifo(dev_id);
	}

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_tx_earc_mode_set(uint32_t dev_id, bool_t b_earc_mode)
{

	sii_drv_cra_bits_set8(dev_id, REG_ADDR__VIOLA_MODE,
			BIT_MSK__VIOLA_MODE__REG_ARC_MODE,
			b_earc_mode);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_spdif_channel_status_query(uint32_t dev_id,
		struct sii_channel_status *p_channel_status)
{
	sii_drv_cra_block_read8(dev_id, REG_ADDR__TX_CHST0,
			p_channel_status->data,
			SII_CHANNEL_STATUS_SIZE);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_reset_ddc_no_ack(uint32_t dev_id)
{
	if (sii_drv_cra_read8(dev_id, REG_ADDR__DDC_STATUS) &
			BIT_MSK__DDC_STATUS__REG_DDC_NO_ACK) {
		sii_drv_cra_bits_set8(dev_id,
			REG_ADDR__DDC_STATUS,
			BIT_MSK__DDC_STATUS__REG_DDC_NO_ACK, FALSE);
	}

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_intr_enable(uint32_t dev_id, bool_t b_en)
{
	uint8_t maskRegs[REG_TX__INT_NUM] = {0};
	uint8_t maskTopRegs[REG_TOP__INT_NUM] = {0};

	if (!b_en) {
		/* Clear the interrupt mask */
		sii_drv_cra_block_write8(dev_id, REG_ADDR__INTR0_MASK,
			maskRegs, REG_TX__INT_NUM);

		sii_drv_cra_block_write8(dev_id, REG_ADDR__TOP_INTR1_MASK,
			maskTopRegs, REG_TOP__INT_NUM);

		sii_drv_cra_bits_set8(dev_id, REG_ADDR__EDID_INTR_MASK,
				BIT_MSK__EDID_INTR_MASK__REG_INTR_MASK0 |
				BIT_MSK__EDID_INTR_MASK__REG_INTR_MASK1,
				FALSE);
	} else {
		/* Enable interrupt mask */
		s_int_mask_init(dev_id);
	}

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_sm_states_intr_enable(uint32_t dev_id, bool_t b_en)
{
	uint8_t maskRegs[REG_TX__INT_NUM] = {0};

	maskRegs[REG_INTR_0] = BIT_MASK__INTR0_MASK__STATE_IDLE1;
	maskRegs[REG_INTR_1] = BIT_MASK__INTR1_MASK__STATE_DISC1 |
			BIT_MASK__INTR1_MASK__STATE_IDLE2;

	maskRegs[REG_INTR_4] = BIT_MASK__INTR4_MASK__STATE_EARC |
			BIT_MASK__INTR4_MASK__STATE_ARC |
			BIT_MASK__INTR4_MASK__STATE_DISC2;

	sii_drv_cra_block_write8(dev_id, REG_ADDR__INTR0_MASK,
					maskRegs, REG_TX__INT_NUM);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_tx_audio_in_reset(uint32_t dev_id, bool_t en)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__SRST2,
			BIT_MSK__SRST2__REG_RST_4CLK_AUDIO_IN_N,
			en ? FALSE : TRUE);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_tx_spdif_ch_status_intr_enable(uint32_t dev_id,
		bool_t en)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__INTR4_MASK,
			BIT_MASK__INTR4_MASK__CH_STATUS_CHANGED,
			en);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_tx_phy_fifo_reset_set(uint32_t dev_id,
				bool_t b_reset)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__VIOLA_STATUS,
			BIT_MSK__VIOLA_STATUS__REG_RST_TX_PHY_FIFO_N,
			!b_reset);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_chip_version_query(uint32_t dev_id,
					uint8_t *p_chip_version)
{
	uint8_t p_chip_id = 0;
	p_chip_id = sii_drv_cra_read8(dev_id,
			REG_ADDR__DEV_IDL);

	if (p_chip_id == 0x38)
		*p_chip_version = 0;
	else if (p_chip_id == 0x3A)
		*p_chip_version = 1;

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_erx_latency_req_set(uint32_t dev_id,
					uint8_t erx_latency_req)
{
	uint8_t access_done = 0;
	uint8_t retry_count = 3;
	uint8_t nretry;
	uint16_t i;
	for (nretry = 0; nretry < retry_count; nretry++) {
		/* b3: clr s/w access done intr */
		sii_drv_cra_write8(dev_id, REG_ADDR__INTR6,
					BIT_MASK_TX__SW_ACCESS_DONE);
		/* eARC devide ID to access Rx 0xD2 and 0xD3 registers */
		sii_drv_cra_write8(dev_id, REG_ADDR__CMC_MASTER_TX21, 0x74);
		/* Offset to 0xD2 */
		sii_drv_cra_write8(dev_id, REG_ADDR__CMC_MASTER_TX22, 0xD3);
		/* New erx latency request value */
		sii_drv_cra_write8(dev_id, REG_ADDR__CMC_MASTER_TX23,
							erx_latency_req);
		/* Write operation */
		sii_drv_cra_write8(dev_id, REG_ADDR__CMC_MASTER_TX26,
				BIT_MSK__CMC_MASTER_TX26__REG_SW_ACC_OP_WRITE);

		access_done = sii_drv_cra_read8(dev_id, REG_ADDR__INTR6) &
				BIT_MASK_TX__SW_ACCESS_DONE;
		/* Check for SW access done */
		/*while (!access_done) {*/
		for (i = 0; i < 1000; i++) {
			access_done = sii_drv_cra_read8(dev_id,
					REG_ADDR__INTR6) &
					BIT_MASK_TX__SW_ACCESS_DONE;
			if (access_done)
				break;
		}
		/* b3: clr s/w access done intr */
		sii_drv_cra_write8(dev_id, REG_ADDR__INTR6,
					BIT_MASK_TX__SW_ACCESS_DONE);
		sii9438_hal_sw_access_status_get(dev_id, &access_done);
		if (access_done & BIT_MASK__SW_ACCESS_SUCCESS) {
			SII_LOG3A("", NULL,
				("Latency req write sw access success\n"));
			break;
		}

		if (access_done & BIT_MASK__SW_ACCESS_FAILED) {
			SII_LOG3A("", NULL,
			("Latency req write sw access failed. Retry..\n"));
		}
	}

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_erx_latency_query(uint32_t dev_id,
					uint8_t *erx_latency)
{
	uint8_t access_done = 0;
	uint8_t retry_count = 3;
	uint8_t nretry;
	uint16_t i;

	for (nretry = 0; nretry < retry_count; nretry++) {
		/* use s/w access mode to read erx_latency from rx */
		/* b3: clr s/w access done intr */
		sii_drv_cra_write8(dev_id, REG_ADDR__INTR6,
					BIT_MASK_TX__SW_ACCESS_DONE);
		/* eARC devide ID to access Rx 0xD2 and 0xD3 registers */
		sii_drv_cra_write8(dev_id, REG_ADDR__CMC_MASTER_TX21, 0x74);
		/* Offset to 0xD2 */
		sii_drv_cra_write8(dev_id, REG_ADDR__CMC_MASTER_TX22, 0xD2);
		/* Read operation */
		sii_drv_cra_write8(dev_id, REG_ADDR__CMC_MASTER_TX26,
				BIT_MSK__CMC_MASTER_TX26__REG_SW_ACC_OP_READ);

		access_done = sii_drv_cra_read8(dev_id, REG_ADDR__INTR6) &
				BIT_MASK_TX__SW_ACCESS_DONE;
		/* Check for SW access done */
		/*while (!access_done) {*/
		for (i = 0; i < 1000; i++) {
			access_done = sii_drv_cra_read8(dev_id,
					REG_ADDR__INTR6) &
					BIT_MASK_TX__SW_ACCESS_DONE;
			if (access_done)
				break;
		}
		/* b3: clr s/w access done intr */
		sii_drv_cra_write8(dev_id, REG_ADDR__INTR6,
					BIT_MASK_TX__SW_ACCESS_DONE);
		sii9438_hal_sw_access_status_get(dev_id, &access_done);
		if (access_done & BIT_MASK__SW_ACCESS_SUCCESS) {
			*erx_latency = sii_drv_cra_read8(dev_id,
					REG_ADDR__CMC_MASTER_TX24);
			SII_LOG1A("", NULL,
				("sw access success\n"));
			SII_LOG1A("", NULL,
				("Rx Audio Latency: %d msec\n", *erx_latency));
			break;
		}
		if (access_done & BIT_MASK__SW_ACCESS_FAILED) {
			SII_LOG1A("", NULL,
				("sw access failed. Retry again\n"));
		}
	}

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_tx_hw_mute_out_status_query(uint32_t dev_id,
						bool_t *hw_mute_out_status)
{
	*hw_mute_out_status = sii_drv_cra_read8(dev_id,
			REG_ADDR__TX_HW_MUTE_ST) &
			BIT_MSK__TX_HW_MUTE_ST__TX_MUTE_HW ? TRUE : FALSE;

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_tx_mute_excep_det_int_clr(uint32_t dev_id)
{
	/* Clear only Mute Exception detected interrupt*/
	sii_drv_cra_write8(dev_id, REG_ADDR__INTR1,
			BIT_MASK__INTR1_MASK__MUTE_EXCEP_DET);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_mclk_div_set(uint32_t dev_id,
		enum sii9438_mclk_div mclk_div)
{
	switch (mclk_div) {
	case SII9438_MCLK_DIV__NO_DIV:
		sii_drv_cra_write8(dev_id, REG_ADDR__MCLK_PHY,
				BIT_MSK__MCLK_PHY__REG_MCLK_NO_DIV);
		SII_LOG1A("", NULL, ("MCLK Divider: NO_DIV\n"));
		break;
	case SII9438_MCLK_DIV__BY2:
		sii_drv_cra_write8(dev_id, REG_ADDR__MCLK_PHY,
				BIT_MSK__MCLK_PHY__REG_MCLK_DIV_2);
		SII_LOG1A("", NULL, ("MCLK Divider: BY2\n"));
		break;
	case SII9438_MCLK_DIV__BY4:
		sii_drv_cra_write8(dev_id, REG_ADDR__MCLK_PHY,
				BIT_MSK__MCLK_PHY__REG_MCLK_DIV_4);
		SII_LOG1A("", NULL, ("MCLK Divider: BY4\n"));
		break;
	default:
		sii_drv_cra_write8(dev_id, REG_ADDR__MCLK_PHY,
				BIT_MSK__MCLK_PHY__REG_MCLK_NO_DIV);
		SII_LOG1A("", NULL, ("Error: MCLK Div. Set Default NO_DIV\n"));
		break;
	}

	return SII_RETURN_VALUE__SUCCESS;
}

/***** local functions *******************************************************/

static bool_t s_is_caps_ds_avail(uint32_t dev_id)
{
	bool_t val = FALSE;
	bool_t result = FALSE;
	uint16_t wait_count = 1000;

	while (!val) {
		val = sii_drv_cra_read8(dev_id, REG_ADDR__EDID_INTR) &
			(BIT_MSK__EDID_INTR_MASK__REG_INTR_MASK1 |
				BIT_MSK__EDID_INTR_MASK__REG_INTR_MASK0);
		if (val) {
			if (val == BIT_MSK__EDID_INTR_MASK__REG_INTR_MASK0) {
				SII_LOG1A("", NULL,
				("Capability Data Struct Read Success\n"));
				result = TRUE;
			} else {
				SII_LOG1A("", NULL,
				("Capability Data Struct Read Failed\n"));
				sii9438_hal_reset_ddc_no_ack(dev_id);
				result = FALSE;
			}
			sii_drv_cra_write8(dev_id,
					REG_ADDR__EDID_INTR, val);
			break;
		}
		wait_count--;
		if (wait_count == 0) {
			SII_LOG1A("", NULL,
			("Capability Data Struct Read Failed: Timeout\n"));
			break;
		}
	}

	return result;
}

static void caps_ds_audio_data_print(char *pName, uint8_t *p_caps_ds,
		uint16_t size)
{
	uint16_t i;
	SII_LOG3A("", NULL, ("%s\n", pName));
	for (i = 0; i < size; i += 8) {
		SII_LOG1A("", NULL,
			("%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.\n",
				p_caps_ds[i], p_caps_ds[i+1],
				p_caps_ds[i+2], p_caps_ds[i+3],
				p_caps_ds[i+4], p_caps_ds[i+5],
				p_caps_ds[i+6], p_caps_ds[i+7]));
	}
}

static void s_int_mask_init(uint32_t dev_id)
{
	uint8_t maskRegs[REG_TX__INT_NUM];
	uint8_t maskTopRegs[REG_TOP__INT_NUM];

	maskRegs[REG_INTR_0] = BIT_MASK__INTR0_MASK__STATE_IDLE1;
	maskRegs[REG_INTR_1] = BIT_MASK_TX__ENCRYPING |
			BIT_MASK__INTR1_MASK__STATE_DISC1 |
			BIT_MASK__INTR1_MASK__STATE_IDLE2 |
			BIT_MASK__INTR1_MASK__MUTE_EXCEP_DET;
	maskRegs[REG_INTR_2] = BIT_MASK_TX__CLK_CHANGED;
	maskRegs[REG_INTR_3] = BIT_MASK_TX__HEARTBEAT_FAILED |
				BIT_MASK_TX__TIMEOUT_NO_COMMA;
	maskRegs[REG_INTR_4] = BIT_MASK_TX__HEARTBEAT_LOST |
			BIT_MASK__INTR4_MASK__STATE_EARC |
			BIT_MASK__INTR4_MASK__STATE_ARC |
			BIT_MASK__INTR4_MASK__STATE_DISC2;

	maskRegs[REG_INTR_5] = BIT_MASK_TX__EARC_HPD |
			BIT_MASK_TX__STAT_CHNG |
			BIT_MASK__INTR5_MASK__CAP_CHNG;
	maskRegs[REG_INTR_6] = BIT_MASK_TX__SW_ACCESS_DONE |
				BIT_MASK_TX__EARC_CONN_CHANGE |
				BIT_MASK__INT6_MASK__ECC_ERR_FIXED |
				BIT_MASK__INT6_MASK__ECC_ERR;
	sii_drv_cra_block_write8(dev_id, REG_ADDR__INTR0_MASK,
					maskRegs, REG_TX__INT_NUM);

	maskTopRegs[REG_INTR_TOP_1] = BIT_MASK__TOP_INTR1_MASK__TOP_TIMER;
	/* GPIO4 change from 0 to 1 */
	maskTopRegs[REG_INTR_TOP_2] = BIT_MSK__TOP_INTR2__REG_TOP_INTR_STAT10;
	/* GPIO4 change from 1 to 0 */
	maskTopRegs[REG_INTR_TOP_3] = BIT_MSK__TOP_INTR3__REG_TOP_INTR_STAT16;

	sii_drv_cra_block_write8(dev_id, REG_ADDR__TOP_INTR1_MASK,
				maskTopRegs, REG_TOP__INT_NUM);

	/* Enable Capability DS read interrupt */
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__EDID_INTR_MASK,
			BIT_MSK__EDID_INTR_MASK__REG_INTR_MASK0 |
			BIT_MSK__EDID_INTR_MASK__REG_INTR_MASK1,
			TRUE);
}

uint32_t sii9438_hal_mute_excep_det_intr_enable(uint32_t dev_id, bool_t en)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__INTR1_MASK,
			BIT_MASK__INTR1_MASK__MUTE_EXCEP_DET, en);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_sm_state_get(uint32_t dev_id, uint8_t *p_state_val)
{
	if (p_state_val) {
		*p_state_val = sii_drv_cra_read8(dev_id,
				REG_ADDR__DISC_DISCONN_TX7) &
		BIT_MSK__DISC_DISCONN_TX7__REG_TX_DISC_DISCONN_STATE_B2_B0;
	}

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_sm_state_set(uint32_t dev_id, uint8_t state_val)
{
	sii_drv_cra_bits_mod8(dev_id, REG_ADDR__DISC_DISCONN_TX8,
		BIT_MSK__DISC_DISCONN_TX8__REG_TX_DISC_DISCON_ST_OVR_B2_B0,
		state_val);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_sm_state_override_enable(uint32_t dev_id, bool_t b_en)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__DISC_DISCONN_TX8,
		BIT_MSK__DISC_DISCONN_TX8__REG_TX_DISC_CONN_ST_OVERRIDE_EN,
		b_en);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_idle2_enable(uint32_t dev_id, bool_t b_en)
{
	sii_drv_cra_bits_set8(dev_id, REG_ADDR__DISC_DISCONN_TX8,
		BIT_MSK__DISC_DISCONN_TX8__TX_DISC_CONN_ST_NO_IDLE2,
		!b_en);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_arc_init_term(uint32_t dev_id, bool_t b_init_is)
{
	if (b_init_is) {
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__CMC_MASTER_TX16,
			BIT_MSK__CMC_MASTER_TX16__REG_CEC_ARC_INIT, TRUE);

		sii_drv_cra_bits_set8(dev_id, REG_ADDR__CMC_MASTER_TX16,
			BIT_MSK__CMC_MASTER_TX16__REG_CEC_ARC_TERM, FALSE);
	} else {
		sii_drv_cra_bits_set8(dev_id, REG_ADDR__CMC_MASTER_TX16,
			BIT_MSK__CMC_MASTER_TX16__REG_CEC_ARC_INIT, FALSE);

		sii_drv_cra_bits_set8(dev_id, REG_ADDR__CMC_MASTER_TX16,
			BIT_MSK__CMC_MASTER_TX16__REG_CEC_ARC_TERM, TRUE);
	}

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_is_spdif_cs_ch_intr_en(uint32_t dev_id, bool_t *is_en)
{
	if (is_en) {
		*is_en = (sii_drv_cra_read8(dev_id,
				REG_ADDR__INTR4_MASK) &
				BIT_MASK__INTR4_MASK__CH_STATUS_CHANGED) ?
						TRUE : FALSE;
	}

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_tx_timeout_set(uint32_t dev_id, uint16_t timeout_val)
{

	sii_drv_cra_bits_mod16(dev_id, REG_ADDR__DISC_DISCONN_TX3, 0x3FF,
			timeout_val);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_hb_intr_mask_en(uint32_t dev_id, bool_t en)
{
	sii_drv_cra_bits_set8(dev_id,
				REG_ADDR__INTR3_MASK,
				BIT_MASK_TX__HEARTBEAT_SUCCESS,
				en);

	return SII_RETURN_VALUE__SUCCESS;
}

uint32_t sii9438_hal_hb_intr_clear(uint32_t dev_id)
{
	sii_drv_cra_write8(dev_id,
				REG_ADDR__INTR3,
				BIT_MASK_TX__HEARTBEAT_SUCCESS);

	return SII_RETURN_VALUE__SUCCESS;
}
/***** end of file ***********************************************************/
