496 lines
14 KiB
C
496 lines
14 KiB
C
#ifdef SUPPORT_MS_EXTENSIONS
|
|
#pragma bss_seg(".iic_api.data.bss")
|
|
#pragma data_seg(".iic_api.data")
|
|
#pragma const_seg(".iic_api.text.const")
|
|
#pragma code_seg(".iic_api.text")
|
|
#endif
|
|
#include "iic_api.h"
|
|
#include "asm/wdt.h"
|
|
#include "atomic.h"
|
|
#include "init.h"
|
|
|
|
#define LOG_TAG_CONST IIC
|
|
#define LOG_TAG "[iic_api]"
|
|
#define LOG_ERROR_ENABLE
|
|
#define LOG_DEBUG_ENABLE
|
|
#define LOG_INFO_ENABLE
|
|
#define LOG_CLI_ENABLE
|
|
#include "debug.h"
|
|
|
|
static OS_MUTEX iic_mutex[2] = {0};
|
|
static atomic_t iic_ref[2];
|
|
//********************hw-iic for tp/alipay se/compass**********************//
|
|
int iic_api_init(void)
|
|
{
|
|
os_mutex_create(&iic_mutex[0]);
|
|
os_mutex_create(&iic_mutex[1]);
|
|
return 0;
|
|
}
|
|
platform_initcall(iic_api_init);
|
|
|
|
|
|
int system_iic_init(hw_iic_dev iic, struct iic_master_config *i2c_config)
|
|
{
|
|
int ret = 0;
|
|
os_mutex_pend(&iic_mutex[iic], 0);
|
|
ASSERT(!config_asser || (atomic_read(&iic_ref[iic]) == 0));
|
|
if (atomic_inc_return(&iic_ref[iic]) == 1) {
|
|
|
|
ret = hw_iic_init(iic, i2c_config);
|
|
}
|
|
os_mutex_post(&iic_mutex[iic]);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int system_iic_deinit(hw_iic_dev iic)
|
|
{
|
|
int ret = 0;
|
|
os_mutex_pend(&iic_mutex[iic], 0);
|
|
if (atomic_read(&iic_ref[iic]) != 0 && atomic_dec_return(&iic_ref[iic])) {
|
|
os_mutex_post(&iic_mutex[iic]);
|
|
return ret;
|
|
}
|
|
ret = hw_iic_deinit(iic);
|
|
os_mutex_post(&iic_mutex[iic]);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void system_iic_reset(hw_iic_dev iic)
|
|
{
|
|
os_mutex_pend(&iic_mutex[iic], 0);
|
|
|
|
hw_iic_reset(iic);
|
|
|
|
os_mutex_post(&iic_mutex[iic]);
|
|
}
|
|
|
|
int system_iic_suspend(hw_iic_dev iic)
|
|
{
|
|
int ret;
|
|
|
|
os_mutex_pend(&iic_mutex[iic], 0);
|
|
ret = hw_iic_suspend(iic);
|
|
os_mutex_post(&iic_mutex[iic]);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int system_iic_resume(hw_iic_dev iic)
|
|
{
|
|
int ret;
|
|
|
|
os_mutex_pend(&iic_mutex[iic], 0);
|
|
ret = hw_iic_resume(iic);
|
|
os_mutex_post(&iic_mutex[iic]);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int system_iic_read_nbytes(hw_iic_dev iic,
|
|
unsigned char dev_7bit_addr, //7位设备地址
|
|
unsigned char *reg_addr, unsigned char reg_len,//设备寄存器地址,长度
|
|
unsigned char *read_buf, int read_len)//缓存buf,读取长度
|
|
{
|
|
int ret;
|
|
os_mutex_pend(&iic_mutex[iic], 0);
|
|
|
|
ret = hw_i2c_master_read_nbytes_from_device_reg(iic, dev_7bit_addr << 1, reg_addr, reg_len, read_buf, read_len);
|
|
|
|
os_mutex_post(&iic_mutex[iic]);
|
|
return ret;
|
|
}
|
|
|
|
int system_iic_write_nbytes(hw_iic_dev iic,
|
|
unsigned char dev_7bit_addr, //7位设备地址
|
|
unsigned char *reg_addr, unsigned char reg_len,//设备寄存器地址,长度
|
|
unsigned char *write_buf, int write_len)//数据buf, 写入长度
|
|
{
|
|
int ret;
|
|
os_mutex_pend(&iic_mutex[iic], 0);
|
|
|
|
ret = hw_i2c_master_write_nbytes_to_device_reg(iic, dev_7bit_addr << 1, reg_addr, reg_len, write_buf, write_len);
|
|
|
|
os_mutex_post(&iic_mutex[iic]);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/******************************soft iic*****************************/
|
|
//如果无reg_addr:reg_addr=NULL,reg_len=0
|
|
//return: <0:error, =read_len:ok
|
|
int soft_i2c_master_read_nbytes_from_device_reg(soft_iic_dev iic,
|
|
unsigned char dev_addr, //设备地址
|
|
unsigned char *reg_addr, unsigned char reg_len,//设备寄存器地址,长度
|
|
unsigned char *read_buf, int read_len)//缓存buf,读取长度
|
|
{
|
|
u8 ack;
|
|
int ret = 0;
|
|
if (soft_iic_check_busy(iic) != IIC_OK) { //busy
|
|
ret = IIC_ERROR_BUSY; //busy
|
|
goto _read_exit2;
|
|
}
|
|
soft_iic_start(iic);
|
|
|
|
if ((reg_addr != NULL) && (reg_len != 0)) {
|
|
ack = soft_iic_tx_byte(iic, dev_addr);
|
|
if (ack == 0) {
|
|
log_error("dev_addr no ack!");
|
|
ret = IIC_ERROR_DEV_ADDR_ACK_ERROR; //无应答
|
|
goto _read_exit1;
|
|
}
|
|
|
|
for (u8 i = 0; i < reg_len; i++) {
|
|
ack = soft_iic_tx_byte(iic, reg_addr[i]);
|
|
if (ack == 0) {
|
|
log_error("reg_addr no ack!");
|
|
ret = IIC_ERROR_REG_ADDR_ACK_ERROR; //无应答
|
|
goto _read_exit1;
|
|
}
|
|
}
|
|
soft_iic_start(iic);
|
|
}
|
|
|
|
ack = soft_iic_tx_byte(iic, dev_addr | BIT(0));
|
|
if (ack == 0) {
|
|
log_error("dev_addr no ack!");
|
|
ret = IIC_ERROR_DEV_ADDR_ACK_ERROR; //无应答
|
|
goto _read_exit1;
|
|
}
|
|
|
|
ret = soft_iic_read_buf(iic, read_buf, read_len);
|
|
_read_exit1:
|
|
soft_iic_stop(iic);
|
|
_read_exit2:
|
|
return ret;
|
|
}
|
|
|
|
|
|
//如果无reg_addr:reg_addr=NULL,reg_len=0
|
|
//return: =write_len:ok, other:error
|
|
int soft_i2c_master_write_nbytes_to_device_reg(soft_iic_dev iic,
|
|
unsigned char dev_addr, //设备地址
|
|
unsigned char *reg_addr, unsigned char reg_len,//设备寄存器地址,长度
|
|
unsigned char *write_buf, int write_len)//数据buf, 写入长度
|
|
{
|
|
int res;
|
|
u8 ack;
|
|
if (soft_iic_check_busy(iic) != IIC_OK) { //busy
|
|
res = IIC_ERROR_BUSY; //busy
|
|
goto _write_exit2;
|
|
}
|
|
|
|
soft_iic_start(iic);
|
|
ack = soft_iic_tx_byte(iic, dev_addr);
|
|
if (ack == 0) {
|
|
log_error("dev_addr no ack!");
|
|
res = IIC_ERROR_DEV_ADDR_ACK_ERROR; //无应答
|
|
goto _write_exit1;
|
|
}
|
|
|
|
if ((reg_addr != NULL) && (reg_len != 0)) {
|
|
for (u8 i = 0; i < reg_len; i++) {
|
|
ack = soft_iic_tx_byte(iic, reg_addr[i]);
|
|
if (ack == 0) {
|
|
log_error("reg_addr no ack!");
|
|
res = IIC_ERROR_REG_ADDR_ACK_ERROR; //无应答
|
|
goto _write_exit1;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (res = 0; res < write_len; res++) {
|
|
if (0 == soft_iic_tx_byte(iic, write_buf[res])) {
|
|
log_error("write data no ack!");
|
|
goto _write_exit1;
|
|
}
|
|
}
|
|
_write_exit1:
|
|
soft_iic_stop(iic);
|
|
_write_exit2:
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************hw iic master*****************************/
|
|
#if defined CONFIG_IIC_VERSION2
|
|
#define HW_IIC_MASTER_ISR_EN 1
|
|
#else
|
|
#define HW_IIC_MASTER_ISR_EN 0
|
|
#endif
|
|
//如果无reg_addr:reg_addr=NULL,reg_len=0
|
|
//return: other:error, =read_len:ok
|
|
int hw_i2c_master_read_nbytes_from_device_reg(hw_iic_dev iic,
|
|
unsigned char dev_addr, //设备地址
|
|
unsigned char *reg_addr, unsigned char reg_len,//设备寄存器地址,长度
|
|
unsigned char *read_buf, int read_len)//缓存buf,读取长度
|
|
{
|
|
#if HW_IIC_MASTER_ISR_EN
|
|
#if defined(P11_HW_IIC_NUM)&&P11_HW_IIC_NUM
|
|
if (iic != HW_P11_IIC_0)
|
|
#endif
|
|
{
|
|
struct hw_iic_master_isr_transmit iic_isr_info = {
|
|
.dev_addr = dev_addr,
|
|
.restart_flag = 1,
|
|
.reg_buf = reg_addr,
|
|
.reg_len = reg_len,
|
|
.data_buf = read_buf,
|
|
.rx_len = read_len,
|
|
.tx_len = 0,
|
|
};
|
|
if ((reg_addr == NULL) || (reg_len == 0)) {
|
|
iic_isr_info .dev_addr = dev_addr | BIT(0);
|
|
iic_isr_info .restart_flag = 0;
|
|
}
|
|
enum iic_state_enum iic_sta = hw_iic_master_isr_transmit_cfg(iic, &iic_isr_info, 20);//byte间隔超时20:20*30ms
|
|
if (iic_sta != IIC_OK) {
|
|
log_error("iic%d isr sta:%d\n", iic, iic_sta);
|
|
if (iic_sta == IIC_ERROR_MASTER_ERROR) {
|
|
hw_iic_reset(iic);
|
|
}
|
|
return iic_sta;
|
|
}
|
|
return iic_isr_info.xfer_postion;
|
|
}
|
|
#endif
|
|
|
|
u8 ack;
|
|
int ret = 0;
|
|
if (hw_iic_check_busy(iic) != IIC_OK) { //busy
|
|
ret = IIC_ERROR_BUSY; //busy
|
|
goto _read_exit2;
|
|
}
|
|
ret = hw_iic_start(iic);
|
|
if (ret < 0) {
|
|
log_error("iic lock busy!%d", ret);
|
|
goto _read_exit2;
|
|
}
|
|
|
|
if ((reg_addr != NULL) && (reg_len != 0)) {
|
|
ack = hw_iic_tx_byte(iic, dev_addr);
|
|
if (ack == 0) {
|
|
log_error("dev_addr no ack!");
|
|
ret = IIC_ERROR_DEV_ADDR_ACK_ERROR; //无应答
|
|
goto _read_exit1;
|
|
}
|
|
|
|
for (u8 i = 0; i < reg_len; i++) {
|
|
ack = hw_iic_tx_byte(iic, reg_addr[i]);
|
|
if (ack == 0) {
|
|
log_error("reg_addr no ack!");
|
|
ret = IIC_ERROR_REG_ADDR_ACK_ERROR; //无应答
|
|
goto _read_exit1;
|
|
}
|
|
}
|
|
hw_iic_start(iic);
|
|
}
|
|
|
|
ack = hw_iic_tx_byte(iic, dev_addr | BIT(0));
|
|
if (ack == 0) {
|
|
log_error("dev_addr no ack!");
|
|
ret = IIC_ERROR_DEV_ADDR_ACK_ERROR; //无应答
|
|
goto _read_exit1;
|
|
}
|
|
|
|
ret = hw_iic_read_buf(iic, read_buf, read_len);
|
|
_read_exit1:
|
|
hw_iic_stop(iic);
|
|
if (ret != read_len) {
|
|
hw_iic_err_reset(iic);
|
|
hw_iic_reset(iic);
|
|
}
|
|
_read_exit2:
|
|
return ret;
|
|
}
|
|
|
|
|
|
//如果无reg_addr:reg_addr=NULL,reg_len=0
|
|
//return: =write_len:ok, other:error
|
|
int hw_i2c_master_write_nbytes_to_device_reg(hw_iic_dev iic,
|
|
unsigned char dev_addr, //设备地址
|
|
unsigned char *reg_addr, unsigned char reg_len,//设备寄存器地址,长度
|
|
unsigned char *write_buf, int write_len)//数据buf, 写入长度
|
|
{
|
|
#if HW_IIC_MASTER_ISR_EN
|
|
#if defined(P11_HW_IIC_NUM)&&P11_HW_IIC_NUM
|
|
if (iic != HW_P11_IIC_0)
|
|
#endif
|
|
{
|
|
struct hw_iic_master_isr_transmit iic_isr_info = {
|
|
.dev_addr = dev_addr,
|
|
.restart_flag = 0,
|
|
.reg_buf = reg_addr,
|
|
.reg_len = reg_len,
|
|
.data_buf = write_buf,
|
|
.rx_len = 0,
|
|
.tx_len = write_len,
|
|
};
|
|
enum iic_state_enum iic_sta = hw_iic_master_isr_transmit_cfg(iic, &iic_isr_info, 20);//byte间隔超时20:20*30ms
|
|
if (iic_sta != IIC_OK) {
|
|
log_error("iic%d isr sta:%d\n", iic, iic_sta);
|
|
if (iic_sta == IIC_ERROR_MASTER_ERROR) {
|
|
hw_iic_reset(iic);
|
|
}
|
|
return iic_sta;
|
|
}
|
|
return iic_isr_info.xfer_postion;
|
|
}
|
|
#endif
|
|
|
|
int res;
|
|
u8 ack;
|
|
if (hw_iic_check_busy(iic) != IIC_OK) { //busy
|
|
res = IIC_ERROR_BUSY; //busy
|
|
goto _write_exit2;
|
|
}
|
|
|
|
res = hw_iic_start(iic);
|
|
if (res < 0) {
|
|
log_error("iic lock busy!%d", res);
|
|
goto _write_exit2;
|
|
}
|
|
ack = hw_iic_tx_byte(iic, dev_addr);
|
|
if (ack == 0) {
|
|
log_error("dev_addr no ack!");
|
|
res = IIC_ERROR_DEV_ADDR_ACK_ERROR; //无应答
|
|
goto _write_exit1;
|
|
}
|
|
|
|
if ((reg_addr != NULL) && (reg_len != 0)) {
|
|
for (u8 i = 0; i < reg_len; i++) {
|
|
ack = hw_iic_tx_byte(iic, reg_addr[i]);
|
|
if (ack == 0) {
|
|
log_error("reg_addr no ack!");
|
|
res = IIC_ERROR_REG_ADDR_ACK_ERROR; //无应答
|
|
goto _write_exit1;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
for (res = 0; res < write_len; res++) {
|
|
if (0 == hw_iic_tx_byte(iic, write_buf[res])) {
|
|
log_error("write data no ack!");
|
|
goto _write_exit1;
|
|
}
|
|
}
|
|
#else
|
|
res = hw_iic_write_buf(iic, write_buf, write_len);
|
|
#endif
|
|
_write_exit1:
|
|
hw_iic_stop(iic);
|
|
if (res != write_len) {
|
|
hw_iic_err_reset(iic);
|
|
hw_iic_reset(iic);
|
|
}
|
|
_write_exit2:
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************hw iic slave*****************************/
|
|
|
|
//rx协议:start,addr write,data0,data1,,,,,,stop
|
|
int hw_iic_slave_polling_rx(hw_iic_dev iic, u8 *rx_buf)
|
|
{
|
|
int rx_cnt = 0;
|
|
int rx_state = 0;
|
|
|
|
log_info("--iic slave polling rx --");
|
|
local_irq_disable();//关闭所有中断
|
|
rx_state = hw_iic_slave_rx_prepare(iic, 0, 600000);//1s
|
|
if (rx_state == IIC_SLAVE_RX_PREPARE_OK) { //rx
|
|
} else if (rx_state == IIC_SLAVE_RX_PREPARE_TIMEOUT) { //error
|
|
log_error("iic slave wait addr timeout!");
|
|
local_irq_enable();
|
|
return 0;
|
|
} else if (rx_state == IIC_SLAVE_RX_PREPARE_END_OK) { //end
|
|
log_error("iic slave wait end!");
|
|
local_irq_enable();
|
|
return 0;
|
|
}
|
|
|
|
rx_state = hw_iic_slave_rx_byte(iic, &rx_buf[0]);//addr
|
|
if (rx_state >= IIC_SLAVE_RX_ADDR_RX) { //rx
|
|
} else if (rx_state == IIC_SLAVE_RX_ADDR_NO_MATCH) { //error
|
|
log_error("iic slave rx addr error!");
|
|
local_irq_enable();
|
|
return 0;
|
|
} else if (rx_state == IIC_SLAVE_RX_ADDR_TX) { //tx
|
|
|
|
}
|
|
rx_state = hw_iic_slave_rx_prepare(iic, 1, 100000);//1s, 1:收到数据应答
|
|
if (rx_state == IIC_SLAVE_RX_PREPARE_OK) { //rx
|
|
} else if (rx_state == IIC_SLAVE_RX_PREPARE_TIMEOUT) { //error
|
|
log_error("iic slave wait reg timeout!");
|
|
local_irq_enable();
|
|
return 0;
|
|
} else if (rx_state == IIC_SLAVE_RX_PREPARE_END_OK) { //end
|
|
log_info("iic slave wait end!");
|
|
local_irq_enable();
|
|
return 0;
|
|
}
|
|
|
|
rx_cnt = hw_iic_slave_rx_nbyte(iic, &rx_buf[1]);
|
|
local_irq_enable();
|
|
/* log_info("rx addr:%x, slave addr:%x", rx_buf[0], hw_iic_slave_get_addr(iic)); */
|
|
rx_cnt++;
|
|
log_info_hexdump(rx_buf, rx_cnt);
|
|
log_info("~~~~~iic rx polling end~~~~~\n");
|
|
memset(rx_buf, 0, rx_cnt);
|
|
return rx_cnt;
|
|
}
|
|
|
|
//tx协议:start,addr read,data0,data1,,,,,nack,stop
|
|
int hw_iic_slave_polling_tx(hw_iic_dev iic, u8 *tx_buf)
|
|
{
|
|
u8 slave_rx_data[3] = {0, 0, 0};
|
|
int rx_cnt = 0, tx_cnt = 0;
|
|
int rx_state = 0;
|
|
log_info("--iic slave polling tx --");
|
|
local_irq_disable();//关闭所有中断
|
|
rx_state = hw_iic_slave_rx_prepare(iic, 0, 600000);//1s
|
|
if (rx_state == IIC_SLAVE_RX_PREPARE_OK) { //rx
|
|
} else if (rx_state == IIC_SLAVE_RX_PREPARE_TIMEOUT) { //error
|
|
log_error("iic slave wait addr timeout!\n");
|
|
local_irq_enable();
|
|
return 0;
|
|
} else if (rx_state == IIC_SLAVE_RX_PREPARE_END_OK) { //end
|
|
log_error("iic slave wait end!\n");
|
|
local_irq_enable();
|
|
return 0;
|
|
}
|
|
|
|
rx_state = hw_iic_slave_rx_byte(iic, &slave_rx_data[rx_cnt++]);//addr
|
|
if (rx_state >= IIC_SLAVE_RX_ADDR_RX) { //rx
|
|
} else if (rx_state == IIC_SLAVE_RX_ADDR_TX) { //tx
|
|
hw_iic_slave_tx_byte(iic, tx_buf[tx_cnt++]);
|
|
goto _tx_strat;
|
|
} else { //error
|
|
log_error("iic slave rx addr error!\n");
|
|
local_irq_enable();
|
|
return 0;
|
|
}
|
|
|
|
_tx_strat:
|
|
tx_cnt = hw_iic_slave_tx_nbyte(iic, &tx_buf[tx_cnt]);
|
|
|
|
local_irq_enable();
|
|
/* log_info("rx0 addr:%x, slave addr:%x", slave_rx_data[0], hw_iic_slave_get_addr(iic)); */
|
|
log_info_hexdump(slave_rx_data, rx_cnt);
|
|
log_info("~~~~~iic tx polling end~~~~~\n");
|
|
return tx_cnt + 1; //ok
|
|
}
|
|
|