/**
 * \file    drv_gpio.c
 * \brief   GPIO interface definition
 *
 * \par     Copyright (c) 2017 UWE Technologies Corp., Ltd. All Rights Reserved.
 * \author  James
 * \date    2017-04-05
 * \version 
 * 
 * \history 
 *  Date        Note
 *  2017-04-05  Original Creation
 * 
 */

#include "libc.h"
#include "drivers.h"

volatile u32_t g_gpio_intr_map = 0;
volatile u32_t g_gpio_intr_mask_map = 0;

/**
 * array of function pointers which contains the IPIC
 * interrupt handlers
 */
static v_func_ptr_t g_gpio_interrupt_handlers[DRV_GPIO_MAX];
/**
 * array of function argument
 */
static u32_t g_gpio_interrupt_handler_args[DRV_GPIO_MAX];

int drv_gpio_val_get(int id)
{
    if (id >= DRV_GPIO_MAX)
        return 0;

    if (drv_gpio_oe_get(id))
    {
        return drv_reg_field_get(GPIO_DR_REG, id, 1);
    }
    else {
        return drv_reg_field_get(GPIO_IDR_REG, id, 1);
    }
}

DRV_GPIO_OD_TYPE_t drv_gpio_od_get(u32_t id)
{
    if (id >= DRV_GPIO_MAX)
        return 0;

    return (drv_reg_field_get(GPIO_ODRV1_REG, id, 1) << 1) | drv_reg_field_get(GPIO_ODRV0_REG, id, 1);
}

void drv_gpio_od_set(u32_t id, DRV_GPIO_OD_TYPE_t flg)
{
    if (id >= DRV_GPIO_MAX)
        return;

    drv_reg_field_set(GPIO_ODRV1_REG, id, 1, flg >> 1);
    drv_reg_field_set(GPIO_ODRV0_REG, id, 1, flg);
}


void drv_gpio_intr_en_set(int id, int flg)
{
    if (id >= DRV_GPIO_MAX)
        return;

    if (flg)
    {
        SAL_BIT_SET(g_gpio_intr_map, id);
    }
    else {
        SAL_BIT_CLEAR(g_gpio_intr_map, id);
    }
    DRV_REG_SET(GPIO_SEN_REG,g_gpio_intr_map);
    DRV_REG_SET(GPIO_INT_EN_REG,g_gpio_intr_map);
    //DRV_REG_SET(GPIO_INT_SYNC_REG,g_gpio_intr_map);
}

void drv_gpio_intr_mask_set(int id, int flg)
{
    if (id >= DRV_GPIO_MAX)
        return;

    if (flg)
    {
        SAL_BIT_SET(g_gpio_intr_mask_map, id);
    }
    else {
        SAL_BIT_CLEAR(g_gpio_intr_mask_map, id);
    }
    DRV_REG_SET(GPIO_INT_MASK_REG,g_gpio_intr_mask_map);
}

void drv_gpio_isr(u32_t arg)
{
    int gpio_id = DRV_GPIO_MAX;
    u32_t intr_status = DRV_REG_GET(GPIO_RAW_INT_STATUS_REG);
#if (DRV_DBG_GPIO_ENABLED)
    u32_t masked_intr_status = DRV_REG_GET(GPIO_INT_STATUS_REG);
#endif

    DRV_REG_SET(GPIO_INT_EN_REG, 0);
    // clear GPIO interrupt
    DRV_REG_SET(GPIO_INT_CLR_REG,0xFFFFFFFF);

#if (DRV_DBG_GPIO_ENABLED)
    drv_uart_putstr("GPIOISR(");
    drv_uart_puthex32(intr_status);
    drv_uart_putbyte(',');
    drv_uart_puthex32(masked_intr_status);
    drv_uart_putstr(")\n");
#endif    

    //valid interrupt
    intr_status &= g_gpio_intr_map & (~g_gpio_intr_mask_map);
    // Local handlers callback here
    while ((intr_status) && (gpio_id > 0))
    {
        gpio_id--;
        if (SAL_IS_BIT_SET(intr_status, gpio_id) && 
            (g_gpio_interrupt_handlers[gpio_id]))
        {
            g_gpio_interrupt_handlers[gpio_id](g_gpio_interrupt_handler_args[gpio_id]);
            SAL_BIT_CLEAR(intr_status, gpio_id);
        }
    }
    DRV_REG_SET(GPIO_INT_EN_REG,g_gpio_intr_map);
}

void drv_gpio_intr_handler_init(void)
{
    int i;
    if(!drv_chip_wkup_flg())
    {
        DRV_REG_SET(GPIO_INT_EN_REG, 0);
        g_gpio_intr_map = 0;

    }
    else{

        g_gpio_intr_map = DRV_REG_GET(GPIO_INT_EN_REG);
    }
    
    for (i = 0; i < DRV_GPIO_MAX; i++)
    {
        g_gpio_interrupt_handlers[i] = NULL;
        g_gpio_interrupt_handler_args[i] = i;
    }
}

void drv_gpio_intr_init(bool_t en)
{
    drv_intr_ext_set(IPIC_CFG_INTR_IDX_GPIO_INT, en, IPIC_INTR_PRI_0, drv_gpio_isr);
}

void drv_gpio_intr_set(bool_t en, int pri)
{
    drv_intr_ext_set(IPIC_CFG_INTR_IDX_GPIO_INT, en, pri, drv_gpio_isr);
}

void drv_gpio_intr_handler_set(int id, v_func_ptr_t intr_func)
{
    if (id >= DRV_GPIO_MAX)
        return;
    g_gpio_interrupt_handlers[id] = intr_func;
}

void drv_gpio_intr_handler_with_arg_set(int id, v_func_ptr_t intr_func, u32_t arg)
{
    if (id >= DRV_GPIO_MAX)
        return;
    g_gpio_interrupt_handlers[id] = intr_func;
    g_gpio_interrupt_handler_args[id] = arg;
}

DRV_GPIO_OUTPUT_DRIVER_t drv_gpio_output_driver_get(u32_t id)
{
    if (id >= DRV_GPIO_MAX)
        return 0;

    return (drv_reg_field_get(GPIO_ES1_REG, id, 1) << 1) | drv_reg_field_get(GPIO_ES0_REG, id, 1);
}

void drv_gpio_output_driver_set(u32_t id, DRV_GPIO_OUTPUT_DRIVER_t flg)
{
    if (id >= DRV_GPIO_MAX)
        return;

    drv_reg_field_set(GPIO_ES1_REG, id, 1, flg >> 1);
    drv_reg_field_set(GPIO_ES0_REG, id, 1, flg);
}
