zephyr/drivers/i2c/i2c_andes_atciic100.c
Yuval Peress 8974c248cf rtio: Add default i2c submit handler
Use the RTIO work queue to fake the i2c submit calls for drivers which
haven't yet implemented the API. Applications can change the size of
the work queue pool depending on how much traffic they have on the buses.

Signed-off-by: Yuval Peress <peress@google.com>
2024-09-04 21:28:26 +02:00

800 lines
20 KiB
C

/*
* 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 const struct i2c_driver_api 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)