/**
 * @file hv_cal_Audio.c
 * @brief audio driver chip abstract layer file.
 * @details This file provides the following functions: \n
 *          (1) Initialization and de-initialization functions \n
 *          (2) Start and stop functions \n
 *          (3) Feed functions \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-18
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author                        <th>Date         <th>Change Description
 * <tr><td>HiView SoC Software Team      <td>2022-08-23   <td>init
 * </table>
 */

#include "hv_cal_Audio.h"
#include "hv_cal_Gpio.h"
#include "hv_drv_Gpio.h"
#include "hv_chip_Config.h"
#include "hv_vos_Comm.h"
#include "hv_comm_Assert.h"
#include "hv_comm_Timer.h"

#define _AUDIO_GPIO_HEADSET_DETECT  HV_BOARD_CONFIG_GPIO_HF_DET_1
#define _AUDIO_GPIO_PA_MUTE         HV_BOARD_CONFIG_GPIO_PA_MUTE_CTL
#define _AUDIO_GPIO_PA_SHDN         HV_BOARD_CONFIG_GPIO_PA_SHDN_CTL


static HV_TIMER_S* s_pstHeadsetDetectTimer = NULL;

/**
 * @brief initialize audio GPIO.
 */
VOID Hv_Cal_Audio_GpioInit(VOID)
{
    //set headset detect
    if(HV_BOARD_CONFIG_GPIO_HF_DET_1 != 0xff)
    {
        Hv_Cal_Gpio_SetDirection(_AUDIO_GPIO_HEADSET_DETECT, GPIO_DIR_INPUT);
    }

    //enable PA
    if(HV_BOARD_CONFIG_GPIO_PA_MUTE_CTL != 0xff)
    {
        Hv_Cal_Gpio_SetDirection(_AUDIO_GPIO_PA_MUTE, GPIO_DIR_OUTPUT);
        Hv_Cal_Gpio_SetPinLevel(_AUDIO_GPIO_PA_MUTE, HV_BOARD_CONFIG_PA_MUTE_ENABLE);
    }

    //enable PA
    if(HV_BOARD_CONFIG_GPIO_PA_SHDN_CTL != 0xff)
    {
        Hv_Cal_Gpio_SetDirection(_AUDIO_GPIO_PA_SHDN, GPIO_DIR_OUTPUT);
        Hv_Cal_Gpio_SetPinLevel(_AUDIO_GPIO_PA_SHDN, HV_BOARD_CONFIG_PA_SHDN_ENABLE);
    }

    return;
}

/**
 * @brief Audio Speaker Mute.
 */
VOID Hv_Cal_Audio_SpeakerMute(VOID)
{
    if ((g_bHeadsetInsertion == 1) || (HV_BOARD_CONFIG_GPIO_HF_DET_1 == 0xff))
    {
        HV_LOG_DEBUG(AUDIO, "Hv_Cal_Audio_SpeakerMute.");
        if(HV_BOARD_CONFIG_GPIO_PA_MUTE_CTL != 0xff)
        {
            Hv_Cal_Gpio_SetPinLevel(_AUDIO_GPIO_PA_MUTE, HV_BOARD_CONFIG_PA_MUTE_ENABLE);
        }
        if(HV_BOARD_CONFIG_GPIO_PA_SHDN_CTL != 0xff)
        {
            Hv_Cal_Gpio_SetPinLevel(_AUDIO_GPIO_PA_SHDN, HV_BOARD_CONFIG_PA_SHDN_ENABLE);
        }
    }
    return;
}

/**
 * @brief Audio Speaker UnMute.
 */
VOID Hv_Cal_Audio_SpeakerUnMute(VOID)
{
    if ((g_bHeadsetInsertion == 0) || (HV_BOARD_CONFIG_GPIO_HF_DET_1 == 0xff))
    {
        HV_LOG_DEBUG(AUDIO, "Hv_Cal_Audio_SpeakerUnMute.");
        if(HV_BOARD_CONFIG_GPIO_PA_MUTE_CTL != 0xff)
        {
            Hv_Cal_Gpio_SetPinLevel(_AUDIO_GPIO_PA_MUTE, HV_BOARD_CONFIG_PA_MUTE_DISABLE);
        }
        if(HV_BOARD_CONFIG_GPIO_PA_SHDN_CTL != 0xff)
        {
            Hv_Cal_Gpio_SetPinLevel(_AUDIO_GPIO_PA_SHDN, HV_BOARD_CONFIG_PA_SHDN_DISABLE);
        }
    }

    return;
}

/**
 * @brief audio HeadsetDetect InterruptHandler.
 */
VOID Hv_Cal_Audio_HeadsetDetectInterruptHandler(const GpioIntState *stIntState, VOID *pArg)
{
    //disable interrupt
    if(HV_BOARD_CONFIG_GPIO_HF_DET_1 != 0xff)
    {
        Hv_Cal_Gpio_DisableInt(_AUDIO_GPIO_HEADSET_DETECT);
    }
    else
    {
        return;
    }

    //start timer
    Hv_Vos_Timer_Start(s_pstHeadsetDetectTimer);

    return;
}

/**
 * @brief audio HeadsetDetect TimerHandler.
 */
VOID Hv_Cal_Audio_HeadsetDetectTimerHandler(void* Arg, USHORT16 usEvent)
{
    INT32 iReturn = 0;

    if(HV_BOARD_CONFIG_GPIO_HF_DET_1 == 0xff)
    {
        return;
    }

    iReturn = Hv_Cal_Gpio_GetPinLevel(_AUDIO_GPIO_HEADSET_DETECT);
    if ((iReturn == HV_BOARD_CONFIG_HEADSET_GPIO_STATE_PULL_OUT) && (g_bHeadsetInsertion == 1))
    {
        g_bHeadsetInsertion = 0;

    #ifdef HV_PROJECT_CONFIG_ANALOG_MAX_VOLUME_SPEAKER
        HV_W32_FIELD(AUDIO_DAC_AUDIO_DAC_TOP_00, reg_DACAVL,    HV_PROJECT_CONFIG_ANALOG_MAX_VOLUME_SPEAKER);
        HV_W32_FIELD(AUDIO_DAC_AUDIO_DAC_TOP_04, reg_DACAVR,    HV_PROJECT_CONFIG_ANALOG_MAX_VOLUME_SPEAKER);
    #endif

        HV_LOG_INFO(AUDIO, "Headset pull out!");
        Hv_Cal_Audio_SpeakerUnMute();
    }
    else if ((iReturn == HV_BOARD_CONFIG_HEADSET_GPIO_STATE_INSERT) && (g_bHeadsetInsertion == 0))
    {
        g_bHeadsetInsertion = 1;

    #ifdef HV_PROJECT_CONFIG_ANALOG_MAX_VOLUME_HEADSET
        HV_W32_FIELD(AUDIO_DAC_AUDIO_DAC_TOP_00, reg_DACAVL,    HV_PROJECT_CONFIG_ANALOG_MAX_VOLUME_HEADSET);
        HV_W32_FIELD(AUDIO_DAC_AUDIO_DAC_TOP_04, reg_DACAVR,    HV_PROJECT_CONFIG_ANALOG_MAX_VOLUME_HEADSET);
    #endif

        HV_LOG_INFO(AUDIO, "Headset insert!");
        Hv_Cal_Audio_SpeakerMute();
    }

    //enable interrupt
    Hv_Cal_Gpio_EnableInt(_AUDIO_GPIO_HEADSET_DETECT);

    return;
}

/**
 * @brief initialize audio HeadsetDetect.
 */
VOID Hv_Cal_Audio_HeadsetDetectInit(VOID)
{
    INT32 iReturn = 0;

    if(HV_BOARD_CONFIG_GPIO_HF_DET_1 == 0xff)
    {
        return;
    }

    iReturn = Hv_Cal_Gpio_GetPinLevel(_AUDIO_GPIO_HEADSET_DETECT);
    if (iReturn == HV_BOARD_CONFIG_HEADSET_GPIO_STATE_PULL_OUT)
    {
        g_bHeadsetInsertion = 0;

    #ifdef HV_PROJECT_CONFIG_ANALOG_MAX_VOLUME_SPEAKER
        HV_W32_FIELD(AUDIO_DAC_AUDIO_DAC_TOP_00, reg_DACAVL,    HV_PROJECT_CONFIG_ANALOG_MAX_VOLUME_SPEAKER);
        HV_W32_FIELD(AUDIO_DAC_AUDIO_DAC_TOP_04, reg_DACAVR,    HV_PROJECT_CONFIG_ANALOG_MAX_VOLUME_SPEAKER);
    #endif

        HV_LOG_INFO(AUDIO, "Headset pull out!");
        Hv_Cal_Audio_SpeakerUnMute();
    }
    else
    {
        g_bHeadsetInsertion = 1;

#ifdef HV_PROJECT_CONFIG_ANALOG_MAX_VOLUME_HEADSET
        HV_W32_FIELD(AUDIO_DAC_AUDIO_DAC_TOP_00, reg_DACAVL,    HV_PROJECT_CONFIG_ANALOG_MAX_VOLUME_HEADSET);
        HV_W32_FIELD(AUDIO_DAC_AUDIO_DAC_TOP_04, reg_DACAVR,    HV_PROJECT_CONFIG_ANALOG_MAX_VOLUME_HEADSET);
#endif

        HV_LOG_INFO(AUDIO, "Headset insert!");
        Hv_Cal_Audio_SpeakerMute();
    }

    //set trigger mode
    Hv_Cal_Gpio_SetIntTriggerMode(_AUDIO_GPIO_HEADSET_DETECT, GPIO_INT_RISING_FALLING);
    //set handler
    Hv_Cal_Gpio_SetIntCallBack(_AUDIO_GPIO_HEADSET_DETECT, Hv_Cal_Audio_HeadsetDetectInterruptHandler);
    //enable interrupt
    Hv_Cal_Gpio_EnableInt(_AUDIO_GPIO_HEADSET_DETECT);

    //init timer
    HV_TIMER_INIT_PARAMS stAudioHeadsetDetectTimerParam = \
    {"AudioHeadsetDetectTimer", 20, HV_FALSE, NULL, Hv_Cal_Audio_HeadsetDetectTimerHandler, 0};
    s_pstHeadsetDetectTimer = Hv_Vos_Timer_Create(&stAudioHeadsetDetectTimerParam);

    return;
}

/**
 * @brief set audio source.
 * @param[in] uiRxOutIndex: HDMI1/HDMI2/DP1/DP2.
 */
Status Hv_Cal_Audio_SetRxOut(UINT32 uiRxOutIndex, ChannelType enChannelType)
{
    HV_LOG_DEBUG(AUDIO, "Hv_Cal_Audio_SetRxOut.");

    //video abnormal detect for MUTE
    if (CHANNEL_TYPE_MAIN == enChannelType)
    {
        HV_W32_FIELD(RX_HSRX_TOP_04,        reg_hsrx_video_abnormal_sel,        0);
    }
    else
    {
        HV_W32_FIELD(RX_HSRX_TOP_04,        reg_hsrx_video_abnormal_sel,        1);
    }

    switch (uiRxOutIndex)
    {
        case _AUDIO_HDMI_0:
        {
            //cable detect for MUTE
            HV_W32_FIELD(RX_HSRX_TOP_00,    reg_hsrx_aud_cable_detect_sel,      2);
            //HDMI mute & HDMI abnormal mute
            HV_W32_FIELD(RX_HSRX_TOP_00,    reg_hsrx_aud_hdmi_sel,              0);
            //set rx output
            HV_W32_FIELD(RX_AUDIO_TOP0_00,  reg_audio_rx_out_sel,               4);
            //enable HDMI pll
            HV_W32_FIELD(RX_AUDIO_TOP0_0C,  reg_hdmi_rx_en,                     1);
            break;
        }
        case _AUDIO_HDMI_1:
        {
            //cable detect for MUTE
            HV_W32_FIELD(RX_HSRX_TOP_00,    reg_hsrx_aud_cable_detect_sel,      3);
            //HDMI mute & HDMI abnormal mute
            HV_W32_FIELD(RX_HSRX_TOP_00,    reg_hsrx_aud_hdmi_sel,              1);
            //set rx output
            HV_W32_FIELD(RX_AUDIO_TOP0_00,  reg_audio_rx_out_sel,               4);
            //enable HDMI pll
            HV_W32_FIELD(RX_AUDIO_TOP0_0C,  reg_hdmi_rx_en,                     1);
            break;
        }
        case _AUDIO_DP_0:
        case _AUDIO_TYPE_C_0:
        {
            //cable detect for MUTE
            HV_W32_FIELD(RX_HSRX_TOP_00,    reg_hsrx_aud_cable_detect_sel,      0);
            //DP mute & DP abnormal mute
            HV_W32_FIELD(RX_HSRX_TOP_00,    reg_hsrx_aud_dp_sel,                0);
            //set rx output
            HV_W32_FIELD(RX_AUDIO_TOP0_00,  reg_audio_rx_out_sel,               2);
            //enable DP pll
            HV_W32_FIELD(RX_AUDIO_TOP0_0C,  reg_hdmi_rx_en,                     0);
            break;
        }
        case _AUDIO_DP_1:
        case _AUDIO_TYPE_C_1:
        {
            //cable detect for MUTE
            HV_W32_FIELD(RX_HSRX_TOP_00,    reg_hsrx_aud_cable_detect_sel,      1);
            //DP mute & DP abnormal mute
            HV_W32_FIELD(RX_HSRX_TOP_00,    reg_hsrx_aud_dp_sel,                1);
            //set rx output
            HV_W32_FIELD(RX_AUDIO_TOP0_00,  reg_audio_rx_out_sel,               2);
            //enable DP pll
            HV_W32_FIELD(RX_AUDIO_TOP0_0C,  reg_hdmi_rx_en,                     0);
            break;
        }
        case _AUDIO_PATTERN:
        {
            HV_W32_FIELD(RX_AUDIO_TOP0_00,  reg_audio_rx_out_sel,               3);
            HV_W32_FIELD(RX_AUDIO_TOP0_00,  reg_audio_pattern_ctl,              3);
            break;
        }
        case _AUDIO_I2S_PAD:
        {
            HV_W32_FIELD(RX_AUDIO_TOP0_00,  reg_audio_rx_out_sel,               0);
            HV_W32_FIELD(RX_AUDIO_TOP0_08,  reg_audio_i2s_rx_src_sel_0,         0x888);

            //rx->tx
            //HV_W32_FIELD(RX_AUDIO_TOP1_E8,  reg_audio_tx_i2s_pcm_sel,           0);
            //bypass
            HV_W32_FIELD(RX_AUDIO_TOP0_00,  reg_audio_rxtx_bypass_en,           1);
            break;
        }
        case _AUDIO_SPDIF_PAD:
        {
            HV_W32_FIELD(RX_AUDIO_TOP0_00,  reg_audio_rx_out_sel,               1);
            HV_W32_FIELD(RX_AUDIO_TOP1_E8,  reg_audio_tx_i2s_pcm_sel,           0);
            break;
        }
        default:
        {
            HV_LOG_ASSERT(AUDIO, "Set an error audio source!");
            return HV_FAILURE;
        }
    }

    return HV_SUCCESS;
}

/**
 * @brief audio spdif out.
 */
VOID Hv_Cal_Audio_SetSpdifOutGpio(BOOL bAudioSpdifOut)
{
    HV_LOG_DEBUG(AUDIO, "Hv_Cal_Audio_SetSpdifOutGpio.");

    //set gpio
    //io mode
    HV_W32_FIELD(RX_SH08_TOP_RX_0X40,       reg_io_user_mode,                   1);

    //pin share
    if (bAudioSpdifOut)
    {
        HV_W32_FIELD(RX_SH08_TOP_RX_CTRL_0, reg_gpio19_func_sel,                6);
    }
    else
    {
        HV_W32_FIELD(RX_SH08_TOP_RX_CTRL_0, reg_gpio19_func_sel,                5);
    }
    HV_W32_FIELD(RX_SH08_TOP_RX_CTRL_8,     reg_gpio19_pin_sel,                 0);
    HV_W32_FIELD(RX_SH08_TOP_RX_CTRL_28,    reg_gpio19_io_ctrl,                 103);

    return;
}

/**
 * @brief audio datapath mute_module init.
 */
VOID Hv_Cal_Audio_DataPathMuteModuleInit(VOID)
{
    UINT32 uiRegValue = 0;

    //mute:hardware or reg_audio_sw_mute_en
    HV_W32_FIELD(RX_AUDIO_TOP0_04,          reg_audio_mute_sel,                 0x1);
    HV_W32_FIELD(RX_AUDIO_TOP0_04,          reg_audio_sw_mute_en,               0x0);

    //unmute:software
    HV_W32_FIELD(RX_AUDIO_TOP0_04,          reg_audio_mute_clr_sel,             0x0);

    //enable mute interruptes--add _AUDIO_PATH_UNMUTE
    HV_R32_DECL_VAR();
    uiRegValue = HV_R32_FIELD(RX_AUDIO_TOP4_D4, reg_audio_int_en);
    uiRegValue &= _AUDIO_DETECT_FS;
    uiRegValue |= _AUDIO_PATH_UNMUTE;
    HV_W32_FIELD(RX_AUDIO_TOP4_D4,          reg_audio_int_en,                   uiRegValue);
    HV_LOG_DEBUG(AUDIO, "Set reg_audio_int_en = %x\n.", uiRegValue);

#ifdef HV_PROJECT_CONFIG_AUDIO_ONLY_TRIGGER_UNMUTE
    //Trigger unMute
    HV_W32_FIELD(RX_AUDIO_TOP4_DC,          reg_audio_int_edge_n,               _AUDIO_PATH_UNMUTE);
    g_uiInterruptTriggerMode = _AUDIO_INT_EDGE_N;
#else
    //Trigger Mute--add _AUDIO_PATH_UNMUTE
    uiRegValue = HV_R32_FIELD(RX_AUDIO_TOP4_DC, reg_audio_int_edge_p);
    uiRegValue &= _AUDIO_DETECT_FS;
    uiRegValue |= _AUDIO_PATH_UNMUTE;
    HV_W32_FIELD(RX_AUDIO_TOP4_DC,          reg_audio_int_edge_p,               uiRegValue);
    g_uiInterruptTriggerMode = _AUDIO_INT_EDGE_P;
#endif

    return;
}

/**
 * @brief audio interrupt Trigger unMute.
 */
VOID Hv_Cal_Audio_SetUnMuteTrigger(VOID)
{
    UINT32 uiRegValue = 0;
    //HV_LOG_ASSERT(AUDIO, "Hv_Cal_Audio_SetUnMuteTrigger.");

    //edge_n set _AUDIO_PATH_UNMUTE
    HV_W32_FIELD(RX_AUDIO_TOP4_E0,          reg_audio_int_edge_n,               _AUDIO_PATH_UNMUTE);

    //edge_p: clear _AUDIO_PATH_UNMUTE
    HV_R32_DECL_VAR();
    uiRegValue = HV_R32_FIELD(RX_AUDIO_TOP4_DC, reg_audio_int_edge_p);
    uiRegValue &= ~_AUDIO_PATH_UNMUTE;
    HV_W32_FIELD(RX_AUDIO_TOP4_DC,          reg_audio_int_edge_p,               uiRegValue);

    g_uiInterruptTriggerMode = _AUDIO_INT_EDGE_N;
    return;
}

/**
 * @brief audio interrupt Trigger Mute.
 */
VOID Hv_Cal_Audio_SetMuteTrigger(VOID)
{
    UINT32 uiRegValue = 0;
    //HV_LOG_ASSERT(AUDIO, "Hv_Cal_Audio_SetMuteTrigger.");

    //edge_p: add _AUDIO_PATH_UNMUTE
    HV_R32_DECL_VAR();
    uiRegValue = HV_R32_FIELD(RX_AUDIO_TOP4_DC, reg_audio_int_edge_p);
    uiRegValue &= _AUDIO_DETECT_FS;
    uiRegValue |= _AUDIO_PATH_UNMUTE;
    HV_W32_FIELD(RX_AUDIO_TOP4_DC,          reg_audio_int_edge_p,               uiRegValue);

    //edge_n: clear
    HV_W32_FIELD(RX_AUDIO_TOP4_E0,          reg_audio_int_edge_n,               0);

    g_uiInterruptTriggerMode = _AUDIO_INT_EDGE_P;
    return;
}

/**
 * @brief audio datapath unmute.
 */
VOID Hv_Cal_Audio_ClearTXMute_EnableAllInt(BOOL bDpisPlay)
{
    UINT32 uiRegValue = 0;
    HV_R32_DECL_VAR();

    HV_W32_FIELD(RX_AUDIO_TOP0_04,          reg_audio_mute_clr,                 1);
    HV_W32_FIELD(RX_AUDIO_TOP0_04,          reg_audio_mute_clr,                 0);

    HV_W32_FIELD(RX_AUDIO_TOP4_D8,          reg_audio_int_clr,                  0x7ff);
    HV_W32_FIELD(RX_AUDIO_TOP4_D8,          reg_audio_int_clr,                  0);
    UINT32 uiAudioOuput = HV_R32_FIELD(RX_AUDIO_TOP0_00,  reg_audio_rx_out_sel);
    //enable all interruptes
    uiRegValue = _AUDIO_DETECT_FS | _AUDIO_PATH_UNMUTE;
    
    if(!bDpisPlay)
    {
        uiRegValue &= (~_DP_AUDIO_PATH_UNMUTE);
    }

    if(uiAudioOuput != 4)
    {
        uiRegValue &= ~0x300; //disable hdmi interrupt 
    }
    HV_W32_FIELD(RX_AUDIO_TOP4_D4,          reg_audio_int_en,                   uiRegValue);
    HV_LOG_DEBUG(AUDIO, "Set reg_audio_int_en = %x\n.", uiRegValue);

    Hv_Vos_WClrMiscInt(2);
    Hv_Vos_UnmaskIrq(HV_CHIP_IRQ_AUDIO);
    return;
}

/**
 * @brief audio datapath unmute interrupt clear.
 */
VOID Hv_Cal_Audio_DisableAllInt_ClearInt(UINT32 uiIntFlag)
{
    //disable all interruptes
    HV_W32_FIELD(RX_AUDIO_TOP4_D4,          reg_audio_int_en,                   0);

    HV_W32_FIELD(RX_AUDIO_TOP4_D8,          reg_audio_int_clr,                  uiIntFlag);
    HV_W32_FIELD(RX_AUDIO_TOP4_D8,          reg_audio_int_clr,                  0);

    return;
}

/**
 * @brief audio datapath unmute interrupt clear.
 */
VOID Hv_Cal_Audio_ClearInt(UINT32 uiIntFlag)
{
    HV_W32_FIELD(RX_AUDIO_TOP4_D8,          reg_audio_int_clr,                  uiIntFlag);
    HV_W32_FIELD(RX_AUDIO_TOP4_D8,          reg_audio_int_clr,                  0);

    return;
}

/**
 * @brief audio datapath mute Source.
 */
UINT32 Hv_Cal_Audio_DataPathMuteSource(VOID)
{
    UINT32 uiRegValue = 0;

    HV_R32_DECL_VAR();
    uiRegValue = HV_R32_FIELD(RX_AUDIO_TOP4_E4, regr_audio_int_out);

    return uiRegValue;
}

/**
 * @brief audio fs's detect init.
 */
VOID Hv_Cal_Audio_DetectFsModuleInit(VOID)
{
    UINT32 uiRegValue = 0;
    HV_R32_DECL_VAR();

    //enable fs moniter interruptes--add _AUDIO_DETECT_FS
    uiRegValue = HV_R32_FIELD(RX_AUDIO_TOP4_D4, reg_audio_int_en);
    uiRegValue &= _AUDIO_PATH_UNMUTE;
    uiRegValue |= _AUDIO_DETECT_FS;
    HV_W32_FIELD(RX_AUDIO_TOP4_D4,          reg_audio_int_en,                   uiRegValue);

    //Trigger fs change
    HV_W32_FIELD(RX_AUDIO_TOP2_E8,          reg_audpll_pg0_det_high,            0x16400);
    HV_W32_FIELD(RX_AUDIO_TOP2_EC,          reg_audpll_pg0_det_low,             0x7800);

    //edge_p trigger--add _AUDIO_DETECT_FS
    uiRegValue = HV_R32_FIELD(RX_AUDIO_TOP4_DC, reg_audio_int_edge_p);
    uiRegValue &= _AUDIO_PATH_UNMUTE;
    uiRegValue |= _AUDIO_DETECT_FS;
    HV_W32_FIELD(RX_AUDIO_TOP4_DC,          reg_audio_int_edge_p,               uiRegValue);

    return;
}

/**
 * @brief audio fs's detect init.
 */
VOID Hv_Cal_Audio_SetSpdifTX(VOID)
{
    //SPDIF_TX
    HV_W32_FIELD(SYS_SH08_TOP_TX_CTRL_0,    reg_gpio10_func_sel,                3);
    HV_W32_FIELD(SYS_SH08_TOP_TX_CTRL_8,    reg_gpio10_pin_sel,                 0);
    HV_W32_FIELD(SYS_SH08_TOP_TX_CTRL_1C,   reg_gpio10_io_ctrl,                 111);

    return;
}

