/**
 * @file hv_cal_Gpio.c
 * @brief gpio driver  layer file.
 * @details This file provides the following functions: \n
 *          (1) gpio pull up/down \n
 *          (2) gpio set direction \n
 *          (3) gpio set irq trigger mode/callback \n
 *          (4) gpio read irq state \n
 *          (5) gpio read level \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2023-05-30
 * @copyright Copyright(c),2023-5, Hiview Software. All rights reserved.
 * @par History:
  */
#include "hv_chip_Config.h"
#include "hv_vos_Comm.h"
#include "hv_comm_Assert.h"
#include "hv_cal_Gpio.h"
#include "hv_comm_Define.h"

#define HV_GPIO_PORT0_PIN_NUM              (40UL)
#define HV_GPIO_PORT1_PIN_NUM              (40UL)
#define HV_GPIO_PORT0_1_PIN_NUM            (HV_GPIO_PORT0_PIN_NUM + HV_GPIO_PORT1_PIN_NUM)

#define HV_GPIO0_GROUP0_NUM                (20UL)
#define HV_GPIO0_GROUP1_NUM                (HV_GPIO_PORT0_PIN_NUM - HV_GPIO0_GROUP0_NUM)
#define HV_GPIO1_GROUP0_NUM                (20UL)
#define HV_GPIO1_GROUP1_NUM                (HV_GPIO_PORT1_PIN_NUM - HV_GPIO1_GROUP0_NUM)

#define GPIO_INT_NUM    10

typedef struct _GpioIntConfig
{
    BOOL bIrqInit[GPIO_INT_NUM];
    UINT32 uiPinNum[GPIO_INT_NUM];
    GpioPort  enPortIdx[GPIO_INT_NUM];
    GpioIndex enGpioIdx[GPIO_INT_NUM];
    UINT32 uiGpioBit[GPIO_INT_NUM];
    GpioIntCallBack pfCallBack[GPIO_INT_NUM];
} GpioIntConfig;

typedef struct _GpioConfig
{
    BOOL bIrqInit[GPIO_INT_HANDLER_MAX];
} GpioConfig;

typedef struct _GpioPinMap
{
    GpioPort  enPortIdx;
    GpioIndex enGpioIdx;
    UINT32 uiGpioBit;
    GpioDomain enGpioDomain;
}GpioPinMap;

/* HT7315 42 Gpios mapping TBL
No  PIN.No  PAD.Name
0  208 GPIO0
1  209 GPIO1
2  210 GPIO2
3  211 GPIO3
4  213 GPIO4
5  214 GPIO5
6  215 GPIO6
7  216 GPIO7
8  204 UART0_RX
9  205 UART0_TX
10 202 UART1_RX
11 203 UART1_TX
12 207 I2CS0_SCL
13 206 I2CS0_SDA
14  57 GPIO19
15  59 GPIO20
16  61 GPIO21
17  63 GPIO22
18  64 GPIO23
19  65 GPIO24
20  58 GPIO25
21  60 GPIO26
22  62 GPIO27
23  67 GPIO28
24  68 GPIO29
25 106 MSPI_MISO
26 103 MSPI_SCK
27 105 MSPI_CS
28 102 MSPI_MOSI
29 104 MSPI_HOLD
30 107 MSPI_WP
31 114 I2CM0_SCL
32 113 I2CM0_SDA
33  97 GPIO10
34  92 GPIO11
35  93 GPIO12
36  96 GPIO13
37  94 GPIO14
38  98 GPIO15
39  99 GPIO16
40 100 GPIO17
41 101 GPIO18
*/
static const UCHAR8 s_GpioPinMap[HV_GPIO_MAX_NUM] =
{
    208, 209, 210, 211, 213, 214, 215, 216, 204, 205, // 00-09
    202, 203, 207, 206, 57, 59, 61, 63, 64, 65,       // 10-19
    58, 60, 62, 67, 68, 106, 103, 105, 102, 104,      // 20-29
    107, 114, 113, 97, 92, 93, 96, 94, 98, 99,        // 30-39
    100, 101,                                         // 40-41
};

/*No  PIN.No  PAD.Name
    0  161 SDBY_0
    1  162 SDBY_1
    2  194 HDMI_RX1_CEC
    3  164 SDBY_3
    4  165 SDBY_4
    5  166 SDBY_5
    6  186 SDBY_6
    7  191 SDBY_7
*/
static const UCHAR8 s_GpioSdbyPinMap[HV_GPIO_STBY_PIN_MAX_NUM][2] =
{
    {161,},
    {162,},
    {163,194},
    {164,195},
    {165,182},
    {166,185},
    {186,189},
    {191,}
};

static GpioConfig s_stGpio = {0};
static GpioIntConfig s_stIntGpio = {0};

/**
 * @brief get standby gpio index from pin index.
 * @param[in] ucPinIdx: pad no.
 * @param[out] pstPinMap:port/gpio index, gpio bit
 * @return Status
 */
static inline Status Hv_Gpio_StbyPinMapIndex(UCHAR8 ucPinIdx, GpioPinMap *pstPinMap)
{
    UINT32 uiGpioIdx = 0;

    for (uiGpioIdx = 0; uiGpioIdx < HV_GPIO_STBY_PIN_MAX_NUM; uiGpioIdx++)
    {
        if ((s_GpioSdbyPinMap[uiGpioIdx][0] == ucPinIdx) || (s_GpioSdbyPinMap[uiGpioIdx][1] == ucPinIdx))
        {
            pstPinMap->enGpioDomain = GPIO_DOMAIN_SDBY;
            pstPinMap->enGpioIdx = uiGpioIdx;
            pstPinMap->uiGpioBit = uiGpioIdx;
            return HV_SUCCESS;
        }
    }
    pstPinMap->enGpioDomain = GPIO_DOMAIN_SYS;
    return HV_FAILURE;
}

/**
 * @brief get gpio index from pin index.
 * @param[in] ucPinIdx: pad no.
 * @param[out] pstPinMap:port/gpio index, gpio bit
 * @return Status
 */
static Status Hv_Gpio_MapPinIndex(UCHAR8 ucPinIdx, GpioPinMap *pstPinMap)
{
    UINT32 uiGpioIdx = 0;
    Hv_Vos_Memset(pstPinMap, 0, sizeof(GpioPinMap));
    //Get standy gpio index
    if (HV_SUCCESS == Hv_Gpio_StbyPinMapIndex(ucPinIdx, pstPinMap))
    {
        HV_LOG_DEBUG(GPIO, "Map standby pin (%d).\n", ucPinIdx);
        return HV_SUCCESS;
    }

    //Get system gpio index
    for (uiGpioIdx = 0; uiGpioIdx < HV_GPIO_MAX_NUM; uiGpioIdx++)
    {
        if (s_GpioPinMap[uiGpioIdx] == ucPinIdx)
        {
            break;
        }
    }

    if (uiGpioIdx >= HV_GPIO_MAX_NUM)
    {
        HV_LOGV("Map Gpio pin(%d) error.\n", ucPinIdx);
        return HV_FAILURE;
    }

    if (uiGpioIdx < HV_GPIO_PORT0_PIN_NUM)
    {
        pstPinMap->enPortIdx = GPIO_PORT0;
        pstPinMap->enGpioIdx = (GpioIndex)uiGpioIdx;
        if (uiGpioIdx < HV_GPIO0_GROUP0_NUM)//20
        {
            pstPinMap->uiGpioBit = uiGpioIdx;
        }
        else//40
        {
            pstPinMap->uiGpioBit = uiGpioIdx - HV_GPIO0_GROUP0_NUM;
        }
    }
    else if (uiGpioIdx < HV_GPIO_PORT0_1_PIN_NUM)
    {
        pstPinMap->enPortIdx = GPIO_PORT1;
        uiGpioIdx -= HV_GPIO_PORT0_PIN_NUM;
        pstPinMap->enGpioIdx = (GpioIndex)uiGpioIdx;
        if (uiGpioIdx < HV_GPIO1_GROUP0_NUM)//20
        {
            pstPinMap->uiGpioBit = uiGpioIdx;
        }
        else
        {
            pstPinMap->uiGpioBit = uiGpioIdx - HV_GPIO1_GROUP0_NUM;
        }
    }
    else
    {
        HV_LOG_ERROR(GPIO, "Not support gpio (%d).\n", uiGpioIdx);
        return HV_FAILURE;
    }

    return HV_SUCCESS;
}

/*
*HV_CHIP_IRQ_GPIO_CH0:gpio0[39:0],HV_GPIO0_IntCallback
*HV_CHIP_IRQ_GPIO_CH1:gpio1[39:0],HV_GPIO1_IntCallback
*HV_CHIP_IRQ_GPIO_CH2:gpio2[1:0], HV_GPIO2_IntCallback
*HV_CHIP_IRQ_GPIO_CH3:gpio3[1:0], HV_GPIO3_IntCallback
*/
static VOID Hv_Gpio_GetIntDetectState(GpioIntState *pstPinInts)
{
    UINT32 uiValue[GPIO_INT_STATE_COUNT] = {0};//4
    uiValue[GPIO_INT_STATE_0] = HV_R32(CPU_SYS_GPIO0_PULSE_DETECT_INT_STATE) & HV_GPIO_GENERAL_INT_REG_MASK & ~(HV_R32(CPU_SYS_GPIO0_INT_MASK));
    uiValue[GPIO_INT_STATE_1] = HV_R32(CPU_SYS_GPIO0_GPIO1_PULSE_DETECT_INT_STATE) & HV_GPIO_GENERAL_INT_REG_MASK & ~(HV_R32(CPU_SYS_GPIO0_GPIO1_INT_MASK));
    uiValue[GPIO_INT_STATE_2] = HV_R32(CPU_SYS_GPIO0_GPIO2_PULSE_DETECT_INT_STATE) & HV_GPIO_GENERAL_INT_REG_MASK & ~(HV_R32(CPU_SYS_GPIO0_GPIO2_INT_MASK));
    uiValue[GPIO_INT_STATE_3] = HV_R32(CPU_SYS_GPIO0_GPIO3_PULSE_DETECT_INT_STATE) & HV_GPIO_GENERAL_INT_REG_MASK & ~(HV_R32(CPU_SYS_GPIO0_GPIO3_INT_MASK));

    pstPinInts->uiIntState[0] = uiValue[GPIO_INT_STATE_0];
    pstPinInts->uiIntState[1] = uiValue[GPIO_INT_STATE_1];
    pstPinInts->uiIntState[2] = uiValue[GPIO_INT_STATE_2];
    pstPinInts->uiIntState[3] = uiValue[GPIO_INT_STATE_3];
    return;
}

/**@brief Set Gpio port0 interrupt callback
 *  @param[in] irq number and params
 */
static HV_VOS_ISR_RESULT_E Hv_Gpio0_IntCallback(UINT32 uiIrqNum, VOID *pArg)
{
    GpioIntState stPinInts = {0};
    UCHAR8 ucLoop = 0;
    HV_UNUSED(uiIrqNum);

    Hv_Gpio_GetIntDetectState(&stPinInts);

    HV_W32_FIELD(CPU_SYS_GPIO0_INT_CLR, gpio0_int_clr, 0xFFFFF);
    HV_W32_FIELD(CPU_SYS_GPIO0_INT_CLR, gpio0_int_clr, 0x00000);
    HV_W32_FIELD(CPU_SYS_GPIO0_GPIO1_INT_CLR, gpio1_int_clr, 0xFFFFF);
    HV_W32_FIELD(CPU_SYS_GPIO0_GPIO1_INT_CLR, gpio1_int_clr, 0x00000);

    for (ucLoop=0; ucLoop<GPIO_INT_NUM; ucLoop++)
    {
        if (s_stIntGpio.bIrqInit[ucLoop] == HV_FALSE)
        {
            continue;
        }
        if (s_stIntGpio.enPortIdx[ucLoop] == GPIO_PORT0)
        {
            if (s_stIntGpio.enGpioIdx[ucLoop] < HV_GPIO0_GROUP0_NUM)//20
            {
                if ((1 << s_stIntGpio.uiGpioBit[ucLoop]) & stPinInts.uiIntState[0])
                {
                    s_stIntGpio.pfCallBack[ucLoop](&stPinInts, pArg);
                }
            }
            else//40
            {
                if ((1 << s_stIntGpio.uiGpioBit[ucLoop]) & stPinInts.uiIntState[1])
                {
                    s_stIntGpio.pfCallBack[ucLoop](&stPinInts, pArg);
                }
            }
        }
    }
    return HV_VOS_ISR_HANDLED;
}

/**@brief Set Gpio port0 interrupt callback
 *  @param[in] irq number and params
 */

static HV_VOS_ISR_RESULT_E Hv_Gpio1_IntCallback(UINT32 uiIrqNum, VOID *pArg)
{
    GpioIntState stPinInts = {0};
    UCHAR8 ucLoop = 0;
    HV_UNUSED(uiIrqNum);
    Hv_Gpio_GetIntDetectState(&stPinInts);

    HV_W32_FIELD(CPU_SYS_GPIO0_GPIO2_INT_CLR, gpio2_int_clr, 0xFFFFF);
    HV_W32_FIELD(CPU_SYS_GPIO0_GPIO2_INT_CLR, gpio2_int_clr, 0x00000);
    HV_W32_FIELD(CPU_SYS_GPIO0_GPIO3_INT_CLR, gpio3_int_clr, 0xFFFFF);
    HV_W32_FIELD(CPU_SYS_GPIO0_GPIO3_INT_CLR, gpio3_int_clr, 0x00000);

    for (ucLoop=0; ucLoop<GPIO_INT_NUM; ucLoop++)
    {
        if (s_stIntGpio.bIrqInit[ucLoop] == HV_FALSE)
        {
            continue;
        }
        if (s_stIntGpio.enPortIdx[ucLoop] == GPIO_PORT1)
        {
            if (s_stIntGpio.enGpioIdx[ucLoop] < HV_GPIO1_GROUP0_NUM)//20
            {
                if ((1 << s_stIntGpio.uiGpioBit[ucLoop]) & stPinInts.uiIntState[2])
                {
                    s_stIntGpio.pfCallBack[ucLoop](&stPinInts, pArg);
                }
            }
            else//40
            {
                if ((1 << s_stIntGpio.uiGpioBit[ucLoop]) & stPinInts.uiIntState[3])
                {
                    s_stIntGpio.pfCallBack[ucLoop](&stPinInts, pArg);
                }
            }
        }
    }

    return HV_VOS_ISR_HANDLED;
}

/**@brief Set input Gpio interrupt trigger mode
 *  @param[in] ipstpinMap pinmap and mask value and trigger mode value
 */
static VOID Hv_Gpio_SetIntTriggerMode(const GpioPinMap *pstpinMap, GpioIntTrigMode enIntTrigMode)
{
    UINT32 szReg[HV_GPIO_PIN_INT_STATE_COUNT_MAX] = {0};
    UINT32 uiMaskShift = 0;
    UINT32 uiMask = 0x7;//3'b111 for every uiTrigger mode
    UINT32 uiGpioIdx = (UINT32)pstpinMap->enGpioIdx;
    UINT32 uiTrig = 0x04;//rising mode

    switch (enIntTrigMode)
    {
        case GPIO_INT_HIGHLEVEL:
        {
            uiTrig = 0x0;
            break;
        }
        case GPIO_INT_LOWLEVEL:
        {
            uiTrig = 0x1;
            break;
        }
        case GPIO_INT_RISING:
        {
            uiTrig = 0x4;
            break;
        }
        case GPIO_INT_FALLING:
        {
            uiTrig = 0x5;
            break;
        }
        case GPIO_INT_RISING_FALLING:
        {
            uiTrig = 0x6;
            break;
        }
        default:
        {
            HV_LOGI("Unknown trig_mode.\n");
            return;
        }
    }

    switch (pstpinMap->enPortIdx)
    {
        case GPIO_PORT0:
        {
            szReg[0] = CPU_SYS_GPIO0_GPIO_TRG_MODE_0;
            szReg[1] = CPU_SYS_GPIO0_GPIO_TRG_MODE_1;
            szReg[2] = CPU_SYS_GPIO0_GPIO_TRG_MODE_2;
            szReg[3] = CPU_SYS_GPIO0_GPIO_TRG_MODE_3;
            szReg[4] = CPU_SYS_GPIO0_GPIO_TRG_MODE_4;
            szReg[5] = CPU_SYS_GPIO0_GPIO_TRG_MODE_5;
            break;
        }
        case GPIO_PORT1:
        {
            szReg[0] = CPU_SYS_GPIO0_GPIO_TRG_MODE_10;
            szReg[1] = CPU_SYS_GPIO0_GPIO_TRG_MODE_11;
            szReg[2] = CPU_SYS_GPIO0_GPIO_TRG_MODE_12;
            szReg[3] = CPU_SYS_GPIO0_GPIO_TRG_MODE_13;
            szReg[4] = CPU_SYS_GPIO0_GPIO_TRG_MODE_14;
            szReg[5] = CPU_SYS_GPIO0_GPIO_TRG_MODE_15;
            break;
        }
        default:
        {
            HV_LOGI("Not support gpio port.\n");
            return;
        }
    }

    if (uiGpioIdx < GPIO_IDX6)
    {
        //3bit for every uiTrigger mode
        uiMaskShift = uiGpioIdx*3;
        HV_W32_MASK(szReg[0], uiMask<<uiMaskShift, uiTrig<<uiMaskShift);
    }
    else if ((uiGpioIdx >= GPIO_IDX7)&&(uiGpioIdx <= GPIO_IDX12))
    {
        //pin index and add 1 bit
        uiMaskShift = (uiGpioIdx - 7)*3 + 1;
        HV_W32_MASK(szReg[1], uiMask<<uiMaskShift, uiTrig<<uiMaskShift);
    }
    else if ((uiGpioIdx >= GPIO_IDX14) && (uiGpioIdx <= GPIO_IDX19))
    {
        uiMaskShift = (uiGpioIdx - 14)*3 + 2;
        HV_W32_MASK(szReg[2], uiMask<<uiMaskShift, uiTrig<<uiMaskShift);
    }
    else if((uiGpioIdx >= GPIO_IDX20)&&(uiGpioIdx <= GPIO_IDX25))
    {
        uiMaskShift = (uiGpioIdx - 20)*3;
        HV_W32_MASK(szReg[3], uiMask<<uiMaskShift, uiTrig<<uiMaskShift);
    }
    else if ((uiGpioIdx >= GPIO_IDX27)&&(uiGpioIdx <= GPIO_IDX32))
    {
        uiMaskShift = (uiGpioIdx - 27)*3 + 1;
        HV_W32_MASK(szReg[4], uiMask<<uiMaskShift, uiTrig<<uiMaskShift);
    }
    else if ((uiGpioIdx >= GPIO_IDX34) && (uiGpioIdx <= GPIO_IDX39))
    {
        uiMaskShift = (uiGpioIdx - 34)*3 + 2;
        HV_W32_MASK(szReg[5], uiMask<<uiMaskShift, uiTrig<<uiMaskShift);
    }
    else if (uiGpioIdx == GPIO_IDX6)
    {
        //uiTrig value low 2bits
        HV_W32_MASK(szReg[0], (uiMask&(~0x04))<<(3*uiGpioIdx - 20*0), (uiTrig&(~0x04))<<(3*uiGpioIdx));
        //uiTrig value high 1 bit
        HV_W32_MASK(szReg[1], ((uiMask&(0x04))>>2),((uiTrig&(0x04))>>2));
    }
    else if (uiGpioIdx == GPIO_IDX13)
    {
        //uiTrig value low 1bit
        HV_W32_MASK(szReg[1], (uiMask&(~0x06))<<(3*uiGpioIdx - 20*1), (uiTrig&(~0x06))<<(3*uiGpioIdx - 20));
        //uiTrig value high 2 bits
        HV_W32_MASK(szReg[2], ((uiMask&(0x06))>>1), ((uiTrig&(0x06))>>1));
    }
    else if (uiGpioIdx == GPIO_IDX26)
    {
        //uiTrig value low 2bits
        HV_W32_MASK(szReg[3], (uiMask&(~0x04))<<(3*uiGpioIdx - 20*3), (uiTrig&(~0x04))<<(3*uiGpioIdx - 60));
        //uiTrig value high 1 bit
        HV_W32_MASK(szReg[4], ((uiMask&(0x04))>>2),((uiTrig&(0x04))>>2));
    }
    else if (uiGpioIdx == GPIO_IDX33)
    {
        //uiTrig value low 1bit
        HV_W32_MASK(szReg[4], (uiMask&(~0x06))<<(3*uiGpioIdx - 20*4), (uiTrig&(~0x06))<<(3*uiGpioIdx - 80));
        //uiTrig value high 2 bits
        HV_W32_MASK(szReg[5], ((uiMask&(0x06))>>1), ((uiTrig&(0x06))>>1));
    }
    else
    {
        //do nothing
    }
    return;
}

/**@brief Init Gpio interrupt
 *  @param[in] ipstpinMap pinmap
 */
static VOID Hv_Gpio_InitInt(const GpioPinMap *pstpinMap)
{
    if ((pstpinMap->enPortIdx == GPIO_PORT0)
         && (s_stGpio.bIrqInit[GPIO_INT_HANDLER0] == HV_FALSE))
    {
        Hv_Vos_AttachIsr(HV_CHIP_IRQ_GPIO_CH0, Hv_Gpio0_IntCallback, NULL);
        Hv_Vos_UnmaskIrq(HV_CHIP_IRQ_GPIO_CH0);
        s_stGpio.bIrqInit[GPIO_INT_HANDLER0] = HV_TRUE;
        HV_W32_FIELD(CPU_SYS_GPIO0_DEBOUNCE_EN, deglitch_capacity, 0x10000);
    }
    else if ((pstpinMap->enPortIdx == GPIO_PORT1)
        && (s_stGpio.bIrqInit[GPIO_INT_HANDLER1] == HV_FALSE))
    {
        Hv_Vos_AttachIsr(HV_CHIP_IRQ_GPIO_CH1, Hv_Gpio1_IntCallback, NULL);
        Hv_Vos_UnmaskIrq(HV_CHIP_IRQ_GPIO_CH1);
        s_stGpio.bIrqInit[GPIO_INT_HANDLER1] = HV_TRUE;
        HV_W32_FIELD(CPU_SYS_GPIO0_DEBOUNCE_EN, deglitch_capacity, 0x10000);
    }
    else
    {
        return;
    }
}

/** Claerup All interrupts
 *  @param[in] None
 */
static VOID Hv_Gpio_ClrAllInts(VOID)
{
    //port0: 40 gpios,intterrupt clear
    HV_W32_FIELD(CPU_SYS_GPIO0_INT_CLR, gpio0_int_clr, 0xFFFFF);
    HV_W32_FIELD(CPU_SYS_GPIO0_INT_CLR, gpio0_int_clr, 0x00000);
    HV_W32_FIELD(CPU_SYS_GPIO0_GPIO1_INT_CLR, gpio1_int_clr, 0xFFFFF);
    HV_W32_FIELD(CPU_SYS_GPIO0_GPIO1_INT_CLR, gpio1_int_clr, 0x00000);

    //port1: 40 gpios,intterrupt clear
    HV_W32_FIELD(CPU_SYS_GPIO0_GPIO2_INT_CLR, gpio2_int_clr, 0xFFFFF);
    HV_W32_FIELD(CPU_SYS_GPIO0_GPIO2_INT_CLR, gpio2_int_clr, 0x00000);
    HV_W32_FIELD(CPU_SYS_GPIO0_GPIO3_INT_CLR, gpio3_int_clr, 0xFFFFF);
    HV_W32_FIELD(CPU_SYS_GPIO0_GPIO3_INT_CLR, gpio3_int_clr, 0x00000);
    return;
}

/** Disable All interrupts
 *  @param[in] None
 */
static VOID Hv_Gpio_DisableAllInts(VOID)
{
    HV_W32(CPU_SYS_GPIO0_INT_MASK,       0xFFFFFFU);
    HV_W32(CPU_SYS_GPIO0_GPIO1_INT_MASK, 0xFFFFFFU);
    HV_W32(CPU_SYS_GPIO0_GPIO2_INT_MASK, 0xFFFFFFU);
    HV_W32(CPU_SYS_GPIO0_GPIO3_INT_MASK, 0xFFFFFFU);
    Hv_Gpio_ClrAllInts();
    return;
}

/** Mask Gpio Interrupt
 *  @param[in] pstpinMap pinmap and mask value
 */
static VOID Hv_Gpio_MaskInt(const GpioPinMap *pstpinMap, UCHAR8 mask)
{
    UINT32 uiVal = 0;
    switch (pstpinMap->enPortIdx)
    {
        case GPIO_PORT0:
        {
            if (pstpinMap->enGpioIdx < HV_GPIO0_GROUP0_NUM)//20
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_INT_MASK);
                uiVal = mask ? (uiVal | (1 << pstpinMap->uiGpioBit)) : (uiVal & ~(1 << pstpinMap->uiGpioBit));
                HV_W32(CPU_SYS_GPIO0_INT_MASK, uiVal);
            }
            else//40
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_GPIO1_INT_MASK);
                uiVal = mask ? (uiVal | (1 << pstpinMap->uiGpioBit)) : (uiVal & ~(1 << pstpinMap->uiGpioBit));
                HV_W32(CPU_SYS_GPIO0_GPIO1_INT_MASK, uiVal);
            }
            break;
        }
        case GPIO_PORT1:
        {
            if (pstpinMap->enGpioIdx <= HV_GPIO1_GROUP0_NUM)//20
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_GPIO2_INT_MASK);
                uiVal = mask ? (uiVal | (1 << pstpinMap->uiGpioBit)) : (uiVal & ~(1 << pstpinMap->uiGpioBit));
                HV_W32(CPU_SYS_GPIO0_GPIO2_INT_MASK, uiVal);
            }
            else//40
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_GPIO3_INT_MASK);
                uiVal = mask ? (uiVal | (1 << pstpinMap->uiGpioBit)) : (uiVal & ~(1 << pstpinMap->uiGpioBit));
                HV_W32(CPU_SYS_GPIO0_GPIO3_INT_MASK, uiVal);
            }
            break;
        }
        default:
        {
            break;
        }
    }
    return;
}

/** Get Gpio Interrupt state
 *  @param[in] pstpinMap pin map struct
 */
static BOOL Hv_Gpio_GetIntState(const GpioPinMap *pstpinMap)
{
    UINT32 uiVal = 0;

    switch (pstpinMap->enPortIdx)
    {
        case GPIO_PORT0:
        {
            if (pstpinMap->enGpioIdx < HV_GPIO0_GROUP0_NUM)
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_PULSE_DETECT_INT_STATE);
            }
            else
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_GPIO1_PULSE_DETECT_INT_STATE);
            }
            break;
        }
        case GPIO_PORT1:
        {
            if (pstpinMap->enGpioIdx < HV_GPIO1_GROUP0_NUM)
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_GPIO2_PULSE_DETECT_INT_STATE);
            }
            else
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_GPIO3_PULSE_DETECT_INT_STATE);
            }
            break;
        }
        default:
        {
            break;
        }
    }

    return ((uiVal & (1 << pstpinMap->uiGpioBit)) ? 1 : 0);
}

static VOID Hv_Cal_Gpio_SetSdbyDir(const GpioPinMap *pstpinMap, GpioDir enDir)
{
    UINT32 uiVal = 0;
    HV_R32_DECL_VAR();
    uiVal = HV_R32_FIELD(STANDBY_STANDBY_PERI_REG_STBY_GPIO0, reg_gpio_oe);

    if (enDir == GPIO_DIR_OUTPUT)
    {
        uiVal |= (BIT_0 << pstpinMap->uiGpioBit);
    }
    else
    {
        uiVal &= ~(BIT_0 << pstpinMap->uiGpioBit);
    }
    HV_W32_FIELD(STANDBY_STANDBY_PERI_REG_STBY_GPIO0, reg_gpio_oe, uiVal);
    return;
}

static GpioDir Hv_Cal_Gpio_GetSdbyDir(const GpioPinMap *pstpinMap)
{
    UINT32 uiVal = 0;
    HV_R32_DECL_VAR();
    uiVal = HV_R32_FIELD(STANDBY_STANDBY_PERI_REG_STBY_GPIO0, reg_gpio_oe);
    return (uiVal & (1 << pstpinMap->uiGpioBit) ? GPIO_DIR_OUTPUT : GPIO_DIR_INPUT);
}

static VOID Hv_Gpio_SetSdbyLevel(const GpioPinMap *pstpinMap, GpioLevel enLevel)
{
    UINT32 uiVal = 0;
    HV_R32_DECL_VAR();
    uiVal = HV_R32_FIELD(STANDBY_STANDBY_PERI_REG_STBY_GPIO0, reg_gpio_o);
    if (enLevel == GPIO_LEVEL_HIGH)
    {
        uiVal |= (BIT_0 << pstpinMap->uiGpioBit);
    }
    else
    {
        uiVal &= ~(BIT_0 << pstpinMap->uiGpioBit);
    }

    HV_W32_FIELD(STANDBY_STANDBY_PERI_REG_STBY_GPIO0, reg_gpio_o, uiVal);
    return;
}

GpioLevel Hv_Gpio_GetSdbyLevel(const GpioPinMap *pstpinMap)
{
    UINT32 uiVal = 0;
    HV_R32_DECL_VAR();
    uiVal = HV_R32_FIELD(STANDBY_STANDBY_PERI_REG_STBY_GPIO0, regr_gpio_i);

    if ((uiVal & (BIT_0 << pstpinMap->uiGpioBit)) > 0)
    {
        return GPIO_LEVEL_HIGH;
    }
    else
    {
        return GPIO_LEVEL_LOW;
    }
}

/** Clear Gpio Interrupt
 *  @param[in] pstpinMap pin map struct
 */
static VOID Hv_Gpio_ClrIntState(const GpioPinMap *pstpinMap)
{
    UINT32 uiVal = 0;

    switch (pstpinMap->enPortIdx)
    {
        case GPIO_PORT0:
        {
            if (pstpinMap->enGpioIdx < HV_GPIO0_GROUP0_NUM)
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_INT_CLR);
                HV_W32(CPU_SYS_GPIO0_INT_CLR, (uiVal | (1 << pstpinMap->uiGpioBit)));
                HV_W32(CPU_SYS_GPIO0_INT_CLR, (uiVal & ~(1 << pstpinMap->uiGpioBit)));
            }
            else
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_GPIO1_INT_CLR);
                HV_W32(CPU_SYS_GPIO0_GPIO1_INT_CLR, (uiVal | (1 << pstpinMap->uiGpioBit)));
                HV_W32(CPU_SYS_GPIO0_GPIO1_INT_CLR, (uiVal & ~(1 << pstpinMap->uiGpioBit)));
            }
            break;
        }
        case GPIO_PORT1:
        {
            if (pstpinMap->enGpioIdx < HV_GPIO1_GROUP0_NUM)
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_GPIO2_INT_CLR);
                HV_W32(CPU_SYS_GPIO0_GPIO2_INT_CLR, (uiVal | (1 << pstpinMap->uiGpioBit)));
                HV_W32(CPU_SYS_GPIO0_GPIO2_INT_CLR, (uiVal & ~(1 << pstpinMap->uiGpioBit)));
            }
            else
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_GPIO3_INT_CLR);
                HV_W32(CPU_SYS_GPIO0_GPIO3_INT_CLR, (uiVal | (1 << pstpinMap->uiGpioBit)));
                HV_W32(CPU_SYS_GPIO0_GPIO3_INT_CLR, (uiVal & ~(1 << pstpinMap->uiGpioBit)));
            }
            break;
        }
        default:
        {
            break;
        }
    }
    return;
}

/** Set Gpio direction
 *  @param[in] pstpinMap pin map struct and direction
 */
static VOID Hv_Gpio_SetDirection(const GpioPinMap *pstpinMap, GpioDir enDir)
{
    switch (pstpinMap->enPortIdx)
    {
        case GPIO_PORT0:
        {
            if (pstpinMap->enGpioIdx < HV_GPIO0_GROUP0_NUM)
            {
                HV_W32(enDir ? CPU_SYS_GPIO0_GPIO_OE0_SET : CPU_SYS_GPIO0_GPIO_OE0_CLR, (1 << pstpinMap->uiGpioBit));
            }
            else
            {
                HV_W32(enDir ? CPU_SYS_GPIO0_GPIO_OE1_SET : CPU_SYS_GPIO0_GPIO_OE1_CLR, (1 << pstpinMap->uiGpioBit));
            }
            break;
        }
        case GPIO_PORT1:
        {
            if (pstpinMap->enGpioIdx < HV_GPIO1_GROUP0_NUM)
            {
                HV_W32(enDir ? CPU_SYS_GPIO0_GPIO_OE2_SET : CPU_SYS_GPIO0_GPIO_OE2_CLR, (1 << pstpinMap->uiGpioBit));
            }
            break;
        }
        default:
        {
            break;
        }
    }
    return;
}


/** Get Gpio direction
 *  @param[in] pstpinMap pin map struct and direction
 */
static GpioDir Hv_Gpio_GetDirection(const GpioPinMap *pstpinMap)
{
    UINT32 uiVal = 0;
    UINT32 uiRegAddr = 0;

    switch (pstpinMap->enPortIdx)
    {
        case GPIO_PORT0:
        {
            if (pstpinMap->enGpioIdx < HV_GPIO0_GROUP0_NUM)
            {
                uiRegAddr = CPU_SYS_GPIO0_OE_STATE;
            }
            else
            {
                uiRegAddr =CPU_SYS_GPIO0_GPIO1_OE_STATE;
            }
            break;
        }
        case GPIO_PORT1:
        {
            if (pstpinMap->enGpioIdx < HV_GPIO1_GROUP0_NUM)
            {
                uiRegAddr = CPU_SYS_GPIO0_GPIO2_OE_STATE;
            }
            else
            {
                uiRegAddr = CPU_SYS_GPIO0_GPIO3_OE_STATE;
            }
            break;
        }
        default:
        {
            break;
        }
    }

    if (uiRegAddr)
    {
        uiVal = HV_R32(uiRegAddr);
        return (uiVal & (1 << pstpinMap->uiGpioBit) ? GPIO_DIR_OUTPUT : GPIO_DIR_INPUT);
    }
    return GPIO_DIR_INPUT;
}

/** Set Gpio output High level
 *  @param[in] pstpinMap pin map struct
 */
static VOID Hv_Cal_Gpio_SetPin(const GpioPinMap *pstpinMap)
{
    UINT32 uiRegAddr = 0;
    switch (pstpinMap->enPortIdx)
    {
        case GPIO_PORT0:
        {
            if(pstpinMap->enGpioIdx < HV_GPIO0_GROUP0_NUM)//20
            {
              uiRegAddr = CPU_SYS_GPIO0_GPIO_OUT0_SET;
            }
            else//40
            {
              uiRegAddr = CPU_SYS_GPIO0_GPIO_OUT1_SET;
            }
            break;
        }
        case GPIO_PORT1:
        {
            if (pstpinMap->enGpioIdx < HV_GPIO1_GROUP0_NUM)//20
            {
                uiRegAddr = CPU_SYS_GPIO0_GPIO_OUT2_SET;
            }
            else//40
            {
                uiRegAddr = CPU_SYS_GPIO0_GPIO_OUT3_SET;
            }
            break;
        }
        default:
        {
            return;
        }
    }

    if (uiRegAddr)
    {
        HV_W32(uiRegAddr, (1 << pstpinMap->uiGpioBit));
    }
    return;
}

/** Set Gpio output Low level
 *  @param[in] pstpinMap pin map struct
 */
static VOID Hv_Cal_Gpio_ClrPin(const GpioPinMap *pstpinMap)
{
    UINT32 uiRegAddr = 0;
    switch (pstpinMap->enPortIdx)
    {
        case GPIO_PORT0:
        {
            if (pstpinMap->enGpioIdx < HV_GPIO0_GROUP0_NUM) //20
            {
                uiRegAddr = CPU_SYS_GPIO0_GPIO_OUT0_CLR;
            }
            else//40
            {
                uiRegAddr = CPU_SYS_GPIO0_GPIO_OUT1_CLR;
            }
            break;
        }
        case GPIO_PORT1:
        {
            if (pstpinMap->enGpioIdx < HV_GPIO1_GROUP0_NUM) //20
            {
                uiRegAddr = CPU_SYS_GPIO0_GPIO_OUT2_CLR;
            }
            else//40
            {
                uiRegAddr = CPU_SYS_GPIO0_GPIO_OUT3_CLR;
            }
            break;
        }
        default:
        {
            break;
        }
    }

    if (uiRegAddr)
    {
       HV_W32(uiRegAddr, (1 << pstpinMap->uiGpioBit));
    }
    return;
}

/** Get Gpio output level
 *  @param[in] pstpinMap pin map struct
 *  @param[out] 0:low level 1:high level
 */
static GpioLevel Hv_Gpio_ReadPin(const GpioPinMap *pstpinMap)
{
    UINT32 uiVal = 0;
    switch (pstpinMap->enPortIdx)
    {
        case GPIO_PORT0:
        {
            if (pstpinMap->enGpioIdx < HV_GPIO0_GROUP0_NUM)//20
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_IN);
            }
            else//40
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_GPIO1_IN);
            }
            break;
        }
        case GPIO_PORT1:
        {
            if (pstpinMap->enGpioIdx < HV_GPIO0_GROUP1_NUM)//20
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_GPIO2_IN);
            }
            else//40
            {
                uiVal = HV_R32(CPU_SYS_GPIO0_GPIO3_IN);
            }
            break;
        }
        default:
        {
            return INVALID_PARAM_UHCAR8;
        }
    }

    return (uiVal & (1 << pstpinMap->uiGpioBit) ? 1 : 0);
}

/**@brief Enable Gpio interrupt
 *  @param[in] pstpinMap pin map struct
 */
static VOID Hv_Gpio_EnableInt(const GpioPinMap *pstPinMap)
{
    Hv_Gpio_InitInt(pstPinMap);
    Hv_Gpio_ClrIntState(pstPinMap);
    Hv_Gpio_MaskInt(pstPinMap, 0);

    //enable all gpio interrupt,whole switch.
    HV_W32_FIELD(CPU_SYS_GPIO0_GPIO_ALL_INT_MASK, gpio_all_int_mask, 0);
    return;
}

/**@brief Enable the designated gpio interrupt
 *  @param[in] ucPinIdx Specified GPIO pin
 */
VOID Hv_Cal_Gpio_EnableInt(UCHAR8 ucPinIdx)
{
    GpioPinMap stpinMap = {0};
    if (HV_FAILURE == (Hv_Gpio_MapPinIndex(ucPinIdx, &stpinMap)))
    {
        return;
    }
    if (stpinMap.enGpioDomain == GPIO_DOMAIN_SYS)
    {
        Hv_Gpio_EnableInt(&stpinMap);
    }
    return;
}

/** Disable the designated gpio interrupt
 *  @param[in] ucPinIdx Specified GPIO pin
 */
VOID Hv_Cal_Gpio_DisableInt(UCHAR8 ucPinIdx)
{
    GpioPinMap stpinMap = {0};
    if (HV_FAILURE == (Hv_Gpio_MapPinIndex(ucPinIdx, &stpinMap)))
    {
        return;
    }
    if (stpinMap.enGpioDomain == GPIO_DOMAIN_SYS)
    {
        Hv_Gpio_MaskInt(&stpinMap, 1);
    }
    return;
}

/**@brief Get interrupt state of designated gpio
 *  @param[in] ucPinIdx Specified GPIO pin
 */
BOOL Hv_Cal_Gpio_GetIntState(UCHAR8 ucPinIdx)
{
    GpioPinMap stpinMap = {0};
    if (HV_FAILURE == (Hv_Gpio_MapPinIndex(ucPinIdx, &stpinMap)))
    {
        return HV_FALSE;
    }
    if (stpinMap.enGpioDomain == GPIO_DOMAIN_SYS)
    {
        return Hv_Gpio_GetIntState(&stpinMap);
    }
    else
    {
        return HV_FALSE;
    }
}

/** Clear the gpio interrupt status
 *  @param[in]: ucPinIdx Specified GPIO pin
 */
VOID Hv_Cal_Gpio_ClrIntState(UCHAR8 ucPinIdx)
{
    GpioPinMap stpinMap = {0};
    if (HV_FAILURE == (Hv_Gpio_MapPinIndex(ucPinIdx, &stpinMap)))
    {
        return;
    }
    if (stpinMap.enGpioDomain == GPIO_DOMAIN_SYS)
    {
        Hv_Gpio_ClrIntState(&stpinMap);
    }
    return;
}

/**@brief Set gpio pin interrupt callback
 *  @param ucPinIdx Specified GPIO pin, pfCallBack Specified callback @ref GpioIntCallBack
 */
VOID Hv_Cal_Gpio_SetIntCallBack(UCHAR8 ucPinIdx, GpioIntCallBack pfCallBack)
{
    GpioPinMap stpinMap = {0};
    if (HV_FAILURE == (Hv_Gpio_MapPinIndex(ucPinIdx, &stpinMap)))
    {
        return;
    }
    if (stpinMap.enGpioDomain == GPIO_DOMAIN_SYS)
    {
        UCHAR8 ucLoop = 0;
        for (ucLoop=0; ucLoop<GPIO_INT_NUM; ucLoop++)
        {
            if (s_stIntGpio.bIrqInit[ucLoop] == HV_TRUE)
            {
                continue;
            }
            s_stIntGpio.uiPinNum[ucLoop]      = ucPinIdx;
            s_stIntGpio.pfCallBack[ucLoop]    = pfCallBack;
            s_stIntGpio.enPortIdx[ucLoop]     = stpinMap.enPortIdx;
            s_stIntGpio.enGpioIdx[ucLoop]     = stpinMap.enGpioIdx;
            s_stIntGpio.uiGpioBit[ucLoop]     = stpinMap.uiGpioBit;
            s_stIntGpio.bIrqInit[ucLoop]      = HV_TRUE;
            HV_LOG_DEBUG(SYSTEM, "IntCallback ucLoop %d", ucLoop);
            HV_LOG_DEBUG(SYSTEM, "IntCallback pin %d", ucPinIdx);
            HV_LOG_DEBUG(SYSTEM, "IntCallback port %d", stpinMap.enPortIdx);
            HV_LOG_DEBUG(SYSTEM, "IntCallback gpio %d", stpinMap.enGpioIdx);
            HV_LOG_DEBUG(SYSTEM, "IntCallback bit %d", stpinMap.uiGpioBit);
            break;
        }
        if (ucLoop == GPIO_INT_NUM)
        {
            HV_LOG_WARN(SYSTEM, "IntCallback failed");
        }
    }
    return;
}

/** Set gpio pin interrupt trigger type
 *  @param[in] ucPinIdx Specified GPIO pin, enPull Specified pull acion @ref GpioIntTrigMode
 */
VOID Hv_Cal_Gpio_SetIntTriggerMode(UCHAR8 ucPinIdx, GpioIntTrigMode enIntTrigMode)
{
    GpioPinMap stpinMap = {0};
    if (HV_FAILURE == (Hv_Gpio_MapPinIndex(ucPinIdx, &stpinMap)))
    {
        return;
    }
    if (stpinMap.enGpioDomain == GPIO_DOMAIN_SYS)
    {
        Hv_Gpio_SetIntTriggerMode(&stpinMap, enIntTrigMode);
    }
    return;
}

/**@brief Set gpio pin interrupt callback
 *  @param ucPinIdx Specified GPIO pin, pfCallBack Specified callback @ref GpioIntCallBack
 */
VOID Hv_Cal_Gpio_CleanupInt(VOID)
{
    if (s_stGpio.bIrqInit[GPIO_INT_HANDLER0] == HV_TRUE)
    {
        Hv_Vos_MaskIrq(HV_CHIP_IRQ_GPIO_CH0);
        Hv_Vos_DetachIsr(HV_CHIP_IRQ_GPIO_CH0, Hv_Gpio0_IntCallback);
        s_stGpio.bIrqInit[GPIO_INT_HANDLER0] = HV_FALSE;
    }
    else if (s_stGpio.bIrqInit[GPIO_INT_HANDLER1] == HV_TRUE)
    {
        Hv_Vos_MaskIrq(HV_CHIP_IRQ_GPIO_CH1);
        Hv_Vos_DetachIsr(HV_CHIP_IRQ_GPIO_CH1, Hv_Gpio1_IntCallback);
        s_stGpio.bIrqInit[GPIO_INT_HANDLER1] = HV_FALSE;
    }
    else
    {
        //do nothing
    }

    Hv_Gpio_DisableAllInts();
    return;
}

/**@brief Set gpio pin direction
 *  @param[in] ucPinIdx Specified GPIO pin, enPull Specified pull acion @ref GpioDir
 */
VOID Hv_Cal_Gpio_SetDirection(UCHAR8 ucPinIdx, GpioDir enDir)
{
    GpioPinMap stpinMap = {0};
    if (HV_FAILURE == (Hv_Gpio_MapPinIndex(ucPinIdx, &stpinMap)))
    {
        return;
    }
    if (stpinMap.enGpioDomain == GPIO_DOMAIN_SDBY)
    {
        Hv_Cal_Gpio_SetSdbyDir(&stpinMap, enDir);
    }
    else
    {
        Hv_Gpio_SetDirection(&stpinMap, enDir);
    }
    return;
}

/**@brief Get gpio pin direction
 *  @param[in] ucPinIdx Specified GPIO pin
 *  @param[out]: dir output/input
 */
GpioDir Hv_Cal_Gpio_GetDirection(UCHAR8 ucPinIdx)
{
    GpioPinMap stpinMap = {0};
    if (HV_FAILURE == (Hv_Gpio_MapPinIndex(ucPinIdx, &stpinMap)))
    {
        return GPIO_DIR_INPUT;
    }
    if (stpinMap.enGpioDomain == GPIO_DOMAIN_SDBY)
    {
        return Hv_Cal_Gpio_GetSdbyDir(&stpinMap);
    }
    else
    {
        return Hv_Gpio_GetDirection(&stpinMap);
    }
}

/**@brief Set gpio pin level
 *  @param ucPinIdx Specified GPIO pin,
 *  @param enLevel high(1) or low(0) level
 */
VOID Hv_Cal_Gpio_SetPinLevel(UCHAR8 ucPinIdx, GpioLevel enLevel)
{
    GpioPinMap stpinMap = {0};
    if (HV_FAILURE == (Hv_Gpio_MapPinIndex(ucPinIdx, &stpinMap)))
    {
        return;
    }

    if (stpinMap.enGpioDomain == GPIO_DOMAIN_SDBY)
    {
        Hv_Gpio_SetSdbyLevel(&stpinMap, enLevel);
    }
    else
    {
        if (enLevel)
        {
            Hv_Cal_Gpio_SetPin(&stpinMap);
        }
        else
        {
            Hv_Cal_Gpio_ClrPin(&stpinMap);
        }
    }
    return;
}

/**@brief Get gpio pin out level
 *  @param[in]  :ucPinIdx Specified GPIO pin
 *  @param[out]: state high(1)/low(0)/invalid(2)
 */
GpioLevel Hv_Cal_Gpio_GetPinLevel(UCHAR8 ucPinIdx)
{
    GpioPinMap stpinMap = {0};
    if (HV_FAILURE == (Hv_Gpio_MapPinIndex(ucPinIdx, &stpinMap)))
    {
        return GPIO_LEVEL_INVALID;
    }

    if (stpinMap.enGpioDomain == GPIO_DOMAIN_SDBY)
    {
        return Hv_Gpio_GetSdbyLevel(&stpinMap);
    }
    else
    {
        return Hv_Gpio_ReadPin(&stpinMap);
    }
}
