/**************************************************************************** * * 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; }