/*  Copyright(c) 2009-2020 Shenzhen TP-LINK Technologies Co.Ltd.
 *
 * file        mt7620Gpio.c
 * brief    mt7620 definition
 * details    
 *
 * version    
 * date        30Oct20
 *
 * history     \arg    create file
 */


/******************************************************************************/
/*                              CONFIGURATIONS                                */
/******************************************************************************/

/******************************************************************************/
/*                              INCLUDE_FILES                                 */
/******************************************************************************/

#include "gpio.h"
#include "mt7620.h"

/******************************************************************************/
/*                              DEFINES                                       */
/******************************************************************************/
#define GPIO_PRINTF(fmt, ...)

#define MT7620_GPIO_INT_EDGE 0
#define MT7620_GPIO_INT_LEVEL 1
#define MT7620_GPIO_INT_POL_LOW 0
#define MT7620_GPIO_INT_POL_HIGH 1


/******************************************************************************/
/*                              LOCAL_PROTOTYPES                              */
/******************************************************************************/

typedef struct _GPIO_MODE_SELECT {
    ULONG gpioNum;
    ULONG modeRegAddr;
    ULONG modeRegMask;
    ULONG modeRegValue;
} GPIO_MODE_SELECT;

LOCAL GPIO_MODE_SELECT mt7620kGpioLedMode[] = {
    {7,  RALINK_REG_GPIOMODE, 0x0000001C, 0x0000001C},
    /*{11, RALINK_REG_GPIOMODE, 0x0000000E, 0x0000000E},*/
    {13, RALINK_REG_GPIOMODE, 0x0000001C, 0x0000001C},
    {42, RALINK_REG_GPIOMODE, 0x00008000, 0x00008000},
    {43, RALINK_REG_GPIOMODE, 0x00008000, 0x00008000},
    {46, RALINK_REG_GPIOMODE, 0x000C0000, 0x00080000},
    {52, RALINK_REG_GPIOMODE, 0x000C0000, 0x00080000},
    {53, RALINK_REG_GPIOMODE, 0x000C0000, 0x00080000},
    {72, RALINK_REG_GPIOMODE, 0x00002000, 0x00002000}
};


/******************************************************************************/
/*                              VARIABLES                                     */
/******************************************************************************/


/******************************************************************************/
/*                              LOCAL_FUNCTIONS                               */
/******************************************************************************/
#if 0
LOCAL void sysGpioCtrlInt(ULONG gpioNum, ULONG edge, ULONG pol)          
{
    ULONG *fallReg;
    ULONG *riseReg;
    ULONG offset;
    if (gpioNum == 72)
    {
        fallReg = (ULONG *)RALINK_REG_PIO72FENA;
        riseReg = (ULONG *)RALINK_REG_PIO72RENA;
        offset = 0;
    }
    else if (gpioNum >= 40)
    {
        fallReg = (ULONG *)RALINK_REG_PIO7140FENA;
        riseReg = (ULONG *)RALINK_REG_PIO7140RENA;
        offset = gpioNum - 40;
    }
    else if(gpioNum >= 24)
    {
        fallReg = (ULONG *)RALINK_REG_PIO3924FENA;
        riseReg = (ULONG *)RALINK_REG_PIO3924RENA;
        offset = gpioNum - 24;
    }
    else
    {
        fallReg = (ULONG *)RALINK_REG_PIO3924FENA;
        riseReg = (ULONG *)RALINK_REG_PIO3924RENA;
        offset = gpioNum;
    }
    
    if (edge == MT7620_GPIO_INT_EDGE)
    {
        if (pol == MT7620_GPIO_INT_POL_LOW)
            *fallReg = (*fallReg | (1L << offset));
        else
            *riseReg = (*riseReg | (1L << offset));
    }
    else
    {
    /* FIXME!!! Not suppoted now.*/
    }
}

LOCAL ULONG isGpioInt(ULONG gpioNum)
{                               
    ULONG *addr;
    ULONG offset;
    if (gpioNum == 72)
    {
        addr = (ULONG *)RALINK_REG_PIO72INT;
        offset = 0;
    }
    else if (gpioNum >= 40)
    {
        addr = (ULONG *)RALINK_REG_PIO7140INT;
        offset = gpioNum - 40;
    }
    else if (gpioNum >= 24)
    {
        addr = (ULONG *)RALINK_REG_PIO3924INT;
        offset = gpioNum - 24;
    }
    else
    {
        addr = (ULONG *)RALINK_REG_PIOINT;
        offset = gpioNum;
    }
    return (*addr & (1 << offset)) ? 1 : 0;
}    

LOCAL ULONG getGpioIntEdge(ULONG gpioNum)
{
    ULONG *addr;
    ULONG offset;

    if (gpioNum == 72)
    {
        addr = (ULONG *)RALINK_REG_PIO72EDGE;
        offset = 0;
    }
    else if (gpioNum >= 40)
    {
        addr = (ULONG *)RALINK_REG_PIO7140EDGE;
        offset = gpioNum - 40;
    }
    else if (gpioNum >= 24)
    {
        addr = (ULONG *)RALINK_REG_PIO3924EDGE;
        offset = gpioNum - 24;
    }
    else
    {
        addr = (ULONG *)RALINK_REG_PIOEDGE;
        offset = gpioNum;
    }
    return (*addr & (1 << offset)) ? MT7620_GPIO_INT_POL_HIGH : MT7620_GPIO_INT_POL_LOW;
}
#endif

/******************************************************************************/
/*                              PUBLIC_FUNCTIONS                              */
/******************************************************************************/

/*!
    @brief        set gpio dir
*/
void set_gpio_dir(ULONG gpioNum, GPIO_DIR d)
{
    ULONG *regAddr;
    ULONG offset;

    if (gpioNum == 72)
    {
        regAddr = (ULONG *)RALINK_REG_PIO72DIR;
        offset = 0;
    }
    else if (gpioNum >= 40)
    {
        regAddr = (ULONG *)RALINK_REG_PIO7140DIR;
        offset = gpioNum - 40;
    }
    else if (gpioNum >= 24)
    {
        regAddr = (ULONG *)RALINK_REG_PIO3924DIR;
        offset = gpioNum - 24;
    }
    else
    {
        regAddr = (ULONG *)RALINK_REG_PIODIR;
        offset = gpioNum;
    }
    if (d)
    {
        *regAddr = (*regAddr | (1 << offset));
    }
    else
    {
        *regAddr = (*regAddr & ~(1 << offset));
    }
}

#if 0
/*!
    @brief        set gpio int type
*/
void set_gpio_int(ULONG gpioNum, GPIO_INT_TYPE type)
{
switch (type)
{
    case GPIO_INT_FALL:
        sysGpioCtrlInt(gpioNum, MT7620_GPIO_INT_EDGE, MT7620_GPIO_INT_POL_LOW);
        break;

    case GPIO_INT_RISE:
        sysGpioCtrlInt(gpioNum, MT7620_GPIO_INT_EDGE, MT7620_GPIO_INT_POL_HIGH);
        break;

    case GPIO_INT_HIGH:
        sysGpioCtrlInt(gpioNum, MT7620_GPIO_INT_LEVEL, MT7620_GPIO_INT_POL_HIGH);
        break;

    case GPIO_INT_LOW:
        sysGpioCtrlInt(gpioNum, MT7620_GPIO_INT_LEVEL, MT7620_GPIO_INT_POL_LOW);
        break;

    default:
        break;
    }
}

/*!
    @brief        get interrupt type 
*/
GPIO_INT_TYPE get_gpio_int_status(ULONG gpioNum)
{
    ULONG type = 0;
    ULONG pol = 0;
    ULONG val = 0;
    if (!isGpioInt(gpioNum))
        return GPIO_INT_DIS;

    /* FIXME: not support level interrupt */
    val = getGpioIntEdge(gpioNum);
    if (val == MT7620_GPIO_INT_POL_HIGH)
    {
        return GPIO_INT_RISE;
    }
    else
    {
        return GPIO_INT_FALL;
    }

    return GPIO_INT_DIS;

}

#endif

/*!
    @brief        read gpio value
*/
GPIO_LEVEL read_gpio_value(ULONG gpioNum)
{
    ULONG *regAddr;
    ULONG offset;

    if (gpioNum == 72)
    {
        regAddr = (ULONG *)RALINK_REG_PIO72DATA;
        offset = 0;
    }
    else if (gpioNum >= 40)
    {
        regAddr = (ULONG *)RALINK_REG_PIO7140DATA;
        offset = gpioNum - 40;
    }
    else if (gpioNum >= 24)
    {
        regAddr = (ULONG *)RALINK_REG_PIO3924DATA;
        offset = gpioNum - 24;
    }
    else
    {
        regAddr = (ULONG *)RALINK_REG_PIODATA;
        offset = gpioNum;
    }

    return (*regAddr & (1 << offset)) ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW;

}

/*!
    @brief        write gpio value
*/
void write_gpio_value(ULONG gpioNum, GPIO_LEVEL value)
{
    ULONG *regAddr;
    ULONG offset;

    if (gpioNum == 72)
    {
        regAddr = (ULONG *)RALINK_REG_PIO72DATA;
        offset = 0;
    }
    else if (gpioNum >= 40)
    {
        regAddr = (ULONG *)RALINK_REG_PIO7140DATA;
        offset = gpioNum - 40;
    }
    else if (gpioNum >= 24)
    {
        regAddr = (ULONG *)RALINK_REG_PIO3924DATA;
        offset = gpioNum - 24;
    }
    else
    {
        regAddr = (ULONG *)RALINK_REG_PIODATA;
        offset = gpioNum;
    }

    if (GPIO_LEVEL_LOW == value)
    {
        *regAddr = ((*regAddr) & ~(1 << offset));
        
    }
    else
    {
        *regAddr = ((*regAddr) | (1 << offset));
    }

    /* FIX ME：对于mr30gv1 sys灯，gpio寄存器写入不生效，此处插入延时500us(临时方案) */
	udelay(500);

}

/*!
    @brief        Clear all gpio interrupts status
*/
void clear_gpio_int(ULONG gpioNum)
{
    ULONG *regAddr;
    ULONG offset;

    if (gpioNum == 72)
    {
        regAddr = (ULONG *)RALINK_REG_PIO72INT;
        offset = 0;
    }
    else if (gpioNum >= 40)
    {
        regAddr = (ULONG *)RALINK_REG_PIO7140INT;
        offset = gpioNum - 40;
    }
    else if (gpioNum >= 24)
    {
        regAddr = (ULONG *)RALINK_REG_PIO3924INT;
        offset = gpioNum - 24;
    }
    else
    {
        regAddr = (ULONG *)RALINK_PRGIO_ADDR;
        offset = gpioNum;
    }

    *regAddr &= ~(1 << offset);

}

/*!
    @brief        Set gpio pin mode. Optional.
*/
void set_gpio_pin_mode(ULONG gpioNum, GPIO_PIN_MODE mode)
{
    /* GPIO MODE */
    int index = 0;
    ULONG *regAddr;
    ULONG mask;
    ULONG value;
    for (index = 0; index < NELEMENTS(mt7620kGpioLedMode); index++)
    {
        if (mt7620kGpioLedMode[index].gpioNum == gpioNum)
        {
            mask = mt7620kGpioLedMode[index].modeRegMask;
            value = mt7620kGpioLedMode[index].modeRegValue;
            regAddr = (ULONG *)mt7620kGpioLedMode[index].modeRegAddr;
            *regAddr = ((*regAddr & ~mask) | (value & mask));
        }
    }
}


