Browse Source

feat(i2c_slave): Add new implementation and API for I2C slave

Cao Sen Miao 2 năm trước cách đây
mục cha
commit
8d639492f2
27 tập tin đã thay đổi với 1046 bổ sung141 xóa
  1. 3 0
      components/driver/CMakeLists.txt
  2. 33 15
      components/driver/i2c/i2c_common.c
  3. 2 29
      components/driver/i2c/i2c_master.c
  4. 30 8
      components/driver/i2c/i2c_private.h
  5. 424 0
      components/driver/i2c/i2c_slave.c
  6. 3 3
      components/driver/i2c/include/driver/i2c_master.h
  7. 166 0
      components/driver/i2c/include/driver/i2c_slave.h
  8. 45 0
      components/driver/i2c/include/driver/i2c_types.h
  9. 15 9
      components/hal/esp32/include/hal/i2c_ll.h
  10. 2 8
      components/hal/esp32c2/include/hal/i2c_ll.h
  11. 42 11
      components/hal/esp32c3/include/hal/i2c_ll.h
  12. 46 14
      components/hal/esp32c6/include/hal/i2c_ll.h
  13. 46 14
      components/hal/esp32h2/include/hal/i2c_ll.h
  14. 17 10
      components/hal/esp32p4/include/hal/i2c_ll.h
  15. 32 12
      components/hal/esp32s2/include/hal/i2c_ll.h
  16. 45 8
      components/hal/esp32s3/include/hal/i2c_ll.h
  17. 10 0
      components/hal/include/hal/i2c_types.h
  18. 12 0
      components/soc/esp32c3/include/soc/Kconfig.soc_caps.in
  19. 3 0
      components/soc/esp32c3/include/soc/soc_caps.h
  20. 16 0
      components/soc/esp32c6/include/soc/Kconfig.soc_caps.in
  21. 4 0
      components/soc/esp32c6/include/soc/soc_caps.h
  22. 16 0
      components/soc/esp32h2/include/soc/Kconfig.soc_caps.in
  23. 4 0
      components/soc/esp32h2/include/soc/soc_caps.h
  24. 16 0
      components/soc/esp32p4/include/soc/Kconfig.soc_caps.in
  25. 4 0
      components/soc/esp32p4/include/soc/soc_caps.h
  26. 8 0
      components/soc/esp32s3/include/soc/Kconfig.soc_caps.in
  27. 2 0
      components/soc/esp32s3/include/soc/soc_caps.h

+ 3 - 0
components/driver/CMakeLists.txt

@@ -108,6 +108,9 @@ if(CONFIG_SOC_I2C_SUPPORTED)
                      "i2c/i2c_master.c"
                      "i2c/i2c_common.c"
         )
+    if(CONFIG_SOC_I2C_SUPPORT_SLAVE)
+        list(APPEND srcs "i2c/i2c_slave.c")
+    endif()
 
     list(APPEND ldfragments "i2c/linker.lf")
 endif()

+ 33 - 15
components/driver/i2c/i2c_common.c

@@ -37,7 +37,7 @@ typedef struct i2c_platform_t {
 
 static i2c_platform_t s_i2c_platform = {}; // singleton platform
 
-esp_err_t i2c_acquire_bus_handle(i2c_port_num_t port_num, i2c_bus_handle_t *i2c_new_bus, i2c_bus_mode_t mode)
+static esp_err_t s_i2c_bus_handle_aquire(i2c_port_num_t port_num, i2c_bus_handle_t *i2c_new_bus, i2c_bus_mode_t mode)
 {
 #if CONFIG_I2C_ENABLE_DEBUG_LOG
     esp_log_level_set(TAG, ESP_LOG_DEBUG);
@@ -76,15 +76,41 @@ esp_err_t i2c_acquire_bus_handle(i2c_port_num_t port_num, i2c_bus_handle_t *i2c_
     return ret;
 }
 
-bool i2c_bus_occupied(i2c_port_num_t port_num)
+static bool i2c_bus_occupied(i2c_port_num_t port_num)
+{
+    return s_i2c_platform.buses[port_num] != NULL;
+}
+
+esp_err_t i2c_acquire_bus_handle(i2c_port_num_t port_num, i2c_bus_handle_t *i2c_new_bus, i2c_bus_mode_t mode)
 {
     bool bus_occupied = false;
+    bool bus_found = false;
+    esp_err_t ret = ESP_OK;
     _lock_acquire(&s_i2c_platform.mutex);
-    if (s_i2c_platform.buses[port_num]) {
-        bus_occupied = true;
+    if (port_num == -1) {
+        for (int i = 0; i < SOC_I2C_NUM; i++) {
+            bus_occupied = i2c_bus_occupied(i);
+            if (bus_occupied == false) {
+                ret = s_i2c_bus_handle_aquire(i, i2c_new_bus, mode);
+                if (ret != ESP_OK) {
+                    ESP_LOGE(TAG, "acquire bus failed");
+                    _lock_release(&s_i2c_platform.mutex);
+                    return ret;
+                }
+                bus_found = true;
+                port_num = i;
+                break;
+            }
+        }
+        ESP_RETURN_ON_FALSE((bus_found == true), ESP_ERR_NOT_FOUND, TAG, "acquire bus failed, no free bus");
+    } else {
+        ret = s_i2c_bus_handle_aquire(port_num, i2c_new_bus, mode);
+        if (ret != ESP_OK) {
+            ESP_LOGE(TAG, "acquire bus failed");
+        }
     }
     _lock_release(&s_i2c_platform.mutex);
-    return bus_occupied;
+    return ret;
 }
 
 esp_err_t i2c_release_bus_handle(i2c_bus_handle_t i2c_bus)
@@ -205,12 +231,8 @@ esp_err_t i2c_common_set_pins(i2c_bus_handle_t handle)
         .pull_up_en = handle->pull_up_enable ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE,
         .pin_bit_mask = 1ULL << handle->sda_num,
     };
-#if CONFIG_IDF_TARGET_ESP32
-    // on esp32, must enable internal pull-up
-    sda_conf.pull_up_en = GPIO_PULLUP_ENABLE;
-#endif
-    ESP_RETURN_ON_ERROR(gpio_config(&sda_conf), TAG, "config GPIO failed");
     ESP_RETURN_ON_ERROR(gpio_set_level(handle->sda_num, 1), TAG, "i2c sda pin set level failed");
+    ESP_RETURN_ON_ERROR(gpio_config(&sda_conf), TAG, "config GPIO failed");
     gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[handle->sda_num], PIN_FUNC_GPIO);
     esp_rom_gpio_connect_out_signal(handle->sda_num, i2c_periph_signal[port_id].sda_out_sig, 0, 0);
     esp_rom_gpio_connect_in_signal(handle->sda_num, i2c_periph_signal[port_id].sda_in_sig, 0);
@@ -224,12 +246,8 @@ esp_err_t i2c_common_set_pins(i2c_bus_handle_t handle)
         .pull_up_en = handle->pull_up_enable ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE,
         .pin_bit_mask = 1ULL << handle->scl_num,
     };
-#if CONFIG_IDF_TARGET_ESP32
-    // on esp32, must enable internal pull-up
-    scl_conf.pull_up_en = GPIO_PULLUP_ENABLE;
-#endif
-    ESP_RETURN_ON_ERROR(gpio_config(&scl_conf), TAG, "config GPIO failed");
     ESP_RETURN_ON_ERROR(gpio_set_level(handle->scl_num, 1), TAG, "i2c scl pin set level failed");
+    ESP_RETURN_ON_ERROR(gpio_config(&scl_conf), TAG, "config GPIO failed");
     gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[handle->scl_num], PIN_FUNC_GPIO);
     esp_rom_gpio_connect_out_signal(handle->scl_num, i2c_periph_signal[port_id].scl_out_sig, 0, 0);
     esp_rom_gpio_connect_in_signal(handle->scl_num, i2c_periph_signal[port_id].scl_in_sig, 0);

+ 2 - 29
components/driver/i2c/i2c_master.c

@@ -35,7 +35,6 @@
 #include "freertos/idf_additions.h"
 
 static const char *TAG = "i2c.master";
-static _lock_t s_i2c_bus_acquire;
 
 #define DIM(array)                (sizeof(array)/sizeof(*array))
 #define I2C_ADDRESS_TRANS_WRITE(device_address)    (((device_address) << 1) | 0)
@@ -785,39 +784,13 @@ esp_err_t i2c_new_master_bus(const i2c_master_bus_config_t *bus_config, i2c_mast
     ESP_RETURN_ON_FALSE(bus_config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
     ESP_RETURN_ON_FALSE((bus_config->i2c_port < SOC_I2C_NUM || bus_config->i2c_port == -1), ESP_ERR_INVALID_ARG, TAG, "invalid i2c port number");
     ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(bus_config->sda_io_num) && GPIO_IS_VALID_GPIO(bus_config->scl_io_num), ESP_ERR_INVALID_ARG, TAG, "invalid SDA/SCL pin number");
-    bool bus_occupied = false;
-    bool bus_found = false;
 
     i2c_master = heap_caps_calloc(1, sizeof(i2c_master_bus_t) + 20 * sizeof(i2c_transaction_t), I2C_MEM_ALLOC_CAPS);
 
     ESP_RETURN_ON_FALSE(i2c_master, ESP_ERR_NO_MEM, TAG, "no memory for i2c master bus");
 
-    _lock_acquire(&s_i2c_bus_acquire);
-    if (i2c_port_num == -1) {
-        for (int i = 0; i < SOC_I2C_NUM; i++) {
-            bus_occupied = i2c_bus_occupied(i);
-            if (bus_occupied == false) {
-                ret = i2c_acquire_bus_handle(i, &i2c_master->base, I2C_BUS_MODE_MASTER);
-                if (ret != ESP_OK) {
-                    ESP_LOGE(TAG, "acquire bus failed");
-                    _lock_release(&s_i2c_bus_acquire);
-                    goto err;
-                }
-                bus_found = true;
-                i2c_port_num = i;
-                break;
-            }
-        }
-        ESP_GOTO_ON_FALSE((bus_found == true), ESP_ERR_NOT_FOUND, err, TAG, "acquire bus failed, no free bus");
-    } else {
-        ret = i2c_acquire_bus_handle(i2c_port_num, &i2c_master->base, I2C_BUS_MODE_MASTER);
-        if (ret != ESP_OK) {
-            ESP_LOGE(TAG, "acquire bus failed");
-            _lock_release(&s_i2c_bus_acquire);
-            goto err;
-        }
-    }
-    _lock_release(&s_i2c_bus_acquire);
+    ESP_GOTO_ON_ERROR(i2c_acquire_bus_handle(i2c_port_num, &i2c_master->base, I2C_BUS_MODE_MASTER), err, TAG, "I2C bus acquire failed");
+    i2c_port_num = i2c_master->base->port_num;
 
     i2c_hal_context_t *hal = &i2c_master->base->hal;
     i2c_master->base->scl_num = bus_config->scl_io_num;

+ 30 - 8
components/driver/i2c/i2c_private.h

@@ -16,6 +16,7 @@
 #include "freertos/semphr.h"
 #include "freertos/task.h"
 #include "freertos/ringbuf.h"
+#include "driver/i2c_slave.h"
 #include "esp_pm.h"
 
 #ifdef __cplusplus
@@ -52,6 +53,7 @@ typedef struct i2c_bus_t i2c_bus_t;
 typedef struct i2c_master_bus_t i2c_master_bus_t;
 typedef struct i2c_bus_t *i2c_bus_handle_t;
 typedef struct i2c_master_dev_t i2c_master_dev_t;
+typedef struct i2c_slave_dev_t i2c_slave_dev_t;
 
 typedef enum {
     I2C_BUS_MODE_MASTER = 0,
@@ -153,6 +155,34 @@ struct i2c_master_dev_t {
     void *user_ctx;                       // Callback user context
 };
 
+typedef struct {
+    bool trans_complete;  // Event of transaction complete
+    bool slave_stretch;   // Event of slave stretch happens
+    bool addr_unmatch;    // Event of address unmatched
+} i2c_slave_evt_t;
+
+typedef struct {
+    uint8_t *buffer;            // Pointer to the buffer need to be received in ISR
+    uint32_t rcv_fifo_cnt;      // receive fifo count.
+} i2c_slave_receive_t;
+
+struct i2c_slave_dev_t {
+    i2c_bus_t *base;                            // bus base class
+    SemaphoreHandle_t slv_rx_mux;               // Mutex for slave rx direction
+    SemaphoreHandle_t slv_tx_mux;               // Mutex for slave tx direction
+    RingbufHandle_t rx_ring_buf;                // Handle for rx ringbuffer
+    RingbufHandle_t tx_ring_buf;                // Handle for tx ringbuffer
+    uint8_t data_buf[SOC_I2C_FIFO_LEN];         // Data buffer for slave
+    uint32_t trans_data_length;                 // Send data length
+    i2c_slave_event_callbacks_t callbacks;      // I2C slave callbacks
+    void *user_ctx;                             // Callback user context
+    i2c_slave_fifo_mode_t fifo_mode;            // Slave fifo mode.
+    QueueHandle_t slv_evt_queue;                // Event Queue used in slave nonfifo mode.
+    i2c_slave_evt_t slave_evt;                  // Slave event structure.
+    i2c_slave_receive_t receive_desc;           // Slave receive descriptor
+    uint32_t already_receive_len;               // Data length already received in ISR.
+};
+
 /**
  * @brief Acquire I2C bus handle
  *
@@ -198,14 +228,6 @@ esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, i2c_clock_source_t cl
  */
 esp_err_t i2c_common_set_pins(i2c_bus_handle_t handle);
 
-/**
- * @brief Check whether I2C bus is occupied
- *
- * @param port_num I2C port number.
- * @return true: occupied, otherwise, false.
- */
-bool i2c_bus_occupied(i2c_port_num_t port_num);
-
 #ifdef __cplusplus
 }
 #endif

+ 424 - 0
components/driver/i2c/i2c_slave.c

@@ -0,0 +1,424 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <string.h>
+#include "esp_types.h"
+#include "esp_intr_alloc.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/task.h"
+#include "freertos/ringbuf.h"
+#include "freertos/queue.h"
+#include "hal/i2c_hal.h"
+#include "soc/i2c_periph.h"
+#include "esp_rom_gpio.h"
+#include "driver/gpio.h"
+#include "hal/gpio_ll.h"
+#include "clk_ctrl_os.h"
+#include "esp_private/esp_clk.h"
+#include "driver/i2c_slave.h"
+#include "i2c_private.h"
+#include "esp_memory_utils.h"
+#include "freertos/idf_additions.h"
+
+#if CONFIG_I2C_ENABLE_DEBUG_LOG
+// The local log level must be defined before including esp_log.h
+// Set the maximum log level for this source file
+#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
+#endif
+#include "esp_log.h"
+#include "esp_check.h"
+
+#define I2C_SLAVE_TIMEOUT_DEFAULT           (32000)     /* I2C slave timeout value, APB clock cycle number */
+#define I2C_FIFO_EMPTY_THRESH_VAL_DEFAULT   (SOC_I2C_FIFO_LEN/2)
+#define I2C_FIFO_FULL_THRESH_VAL_DEFAULT    (SOC_I2C_FIFO_LEN/2)
+
+static const char *TAG = "i2c.slave";
+
+static esp_err_t i2c_slave_bus_destroy(i2c_slave_dev_handle_t i2c_slave);
+
+#if SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE
+static IRAM_ATTR void s_i2c_handle_clock_stretch(i2c_slave_dev_handle_t i2c_slave)
+{
+    i2c_hal_context_t *hal = &i2c_slave->base->hal;
+    if (i2c_slave->callbacks.on_stretch_occur) {
+        i2c_slave_stretch_event_data_t evt = { 0 };
+        i2c_hal_context_t *hal = &i2c_slave->base->hal;
+        i2c_ll_slave_get_stretch_cause(hal->dev, &evt.stretch_cause);
+        i2c_slave->callbacks.on_stretch_occur(i2c_slave, &evt, i2c_slave->user_ctx);
+    }
+    i2c_ll_slave_clear_stretch(hal->dev);
+}
+#endif
+
+static IRAM_ATTR void s_i2c_handle_rx_fifo_wm(i2c_slave_dev_handle_t i2c_slave, i2c_slave_receive_t *t)
+{
+    i2c_hal_context_t *hal = &i2c_slave->base->hal;
+    uint32_t rx_fifo_cnt;
+    i2c_ll_get_rxfifo_cnt(hal->dev, &rx_fifo_cnt);
+    i2c_ll_read_rxfifo(hal->dev, i2c_slave->data_buf, rx_fifo_cnt);
+    memcpy(t->buffer + i2c_slave->already_receive_len, i2c_slave->data_buf, rx_fifo_cnt);
+    i2c_slave->already_receive_len += rx_fifo_cnt;
+    t->rcv_fifo_cnt -= rx_fifo_cnt;
+}
+
+static IRAM_ATTR void s_i2c_handle_complete(i2c_slave_dev_handle_t i2c_slave, i2c_slave_receive_t *t, BaseType_t *do_yield)
+{
+    i2c_hal_context_t *hal = &i2c_slave->base->hal;
+    uint32_t rx_fifo_cnt;
+    i2c_ll_get_rxfifo_cnt(hal->dev, &rx_fifo_cnt);
+    if (rx_fifo_cnt != 0) {
+        i2c_ll_read_rxfifo(hal->dev, i2c_slave->data_buf, t->rcv_fifo_cnt);
+        memcpy(t->buffer + i2c_slave->already_receive_len, i2c_slave->data_buf, t->rcv_fifo_cnt);
+        i2c_slave->already_receive_len += t->rcv_fifo_cnt;
+        t->rcv_fifo_cnt -= t->rcv_fifo_cnt;
+    }
+    if (i2c_slave->callbacks.on_recv_done) {
+
+        i2c_slave_rx_done_event_data_t edata = {
+            .buffer = t->buffer,
+        };
+        i2c_slave->callbacks.on_recv_done(i2c_slave, &edata, i2c_slave->user_ctx);
+        xSemaphoreGiveFromISR(i2c_slave->slv_rx_mux, do_yield);
+        i2c_ll_disable_intr_mask(hal->dev, I2C_LL_SLAVE_RX_EVENT_INTR);
+    }
+}
+
+static IRAM_ATTR void s_i2c_handle_tx_fifo_wm(i2c_slave_dev_handle_t i2c_slave, BaseType_t *do_yield)
+{
+    i2c_hal_context_t *hal = &i2c_slave->base->hal;
+    uint32_t tx_fifo_rem;
+    i2c_ll_get_txfifo_len(hal->dev, &tx_fifo_rem);
+    size_t size = 0;
+    uint8_t *data = (uint8_t *) xRingbufferReceiveUpToFromISR(i2c_slave->tx_ring_buf, &size, tx_fifo_rem);
+    if (data) {
+        i2c_ll_write_txfifo(hal->dev, data, size);
+        vRingbufferReturnItemFromISR(i2c_slave->tx_ring_buf, data, do_yield);
+    }
+    if (size <= i2c_slave->trans_data_length) {
+        portENTER_CRITICAL_ISR(&i2c_slave->base->spinlock);
+        i2c_slave->trans_data_length -= size;
+        portEXIT_CRITICAL_ISR(&i2c_slave->base->spinlock);
+        if (i2c_slave->trans_data_length == 0) {
+            i2c_ll_slave_disable_tx_it(hal->dev);
+        }
+    } else {
+        ESP_DRAM_LOGE(TAG, "I2C TX BUFFER SIZE ERROR");
+    }
+}
+
+static IRAM_ATTR void s_slave_fifo_isr_handler(uint32_t int_mask, void *arg, BaseType_t *do_yield)
+{
+    i2c_slave_dev_handle_t i2c_slave = (i2c_slave_dev_handle_t) arg;
+#if SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE
+    if (int_mask & I2C_INTR_STRETCH) {
+        s_i2c_handle_clock_stretch(i2c_slave);
+    }
+#endif
+    i2c_slave_receive_t *t = &i2c_slave->receive_desc;
+    if (int_mask & I2C_INTR_SLV_RXFIFO_WM) {
+        s_i2c_handle_rx_fifo_wm(i2c_slave, t);
+    }
+    if (int_mask & I2C_INTR_SLV_COMPLETE) {
+        s_i2c_handle_complete(i2c_slave, t, do_yield);
+    }
+    if (int_mask & I2C_INTR_SLV_TXFIFO_WM) {
+        s_i2c_handle_tx_fifo_wm(i2c_slave, do_yield);
+    }
+}
+
+static IRAM_ATTR void s_slave_nonfifo_isr_handler(uint32_t int_mask, void *arg, BaseType_t *do_yield)
+{
+    i2c_slave_dev_handle_t i2c_slave = (i2c_slave_dev_handle_t) arg;
+    i2c_hal_context_t *hal = &i2c_slave->base->hal;
+    if (int_mask & I2C_INTR_STRETCH) {
+        i2c_slave->slave_evt.slave_stretch = 1;
+        i2c_ll_slave_clear_stretch(hal->dev);
+    }
+
+    if (int_mask & I2C_INTR_SLV_COMPLETE) {
+        i2c_slave->slave_evt.trans_complete = 1;
+    }
+    xQueueSendFromISR(i2c_slave->slv_evt_queue, &i2c_slave->slave_evt, do_yield);
+}
+
+static IRAM_ATTR void s_slave_isr_handle_default(void *arg)
+{
+    i2c_slave_dev_handle_t i2c_slave = (i2c_slave_dev_handle_t) arg;
+    i2c_hal_context_t *hal = &i2c_slave->base->hal;
+    portBASE_TYPE HPTaskAwoken = pdFALSE;
+    uint32_t int_mask = 0;
+
+    i2c_ll_get_intr_mask(hal->dev, &int_mask);
+    i2c_ll_clear_intr_mask(hal->dev, int_mask);
+    if (int_mask == 0) {
+        return;
+    }
+#if SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH
+    if (int_mask & I2C_INTR_UNMATCH) {
+        i2c_slave->slave_evt.addr_unmatch = 1;
+        ESP_DRAM_LOGE(TAG, "I2C address not match, trans failed");
+    }
+#endif
+
+    if (i2c_slave->fifo_mode == I2C_SLAVE_NONFIFO) {
+        s_slave_nonfifo_isr_handler(int_mask, i2c_slave, &HPTaskAwoken);
+    } else {
+        s_slave_fifo_isr_handler(int_mask, i2c_slave, &HPTaskAwoken);
+    }
+
+    //We only need to check here if there is a high-priority task needs to be switched.
+    if (HPTaskAwoken == pdTRUE) {
+        portYIELD_FROM_ISR();
+    }
+
+}
+
+esp_err_t i2c_new_slave_device(const i2c_slave_config_t *slave_config, i2c_slave_dev_handle_t *ret_handle)
+{
+#if CONFIG_I2C_ENABLE_DEBUG_LOG
+    esp_log_level_set(TAG, ESP_LOG_DEBUG);
+#endif
+    esp_err_t ret = ESP_OK;
+    i2c_slave_dev_t *i2c_slave = NULL;
+    ESP_RETURN_ON_FALSE(slave_config && ret_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
+    ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(slave_config->sda_io_num) && GPIO_IS_VALID_GPIO(slave_config->scl_io_num), ESP_ERR_INVALID_ARG, TAG, "invalid SDA/SCL pin number");
+    ESP_RETURN_ON_FALSE(slave_config->i2c_port < SOC_I2C_NUM || slave_config->i2c_port == -1, ESP_ERR_INVALID_ARG, TAG, "invalid i2c port number");
+    ESP_RETURN_ON_FALSE((slave_config->send_buf_depth > 0), ESP_ERR_INVALID_ARG, TAG, "invalid SCL speed");
+#if SOC_I2C_SLAVE_SUPPORT_BROADCAST
+    ESP_GOTO_ON_FALSE(((slave_config->addr_bit_len != I2C_ADDR_BIT_LEN_10) || (!slave_config->flags.broadcast_en)), ESP_ERR_INVALID_STATE, err, TAG, "10bits address cannot used together with broadcast");
+#endif
+
+    int i2c_port_num = slave_config->i2c_port;
+    i2c_slave = heap_caps_calloc(1, sizeof(i2c_slave_dev_t), I2C_MEM_ALLOC_CAPS);
+    ESP_RETURN_ON_FALSE(i2c_slave, ESP_ERR_NO_MEM, TAG, "no memory for i2c slave bus");
+
+    ESP_GOTO_ON_ERROR(i2c_acquire_bus_handle(i2c_port_num, &i2c_slave->base, I2C_BUS_MODE_SLAVE), err, TAG, "I2C bus acquire failed");
+
+    i2c_hal_context_t *hal = &i2c_slave->base->hal;
+    i2c_slave->base->scl_num = slave_config->scl_io_num;
+    i2c_slave->base->sda_num = slave_config->sda_io_num;
+#if SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS
+    i2c_slave->fifo_mode = (slave_config->flags.access_ram_en == true) ? I2C_SLAVE_NONFIFO : I2C_SLAVE_FIFO;
+#endif
+
+#if SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH
+    if (slave_config->flags.slave_unmatch_en) {
+        i2c_ll_enable_intr_mask(hal->dev, I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M);
+    }
+#endif
+
+    ESP_GOTO_ON_ERROR(i2c_common_set_pins(i2c_slave->base), err, TAG, "i2c slave set pins failed");
+
+    i2c_slave->tx_ring_buf = xRingbufferCreateWithCaps(slave_config->send_buf_depth, RINGBUF_TYPE_BYTEBUF, I2C_MEM_ALLOC_CAPS);
+    ESP_GOTO_ON_FALSE(i2c_slave->tx_ring_buf != NULL, ESP_ERR_INVALID_STATE, err, TAG, "ringbuffer create failed");
+
+    i2c_slave->slv_rx_mux = xSemaphoreCreateBinaryWithCaps(I2C_MEM_ALLOC_CAPS);
+    ESP_GOTO_ON_FALSE(i2c_slave->slv_rx_mux, ESP_ERR_NO_MEM, err, TAG, "No memory for binary semaphore");
+    i2c_slave->slv_tx_mux = xSemaphoreCreateBinaryWithCaps(I2C_MEM_ALLOC_CAPS);
+    ESP_GOTO_ON_FALSE(i2c_slave->slv_tx_mux, ESP_ERR_NO_MEM, err, TAG, "No memory for binary semaphore");
+    i2c_slave->slv_evt_queue = xQueueCreateWithCaps(1, sizeof(i2c_slave_evt_t), I2C_MEM_ALLOC_CAPS);
+    ESP_GOTO_ON_FALSE((i2c_slave->slv_evt_queue != NULL), ESP_ERR_INVALID_STATE, err, TAG, "queue create failed");
+
+    int isr_flags = I2C_INTR_ALLOC_FLAG;
+    if (slave_config->intr_priority) {
+        isr_flags |= 1 << (slave_config->intr_priority);
+    }
+    ret = esp_intr_alloc_intrstatus(i2c_periph_signal[i2c_port_num].irq, I2C_INTR_ALLOC_FLAG, (uint32_t)i2c_ll_get_interrupt_status_reg(hal->dev), I2C_LL_SLAVE_EVENT_INTR, s_slave_isr_handle_default, i2c_slave, &i2c_slave->base->intr_handle);
+    ESP_GOTO_ON_ERROR(ret, err, TAG, "install i2c slave interrupt failed");
+
+    portENTER_CRITICAL(&i2c_slave->base->spinlock);
+    i2c_ll_clear_intr_mask(hal->dev, I2C_LL_SLAVE_EVENT_INTR);
+    i2c_hal_slave_init(hal);
+
+#if SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS
+    if (i2c_slave->fifo_mode == I2C_SLAVE_NONFIFO) {
+        i2c_ll_slave_set_fifo_mode(hal->dev, false);
+        i2c_ll_enable_mem_access_nonfifo(hal->dev, true);
+    } else {
+        i2c_ll_slave_set_fifo_mode(hal->dev, true);
+        i2c_ll_enable_mem_access_nonfifo(hal->dev, false);
+    }
+#endif
+
+    //Default, we enable hardware filter
+    i2c_ll_set_source_clk(hal->dev, slave_config->clk_source);
+    bool addr_10bit_en = slave_config->addr_bit_len != I2C_ADDR_BIT_LEN_7;
+    i2c_ll_set_slave_addr(hal->dev, slave_config->slave_addr, addr_10bit_en);
+#if SOC_I2C_SLAVE_SUPPORT_BROADCAST
+    i2c_ll_slave_broadcast_enable(hal->dev, slave_config->flags.broadcast_en);
+#endif
+    i2c_ll_set_txfifo_empty_thr(hal->dev, I2C_FIFO_EMPTY_THRESH_VAL_DEFAULT);
+    i2c_ll_set_rxfifo_full_thr(hal->dev, I2C_FIFO_FULL_THRESH_VAL_DEFAULT);
+    // set timing for data
+    i2c_ll_set_sda_timing(hal->dev, 10, 10);
+    i2c_ll_set_tout(hal->dev, I2C_SLAVE_TIMEOUT_DEFAULT);
+
+#if SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE
+    i2c_ll_slave_enable_scl_stretch(hal->dev, slave_config->flags.stretch_en);
+#endif
+    i2c_ll_slave_tx_auto_start_en(hal->dev, true);
+
+    i2c_ll_update(hal->dev);
+    portEXIT_CRITICAL(&i2c_slave->base->spinlock);
+
+    xSemaphoreGive(i2c_slave->slv_rx_mux);
+    xSemaphoreGive(i2c_slave->slv_tx_mux);
+    *ret_handle = i2c_slave;
+    return ESP_OK;
+
+err:
+    if (i2c_slave) {
+        i2c_slave_bus_destroy(i2c_slave);
+    }
+    return ret;
+}
+
+static esp_err_t i2c_slave_bus_destroy(i2c_slave_dev_handle_t i2c_slave)
+{
+    if (i2c_slave) {
+        if (i2c_slave->slv_rx_mux) {
+            vSemaphoreDeleteWithCaps(i2c_slave->slv_rx_mux);
+            i2c_slave->slv_rx_mux = NULL;
+        }
+        if (i2c_slave->slv_tx_mux) {
+            vSemaphoreDeleteWithCaps(i2c_slave->slv_tx_mux);
+            i2c_slave->slv_tx_mux = NULL;
+        }
+        if (i2c_slave->tx_ring_buf) {
+            vRingbufferDeleteWithCaps(i2c_slave->tx_ring_buf);
+            i2c_slave->tx_ring_buf = NULL;
+        }
+        if (i2c_slave->slv_evt_queue) {
+            vQueueDeleteWithCaps(i2c_slave->slv_evt_queue);
+        }
+        i2c_release_bus_handle(i2c_slave->base);
+    }
+
+    free(i2c_slave);
+    return ESP_OK;
+}
+
+esp_err_t i2c_del_slave_device(i2c_slave_dev_handle_t i2c_slave)
+{
+    ESP_RETURN_ON_FALSE(i2c_slave, ESP_ERR_INVALID_ARG, TAG, "i2c slave not initialized");
+    int port_id = i2c_slave->base->port_num;
+    ESP_LOGD(TAG, "del i2c bus(%d)", port_id);
+    ESP_RETURN_ON_ERROR(i2c_slave_bus_destroy(i2c_slave), TAG, "destroy i2c bus failed");
+    return ESP_OK;
+}
+
+esp_err_t i2c_slave_transmit(i2c_slave_dev_handle_t i2c_slave, const uint8_t *data, int size, int xfer_timeout_ms)
+{
+    ESP_RETURN_ON_FALSE(i2c_slave, ESP_ERR_INVALID_ARG, TAG, "i2c slave not initialized");
+    ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "invalid data buffer");
+    ESP_RETURN_ON_FALSE((i2c_slave->fifo_mode == I2C_SLAVE_FIFO), ESP_ERR_NOT_SUPPORTED, TAG, "non-fifo mode is not suppored in this API, please set access_ram_en to false");
+    esp_err_t ret = ESP_OK;
+    i2c_hal_context_t *hal = &i2c_slave->base->hal;
+    TickType_t wait_ticks = (xfer_timeout_ms == -1) ? portMAX_DELAY : pdMS_TO_TICKS(xfer_timeout_ms);
+
+    ESP_RETURN_ON_FALSE(xSemaphoreTake(i2c_slave->slv_tx_mux, wait_ticks) == pdTRUE, ESP_ERR_TIMEOUT, TAG, "transmit timeout");
+    ESP_GOTO_ON_FALSE(xRingbufferSend(i2c_slave->tx_ring_buf, data, size, wait_ticks) == pdTRUE, ESP_ERR_INVALID_STATE, err, TAG, "no space in ringbuffer");
+    portENTER_CRITICAL(&i2c_slave->base->spinlock);
+    i2c_slave->trans_data_length += size;
+    i2c_ll_enable_intr_mask(hal->dev, I2C_LL_SLAVE_TX_EVENT_INTR);
+    portEXIT_CRITICAL(&i2c_slave->base->spinlock);
+err:
+    xSemaphoreGive(i2c_slave->slv_tx_mux);
+    return ret;
+}
+
+esp_err_t i2c_slave_receive(i2c_slave_dev_handle_t i2c_slave, uint8_t *data, size_t receive_size)
+{
+    ESP_RETURN_ON_FALSE(i2c_slave, ESP_ERR_INVALID_ARG, TAG, "i2c slave not initialized");
+    ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "invalid data buffer");
+    ESP_RETURN_ON_FALSE((i2c_slave->fifo_mode == I2C_SLAVE_FIFO), ESP_ERR_NOT_SUPPORTED, TAG, "non-fifo mode is not suppored in this API, please set access_ram_en to false");
+#if CONFIG_I2C_ISR_IRAM_SAFE
+    ESP_RETURN_ON_FALSE(esp_ptr_internal(data), ESP_ERR_INVALID_ARG, TAG, "buffer must locate in internal RAM if IRAM_SAFE is enabled");
+#endif
+    i2c_hal_context_t *hal = &i2c_slave->base->hal;
+
+    xSemaphoreTake(i2c_slave->slv_rx_mux, portMAX_DELAY);
+    i2c_slave_receive_t *t = &i2c_slave->receive_desc;
+    t->buffer = data;
+    t->rcv_fifo_cnt = receive_size;
+    i2c_slave->already_receive_len = 0;
+    // Clear all interrupt raw bits before enable, avoid previous bus data affects interrupt.
+    i2c_ll_clear_intr_mask(hal->dev, I2C_LL_SLAVE_RX_EVENT_INTR);
+    i2c_ll_enable_intr_mask(hal->dev, I2C_LL_SLAVE_RX_EVENT_INTR);
+
+    return ESP_OK;
+}
+
+#if SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS
+
+esp_err_t i2c_slave_read_ram(i2c_slave_dev_handle_t i2c_slave, uint8_t ram_offset, uint8_t *data, size_t receive_size)
+{
+    ESP_RETURN_ON_FALSE(i2c_slave, ESP_ERR_INVALID_ARG, TAG, "i2c slave not initialized");
+    ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "invalid data buffer");
+    ESP_RETURN_ON_FALSE((ram_offset + receive_size <=  SOC_I2C_FIFO_LEN), ESP_ERR_INVALID_SIZE, TAG, "don't read data cross fifo boundary, see `SOC_I2C_FIFO_LEN`");
+    ESP_RETURN_ON_FALSE((i2c_slave->fifo_mode == I2C_SLAVE_NONFIFO), ESP_ERR_NOT_SUPPORTED, TAG, "fifo mode is not suppored in this API, please set access_ram_en to true");
+    i2c_hal_context_t *hal = &i2c_slave->base->hal;
+
+    uint32_t fifo_size = 0;
+    portENTER_CRITICAL(&i2c_slave->base->spinlock);
+    i2c_ll_get_rxfifo_cnt(hal->dev, &fifo_size);
+    if (receive_size > fifo_size) {
+        ESP_LOGE(TAG, "receive size is so large that fifo has not so much data to get");
+        portEXIT_CRITICAL(&i2c_slave->base->spinlock);
+        return ESP_ERR_INVALID_SIZE;
+    }
+    i2c_ll_read_by_nonfifo(hal->dev, ram_offset, data, fifo_size);
+    portEXIT_CRITICAL(&i2c_slave->base->spinlock);
+
+    return ESP_OK;
+}
+
+esp_err_t i2c_slave_write_ram(i2c_slave_dev_handle_t i2c_slave, uint8_t ram_offset, const uint8_t *data, size_t size)
+{
+    ESP_RETURN_ON_FALSE(i2c_slave, ESP_ERR_INVALID_ARG, TAG, "i2c slave not initialized");
+    ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "invalid data buffer");
+    ESP_RETURN_ON_FALSE((i2c_slave->fifo_mode == I2C_SLAVE_NONFIFO), ESP_ERR_NOT_SUPPORTED, TAG, "fifo mode is not suppored in this API, please set access_ram_en to true");
+
+    i2c_hal_context_t *hal = &i2c_slave->base->hal;
+    ESP_RETURN_ON_FALSE(xSemaphoreTake(i2c_slave->slv_tx_mux, portMAX_DELAY) == pdTRUE, ESP_ERR_TIMEOUT, TAG, "write to ram lock timeout");
+    uint32_t fifo_size = 0;
+    i2c_ll_txfifo_rst(hal->dev);
+    i2c_ll_get_txfifo_len(hal->dev, &fifo_size);
+    if (ram_offset + fifo_size < size) {
+        ESP_EARLY_LOGE(TAG, "No extra fifo to fill your buffer, please split your buffer");
+        return ESP_ERR_INVALID_SIZE;
+    }
+    i2c_ll_write_by_nonfifo(hal->dev, ram_offset, data, size);
+    xSemaphoreGive(i2c_slave->slv_tx_mux);
+    return ESP_OK;
+}
+
+#endif
+
+esp_err_t i2c_slave_register_event_callbacks(i2c_slave_dev_handle_t i2c_slave, const i2c_slave_event_callbacks_t *cbs, void *user_data)
+{
+    ESP_RETURN_ON_FALSE(i2c_slave != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c slave handle not initialized");
+    ESP_RETURN_ON_FALSE(cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
+
+#if CONFIG_I2C_ISR_IRAM_SAFE
+#if SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE
+    if (cbs->on_stretch_occur) {
+        ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_stretch_occur), ESP_ERR_INVALID_ARG, TAG, "i2c stretch occur callback not in IRAM");
+    }
+#endif // SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE
+    if (cbs->on_recv_done) {
+        ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_recv_done), ESP_ERR_INVALID_ARG, TAG, "i2c receive done callback not in IRAM");
+    }
+    if (user_data) {
+        ESP_RETURN_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM");
+    }
+#endif // CONFIG_I2C_ISR_IRAM_SAFE
+
+    memcpy(&(i2c_slave->callbacks), cbs, sizeof(i2c_slave_event_callbacks_t));
+    i2c_slave->user_ctx = user_data;
+    return ESP_OK;
+}

+ 3 - 3
components/driver/i2c/include/driver/i2c_master.h

@@ -109,7 +109,7 @@ esp_err_t i2c_master_bus_rm_device(i2c_master_dev_handle_t handle);
  * @param[in] xfer_timeout_ms Wait timeout, in ms. Note: -1 means wait forever.
  * @return
  *      - ESP_OK: I2C master transmit success
- *      - ESP_ERR_INVALID_ARG: I2c master transmit parameter invalid.
+ *      - ESP_ERR_INVALID_ARG: I2C master transmit parameter invalid.
  *      - ESP_ERR_TIMEOUT: Operation timeout(larger than xfer_timeout_ms) because the bus is busy or hardware crash.
  */
 esp_err_t i2c_master_transmit(i2c_master_dev_handle_t i2c_dev, const uint8_t *write_buffer, size_t write_size, int xfer_timeout_ms);
@@ -130,7 +130,7 @@ esp_err_t i2c_master_transmit(i2c_master_dev_handle_t i2c_dev, const uint8_t *wr
  * @param[in] xfer_timeout_ms Wait timeout, in ms. Note: -1 means wait forever.
  * @return
  *      - ESP_OK: I2C master transmit-receive success
- *      - ESP_ERR_INVALID_ARG: I2c master transmit parameter invalid.
+ *      - ESP_ERR_INVALID_ARG: I2C master transmit parameter invalid.
  *      - ESP_ERR_TIMEOUT: Operation timeout(larger than xfer_timeout_ms) because the bus is busy or hardware crash.
  */
 esp_err_t i2c_master_transmit_receive(i2c_master_dev_handle_t i2c_dev, const uint8_t *write_buffer, size_t write_size, uint8_t *read_buffer, size_t read_size, int xfer_timeout_ms);
@@ -149,7 +149,7 @@ esp_err_t i2c_master_transmit_receive(i2c_master_dev_handle_t i2c_dev, const uin
  * @param[in] xfer_timeout_ms Wait timeout, in ms. Note: -1 means wait forever.
  * @return
  *      - ESP_OK: I2C master receive success
- *      - ESP_ERR_INVALID_ARG: I2c master receive parameter invalid.
+ *      - ESP_ERR_INVALID_ARG: I2C master receive parameter invalid.
  *      - ESP_ERR_TIMEOUT: Operation timeout(larger than xfer_timeout_ms) because the bus is busy or hardware crash.
  */
 esp_err_t i2c_master_receive(i2c_master_dev_handle_t i2c_dev, uint8_t *read_buffer, size_t read_size, int xfer_timeout_ms);

+ 166 - 0
components/driver/i2c/include/driver/i2c_slave.h

@@ -0,0 +1,166 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#pragma once
+
+#include <stdint.h>
+#include "esp_err.h"
+#include "driver/i2c_types.h"
+#include "hal/gpio_types.h"
+#include "soc/soc_caps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief I2C slave specific configurations
+ */
+typedef struct {
+    i2c_port_num_t i2c_port;                 /*!< I2C port number, `-1` for auto selecting */
+    gpio_num_t sda_io_num;                   /*!< SDA IO number used by I2C bus */
+    gpio_num_t scl_io_num;                   /*!< SCL IO number used by I2C bus */
+    i2c_clock_source_t clk_source;           /*!< Clock source of I2C bus. */
+    uint32_t send_buf_depth;                 /*!< Depth of internal transfer ringbuffer, increase this value can support more transfers pending in the background */
+    uint16_t slave_addr;                     /*!< I2C slave address */
+    i2c_addr_bit_len_t addr_bit_len;         /*!< I2C slave address in bit length */
+    int intr_priority;                       /*!< I2C interrupt priority, if set to 0, driver will select the default priority (1,2,3). */
+    struct {
+#if SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE
+        uint32_t stretch_en:1;               /*!< Enable slave stretch */
+#endif
+#if SOC_I2C_SLAVE_SUPPORT_BROADCAST
+        uint32_t broadcast_en:1;             /*!< I2C slave enable broadcast */
+#endif
+#if SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS
+        uint32_t access_ram_en:1;            /*!< Can get access to I2C RAM directly */
+#endif
+#if SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH
+        uint32_t slave_unmatch_en:1;         /*!< Can trigger unmatch interrupt when slave address does not match what master sends*/
+#endif
+    } flags;
+} i2c_slave_config_t;
+
+/**
+ * @brief Group of I2C slave callbacks (e.g. get i2c slave stretch cause). But take care of potential concurrency issues.
+ * @note The callbacks are all running under ISR context
+ * @note When CONFIG_I2C_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
+ *       The variables used in the function should be in the SRAM as well.
+ */
+typedef struct {
+#if SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE
+    i2c_slave_stretch_callback_t on_stretch_occur;  /*!< I2C slave stretched callback */
+#endif
+    i2c_slave_received_callback_t on_recv_done;   /*!< I2C slave receive done callback */
+} i2c_slave_event_callbacks_t;
+
+/**
+ * @brief Initialize an I2C slave device
+ *
+ * @param[in] slave_config I2C slave device configurations
+ * @param[out] ret_handle Return a generic I2C device handle
+ * @return
+ *      - ESP_OK: I2C slave device initialized successfully
+ *      - ESP_ERR_INVALID_ARG: I2C device initialization failed because of invalid argument.
+ *      - ESP_ERR_NO_MEM: Create I2C device failed because of out of memory.
+ */
+esp_err_t i2c_new_slave_device(const i2c_slave_config_t *slave_config, i2c_slave_dev_handle_t *ret_handle);
+
+/**
+ * @brief Deinitialize the I2C slave device
+ *
+ * @param[in] i2c_slave I2C slave device handle that created by `i2c_new_slave_device`.
+ * @return
+ *      - ESP_OK: Delete I2C device successfully.
+ *      - ESP_ERR_INVALID_ARG: I2C device initialization failed because of invalid argument.
+ */
+esp_err_t i2c_del_slave_device(i2c_slave_dev_handle_t i2c_slave);
+
+/**
+ * @brief Read bytes from I2C internal buffer. Start a job to receive I2C data.
+ *
+ * @note This function is non-blocking, it initiates a new receive job and then returns.
+ *       User should check the received data from the `on_recv_done` callback that registered by `i2c_slave_register_event_callbacks()`.
+ *
+ * @param[in] i2c_slave I2C slave device handle that created by `i2c_new_slave_device`.
+ * @param[out] data Buffer to store data from I2C fifo. Should be valid until `on_recv_done` is triggered.
+ * @param[in] buffer_size Buffer size of data that provided by users.
+ * @return
+ *      - ESP_OK: I2C slave receive success.
+ *      - ESP_ERR_INVALID_ARG: I2C slave receive parameter invalid.
+ *      - ESP_ERR_NOT_SUPPORTED: This function should be work in fifo mode, but I2C_SLAVE_NONFIFO mode is configured
+ */
+esp_err_t i2c_slave_receive(i2c_slave_dev_handle_t i2c_slave, uint8_t *data, size_t buffer_size);
+
+/**
+ * @brief Write bytes to internal ringbuffer of the I2C slave data. When the TX fifo empty, the ISR will
+ *        fill the hardware FIFO with the internal ringbuffer's data.
+ *
+ * @note If you connect this slave device to some master device, the data transaction direction is from slave
+ *       device to master device.
+ *
+ * @param[in] i2c_slave I2C slave device handle that created by `i2c_new_slave_device`.
+ * @param[in] data Buffer to write to slave fifo, can pickup by master. Can be freed after this function returns. Equal or larger than `size`.
+ * @param[in] size In bytes, of `data` buffer.
+ * @param[in] xfer_timeout_ms Wait timeout, in ms. Note: -1 means wait forever.
+ * @return
+ *      - ESP_OK: I2C slave transmit success.
+ *      - ESP_ERR_INVALID_ARG: I2C slave transmit parameter invalid.
+ *      - ESP_ERR_TIMEOUT: Operation timeout(larger than xfer_timeout_ms) because the device is busy or hardware crash.
+ *      - ESP_ERR_NOT_SUPPORTED: This function should be work in fifo mode, but I2C_SLAVE_NONFIFO mode is configured
+ */
+esp_err_t i2c_slave_transmit(i2c_slave_dev_handle_t i2c_slave, const uint8_t *data, int size, int xfer_timeout_ms);
+
+/**
+ * @brief Set I2C slave event callbacks for I2C slave channel.
+ *
+ * @note User can deregister a previously registered callback by calling this function and setting the callback member in the `cbs` structure to NULL.
+ * @note When CONFIG_I2C_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
+ *       The variables used in the function should be in the SRAM as well. The `user_data` should also reside in SRAM.
+ *
+ * @param[in] i2c_slave I2C slave device handle that created by `i2c_new_slave_device`.
+ * @param[in] cbs Group of callback functions
+ * @param[in] user_data User data, which will be passed to callback functions directly
+ * @return
+ *      - ESP_OK: Set I2C transaction callbacks successfully
+ *      - ESP_ERR_INVALID_ARG: Set I2C transaction callbacks failed because of invalid argument
+ *      - ESP_FAIL: Set I2C transaction callbacks failed because of other error
+ */
+esp_err_t i2c_slave_register_event_callbacks(i2c_slave_dev_handle_t i2c_slave, const i2c_slave_event_callbacks_t *cbs, void *user_data);
+
+#if SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS
+/**
+ * @brief Read bytes from I2C internal ram. This can be only used when `access_ram_en` in configuration structure set to true.
+ *
+ * @param[in] i2c_slave I2C slave device handle that created by `i2c_new_slave_device`.
+ * @param[in] ram_address The offset of RAM (Cannot larger than I2C RAM memory)
+ * @param[out] data Buffer to store data read from I2C ram.
+ * @param[in] receive_size Received size from RAM.
+ * @return
+ *      - ESP_OK: I2C slave transmit success.
+ *      - ESP_ERR_INVALID_ARG: I2C slave transmit parameter invalid.
+ *      - ESP_ERR_NOT_SUPPORTED: This function should be work in non-fifo mode, but I2C_SLAVE_FIFO mode is configured
+ */
+esp_err_t i2c_slave_read_ram(i2c_slave_dev_handle_t i2c_slave, uint8_t ram_address, uint8_t *data, size_t receive_size);
+
+/**
+ * @brief Write bytes to I2C internal ram. This can be only used when `access_ram_en` in configuration structure set to true.
+ *
+ * @param[in] i2c_slave I2C slave device handle that created by `i2c_new_slave_device`.
+ * @param[in] ram_address The offset of RAM (Cannot larger than I2C RAM memory)
+ * @param[in] data Buffer to fill.
+ * @param[in] size Received size from RAM.
+ * @return
+ *      - ESP_OK: I2C slave transmit success.
+ *      - ESP_ERR_INVALID_ARG: I2C slave transmit parameter invalid.
+ *      - ESP_ERR_INVALID_SIZE: Write size is larger than
+ *      - ESP_ERR_NOT_SUPPORTED: This function should be work in non-fifo mode, but I2C_SLAVE_FIFO mode is configured
+ */
+esp_err_t i2c_slave_write_ram(i2c_slave_dev_handle_t i2c_slave, uint8_t ram_address, const uint8_t *data, size_t size);
+
+#endif
+#ifdef __cplusplus
+}
+#endif

+ 45 - 0
components/driver/i2c/include/driver/i2c_types.h

@@ -51,6 +51,11 @@ typedef struct i2c_master_bus_t *i2c_master_bus_handle_t;
  */
 typedef struct i2c_master_dev_t *i2c_master_dev_handle_t;
 
+/**
+ * @brief Type of I2C slave device handle
+ */
+typedef struct i2c_slave_dev_t *i2c_slave_dev_handle_t;
+
 /**
  * @brief Data type used in I2C event callback
  */
@@ -69,6 +74,46 @@ typedef struct {
  */
 typedef bool (*i2c_master_callback_t)(i2c_master_dev_handle_t i2c_dev, const i2c_master_event_data_t *evt_data, void *arg);
 
+/**
+ * @brief Event structure used in I2C slave
+ */
+typedef struct {
+    uint8_t *buffer;
+} i2c_slave_rx_done_event_data_t;
+
+/**
+ * @brief Callback signature for I2C slave.
+ *
+ * @param[in]  i2c_slave Handle for I2C slave.
+ * @param[out] evt_data I2C capture event data, fed by driver
+ * @param[in]  user_ctx User data, set in `i2c_slave_register_event_callbacks()`
+ *
+ * @return Whether a high priority task has been waken up by this function
+ */
+typedef bool (*i2c_slave_received_callback_t)(i2c_slave_dev_handle_t i2c_slave, const i2c_slave_rx_done_event_data_t *evt_data, void *arg);
+
+#if SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE
+
+/**
+ * @brief Stretch cause event structure used in I2C slave
+ */
+typedef struct {
+    i2c_slave_stretch_cause_t stretch_cause;
+} i2c_slave_stretch_event_data_t;
+
+/**
+ * @brief Callback signature for I2C slave stretch.
+ *
+ * @param[in]  i2c_slave Handle for I2C slave.
+ * @param[out] evt_cause I2C capture event cause, fed by driver
+ * @param[in]  user_ctx User data, set in `i2c_slave_register_event_callbacks()`
+ *
+ * @return Whether a high priority task has been waken up by this function
+ */
+typedef bool (*i2c_slave_stretch_callback_t)(i2c_slave_dev_handle_t i2c_slave, const i2c_slave_stretch_event_data_t *evt_cause, void *arg);
+
+#endif
+
 #ifdef __cplusplus
 }
 #endif

+ 15 - 9
components/hal/esp32/include/hal/i2c_ll.h

@@ -45,24 +45,29 @@ typedef union {
 #define I2C_LL_CMD_END        4    /*!<I2C end command */
 
 typedef enum {
-    I2C_LL_INTR_TXFIFO_WM = (1 << 1),
-    I2C_LL_INTR_RXFIFO_WM = (1 << 0),
+    I2C_INTR_MST_TXFIFO_WM = (1 << 1),
+    I2C_INTR_MST_RXFIFO_WM = (1 << 11),
     I2C_LL_INTR_NACK = (1 << 10),
     I2C_LL_INTR_TIMEOUT = (1 << 8),
     I2C_LL_INTR_MST_COMPLETE = (1 << 7),
     I2C_LL_INTR_ARBITRATION = (1 << 5),
     I2C_LL_INTR_END_DETECT = (1 << 3),
     I2C_LL_INTR_ST_TO = (1 << 13),
-    I2C_LL_INTR_START = (1 << 15),
-    I2C_LL_INTR_STRETCH = (1 << 16),
-    I2C_LL_INTR_UNMATCH = (1 << 18),
-} i2c_ll_intr_t;
+} i2c_ll_master_intr_t;
+
+typedef enum {
+    I2C_INTR_SLV_TXFIFO_WM = (1 << 1),
+    I2C_INTR_SLV_RXFIFO_WM = (1 << 11),
+    I2C_INTR_SLV_COMPLETE = (1 << 7),
+    I2C_INTR_START = (1 << 15),
+    I2C_INTR_STRETCH = (1 << 16),
+} i2c_ll_slave_intr_t;
 
 // Get the I2C hardware instance
 #define I2C_LL_GET_HW(i2c_num)        (((i2c_num) == 0) ? &I2C0 : &I2C1)
 #define I2C_LL_MASTER_EVENT_INTR    (I2C_ACK_ERR_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
-#define I2C_LL_SLAVE_EVENT_INTR     (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_EMPTY_INT_ENA_M)
-#define I2C_LL_SLAVE_RX_EVENT_INTR  (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_RXFIFO_FULL_INT_ENA_M)
+#define I2C_LL_SLAVE_EVENT_INTR     (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_EMPTY_INT_ENA_M|I2C_RX_REC_FULL_INT_ST_M)
+#define I2C_LL_SLAVE_RX_EVENT_INTR  (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_RX_REC_FULL_INT_ST_M)
 #define I2C_LL_SLAVE_TX_EVENT_INTR  (I2C_TXFIFO_EMPTY_INT_ENA_M)
 
 /**
@@ -277,7 +282,7 @@ static inline void i2c_ll_set_slave_addr(i2c_dev_t *hw, uint16_t slave_addr, boo
 {
     hw->slave_addr.en_10bit = addr_10bit_en;
     if (addr_10bit_en) {
-        uint8_t addr_14_7 = (slave_addr & 0xff) << 7;
+        uint16_t addr_14_7 = (slave_addr & 0xff) << 7;
         uint8_t addr_6_0 = ((slave_addr & 0x300) >> 8) || 0x78;
         hw->slave_addr.addr = addr_14_7 || addr_6_0;
     } else {
@@ -368,6 +373,7 @@ static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr)
  */
 static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr)
 {
+    hw->fifo_conf.nonfifo_rx_thres = full_thr;
     hw->fifo_conf.rx_fifo_full_thrhd = full_thr;
 }
 

+ 2 - 8
components/hal/esp32c2/include/hal/i2c_ll.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -47,23 +47,17 @@ typedef union {
 #define I2C_LL_CMD_END        4    /*!<I2C end command */
 
 typedef enum {
-    I2C_LL_INTR_TXFIFO_WM = (1 << 1),
-    I2C_LL_INTR_RXFIFO_WM = (1 << 0),
     I2C_LL_INTR_NACK = (1 << 10),
     I2C_LL_INTR_TIMEOUT = (1 << 8),
     I2C_LL_INTR_MST_COMPLETE = (1 << 7),
     I2C_LL_INTR_ARBITRATION = (1 << 5),
     I2C_LL_INTR_END_DETECT = (1 << 3),
     I2C_LL_INTR_ST_TO = (1 << 13),
-    I2C_LL_INTR_START = (1 << 15),
-    I2C_LL_INTR_STRETCH = (1 << 16),
-    I2C_LL_INTR_UNMATCH = (1 << 18),
-} i2c_ll_intr_t;
+} i2c_ll_master_intr_t;
 
 // Get the I2C hardware instance
 #define I2C_LL_GET_HW(i2c_num)        (&I2C0)
 #define I2C_LL_MASTER_EVENT_INTR    (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
-#define I2C_LL_SLAVE_EVENT_INTR     0
 #define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT   (9)
 
 /**

+ 42 - 11
components/hal/esp32c3/include/hal/i2c_ll.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -49,24 +49,23 @@ typedef union {
 #define I2C_LL_CMD_END        4    /*!<I2C end command */
 
 typedef enum {
-    I2C_LL_INTR_TXFIFO_WM = (1 << 1),
-    I2C_LL_INTR_RXFIFO_WM = (1 << 0),
+    I2C_INTR_MST_TXFIFO_WM = (1 << 1),
+    I2C_INTR_MST_RXFIFO_WM = (1 << 0),
     I2C_LL_INTR_NACK = (1 << 10),
     I2C_LL_INTR_TIMEOUT = (1 << 8),
     I2C_LL_INTR_MST_COMPLETE = (1 << 7),
     I2C_LL_INTR_ARBITRATION = (1 << 5),
     I2C_LL_INTR_END_DETECT = (1 << 3),
     I2C_LL_INTR_ST_TO = (1 << 13),
-    I2C_LL_INTR_START = (1 << 15),
-    I2C_LL_INTR_STRETCH = (1 << 16),
-    I2C_LL_INTR_UNMATCH = (1 << 18),
-} i2c_ll_intr_t;
+} i2c_ll_master_intr_t;
 
 typedef enum {
-    I2C_LL_STRETCH_REASON_MASTER_START = 0,
-    I2C_LL_STRETCH_REASON_TX_EMPTY = 1,
-    I2C_LL_STRETCH_REASON_RX_FULL = 2,
-} i2c_ll_stretch_cause_t;
+    I2C_INTR_SLV_TXFIFO_WM = (1 << 1),
+    I2C_INTR_SLV_RXFIFO_WM = (1 << 0),
+    I2C_INTR_SLV_COMPLETE = (1 << 7),
+    I2C_INTR_START = (1 << 15),
+    I2C_INTR_STRETCH = (1 << 16),
+} i2c_ll_slave_intr_t;
 
 // Get the I2C hardware instance
 #define I2C_LL_GET_HW(i2c_num)        (&I2C0)
@@ -295,6 +294,37 @@ static inline void i2c_ll_slave_broadcast_enable(i2c_dev_t *hw, bool broadcast_e
     hw->ctr.addr_broadcasting_en = broadcast_en;
 }
 
+/**
+ * @brief Get the cause of SCL clock stretching in slave mode
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param stretch_cause Pointer to stretch cause in the slave mode.
+ *
+ * @return None
+ */
+__attribute__((always_inline))
+static inline void i2c_ll_slave_get_stretch_cause(i2c_dev_t *hw, i2c_slave_stretch_cause_t *stretch_cause)
+{
+    switch (hw->sr.stretch_cause)
+    {
+    case 0:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_ADDRESS_MATCH;
+        break;
+    case 1:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_TX_EMPTY;
+        break;
+    case 2:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_RX_FULL;
+        break;
+    case 3:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_SENDING_ACK;
+        break;
+    default:
+        HAL_ASSERT(false);
+        break;
+    }
+}
+
 /**
  * @brief  Configure I2C slave address
  *
@@ -400,6 +430,7 @@ static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr)
  */
 static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr)
 {
+    hw->fifo_conf.fifo_prt_en = 1;
     hw->fifo_conf.rx_fifo_wm_thrhd = full_thr;
 }
 

+ 46 - 14
components/hal/esp32c6/include/hal/i2c_ll.h

@@ -49,31 +49,31 @@ typedef union {
 #define I2C_LL_CMD_END        4    /*!<I2C end command */
 
 typedef enum {
-    I2C_LL_INTR_TXFIFO_WM = (1 << 1),
-    I2C_LL_INTR_RXFIFO_WM = (1 << 0),
+    I2C_INTR_MST_TXFIFO_WM = (1 << 1),
+    I2C_INTR_MST_RXFIFO_WM = (1 << 0),
     I2C_LL_INTR_NACK = (1 << 10),
     I2C_LL_INTR_TIMEOUT = (1 << 8),
     I2C_LL_INTR_MST_COMPLETE = (1 << 7),
     I2C_LL_INTR_ARBITRATION = (1 << 5),
     I2C_LL_INTR_END_DETECT = (1 << 3),
     I2C_LL_INTR_ST_TO = (1 << 13),
-    I2C_LL_INTR_START = (1 << 15),
-    I2C_LL_INTR_STRETCH = (1 << 16),
-    I2C_LL_INTR_UNMATCH = (1 << 18),
-} i2c_ll_intr_t;
+} i2c_ll_master_intr_t;
 
 typedef enum {
-    I2C_LL_STRETCH_REASON_MASTER_START = 0,
-    I2C_LL_STRETCH_REASON_TX_EMPTY = 1,
-    I2C_LL_STRETCH_REASON_RX_FULL = 2,
-} i2c_ll_stretch_cause_t;
+    I2C_INTR_SLV_TXFIFO_WM = (1 << 1),
+    I2C_INTR_SLV_RXFIFO_WM = (1 << 0),
+    I2C_INTR_SLV_COMPLETE = (1 << 7),
+    I2C_INTR_START = (1 << 15),
+    I2C_INTR_STRETCH = (1 << 16),
+    I2C_INTR_UNMATCH = (1 << 18),
+} i2c_ll_slave_intr_t;
 
 // Get the I2C hardware instance
 #define I2C_LL_GET_HW(i2c_num)      (((i2c_num) == I2C_NUM_0) ? (&I2C0) : (&LP_I2C))
 #define I2C_LL_MASTER_EVENT_INTR    (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
-#define I2C_LL_SLAVE_EVENT_INTR     (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
-#define I2C_LL_SLAVE_RX_EVENT_INTR  (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
-#define I2C_LL_SLAVE_TX_EVENT_INTR  (I2C_TXFIFO_WM_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
+#define I2C_LL_SLAVE_EVENT_INTR     (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
+#define I2C_LL_SLAVE_RX_EVENT_INTR  (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
+#define I2C_LL_SLAVE_TX_EVENT_INTR  (I2C_TXFIFO_WM_INT_ENA_M)
 #define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT   (9)
 
 /**
@@ -299,6 +299,37 @@ static inline void i2c_ll_slave_broadcast_enable(i2c_dev_t *hw, bool broadcast_e
     hw->ctr.addr_broadcasting_en = broadcast_en;
 }
 
+/**
+ * @brief Get the cause of SCL clock stretching in slave mode
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param stretch_cause Pointer to stretch cause in the slave mode.
+ *
+ * @return None
+ */
+__attribute__((always_inline))
+static inline void i2c_ll_slave_get_stretch_cause(i2c_dev_t *hw, i2c_slave_stretch_cause_t *stretch_cause)
+{
+    switch (hw->sr.stretch_cause)
+    {
+    case 0:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_ADDRESS_MATCH;
+        break;
+    case 1:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_TX_EMPTY;
+        break;
+    case 2:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_RX_FULL;
+        break;
+    case 3:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_SENDING_ACK;
+        break;
+    default:
+        HAL_ASSERT(false);
+        break;
+    }
+}
+
 /**
  * @brief  Configure I2C slave address
  *
@@ -312,7 +343,7 @@ static inline void i2c_ll_set_slave_addr(i2c_dev_t *hw, uint16_t slave_addr, boo
 {
     hw->slave_addr.addr_10bit_en = addr_10bit_en;
     if (addr_10bit_en) {
-        uint8_t addr_14_7 = (slave_addr & 0xff) << 7;
+        uint16_t addr_14_7 = (slave_addr & 0xff) << 7;
         uint8_t addr_6_0 = ((slave_addr & 0x300) >> 8) | 0x78;
         hw->slave_addr.slave_addr = addr_14_7 | addr_6_0;
         hw->ctr.addr_10bit_rw_check_en = addr_10bit_en;
@@ -404,6 +435,7 @@ static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr)
  */
 static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr)
 {
+    hw->fifo_conf.fifo_prt_en = 1;
     hw->fifo_conf.rxfifo_wm_thrhd = full_thr;
 }
 

+ 46 - 14
components/hal/esp32h2/include/hal/i2c_ll.h

@@ -47,32 +47,32 @@ typedef union {
 #define I2C_LL_CMD_END        4    /*!<I2C end command */
 
 typedef enum {
-    I2C_LL_INTR_TXFIFO_WM = (1 << 1),
-    I2C_LL_INTR_RXFIFO_WM = (1 << 0),
+    I2C_INTR_MST_TXFIFO_WM = (1 << 1),
+    I2C_INTR_MST_RXFIFO_WM = (1 << 0),
     I2C_LL_INTR_NACK = (1 << 10),
     I2C_LL_INTR_TIMEOUT = (1 << 8),
     I2C_LL_INTR_MST_COMPLETE = (1 << 7),
     I2C_LL_INTR_ARBITRATION = (1 << 5),
     I2C_LL_INTR_END_DETECT = (1 << 3),
     I2C_LL_INTR_ST_TO = (1 << 13),
-    I2C_LL_INTR_START = (1 << 15),
-    I2C_LL_INTR_STRETCH = (1 << 16),
-    I2C_LL_INTR_UNMATCH = (1 << 18),
-} i2c_ll_intr_t;
+} i2c_ll_master_intr_t;
 
 typedef enum {
-    I2C_LL_STRETCH_REASON_MASTER_START = 0,
-    I2C_LL_STRETCH_REASON_TX_EMPTY = 1,
-    I2C_LL_STRETCH_REASON_RX_FULL = 2,
-} i2c_ll_stretch_cause_t;
+    I2C_INTR_SLV_TXFIFO_WM = (1 << 1),
+    I2C_INTR_SLV_RXFIFO_WM = (1 << 0),
+    I2C_INTR_SLV_COMPLETE = (1 << 7),
+    I2C_INTR_START = (1 << 15),
+    I2C_INTR_STRETCH = (1 << 16),
+    I2C_INTR_UNMATCH = (1 << 18),
+} i2c_ll_slave_intr_t;
 
 // Get the I2C hardware instance
 #define I2C_LL_GET_HW(i2c_num)      (i2c_num == 0 ? (&I2C0) : (&I2C1))
 #define I2C_LL_GET_NUM(hw)          (hw == &I2C0 ? 0 : 1)
 #define I2C_LL_MASTER_EVENT_INTR    (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
-#define I2C_LL_SLAVE_EVENT_INTR     (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
-#define I2C_LL_SLAVE_RX_EVENT_INTR  (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
-#define I2C_LL_SLAVE_TX_EVENT_INTR  (I2C_TXFIFO_WM_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
+#define I2C_LL_SLAVE_EVENT_INTR     (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
+#define I2C_LL_SLAVE_RX_EVENT_INTR  (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
+#define I2C_LL_SLAVE_TX_EVENT_INTR  (I2C_TXFIFO_WM_INT_ENA_M)
 #define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT   (9)
 
 /**
@@ -295,6 +295,37 @@ static inline void i2c_ll_slave_broadcast_enable(i2c_dev_t *hw, bool broadcast_e
     hw->ctr.addr_broadcasting_en = broadcast_en;
 }
 
+/**
+ * @brief Get the cause of SCL clock stretching in slave mode
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param stretch_cause Pointer to stretch cause in the slave mode.
+ *
+ * @return None
+ */
+__attribute__((always_inline))
+static inline void i2c_ll_slave_get_stretch_cause(i2c_dev_t *hw, i2c_slave_stretch_cause_t *stretch_cause)
+{
+    switch (hw->sr.stretch_cause)
+    {
+    case 0:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_ADDRESS_MATCH;
+        break;
+    case 1:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_TX_EMPTY;
+        break;
+    case 2:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_RX_FULL;
+        break;
+    case 3:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_SENDING_ACK;
+        break;
+    default:
+        HAL_ASSERT(false);
+        break;
+    }
+}
+
 /**
  * @brief  Configure I2C slave address
  *
@@ -308,7 +339,7 @@ static inline void i2c_ll_set_slave_addr(i2c_dev_t *hw, uint16_t slave_addr, boo
 {
     hw->slave_addr.addr_10bit_en = addr_10bit_en;
     if (addr_10bit_en) {
-        uint8_t addr_14_7 = (slave_addr & 0xff) << 7;
+        uint16_t addr_14_7 = (slave_addr & 0xff) << 7;
         uint8_t addr_6_0 = ((slave_addr & 0x300) >> 8) | 0x78;
         hw->slave_addr.slave_addr = addr_14_7 | addr_6_0;
         hw->ctr.addr_10bit_rw_check_en = addr_10bit_en;
@@ -400,6 +431,7 @@ static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr)
  */
 static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr)
 {
+    hw->fifo_conf.fifo_prt_en = 1;
     hw->fifo_conf.rxfifo_wm_thrhd = full_thr;
 }
 

+ 17 - 10
components/hal/esp32p4/include/hal/i2c_ll.h

@@ -47,18 +47,24 @@ typedef union {
 #define I2C_LL_CMD_END        4    /*!<I2C end command */
 
 typedef enum {
-    I2C_LL_INTR_TXFIFO_WM = (1 << 1),
-    I2C_LL_INTR_RXFIFO_WM = (1 << 0),
+    I2C_INTR_MST_TXFIFO_WM = (1 << 1),
+    I2C_INTR_MST_RXFIFO_WM = (1 << 0),
     I2C_LL_INTR_NACK = (1 << 10),
     I2C_LL_INTR_TIMEOUT = (1 << 8),
     I2C_LL_INTR_MST_COMPLETE = (1 << 7),
     I2C_LL_INTR_ARBITRATION = (1 << 5),
     I2C_LL_INTR_END_DETECT = (1 << 3),
     I2C_LL_INTR_ST_TO = (1 << 13),
-    I2C_LL_INTR_START = (1 << 15),
-    I2C_LL_INTR_STRETCH = (1 << 16),
-    I2C_LL_INTR_UNMATCH = (1 << 18),
-} i2c_ll_intr_t;
+} i2c_ll_master_intr_t;
+
+typedef enum {
+    I2C_INTR_SLV_TXFIFO_WM = (1 << 1),
+    I2C_INTR_SLV_RXFIFO_WM = (1 << 0),
+    I2C_INTR_SLV_COMPLETE = (1 << 7),
+    I2C_INTR_START = (1 << 15),
+    I2C_INTR_STRETCH = (1 << 16),
+    I2C_INTR_UNMATCH = (1 << 18),
+} i2c_ll_slave_intr_t;
 
 typedef enum {
     I2C_LL_STRETCH_REASON_MASTER_START = 0,
@@ -69,9 +75,9 @@ typedef enum {
 // Get the I2C hardware instance
 #define I2C_LL_GET_HW(i2c_num)      (((i2c_num) == I2C_NUM_0) ? (&I2C0) : (((i2c_num) == I2C_NUM_1) ? (&I2C1) : (&LP_I2C)))
 #define I2C_LL_MASTER_EVENT_INTR    (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
-#define I2C_LL_SLAVE_EVENT_INTR     (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
-#define I2C_LL_SLAVE_RX_EVENT_INTR  (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
-#define I2C_LL_SLAVE_TX_EVENT_INTR  (I2C_TXFIFO_WM_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
+#define I2C_LL_SLAVE_EVENT_INTR     (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
+#define I2C_LL_SLAVE_RX_EVENT_INTR  (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
+#define I2C_LL_SLAVE_TX_EVENT_INTR  (I2C_TXFIFO_WM_INT_ENA_M)
 #define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT   (9)
 
 /**
@@ -319,7 +325,7 @@ static inline void i2c_ll_set_slave_addr(i2c_dev_t *hw, uint16_t slave_addr, boo
 {
     hw->slave_addr.addr_10bit_en = addr_10bit_en;
     if (addr_10bit_en) {
-        uint8_t addr_14_7 = (slave_addr & 0xff) << 7;
+        uint16_t addr_14_7 = (slave_addr & 0xff) << 7;
         uint8_t addr_6_0 = ((slave_addr & 0x300) >> 8) | 0x78;
         hw->slave_addr.slave_addr = addr_14_7 | addr_6_0;
         hw->ctr.addr_10bit_rw_check_en = addr_10bit_en;
@@ -411,6 +417,7 @@ static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr)
  */
 static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr)
 {
+    hw->fifo_conf.fifo_prt_en = 1;
     hw->fifo_conf.rxfifo_wm_thrhd = full_thr;
 }
 

+ 32 - 12
components/hal/esp32s2/include/hal/i2c_ll.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -44,24 +44,29 @@ typedef union {
 #define I2C_LL_CMD_END        4    /*!<I2C end command */
 
 typedef enum {
-    I2C_LL_INTR_TXFIFO_WM = (1 << 1),
-    I2C_LL_INTR_RXFIFO_WM = (1 << 0),
+    I2C_INTR_MST_TXFIFO_WM = (1 << 1),
+    I2C_INTR_MST_RXFIFO_WM = (1 << 0),
     I2C_LL_INTR_NACK = (1 << 10),
     I2C_LL_INTR_TIMEOUT = (1 << 8),
     I2C_LL_INTR_MST_COMPLETE = (1 << 7),
     I2C_LL_INTR_ARBITRATION = (1 << 5),
     I2C_LL_INTR_END_DETECT = (1 << 3),
     I2C_LL_INTR_ST_TO = (1 << 13),
-    I2C_LL_INTR_START = (1 << 15),
-    I2C_LL_INTR_STRETCH = (1 << 16),
-    I2C_LL_INTR_UNMATCH = (1 << 18),
-} i2c_ll_intr_t;
+} i2c_ll_master_intr_t;
+
+typedef enum {
+    I2C_INTR_SLV_TXFIFO_WM = (1 << 1),
+    I2C_INTR_SLV_RXFIFO_WM = (1 << 0),
+    I2C_INTR_SLV_COMPLETE = (1 << 7),
+    I2C_INTR_START = (1 << 15),
+    I2C_INTR_STRETCH = (1 << 16),
+} i2c_ll_slave_intr_t;
 
 // Get the I2C hardware instance
 #define I2C_LL_GET_HW(i2c_num)        (((i2c_num) == 0) ? &I2C0 : &I2C1)
 #define I2C_LL_MASTER_EVENT_INTR    (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
-#define I2C_LL_SLAVE_EVENT_INTR     (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_SLAVE_STRETCH_INT_ENA_M)
-#define I2C_LL_SLAVE_RX_EVENT_INTR  (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
+#define I2C_LL_SLAVE_EVENT_INTR     (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
+#define I2C_LL_SLAVE_RX_EVENT_INTR  (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
 #define I2C_LL_SLAVE_TX_EVENT_INTR  (I2C_TXFIFO_WM_INT_ENA_M)
 #define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT   (9)
 
@@ -252,6 +257,20 @@ static inline void i2c_ll_slave_broadcast_enable(i2c_dev_t *hw, bool broadcast_e
     // Not supported on esp32s2
 }
 
+/**
+ * @brief Get the cause of SCL clock stretching in slave mode
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param stretch_cause Pointer to stretch cause in the slave mode.
+ *
+ * @return None
+ */
+__attribute__((always_inline))
+static inline void i2c_ll_slave_get_stretch_cause(i2c_dev_t *hw, i2c_slave_stretch_cause_t *stretch_cause)
+{
+    // Not supported on esp32s2
+}
+
 /**
  * @brief  Configure I2C slave address
  *
@@ -265,9 +284,9 @@ static inline void i2c_ll_set_slave_addr(i2c_dev_t *hw, uint16_t slave_addr, boo
 {
     hw->slave_addr.en_10bit = addr_10bit_en;
     if (addr_10bit_en) {
-        uint8_t addr_14_7 = (slave_addr & 0xff) << 7;
-        uint8_t addr_6_0 = ((slave_addr & 0x300) >> 8) || 0x78;
-        hw->slave_addr.addr = addr_14_7 || addr_6_0;
+        uint16_t addr_14_7 = (slave_addr & 0xff) << 7;
+        uint8_t addr_6_0 = ((slave_addr & 0x300) >> 8) | 0x78;
+        hw->slave_addr.addr = addr_14_7 | addr_6_0;
     } else {
         hw->slave_addr.addr = slave_addr;
     }
@@ -356,6 +375,7 @@ static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr)
  */
 static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr)
 {
+    hw->fifo_conf.fifo_prt_en = 1;
     hw->fifo_conf.rx_fifo_wm_thrhd = full_thr;
 }
 

+ 45 - 8
components/hal/esp32s3/include/hal/i2c_ll.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -48,18 +48,23 @@ typedef union {
 #define I2C_LL_CMD_END        4    /*!<I2C end command */
 
 typedef enum {
-    I2C_LL_INTR_TXFIFO_WM = (1 << 1),
-    I2C_LL_INTR_RXFIFO_WM = (1 << 0),
+    I2C_INTR_MST_TXFIFO_WM = (1 << 1),
+    I2C_INTR_MST_RXFIFO_WM = (1 << 0),
     I2C_LL_INTR_NACK = (1 << 10),
     I2C_LL_INTR_TIMEOUT = (1 << 8),
     I2C_LL_INTR_MST_COMPLETE = (1 << 7),
     I2C_LL_INTR_ARBITRATION = (1 << 5),
     I2C_LL_INTR_END_DETECT = (1 << 3),
     I2C_LL_INTR_ST_TO = (1 << 13),
-    I2C_LL_INTR_START = (1 << 15),
-    I2C_LL_INTR_STRETCH = (1 << 16),
-    I2C_LL_INTR_UNMATCH = (1 << 18),
-} i2c_ll_intr_t;
+} i2c_ll_master_intr_t;
+
+typedef enum {
+    I2C_INTR_SLV_TXFIFO_WM = (1 << 1),
+    I2C_INTR_SLV_RXFIFO_WM = (1 << 0),
+    I2C_INTR_SLV_COMPLETE = (1 << 7),
+    I2C_INTR_START = (1 << 15),
+    I2C_INTR_STRETCH = (1 << 16),
+} i2c_ll_slave_intr_t;
 
 // Get the I2C hardware instance
 #define I2C_LL_GET_HW(i2c_num)        (((i2c_num) == 0) ? &I2C0 : &I2C1)
@@ -288,6 +293,37 @@ static inline void i2c_ll_slave_broadcast_enable(i2c_dev_t *hw, bool broadcast_e
     hw->ctr.addr_broadcasting_en = broadcast_en;
 }
 
+/**
+ * @brief Get the cause of SCL clock stretching in slave mode
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param stretch_cause Pointer to stretch cause in the slave mode.
+ *
+ * @return None
+ */
+__attribute__((always_inline))
+static inline void i2c_ll_slave_get_stretch_cause(i2c_dev_t *hw, i2c_slave_stretch_cause_t *stretch_cause)
+{
+    switch (hw->sr.stretch_cause)
+    {
+    case 0:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_ADDRESS_MATCH;
+        break;
+    case 1:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_TX_EMPTY;
+        break;
+    case 2:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_RX_FULL;
+        break;
+    case 3:
+        *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_SENDING_ACK;
+        break;
+    default:
+        HAL_ASSERT(false);
+        break;
+    }
+}
+
 /**
  * @brief  Configure I2C slave address
  *
@@ -301,7 +337,7 @@ static inline void i2c_ll_set_slave_addr(i2c_dev_t *hw, uint16_t slave_addr, boo
 {
     hw->slave_addr.addr_10bit_en = addr_10bit_en;
     if (addr_10bit_en) {
-        uint8_t addr_14_7 = (slave_addr & 0xff) << 7;
+        uint16_t addr_14_7 = (slave_addr & 0xff) << 7;
         uint8_t addr_6_0 = ((slave_addr & 0x300) >> 8) | 0x78;
         hw->slave_addr.slave_addr = addr_14_7 | addr_6_0;
         hw->ctr.addr_10bit_rw_check_en = addr_10bit_en;
@@ -393,6 +429,7 @@ static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr)
  */
 static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr)
 {
+    hw->fifo_conf.fifo_prt_en = 1;
     hw->fifo_conf.rxfifo_wm_thrhd = full_thr;
 }
 

+ 10 - 0
components/hal/include/hal/i2c_types.h

@@ -87,6 +87,16 @@ typedef enum {
     I2C_MASTER_ACK_MAX,
 } i2c_ack_type_t;
 
+/**
+ * @brief Enum for I2C slave stretch causes
+ */
+typedef enum {
+    I2C_SLAVE_STRETCH_CAUSE_ADDRESS_MATCH = 0,   /*!< Stretching SCL low when the slave is read by the master and the address just matched */
+    I2C_SLAVE_STRETCH_CAUSE_TX_EMPTY = 1,        /*!< Stretching SCL low when TX FIFO is empty in slave mode */
+    I2C_SLAVE_STRETCH_CAUSE_RX_FULL = 2,         /*!< Stretching SCL low when RX FIFO is full in slave mode */
+    I2C_SLAVE_STRETCH_CAUSE_SENDING_ACK = 3,     /*!< Stretching SCL low when slave sending ACK */
+} i2c_slave_stretch_cause_t;
+
 #if SOC_I2C_SUPPORTED
 /**
  * @brief I2C group clock source

+ 12 - 0
components/soc/esp32c3/include/soc/Kconfig.soc_caps.in

@@ -419,6 +419,18 @@ config SOC_I2C_SUPPORT_10BIT_ADDR
     bool
     default y
 
+config SOC_I2C_SLAVE_SUPPORT_BROADCAST
+    bool
+    default y
+
+config SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE
+    bool
+    default y
+
+config SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS
+    bool
+    default y
+
 config SOC_I2S_NUM
     int
     default 1

+ 3 - 0
components/soc/esp32c3/include/soc/soc_caps.h

@@ -196,6 +196,9 @@
 #define SOC_I2C_SUPPORT_XTAL        (1)
 #define SOC_I2C_SUPPORT_RTC         (1)
 #define SOC_I2C_SUPPORT_10BIT_ADDR   (1)
+#define SOC_I2C_SLAVE_SUPPORT_BROADCAST    (1)
+#define SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE    (1)
+#define SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS   (1)
 
 /*-------------------------- I2S CAPS ----------------------------------------*/
 #define SOC_I2S_NUM                 (1U)

+ 16 - 0
components/soc/esp32c6/include/soc/Kconfig.soc_caps.in

@@ -539,6 +539,22 @@ config SOC_I2C_SUPPORT_10BIT_ADDR
     bool
     default y
 
+config SOC_I2C_SLAVE_SUPPORT_BROADCAST
+    bool
+    default y
+
+config SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE
+    bool
+    default y
+
+config SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS
+    bool
+    default y
+
+config SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH
+    bool
+    default y
+
 config SOC_LP_I2C_NUM
     int
     default 1

+ 4 - 0
components/soc/esp32c6/include/soc/soc_caps.h

@@ -239,6 +239,10 @@
 #define SOC_I2C_SUPPORT_XTAL        (1)
 #define SOC_I2C_SUPPORT_RTC         (1)
 #define SOC_I2C_SUPPORT_10BIT_ADDR   (1)
+#define SOC_I2C_SLAVE_SUPPORT_BROADCAST    (1)
+#define SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE    (1)
+#define SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS   (1)
+#define SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH    (1)
 
 /*-------------------------- LP_I2C CAPS -------------------------------------*/
 // ESP32-C6 has 1 LP_I2C

+ 16 - 0
components/soc/esp32h2/include/soc/Kconfig.soc_caps.in

@@ -531,6 +531,22 @@ config SOC_I2C_SUPPORT_10BIT_ADDR
     bool
     default y
 
+config SOC_I2C_SLAVE_SUPPORT_BROADCAST
+    bool
+    default y
+
+config SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE
+    bool
+    default y
+
+config SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS
+    bool
+    default y
+
+config SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH
+    bool
+    default y
+
 config SOC_I2S_NUM
     int
     default 1

+ 4 - 0
components/soc/esp32h2/include/soc/soc_caps.h

@@ -242,6 +242,10 @@
 #define SOC_I2C_SUPPORT_XTAL        (1)
 #define SOC_I2C_SUPPORT_RTC         (1)
 #define SOC_I2C_SUPPORT_10BIT_ADDR   (1)
+#define SOC_I2C_SLAVE_SUPPORT_BROADCAST    (1)
+#define SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE    (1)
+#define SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS   (1)
+#define SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH    (1)
 
 /*-------------------------- I2S CAPS ----------------------------------------*/
 #define SOC_I2S_NUM                 (1U)

+ 16 - 0
components/soc/esp32p4/include/soc/Kconfig.soc_caps.in

@@ -479,6 +479,22 @@ config SOC_I2C_SUPPORT_RTC
     bool
     default y
 
+config SOC_I2C_SUPPORT_10BIT_ADDR
+    bool
+    default y
+
+config SOC_I2C_SLAVE_SUPPORT_BROADCAST
+    bool
+    default y
+
+config SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS
+    bool
+    default y
+
+config SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH
+    bool
+    default y
+
 config SOC_I2S_NUM
     int
     default 3

+ 4 - 0
components/soc/esp32p4/include/soc/soc_caps.h

@@ -246,6 +246,10 @@
 
 #define SOC_I2C_SUPPORT_XTAL        (1)
 #define SOC_I2C_SUPPORT_RTC         (1)
+#define SOC_I2C_SUPPORT_10BIT_ADDR  (1)
+#define SOC_I2C_SLAVE_SUPPORT_BROADCAST    (1)
+#define SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS   (1)
+#define SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH    (1)
 
 /*-------------------------- I2S CAPS ----------------------------------------*/
 #define SOC_I2S_NUM                 (3U)

+ 8 - 0
components/soc/esp32s3/include/soc/Kconfig.soc_caps.in

@@ -483,6 +483,14 @@ config SOC_I2C_SUPPORT_10BIT_ADDR
     bool
     default y
 
+config SOC_I2C_SLAVE_SUPPORT_BROADCAST
+    bool
+    default y
+
+config SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS
+    bool
+    default y
+
 config SOC_I2S_NUM
     int
     default 2

+ 2 - 0
components/soc/esp32s3/include/soc/soc_caps.h

@@ -201,6 +201,8 @@
 #define SOC_I2C_SUPPORT_RTC        (1)
 
 #define SOC_I2C_SUPPORT_10BIT_ADDR  (1)
+#define SOC_I2C_SLAVE_SUPPORT_BROADCAST    (1)
+#define SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS   (1)
 
 /*-------------------------- I2S CAPS ----------------------------------------*/
 #define SOC_I2S_NUM                 (2U)