Files
kunlun/driver/src/hw3/i2c_hw.c
2024-09-28 14:24:04 +08:00

512 lines
13 KiB
C
Executable File

/****************************************************************************
*
* Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
*
* This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
* be copied by any method or incorporated into another program without
* the express written consent of Aerospace C.Power. This Information or any portion
* thereof remains the property of Aerospace C.Power. The Information contained herein
* is believed to be accurate and Aerospace C.Power assumes no responsibility or
* liability for its use in any way and conveys no license or title under
* any patent or copyright and makes no representation or warranty that this
* Information is free from patent or copyright infringement.
*
* ****************************************************************************/
#include "os_types.h"
#include "iot_errno.h"
#include "apb_glb_reg.h"
#include "hw_reg_api.h"
#include "iot_io.h"
#include "iot_i2c_api.h"
#include "gpio_mtx.h"
#include "i2c_reg.h"
#include "i2c_hw.h"
#include "apb.h"
#include "iot_irq.h"
static const IOT_INTR_VECTOR g_i2c_vector_table[] = {
HAL_VECTOR_IIC_M0, HAL_VECTOR_IIC_M1, HAL_VECTOR_IIC_M2, HAL_VECTOR_IIC_M3};
i2c_isr g_isr[I2C_PORT_NUM] = {NULL, NULL, NULL, NULL};
uint8_t i2c_gpio_sel(uint8_t port, uint8_t scl, uint8_t sda)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
gpio_mtx_enable();
uint8_t scl_func = 0;
uint8_t sda_func = 0;
scl_func = gpio_pin_func_get(scl);
sda_func = gpio_pin_func_get(sda);
gpio_sig_info_t info = {0};
if (port == IOT_I2C_PORT_0) {
info.sig_type = 2;
info.CFG[0].type = IO_TYPE_OUT;
info.CFG[0].func = scl_func;
info.CFG[0].gpio = scl;
info.CFG[0].inid = 0xff;
info.CFG[0].outid = GPIO_MTX_I2C0_SCL_OUT;
info.CFG[1].type = IO_TYPE_IO;
info.CFG[1].func = sda_func;
info.CFG[1].gpio = sda;
info.CFG[1].inid = GPIO_MTX_I2C0_SDA_IN;
info.CFG[1].outid = GPIO_MTX_I2C0_SDA_OUT;
} else if (port == IOT_I2C_PORT_1){
info.sig_type = 2;
info.CFG[0].type = IO_TYPE_OUT;
info.CFG[0].func = scl_func;
info.CFG[0].gpio = scl;
info.CFG[0].inid = 0xff;
info.CFG[0].outid = GPIO_MTX_I2C1_SCL_OUT;
info.CFG[1].type = IO_TYPE_IO;
info.CFG[1].func = sda_func;
info.CFG[1].gpio = sda;
info.CFG[1].inid = GPIO_MTX_I2C1_SDA_IN;
info.CFG[1].outid = GPIO_MTX_I2C1_SDA_OUT;
} else if (port == IOT_I2C_PORT_2) {
info.sig_type = 2;
info.CFG[0].type = IO_TYPE_OUT;
info.CFG[0].func = scl_func;
info.CFG[0].gpio = scl;
info.CFG[0].inid = 0xff;
info.CFG[0].outid = GPIO_MTX_I2C2_SCL_OUT;
info.CFG[1].type = IO_TYPE_IO;
info.CFG[1].func = sda_func;
info.CFG[1].gpio = sda;
info.CFG[1].inid = GPIO_MTX_I2C2_SDA_IN;
info.CFG[1].outid = GPIO_MTX_I2C2_SDA_OUT;
}else if (port == IOT_I2C_PORT_3) {
info.sig_type = 2;
info.CFG[0].type = IO_TYPE_OUT;
info.CFG[0].func = scl_func;
info.CFG[0].gpio = scl;
info.CFG[0].inid = 0xff;
info.CFG[0].outid = GPIO_MTX_I2C3_SCL_OUT;
info.CFG[1].type = IO_TYPE_IO;
info.CFG[1].func = sda_func;
info.CFG[1].gpio = sda;
info.CFG[1].inid = GPIO_MTX_I2C3_SDA_IN;
info.CFG[1].outid = GPIO_MTX_I2C3_SDA_OUT;
}
gpio_module_pin_select(&info);
gpio_module_sig_select(&info, GPIO_MTX_MODE_MATRIX);
return ERR_OK;
}
uint8_t i2c_port_enable(uint8_t port)
{
if (port == IOT_I2C_PORT_0) {
apb_enable(APB_I2CM0);
} else if (port == IOT_I2C_PORT_1) {
apb_enable(APB_I2CM1);
} else if (port == IOT_I2C_PORT_2) {
apb_enable(APB_I2CM2);
} else if (port == IOT_I2C_PORT_3) {
apb_enable(APB_I2CM3);
} else {
return ERR_FAIL;
}
return ERR_OK;
}
uint8_t i2c_txfifo_full(uint8_t port)
{
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_STATUS_ADDR);
return REG_FIELD_GET(TX_FIFO_FULL, tmp);
}
uint8_t i2c_txfifo_empty(uint8_t port)
{
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_STATUS_ADDR);
return REG_FIELD_GET(TX_FIFO_EMPTY, tmp);
}
uint8_t i2c_rxfifo_full(uint8_t port)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_STATUS_ADDR);
return REG_FIELD_GET(RX_FIFO_FULL, tmp);
}
uint8_t i2c_rxfifo_empty(uint8_t port)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_STATUS_ADDR);
return REG_FIELD_GET(RX_FIFO_EMPTY, tmp);
}
uint8_t i2c_send_num_set(uint8_t port, uint8_t num)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_DATA_NUM_CONF_ADDR);
REG_FIELD_SET(SEND_NUM, tmp, num);
I2C_PORT_WRITE_REG(port, CFG_DATA_NUM_CONF_ADDR, tmp);
return ERR_OK;
}
uint8_t i2c_receive_num_set(uint8_t port, uint8_t num)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_DATA_NUM_CONF_ADDR);
REG_FIELD_SET(REC_NUM, tmp, num);
I2C_PORT_WRITE_REG(port, CFG_DATA_NUM_CONF_ADDR, tmp);
return ERR_OK;
}
uint8_t i2c_mode_set(uint8_t port, uint8_t mode)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_MODE_ADDR);
REG_FIELD_SET(I2C_BUSRT_MODE, tmp, mode);
I2C_PORT_WRITE_REG(port, CFG_I2C_MODE_ADDR, tmp);
return ERR_OK;
}
uint8_t i2c_data_dir_mode(uint8_t port, uint8_t dir)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
if (dir != IOT_I2C_DIRC_RD && dir != IOT_I2C_DIRC_WR) {
return ERR_FAIL;
}
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_MODE_ADDR);
if (dir == IOT_I2C_DIRC_RD) {
REG_FIELD_SET(IIC_RD, tmp, 1);
REG_FIELD_SET(IIC_WR, tmp, 0);
} else {
REG_FIELD_SET(IIC_RD, tmp, 0);
REG_FIELD_SET(IIC_WR, tmp, 1);
}
I2C_PORT_WRITE_REG(port, CFG_I2C_MODE_ADDR, tmp);
return ERR_OK;
}
uint8_t i2c_stop(uint8_t port)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_MODE_ADDR);
REG_FIELD_SET(I2C_TRANS_STOP, tmp, 1);
I2C_PORT_WRITE_REG(port, CFG_I2C_MODE_ADDR, tmp);
return ERR_OK;
}
uint8_t i2c_start(uint8_t port)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_START_ADDR);
REG_FIELD_SET(I2C_START, tmp, 1);
I2C_PORT_WRITE_REG(port, CFG_START_ADDR, tmp);
return ERR_OK;
}
//todo
uint8_t i2c_clear_int_status(uint8_t port, uint32_t mask)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
uint32_t tmp = 0;
tmp |= mask;
I2C_PORT_WRITE_REG(port, CFG_CLR_INT_ADDR, tmp);
return ERR_OK;
}
//todo
uint8_t i2c_clear_master_int_flag(uint8_t port, uint32_t mask)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
uint32_t tmp = 0;
tmp |= mask;
I2C_PORT_WRITE_REG(port, CFG_I2C_MASTER_INT_CLR_ADDR, tmp);
return ERR_OK;
}
uint8_t i2c_clear_int(uint8_t port, uint32_t mask)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
uint32_t tmp = 0;
tmp |= mask;
I2C_PORT_WRITE_REG(port, CFG_CLR_INT_ADDR, tmp);
return ERR_OK;
}
uint8_t i2c_enable_int(uint8_t port, uint32_t mask)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_MASTER_INT_ENA_ADDR);
tmp |= mask;
I2C_PORT_WRITE_REG(port, CFG_I2C_MASTER_INT_ENA_ADDR, tmp);
return ERR_OK;
}
uint8_t i2c_disable_int(uint8_t port, uint32_t mask)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_MASTER_INT_ENA_ADDR);
tmp &= ~mask;
I2C_PORT_WRITE_REG(port, CFG_I2C_MASTER_INT_ENA_ADDR, tmp);
return ERR_OK;
}
//todo
uint8_t i2c_get_int_status(uint8_t port, uint8_t bit)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
return (REG_BIT_GET(port, CFG_I2C_STATUS_ADDR, bit));
}
uint8_t i2c_set_baudrate(uint8_t port, uint32_t baud)
{
uint32_t temp;
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
temp = I2C_INPUT_CLK_KHZ / baud - 1;// i2c clk 25Mhz
if (temp > (CLK_DIV_MASK >> CLK_DIV_OFFSET)) {
temp = CLK_DIV_OFFSET - 1;
}
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_CLOCK_DIV_ADDR);
REG_FIELD_SET(CLK_DIV, tmp, temp);
I2C_PORT_WRITE_REG(port, CFG_CLOCK_DIV_ADDR, tmp);
return ERR_OK;
}
uint8_t i2c_set_nack_wait_num(uint8_t port, uint32_t num)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_WAIT_NACK_MAX_ADDR);
REG_FIELD_SET(WAIT_NACK_MAX, tmp, num);
I2C_PORT_WRITE_REG(port, CFG_WAIT_NACK_MAX_ADDR, tmp);
return ERR_OK;
}
uint8_t i2c_tx_fifo_write(uint8_t port, uint8_t data)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
i2c_data_dir_mode(port, IOT_I2C_DIRC_WR);
uint32_t cnt = 0;
while(1) {
uint8_t ret = i2c_txfifo_full(port);
if (ret) {
break;
} else {
cnt++;
if (cnt >= 1000000) {
iot_printf("i2c_tx_fifo_write timeout.\n");
return ERR_BUSY;
}
}
}
I2C_REG(port, CFG_I2C_TX_FIFO_WDATA_ADDR) = data;
return ERR_OK;
}
uint8_t i2c_tx_fifo_thrs(uint8_t port, uint8_t thrs)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_MASTER_FIFO_CFG_ADDR);
REG_FIELD_SET(I2C_TXFIFO_THRS, tmp, thrs);
I2C_PORT_WRITE_REG(port, CFG_I2C_MASTER_FIFO_CFG_ADDR, tmp);
return ERR_OK;
}
uint8_t i2c_rx_fifo_thrs(uint8_t port, uint8_t thrs)
{
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_MASTER_FIFO_CFG_ADDR);
REG_FIELD_SET(I2C_RXFIFO_THRS, tmp, thrs);
I2C_PORT_WRITE_REG(port, CFG_I2C_MASTER_FIFO_CFG_ADDR, tmp);
return ERR_OK;
}
static uint32_t IRAM_ATTR i2c_interupt_handler(uint32_t vector, iot_addrword_t data)
{
uint32_t status = 0;
uint32_t mask = 0;
int port = 0;
/*vector map to port*/
if (HAL_VECTOR_IIC_M0 == vector) {
port = IOT_I2C_PORT_0;
} else if (HAL_VECTOR_IIC_M1 == vector) {
port = IOT_I2C_PORT_1;
} else if (HAL_VECTOR_IIC_M2 == vector) {
port = IOT_I2C_PORT_2;
} else if (HAL_VECTOR_IIC_M3 == vector) {
port = IOT_I2C_PORT_3;
} else {
return 0;
}
status = I2C_PORT_READ_REG(port, CFG_I2C_MASTER_INT_ST_ADDR);
if (status & I2C_M_NACK_INT_ST_MASK) {
mask |= I2C_NACK_TIMEOUT;
}
if (status & I2C_M_TX_EMP_INT_ST_MASK) {
mask |= I2C_FIFO_EMPTY;
}
if (status & I2C_M_RX_FULL_INT_ST_MASK) {
mask |= I2C_FIFO_FULL;
}
if (status & I2C_M_TX_UNDERFLOW_INT_ST_MASK) {
mask |= I2C_FIFO_UNDER;
}
if (status & I2C_M_RX_OVERFLOW_INT_ST_MASK) {
mask |= I2C_FIFO_OVER;
}
if (status & I2C_M_DONE_INT_ST_MASK) {
mask |= I2C_TRANS_DOWN;
}
/*call isr*/
if (NULL != g_isr[port]) {
g_isr[port](port, mask);
}
//---------------------------------------------
/*clear all int*/
i2c_clear_master_int_flag(port, I2C_M_NACK_INT_CLR_MASK
| I2C_M_TX_EMP_INT_CLR_MASK
| I2C_M_RX_FULL_INT_CLR_MASK
| I2C_M_TX_UNDERFLOW_INT_CLR_MASK
| I2C_M_RX_OVERFLOW_INT_CLR_MASK
| I2C_M_DONE_INT_CLR_MASK
);
return 0;
}
uint8_t i2c_interrupt_init(uint8_t port, uint32_t mask, i2c_isr isr)
{
uint32_t i2c_mask = 0;
if (I2C_INVALID(port)) {
return ERR_FAIL;
}
/* clr i2c int */
i2c_clear_int(port, I2C_INT_CLR_MASK | NACK_INT_CLR_MASK
| I2C_RXFIFO_CLR_MASK | I2C_TXFIFO_CLR_MASK);
i2c_clear_master_int_flag(port, I2C_M_NACK_INT_CLR_MASK
| I2C_M_TX_EMP_INT_CLR_MASK
| I2C_M_RX_FULL_INT_CLR_MASK
| I2C_M_TX_UNDERFLOW_INT_CLR_MASK
| I2C_M_RX_OVERFLOW_INT_CLR_MASK
| I2C_M_DONE_INT_CLR_MASK
);
/* inner int enable */
if (mask & I2C_NACK_TIMEOUT) {
i2c_mask |= I2C_M_NACK_INT_ENA_MASK;
}
if (mask & I2C_FIFO_EMPTY) {
i2c_mask |= I2C_M_TX_EMP_INT_ENA_MASK;
}
if (mask & I2C_FIFO_FULL) {
i2c_mask |= I2C_M_RX_FULL_INT_ENA_MASK;
}
if (mask & I2C_FIFO_UNDER) {
i2c_mask |= I2C_M_TX_UNDERFLOW_INT_ENA_MASK;
}
if (mask & I2C_FIFO_OVER) {
i2c_mask |= I2C_M_RX_OVERFLOW_INT_ENA_MASK;
}
if (mask & I2C_TRANS_DOWN) {
i2c_mask |= I2C_M_DONE_INT_ENA_MASK;
}
i2c_enable_int(port, i2c_mask);
g_isr[port] = isr;
/* interrupt controller */
iot_irq_t irq_handle = iot_interrupt_create(g_i2c_vector_table[port],
HAL_INTR_PRI_0, 0, i2c_interupt_handler);
iot_interrupt_attach(irq_handle);
iot_interrupt_unmask(irq_handle);
return 0;
}