/*****************************************************************************************
 * @Author: Cedric Kong <dachao.kong@omnilinktek.com>
 * @Date: 2024-03-01 17:28:57
 * @LastEditors: Cedric Kong
 * @LastEditTime: 2024-03-05 15:06:48
 * @FilePath: omw_iic.c
 * @Description: 请填写文件说明
 * @Copyright: © 2021-2024 OmniLinkTek, All Rights Reserved.
 ****************************************************************************************/

#include <stdint.h>

#include "omw_iic.h"



#define IC_CON              (0x0  >> 2)
#define IC_TAR              (0x4  >> 2)
#define IC_SAR              (0x8  >> 2)
#define IC_DATA_CMD         (0x10 >> 2)
#define IC_SS_SCL_HCNT      (0x14 >> 2)
#define IC_SS_SCL_LCNT      (0x18 >> 2)
#define IC_RAW_INTR_STAT    (0x34 >> 2)
#define IC_RX_TL            (0x38 >> 2)
#define IC_TX_TL            (0x3C >> 2)
#define IC_CLR_RD_REQ       (0X50 >> 2)
#define IC_CLR_TX_ABRT      (0x54 >> 2)
#define IC_ENABLE           (0x6C >> 2)
#define IC_TXFLR            (0x74 >> 2)
#define IC_RXFLR            (0x78 >> 2)

#define IIC_PIN_NUM          2

// TODO: TIMER_VAL ?
#define CURR_TIMER_VAL      (*((volatile uint32_t*)0x42000104))

#ifdef OMW_IIC
const struct gpio_cfg_tag iic_pin_cfg[] = {
    {OMW_IIC_PIN_SCL,  OMW_IIC_FUN_CFG_SCL},
    {OMW_IIC_PIN_SDA,  OMW_IIC_FUN_CFG_SDA}
};


void omw_iic_init( uint32_t * iic_ctrl, uint16_t iic_mode, uint16_t addr_method, uint16_t addr, uint16_t clk)
{
	const struct gpio_cfg_tag  * pin_cfg = iic_pin_cfg;
	omw_gpio_set_func_ex(pin_cfg, IIC_PIN_NUM);

	volatile uint32_t * iic_cfg_addr = iic_ctrl;
    iic_cfg_addr[IC_ENABLE] = DISABLE;
    iic_cfg_addr[IC_CON] = (iic_mode << 6) + (1 << 5) + (addr_method << (3 + iic_mode)) + (1 << 1) + iic_mode;
	iic_cfg_addr[IC_RX_TL] = 5;
	iic_cfg_addr[IC_TX_TL] = 5;
    if (iic_mode & IIC_MODE_MASTER) {
        iic_cfg_addr[IC_TAR] = addr;
		iic_cfg_addr[IC_SS_SCL_HCNT] = clk;
		iic_cfg_addr[IC_SS_SCL_LCNT] = clk;
    } else {
        iic_cfg_addr[IC_SAR] = addr;
    }
    iic_cfg_addr[IC_ENABLE] = ENABLE;
}

void omw_iic_master_send(uint32_t *iic_ctrl, uint8_t *buf, uint16_t len)
{
	volatile uint32_t * iic_cfg_addr = iic_ctrl;
    uint32_t i = 0, temp;
        while (i < len ) {
            if (iic_cfg_addr[IC_TXFLR] < 5) {
                iic_cfg_addr[IC_DATA_CMD] = buf[i];
                ++i;
            }
		}
}

void omw_iic_slave_recv( uint32_t *iic_ctrl, uint8_t *buf, uint32_t len)
{
	int i;
	volatile uint32_t * iic_cfg_addr = iic_ctrl;
    uint8_t *rx_data = (uint8_t*)buf;
    while (i < len) {
        if (iic_cfg_addr[IC_RXFLR] > 0) {
            rx_data[i] = iic_cfg_addr[IC_DATA_CMD] & 0xFF;
            ++i;
        }
    }
}

void omw_iic_slave_send(uint32_t * iic_ctrl, uint8_t *buf, uint16_t len)
{
	volatile uint32_t * iic_cfg_addr = iic_ctrl;
    uint32_t i = 0, temp;
    while (~(iic_cfg_addr[IC_RAW_INTR_STAT] & 0x20));
    if ((iic_cfg_addr[IC_RAW_INTR_STAT] & 0x20)) {
        while (i < len ) {
            if (iic_cfg_addr[IC_TXFLR] < 5) {
                iic_cfg_addr[IC_DATA_CMD] = buf[i];
                ++i;
            }
		}
    }
	//Clear RX/TX status
    (void)(temp = iic_ctrl[IC_CLR_RD_REQ] + iic_ctrl[IC_CLR_TX_ABRT]);
}


void omw_iic_master_recv(uint32_t * iic_ctrl, uint8_t *buf, uint32_t len)
{
	int i;
	volatile uint32_t * iic_cfg_addr = iic_ctrl;
    uint8_t *rx_data = (uint8_t*)buf;
    while (i < len) {
        if (iic_cfg_addr[IC_RXFLR] > 0) {
            rx_data[i] = iic_cfg_addr[IC_DATA_CMD] & 0xFF;
            ++i;
        }
    }
}
#endif