From ab1f0c739d887acee2cdc299f35351e280de4532 Mon Sep 17 00:00:00 2001 From: young Date: Tue, 14 Jan 2025 15:10:05 +0800 Subject: [PATCH] common: patch: i2c: Add multi-slave behavior support Description - Support up to 3 slave address on the same bus Motivation - Some project will use 2 more slave address on the same bus Test plan - Build code: Pass - Stress 3 salve address with ENABLE_I2C_MULTI_SLAVE - Stress without ENABLE_I2C_MULTI_SLAVE --- common/hal/hal_i2c_target.c | 77 ++- common/hal/hal_i2c_target.h | 9 + ...i2c-Add-multi-salve-behavior-support.patch | 596 ++++++++++++++++++ 3 files changed, 676 insertions(+), 6 deletions(-) create mode 100644 fix_patch/tag_v00.01.06_d014527731033db477f806f5bff2e1ca5d4b2ba7/0088-i2c-Add-multi-salve-behavior-support.patch diff --git a/common/hal/hal_i2c_target.c b/common/hal/hal_i2c_target.c index b860e051c0..7fd4bc366f 100644 --- a/common/hal/hal_i2c_target.c +++ b/common/hal/hal_i2c_target.c @@ -21,6 +21,7 @@ #include #include "hal_i2c_target.h" #include "libutil.h" +#include "plat_def.h" /* LOG SET */ #include @@ -49,12 +50,38 @@ static void do_something_after_wr_rcv(void *arg) ARG_UNUSED(arg); } +static struct i2c_target_data* i2c_find_slave_config(struct i2c_slave_config *config) +{ +#ifdef ENABLE_I2C_MULTI_SLAVE + for (int i=0; i < MAX_TARGET_NUM; i++) { + if (i2c_target_device_global[i].is_init && i2c_target_device_global[i].is_register) { + if (&i2c_target_device_global[i].data.config == config) { + return CONTAINER_OF(config, struct i2c_target_data, config); + } + if (i2c_target_device_global[i].is_enable_sec) { + if (&i2c_target_device_global[i].data.config_sec == config) { + return CONTAINER_OF(config, struct i2c_target_data, config_sec); + } + } + if (i2c_target_device_global[i].is_enable_thd) { + if (&i2c_target_device_global[i].data.config_thd == config) { + return CONTAINER_OF(config, struct i2c_target_data, config_thd); + } + } + } + } +#endif + return CONTAINER_OF(config, struct i2c_target_data, config); +} + static int i2c_target_write_requested(struct i2c_slave_config *config) { CHECK_NULL_ARG_WITH_RETURN(config, 1); struct i2c_target_data *data; - data = CONTAINER_OF(config, struct i2c_target_data, config); + data = i2c_find_slave_config(config); + + data->req_address = config->address & 0xFF; data->target_wr_msg.msg_length = 0; memset(data->target_wr_msg.msg, 0x0, MAX_I2C_TARGET_BUFF); @@ -69,7 +96,7 @@ static int i2c_target_write_received(struct i2c_slave_config *config, uint8_t va CHECK_NULL_ARG_WITH_RETURN(config, 1); struct i2c_target_data *data; - data = CONTAINER_OF(config, struct i2c_target_data, config); + data = i2c_find_slave_config(config); if (data->wr_buffer_idx >= MAX_I2C_TARGET_BUFF) { LOG_ERR("Buffer_idx over limit!"); @@ -89,7 +116,7 @@ static int i2c_target_read_requested(struct i2c_slave_config *config, uint8_t *v CHECK_NULL_ARG_WITH_RETURN(val, 1); struct i2c_target_data *data; - data = CONTAINER_OF(config, struct i2c_target_data, config); + data = i2c_find_slave_config(config); if (data->rd_data_collect_func) { if (data->rd_data_collect_func(data) == false) @@ -113,7 +140,7 @@ static int i2c_target_read_processed(struct i2c_slave_config *config, uint8_t *v CHECK_NULL_ARG_WITH_RETURN(val, 1); struct i2c_target_data *data; - data = CONTAINER_OF(config, struct i2c_target_data, config); + data = i2c_find_slave_config(config); if (data->target_rd_msg.msg_length - data->rd_buffer_idx == 0) { LOG_DBG("No remain buffer to read!"); @@ -135,7 +162,7 @@ static int i2c_target_stop(struct i2c_slave_config *config) CHECK_NULL_ARG_WITH_RETURN(config, 1); struct i2c_target_data *data; - data = CONTAINER_OF(config, struct i2c_target_data, config); + data = i2c_find_slave_config(config); int ret = 1; @@ -165,7 +192,7 @@ static int i2c_target_stop(struct i2c_slave_config *config) if (data->rd_buffer_idx) { if (data->target_rd_msg.msg_length - data->rd_buffer_idx) { - LOG_WRN("Read buffer doesn't read complete"); + LOG_DBG("Read buffer doesn't read complete"); } } @@ -479,6 +506,8 @@ static int do_i2c_target_cfg(uint8_t bus_num, struct _i2c_target_config *cfg) } /* need unregister first */ + i2c_target_device_global[bus_num].is_enable_sec = cfg->is_enable_sec; + i2c_target_device_global[bus_num].is_enable_thd = cfg->is_enable_thd; if (!(target_status & I2C_TARGET_NOT_REGISTER)) { int status = do_i2c_target_unregister(bus_num); if (status) { @@ -526,6 +555,14 @@ static int do_i2c_target_cfg(uint8_t bus_num, struct _i2c_target_config *cfg) } data->config.callbacks = &i2c_target_cb; +#ifdef ENABLE_I2C_MULTI_SLAVE + if (cfg->is_enable_sec) { + data->config_sec.callbacks = &i2c_target_cb; + } + if (cfg->is_enable_thd) { + data->config_thd.callbacks = &i2c_target_cb; + } +#endif } /* do modify, modify config set after init */ else { @@ -538,6 +575,14 @@ static int do_i2c_target_cfg(uint8_t bus_num, struct _i2c_target_config *cfg) data->max_msg_count = cfg->i2c_msg_count; data->config.address = cfg->address >> 1; // to 7-bit target address +#ifdef ENABLE_I2C_MULTI_SLAVE + if (cfg->is_enable_sec) { + data->config_sec.address = cfg->address_sec >> 1; + } + if (cfg->is_enable_thd) { + data->config_thd.address = cfg->address_thd >> 1; + } +#endif if (cfg->rd_data_collect_func) data->rd_data_collect_func = cfg->rd_data_collect_func; @@ -611,6 +656,16 @@ static int do_i2c_target_register(uint8_t bus_num) if (ret) return ret; +#ifdef ENABLE_I2C_MULTI_SLAVE + if (i2c_target_device_global[bus_num].is_enable_sec) { + ret = i2c_slave_register(data->i2c_controller, &data->config_sec); + } + + if (i2c_target_device_global[bus_num].is_enable_thd) { + ret = i2c_slave_register(data->i2c_controller, &data->config_thd); + } +#endif + i2c_target_device_global[bus_num].is_register = 1; return I2C_TARGET_API_NO_ERR; @@ -645,6 +700,16 @@ static int do_i2c_target_unregister(uint8_t bus_num) struct i2c_target_data *data = &i2c_target_device_global[bus_num].data; +#ifdef ENABLE_I2C_MULTI_SLAVE + if (i2c_target_device_global[bus_num].is_enable_thd) { + i2c_slave_unregister(data->i2c_controller, &data->config_thd); + } + + if (i2c_target_device_global[bus_num].is_enable_sec) { + i2c_slave_unregister(data->i2c_controller, &data->config_sec); + } +#endif + int ret = i2c_slave_unregister(data->i2c_controller, &data->config); if (ret) return ret; diff --git a/common/hal/hal_i2c_target.h b/common/hal/hal_i2c_target.h index 7d347b2e50..aea18c354d 100644 --- a/common/hal/hal_i2c_target.h +++ b/common/hal/hal_i2c_target.h @@ -34,6 +34,9 @@ struct i2c_target_data { uint8_t i2c_bus; // i2c bus number const struct device *i2c_controller; // i2c controller for one target bus struct i2c_slave_config config; // i2c target relative config + struct i2c_slave_config config_sec; // i2c target relative config for 2nd address + struct i2c_slave_config config_thd; // i2c target relative config for 3rd address + uint8_t req_address; // current request address /* TARGET WRITE - Support message queue for massive pending messages storage */ uint16_t wr_buffer_idx; // message buffer index @@ -54,12 +57,18 @@ struct _i2c_target_config { uint32_t i2c_msg_count; bool (*rd_data_collect_func)(void *); void (*post_wr_rcv_func)(void *); + uint8_t address_sec; + bool is_enable_sec; + uint8_t address_thd; + bool is_enable_thd; }; struct i2c_target_device { struct i2c_target_data data; bool is_init; bool is_register; + bool is_enable_sec; + bool is_enable_thd; }; /* Retern value set for i2c target status */ diff --git a/fix_patch/tag_v00.01.06_d014527731033db477f806f5bff2e1ca5d4b2ba7/0088-i2c-Add-multi-salve-behavior-support.patch b/fix_patch/tag_v00.01.06_d014527731033db477f806f5bff2e1ca5d4b2ba7/0088-i2c-Add-multi-salve-behavior-support.patch new file mode 100644 index 0000000000..e518d06b70 --- /dev/null +++ b/fix_patch/tag_v00.01.06_d014527731033db477f806f5bff2e1ca5d4b2ba7/0088-i2c-Add-multi-salve-behavior-support.patch @@ -0,0 +1,596 @@ +From 78e2040293e19810b5373a21665e81dc66248d7b Mon Sep 17 00:00:00 2001 +From: young +Date: Tue, 14 Jan 2025 10:32:15 +0800 +Subject: [PATCH] i2c: Add multi-salve behavior support + +--- + drivers/i2c/i2c_aspeed.c | 219 +++++++++++++++++++++++++++++++---------------- + 1 file changed, 145 insertions(+), 74 deletions(-) + +diff --git a/drivers/i2c/i2c_aspeed.c b/drivers/i2c/i2c_aspeed.c +index fe78b35..22a89707 100644 +--- a/drivers/i2c/i2c_aspeed.c ++++ b/drivers/i2c/i2c_aspeed.c +@@ -20,6 +20,7 @@ LOG_MODULE_REGISTER(i2c_aspeed); + + #include "i2c-priv.h" + ++#define I2C_SLAVE_COUNT 3 + #define I2C_SLAVE_BUF_SIZE 256 + + #define I2C_BUF_SIZE 0x20 +@@ -163,6 +164,7 @@ LOG_MODULE_REGISTER(i2c_aspeed); + #define AST_I2CS_ADDR1_NAK BIT(20) + + #define AST_I2CS_ADDR_MASK (3 << 18) ++#define AST_I2CS_GET_SLAVE(x) (((x) >> 30) & 0x3) + #define AST_I2CS_PKT_ERROR BIT(17) + #define AST_I2CS_PKT_DONE BIT(16) + #define AST_I2CS_INACTIVE_TO BIT(15) +@@ -299,7 +301,7 @@ struct i2c_aspeed_data { + + int master_xfer_cnt; /* total xfer count */ + +- bool slave_attached; ++ uint8_t slave_attached; /* slave attached count */ + + int xfer_complete; + +@@ -320,7 +322,7 @@ struct i2c_aspeed_data { + + #ifdef CONFIG_I2C_SLAVE + unsigned char slave_dma_buf[I2C_SLAVE_BUF_SIZE]; +- struct i2c_slave_config *slave_cfg; ++ struct i2c_slave_config *slave_cfg[I2C_SLAVE_COUNT]; + #endif + }; + +@@ -1338,12 +1340,13 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + { + struct i2c_aspeed_config *config = DEV_CFG(dev); + struct i2c_aspeed_data *data = DEV_DATA(dev); +- const struct i2c_slave_callbacks *slave_cb = data->slave_cfg->callbacks; ++ struct i2c_slave_config *slave_cfg = data->slave_cfg[AST_I2CS_GET_SLAVE(sts)]; ++ const struct i2c_slave_callbacks *slave_cb = slave_cfg->callbacks; + uint32_t cmd = 0; + uint32_t i, slave_rx_len = 0; + uint8_t byte_data = 0, value = 0; + +- sts &= ~(AST_I2CS_PKT_DONE | AST_I2CS_PKT_ERROR); ++ sts &= ~(AST_I2CS_PKT_DONE | AST_I2CS_PKT_ERROR | AST_I2CS_ADDR_INDICAT_MASK); + + switch (sts) { + case AST_I2CS_SLAVE_MATCH | AST_I2CS_RX_DONE | AST_I2CS_Wait_RX_DMA: /* re-trigger? */ +@@ -1353,7 +1356,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + } else { + LOG_DBG("S : Sw|D - Issue rx dma\n"); + if (slave_cb->write_requested) { +- slave_cb->write_requested(data->slave_cfg); ++ slave_cb->write_requested(slave_cfg); + } + + if (config->mode == DMA_MODE) { +@@ -1367,7 +1370,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + if (slave_cb->write_received) { + for (i = 0; i < slave_rx_len; i++) { + LOG_DBG("[%02x] ", data->slave_dma_buf[i]); +- slave_cb->write_received(data->slave_cfg ++ slave_cb->write_received(slave_cfg + , data->slave_dma_buf[i]); + } + } +@@ -1378,7 +1381,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + + if (slave_cb->write_received) { + for (i = 0; i < slave_rx_len ; i++) { +- slave_cb->write_received(data->slave_cfg ++ slave_cb->write_received(slave_cfg + , sys_read8(config->buf_base + i)); + } + } +@@ -1387,7 +1390,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + AST_I2CC_GET_RX_BUFF(sys_read32(i2c_base + AST_I2CC_STS_AND_BUFF)); + LOG_DBG("[%02x]", byte_data); + if (slave_cb->write_received) { +- slave_cb->write_received(data->slave_cfg, byte_data); ++ slave_cb->write_received(slave_cfg, byte_data); + } + } + aspeed_i2c_trigger_package_cmd(i2c_base, config->mode); +@@ -1396,7 +1399,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + case AST_I2CS_SLAVE_MATCH | AST_I2CS_STOP: + LOG_DBG("S : Sw | P\n"); + if (slave_cb->stop) { +- slave_cb->stop(data->slave_cfg); ++ slave_cb->stop(slave_cfg); + } + sys_write32(AST_I2CS_SET_RX_DMA_LEN(I2C_SLAVE_BUF_SIZE) + , i2c_base + AST_I2CS_DMA_LEN); +@@ -1421,7 +1424,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + + if (sts & AST_I2CS_SLAVE_MATCH) { + if (slave_cb->write_requested) { +- slave_cb->write_requested(data->slave_cfg); ++ slave_cb->write_requested(slave_cfg); + } + } + +@@ -1436,8 +1439,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + if (slave_cb->write_received) { + for (i = 0; i < slave_rx_len; i++) { + LOG_DBG("[%02x] ", data->slave_dma_buf[i]); +- slave_cb->write_received(data->slave_cfg +- , data->slave_dma_buf[i]); ++ slave_cb->write_received(slave_cfg, data->slave_dma_buf[i]); + } + } + +@@ -1450,8 +1452,8 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + + if (slave_cb->write_received) { + for (i = 0; i < slave_rx_len ; i++) { +- slave_cb->write_received(data->slave_cfg +- , sys_read8(config->buf_base + i)); ++ slave_cb->write_received(slave_cfg, ++ sys_read8(config->buf_base + i)); + } + } + } else { +@@ -1459,12 +1461,12 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + AST_I2CC_GET_RX_BUFF(sys_read32(i2c_base + AST_I2CC_STS_AND_BUFF)); + LOG_DBG("[%02x]", byte_data); + if (slave_cb->write_received) { +- slave_cb->write_received(data->slave_cfg, byte_data); ++ slave_cb->write_received(slave_cfg, byte_data); + } + } + if (sts & AST_I2CS_STOP) { + if (slave_cb->stop) { +- slave_cb->stop(data->slave_cfg); ++ slave_cb->stop(slave_cfg); + } + } + aspeed_i2c_trigger_package_cmd(i2c_base, config->mode); +@@ -1481,7 +1483,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + + if (sts & AST_I2CS_SLAVE_MATCH) { + if (slave_cb->write_requested) { +- slave_cb->write_requested(data->slave_cfg); ++ slave_cb->write_requested(slave_cfg); + } + } + +@@ -1496,14 +1498,12 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + , 1, K_CACHE_INVD); + LOG_DBG("rx [%02x]", data->slave_dma_buf[i]); + if (slave_cb->write_received) { +- slave_cb->write_received(data->slave_cfg +- , data->slave_dma_buf[i]); ++ slave_cb->write_received(slave_cfg, data->slave_dma_buf[i]); + } + } + + if (slave_cb->read_requested) { +- slave_cb->read_requested(data->slave_cfg +- , &data->slave_dma_buf[0]); ++ slave_cb->read_requested(slave_cfg, &data->slave_dma_buf[0]); + } + LOG_DBG("tx [%02x]", data->slave_dma_buf[0]); + +@@ -1518,13 +1518,13 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + for (i = 0; i < slave_rx_len; i++) { + LOG_DBG("rx [%02x]", (sys_read32(config->buf_base + i) & 0xFF)); + if (slave_cb->write_received) { +- slave_cb->write_received(data->slave_cfg ++ slave_cb->write_received(slave_cfg + , (sys_read32(config->buf_base + i) & 0xFF)); + } + } + + if (slave_cb->read_requested) { +- slave_cb->read_requested(data->slave_cfg, &value); ++ slave_cb->read_requested(slave_cfg, &value); + } + LOG_DBG("tx [%02x]", value); + +@@ -1537,10 +1537,10 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + byte_data = AST_I2CC_GET_RX_BUFF(sys_read32(i2c_base + AST_I2CC_STS_AND_BUFF)); + LOG_DBG("rx : [%02x]", byte_data); + if (slave_cb->write_received) { +- slave_cb->write_received(data->slave_cfg, byte_data); ++ slave_cb->write_received(slave_cfg, byte_data); + } + if (slave_cb->read_requested) { +- slave_cb->read_requested(data->slave_cfg, &byte_data); ++ slave_cb->read_requested(slave_cfg, &byte_data); + } + LOG_DBG("tx : [%02x]", byte_data); + sys_write32(byte_data, i2c_base + AST_I2CC_STS_AND_BUFF); +@@ -1556,8 +1556,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + if (config->mode == DMA_MODE) { + cmd |= AST_I2CS_TX_DMA_EN; + if (slave_cb->read_requested) { +- slave_cb->read_requested(data->slave_cfg +- , &data->slave_dma_buf[0]); ++ slave_cb->read_requested(slave_cfg, &data->slave_dma_buf[0]); + } + /*currently i2c slave framework only support one byte request.*/ + LOG_DBG("tx: [%x]\n", data->slave_dma_buf[0]); +@@ -1566,7 +1565,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + } else if (config->mode == BUFF_MODE) { + cmd |= AST_I2CS_TX_BUFF_EN; + if (slave_cb->read_requested) { +- slave_cb->read_requested(data->slave_cfg, &byte_data); ++ slave_cb->read_requested(slave_cfg, &byte_data); + } + /* currently i2c slave framework only support one byte request. */ + LOG_DBG("tx : [%02x]", byte_data); +@@ -1577,7 +1576,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + cmd &= ~AST_I2CS_PKT_MODE_EN; + cmd |= AST_I2CS_TX_CMD; + if (slave_cb->read_requested) { +- slave_cb->read_requested(data->slave_cfg, &byte_data); ++ slave_cb->read_requested(slave_cfg, &byte_data); + } + sys_write32(byte_data, i2c_base + AST_I2CC_STS_AND_BUFF); + } +@@ -1591,8 +1590,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + if (config->mode == DMA_MODE) { + cmd |= AST_I2CS_TX_DMA_EN; + if (slave_cb->read_processed) { +- slave_cb->read_processed(data->slave_cfg +- , &data->slave_dma_buf[0]); ++ slave_cb->read_processed(slave_cfg, &data->slave_dma_buf[0]); + } + LOG_DBG("rx : [%02x]", data->slave_dma_buf[0]); + sys_write32(0, i2c_base + AST_I2CS_DMA_LEN_STS); +@@ -1601,7 +1599,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + } else if (config->mode == BUFF_MODE) { + cmd |= AST_I2CS_TX_BUFF_EN; + if (slave_cb->read_processed) { +- slave_cb->read_processed(data->slave_cfg, &value); ++ slave_cb->read_processed(slave_cfg, &value); + } + LOG_DBG("tx: [%02x]\n", value); + sys_write8(value, config->buf_base); +@@ -1611,7 +1609,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + cmd &= ~AST_I2CS_PKT_MODE_EN; + cmd |= AST_I2CS_TX_CMD; + if (slave_cb->read_processed) { +- slave_cb->read_processed(data->slave_cfg, &byte_data); ++ slave_cb->read_processed(slave_cfg, &byte_data); + } + LOG_DBG("tx: [%02x]\n", byte_data); + sys_write32(byte_data, i2c_base + AST_I2CC_STS_AND_BUFF); +@@ -1623,7 +1621,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + LOG_DBG("S: AST_I2CS_TX_NAK\n"); + cmd = SLAVE_TRIGGER_CMD; + if (slave_cb->stop) { +- slave_cb->stop(data->slave_cfg); ++ slave_cb->stop(slave_cfg); + } + if (config->mode == DMA_MODE) { + cmd |= AST_I2CS_RX_DMA_EN; +@@ -1643,14 +1641,14 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + case AST_I2CS_SLAVE_MATCH | AST_I2CS_RX_DONE | AST_I2CS_Wait_RX_DMA | AST_I2CS_STOP | AST_I2CS_TX_NAK: + LOG_DBG("S: AST_I2CS_TX_NAK\n"); + if (slave_cb->stop) { +- slave_cb->stop(data->slave_cfg); ++ slave_cb->stop(slave_cfg); + } + if (sys_read32(i2c_base + AST_I2CM_ISR)) { + LOG_DBG("S : Sw|D - Wait normal\n"); + } else { + LOG_DBG("S : Sw|D - Issue rx dma\n"); + if (slave_cb->write_requested) { +- slave_cb->write_requested(data->slave_cfg); ++ slave_cb->write_requested(slave_cfg); + } + + if (config->mode == DMA_MODE) { +@@ -1664,7 +1662,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + if (slave_cb->write_received) { + for (i = 0; i < slave_rx_len; i++) { + LOG_DBG("[%02x] ", data->slave_dma_buf[i]); +- slave_cb->write_received(data->slave_cfg ++ slave_cb->write_received(slave_cfg + , data->slave_dma_buf[i]); + } + } +@@ -1675,7 +1673,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + + if (slave_cb->write_received) { + for (i = 0; i < slave_rx_len ; i++) { +- slave_cb->write_received(data->slave_cfg ++ slave_cb->write_received(slave_cfg + , sys_read8(config->buf_base + i)); + } + } +@@ -1684,7 +1682,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + AST_I2CC_GET_RX_BUFF(sys_read32(i2c_base + AST_I2CC_STS_AND_BUFF)); + LOG_DBG("[%02x]", byte_data); + if (slave_cb->write_received) { +- slave_cb->write_received(data->slave_cfg, byte_data); ++ slave_cb->write_received(slave_cfg, byte_data); + } + } + aspeed_i2c_trigger_package_cmd(i2c_base, config->mode); +@@ -1693,7 +1691,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + + case AST_I2CS_SLAVE_MATCH | AST_I2CS_RX_DONE: + if (slave_cb->write_requested) { +- slave_cb->write_requested(data->slave_cfg); ++ slave_cb->write_requested(slave_cfg); + } + break; + +@@ -1701,7 +1699,7 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + /*it just tx complete*/ + LOG_DBG("S: AST_I2CS_STOP\n"); + if (slave_cb->stop) { +- slave_cb->stop(data->slave_cfg); ++ slave_cb->stop(slave_cfg); + } + break; + +@@ -1719,10 +1717,13 @@ void aspeed_i2c_slave_packet_irq(const struct device *dev, uint32_t i2c_base, ui + void aspeed_i2c_slave_byte_irq(const struct device *dev, uint32_t i2c_base, uint32_t sts) + { + struct i2c_aspeed_data *data = DEV_DATA(dev); +- const struct i2c_slave_callbacks *slave_cb = data->slave_cfg->callbacks; ++ struct i2c_slave_config *slave_cfg = data->slave_cfg[AST_I2CS_GET_SLAVE(sts)]; ++ const struct i2c_slave_callbacks *slave_cb = slave_cfg->callbacks; + uint32_t cmd = AST_I2CS_ACTIVE_ALL; + uint8_t byte_data = 0; + ++ sts &= ~(AST_I2CS_ADDR_INDICAT_MASK); ++ + LOG_DBG("byte mode\n"); + + switch (sts) { +@@ -1737,7 +1738,7 @@ void aspeed_i2c_slave_byte_irq(const struct device *dev, uint32_t i2c_base, uint + /* If the record address is still same, it is re-start case. */ + if ((slave_cb->write_requested) && + byte_data != data->slave_addr_last) { +- slave_cb->write_requested(data->slave_cfg); ++ slave_cb->write_requested(slave_cfg); + } + + data->slave_addr_last = byte_data; +@@ -1748,7 +1749,7 @@ void aspeed_i2c_slave_byte_irq(const struct device *dev, uint32_t i2c_base, uint + LOG_DBG("S : Sw|D|P\n"); + + if (slave_cb->stop) { +- slave_cb->stop(data->slave_cfg); ++ slave_cb->stop(slave_cfg); + } + + /* clear record slave address */ +@@ -1761,7 +1762,7 @@ void aspeed_i2c_slave_byte_irq(const struct device *dev, uint32_t i2c_base, uint + + /* address set request */ + if (slave_cb->write_requested) { +- slave_cb->write_requested(data->slave_cfg); ++ slave_cb->write_requested(slave_cfg); + } + + data->slave_addr_last = byte_data; +@@ -1773,7 +1774,7 @@ void aspeed_i2c_slave_byte_irq(const struct device *dev, uint32_t i2c_base, uint + LOG_DBG("rx [%x]", byte_data); + + if (slave_cb->write_received) { +- slave_cb->write_received(data->slave_cfg ++ slave_cb->write_received(slave_cfg + , byte_data); + } + break; +@@ -1785,7 +1786,7 @@ void aspeed_i2c_slave_byte_irq(const struct device *dev, uint32_t i2c_base, uint + LOG_DBG("addr : [%02x]", byte_data); + + if (slave_cb->read_requested) { +- slave_cb->read_requested(data->slave_cfg ++ slave_cb->read_requested(slave_cfg + , &byte_data); + } + +@@ -1797,7 +1798,7 @@ void aspeed_i2c_slave_byte_irq(const struct device *dev, uint32_t i2c_base, uint + LOG_DBG("S : D\n"); + + if (slave_cb->read_processed) { +- slave_cb->read_processed(data->slave_cfg ++ slave_cb->read_processed(slave_cfg + , &byte_data); + } + +@@ -1810,7 +1811,7 @@ void aspeed_i2c_slave_byte_irq(const struct device *dev, uint32_t i2c_base, uint + case AST_I2CS_SLAVE_MATCH | AST_I2CS_Wait_RX_DMA | AST_I2CS_STOP | AST_I2CS_TX_NAK: + LOG_DBG("S : P\n"); + if (slave_cb->stop) { +- slave_cb->stop(data->slave_cfg); ++ slave_cb->stop(slave_cfg); + } + + if (sts & AST_I2CS_TX_NAK) { +@@ -1848,10 +1849,9 @@ int aspeed_i2c_slave_irq(const struct device *dev) + return 0; + } + +- LOG_DBG("S irq sts %x, bus %x\n", sts, sys_read32(i2c_base + AST_I2CC_STS_AND_BUFF)); + + /* remove unnessary status flags */ +- sts &= ~(AST_I2CS_ADDR_INDICAT_MASK | AST_I2CS_SLAVE_PENDING); ++ sts &= ~(AST_I2CS_SLAVE_PENDING); + + if (AST_I2CS_ADDR1_NAK & sts) { + sts &= ~AST_I2CS_ADDR1_NAK; +@@ -1926,9 +1926,9 @@ static int i2c_aspeed_init(const struct device *dev) + uint32_t i2c_count = ((i2c_base & 0xFFFF) / 0x80) - 1; + uint32_t i2c_base_offset = I2C_BUF_BASE + (i2c_count * 0x20); + uint32_t bitrate_cfg; +- int error; ++ int error, i; + uint64_t rev_id; +- size_t len; ++ size_t len; + + k_sem_init(&data->sync_sem, 0, UINT_MAX); + +@@ -1946,9 +1946,13 @@ static int i2c_aspeed_init(const struct device *dev) + /* byte mode check re-start */ + data->slave_addr_last = 0xFF; + +- /* check chip id*/ +- len = hwinfo_get_device_id((uint8_t *)&rev_id, sizeof(rev_id)); ++ /* initial slave attach function pointer */ ++ data->slave_attached = 0; ++ for (i = 0; i < I2C_SLAVE_COUNT; i++) ++ data->slave_cfg[i] = NULL; + ++ /* check chip id*/ ++ len = hwinfo_get_device_id((uint8_t *)&rev_id, sizeof(rev_id)); + clock_control_get_rate(config->clock_dev, config->clk_id, &config->clk_src); + LOG_DBG("clk src %d, div mode %d, multi-master %d, xfer mode %d\n", + config->clk_src, config->clk_div_mode, config->multi_master, config->mode); +@@ -1971,24 +1975,57 @@ static int i2c_aspeed_slave_register(const struct device *dev, + { + struct i2c_aspeed_config *i2c_config = DEV_CFG(dev); + struct i2c_aspeed_data *data = dev->data; ++ uint8_t i = 0; + uint32_t i2c_base = DEV_BASE(dev); + uint32_t cmd = AST_I2CS_ACTIVE_ALL | AST_I2CS_PKT_MODE_EN; +- uint32_t slave_en = (sys_read32(i2c_base + AST_I2CC_FUN_CTRL) +- & AST_I2CC_SLAVE_EN); ++ uint32_t slave_addr = sys_read32(i2c_base + AST_I2CS_ADDR_CTRL); + +- /* check slave config exist or has attached ever*/ +- if ((!config) || (data->slave_attached) || slave_en) { ++ /* check slave config input */ ++ if (!config || data->slave_attached == 3) { + return -EINVAL; + } + +- data->slave_cfg = config; ++ /* check duplicate address */ ++ for (i = 0; i < I2C_SLAVE_COUNT; i++) { ++ if (data->slave_cfg[i]) { ++ if (data->slave_cfg[i]->address == config->address) { ++ LOG_DBG("duplicate address [%x] on %d\n", config->address, i); ++ return -EINVAL; ++ } ++ } ++ } ++ ++ /* assign the slave into slave array */ ++ for (i = 0; i < I2C_SLAVE_COUNT; i++) { ++ if (!data->slave_cfg[i]) { + +- LOG_DBG(" [%x]\n", config->address); ++ data->slave_cfg[i] = config; ++ LOG_DBG("reg [%x] into %d\n", config->address, i); + +- /* set slave addr. */ +- sys_write32(config->address | +- (sys_read32(i2c_base + AST_I2CS_ADDR_CTRL) & ~AST_I2CS_ADDR1_MASK), +- i2c_base + AST_I2CS_ADDR_CTRL); ++ /* set slave addr by index */ ++ switch (i) { ++ case 0: ++ slave_addr &= ~(AST_I2CS_ADDR1_MASK); ++ slave_addr |= (AST_I2CS_ADDR1(config->address) ++ | AST_I2CS_ADDR1_ENABLE); ++ break; ++ case 1: ++ slave_addr &= ~(AST_I2CS_ADDR2_MASK); ++ slave_addr |= (AST_I2CS_ADDR2(config->address) ++ | AST_I2CS_ADDR2_ENABLE); ++ break; ++ case 2: ++ slave_addr &= ~(AST_I2CS_ADDR3_MASK); ++ slave_addr |= (AST_I2CS_ADDR3(config->address) ++ | AST_I2CS_ADDR3_ENABLE); ++ break; ++ } ++ ++ LOG_DBG("reg slave_addr [%x]\n", slave_addr); ++ sys_write32(slave_addr, i2c_base + AST_I2CS_ADDR_CTRL); ++ break; ++ } ++ } + + /* trigger rx buffer */ + if (i2c_config->mode == DMA_MODE) { +@@ -2010,7 +2047,7 @@ static int i2c_aspeed_slave_register(const struct device *dev, + sys_write32(AST_I2CC_SLAVE_EN | sys_read32(i2c_base + AST_I2CC_FUN_CTRL) + , i2c_base + AST_I2CC_FUN_CTRL); + +- data->slave_attached = true; ++ data->slave_attached++; + + return 0; + } +@@ -2020,20 +2057,54 @@ static int i2c_aspeed_slave_unregister(const struct device *dev, + { + struct i2c_aspeed_data *data = dev->data; + uint32_t i2c_base = DEV_BASE(dev); ++ uint32_t slave_addr = sys_read32(i2c_base + AST_I2CS_ADDR_CTRL); ++ bool slave_found = false; ++ uint8_t i; + +- if (!data->slave_attached) { ++ /* check slave config input */ ++ if (!config || data->slave_attached == 0) { + return -EINVAL; + } + +- LOG_DBG(" [%x]\n", config->address); ++ /* remove the slave call back from array */ ++ for (i = 0; i < I2C_SLAVE_COUNT; i++) { ++ if (data->slave_cfg[i]) { ++ if (data->slave_cfg[i]->address == config->address) { ++ slave_found = true; ++ data->slave_cfg[i] = NULL; ++ LOG_DBG("remove [%x] from %d\n", config->address, i); ++ ++ /* remove slave addr by index */ ++ switch (i) { ++ case 0: ++ slave_addr &= ~(AST_I2CS_ADDR1_MASK); ++ break; ++ case 1: ++ slave_addr &= ~(AST_I2CS_ADDR2_MASK); ++ break; ++ case 2: ++ slave_addr &= ~(AST_I2CS_ADDR3_MASK); ++ break; ++ } + +- /*Turn off slave mode.*/ +- sys_write32(~AST_I2CC_SLAVE_EN & sys_read32(i2c_base + AST_I2CC_FUN_CTRL) +- , i2c_base + AST_I2CC_FUN_CTRL); +- sys_write32(sys_read32(i2c_base + AST_I2CS_ADDR_CTRL) & ~AST_I2CS_ADDR1_MASK +- , i2c_base + AST_I2CS_ADDR_CTRL); ++ LOG_DBG("un-reg slave_addr [%x]\n", slave_addr); ++ sys_write32(slave_addr, i2c_base + AST_I2CS_ADDR_CTRL); ++ break; ++ } ++ } ++ } + +- data->slave_attached = false; ++ /* don't find slave to remove */ ++ if (!slave_found) ++ return -EINVAL; ++ ++ data->slave_attached--; ++ ++ if (data->slave_attached == 0x0) { ++ /*Turn off slave mode.*/ ++ sys_write32(~AST_I2CC_SLAVE_EN & sys_read32(i2c_base + AST_I2CC_FUN_CTRL) ++ , i2c_base + AST_I2CC_FUN_CTRL); ++ } + + return 0; + } +-- +2.7.4 +