THB2/bthome_phy6222/SDK/components/driver/i2c/i2c.c

439 lines
9.9 KiB
C

/*******************************************************************************
@file i2c.c
@brief Contains all functions support for i2c driver
@version 0.0
@date 25. Oct. 2017
@author qing.han
SDK_LICENSE
*******************************************************************************/
/*******************************************************************************
@ Module : pre-compiler
@ Description : NULL
*******************************************************************************/
#define _I2C_CMD_
/*******************************************************************************
@ Module : Includes
@ Description : None
*******************************************************************************/
#include "rom_sym_def.h"
#include "types.h"
#include "gpio.h"
#include "i2c.h"
#include "clock.h"
#include "log.h"
#include "error.h"
#include "OSAL.h"
#include "pwrmgr.h"
#define I2C_OP_TIMEOUT 100 //100ms for an Byte operation
extern uint32_t pclk;
/**************************************************************************************
@fn hal_master_send_read_cmd
@brief This function process for master send read command;It's vaild when the chip act as master
input parameters
@param uint8_t len: read length
output parameters
@param None.
@return None.
**************************************************************************************/
static void hal_master_send_read_cmd(void* pi2c, uint8_t len)
{
uint8_t i;
AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c;
for(i=0; i<len; i++)
{
I2C_READ_CMD(pi2cdev);
}
}
static void _hal_i2c_send_byte(void* pi2c, uint8_t data)
{
AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c;
pi2cdev->IC_DATA_CMD = data; //data
}
static void _hal_i2c_send_byte_x(void* pi2c, uint8_t data)
{
AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c;
pi2cdev->IC_DATA_CMD = data; //data
while(!(pi2cdev->IC_RAW_INTR_STAT&0x10));
}
/**************************************************************************************
@fn hal_i2c_send
@brief This function process for send a serial(programe length) data by i2c interface
input parameters
@param unsigned char* str: send data(string)
uint32_t len: send length
output parameters
@param None.
@return None.
**************************************************************************************/
int hal_i2c_send(void* pi2c, uint8_t* str,uint8_t len)
{
uint8_t i;
AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c;
if(pi2cdev != AP_I2C0 && pi2cdev != AP_I2C1)
{
return PPlus_ERR_INVALID_PARAM;
}
for(i=0; i<len; i++)
{
_hal_i2c_send_byte(pi2c, str[i]);
}
return PPlus_SUCCESS;
}
int hal_i2c_send_x(void* pi2c, uint8_t* str,uint8_t len)
{
uint8_t i;
AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c;
if(pi2cdev != AP_I2C0 && pi2cdev != AP_I2C1)
{
return PPlus_ERR_INVALID_PARAM;
}
for(i=0; i<len; i++)
{
_hal_i2c_send_byte_x(pi2c, str[i]);
}
return PPlus_SUCCESS;
}
int hal_i2c_wait_tx_completed(void* pi2c)
{
int cnt = 0;
//uint32 st0, st;
AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c;
I2C_INIT_TOUT(to);
if(pi2cdev != AP_I2C0 && pi2cdev != AP_I2C1)
{
return PPlus_ERR_INVALID_PARAM;
}
//st0 = pi2cdev->IC_INTR_STAT;
//st = pi2cdev->IC_RAW_INTR_STAT;
while(1)
{
cnt++;
if(pi2cdev->IC_RAW_INTR_STAT&0x200)//check tx empty
break;
I2C_CHECK_TOUT(to, I2C_OP_TIMEOUT, "hal_i2c_wait_tx_completed TO\n");
}
//LOG("I2c Tx empty:%x, %x\n", st0,st);
return PPlus_SUCCESS;
}
void* hal_i2c_init(i2c_dev_t dev, I2C_CLOCK_e i2c_clock_rate)
{
int pclk = clk_get_pclk();
AP_I2C_TypeDef* pi2cdev = NULL;
if(dev == I2C_0)
{
pi2cdev = AP_I2C0;
hal_clk_gate_enable(MOD_I2C0);
}
else if(dev == I2C_1)
{
pi2cdev = AP_I2C1;
hal_clk_gate_enable(MOD_I2C1);
}
else
{
return NULL;
}
pi2cdev->IC_ENABLE=0;
pi2cdev->IC_CON=0x61;
if(i2c_clock_rate==I2C_CLOCK_100K)
{
pi2cdev->IC_CON= ((pi2cdev->IC_CON) & 0xfffffff9)|(0x01 << 1);
if(pclk==16000000)
{
pi2cdev->IC_SS_SCL_HCNT=70; //16
pi2cdev->IC_SS_SCL_LCNT=76; //32)
}
else if(pclk==32000000)
{
pi2cdev->IC_SS_SCL_HCNT=148; //16
pi2cdev->IC_SS_SCL_LCNT=154; //32)
}
else if(pclk==48000000)
{
pi2cdev->IC_SS_SCL_HCNT=230; //16
pi2cdev->IC_SS_SCL_LCNT=236; //32)
}
else if(pclk==64000000)
{
pi2cdev->IC_SS_SCL_HCNT=307; //16
pi2cdev->IC_SS_SCL_LCNT=320; //32)
}
else if(pclk==96000000)
{
pi2cdev->IC_SS_SCL_HCNT=460; //16
pi2cdev->IC_SS_SCL_LCNT=470; //32)
}
}
else if(i2c_clock_rate==I2C_CLOCK_400K)
{
pi2cdev->IC_CON= ((pi2cdev->IC_CON) & 0xfffffff9)|(0x02 << 1);
if(pclk==16000000)
{
pi2cdev->IC_FS_SCL_HCNT=10; //16
pi2cdev->IC_FS_SCL_LCNT=17; //32)
}
else if(pclk==32000000)
{
pi2cdev->IC_FS_SCL_HCNT=30; //16
pi2cdev->IC_FS_SCL_LCNT=35; //32)
}
else if(pclk==48000000)
{
pi2cdev->IC_FS_SCL_HCNT=48; //16
pi2cdev->IC_FS_SCL_LCNT=54; //32)
}
else if(pclk==64000000)
{
pi2cdev->IC_FS_SCL_HCNT=67; //16
pi2cdev->IC_FS_SCL_LCNT=75; //32)
}
else if(pclk==96000000)
{
pi2cdev->IC_FS_SCL_HCNT=105; //16
pi2cdev->IC_FS_SCL_LCNT=113; //32)
}
}
pi2cdev->IC_TAR = I2C_MASTER_ADDR_DEF;
pi2cdev->IC_INTR_MASK=0;
pi2cdev->IC_RX_TL=0x0;
pi2cdev->IC_TX_TL=0x1;
pi2cdev->IC_ENABLE=1;
return (void*)pi2cdev;
}
int hal_i2c_deinit(void* pi2c)
{
AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c;
if(pi2cdev == AP_I2C0)
{
pi2cdev->IC_ENABLE=0;
hal_clk_gate_disable(MOD_I2C0);
}
else if(pi2cdev == AP_I2C1)
{
pi2cdev->IC_ENABLE=0;
hal_clk_gate_disable(MOD_I2C1);
}
else
{
return PPlus_ERR_INVALID_PARAM;
}
return PPlus_SUCCESS;
}
/**************************************************************************************
@fn hal_i2c_pin_init
@brief This function process for i2c pin initial(2 lines);You can use two i2c,i2c0 and i2c1,should programe by USE_AP_I2CX
input parameters
@param gpio_pin_e pin_sda: define sda_pin
gpio_pin_e pin_clk: define clk_pin
output parameters
@param None.
@return None.
**************************************************************************************/
int hal_i2c_pin_init(i2c_dev_t dev, gpio_pin_e pin_sda, gpio_pin_e pin_clk)
{
if(dev == I2C_0)
{
hal_gpio_fmux_set(pin_clk, FMUX_IIC0_SCL);
hal_gpio_fmux_set(pin_sda, FMUX_IIC0_SDA);
}
else if(dev == I2C_1)
{
hal_gpio_fmux_set(pin_clk, FMUX_IIC1_SCL);
hal_gpio_fmux_set(pin_sda, FMUX_IIC1_SDA);
}
else
{
return PPlus_ERR_INVALID_PARAM;
}
hal_gpio_pull_set(pin_sda,GPIO_PULL_UP_S);
hal_gpio_pull_set(pin_clk,GPIO_PULL_UP_S);
if(dev == I2C_0)
{
hal_clk_gate_enable(MOD_I2C0);
}
else if(dev == I2C_1)
{
hal_clk_gate_enable(MOD_I2C1);
}
return PPlus_SUCCESS;
}
int hal_i2c_tx_start(void* pi2c)
{
AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c;
if(pi2cdev != AP_I2C0 && pi2cdev != AP_I2C1)
{
return PPlus_ERR_INVALID_PARAM;
}
pi2cdev->IC_ENABLE=1;
return PPlus_SUCCESS;
}
/**************************************************************************************
@fn hal_i2c_addr_update
@brief This function process for tar update
input parameters
@param uint8_t addr: address
output parameters
@param None.
@return None.
**************************************************************************************/
int hal_i2c_addr_update(void* pi2c, uint8_t addr)
{
AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c;
if(pi2cdev != AP_I2C0 && pi2cdev != AP_I2C1)
{
return PPlus_ERR_INVALID_PARAM;
}
pi2cdev->IC_ENABLE=0;
pi2cdev->IC_TAR = addr;
pi2cdev->IC_ENABLE=1;
return PPlus_SUCCESS;
}
int _hal_i2c_read_s(void* pi2c, uint8_t slave_addr, uint8_t reg, uint8_t* data, uint8_t size)
{
I2C_INIT_TOUT(to);
AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c;
if(pi2cdev != AP_I2C0 && pi2cdev != AP_I2C1)
{
return PPlus_ERR_INVALID_PARAM;
}
hal_i2c_addr_update(pi2c, slave_addr);
HAL_ENTER_CRITICAL_SECTION();
hal_i2c_tx_start(pi2c);
_hal_i2c_send_byte(pi2c, reg);
hal_master_send_read_cmd(pi2c, size);
HAL_EXIT_CRITICAL_SECTION();
while(1)
{
if(I2C_RX_FIFO_NOT_EMPTY(pi2cdev))
{
*data = (pi2cdev->IC_DATA_CMD&0xff);
data++;
size --;
if(size == 0)
break;
}
I2C_CHECK_TOUT(to, I2C_OP_TIMEOUT*size, "I2C RD TO\n");
}
return PPlus_SUCCESS;
}
int hal_i2c_read(
void* pi2c,
uint8_t slave_addr,
uint8_t reg,
uint8_t* data,
uint8_t size)
{
uint8_t cnt;
int ret = PPlus_SUCCESS;
AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c;
if(pi2cdev != AP_I2C0 && pi2cdev != AP_I2C1)
{
return PPlus_ERR_INVALID_PARAM;
}
while(size)
{
cnt = (size >7) ? 7 : size;
size -= cnt;
ret = _hal_i2c_read_s(pi2c, slave_addr, reg, data, cnt);
if(ret != PPlus_SUCCESS)
break;
data += cnt;
}
return ret;
}