1217 lines
31 KiB
C
1217 lines
31 KiB
C
|
// Copyright 2020-2021 Beken
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
|
||
|
#include <driver/gpio.h>
|
||
|
#include <driver/int.h>
|
||
|
#include <driver/i2c.h>
|
||
|
#include "clock_driver.h"
|
||
|
#include "gpio_driver.h"
|
||
|
#include "icu_driver.h"
|
||
|
#include <os/mem.h>
|
||
|
#include "power_driver.h"
|
||
|
#include <os/os.h>
|
||
|
#include "i2c_hw.h"
|
||
|
#include "i2c_driver.h"
|
||
|
#include "i2c_hal.h"
|
||
|
#include "i2c_statis.h"
|
||
|
#include "sys_driver.h"
|
||
|
#if CONFIG_SPE
|
||
|
#include "security.h"
|
||
|
#endif
|
||
|
#if CONFIG_I2C_PM_CB_SUPPORT
|
||
|
#include <modules/pm.h>
|
||
|
#endif
|
||
|
|
||
|
typedef enum {
|
||
|
I2C_IDLE = 0,
|
||
|
I2C_START,
|
||
|
I2C_TX_DEV_ADDR,
|
||
|
I2C_RX_DEV_ADDR,
|
||
|
I2C_TX_MEM_ADDR_HIGH_8BIT,
|
||
|
I2C_TX_MEM_ADDR_LOW_8BIT,
|
||
|
I2C_TX_DATA,
|
||
|
I2C_RX_DATA,
|
||
|
I2C_STOP,
|
||
|
I2C_GET_ACK,
|
||
|
} i2c_master_status_t;
|
||
|
|
||
|
typedef struct {
|
||
|
i2c_hal_t hal;
|
||
|
uint8_t id_init_bits;
|
||
|
i2c_work_mode_t work_mode;
|
||
|
i2c_addr_mode_t addr_mode;
|
||
|
bool is_addr_tx_done;
|
||
|
bool is_with_mem_addr;
|
||
|
uint8_t *data_ptr;
|
||
|
uint32_t data_size;
|
||
|
uint32_t data_offset;
|
||
|
uint16_t dev_addr;
|
||
|
uint32_t mem_addr;
|
||
|
i2c_mem_addr_size_t mem_addr_size;
|
||
|
i2c_master_status_t master_status;
|
||
|
beken_semaphore_t tx_sema;
|
||
|
beken_semaphore_t rx_sema;
|
||
|
uint32_t int_status;
|
||
|
volatile bk_err_t err_code;
|
||
|
#if CONFIG_I2C_PM_CB_SUPPORT
|
||
|
uint32_t pm_backup[I2C_PM_BACKUP_REG_NUM];
|
||
|
uint8_t pm_backup_is_valid;
|
||
|
#endif
|
||
|
} i2c_driver_t;
|
||
|
|
||
|
typedef struct {
|
||
|
i2c_isr_t callback;
|
||
|
void *param;
|
||
|
} i2c_callback_t;
|
||
|
|
||
|
typedef struct bkTimerCallback{
|
||
|
beken2_timer_t* i2ctimer;
|
||
|
int callbackflag;
|
||
|
int asyncflag;
|
||
|
uint8_t transtate;
|
||
|
}bkTimercb_t;
|
||
|
|
||
|
|
||
|
#define I2C_RETURN_ON_NOT_INIT() do {\
|
||
|
if (!s_i2c_driver_is_init) {\
|
||
|
I2C_LOGD("i2c driver not init\r\n");\
|
||
|
return BK_ERR_I2C_NOT_INIT;\
|
||
|
}\
|
||
|
} while(0)
|
||
|
|
||
|
#define I2C_RETURN_ON_ID_NOT_INIT(id) do {\
|
||
|
if (!(s_i2c[id].id_init_bits & BIT((id)))) {\
|
||
|
I2C_LOGD("i2c id number(%d) is not init\r\n", (id));\
|
||
|
return BK_ERR_I2C_ID_NOT_INIT;\
|
||
|
}\
|
||
|
} while(0)
|
||
|
|
||
|
#define I2C_SET_PIN(id) do {\
|
||
|
i2c_hal_set_pin(&s_i2c[id].hal);\
|
||
|
gpio_dev_unmap(I2C##id##_LL_SDA_PIN);\
|
||
|
gpio_dev_unmap(I2C##id##_LL_SCL_PIN);\
|
||
|
gpio_dev_map(I2C##id##_LL_SCL_PIN, GPIO_DEV_I2C##id##_SCL);\
|
||
|
gpio_dev_map(I2C##id##_LL_SDA_PIN, GPIO_DEV_I2C##id##_SDA);\
|
||
|
bk_gpio_pull_up(I2C##id##_LL_SCL_PIN);\
|
||
|
bk_gpio_pull_up(I2C##id##_LL_SDA_PIN);\
|
||
|
} while(0)
|
||
|
|
||
|
#if CONFIG_SPE
|
||
|
#define I2C_CHECK_SECURE(id) do {\
|
||
|
switch (id) {\
|
||
|
case I2C_ID_0:\
|
||
|
BK_ASSERT(DEV_IS_SECURE(I2C0) == 1);\
|
||
|
break;\
|
||
|
case I2C_ID_1:\
|
||
|
BK_ASSERT(DEV_IS_SECURE(I2C1) == 1);\
|
||
|
break;\
|
||
|
default:\
|
||
|
break;\
|
||
|
}\
|
||
|
} while(0)
|
||
|
#else
|
||
|
#define I2C_CHECK_SECURE(id)
|
||
|
#endif
|
||
|
|
||
|
static bkTimercb_t i2ccallback[SOC_I2C_UNIT_NUM] ={0};
|
||
|
static i2c_driver_t s_i2c[SOC_I2C_UNIT_NUM] = {0};
|
||
|
static bool s_i2c_driver_is_init = false;
|
||
|
|
||
|
static void i2c0_isr(void);
|
||
|
#if (SOC_I2C_UNIT_NUM > 1)
|
||
|
static void i2c1_isr(void);
|
||
|
#endif
|
||
|
#if (SOC_I2C_UNIT_NUM > 2)
|
||
|
static void i2c2_isr(void);
|
||
|
#endif
|
||
|
|
||
|
#if CONFIG_GPIO_DEFAULT_SET_SUPPORT
|
||
|
//if the special hardware/board needs to over-write the I2C GPIO,please implement it here like i2c_init_gpio
|
||
|
#else
|
||
|
static void i2c_init_gpio(i2c_id_t id)
|
||
|
{
|
||
|
switch(id) {
|
||
|
case I2C_ID_0:
|
||
|
I2C_SET_PIN(0);
|
||
|
break;
|
||
|
#if (SOC_I2C_UNIT_NUM > 1)
|
||
|
case I2C_ID_1:
|
||
|
I2C_SET_PIN(1);
|
||
|
break;
|
||
|
#endif
|
||
|
#if (SOC_I2C_UNIT_NUM > 2)
|
||
|
case I2C_ID_2:
|
||
|
I2C_SET_PIN(2);
|
||
|
break;
|
||
|
#endif
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (CONFIG_SYSTEM_CTRL)
|
||
|
static void i2c_clock_enable(i2c_id_t id)
|
||
|
{
|
||
|
switch(id)
|
||
|
{
|
||
|
case I2C_ID_0:
|
||
|
sys_drv_dev_clk_pwr_up(CLK_PWR_ID_I2C1, CLK_PWR_CTRL_PWR_UP);
|
||
|
break;
|
||
|
|
||
|
#if (SOC_I2C_UNIT_NUM > 1)
|
||
|
case I2C_ID_1:
|
||
|
sys_drv_dev_clk_pwr_up(CLK_PWR_ID_I2C2, CLK_PWR_CTRL_PWR_UP);
|
||
|
break;
|
||
|
#endif
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void i2c_clock_disable(i2c_id_t id)
|
||
|
{
|
||
|
switch(id)
|
||
|
{
|
||
|
case I2C_ID_0:
|
||
|
sys_drv_dev_clk_pwr_up(CLK_PWR_ID_I2C1, CLK_PWR_CTRL_PWR_DOWN);
|
||
|
break;
|
||
|
#if (SOC_I2C_UNIT_NUM > 1)
|
||
|
case I2C_ID_1:
|
||
|
sys_drv_dev_clk_pwr_up(CLK_PWR_ID_I2C2, CLK_PWR_CTRL_PWR_DOWN);
|
||
|
break;
|
||
|
#endif
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void i2c_interrupt_enable(i2c_id_t id)
|
||
|
{
|
||
|
switch(id)
|
||
|
{
|
||
|
case I2C_ID_0:
|
||
|
sys_drv_int_enable(I2C_INTERRUPT_CTRL_BIT);
|
||
|
break;
|
||
|
#if (SOC_I2C_UNIT_NUM > 1)
|
||
|
case I2C_ID_1:
|
||
|
sys_drv_int_enable(I2C1_INTERRUPT_CTRL_BIT);
|
||
|
break;
|
||
|
#endif
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void i2c_interrupt_disable(i2c_id_t id)
|
||
|
{
|
||
|
switch(id)
|
||
|
{
|
||
|
case I2C_ID_0:
|
||
|
sys_drv_int_disable(I2C_INTERRUPT_CTRL_BIT);
|
||
|
break;
|
||
|
#if (SOC_I2C_UNIT_NUM > 1)
|
||
|
case I2C_ID_1:
|
||
|
sys_drv_int_disable(I2C1_INTERRUPT_CTRL_BIT);
|
||
|
break;
|
||
|
#endif
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* 1. power up i2c
|
||
|
* 2. set clk
|
||
|
* 3. icu enable interrupt
|
||
|
* 4. set gpio as i2c
|
||
|
*/
|
||
|
static void i2c_id_init_common(i2c_id_t id)
|
||
|
{
|
||
|
bk_err_t ret = 0;
|
||
|
|
||
|
#if (CONFIG_SYSTEM_CTRL)
|
||
|
i2c_clock_enable(id);
|
||
|
i2c_interrupt_enable(id);
|
||
|
#else
|
||
|
power_i2c_pwr_up(id);
|
||
|
clk_set_i2c_clk_26m(id);
|
||
|
icu_enable_i2c_interrupt(id);
|
||
|
#endif
|
||
|
#if CONFIG_GPIO_DEFAULT_SET_SUPPORT
|
||
|
/*
|
||
|
* GPIO info is setted in GPIO_DEFAULT_DEV_CONFIG and
|
||
|
* inited in bk_gpio_driver_init->gpio_hal_default_map_init.
|
||
|
* If needs to re-config GPIO, can deal it here.
|
||
|
*/
|
||
|
#else
|
||
|
i2c_init_gpio(id);
|
||
|
#endif
|
||
|
if (s_i2c[id].tx_sema == NULL) {
|
||
|
ret = rtos_init_semaphore(&(s_i2c[id].tx_sema), 1);
|
||
|
BK_ASSERT(kNoErr == ret); /* ASSERT VERIFIED */
|
||
|
}
|
||
|
|
||
|
if (s_i2c[id].rx_sema == NULL) {
|
||
|
ret = rtos_init_semaphore(&(s_i2c[id].rx_sema), 1);
|
||
|
BK_ASSERT(kNoErr == ret); /* ASSERT VERIFIED */
|
||
|
}
|
||
|
|
||
|
s_i2c[id].id_init_bits |= BIT(id);
|
||
|
}
|
||
|
|
||
|
static void i2c_id_deinit_common(i2c_id_t id)
|
||
|
{
|
||
|
i2c_hal_stop_common(&s_i2c[id].hal);
|
||
|
i2c_hal_reset_config_to_default(&s_i2c[id].hal);
|
||
|
|
||
|
#if (CONFIG_SYSTEM_CTRL)
|
||
|
i2c_clock_disable(id);
|
||
|
i2c_interrupt_disable(id);
|
||
|
#else
|
||
|
icu_disable_i2c_interrupt(id);
|
||
|
power_i2c_pwr_down(id);
|
||
|
#endif
|
||
|
|
||
|
s_i2c[id].addr_mode = 0;
|
||
|
rtos_deinit_semaphore(&(s_i2c[id].tx_sema));
|
||
|
rtos_deinit_semaphore(&(s_i2c[id].rx_sema));
|
||
|
s_i2c[id].tx_sema = NULL;
|
||
|
s_i2c[id].rx_sema = NULL;
|
||
|
s_i2c[id].id_init_bits &= ~BIT(id);
|
||
|
}
|
||
|
|
||
|
static bk_err_t i2c_wait_sm_bus_idle(i2c_id_t id, uint32_t timeout_ms)
|
||
|
{
|
||
|
uint32_t start_tick = 0;
|
||
|
uint32_t cur_tick = 0;
|
||
|
uint32_t tick_offset = 0;
|
||
|
|
||
|
start_tick = rtos_get_time();
|
||
|
while (i2c_hal_is_busy(&s_i2c[id].hal)) {
|
||
|
cur_tick = rtos_get_time();
|
||
|
tick_offset = (cur_tick >= start_tick) ? (cur_tick - start_tick) : (0xffffffff - start_tick + cur_tick);
|
||
|
if (tick_offset > timeout_ms) {
|
||
|
I2C_LOGW("i2c sm bus is busy\r\n");
|
||
|
return BK_ERR_I2C_SM_BUS_BUSY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
static void i2c_transtate_reset (int id)
|
||
|
{
|
||
|
i2ccallback[id].transtate = 0;
|
||
|
}
|
||
|
|
||
|
static void i2c_transtate_set (int id)
|
||
|
{
|
||
|
i2ccallback[id].transtate = 1;
|
||
|
}
|
||
|
|
||
|
static void i2c_timer_start ( int id )
|
||
|
{
|
||
|
if ((i2ccallback[id].asyncflag == 1)&&(i2ccallback[id].callbackflag == 1)) {
|
||
|
if (i2ccallback[id].i2ctimer!= NULL) {
|
||
|
rtos_start_oneshot_timer( i2ccallback[id].i2ctimer) ;
|
||
|
}
|
||
|
i2ccallback[id].asyncflag = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bk_err_t i2c_master_start(i2c_id_t id)
|
||
|
{
|
||
|
i2c_hal_disable_stop(&s_i2c[id].hal);
|
||
|
i2c_hal_set_tx_mode(&s_i2c[id].hal);
|
||
|
s_i2c[id].master_status = I2C_TX_DEV_ADDR;
|
||
|
i2c_transtate_reset(id);
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
static bk_err_t i2c_master_stop(i2c_id_t id)
|
||
|
{
|
||
|
i2c_hal_enable_stop(&s_i2c[id].hal);
|
||
|
s_i2c[id].int_status |= I2C1_F_STOP;
|
||
|
s_i2c[id].master_status = I2C_IDLE;
|
||
|
i2c_timer_start(id);
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
static bk_err_t i2c_master_set_write_dev_addr(i2c_id_t id, uint16_t dev_addr)
|
||
|
{
|
||
|
/* write slave_addr first,then enable start bit,
|
||
|
* otherwise the slave_addr written will be zero
|
||
|
*/
|
||
|
i2c_hal_write_byte(&s_i2c[id].hal, dev_addr << 1 & (~0x01));
|
||
|
i2c_hal_enable_start(&s_i2c[id].hal);
|
||
|
|
||
|
if (!s_i2c[id].is_with_mem_addr) {
|
||
|
s_i2c[id].master_status = I2C_TX_DATA;
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
if (s_i2c[id].mem_addr_size == I2C_MEM_ADDR_SIZE_16BIT) {
|
||
|
s_i2c[id].master_status = I2C_TX_MEM_ADDR_HIGH_8BIT;
|
||
|
} else {
|
||
|
s_i2c[id].master_status = I2C_TX_MEM_ADDR_LOW_8BIT;
|
||
|
}
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
static bk_err_t i2c_master_set_read_dev_addr(i2c_id_t id, uint16_t dev_addr)
|
||
|
{
|
||
|
i2c_hal_write_byte(&s_i2c[id].hal, dev_addr << 1 | 0x01);
|
||
|
i2c_hal_enable_start(&s_i2c[id].hal);
|
||
|
s_i2c[id].int_status |= I2C1_F_START;
|
||
|
s_i2c[id].master_status = I2C_RX_DATA;
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
static bk_err_t i2c_master_write_mem_addr_high_8bit(i2c_id_t id, uint16_t mem_addr)
|
||
|
{
|
||
|
i2c_hal_write_byte(&s_i2c[id].hal, mem_addr >> 8 & 0xff);
|
||
|
s_i2c[id].master_status = I2C_TX_MEM_ADDR_LOW_8BIT;
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
static bk_err_t i2c_master_write_mem_addr_low_8bit(i2c_id_t id, uint16_t mem_addr)
|
||
|
{
|
||
|
i2c_hal_write_byte(&s_i2c[id].hal, mem_addr & 0xff);
|
||
|
if (s_i2c[id].work_mode == I2C_MASTER_WRITE) {
|
||
|
s_i2c[id].master_status = I2C_TX_DATA;
|
||
|
} else if (s_i2c[id].work_mode == I2C_MASTER_READ) {
|
||
|
s_i2c[id].master_status = I2C_RX_DEV_ADDR;
|
||
|
}
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
static bk_err_t i2c_master_write_byte(i2c_id_t id, uint8_t data)
|
||
|
{
|
||
|
i2c_hal_write_byte(&s_i2c[id].hal, data);
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
#if (CONFIG_FM_I2C)
|
||
|
static uint8_t i2c_master_read_byte(i2c_id_t id)
|
||
|
{
|
||
|
return i2c_hal_read_byte(&s_i2c[id].hal);
|
||
|
}
|
||
|
|
||
|
static bk_err_t i2c0_master_write_data(i2c_id_t id)
|
||
|
{
|
||
|
uint32_t remain_size = s_i2c[id].data_size - s_i2c[id].data_offset;
|
||
|
if (!remain_size) {
|
||
|
I2C_LOGD("data_size:%d tx done\r\n", s_i2c[id].data_size);
|
||
|
i2c_master_stop(id);
|
||
|
rtos_set_semaphore(&s_i2c[id].tx_sema);
|
||
|
} else {
|
||
|
i2c_master_write_byte(id, s_i2c[id].data_ptr[(s_i2c[id].data_offset)++]);
|
||
|
s_i2c[id].master_status = I2C_TX_DATA;
|
||
|
}
|
||
|
return BK_OK;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static bk_err_t i2c1_master_write_data(i2c_id_t id)
|
||
|
{
|
||
|
uint32_t data_size = 0;
|
||
|
uint32_t remain_size = s_i2c[id].data_size - s_i2c[id].data_offset;
|
||
|
if (!remain_size) {
|
||
|
I2C_LOGD("data_size:%d tx done\r\n", s_i2c[id].data_size);
|
||
|
i2c_master_stop(id);
|
||
|
rtos_set_semaphore(&s_i2c[id].tx_sema);
|
||
|
return BK_OK;
|
||
|
}
|
||
|
uint32_t empty_fifo_num = i2c_hal_get_write_empty_fifo_num(&s_i2c[id].hal);
|
||
|
if (remain_size < empty_fifo_num) {
|
||
|
data_size = remain_size;
|
||
|
} else {
|
||
|
data_size = empty_fifo_num;
|
||
|
}
|
||
|
for (uint32_t i = 0; i < data_size; i++) {
|
||
|
i2c_master_write_byte(id, s_i2c[id].data_ptr[(s_i2c[id].data_offset)++]);
|
||
|
}
|
||
|
remain_size = s_i2c[id].data_size - s_i2c[id].data_offset;
|
||
|
if (remain_size < empty_fifo_num) {
|
||
|
I2C_LOGD("remain_size:%d, empty_fifo_num:%d\r\n", remain_size, empty_fifo_num);
|
||
|
s_i2c[id].int_status &= ~(I2C1_F_INT_MODE_V | I2C1_F_START);
|
||
|
}
|
||
|
s_i2c[id].master_status = I2C_TX_DATA;
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
#if (CONFIG_FM_I2C)
|
||
|
static bk_err_t i2c0_master_read_data(i2c_id_t id)
|
||
|
{
|
||
|
i2c_hal_set_rx_mode(&s_i2c[id].hal);
|
||
|
/* tx ack, next isr read data */
|
||
|
if (i2c_hal_is_start(&s_i2c[id].hal)) {
|
||
|
i2c_hal_tx_ack(&s_i2c[id].hal);
|
||
|
s_i2c[id].master_status = I2C_RX_DATA;
|
||
|
return BK_OK;
|
||
|
}
|
||
|
s_i2c[id].data_ptr[(s_i2c[id].data_offset)++] = i2c_master_read_byte(id);
|
||
|
if (s_i2c[id].data_offset == s_i2c[id].data_size) {
|
||
|
I2C_LOGI("data_size:%d rx done\r\n", s_i2c[id].data_size);
|
||
|
/* rx data done, send NACK and stop*/
|
||
|
i2c_hal_tx_non_ack(&s_i2c[id].hal);
|
||
|
i2c_master_stop(id);
|
||
|
rtos_set_semaphore(&s_i2c[id].rx_sema);
|
||
|
} else {
|
||
|
i2c_hal_tx_ack(&s_i2c[id].hal);
|
||
|
s_i2c[id].master_status = I2C_RX_DATA;
|
||
|
}
|
||
|
return BK_OK;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
bk_err_t i2c1_master_read_data(i2c_id_t id)
|
||
|
{
|
||
|
if (i2c_hal_is_start(&s_i2c[id].hal)) {
|
||
|
I2C_LOGD("master_read i2c_is_start\r\n");
|
||
|
s_i2c[id].int_status |= I2C1_F_ACK;
|
||
|
s_i2c[id].master_status = I2C_RX_DATA;
|
||
|
return BK_OK;
|
||
|
}
|
||
|
uint32_t fifo_num = i2c_hal_get_read_fifo_num(&s_i2c[id].hal);
|
||
|
for (uint32_t i = 0; i < fifo_num; i++) {
|
||
|
s_i2c[id].data_ptr[(s_i2c[id].data_offset)++] = i2c_hal_read_byte(&s_i2c[id].hal);
|
||
|
if (s_i2c[id].data_offset == s_i2c[id].data_size) { /* avoid index is out of array range */
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
uint32_t remain_size = s_i2c[id].data_size - s_i2c[id].data_offset;
|
||
|
if (!remain_size) {
|
||
|
s_i2c[id].int_status &= ~(I2C1_F_ACK | I2C1_F_START);
|
||
|
i2c_master_stop(id);
|
||
|
rtos_set_semaphore(&s_i2c[id].rx_sema);
|
||
|
} else if (remain_size < fifo_num) {
|
||
|
s_i2c[id].int_status |= (I2C1_F_ACK | I2C1_F_INT_MODE_V);
|
||
|
s_i2c[id].master_status = I2C_RX_DATA;
|
||
|
} else {
|
||
|
s_i2c[id].int_status |= I2C1_F_ACK;
|
||
|
s_i2c[id].master_status = I2C_RX_DATA;
|
||
|
}
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
void bk_i2c_timer_callback(int id, void* myTimer)
|
||
|
{
|
||
|
os_memset(&i2ccallback[id],0,sizeof(bkTimercb_t));
|
||
|
i2ccallback[id].i2ctimer =(beken2_timer_t*) myTimer;
|
||
|
i2ccallback[id].callbackflag = 1;
|
||
|
}
|
||
|
|
||
|
uint8_t bk_i2c_get_busstate ( int id )
|
||
|
{
|
||
|
I2C_LOGD("bk_i2c_get_busstate[%d].\n",s_i2c[id].master_status);
|
||
|
if(s_i2c[id].master_status==0){
|
||
|
return 1;//idle
|
||
|
} else {
|
||
|
return 0;//busy
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint8_t bk_i2c_get_transstate ( int id )
|
||
|
{
|
||
|
return i2ccallback[id].transtate;
|
||
|
}
|
||
|
|
||
|
#if (CONFIG_I2C_PM_CB_SUPPORT)
|
||
|
#define I2C_PM_CHECK_RESTORE(id) do {\
|
||
|
if ((id == I2C_ID_0) && bk_pm_module_lv_sleep_state_get(PM_DEV_ID_I2C1)) {\
|
||
|
bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_I2C0, PM_POWER_MODULE_STATE_ON);\
|
||
|
i2c_pm_restore(0, (void *)id);\
|
||
|
bk_pm_module_lv_sleep_state_clear(PM_DEV_ID_I2C1); \
|
||
|
} else if ((id == I2C_ID_1) && bk_pm_module_lv_sleep_state_get(PM_DEV_ID_I2C2) ) {\
|
||
|
bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_I2C1, PM_POWER_MODULE_STATE_ON);\
|
||
|
i2c_pm_restore(0, (void *)id);\
|
||
|
bk_pm_module_lv_sleep_state_clear(PM_DEV_ID_I2C2); \
|
||
|
}\
|
||
|
} while(0)
|
||
|
|
||
|
static int i2c_pm_backup(uint64_t sleep_time, void *args)
|
||
|
{
|
||
|
i2c_id_t id = (i2c_id_t)args;
|
||
|
I2C_RETURN_ON_NOT_INIT();
|
||
|
I2C_RETURN_ON_ID_NOT_INIT(id);
|
||
|
|
||
|
if (!s_i2c[id].pm_backup_is_valid)
|
||
|
{
|
||
|
s_i2c[id].pm_backup_is_valid = 1;
|
||
|
i2c_hal_backup(&s_i2c[id].hal, &s_i2c[id].pm_backup[0]);
|
||
|
i2c_clock_disable(id);
|
||
|
}
|
||
|
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
static int i2c_pm_restore(uint64_t sleep_time, void *args)
|
||
|
{
|
||
|
i2c_id_t id = (i2c_id_t)args;
|
||
|
I2C_RETURN_ON_NOT_INIT();
|
||
|
I2C_RETURN_ON_ID_NOT_INIT(id);
|
||
|
|
||
|
if (s_i2c[id].pm_backup_is_valid)
|
||
|
{
|
||
|
i2c_clock_enable(id);
|
||
|
i2c_hal_restore(&s_i2c[id].hal, &s_i2c[id].pm_backup[0]);
|
||
|
s_i2c[id].pm_backup_is_valid = 0;
|
||
|
}
|
||
|
|
||
|
return BK_OK;
|
||
|
}
|
||
|
#else
|
||
|
#define I2C_PM_CHECK_RESTORE(id)
|
||
|
#endif
|
||
|
|
||
|
bk_err_t bk_i2c_driver_init(void)
|
||
|
{
|
||
|
if (s_i2c_driver_is_init) {
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
os_memset(&s_i2c, 0, sizeof(s_i2c));
|
||
|
for (int id = I2C_ID_0; id < I2C_ID_MAX; id++) {
|
||
|
s_i2c[id].hal.id = id;
|
||
|
#if (CONFIG_I2C_PM_CB_SUPPORT)
|
||
|
if (id == I2C_ID_0) {
|
||
|
bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_I2C0, PM_POWER_MODULE_STATE_ON);
|
||
|
} else if (id == I2C_ID_1) {
|
||
|
bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_I2C1, PM_POWER_MODULE_STATE_ON);
|
||
|
}
|
||
|
#endif
|
||
|
i2c_hal_init(&s_i2c[id].hal);
|
||
|
}
|
||
|
bk_int_isr_register(INT_SRC_I2C0, i2c0_isr, NULL);
|
||
|
#if (SOC_I2C_UNIT_NUM > 1)
|
||
|
bk_int_isr_register(INT_SRC_I2C1, i2c1_isr, NULL);
|
||
|
#endif
|
||
|
#if (SOC_I2C_UNIT_NUM > 2)
|
||
|
bk_int_isr_register(INT_SRC_I2C2, i2c2_isr, NULL);
|
||
|
#endif
|
||
|
i2c_statis_init();
|
||
|
s_i2c_driver_is_init = true;
|
||
|
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
bk_err_t bk_i2c_driver_deinit(void)
|
||
|
{
|
||
|
if (!s_i2c_driver_is_init) {
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
for (int id = I2C_ID_0; id < I2C_ID_MAX; id++) {
|
||
|
i2c_id_deinit_common(id);
|
||
|
#if (CONFIG_I2C_PM_CB_SUPPORT)
|
||
|
if (id == I2C_ID_0) {
|
||
|
bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_I2C0, PM_POWER_MODULE_STATE_OFF);
|
||
|
} else if (id == I2C_ID_1) {
|
||
|
bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_I2C1, PM_POWER_MODULE_STATE_OFF);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
bk_int_isr_unregister(INT_SRC_I2C0);
|
||
|
#if (SOC_I2C_UNIT_NUM > 1)
|
||
|
bk_int_isr_unregister(INT_SRC_I2C1);
|
||
|
#endif
|
||
|
#if (SOC_I2C_UNIT_NUM > 2)
|
||
|
bk_int_isr_unregister(INT_SRC_I2C2);
|
||
|
#endif
|
||
|
s_i2c_driver_is_init = false;
|
||
|
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
bk_err_t bk_i2c_init(i2c_id_t id, const i2c_config_t *cfg)
|
||
|
{
|
||
|
BK_RETURN_ON_NULL(cfg);
|
||
|
I2C_RETURN_ON_NOT_INIT();
|
||
|
I2C_CHECK_SECURE(id);
|
||
|
|
||
|
#if (CONFIG_I2C_PM_CB_SUPPORT)
|
||
|
pm_cb_conf_t enter_config = {i2c_pm_backup, (void *)id};
|
||
|
if (id == I2C_ID_0) {
|
||
|
bk_pm_module_lv_sleep_state_clear(PM_DEV_ID_I2C1);
|
||
|
bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_I2C0, PM_POWER_MODULE_STATE_ON);
|
||
|
bk_pm_sleep_register_cb(PM_MODE_LOW_VOLTAGE, PM_DEV_ID_I2C1, &enter_config, NULL);
|
||
|
} else if (id == I2C_ID_1) {
|
||
|
bk_pm_module_lv_sleep_state_clear(PM_DEV_ID_I2C2);
|
||
|
bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_I2C1, PM_POWER_MODULE_STATE_ON);
|
||
|
bk_pm_sleep_register_cb(PM_MODE_LOW_VOLTAGE, PM_DEV_ID_I2C2, &enter_config, NULL);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (CONFIG_CPU_CNT > 1)
|
||
|
uint32_t support_id = CONFIG_I2C_SUPPORT_ID_BITS;
|
||
|
uint32_t id_init_bits = BIT(id);
|
||
|
if (!(support_id & id_init_bits))
|
||
|
return BK_ERR_I2C_CHECK_DEFCONFIG;
|
||
|
#endif
|
||
|
s_i2c[id].int_status = 0;
|
||
|
s_i2c[id].addr_mode = cfg->addr_mode;
|
||
|
i2c_id_init_common(id);
|
||
|
i2c_hal_configure(&s_i2c[id].hal, cfg);
|
||
|
i2c_hal_start_common(&s_i2c[id].hal);
|
||
|
I2C_LOGI("I2C(%d) init ok, baud_rate:%d\r\n", id, cfg->baud_rate);
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
bk_err_t bk_i2c_deinit(i2c_id_t id)
|
||
|
{
|
||
|
I2C_RETURN_ON_NOT_INIT();
|
||
|
|
||
|
i2c_id_deinit_common(id);
|
||
|
#if (CONFIG_I2C_PM_CB_SUPPORT)
|
||
|
if (id == I2C_ID_0) {
|
||
|
bk_pm_sleep_unregister_cb(PM_MODE_LOW_VOLTAGE, PM_DEV_ID_I2C1, true, true);
|
||
|
bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_I2C0, PM_POWER_MODULE_STATE_OFF);
|
||
|
} else if (id == I2C_ID_1) {
|
||
|
bk_pm_sleep_unregister_cb(PM_MODE_LOW_VOLTAGE, PM_DEV_ID_I2C2, true, true);
|
||
|
bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_I2C1, PM_POWER_MODULE_STATE_OFF);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
bk_err_t bk_i2c_master_write(i2c_id_t id, uint32_t dev_addr, const uint8_t *data, uint32_t size, uint32_t timeout_ms)
|
||
|
{
|
||
|
I2C_RETURN_ON_NOT_INIT();
|
||
|
I2C_RETURN_ON_ID_NOT_INIT(id);
|
||
|
I2C_PM_CHECK_RESTORE(id);
|
||
|
BK_RETURN_ON_ERR(i2c_wait_sm_bus_idle(id, timeout_ms));
|
||
|
if (timeout_ms != 0xFFFFFFFF){
|
||
|
i2ccallback[id].asyncflag = 1;
|
||
|
}
|
||
|
uint32_t int_level = rtos_enter_critical();
|
||
|
s_i2c[id].err_code = BK_OK;
|
||
|
s_i2c[id].work_mode = I2C_MASTER_WRITE;
|
||
|
s_i2c[id].is_with_mem_addr = false;
|
||
|
s_i2c[id].dev_addr = dev_addr;
|
||
|
s_i2c[id].data_ptr = (uint8_t *)data;
|
||
|
s_i2c[id].data_size = size;
|
||
|
s_i2c[id].data_offset = 0;
|
||
|
s_i2c[id].int_status = 0;
|
||
|
i2c_master_start(id);
|
||
|
i2c_master_set_write_dev_addr(id, dev_addr);
|
||
|
i2c_hal_set_write_int_mode(&s_i2c[id].hal, size);
|
||
|
rtos_exit_critical(int_level);
|
||
|
|
||
|
rtos_get_semaphore(&s_i2c[id].tx_sema, timeout_ms);
|
||
|
|
||
|
return s_i2c[id].err_code;
|
||
|
}
|
||
|
|
||
|
bk_err_t bk_i2c_master_write_noaddr(i2c_id_t id, const uint8_t *data, uint32_t size, uint32_t timeout_ms)
|
||
|
{
|
||
|
I2C_RETURN_ON_NOT_INIT();
|
||
|
I2C_RETURN_ON_ID_NOT_INIT(id);
|
||
|
I2C_PM_CHECK_RESTORE(id);
|
||
|
BK_RETURN_ON_ERR(i2c_wait_sm_bus_idle(id, timeout_ms));
|
||
|
if (timeout_ms != 0xFFFFFFFF){
|
||
|
i2ccallback[id].asyncflag = 1;
|
||
|
}
|
||
|
uint32_t int_level = rtos_enter_critical();
|
||
|
s_i2c[id].err_code = BK_OK;
|
||
|
s_i2c[id].work_mode = I2C_MASTER_WRITE;
|
||
|
s_i2c[id].is_with_mem_addr = false;
|
||
|
s_i2c[id].dev_addr = data[0];
|
||
|
s_i2c[id].data_ptr = (uint8_t *)data + 1;
|
||
|
s_i2c[id].data_size = size - 1;
|
||
|
s_i2c[id].data_offset = 0;
|
||
|
s_i2c[id].int_status = 0;
|
||
|
i2c_master_start(id);
|
||
|
// write first byte
|
||
|
i2c_hal_write_byte(&s_i2c[id].hal, data[0]);
|
||
|
i2c_hal_enable_start(&s_i2c[id].hal);
|
||
|
s_i2c[id].master_status = I2C_TX_DATA;
|
||
|
i2c_hal_set_write_int_mode(&s_i2c[id].hal, size);
|
||
|
rtos_exit_critical(int_level);
|
||
|
|
||
|
rtos_get_semaphore(&s_i2c[id].tx_sema, timeout_ms);
|
||
|
|
||
|
return s_i2c[id].err_code;
|
||
|
}
|
||
|
|
||
|
bk_err_t bk_i2c_master_read(i2c_id_t id, uint32_t dev_addr, uint8_t *data, uint32_t size, uint32_t timeout_ms)
|
||
|
{
|
||
|
I2C_RETURN_ON_NOT_INIT();
|
||
|
I2C_RETURN_ON_ID_NOT_INIT(id);
|
||
|
I2C_PM_CHECK_RESTORE(id);
|
||
|
BK_RETURN_ON_ERR(i2c_wait_sm_bus_idle(id, timeout_ms));
|
||
|
if (timeout_ms != 0xFFFFFFFF){
|
||
|
i2ccallback[id].asyncflag = 1;
|
||
|
}
|
||
|
uint32_t int_level = rtos_enter_critical();
|
||
|
s_i2c[id].err_code = BK_OK;
|
||
|
s_i2c[id].work_mode = I2C_MASTER_READ;
|
||
|
s_i2c[id].is_with_mem_addr = false;
|
||
|
s_i2c[id].dev_addr = dev_addr;
|
||
|
s_i2c[id].data_ptr = data;
|
||
|
s_i2c[id].data_size = size;
|
||
|
s_i2c[id].data_offset = 0;
|
||
|
s_i2c[id].int_status = 0;
|
||
|
i2c_master_start(id);
|
||
|
i2c_master_set_read_dev_addr(id, dev_addr);
|
||
|
i2c_hal_set_rx_mode(&s_i2c[id].hal);
|
||
|
i2c_hal_set_read_int_mode(&s_i2c[id].hal, size);
|
||
|
rtos_exit_critical(int_level);
|
||
|
|
||
|
rtos_get_semaphore(&s_i2c[id].rx_sema, timeout_ms);
|
||
|
|
||
|
return s_i2c[id].err_code;
|
||
|
}
|
||
|
|
||
|
bk_err_t bk_i2c_master_read_noaddr(i2c_id_t id, uint8_t *data, uint32_t size, uint32_t timeout_ms)
|
||
|
{
|
||
|
I2C_RETURN_ON_NOT_INIT();
|
||
|
I2C_RETURN_ON_ID_NOT_INIT(id);
|
||
|
I2C_PM_CHECK_RESTORE(id);
|
||
|
BK_RETURN_ON_ERR(i2c_wait_sm_bus_idle(id, timeout_ms));
|
||
|
if (timeout_ms != 0xFFFFFFFF){
|
||
|
i2ccallback[id].asyncflag = 1;
|
||
|
}
|
||
|
uint32_t int_level = rtos_enter_critical();
|
||
|
s_i2c[id].err_code = BK_OK;
|
||
|
s_i2c[id].work_mode = I2C_MASTER_READ;
|
||
|
s_i2c[id].is_with_mem_addr = false;
|
||
|
s_i2c[id].dev_addr = data[0];
|
||
|
s_i2c[id].data_ptr = data;
|
||
|
s_i2c[id].data_size = size;
|
||
|
s_i2c[id].data_offset = 0;
|
||
|
s_i2c[id].int_status = 0;
|
||
|
i2c_master_start(id);
|
||
|
// skip read slave address
|
||
|
s_i2c[id].master_status = I2C_RX_DATA;
|
||
|
i2c_hal_enable_start(&s_i2c[id].hal);
|
||
|
s_i2c[id].int_status |= I2C1_F_START;
|
||
|
i2c_hal_set_rx_mode(&s_i2c[id].hal);
|
||
|
i2c_hal_set_read_int_mode(&s_i2c[id].hal, size);
|
||
|
rtos_exit_critical(int_level);
|
||
|
|
||
|
rtos_get_semaphore(&s_i2c[id].rx_sema, timeout_ms);
|
||
|
|
||
|
return s_i2c[id].err_code;
|
||
|
}
|
||
|
|
||
|
bk_err_t bk_i2c_slave_write(i2c_id_t id, const uint8_t *data, uint32_t size, uint32_t timeout_ms)
|
||
|
{
|
||
|
I2C_RETURN_ON_NOT_INIT();
|
||
|
I2C_RETURN_ON_ID_NOT_INIT(id);
|
||
|
I2C_PM_CHECK_RESTORE(id);
|
||
|
BK_RETURN_ON_ERR(i2c_wait_sm_bus_idle(id, timeout_ms));
|
||
|
|
||
|
uint32_t int_level = rtos_enter_critical();
|
||
|
i2c_hal_set_write_int_mode(&s_i2c[id].hal, size);
|
||
|
s_i2c[id].work_mode = I2C_SLAVE_WRITE;
|
||
|
s_i2c[id].is_with_mem_addr = false;
|
||
|
s_i2c[id].data_ptr = (uint8_t *)data;
|
||
|
s_i2c[id].data_size = size;
|
||
|
s_i2c[id].data_offset = 0;
|
||
|
s_i2c[id].int_status = 0;
|
||
|
rtos_exit_critical(int_level);
|
||
|
|
||
|
rtos_get_semaphore(&s_i2c[id].tx_sema, timeout_ms);
|
||
|
//reset i2c to clear fifo
|
||
|
i2c_hal_stop_common(&s_i2c[id].hal);
|
||
|
i2c_hal_start_common(&s_i2c[id].hal);
|
||
|
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
bk_err_t bk_i2c_slave_read(i2c_id_t id, uint8_t *data, uint32_t size, uint32_t timeout_ms)
|
||
|
{
|
||
|
I2C_RETURN_ON_NOT_INIT();
|
||
|
I2C_RETURN_ON_ID_NOT_INIT(id);
|
||
|
I2C_PM_CHECK_RESTORE(id);
|
||
|
BK_RETURN_ON_ERR(i2c_wait_sm_bus_idle(id, timeout_ms));
|
||
|
|
||
|
uint32_t int_level = rtos_enter_critical();
|
||
|
i2c_hal_set_read_int_mode(&s_i2c[id].hal, size);
|
||
|
s_i2c[id].work_mode = I2C_SLAVE_READ;
|
||
|
s_i2c[id].is_with_mem_addr = false;
|
||
|
s_i2c[id].data_ptr = data;
|
||
|
s_i2c[id].data_size = size;
|
||
|
s_i2c[id].data_offset = 0;
|
||
|
s_i2c[id].int_status = 0;
|
||
|
rtos_exit_critical(int_level);
|
||
|
|
||
|
rtos_get_semaphore(&s_i2c[id].rx_sema, timeout_ms);
|
||
|
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
bk_err_t bk_i2c_memory_write(i2c_id_t id, const i2c_mem_param_t *mem_param)
|
||
|
{
|
||
|
I2C_RETURN_ON_NOT_INIT();
|
||
|
I2C_RETURN_ON_ID_NOT_INIT(id);
|
||
|
I2C_PM_CHECK_RESTORE(id);
|
||
|
BK_RETURN_ON_ERR(i2c_wait_sm_bus_idle(id, mem_param->timeout_ms));
|
||
|
|
||
|
uint32_t int_level = rtos_enter_critical();
|
||
|
s_i2c[id].err_code = BK_OK;
|
||
|
s_i2c[id].work_mode = I2C_MASTER_WRITE;
|
||
|
s_i2c[id].is_with_mem_addr = true;
|
||
|
s_i2c[id].dev_addr = mem_param->dev_addr;
|
||
|
s_i2c[id].mem_addr = mem_param->mem_addr;
|
||
|
s_i2c[id].mem_addr_size = mem_param->mem_addr_size;
|
||
|
s_i2c[id].data_ptr = mem_param->data;
|
||
|
s_i2c[id].data_size = mem_param->data_size;
|
||
|
s_i2c[id].data_offset = 0;
|
||
|
s_i2c[id].int_status = 0;
|
||
|
i2c_master_start(id);
|
||
|
i2c_master_set_write_dev_addr(id, mem_param->dev_addr);
|
||
|
i2c_hal_set_write_int_mode(&s_i2c[id].hal, mem_param->data_size);
|
||
|
rtos_exit_critical(int_level);
|
||
|
|
||
|
rtos_get_semaphore(&s_i2c[id].tx_sema, mem_param->timeout_ms);
|
||
|
|
||
|
return s_i2c[id].err_code;
|
||
|
}
|
||
|
|
||
|
bk_err_t bk_i2c_memory_read(i2c_id_t id, const i2c_mem_param_t *mem_param)
|
||
|
{
|
||
|
I2C_RETURN_ON_NOT_INIT();
|
||
|
I2C_RETURN_ON_ID_NOT_INIT(id);
|
||
|
I2C_PM_CHECK_RESTORE(id);
|
||
|
BK_RETURN_ON_ERR(i2c_wait_sm_bus_idle(id, mem_param->timeout_ms));
|
||
|
|
||
|
uint32_t int_level = rtos_enter_critical();
|
||
|
s_i2c[id].err_code = BK_OK;
|
||
|
s_i2c[id].work_mode = I2C_MASTER_READ;
|
||
|
s_i2c[id].is_with_mem_addr = true;
|
||
|
s_i2c[id].dev_addr = mem_param->dev_addr;
|
||
|
s_i2c[id].mem_addr = mem_param->mem_addr;
|
||
|
s_i2c[id].mem_addr_size = mem_param->mem_addr_size;
|
||
|
s_i2c[id].data_ptr = mem_param->data;
|
||
|
s_i2c[id].data_size = mem_param->data_size;
|
||
|
s_i2c[id].data_offset = 0;
|
||
|
s_i2c[id].int_status = 0;
|
||
|
i2c_master_start(id);
|
||
|
i2c_master_set_write_dev_addr(id, mem_param->dev_addr);
|
||
|
i2c_hal_set_read_int_mode(&s_i2c[id].hal, mem_param->data_size);
|
||
|
rtos_exit_critical(int_level);
|
||
|
|
||
|
rtos_get_semaphore(&s_i2c[id].rx_sema, mem_param->timeout_ms);
|
||
|
|
||
|
return s_i2c[id].err_code;
|
||
|
}
|
||
|
|
||
|
bk_err_t bk_i2c_set_baud_rate(i2c_id_t id, uint32_t baud_rate)
|
||
|
{
|
||
|
I2C_RETURN_ON_NOT_INIT();
|
||
|
I2C_RETURN_ON_ID_NOT_INIT(id);
|
||
|
I2C_PM_CHECK_RESTORE(id);
|
||
|
i2c_hal_set_baud_rate(&s_i2c[id].hal, baud_rate);
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
bk_err_t bk_i2c_set_slave_address(i2c_id_t id, uint16_t slave_addr)
|
||
|
{
|
||
|
I2C_RETURN_ON_NOT_INIT();
|
||
|
I2C_RETURN_ON_ID_NOT_INIT(id);
|
||
|
I2C_PM_CHECK_RESTORE(id);
|
||
|
i2c_hal_set_slave_addr(&s_i2c[id].hal, slave_addr);
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
bk_err_t bk_i2c_enable_interrupt(i2c_id_t id)
|
||
|
{
|
||
|
#if (CONFIG_SYSTEM_CTRL)
|
||
|
i2c_interrupt_enable(id);
|
||
|
#else
|
||
|
icu_enable_i2c_interrupt(id);
|
||
|
#endif
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
bk_err_t bk_i2c_disable_interrupt(i2c_id_t id)
|
||
|
{
|
||
|
#if (CONFIG_SYSTEM_CTRL)
|
||
|
i2c_interrupt_disable(id);
|
||
|
#else
|
||
|
icu_disable_i2c_interrupt(id);
|
||
|
#endif
|
||
|
return BK_OK;
|
||
|
}
|
||
|
|
||
|
bool bk_i2c_is_bus_busy(i2c_id_t id)
|
||
|
{
|
||
|
I2C_RETURN_ON_NOT_INIT();
|
||
|
I2C_RETURN_ON_ID_NOT_INIT(id);
|
||
|
I2C_PM_CHECK_RESTORE(id);
|
||
|
return i2c_hal_is_busy(&s_i2c[id].hal);
|
||
|
}
|
||
|
|
||
|
uint32_t bk_i2c_get_cur_action(i2c_id_t id)
|
||
|
{
|
||
|
return s_i2c[id].master_status;
|
||
|
}
|
||
|
|
||
|
static void i2c_master_isr_common(i2c_id_t id)
|
||
|
{
|
||
|
I2C_LOGD("s_i2c[id].master_status=%d\r\n", s_i2c[id].master_status);
|
||
|
switch (s_i2c[id].master_status) {
|
||
|
case I2C_START:
|
||
|
i2c_master_start(id);
|
||
|
break;
|
||
|
case I2C_TX_DEV_ADDR:
|
||
|
i2c_master_set_write_dev_addr(id, s_i2c[id].dev_addr);
|
||
|
break;
|
||
|
case I2C_RX_DEV_ADDR:
|
||
|
i2c_master_set_read_dev_addr(id, s_i2c[id].dev_addr);
|
||
|
break;
|
||
|
case I2C_TX_MEM_ADDR_HIGH_8BIT:
|
||
|
i2c_master_write_mem_addr_high_8bit(id, s_i2c[id].mem_addr);
|
||
|
break;
|
||
|
case I2C_TX_MEM_ADDR_LOW_8BIT:
|
||
|
i2c_master_write_mem_addr_low_8bit(id, s_i2c[id].mem_addr);
|
||
|
break;
|
||
|
case I2C_TX_DATA: {
|
||
|
if (id == I2C_ID_0) {
|
||
|
#if (CONFIG_FM_I2C)
|
||
|
i2c0_master_write_data(id);
|
||
|
#else
|
||
|
i2c1_master_write_data(id);
|
||
|
#endif
|
||
|
|
||
|
} else {
|
||
|
i2c1_master_write_data(id);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case I2C_RX_DATA: {
|
||
|
if (id == I2C_ID_0) {
|
||
|
#if (CONFIG_FM_I2C)
|
||
|
i2c0_master_read_data(id);
|
||
|
#else
|
||
|
i2c1_master_read_data(id);
|
||
|
#endif
|
||
|
} else {
|
||
|
i2c1_master_read_data(id);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case I2C_STOP:
|
||
|
i2c_master_stop(id);
|
||
|
break;
|
||
|
default:
|
||
|
s_i2c[id].master_status = I2C_IDLE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if CONFIG_FM_I2C
|
||
|
static void i2c0_isr_common(i2c_id_t id)
|
||
|
{
|
||
|
i2c_hal_t *hal = &s_i2c[id].hal;
|
||
|
uint32_t int_status = 0;
|
||
|
|
||
|
int_status = i2c_hal_get_interrupt_status(hal);
|
||
|
I2C_LOGD("isr_i2c0_config:0x%x\r\n", int_status);
|
||
|
if(!i2c_hal_is_sm_int_triggered(hal, int_status)) {
|
||
|
I2C_LOGW("sm bus int not triggered\r\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
switch (s_i2c[id].work_mode) {
|
||
|
case I2C_MASTER_WRITE: {
|
||
|
if (!i2c_hal_is_rx_ack_triggered(hal, int_status)) {
|
||
|
I2C_LOGW("i2c(%d) master_write get ack failed\r\n", id);
|
||
|
i2c_transtate_set(id);
|
||
|
i2c_master_stop(id);
|
||
|
rtos_set_semaphore(&s_i2c[id].tx_sema);
|
||
|
break;
|
||
|
}
|
||
|
i2c_master_isr_common(id);
|
||
|
break;
|
||
|
}
|
||
|
case I2C_MASTER_READ: {
|
||
|
if (s_i2c[id].master_status != I2C_RX_DATA &&
|
||
|
!i2c_hal_is_rx_ack_triggered(hal, int_status)) {
|
||
|
I2C_LOGW("i2c(%d) master_read get ack failed\r\n", id);
|
||
|
i2c_transtate_set(id);
|
||
|
i2c_master_stop(id);
|
||
|
rtos_set_semaphore(&s_i2c[id].rx_sema);
|
||
|
break;
|
||
|
}
|
||
|
if (i2c_hal_is_start_triggered(hal, int_status) &&
|
||
|
!i2c_hal_is_rx_ack_triggered(hal, int_status)) {
|
||
|
I2C_LOGW("i2c_read get ack failed\r\n");
|
||
|
i2c_transtate_set(id);
|
||
|
i2c_master_stop(id);
|
||
|
rtos_set_semaphore(&s_i2c[id].rx_sema);
|
||
|
break;
|
||
|
}
|
||
|
i2c_master_isr_common(id);
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
/* must clear SI at last,otherwise slave_addr will be sent twice */
|
||
|
i2c_hal_clear_interrupt_status(hal, int_status);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void i2c1_isr_common(i2c_id_t id)
|
||
|
{
|
||
|
i2c_hal_t *hal = &s_i2c[id].hal;
|
||
|
uint32_t int_status = s_i2c[id].int_status;
|
||
|
uint32_t data_num = 0;
|
||
|
uint32_t remain_size = 0;
|
||
|
|
||
|
int_status = i2c_hal_get_interrupt_status(hal);
|
||
|
s_i2c[id].int_status = int_status;
|
||
|
I2C_LOGD("isr_i2c1_status:%x\r\n", int_status);
|
||
|
|
||
|
if(!i2c_hal_is_sm_int_triggered(hal, int_status)) {
|
||
|
if (i2c_hal_is_scl_timeout_triggered(hal, int_status)) {
|
||
|
I2C_LOGW("SCL timeout triggered, restart i2c\r\n");
|
||
|
s_i2c[id].master_status = I2C_IDLE;
|
||
|
/* i2c must close->open when SCL low timeout triggered */
|
||
|
i2c_hal_disable_scl_timeout(hal); //disable scl_timeout interrupt to aviod error log too much
|
||
|
i2c_hal_disable(hal);
|
||
|
i2c_hal_enable(hal);
|
||
|
s_i2c[id].err_code = BK_ERR_I2C_SCL_TIMEOUT;
|
||
|
if (s_i2c[id].work_mode == I2C_MASTER_WRITE) {
|
||
|
rtos_set_semaphore(&s_i2c[id].tx_sema);
|
||
|
} else if (s_i2c[id].work_mode == I2C_MASTER_READ) {
|
||
|
rtos_set_semaphore(&s_i2c[id].rx_sema);
|
||
|
}
|
||
|
}
|
||
|
if (i2c_hal_is_arb_lost_triggered(hal, int_status)) {
|
||
|
I2C_LOGW("arb lost int triggered\r\n");
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
switch (s_i2c[id].work_mode) {
|
||
|
case I2C_MASTER_WRITE: {
|
||
|
s_i2c[id].int_status &= ~I2C1_F_START;
|
||
|
/* send stop if not receive ack */
|
||
|
if (!i2c_hal_is_rx_ack_triggered(hal, int_status)) {
|
||
|
I2C_LOGW("i2c(%d) master_write get ack failed\r\n", id);
|
||
|
i2c_transtate_set(id);
|
||
|
i2c_master_stop(id);
|
||
|
s_i2c[id].err_code = BK_ERR_I2C_ACK_TIMEOUT;
|
||
|
rtos_set_semaphore(&s_i2c[id].tx_sema);
|
||
|
break;
|
||
|
}
|
||
|
i2c_master_isr_common(id);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case I2C_MASTER_READ: {
|
||
|
s_i2c[id].int_status &= ~I2C1_F_START;
|
||
|
if (i2c_hal_is_start_triggered(hal, int_status) &&
|
||
|
!i2c_hal_is_rx_ack_triggered(hal, int_status)) {
|
||
|
I2C_LOGW("i2c(%d) master_read get ack failed\r\n", id);
|
||
|
s_i2c[id].master_status = I2C_IDLE;
|
||
|
s_i2c[id].int_status |= I2C1_F_STOP;
|
||
|
s_i2c[id].err_code = BK_ERR_I2C_ACK_TIMEOUT;
|
||
|
rtos_set_semaphore(&s_i2c[id].rx_sema);
|
||
|
break;
|
||
|
}
|
||
|
i2c_master_isr_common(id);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case I2C_SLAVE_WRITE:
|
||
|
if (i2c_hal_is_stop_triggered(hal, int_status) || i2c_hal_is_rx_mode(hal)) {
|
||
|
I2C_LOGI("i2c(%d) slave_write get stopped\r\n", id);
|
||
|
rtos_set_semaphore(&s_i2c[id].tx_sema);
|
||
|
break;
|
||
|
}
|
||
|
if (i2c_hal_is_addr_matched(hal)) {
|
||
|
s_i2c[id].int_status |= I2C1_F_ACK;
|
||
|
}
|
||
|
|
||
|
i2c_hal_write_byte(hal, s_i2c[id].data_ptr[(s_i2c[id].data_offset)++]);
|
||
|
if (s_i2c[id].data_offset == s_i2c[id].data_size) {
|
||
|
I2C_LOGD("i2c(%d) slave_write data_offset==data_size\r\n", id);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case I2C_SLAVE_READ:
|
||
|
if (i2c_hal_is_stop_triggered(hal, int_status)) {
|
||
|
I2C_LOGI("i2c(%d) slave_read get stopped\r\n", id);
|
||
|
rtos_set_semaphore(&s_i2c[id].rx_sema);
|
||
|
break;
|
||
|
}
|
||
|
if (i2c_hal_is_addr_matched(hal)) {
|
||
|
s_i2c[id].int_status |= I2C1_F_ACK;
|
||
|
break;
|
||
|
}
|
||
|
remain_size = s_i2c[id].data_size - s_i2c[id].data_offset;
|
||
|
data_num = i2c_hal_get_read_fifo_num(hal);
|
||
|
for (uint32_t i = 0; i < data_num; i++) {
|
||
|
s_i2c[id].data_ptr[(s_i2c[id].data_offset)++] = i2c_hal_read_byte(hal);
|
||
|
remain_size--;
|
||
|
if (!remain_size) { /* avoid index is out of array range */
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!remain_size) {
|
||
|
s_i2c[id].int_status |= I2C1_F_ACK;
|
||
|
} else if (remain_size < data_num) {
|
||
|
s_i2c[id].int_status |= (I2C1_F_ACK | I2C1_F_INT_MODE_V);
|
||
|
} else {
|
||
|
s_i2c[id].int_status |= I2C1_F_ACK;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
/* int_status sm_int/ack/start/stop/int_mode must operate together, otherwise will not work
|
||
|
* e.g.
|
||
|
* i2c_hal_enable_ack(); // only set bit of ack(bit[8]), no ack will be sent
|
||
|
*/
|
||
|
i2c_hal_clear_interrupt_status(hal, s_i2c[id].int_status);
|
||
|
}
|
||
|
|
||
|
static void i2c0_isr(void)
|
||
|
{
|
||
|
I2C_LOGD("enter i2c0_isr\r\n");
|
||
|
#if CONFIG_FM_I2C
|
||
|
i2c0_isr_common(I2C_ID_0);
|
||
|
#else
|
||
|
i2c1_isr_common(I2C_ID_0);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#if (SOC_I2C_UNIT_NUM > 1)
|
||
|
static void i2c1_isr(void)
|
||
|
{
|
||
|
I2C_LOGD("enter i2c1_isr\r\n");
|
||
|
i2c1_isr_common(I2C_ID_1);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (SOC_I2C_UNIT_NUM > 2)
|
||
|
static void i2c2_isr(void)
|
||
|
{
|
||
|
I2C_LOGD("enter i2c2_isr\r\n");
|
||
|
i2c1_isr_common(I2C_ID_2);
|
||
|
}
|
||
|
#endif
|
||
|
|