/**************************************************************************************************
*******
**************************************************************************************************/


#include "bus_dev.h"
#include "gpio.h"
#include "clock.h"
#include "i2c_s.h"
#include "i2c.h"
#include "error.h"
#include "log.h"

typedef struct
{
    uint8_t           id;  //0: uninit, 1: i2c0, 2:i2c1
    uint8_t           mode; //(1)I2CS_MODE_REG_8BIT,  (2)I2CS_MODE_REG_16BIT,(3)I2CS_MODE_RAW
    uint8_t           saddr;
    gpio_pin_e        cs;  //cs pin, used to  wakeup or release
    gpio_pin_e        sda;
    gpio_pin_e        scl;
    AP_I2C_TypeDef*   dev;
    i2cs_hdl_t        evt_handler;
    uint8_t           rxoffset;
    uint8_t           rxbuf[I2CS_RX_MAX_SIZE];
    uint8_t           txoffset;
    uint8_t           txbuf[I2CS_TX_MAX_SIZE];
} i2cs_ctx_t;

static uint8_t s_i2cs_state = I2CSST_IDLE;

static i2cs_ctx_t s_i2cs_ctx;

static void i2cs_irq_rx_handler(AP_I2C_TypeDef* pdev)
{
    uint32_t val;

    while(1)
    {
        if((pdev->IC_STATUS & BV(3)) == 0)
            break;

        val = pdev->IC_DATA_CMD;
        LOG("Rx %x\n",val);
    }
}
static uint32_t tx_dummy = 0;
static void i2cs_irq_tx_handler(AP_I2C_TypeDef* pdev)
{
    pdev->IC_DATA_CMD = tx_dummy &0xff;
    tx_dummy ++;
    pdev->IC_DATA_CMD = tx_dummy &0xff;
    tx_dummy ++;
    //LOG("Tx\n");
}
static void i2cs_irq_handler(AP_I2C_TypeDef* pdev)
{
    uint32_t int_status = pdev->IC_INTR_STAT;
    uint32_t clr = pdev->IC_CLR_INTR;

    //LOG("i2cs_irq_handler %x\n",int_status);
    if(int_status & I2C_MASK_START_DET)
    {
    }

    if(int_status & I2C_MASK_RX_FULL)
    {
        i2cs_irq_rx_handler(pdev);
    }

    if(int_status & I2C_MASK_RD_REQ)
    {
        i2cs_irq_tx_handler(pdev);
    }
}

void __attribute__((used)) hal_I2C0_IRQHandler(void)
{
    i2cs_ctx_t* pctx = &s_i2cs_ctx;

    if(pctx->id == I2CS_0)
        i2cs_irq_handler(AP_I2C0);
}
void __attribute__((used)) hal_I2C1_IRQHandler(void)
{
    i2cs_ctx_t* pctx = &s_i2cs_ctx;

    if(pctx->id == I2CS_1)
        i2cs_irq_handler(AP_I2C1);
}



int i2cs_init(
    i2cs_channel_t  ch_id,
    i2cs_mode_t     mode,
    uint8_t         saddr,  //slave address
    gpio_pin_e      cs,  //if need not cs, choose GPIO_DUMMY_PIN
    gpio_pin_e      sda,
    gpio_pin_e      scl,
    i2cs_hdl_t      evt_handler)
{
    i2cs_ctx_t* pctx = &s_i2cs_ctx;
    Fmux_Type_e   fmux;
    MODULE_e      module;
    AP_I2C_TypeDef* pdev = NULL;
    int    irqid;

    if(pctx->id)
    {
        return PPlus_ERR_IO_CONFILCT;
    }

    //parameter validate check
    //set device
    irqid = (ch_id == I2CS_0) ? I2C0_IRQ : I2C1_IRQ;
    module = (ch_id == I2CS_0) ? MOD_I2C0 : MOD_I2C1;
    hal_clk_gate_enable(module);
    pdev = (ch_id == I2CS_0) ? AP_I2C0 : AP_I2C1;
    pctx->id = ch_id;
    pctx->dev = pdev;
    pctx->saddr = saddr;
    pctx->cs = cs;
    pctx->scl = scl;
    pctx->sda = sda;
    pctx->evt_handler = evt_handler;
    fmux = (ch_id == I2CS_0) ? IIC0_SCL : IIC1_SCL;
    hal_gpio_fmux_set(scl, fmux);
    fmux = (ch_id == I2CS_0) ? IIC0_SDA : IIC1_SDA;
    hal_gpio_fmux_set(sda, fmux);
    hal_gpio_pull_set(scl, STRONG_PULL_UP);
    hal_gpio_pull_set(sda, STRONG_PULL_UP);
    pdev->IC_ENABLE = 0; //disable
    pdev->IC_CON = (SPEED_FAST) << 1;
    pdev->IC_SAR = saddr;
    pdev->IC_RX_TL = 1;
    pdev->IC_TX_TL = 1;
    pdev->IC_INTR_MASK = 0xfef;//(I2C_MASK_TX_ABRT | I2C_MASK_RD_REQ | I2C_MASK_RX_FULL | I2C_MASK_RX_DONE);
    pdev->IC_ENABLE = 1; //disable
    NVIC_EnableIRQ((IRQn_Type)irqid);
    NVIC_SetPriority(irqid, IRQ_PRIO_HAL);
    return PPlus_SUCCESS;
}


int i2cs_deinit(void)
{
    i2cs_ctx_t* pctx = &s_i2cs_ctx;

    if(pctx->id == 0)
        return PPlus_ERR_IO_FAIL;

    //release io
    return PPlus_SUCCESS;
}

