|  | /* | 
|  | * Copyright (c) 2022 Andes Technology Corporation | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | /** | 
|  | * @file I2C driver for AndesTech atciic100 IP | 
|  | */ | 
|  |  | 
|  | #include <string.h> | 
|  | #include <zephyr/drivers/i2c.h> | 
|  | #include <zephyr/irq.h> | 
|  | #include "i2c_andes_atciic100.h" | 
|  |  | 
|  | #define DT_DRV_COMPAT andestech_atciic100 | 
|  |  | 
|  | typedef void (*atciic100_dt_init_func_t)(void); | 
|  |  | 
|  | struct i2c_atciic100_config { | 
|  | uint32_t			base; | 
|  | uint32_t			irq_num; | 
|  | atciic100_dt_init_func_t	dt_init_fn; | 
|  | }; | 
|  |  | 
|  | static int i2c_atciic100_controller_send(const struct device *dev, | 
|  | uint16_t addr, const uint8_t *data, uint32_t num, uint8_t flags); | 
|  | static int i2c_atciic100_controller_receive(const struct device *dev, | 
|  | uint16_t addr, uint8_t *data, uint32_t num, uint8_t flags); | 
|  | static void i2c_controller_fifo_write(const struct device *dev, | 
|  | uint8_t is_init); | 
|  | static void i2c_controller_fifo_read(const struct device *dev); | 
|  | static int i2c_atciic100_init(const struct device *dev); | 
|  |  | 
|  | #if defined(CONFIG_I2C_TARGET) | 
|  | static void i2c_atciic100_target_send(const struct device *dev, | 
|  | const uint8_t *data); | 
|  | static void i2c_atciic100_target_receive(const struct device *dev, | 
|  | uint8_t *data); | 
|  | #endif | 
|  |  | 
|  | static void i2c_atciic100_default_control(const struct device *dev) | 
|  | { | 
|  | struct i2c_atciic100_dev_data_t *dev_data = dev->data; | 
|  | uint32_t reg = 0; | 
|  |  | 
|  | k_sem_init(&dev_data->bus_lock, 1, 1); | 
|  | k_sem_init(&dev_data->device_sync_sem, 0, 1); | 
|  |  | 
|  | /* Reset I2C bus */ | 
|  | reg = sys_read32(I2C_CMD(dev)); | 
|  | reg &= (~CMD_MSK); | 
|  | reg |= (CMD_RESET_I2C); | 
|  | sys_write32(reg, I2C_CMD(dev)); | 
|  |  | 
|  | /* I2C query FIFO depth */ | 
|  | reg = sys_read32(I2C_CFG(dev)); | 
|  | switch (reg & 0x3) { | 
|  | case 0x0: | 
|  | dev_data->fifo_depth = 2; | 
|  | break; | 
|  | case 0x1: | 
|  | dev_data->fifo_depth = 4; | 
|  | break; | 
|  | case 0x2: | 
|  | dev_data->fifo_depth = 8; | 
|  | break; | 
|  | case 0x3: | 
|  | dev_data->fifo_depth = 16; | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * I2C setting: target mode(default), standard speed | 
|  | * 7-bit, CPU mode | 
|  | */ | 
|  | sys_write32(0x0, I2C_SET(dev)); | 
|  | reg = sys_read32(I2C_SET(dev)); | 
|  | reg |= ((SETUP_T_SUDAT_STD << 24)	| | 
|  | (SETUP_T_SP_STD  << 21)		| | 
|  | (SETUP_T_HDDAT_STD << 16)	| | 
|  | (SETUP_T_SCL_RATIO_STD << 13)	| | 
|  | (SETUP_T_SCLHI_STD << 4)	| | 
|  | SETUP_I2C_EN); | 
|  |  | 
|  | sys_write32(reg, I2C_SET(dev)); | 
|  |  | 
|  | dev_data->driver_state = I2C_DRV_INIT; | 
|  | dev_data->status.mode = 0; | 
|  | dev_data->status.arbitration_lost = 0; | 
|  | dev_data->status.target_ack = 0; | 
|  | } | 
|  |  | 
|  | static int i2c_atciic100_configure(const struct device *dev, | 
|  | uint32_t dev_config) | 
|  | { | 
|  | struct i2c_atciic100_dev_data_t *dev_data = dev->data; | 
|  | uint32_t reg = 0; | 
|  | int ret = 0; | 
|  |  | 
|  | reg = sys_read32(I2C_SET(dev)); | 
|  |  | 
|  | switch (I2C_SPEED_GET(dev_config)) { | 
|  | case I2C_SPEED_STANDARD: | 
|  | reg |= SETUP_SPEED_STD; | 
|  | break; | 
|  |  | 
|  | case I2C_SPEED_FAST: | 
|  | reg |= SETUP_SPEED_FAST; | 
|  | break; | 
|  |  | 
|  | case I2C_SPEED_FAST_PLUS: | 
|  | reg |= SETUP_SPEED_FAST_PLUS; | 
|  |  | 
|  | case I2C_SPEED_HIGH: | 
|  | ret = -EIO; | 
|  | goto unlock; | 
|  | case 0x00: | 
|  | break; | 
|  | default: | 
|  | ret = -EIO; | 
|  | goto unlock; | 
|  | } | 
|  |  | 
|  | if (dev_config & I2C_MODE_CONTROLLER) { | 
|  | reg |= SETUP_CONTROLLER; | 
|  | dev_data->status.mode = 1; | 
|  | } else { | 
|  | reg &= ~SETUP_CONTROLLER; | 
|  | dev_data->status.mode = 0; | 
|  | } | 
|  |  | 
|  | if (dev_config & I2C_ADDR_10_BITS) { | 
|  | reg |= SETUP_ADDRESSING; | 
|  | } else { | 
|  | reg &= ~SETUP_ADDRESSING; | 
|  | } | 
|  |  | 
|  | sys_write32(reg, I2C_SET(dev)); | 
|  |  | 
|  | dev_data->driver_state |= I2C_DRV_CFG_PARAM; | 
|  |  | 
|  | unlock: | 
|  | k_sem_give(&dev_data->bus_lock); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int i2c_atciic100_transfer(const struct device *dev, | 
|  | struct i2c_msg *msgs, uint8_t num_msgs, uint16_t addr) | 
|  | { | 
|  | struct i2c_atciic100_dev_data_t *dev_data = dev->data; | 
|  | int ret = 0; | 
|  | int count = 0; | 
|  | uint8_t burst_write_len = msgs[0].len + msgs[1].len; | 
|  | uint8_t burst_write_buf[I2C_MAX_COUNT + BURST_CMD_COUNT]; | 
|  |  | 
|  | k_sem_take(&dev_data->bus_lock, K_FOREVER); | 
|  |  | 
|  | if ((msgs[0].flags == I2C_MSG_WRITE) | 
|  | && (msgs[1].flags == (I2C_MSG_WRITE | I2C_MSG_STOP))) { | 
|  |  | 
|  | burst_write_len = msgs[0].len + msgs[1].len; | 
|  | if (burst_write_len > MAX_XFER_SZ) { | 
|  | return -EIO; | 
|  | } | 
|  | for (count = 0; count < burst_write_len; count++) { | 
|  | if (count < msgs[0].len) { | 
|  | burst_write_buf[count] = msgs[0].buf[count]; | 
|  | } else { | 
|  | burst_write_buf[count] = | 
|  | msgs[1].buf[count - msgs[0].len]; | 
|  | } | 
|  | } | 
|  | ret = i2c_atciic100_controller_send(dev, addr, burst_write_buf, | 
|  | burst_write_len, true); | 
|  | goto exit; | 
|  | } | 
|  |  | 
|  | for (uint8_t i = 0; i < num_msgs; i++) { | 
|  | if ((msgs[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) { | 
|  | ret = i2c_atciic100_controller_send(dev, | 
|  | addr, msgs[i].buf, msgs[i].len, msgs[i].flags); | 
|  | } else { | 
|  | ret = i2c_atciic100_controller_receive(dev, | 
|  | addr, msgs[i].buf, msgs[i].len, msgs[i].flags); | 
|  | } | 
|  |  | 
|  | if (ret < 0) { | 
|  | goto exit; | 
|  | } | 
|  | } | 
|  |  | 
|  | exit: | 
|  | /* Wait for transfer complete */ | 
|  | k_sem_give(&dev_data->bus_lock); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  |  | 
|  | static int i2c_atciic100_controller_send(const struct device *dev, | 
|  | uint16_t addr, const uint8_t *data, uint32_t num, uint8_t flags) | 
|  | { | 
|  | struct i2c_atciic100_dev_data_t *dev_data = dev->data; | 
|  | uint32_t reg = 0; | 
|  |  | 
|  | /* | 
|  | * Max to 10-bit address. | 
|  | * Parameters data = null or num = 0 means no payload for | 
|  | * acknowledge polling. If no I2C payload, set Phase_data=0x0. | 
|  | */ | 
|  | if (addr > 0x3FF) { | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | /* Disable all I2C interrupts */ | 
|  | reg = sys_read32(I2C_INTE(dev)); | 
|  | reg &= (~IEN_ALL); | 
|  | sys_write32(reg, I2C_INTE(dev)); | 
|  |  | 
|  | dev_data->status.mode = 1; | 
|  | reg = sys_read32(I2C_SET(dev)); | 
|  | reg |= SETUP_CONTROLLER; | 
|  | sys_write32(reg, I2C_SET(dev)); | 
|  |  | 
|  | /* Direction => tx:0, rx:1 */ | 
|  | dev_data->status.arbitration_lost = 0; | 
|  | dev_data->status.target_ack = 0; | 
|  | dev_data->driver_state = I2C_DRV_CONTROLLER_TX; | 
|  |  | 
|  | /* Step1, Clear FIFO */ | 
|  | reg = sys_read32(I2C_CMD(dev)); | 
|  | reg &= (~CMD_MSK); | 
|  | reg |= (CMD_CLEAR_FIFO); | 
|  | sys_write32(reg, I2C_CMD(dev)); | 
|  |  | 
|  | /* | 
|  | * Step2 | 
|  | * Enable START, ADDRESS, DATA and STOP phase. | 
|  | * If no payload, clear DATA phase. | 
|  | * STOP condition triggered when transmission finish in controller mode. | 
|  | * The bus is busy until STOP condition triggered. | 
|  | * For 10-bit target address, we must set STOP bit. | 
|  | * I2C direction : controller tx, set xfer DATA count. | 
|  | */ | 
|  | reg = sys_read32(I2C_CTRL(dev)); | 
|  | reg &= (~(CTRL_PHASE_START | CTRL_PHASE_ADDR | CTRL_PHASE_STOP | | 
|  | CTRL_DIR | CTRL_DATA_COUNT)); | 
|  |  | 
|  | if (flags & I2C_MSG_STOP) { | 
|  | reg |= CTRL_PHASE_STOP; | 
|  | } | 
|  | if ((flags & I2C_MSG_RESTART) == 0) { | 
|  | reg |= (CTRL_PHASE_START | CTRL_PHASE_ADDR); | 
|  | } | 
|  | if (num) { | 
|  | reg |= (CTRL_PHASE_DATA | (num & CTRL_DATA_COUNT)); | 
|  | } | 
|  |  | 
|  | sys_write32(reg, I2C_CTRL(dev)); | 
|  |  | 
|  | /* Step3 init I2C info */ | 
|  | dev_data->target_addr = addr; | 
|  | dev_data->xfered_data_wt_ptr = 0; | 
|  | dev_data->xfer_wt_num = num; | 
|  | dev_data->middleware_tx_buf = (uint8_t *)data; | 
|  |  | 
|  | /* In I2C target address, general call address = 0x0(7-bit or 10-bit) */ | 
|  | reg = sys_read32(I2C_ADDR(dev)); | 
|  | reg &= (~TARGET_ADDR_MSK); | 
|  | reg |= (dev_data->target_addr & (TARGET_ADDR_MSK)); | 
|  | sys_write32(reg, I2C_ADDR(dev)); | 
|  |  | 
|  | /* | 
|  | * Step4 Enable Interrupts: Complete, Arbitration Lose | 
|  | * Enable/Disable the FIFO Empty Interrupt | 
|  | * Fill the FIFO before enabling FIFO Empty Interrupt | 
|  | */ | 
|  | reg = sys_read32(I2C_INTE(dev)); | 
|  |  | 
|  | i2c_controller_fifo_write(dev, 1); | 
|  |  | 
|  | reg |= (IEN_CMPL | IEN_ARB_LOSE | IEN_ADDR_HIT); | 
|  |  | 
|  | if (num > 0) { | 
|  | reg |= IEN_FIFO_EMPTY; | 
|  | } else { | 
|  | reg &= (~IEN_FIFO_EMPTY); | 
|  | } | 
|  |  | 
|  | sys_write32(reg, I2C_INTE(dev)); | 
|  |  | 
|  | /* | 
|  | * Step5, | 
|  | * I2C Write 0x1 to the Command register to issue the transaction | 
|  | */ | 
|  | reg = sys_read32(I2C_CMD(dev)); | 
|  | reg &= (~CMD_MSK); | 
|  | reg |= (CMD_ISSUE_TRANSACTION); | 
|  | sys_write32(reg, I2C_CMD(dev)); | 
|  |  | 
|  | k_sem_take(&dev_data->device_sync_sem, K_FOREVER); | 
|  |  | 
|  | if (dev_data->status.target_ack != 1) { | 
|  | return -EIO; | 
|  | } | 
|  | dev_data->status.target_ack = 0; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int i2c_atciic100_controller_receive(const struct device *dev, | 
|  | uint16_t addr, uint8_t *data, uint32_t num, uint8_t flags) | 
|  | { | 
|  | struct i2c_atciic100_dev_data_t *dev_data = dev->data; | 
|  | uint32_t reg = 0; | 
|  |  | 
|  | /* | 
|  | * Max to 10-bit address. | 
|  | * Parameters data = null or num = 0 means no payload for | 
|  | * acknowledge polling. If no I2C payload, set Phase_data=0x0. | 
|  | */ | 
|  | if (addr > 0x3FF) { | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | /* Disable all I2C interrupts */ | 
|  | reg = sys_read32(I2C_INTE(dev)); | 
|  | reg &= (~IEN_ALL); | 
|  | sys_write32(reg, I2C_INTE(dev)); | 
|  |  | 
|  | dev_data->status.mode = 1; | 
|  | reg = sys_read32(I2C_SET(dev)); | 
|  | reg |= SETUP_CONTROLLER; | 
|  | sys_write32(reg, I2C_SET(dev)); | 
|  |  | 
|  | /* Direction => tx:0, rx:1 */ | 
|  | dev_data->status.arbitration_lost = 0; | 
|  | dev_data->status.target_ack = 0; | 
|  | dev_data->driver_state = I2C_DRV_CONTROLLER_RX; | 
|  |  | 
|  | /* Step1, Clear FIFO */ | 
|  | reg = sys_read32(I2C_CMD(dev)); | 
|  | reg &= (~CMD_MSK); | 
|  | reg |= (CMD_CLEAR_FIFO); | 
|  | sys_write32(reg, I2C_CMD(dev)); | 
|  |  | 
|  | /* | 
|  | * Step2 | 
|  | * Enable START, ADDRESS, DATA and STOP phase. | 
|  | * If no payload, clear DATA phase. | 
|  | * STOP condition triggered when transmission finish in Controller mode. | 
|  | * The bus is busy until STOP condition triggered. | 
|  | * For 10-bit target address, we must set STOP bit. | 
|  | * I2C direction : controller rx, set xfer data count. | 
|  | */ | 
|  | reg = sys_read32(I2C_CTRL(dev)); | 
|  | reg &= (~(CTRL_PHASE_START | CTRL_PHASE_ADDR | CTRL_PHASE_STOP | | 
|  | CTRL_DIR | CTRL_DATA_COUNT)); | 
|  | reg |= (CTRL_PHASE_START | CTRL_PHASE_ADDR | CTRL_DIR); | 
|  |  | 
|  | if (flags & I2C_MSG_STOP) { | 
|  | reg |= CTRL_PHASE_STOP; | 
|  | } | 
|  | if (num) { | 
|  | reg |= (CTRL_PHASE_DATA | (num & CTRL_DATA_COUNT)); | 
|  | } | 
|  |  | 
|  | sys_write32(reg, I2C_CTRL(dev)); | 
|  |  | 
|  | /* Step3 init I2C info */ | 
|  | dev_data->target_addr = addr; | 
|  | dev_data->xfered_data_rd_ptr = 0; | 
|  | dev_data->xfer_rd_num = num; | 
|  | dev_data->middleware_rx_buf = (uint8_t *)data; | 
|  |  | 
|  | /* In I2C target address, general call address = 0x0(7-bit or 10-bit) */ | 
|  | reg = sys_read32(I2C_ADDR(dev)); | 
|  | reg &= (~TARGET_ADDR_MSK); | 
|  | reg |= (dev_data->target_addr & (TARGET_ADDR_MSK)); | 
|  | sys_write32(reg, I2C_ADDR(dev)); | 
|  |  | 
|  | /* | 
|  | * Step4 Enable Interrupts: Complete, Arbitration Lose | 
|  | * Enable/Disable the FIFO Full Interrupt | 
|  | */ | 
|  | reg = sys_read32(I2C_INTE(dev)); | 
|  | reg |= (IEN_CMPL | IEN_FIFO_FULL | IEN_ARB_LOSE | IEN_ADDR_HIT); | 
|  | sys_write32(reg, I2C_INTE(dev)); | 
|  |  | 
|  | /* | 
|  | * Step5, | 
|  | * I2C write 0x1 to the Command register to issue the transaction | 
|  | */ | 
|  | reg = sys_read32(I2C_CMD(dev)); | 
|  | reg &= (~CMD_MSK); | 
|  | reg |= (CMD_ISSUE_TRANSACTION); | 
|  | sys_write32(reg, I2C_CMD(dev)); | 
|  |  | 
|  | k_sem_take(&dev_data->device_sync_sem, K_FOREVER); | 
|  | if (dev_data->status.target_ack != 1) { | 
|  | return -EIO; | 
|  | } | 
|  | dev_data->status.target_ack = 0; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #if defined(CONFIG_I2C_TARGET) | 
|  | static void i2c_atciic100_target_send(const struct device *dev, | 
|  | const uint8_t *data) | 
|  | { | 
|  | uint32_t reg = 0; | 
|  |  | 
|  | /* Clear FIFO */ | 
|  | reg = sys_read32(I2C_CMD(dev)); | 
|  | reg &= (~CMD_MSK); | 
|  | reg |= (CMD_CLEAR_FIFO); | 
|  | sys_write32(reg, I2C_CMD(dev)); | 
|  |  | 
|  | sys_write32(*data, I2C_DATA(dev)); | 
|  | } | 
|  |  | 
|  | static void i2c_atciic100_target_receive(const struct device *dev, | 
|  | uint8_t *data) | 
|  | { | 
|  | *data = sys_read32(I2C_DATA(dev)); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | static void i2c_controller_fifo_write(const struct device *dev, | 
|  | uint8_t is_init) | 
|  | { | 
|  | struct i2c_atciic100_dev_data_t *dev_data = dev->data; | 
|  | uint32_t i = 0, write_fifo_count = 0, reg = 0; | 
|  | uint8_t write_data; | 
|  |  | 
|  | write_fifo_count = dev_data->xfer_wt_num - dev_data->xfered_data_wt_ptr; | 
|  |  | 
|  | if (write_fifo_count >= dev_data->fifo_depth) { | 
|  | write_fifo_count = dev_data->fifo_depth; | 
|  | } | 
|  |  | 
|  | if (is_init) { | 
|  | write_fifo_count = 2; | 
|  | } | 
|  |  | 
|  | /* I2C write a patch of data(FIFO_Depth) to FIFO */ | 
|  | for (i = 0; i < write_fifo_count; i++) { | 
|  |  | 
|  | write_data = | 
|  | dev_data->middleware_tx_buf[dev_data->xfered_data_wt_ptr]; | 
|  | sys_write32((write_data & DATA_MSK), I2C_DATA(dev)); | 
|  | dev_data->xfered_data_wt_ptr++; | 
|  |  | 
|  | /* Disable the FIFO Empty Interrupt if no more data to send */ | 
|  | if (dev_data->xfered_data_wt_ptr == dev_data->xfer_wt_num) { | 
|  | reg = sys_read32(I2C_INTE(dev)); | 
|  | reg &= (~IEN_FIFO_EMPTY); | 
|  | sys_write32(reg, I2C_INTE(dev)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Basic fifo read function */ | 
|  | static void i2c_controller_fifo_read(const struct device *dev) | 
|  | { | 
|  | struct i2c_atciic100_dev_data_t *dev_data = dev->data; | 
|  | uint32_t i = 0, read_fifo_count = 0, reg = 0; | 
|  | uint8_t read_data; | 
|  |  | 
|  | read_fifo_count = dev_data->xfer_rd_num - dev_data->xfered_data_rd_ptr; | 
|  |  | 
|  | if (read_fifo_count >= dev_data->fifo_depth) { | 
|  | read_fifo_count = dev_data->fifo_depth; | 
|  | } | 
|  |  | 
|  | /* I2C read a patch of data(FIFO_Depth) from FIFO */ | 
|  | for (i = 0; i < read_fifo_count; i++) { | 
|  |  | 
|  | read_data = sys_read32(I2C_DATA(dev)) & DATA_MSK; | 
|  |  | 
|  | dev_data->middleware_rx_buf[dev_data->xfered_data_rd_ptr] = | 
|  | read_data; | 
|  | dev_data->xfered_data_rd_ptr++; | 
|  |  | 
|  | /* Disable the FIFO Full Interrupt if no more data to receive */ | 
|  | if (dev_data->xfered_data_rd_ptr == dev_data->xfer_rd_num) { | 
|  | reg = sys_read32(I2C_INTE(dev)); | 
|  | reg &= (~IEN_FIFO_FULL); | 
|  | sys_write32(reg, I2C_INTE(dev)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void i2c_fifo_empty_handler(const struct device *dev) | 
|  | { | 
|  | struct i2c_atciic100_dev_data_t *dev_data = dev->data; | 
|  |  | 
|  | if (dev_data->driver_state & I2C_DRV_CONTROLLER_TX) { | 
|  | i2c_controller_fifo_write(dev, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void i2c_fifo_full_handler(const struct device *dev) | 
|  | { | 
|  | struct i2c_atciic100_dev_data_t *dev_data = dev->data; | 
|  |  | 
|  | if (dev_data->driver_state & I2C_DRV_CONTROLLER_RX) { | 
|  | i2c_controller_fifo_read(dev); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void i2c_cmpl_handler(const struct device *dev, uint32_t reg_stat) | 
|  | { | 
|  | struct i2c_atciic100_dev_data_t *dev_data = dev->data; | 
|  | uint32_t reg_set = 0, reg_ctrl = 0, reg = 0; | 
|  |  | 
|  | reg_set = sys_read32(I2C_SET(dev)); | 
|  |  | 
|  | /* Controller mode */ | 
|  | if (dev_data->status.mode == 1) { | 
|  | /* Disable all I2C interrupts */ | 
|  | reg = sys_read32(I2C_INTE(dev)); | 
|  | reg &= (~IEN_ALL); | 
|  | sys_write32(reg, I2C_INTE(dev)); | 
|  | } | 
|  |  | 
|  | if (dev_data->driver_state & | 
|  | (I2C_DRV_CONTROLLER_TX | I2C_DRV_CONTROLLER_RX)) { | 
|  |  | 
|  | /* Get the remain number of data */ | 
|  | reg_ctrl = sys_read32(I2C_CTRL(dev)) & CTRL_DATA_COUNT; | 
|  |  | 
|  | if (dev_data->driver_state & I2C_DRV_CONTROLLER_TX) { | 
|  | /* Clear & set driver state to controller tx complete */ | 
|  | dev_data->driver_state = I2C_DRV_CONTROLLER_TX_CMPL; | 
|  | } | 
|  |  | 
|  | if (dev_data->driver_state & I2C_DRV_CONTROLLER_RX) { | 
|  | i2c_controller_fifo_read(dev); | 
|  | /* Clear & set driver state to controller rx complete */ | 
|  | dev_data->driver_state = I2C_DRV_CONTROLLER_RX_CMPL; | 
|  | } | 
|  |  | 
|  | k_sem_give(&dev_data->device_sync_sem); | 
|  | } | 
|  |  | 
|  | #if defined(CONFIG_I2C_TARGET) | 
|  | if (dev_data->driver_state & (I2C_DRV_TARGET_TX | I2C_DRV_TARGET_RX)) { | 
|  | reg_set = sys_read32(I2C_SET(dev)); | 
|  | reg_ctrl = sys_read32(I2C_CTRL(dev)); | 
|  |  | 
|  | if (dev_data->driver_state & I2C_DRV_TARGET_TX) { | 
|  | dev_data->driver_state = I2C_DRV_TARGET_TX_CMPL; | 
|  | } | 
|  |  | 
|  | if (dev_data->driver_state & I2C_DRV_TARGET_RX) { | 
|  | dev_data->driver_state = I2C_DRV_TARGET_RX_CMPL; | 
|  | } | 
|  |  | 
|  | /* If the Completion Interrupt asserts, | 
|  | * clear the FIFO and go next transaction. | 
|  | */ | 
|  | uint32_t reg_cmd = 0; | 
|  |  | 
|  | reg_cmd = sys_read32(I2C_CMD(dev)); | 
|  | reg_cmd &= (~CMD_MSK); | 
|  | reg_cmd |= (CMD_CLEAR_FIFO); | 
|  | sys_write32(reg_cmd, I2C_CMD(dev)); | 
|  | } | 
|  |  | 
|  | /* Enable Completion & Address Hit Interrupt */ | 
|  | /* Enable Byte Receive & Transfer for default target mode */ | 
|  | reg = 0x0; | 
|  | reg |= (IEN_CMPL | IEN_ADDR_HIT | STATUS_BYTE_RECV | STATUS_BYTE_TRANS); | 
|  | sys_write32(reg, I2C_INTE(dev)); | 
|  |  | 
|  | reg = sys_read32(I2C_SET(dev)); | 
|  | reg &= ~(SETUP_CONTROLLER); | 
|  | sys_write32(reg, I2C_SET(dev)); | 
|  |  | 
|  | reg &= (~TARGET_ADDR_MSK); | 
|  | reg |= (dev_data->target_config->address & (TARGET_ADDR_MSK)); | 
|  | sys_write32(reg, I2C_ADDR(dev)); | 
|  |  | 
|  | dev_data->driver_state = I2C_DRV_INIT; | 
|  | dev_data->status.mode = 0; | 
|  | dev_data->status.arbitration_lost = 0; | 
|  | #endif | 
|  |  | 
|  | } | 
|  |  | 
|  | #if defined(CONFIG_I2C_TARGET) | 
|  | static void andes_i2c_target_event(const struct device *dev, | 
|  | uint32_t reg_stat, uint32_t reg_ctrl) | 
|  | { | 
|  | struct i2c_atciic100_dev_data_t *dev_data = dev->data; | 
|  | uint32_t reg_set = 0; | 
|  | uint8_t  val; | 
|  | /* | 
|  | * Here is the entry for target mode driver to detect | 
|  | * target RX/TX action depend on controller TX/RX action. | 
|  | * A new I2C data transaction(START-ADDRESS-DATA-STOP) | 
|  | */ | 
|  | if (reg_stat & STATUS_ADDR_HIT) { | 
|  | if (k_sem_take(&dev_data->bus_lock, K_NO_WAIT) != 0) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (((reg_ctrl & CTRL_DIR) >> 8) == I2C_TARGET_TX) { | 
|  | /* Notify middleware to do target rx action */ | 
|  | dev_data->driver_state = I2C_DRV_TARGET_TX; | 
|  | dev_data->target_callbacks->read_requested | 
|  | (dev_data->target_config, &val); | 
|  | i2c_atciic100_target_send(dev, &val); | 
|  |  | 
|  | } else if (((reg_ctrl & CTRL_DIR) >> 8) == I2C_TARGET_RX) { | 
|  | /* Notify middleware to do target tx action */ | 
|  | dev_data->driver_state = I2C_DRV_TARGET_RX; | 
|  | dev_data->target_callbacks->write_requested | 
|  | (dev_data->target_config); | 
|  | } | 
|  | reg_set |= (CMD_ACK); | 
|  | sys_write32(reg_set, I2C_CMD(dev)); | 
|  | } | 
|  |  | 
|  | if (reg_stat & STATUS_BYTE_RECV) { | 
|  | i2c_atciic100_target_receive(dev, &val); | 
|  | dev_data->target_callbacks->write_received | 
|  | (dev_data->target_config, val); | 
|  |  | 
|  | reg_set = 0; | 
|  | if ((reg_stat & STATUS_CMPL) == 0) { | 
|  | reg_set |= (CMD_ACK); | 
|  | sys_write32(reg_set, I2C_CMD(dev)); | 
|  | } else { | 
|  | reg_set |= (CMD_NACK); | 
|  | sys_write32(reg_set, I2C_CMD(dev)); | 
|  | } | 
|  |  | 
|  | } else if (reg_stat & STATUS_BYTE_TRANS) { | 
|  | dev_data->target_callbacks->read_processed | 
|  | (dev_data->target_config, &val); | 
|  | i2c_atciic100_target_send(dev, &val); | 
|  | } | 
|  |  | 
|  | if (reg_stat & STATUS_CMPL) { | 
|  | i2c_cmpl_handler(dev, reg_stat); | 
|  | k_sem_give(&dev_data->bus_lock); | 
|  | } | 
|  | } | 
|  |  | 
|  | static int i2c_atciic100_target_register(const struct device *dev, | 
|  | struct i2c_target_config *cfg) | 
|  | { | 
|  | struct i2c_atciic100_dev_data_t *dev_data = dev->data; | 
|  | uint16_t reg_addr = 0; | 
|  | uint32_t reg; | 
|  |  | 
|  | reg_addr &= (~TARGET_ADDR_MSK); | 
|  | reg_addr |= (cfg->address & (TARGET_ADDR_MSK)); | 
|  |  | 
|  | sys_write32(reg_addr, I2C_ADDR(dev)); | 
|  |  | 
|  | dev_data->target_callbacks = cfg->callbacks; | 
|  | dev_data->target_config = cfg; | 
|  |  | 
|  | /* Enable Completion & Address Hit Interrupt */ | 
|  | /* Enable Byte Receive & Transfer for default target mode */ | 
|  | reg = 0x0; | 
|  | reg |= (IEN_CMPL | IEN_ADDR_HIT | STATUS_BYTE_RECV | STATUS_BYTE_TRANS); | 
|  | sys_write32(reg, I2C_INTE(dev)); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int i2c_atciic100_target_unregister(const struct device *dev, | 
|  | struct i2c_target_config *cfg) | 
|  | { | 
|  | uint32_t reg; | 
|  |  | 
|  | /* Disable all I2C interrupts */ | 
|  | reg = sys_read32(I2C_INTE(dev)); | 
|  | reg &= (~IEN_ALL); | 
|  | sys_write32(reg, I2C_INTE(dev)); | 
|  |  | 
|  | sys_write32(0x0, I2C_ADDR(dev)); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | static void i2c_atciic100_irq_handler(void *arg) | 
|  | { | 
|  | const struct device *dev = (struct device *)arg; | 
|  | struct i2c_atciic100_dev_data_t *dev_data = dev->data; | 
|  |  | 
|  | uint32_t reg_set, reg_stat = 0, reg_ctrl = 0; | 
|  |  | 
|  | reg_stat = sys_read32(I2C_STAT(dev)); | 
|  | reg_set = sys_read32(I2C_SET(dev)); | 
|  | reg_ctrl = sys_read32(I2C_CTRL(dev)); | 
|  |  | 
|  | /* Clear interrupts status */ | 
|  | sys_write32((reg_stat & STATUS_W1C_ALL), I2C_STAT(dev)); | 
|  |  | 
|  | #if defined(CONFIG_I2C_TARGET) | 
|  | if (dev_data->status.mode == 0) { | 
|  | andes_i2c_target_event(dev, reg_stat, reg_ctrl); | 
|  | return; | 
|  | } | 
|  | #endif | 
|  | if (reg_stat & STATUS_ADDR_HIT) { | 
|  | dev_data->status.target_ack = 1; | 
|  | } | 
|  |  | 
|  | if (reg_stat & STATUS_FIFO_EMPTY) { | 
|  | i2c_fifo_empty_handler(dev); | 
|  | } | 
|  |  | 
|  | if (reg_stat & STATUS_FIFO_FULL) { | 
|  | /* Store hw receive data count quickly */ | 
|  | i2c_fifo_full_handler(dev); | 
|  | } | 
|  |  | 
|  | if (reg_stat & STATUS_CMPL) { | 
|  | /* Store hw receive data count quickly */ | 
|  | i2c_cmpl_handler(dev, reg_stat); | 
|  | } | 
|  |  | 
|  | if ((reg_stat & STATUS_ARB_LOSE) && (reg_set & SETUP_CONTROLLER)) { | 
|  | dev_data->status.arbitration_lost = 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static DEVICE_API(i2c, i2c_atciic100_driver) = { | 
|  | .configure = (i2c_api_configure_t)i2c_atciic100_configure, | 
|  | .transfer = (i2c_api_full_io_t)i2c_atciic100_transfer, | 
|  | #if defined(CONFIG_I2C_TARGET) | 
|  | .target_register = (i2c_api_target_register_t)i2c_atciic100_target_register, | 
|  | .target_unregister = (i2c_api_target_unregister_t)i2c_atciic100_target_unregister, | 
|  | #endif | 
|  | #ifdef CONFIG_I2C_RTIO | 
|  | .iodev_submit = i2c_iodev_submit_fallback, | 
|  | #endif | 
|  | }; | 
|  |  | 
|  | static int i2c_atciic100_init(const struct device *dev) | 
|  | { | 
|  | const struct i2c_atciic100_config *dev_cfg = dev->config; | 
|  |  | 
|  | /* Disable all interrupts. */ | 
|  | sys_write32(0x00000000, I2C_INTE(dev)); | 
|  | /* Clear interrupts status. */ | 
|  | sys_write32(0xFFFFFFFF, I2C_STAT(dev)); | 
|  |  | 
|  | dev_cfg->dt_init_fn(); | 
|  |  | 
|  | i2c_atciic100_default_control(dev); | 
|  |  | 
|  | #if defined(CONFIG_I2C_TARGET) | 
|  | i2c_atciic100_configure(dev, I2C_SPEED_SET(I2C_SPEED_STANDARD)); | 
|  | #else | 
|  | i2c_atciic100_configure(dev, I2C_SPEED_SET(I2C_SPEED_STANDARD) | 
|  | | I2C_MODE_CONTROLLER); | 
|  | #endif | 
|  | irq_enable(dev_cfg->irq_num); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #define I2C_INIT(n)							\ | 
|  | static struct i2c_atciic100_dev_data_t				\ | 
|  | i2c_atciic100_dev_data_##n;	\ | 
|  | static void i2c_dt_init_##n(void);				\ | 
|  | static const struct i2c_atciic100_config			\ | 
|  | i2c_atciic100_config_##n = {				\ | 
|  | .base	= DT_INST_REG_ADDR(n),				\ | 
|  | .irq_num	= DT_INST_IRQN(n),			\ | 
|  | .dt_init_fn	= i2c_dt_init_##n			\ | 
|  | };								\ | 
|  | I2C_DEVICE_DT_INST_DEFINE(n,					\ | 
|  | i2c_atciic100_init,					\ | 
|  | NULL,							\ | 
|  | &i2c_atciic100_dev_data_##n,				\ | 
|  | &i2c_atciic100_config_##n,				\ | 
|  | POST_KERNEL,						\ | 
|  | CONFIG_I2C_INIT_PRIORITY,				\ | 
|  | &i2c_atciic100_driver);					\ | 
|  | \ | 
|  | static void i2c_dt_init_##n(void)				\ | 
|  | {								\ | 
|  | IRQ_CONNECT(DT_INST_IRQN(n),				\ | 
|  | DT_INST_IRQ(n, priority),				\ | 
|  | i2c_atciic100_irq_handler,				\ | 
|  | DEVICE_DT_INST_GET(n),					\ | 
|  | 0);							\ | 
|  | } | 
|  |  | 
|  | DT_INST_FOREACH_STATUS_OKAY(I2C_INIT) |