Răsfoiți Sursa

Merge branch 'feature/support_i2s_on_esp32c6' into 'master'

i2s: support i2s on esp32c6

See merge request espressif/esp-idf!19989
Kevin (Lao Kaiyao) 3 ani în urmă
părinte
comite
04b4bc6cb5
33 a modificat fișierele cu 1358 adăugiri și 84 ștergeri
  1. 4 2
      components/driver/deprecated/i2s_legacy.c
  2. 21 1
      components/driver/i2s/i2s_common.c
  3. 2 10
      components/driver/i2s/i2s_pdm.c
  4. 4 5
      components/driver/i2s/i2s_private.h
  5. 1 5
      components/driver/i2s/i2s_std.c
  6. 1 6
      components/driver/i2s/i2s_tdm.c
  7. 12 1
      components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c
  8. 1 1
      components/driver/test_apps/i2s_test_apps/test_inc/test_i2s.h
  9. 2 3
      components/hal/esp32/include/hal/i2s_ll.h
  10. 28 6
      components/hal/esp32c3/include/hal/i2s_ll.h
  11. 1166 0
      components/hal/esp32c6/include/hal/i2s_ll.h
  12. 28 7
      components/hal/esp32h2/include/hal/i2s_ll.h
  13. 2 4
      components/hal/esp32s2/include/hal/i2s_ll.h
  14. 28 9
      components/hal/esp32s3/include/hal/i2s_ll.h
  15. 4 0
      components/soc/esp32c3/include/soc/Kconfig.soc_caps.in
  16. 2 1
      components/soc/esp32c3/include/soc/clk_tree_defs.h
  17. 2 2
      components/soc/esp32c3/include/soc/i2s_struct.h
  18. 1 0
      components/soc/esp32c3/include/soc/soc_caps.h
  19. 0 1
      components/soc/esp32c6/CMakeLists.txt
  20. 8 0
      components/soc/esp32c6/include/soc/Kconfig.soc_caps.in
  21. 10 1
      components/soc/esp32c6/include/soc/clk_tree_defs.h
  22. 8 8
      components/soc/esp32c6/include/soc/i2s_struct.h
  23. 2 2
      components/soc/esp32c6/include/soc/pcr_struct.h
  24. 2 2
      components/soc/esp32c6/include/soc/soc_caps.h
  25. 4 0
      components/soc/esp32h2/include/soc/Kconfig.soc_caps.in
  26. 2 1
      components/soc/esp32h2/include/soc/clk_tree_defs.h
  27. 2 2
      components/soc/esp32h2/include/soc/i2s_struct.h
  28. 1 0
      components/soc/esp32h2/include/soc/soc_caps.h
  29. 4 0
      components/soc/esp32s3/include/soc/Kconfig.soc_caps.in
  30. 2 1
      components/soc/esp32s3/include/soc/clk_tree_defs.h
  31. 2 2
      components/soc/esp32s3/include/soc/i2s_struct.h
  32. 1 0
      components/soc/esp32s3/include/soc/soc_caps.h
  33. 1 1
      examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/main/i2s_es7210_record_example.c

+ 4 - 2
components/driver/deprecated/i2s_legacy.c

@@ -47,6 +47,7 @@
 #include "esp_efuse.h"
 #include "esp_efuse.h"
 #include "esp_rom_gpio.h"
 #include "esp_rom_gpio.h"
 #include "esp_private/periph_ctrl.h"
 #include "esp_private/periph_ctrl.h"
+#include "esp_private/esp_clk.h"
 
 
 static const char *TAG = "i2s(legacy)";
 static const char *TAG = "i2s(legacy)";
 
 
@@ -624,6 +625,7 @@ err:
 /*-------------------------------------------------------------
 /*-------------------------------------------------------------
                    I2S clock operation
                    I2S clock operation
   -------------------------------------------------------------*/
   -------------------------------------------------------------*/
+  // [clk_tree] TODO: replace the following switch table by clk_tree API
 static uint32_t i2s_config_source_clock(i2s_port_t i2s_num, bool use_apll, uint32_t mclk)
 static uint32_t i2s_config_source_clock(i2s_port_t i2s_num, bool use_apll, uint32_t mclk)
 {
 {
 #if SOC_I2S_SUPPORTS_APLL
 #if SOC_I2S_SUPPORTS_APLL
@@ -650,12 +652,12 @@ static uint32_t i2s_config_source_clock(i2s_port_t i2s_num, bool use_apll, uint3
         /* In APLL mode, there is no sclk but only mclk, so return 0 here to indicate APLL mode */
         /* In APLL mode, there is no sclk but only mclk, so return 0 here to indicate APLL mode */
         return real_freq;
         return real_freq;
     }
     }
-    return I2S_LL_BASE_CLK;
+    return esp_clk_apb_freq() * 2;
 #else
 #else
     if (use_apll) {
     if (use_apll) {
         ESP_LOGW(TAG, "APLL not supported on current chip, use I2S_CLK_SRC_DEFAULT as default clock source");
         ESP_LOGW(TAG, "APLL not supported on current chip, use I2S_CLK_SRC_DEFAULT as default clock source");
     }
     }
-    return I2S_LL_BASE_CLK;
+    return esp_clk_apb_freq() * 2;
 #endif
 #endif
 }
 }
 
 

+ 21 - 1
components/driver/i2s/i2s_common.c

@@ -35,6 +35,7 @@
 
 
 #include "esp_private/i2s_platform.h"
 #include "esp_private/i2s_platform.h"
 #include "esp_private/periph_ctrl.h"
 #include "esp_private/periph_ctrl.h"
+#include "esp_private/esp_clk.h"
 
 
 #include "driver/gpio.h"
 #include "driver/gpio.h"
 #include "driver/i2s_common.h"
 #include "driver/i2s_common.h"
@@ -444,7 +445,7 @@ err:
 }
 }
 
 
 #if SOC_I2S_SUPPORTS_APLL
 #if SOC_I2S_SUPPORTS_APLL
-uint32_t i2s_set_get_apll_freq(uint32_t mclk_freq_hz)
+static uint32_t i2s_set_get_apll_freq(uint32_t mclk_freq_hz)
 {
 {
     /* Calculate the expected APLL  */
     /* Calculate the expected APLL  */
     int mclk_div = (int)((SOC_APLL_MIN_HZ / mclk_freq_hz) + 1);
     int mclk_div = (int)((SOC_APLL_MIN_HZ / mclk_freq_hz) + 1);
@@ -473,6 +474,25 @@ uint32_t i2s_set_get_apll_freq(uint32_t mclk_freq_hz)
 }
 }
 #endif
 #endif
 
 
+// [clk_tree] TODO: replace the following switch table by clk_tree API
+uint32_t i2s_get_source_clk_freq(i2s_clock_src_t clk_src, uint32_t mclk_freq_hz)
+{
+    switch (clk_src)
+    {
+#if SOC_I2S_SUPPORTS_APLL
+    case I2S_CLK_SRC_APLL:
+        return i2s_set_get_apll_freq(mclk_freq_hz);
+#endif
+#if SOC_I2S_SUPPORTS_XTAL
+    case I2S_CLK_SRC_XTAL:
+        (void)mclk_freq_hz;
+        return esp_clk_xtal_freq();
+#endif
+    default: // I2S_CLK_SRC_PLL_160M
+        return esp_clk_apb_freq() * 2;
+    }
+}
+
 #if SOC_GDMA_SUPPORTED
 #if SOC_GDMA_SUPPORTED
 static bool IRAM_ATTR i2s_dma_rx_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
 static bool IRAM_ATTR i2s_dma_rx_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
 {
 {

+ 2 - 10
components/driver/i2s/i2s_pdm.c

@@ -38,11 +38,7 @@ static esp_err_t i2s_pdm_tx_calculate_clock(i2s_chan_handle_t handle, const i2s_
     clk_info->bclk = rate * I2S_LL_PDM_BCK_FACTOR * pdm_tx_clk->up_sample_fp / pdm_tx_clk->up_sample_fs;
     clk_info->bclk = rate * I2S_LL_PDM_BCK_FACTOR * pdm_tx_clk->up_sample_fp / pdm_tx_clk->up_sample_fs;
     clk_info->bclk_div = 8;
     clk_info->bclk_div = 8;
     clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
     clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
-#if SOC_I2S_SUPPORTS_APLL
-    clk_info->sclk = (clk_cfg->clk_src == I2S_CLK_SRC_APLL) ? i2s_set_get_apll_freq(clk_info->mclk) : I2S_LL_BASE_CLK;
-#else
-    clk_info->sclk = I2S_LL_BASE_CLK;
-#endif
+    clk_info->sclk = i2s_get_source_clk_freq(clk_cfg->clk_src, clk_info->mclk);
     clk_info->mclk_div = clk_info->sclk / clk_info->mclk;
     clk_info->mclk_div = clk_info->sclk / clk_info->mclk;
 
 
     /* Check if the configuration is correct */
     /* Check if the configuration is correct */
@@ -326,11 +322,7 @@ static esp_err_t i2s_pdm_rx_calculate_clock(i2s_chan_handle_t handle, const i2s_
     clk_info->bclk = rate * I2S_LL_PDM_BCK_FACTOR * (pdm_rx_clk->dn_sample_mode == I2S_PDM_DSR_16S ? 2 : 1);
     clk_info->bclk = rate * I2S_LL_PDM_BCK_FACTOR * (pdm_rx_clk->dn_sample_mode == I2S_PDM_DSR_16S ? 2 : 1);
     clk_info->bclk_div = 8;
     clk_info->bclk_div = 8;
     clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
     clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
-#if SOC_I2S_SUPPORTS_APLL
-    clk_info->sclk = (clk_cfg->clk_src == I2S_CLK_SRC_APLL) ? i2s_set_get_apll_freq(clk_info->mclk) : I2S_LL_BASE_CLK;
-#else
-    clk_info->sclk = I2S_LL_BASE_CLK;
-#endif
+    clk_info->sclk = i2s_get_source_clk_freq(clk_cfg->clk_src, clk_info->mclk);
     clk_info->mclk_div = clk_info->sclk / clk_info->mclk;
     clk_info->mclk_div = clk_info->sclk / clk_info->mclk;
 
 
     /* Check if the configuration is correct */
     /* Check if the configuration is correct */

+ 4 - 5
components/driver/i2s/i2s_private.h

@@ -161,16 +161,15 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu
  */
  */
 uint32_t i2s_get_buf_size(i2s_chan_handle_t handle, uint32_t data_bit_width, uint32_t dma_frame_num);
 uint32_t i2s_get_buf_size(i2s_chan_handle_t handle, uint32_t data_bit_width, uint32_t dma_frame_num);
 
 
-#if SOC_I2S_SUPPORTS_APLL
 /**
 /**
- * @brief Set mclk frequency and get the actuall APLL frequency
+ * @brief Get the frequency of the source clock
  *
  *
+ * @param clk_src       clock source
  * @param mclk_freq_hz  Expected mclk frequenct in Hz
  * @param mclk_freq_hz  Expected mclk frequenct in Hz
  * @return
  * @return
- *  - Actuall APLL frequency
+ *      - Actual source clock frequency
  */
  */
-uint32_t i2s_set_get_apll_freq(uint32_t mclk_freq_hz);
-#endif
+uint32_t i2s_get_source_clk_freq(i2s_clock_src_t clk_src, uint32_t mclk_freq_hz);
 
 
 /**
 /**
  * @brief Check gpio validity and attach to corresponding signal
  * @brief Check gpio validity and attach to corresponding signal

+ 1 - 5
components/driver/i2s/i2s_std.c

@@ -45,11 +45,7 @@ static esp_err_t i2s_std_calculate_clock(i2s_chan_handle_t handle, const i2s_std
         clk_info->bclk = rate * handle->total_slot * slot_bits;
         clk_info->bclk = rate * handle->total_slot * slot_bits;
         clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
         clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
     }
     }
-#if SOC_I2S_SUPPORTS_APLL
-    clk_info->sclk = (clk_cfg->clk_src == I2S_CLK_SRC_APLL) ? i2s_set_get_apll_freq(clk_info->mclk) : I2S_LL_BASE_CLK;
-#else
-    clk_info->sclk = I2S_LL_BASE_CLK;
-#endif
+    clk_info->sclk = i2s_get_source_clk_freq(clk_cfg->clk_src, clk_info->mclk);
     clk_info->mclk_div = clk_info->sclk / clk_info->mclk;
     clk_info->mclk_div = clk_info->sclk / clk_info->mclk;
 
 
     /* Check if the configuration is correct */
     /* Check if the configuration is correct */

+ 1 - 6
components/driver/i2s/i2s_tdm.c

@@ -54,12 +54,7 @@ static esp_err_t i2s_tdm_calculate_clock(i2s_chan_handle_t handle, const i2s_tdm
         clk_info->bclk = rate * handle->total_slot * slot_bits;
         clk_info->bclk = rate * handle->total_slot * slot_bits;
         clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
         clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
     }
     }
-
-#if SOC_I2S_SUPPORTS_APLL
-    clk_info->sclk = clk_cfg->clk_src == I2S_CLK_SRC_APLL ? i2s_set_get_apll_freq(clk_info->mclk) : I2S_LL_BASE_CLK;
-#else
-    clk_info->sclk = I2S_LL_BASE_CLK;
-#endif
+    clk_info->sclk = i2s_get_source_clk_freq(clk_cfg->clk_src, clk_info->mclk);
     clk_info->mclk_div = clk_info->sclk / clk_info->mclk;
     clk_info->mclk_div = clk_info->sclk / clk_info->mclk;
 
 
     /* Check if the configuration is correct */
     /* Check if the configuration is correct */

+ 12 - 1
components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c

@@ -751,7 +751,14 @@ static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_std_clk_c
                             32000, 44100, 48000, 64000, 88200, 96000,
                             32000, 44100, 48000, 64000, 88200, 96000,
                             128000, 144000, 196000};
                             128000, 144000, 196000};
     int real_pulse = 0;
     int real_pulse = 0;
-    for (int i = 0; i < 15; i++) {
+    int case_cnt = 15;
+#if SOC_I2S_HW_VERSION_2
+    // Can't support a very high sample rate while using XTAL as clock source
+    if (clk_cfg->clk_src == I2S_CLK_SRC_XTAL) {
+        case_cnt = 9;
+    }
+#endif
+    for (int i = 0; i < case_cnt; i++) {
         int expt_pulse = (int)((float)test_freq[i] * (TEST_I2S_PERIOD_MS / 1000.0));
         int expt_pulse = (int)((float)test_freq[i] * (TEST_I2S_PERIOD_MS / 1000.0));
         clk_cfg->sample_rate_hz = test_freq[i];
         clk_cfg->sample_rate_hz = test_freq[i];
         TEST_ESP_OK(i2s_channel_reconfig_std_clock(rx_chan, clk_cfg));
         TEST_ESP_OK(i2s_channel_reconfig_std_clock(rx_chan, clk_cfg));
@@ -789,6 +796,10 @@ TEST_CASE("I2S_default_PLL_clock_test", "[i2s]")
     TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg));
     TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg));
 
 
     i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg);
     i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg);
+#if SOC_I2S_HW_VERSION_2
+    std_cfg.clk_cfg.clk_src = I2S_CLK_SRC_XTAL;
+    i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg);
+#endif
     TEST_ESP_OK(i2s_del_channel(rx_handle));
     TEST_ESP_OK(i2s_del_channel(rx_handle));
 }
 }
 
 

+ 1 - 1
components/driver/test_apps/i2s_test_apps/test_inc/test_i2s.h

@@ -44,7 +44,7 @@ extern "C" {
 #define SLAVE_WS_IO 15
 #define SLAVE_WS_IO 15
 #define DATA_IN_IO 19
 #define DATA_IN_IO 19
 #define DATA_OUT_IO 18
 #define DATA_OUT_IO 18
-#elif CONFIG_IDF_TARGET_ESP32H2
+#elif CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C6
 #define MASTER_MCK_IO 0
 #define MASTER_MCK_IO 0
 #define MASTER_BCK_IO 4
 #define MASTER_BCK_IO 4
 #define MASTER_WS_IO 5
 #define MASTER_WS_IO 5

+ 2 - 3
components/hal/esp32/include/hal/i2s_ll.h

@@ -29,7 +29,6 @@ extern "C" {
 
 
 #define I2S_LL_AD_BCK_FACTOR           (2)
 #define I2S_LL_AD_BCK_FACTOR           (2)
 #define I2S_LL_PDM_BCK_FACTOR          (64)
 #define I2S_LL_PDM_BCK_FACTOR          (64)
-#define I2S_LL_BASE_CLK                (2 * APB_CLK_FREQ)
 
 
 #define I2S_LL_MCLK_DIVIDER_BIT_WIDTH  (6)
 #define I2S_LL_MCLK_DIVIDER_BIT_WIDTH  (6)
 #define I2S_LL_MCLK_DIVIDER_MAX        ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
 #define I2S_LL_MCLK_DIVIDER_MAX        ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
@@ -287,7 +286,7 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
  * @note mclk on ESP32 is shared by both TX and RX channel
  * @note mclk on ESP32 is shared by both TX and RX channel
  *
  *
  * @param hw Peripheral I2S hardware instance address.
  * @param hw Peripheral I2S hardware instance address.
- * @param sclk system clock, 0 means use apll
+ * @param sclk system clock
  * @param mclk module clock
  * @param mclk module clock
  * @param mclk_div integer part of the division from sclk to mclk
  * @param mclk_div integer part of the division from sclk to mclk
  */
  */
@@ -363,7 +362,7 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
  * @note mclk on ESP32 is shared by both TX and RX channel
  * @note mclk on ESP32 is shared by both TX and RX channel
  *
  *
  * @param hw Peripheral I2S hardware instance address.
  * @param hw Peripheral I2S hardware instance address.
- * @param sclk system clock, 0 means use apll
+ * @param sclk system clock
  * @param mclk module clock
  * @param mclk module clock
  * @param mclk_div integer part of the division from sclk to mclk
  * @param mclk_div integer part of the division from sclk to mclk
  */
  */

+ 28 - 6
components/hal/esp32c3/include/hal/i2s_ll.h

@@ -14,6 +14,7 @@
 #pragma once
 #pragma once
 #include <stdbool.h>
 #include <stdbool.h>
 #include "hal/misc.h"
 #include "hal/misc.h"
+#include "hal/assert.h"
 #include "soc/i2s_periph.h"
 #include "soc/i2s_periph.h"
 #include "soc/i2s_struct.h"
 #include "soc/i2s_struct.h"
 #include "hal/i2s_types.h"
 #include "hal/i2s_types.h"
@@ -23,11 +24,10 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-#define I2S_LL_GET_HW(num)             (&I2S0)
+#define I2S_LL_GET_HW(num)             (((num) == 0)? (&I2S0) : NULL)
 
 
 #define I2S_LL_TDM_CH_MASK             (0xffff)
 #define I2S_LL_TDM_CH_MASK             (0xffff)
 #define I2S_LL_PDM_BCK_FACTOR          (64)
 #define I2S_LL_PDM_BCK_FACTOR          (64)
-#define I2S_LL_BASE_CLK                (2*APB_CLK_FREQ)
 
 
 #define I2S_LL_MCLK_DIVIDER_BIT_WIDTH  (9)
 #define I2S_LL_MCLK_DIVIDER_BIT_WIDTH  (9)
 #define I2S_LL_MCLK_DIVIDER_MAX        ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
 #define I2S_LL_MCLK_DIVIDER_MAX        ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
@@ -193,18 +193,40 @@ static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw)
  */
  */
 static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
 static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
 {
 {
-    hw->tx_clkm_conf.tx_clk_sel = 2;
+    switch (src)
+    {
+    case I2S_CLK_SRC_XTAL:
+        hw->tx_clkm_conf.tx_clk_sel = 0;
+        break;
+    case I2S_CLK_SRC_PLL_160M:
+        hw->tx_clkm_conf.tx_clk_sel = 2;
+        break;
+    default:
+        HAL_ASSERT(false && "unsupported clock source");
+        break;
+    }
 }
 }
 
 
 /**
 /**
  * @brief Set RX source clock
  * @brief Set RX source clock
  *
  *
  * @param hw Peripheral I2S hardware instance address.
  * @param hw Peripheral I2S hardware instance address.
- * @param src I2S source clock,  ESP32-C3 only support `I2S_CLK_SRC_PLL_160M`
+ * @param src I2S source clock
  */
  */
 static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
 static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
 {
 {
-    hw->rx_clkm_conf.rx_clk_sel = 2;
+    switch (src)
+    {
+    case I2S_CLK_SRC_XTAL:
+        hw->rx_clkm_conf.rx_clk_sel = 0;
+        break;
+    case I2S_CLK_SRC_PLL_160M:
+        hw->rx_clkm_conf.rx_clk_sel = 2;
+        break;
+    default:
+        HAL_ASSERT(false && "unsupported clock source");
+        break;
+    }
 }
 }
 
 
 /**
 /**
@@ -256,7 +278,7 @@ static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t
  * @brief Configure I2S TX module clock divider
  * @brief Configure I2S TX module clock divider
  *
  *
  * @param hw Peripheral I2S hardware instance address.
  * @param hw Peripheral I2S hardware instance address.
- * @param sclk system clock, 0 means use apll
+ * @param sclk system clock
  * @param mclk module clock
  * @param mclk module clock
  * @param mclk_div integer part of the division from sclk to mclk
  * @param mclk_div integer part of the division from sclk to mclk
  */
  */

+ 1166 - 0
components/hal/esp32c6/include/hal/i2s_ll.h

@@ -0,0 +1,1166 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+// The LL layer for I2S register operations
+/*******************************************************************************
+ * NOTICE
+ * The hal is not public api, don't use in application code.
+ * See readme.md in hal/include/hal/readme.md
+ ******************************************************************************/
+
+#pragma once
+#include <stdbool.h>
+#include "hal/misc.h"
+#include "hal/assert.h"
+#include "soc/i2s_periph.h"
+#include "soc/i2s_struct.h"
+#include "soc/pcr_struct.h"
+#include "hal/i2s_types.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define I2S_LL_GET_HW(num)             (((num) == 0)? (&I2S0) : NULL)
+
+#define I2S_LL_TDM_CH_MASK             (0xffff)
+#define I2S_LL_PDM_BCK_FACTOR          (64)
+
+#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH  (9)
+#define I2S_LL_MCLK_DIVIDER_MAX        ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
+
+/* I2S clock configuration structure */
+typedef struct {
+    uint16_t mclk_div; // I2S module clock divider, Fmclk = Fsclk /(mclk_div+b/a)
+    uint16_t a;
+    uint16_t b;        // The decimal part of module clock divider, the decimal is: b/a
+} i2s_ll_mclk_div_t;
+
+/**
+ * @brief I2S module general init, enable I2S clock.
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_enable_clock(i2s_dev_t *hw)
+{
+    // The clock gate enabling is moved to `periph_module_enable`
+    (void *)hw;
+}
+
+/**
+ * @brief I2S module disable I2S clock.
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_disable_clock(i2s_dev_t *hw)
+{
+    // The clock gate disabling is moved to `periph_module_disable`
+    (void *)hw;
+}
+
+/**
+ * @brief Enable I2S tx module clock
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_tx_enable_clock(i2s_dev_t *hw)
+{
+    (void *)hw;
+    PCR.i2s_tx_clkm_conf.i2s_tx_clkm_en = 1;
+}
+
+/**
+ * @brief Enable I2S rx module clock
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw)
+{
+    (void *)hw;
+    PCR.i2s_rx_clkm_conf.i2s_rx_clkm_en = 1;
+}
+
+/**
+ * @brief Disable I2S tx module clock
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw)
+{
+    (void *)hw;
+    PCR.i2s_tx_clkm_conf.i2s_tx_clkm_en = 0;
+}
+
+/**
+ * @brief Disable I2S rx module clock
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw)
+{
+    (void *)hw;
+    PCR.i2s_rx_clkm_conf.i2s_rx_clkm_en = 0;
+}
+
+/**
+ * @brief I2S mclk use tx module clock
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_mclk_bind_to_tx_clk(i2s_dev_t *hw)
+{
+    (void *)hw;
+    PCR.i2s_rx_clkm_conf.i2s_mclk_sel = 0;
+}
+
+/**
+ * @brief I2S mclk use rx module clock
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_mclk_bind_to_rx_clk(i2s_dev_t *hw)
+{
+    (void *)hw;
+    PCR.i2s_rx_clkm_conf.i2s_mclk_sel = 1;
+}
+
+/**
+ * @brief Enable I2S TX slave mode
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param slave_en Set true to enable slave mode
+ */
+static inline void i2s_ll_tx_set_slave_mod(i2s_dev_t *hw, bool slave_en)
+{
+    hw->tx_conf.tx_slave_mod = slave_en;
+}
+
+/**
+ * @brief Enable I2S RX slave mode
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param slave_en Set true to enable slave mode
+ */
+static inline void i2s_ll_rx_set_slave_mod(i2s_dev_t *hw, bool slave_en)
+{
+    hw->rx_conf.rx_slave_mod = slave_en;
+}
+
+/**
+ * @brief Reset I2S TX module
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_tx_reset(i2s_dev_t *hw)
+{
+    hw->tx_conf.tx_reset = 1;
+    hw->tx_conf.tx_reset = 0;
+}
+
+/**
+ * @brief Reset I2S RX module
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_rx_reset(i2s_dev_t *hw)
+{
+    hw->rx_conf.rx_reset = 1;
+    hw->rx_conf.rx_reset = 0;
+}
+
+/**
+ * @brief Reset I2S TX FIFO
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_tx_reset_fifo(i2s_dev_t *hw)
+{
+    hw->tx_conf.tx_fifo_reset = 1;
+    hw->tx_conf.tx_fifo_reset = 0;
+}
+
+/**
+ * @brief Reset I2S RX FIFO
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw)
+{
+    hw->rx_conf.rx_fifo_reset = 1;
+    hw->rx_conf.rx_fifo_reset = 0;
+}
+
+/**
+ * @brief Set TX source clock
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param src I2S source clock.
+ */
+static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
+{
+    (void *)hw;
+    switch (src)
+    {
+    case I2S_CLK_SRC_XTAL:
+        PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 0;
+        break;
+    case I2S_CLK_SRC_PLL_160M:
+        PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 2;
+        break;
+    default:
+        HAL_ASSERT(false && "unsupported clock source");
+        break;
+    }
+}
+
+/**
+ * @brief Set RX source clock
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param src I2S source clock
+ */
+static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
+{
+    (void *)hw;
+    switch (src)
+    {
+    case I2S_CLK_SRC_XTAL:
+        PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 0;
+        break;
+    case I2S_CLK_SRC_PLL_160M:
+        PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 2;
+        break;
+    default:
+        HAL_ASSERT(false && "unsupported clock source");
+        break;
+    }
+}
+
+/**
+ * @brief Set I2S tx bck div num
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param val value to set tx bck div num
+ */
+static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
+{
+    hw->tx_conf1.tx_bck_div_num = val - 1;
+}
+
+/**
+ * @brief Set I2S tx raw clock division
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param x  div x
+ * @param y  div y
+ * @param z  div z
+ * @param yn1 yn1
+ */
+static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1)
+{
+    (void *)hw;
+    PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = x;
+    PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = y;
+    PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = z;
+    PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = yn1;
+}
+
+/**
+ * @brief Set I2S rx raw clock division
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param x  div x
+ * @param y  div y
+ * @param z  div z
+ * @param yn1 yn1
+ */
+static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1)
+{
+    (void *)hw;
+    PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = x;
+    PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = y;
+    PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = z;
+    PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = yn1;
+}
+
+/**
+ * @brief Configure I2S TX module clock divider
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param sclk system clock
+ * @param mclk module clock
+ * @param mclk_div integer part of the division from sclk to mclk
+ */
+static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mclk, uint32_t mclk_div)
+{
+    (void *)hw;
+    int ma = 0;
+    int mb = 0;
+    int denominator = 1;
+    int numerator = 0;
+
+    uint32_t freq_diff = abs((int)sclk - (int)(mclk * mclk_div));
+    if (!freq_diff) {
+        goto finish;
+    }
+    float decimal = freq_diff / (float)mclk;
+    // Carry bit if the decimal is greater than 1.0 - 1.0 / (63.0 * 2) = 125.0 / 126.0
+    if (decimal > 125.0 / 126.0) {
+        mclk_div++;
+        goto finish;
+    }
+    uint32_t min = ~0;
+    for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) {
+        int b = (int)(a * (freq_diff / (double)mclk) + 0.5);
+        ma = freq_diff * a;
+        mb = mclk * b;
+        if (ma == mb) {
+            denominator = a;
+            numerator = b;
+            goto finish;
+        }
+        if (abs((mb - ma)) < min) {
+            denominator = a;
+            numerator = b;
+            min = abs(mb - ma);
+        }
+    }
+finish:
+    if (denominator == 0 || numerator == 0) {
+        PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = 0;
+        PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = 0;
+        PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = 0;
+    } else {
+        if (numerator > denominator / 2) {
+            PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = denominator / (denominator - numerator) - 1;
+            PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = denominator % (denominator - numerator);
+            PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = denominator - numerator;
+            PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = 1;
+        } else {
+            PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = denominator / numerator - 1;
+            PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = denominator % numerator;
+            PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = numerator;
+            PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = 0;
+        }
+    }
+    HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_tx_clkm_conf, i2s_tx_clkm_div_num, mclk_div);
+}
+
+/**
+ * @brief Set I2S rx bck div num
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param val value to set rx bck div num
+ */
+static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
+{
+    hw->rx_conf1.rx_bck_div_num = val - 1;
+}
+
+/**
+ * @brief Configure I2S RX module clock divider
+ * @note mclk on ESP32 is shared by both TX and RX channel
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param sclk system clock, 0 means use apll
+ * @param mclk module clock
+ * @param mclk_div integer part of the division from sclk to mclk
+ */
+static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mclk, uint32_t mclk_div)
+{
+    (void *)hw;
+    int ma = 0;
+    int mb = 0;
+    int denominator = 1;
+    int numerator = 0;
+
+    uint32_t freq_diff = abs((int)sclk - (int)(mclk * mclk_div));
+    if (!freq_diff) {
+        goto finish;
+    }
+    float decimal = freq_diff / (float)mclk;
+    // Carry bit if the decimal is greater than 1.0 - 1.0 / (63.0 * 2) = 125.0 / 126.0
+    if (decimal > 125.0 / 126.0) {
+        mclk_div++;
+        goto finish;
+    }
+    uint32_t min = ~0;
+    for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) {
+        int b = (int)(a * (freq_diff / (double)mclk) + 0.5);
+        ma = freq_diff * a;
+        mb = mclk * b;
+        if (ma == mb) {
+            denominator = a;
+            numerator = b;
+            goto finish;
+        }
+        if (abs((mb - ma)) < min) {
+            denominator = a;
+            numerator = b;
+            min = abs(mb - ma);
+        }
+    }
+finish:
+    if (denominator == 0 || numerator == 0) {
+        PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = 0;
+        PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = 0;
+        PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = 0;
+    } else {
+        if (numerator > denominator / 2) {
+            PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = denominator / (denominator - numerator) - 1;
+            PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = denominator % (denominator - numerator);
+            PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = denominator - numerator;
+            PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = 1;
+        } else {
+            PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = denominator / numerator - 1;
+            PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = denominator % numerator;
+            PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = numerator;
+            PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = 0;
+        }
+    }
+    HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_rx_clkm_conf, i2s_rx_clkm_div_num, mclk_div);
+}
+
+/**
+ * @brief Start I2S TX
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_tx_start(i2s_dev_t *hw)
+{
+    hw->tx_conf.tx_update = 0;
+    hw->tx_conf.tx_update = 1;
+    hw->tx_conf.tx_start = 1;
+}
+
+/**
+ * @brief Start I2S RX
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_rx_start(i2s_dev_t *hw)
+{
+    hw->rx_conf.rx_update = 0;
+    hw->rx_conf.rx_update = 1;
+    hw->rx_conf.rx_start = 1;
+}
+
+/**
+ * @brief Stop I2S TX
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_tx_stop(i2s_dev_t *hw)
+{
+    hw->tx_conf.tx_start = 0;
+}
+
+/**
+ * @brief Stop I2S RX
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_rx_stop(i2s_dev_t *hw)
+{
+    hw->rx_conf.rx_start = 0;
+}
+
+/**
+ * @brief Configure TX WS signal width
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param width WS width in BCK cycle
+ */
+static inline void i2s_ll_tx_set_ws_width(i2s_dev_t *hw, int width)
+{
+    hw->tx_conf1.tx_tdm_ws_width = width - 1;
+}
+
+/**
+ * @brief Configure RX WS signal width
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param width WS width in BCK cycle
+ */
+static inline void i2s_ll_rx_set_ws_width(i2s_dev_t *hw, int width)
+{
+    hw->rx_conf1.rx_tdm_ws_width = width - 1;
+}
+
+/**
+ * @brief Configure the received length to trigger in_suc_eof interrupt
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param eof_num the byte length to trigger in_suc_eof interrupt
+ */
+static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, int eof_num)
+{
+    hw->rx_eof_num.rx_eof_num = eof_num;
+}
+
+/**
+ * @brief Congfigure TX chan bit and audio data bit
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param chan_bit The chan bit width
+ * @param data_bit The audio data bit width
+ */
+static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit)
+{
+    hw->tx_conf1.tx_bits_mod = data_bit - 1;
+    hw->tx_conf1.tx_tdm_chan_bits = chan_bit - 1;
+}
+
+/**
+ * @brief Congfigure RX chan bit and audio data bit
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param chan_bit The chan bit width
+ * @param data_bit The audio data bit width
+ */
+static inline void i2s_ll_rx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit)
+{
+    hw->rx_conf1.rx_bits_mod = data_bit - 1;
+    hw->rx_conf1.rx_tdm_chan_bits = chan_bit - 1;
+}
+
+/**
+ * @brief Configure RX half_sample_bit
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param half_sample_bits half sample bit width
+ */
+static inline void i2s_ll_tx_set_half_sample_bit(i2s_dev_t *hw, int half_sample_bits)
+{
+    hw->tx_conf1.tx_half_sample_bits = half_sample_bits - 1;
+}
+
+/**
+ * @brief Configure RX half_sample_bit
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param half_sample_bits half sample bit width
+ */
+static inline void i2s_ll_rx_set_half_sample_bit(i2s_dev_t *hw, int half_sample_bits)
+{
+    hw->rx_conf1.rx_half_sample_bits = half_sample_bits - 1;
+}
+
+/**
+ * @brief Enable TX MSB shift, the data will be launch at the first BCK clock
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param msb_shift_enable Set true to enable MSB shift
+ */
+static inline void i2s_ll_tx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable)
+{
+    hw->tx_conf1.tx_msb_shift = msb_shift_enable;
+}
+
+/**
+ * @brief Enable RX MSB shift, the data will be launch at the first BCK clock
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param msb_shift_enable Set true to enable MSB shift
+ */
+static inline void i2s_ll_rx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable)
+{
+    hw->rx_conf1.rx_msb_shift = msb_shift_enable;
+}
+
+/**
+ * @brief Configure TX total chan number
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param total_num Total chan number
+ */
+static inline void i2s_ll_tx_set_chan_num(i2s_dev_t *hw, int total_num)
+{
+    hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1;
+}
+
+/**
+ * @brief Configure RX total chan number
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param total_num Total chan number
+ */
+static inline void i2s_ll_rx_set_chan_num(i2s_dev_t *hw, int total_num)
+{
+    hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1;
+}
+
+/**
+ * @brief Set the bimap of the active TX chan, only the active chan can launch audio data.
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param chan_mask mask of tx active chan
+ */
+static inline void i2s_ll_tx_set_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask)
+{
+    typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl;
+    tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK;
+    tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK;
+    hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val;
+}
+
+/**
+ * @brief Set the bimap of the active RX chan, only the active chan can receive audio data.
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param chan_mask mask of rx active chan
+ */
+static inline void i2s_ll_rx_set_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask)
+{
+    typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl;
+    tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK;
+    tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK;
+    hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val;
+}
+
+/**
+ * @brief Set I2S tx chan mode
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param slot_mask select slot to send data
+ */
+static inline void i2s_ll_tx_select_std_slot(i2s_dev_t *hw, i2s_std_slot_mask_t slot_mask)
+{
+    /* In mono mode, there only should be one slot enabled, another inactive slot will transmit same data as enabled slot
+     * Otherwise always enable the first two slots */
+    hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = 1;  // tx_tdm_tot_chan_num = 2 slots - 1 = 1
+    hw->tx_tdm_ctrl.val &= ~I2S_LL_TDM_CH_MASK;
+    switch (slot_mask)
+    {
+    case I2S_STD_SLOT_LEFT:
+        hw->tx_tdm_ctrl.val |= 0x01;
+        break;
+    case I2S_STD_SLOT_RIGHT:
+        hw->tx_tdm_ctrl.val |= 0x02;
+        break;
+    case I2S_STD_SLOT_BOTH:
+        hw->tx_tdm_ctrl.val |= 0x03;
+        break;
+    default:
+        break;
+    }
+}
+
+/**
+ * @brief Set I2S rx chan mode
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param slot_mask select slot to receive data
+ */
+static inline void i2s_ll_rx_select_std_slot(i2s_dev_t *hw, i2s_std_slot_mask_t slot_mask)
+{
+    /* In mono mode, there only should be one slot enabled, another inactive slot will transmit same data as enabled slot
+     * Otherwise always enable the first two slots */
+    hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = 1;  // rx_tdm_tot_chan_num = 2 slots - 1 = 1
+    hw->rx_tdm_ctrl.val &= ~I2S_LL_TDM_CH_MASK;
+    switch (slot_mask)
+    {
+    case I2S_STD_SLOT_LEFT:
+        hw->rx_tdm_ctrl.val |= 0x01;
+        break;
+    case I2S_STD_SLOT_RIGHT:
+        hw->rx_tdm_ctrl.val |= 0x02;
+        break;
+    case I2S_STD_SLOT_BOTH:
+        hw->rx_tdm_ctrl.val |= 0x03;
+        break;
+    default:
+        break;
+    }
+}
+
+/**
+ * @brief PDM slot mode
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param mod Channel mode
+ *            while tx_ws_idle_pol = 0:
+ *            0: stereo
+ *            1: Both slots transmit left
+ *            2: Both slots transmit right
+ *            3: Left transmits `conf_single_data` right transmits data
+ *            4: Right transmits `conf_single_data` left transmits data
+ *            while tx_ws_idle_pol = 1:
+              0: stereo
+ *            1: Both slots transmit right
+ *            2: Both slots transmit left
+ *            3: Right transmits `conf_single_data` left transmits data
+ *            4: Left transmits `conf_single_data` right transmits data
+ */
+static inline void i2s_ll_tx_set_pdm_chan_mod(i2s_dev_t *hw, uint32_t mod)
+{
+    hw->tx_conf.tx_chan_mod = mod;
+}
+
+/**
+ * @brief Set TX WS signal pol level
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param ws_pol_level pin level of WS(output) when receiving left channel data
+ */
+static inline void i2s_ll_tx_set_ws_idle_pol(i2s_dev_t *hw, bool ws_pol_level)
+{
+    hw->tx_conf.tx_ws_idle_pol = ws_pol_level;
+}
+
+/**
+ * @brief Set RX WS signal pol level
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param ws_pol_level pin level of WS(input) when receiving left channel data
+ */
+static inline void i2s_ll_rx_set_ws_idle_pol(i2s_dev_t *hw, bool ws_pol_level)
+{
+    hw->rx_conf.rx_ws_idle_pol = ws_pol_level;
+}
+
+/**
+ * @brief Enable I2S TX TDM mode
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_tx_enable_tdm(i2s_dev_t *hw)
+{
+    hw->tx_conf.tx_pdm_en = false;
+    hw->tx_conf.tx_tdm_en = true;
+    hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = false;
+}
+
+/**
+ * @brief Enable I2S RX TDM mode
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_rx_enable_tdm(i2s_dev_t *hw)
+{
+    hw->rx_conf.rx_pdm_en = false;
+    hw->rx_conf.rx_tdm_en = true;
+}
+
+/**
+ * @brief Enable I2S TX STD mode
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_tx_enable_std(i2s_dev_t *hw)
+{
+    i2s_ll_tx_enable_tdm(hw);
+}
+
+/**
+ * @brief Enable I2S RX STD mode
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_rx_enable_std(i2s_dev_t *hw)
+{
+    i2s_ll_rx_enable_tdm(hw);
+}
+
+/**
+ * @brief Enable TX PDM mode.
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ */
+static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw)
+{
+    hw->tx_conf.tx_pdm_en = true;
+    hw->tx_conf.tx_tdm_en = false;
+    hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = true;
+}
+
+/**
+ * @brief Set I2S TX PDM prescale
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param prescale I2S TX PDM prescale
+ */
+static inline void i2s_ll_tx_set_pdm_prescale(i2s_dev_t *hw, bool prescale)
+{
+    HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_pcm2pdm_conf, tx_pdm_prescale, prescale);
+}
+
+/**
+ * @brief Set I2S TX PDM high pass filter scaling
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param sig_scale I2S TX PDM signal scaling before transmit to the filter
+ */
+static inline void i2s_ll_tx_set_pdm_hp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale)
+{
+    hw->tx_pcm2pdm_conf.tx_pdm_hp_in_shift = sig_scale;
+}
+
+/**
+ * @brief Set I2S TX PDM low pass filter scaling
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param sig_scale I2S TX PDM signal scaling before transmit to the filter
+ */
+static inline void i2s_ll_tx_set_pdm_lp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale)
+{
+    hw->tx_pcm2pdm_conf.tx_pdm_lp_in_shift = sig_scale;
+}
+
+/**
+ * @brief Set I2S TX PDM sinc filter scaling
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param sig_scale I2S TX PDM signal scaling before transmit to the filter
+ */
+static inline void i2s_ll_tx_set_pdm_sinc_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale)
+{
+    hw->tx_pcm2pdm_conf.tx_pdm_sinc_in_shift = sig_scale;
+}
+
+/**
+ * @brief Set I2S TX PDM sigma-delta filter scaling
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param sig_scale I2S TX PDM signal scaling before transmit to the filter
+ */
+static inline void i2s_ll_tx_set_pdm_sd_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale)
+{
+    hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_in_shift = sig_scale;
+}
+
+/**
+ * @brief Set I2S TX PDM high pass filter param0
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param param The fourth parameter of PDM TX IIR_HP filter stage 1 is (504 + I2S_TX_IIR_HP_MULT12_0[2:0])
+ */
+static inline void i2s_ll_tx_set_pdm_hp_filter_param0(i2s_dev_t *hw, uint32_t param)
+{
+    hw->tx_pcm2pdm_conf1.tx_iir_hp_mult12_0 = param;
+}
+
+/**
+ * @brief Set I2S TX PDM high pass filter param5
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param param The fourth parameter of PDM TX IIR_HP filter stage 2 is (504 + I2S_TX_IIR_HP_MULT12_5[2:0])
+ */
+static inline void i2s_ll_tx_set_pdm_hp_filter_param5(i2s_dev_t *hw, uint32_t param)
+{
+    hw->tx_pcm2pdm_conf1.tx_iir_hp_mult12_5 = param;
+}
+
+/**
+ * @brief Enable I2S TX PDM high pass filter
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param enable Set true to enable I2S TX PDM high pass filter, set false to bypass it
+ */
+static inline void i2s_ll_tx_enable_pdm_hp_filter(i2s_dev_t *hw, bool enable)
+{
+    hw->tx_pcm2pdm_conf.tx_pdm_hp_bypass = !enable;
+}
+
+/**
+ * @brief Set I2S TX PDM sigma-delta codec dither
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param dither I2S TX PDM sigmadelta dither value
+ */
+static inline void i2s_ll_tx_set_pdm_sd_dither(i2s_dev_t *hw, uint32_t dither)
+{
+    hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_dither = dither;
+}
+
+/**
+ * @brief Set I2S TX PDM sigma-delta codec dither
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param dither2 I2S TX PDM sigmadelta dither2 value
+ */
+static inline void i2s_ll_tx_set_pdm_sd_dither2(i2s_dev_t *hw, uint32_t dither2)
+{
+    hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_dither2 = dither2;
+}
+
+/**
+ * @brief Configure I2S TX PDM sample rate
+ *        Fpdm = 64*Fpcm*fp/fs
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param fp The fp value of TX PDM filter module group0.
+ * @param fs The fs value of TX PDM filter module group0.
+ */
+static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs)
+{
+    hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp;
+    hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs;
+    hw->tx_pcm2pdm_conf.tx_pdm_sinc_osr2 = fp / fs;
+}
+
+/**
+ * @brief Get I2S TX PDM fp configuration paramater
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @return
+ *        - fp configuration paramater
+ */
+static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw)
+{
+    return hw->tx_pcm2pdm_conf1.tx_pdm_fp;
+}
+
+/**
+ * @brief Get I2S TX PDM fs configuration paramater
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @return
+ *        - fs configuration paramater
+ */
+static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw)
+{
+    return hw->tx_pcm2pdm_conf1.tx_pdm_fs;
+}
+
+/**
+ * @brief Enable RX PDM mode.
+ * @note  ESP32-C6 doesn't support pdm in rx mode, disable anyway
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param pdm_enable Set true to RX enable PDM mode (ignored)
+ */
+static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable)
+{
+    hw->rx_conf.rx_pdm_en = 0;
+    hw->rx_conf.rx_tdm_en = 1;
+}
+
+/**
+ * @brief Configura TX a/u-law decompress or compress
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param pcm_cfg PCM configuration paramater
+ */
+static inline void i2s_ll_tx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg)
+{
+    hw->tx_conf.tx_pcm_conf = pcm_cfg;
+    hw->tx_conf.tx_pcm_bypass = !pcm_cfg;
+}
+
+/**
+ * @brief Configure RX a/u-law decompress or compress
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param pcm_cfg PCM configuration paramater
+ */
+static inline void i2s_ll_rx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg)
+{
+    hw->rx_conf.rx_pcm_conf = pcm_cfg;
+    hw->rx_conf.rx_pcm_bypass = !pcm_cfg;
+}
+
+/**
+ * @brief Enable TX audio data left alignment
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param ena Set true to enable left alignment
+ */
+static inline void i2s_ll_tx_enable_left_align(i2s_dev_t *hw, bool ena)
+{
+    hw->tx_conf.tx_left_align = ena;
+}
+
+/**
+ * @brief Enable RX audio data left alignment
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param ena Set true to enable left alignment
+ */
+static inline void i2s_ll_rx_enable_left_align(i2s_dev_t *hw, bool ena)
+{
+    hw->rx_conf.rx_left_align = ena;
+}
+
+/**
+ * @brief Enable TX big endian mode
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param ena Set true to enable big endian mode
+ */
+static inline void i2s_ll_rx_enable_big_endian(i2s_dev_t *hw, bool ena)
+{
+    hw->rx_conf.rx_big_endian = ena;
+}
+
+/**
+ * @brief Enable RX big endian mode
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param ena Set true to enable big endian mode
+ */
+static inline void i2s_ll_tx_enable_big_endian(i2s_dev_t *hw, bool ena)
+{
+    hw->tx_conf.tx_big_endian = ena;
+}
+
+/**
+ * @brief Configure TX bit order
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param lsb_order_ena Set true to enable LSB bit order
+ */
+static inline void i2s_ll_tx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena)
+{
+    hw->tx_conf.tx_bit_order = lsb_order_ena;
+}
+
+/**
+ * @brief Configure RX bit order
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param lsb_order_ena Set true to enable LSB bit order
+ */
+static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena)
+{
+    hw->rx_conf.rx_bit_order = lsb_order_ena;
+}
+
+/**
+ * @brief Configure TX skip mask enable
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param skip_mask_ena Set true to skip inactive channels.
+ */
+static inline void i2s_ll_tx_set_skip_mask(i2s_dev_t *hw, bool skip_mask_ena)
+{
+    hw->tx_tdm_ctrl.tx_tdm_skip_msk_en = skip_mask_ena;
+}
+
+
+/**
+ * @brief Configure single data
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param data Single data to be set
+ */
+static inline void i2s_ll_set_single_data(i2s_dev_t *hw, uint32_t data)
+{
+    hw->conf_single_data.val = data;
+}
+
+/**
+ * @brief Enable TX mono mode
+ * @note MONO in hardware means only one channel got data, but another doesn't
+ *       MONO in software means two channel share same data
+ *       This function aims to use MONO in software meaning
+ *       so 'tx_mono' and 'tx_chan_equal' should be enabled at the same time
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param mono_ena Set true to enable mono mde.
+ */
+static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena)
+{
+    hw->tx_conf.tx_mono = mono_ena;
+    hw->tx_conf.tx_chan_equal = mono_ena;
+}
+
+/**
+ * @brief Enable RX mono mode
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param mono_ena Set true to enable mono mde.
+ */
+static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena)
+{
+    hw->rx_conf.rx_mono = mono_ena;
+    hw->rx_conf.rx_mono_fst_vld = mono_ena;
+}
+
+/**
+ * @brief Enable loopback mode
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param ena Set true to share BCK and WS signal for tx module and rx module.
+ */
+static inline void i2s_ll_share_bck_ws(i2s_dev_t *hw, bool ena)
+{
+    hw->tx_conf.sig_loopback = ena;
+}
+
+/**
+ * @brief PDM TX DMA data take mode
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param is_mono   The DMA data only has one slot (mono) or contains two slots (stereo)
+ * @param is_fst_valid  Whether take the DMA data at the first half period
+ *                      Only take effet when 'is_mono' is true
+ */
+static inline void i2s_ll_tx_pdm_dma_take_mode(i2s_dev_t *hw, bool is_mono, bool is_fst_valid)
+{
+    hw->tx_conf.tx_mono = is_mono;
+    hw->tx_conf.tx_mono_fst_vld = is_fst_valid;
+}
+
+/**
+ * @brief PDM TX slot mode
+ * @note     Mode     Left Slot       Right Slot      Chan Mode       WS Pol
+ *          -----------------------------------------------------------------
+ *           Stereo   Left            Right           0               x
+ *          -----------------------------------------------------------------
+ *           Mono     Left            Left            1               0
+ *           Mono     Right           Right           2               0
+ *           Mono     Single          Right           3               0
+ *           Mono     Left            Single          4               0
+ *          -----------------------------------------------------------------
+ *           Mono     Right           Right           1               1
+ *           Mono     Left            Left            2               1
+ *           Mono     Left            Single          3               1
+ *           Mono     Single          Right           4               1
+ * @note  The 'Single' above means always sending the value of `conf_single_data` reg
+ *        The default value of `conf_single_data` reg is '0', it is not public for now
+ *
+ * @param hw Peripheral I2S hardware instance address.
+ * @param is_mono   The DMA data only has one slot (mono) or contains two slots (stereo)
+ * @param is_copy   Whether the un-selected slot copies the data from the selected one
+ *                  If not, the un-selected slot will transmit the data from 'conf_single_data'
+ * @param mask      The slot mask to selet the slot
+ */
+static inline void i2s_ll_tx_pdm_slot_mode(i2s_dev_t *hw, bool is_mono, bool is_copy, i2s_pdm_slot_mask_t mask)
+{
+    if (is_mono) {
+        /* The default tx_ws_idle_pol is false */
+        if (is_copy) {
+            hw->tx_conf.tx_chan_mod = mask == I2S_PDM_SLOT_LEFT ? 1 : 2;
+        } else {
+            hw->tx_conf.tx_chan_mod = mask == I2S_PDM_SLOT_LEFT ? 4 : 3;
+        }
+    } else {
+        hw->tx_conf.tx_chan_mod = 0;
+    }
+}
+
+/**
+ * @brief PDM TX line mode
+ * @note    Mode         DAC Mode        2 lines output
+ *          -------------------------------------------
+ *          PDM codec    0               1
+ *          DAC 1-line   1               0
+ *          DAC 2-line   1               1
+ *
+ * @param hw    Peripheral I2S hardware instance address.
+ * @param line_mode    PDM TX line mode
+ */
+static inline void i2s_ll_tx_pdm_line_mode(i2s_dev_t *hw, i2s_pdm_tx_line_mode_t line_mode)
+{
+    hw->tx_pcm2pdm_conf.tx_pdm_dac_mode_en = line_mode > I2S_PDM_TX_ONE_LINE_CODEC;
+    hw->tx_pcm2pdm_conf.tx_pdm_dac_2out_en = line_mode != I2S_PDM_TX_ONE_LINE_DAC;
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 28 - 7
components/hal/esp32h2/include/hal/i2s_ll.h

@@ -15,6 +15,7 @@
 #pragma once
 #pragma once
 #include <stdbool.h>
 #include <stdbool.h>
 #include "hal/misc.h"
 #include "hal/misc.h"
+#include "hal/assert.h"
 #include "soc/i2s_periph.h"
 #include "soc/i2s_periph.h"
 #include "soc/i2s_struct.h"
 #include "soc/i2s_struct.h"
 #include "hal/i2s_types.h"
 #include "hal/i2s_types.h"
@@ -24,12 +25,10 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-#define I2S_LL_GET_HW(num)             (&I2S0)
+#define I2S_LL_GET_HW(num)             (((num) == 0)? (&I2S0) : NULL)
 
 
 #define I2S_LL_TDM_CH_MASK             (0xffff)
 #define I2S_LL_TDM_CH_MASK             (0xffff)
 #define I2S_LL_PDM_BCK_FACTOR          (64)
 #define I2S_LL_PDM_BCK_FACTOR          (64)
-// [clk_tree] TODO: replace the following switch table by clk_tree API
-#define I2S_LL_BASE_CLK                (96*1000000)
 
 
 #define I2S_LL_MCLK_DIVIDER_BIT_WIDTH  (9)
 #define I2S_LL_MCLK_DIVIDER_BIT_WIDTH  (9)
 #define I2S_LL_MCLK_DIVIDER_MAX        ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
 #define I2S_LL_MCLK_DIVIDER_MAX        ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
@@ -195,18 +194,40 @@ static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw)
  */
  */
 static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
 static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
 {
 {
-    hw->tx_clkm_conf.tx_clk_sel = 2;
+    switch (src)
+    {
+    case I2S_CLK_SRC_XTAL:
+        hw->tx_clkm_conf.tx_clk_sel = 0;
+        break;
+    case I2S_CLK_SRC_PLL_96M:
+        hw->tx_clkm_conf.tx_clk_sel = 2;
+        break;
+    default:
+        HAL_ASSERT(false && "unsupported clock source");
+        break;
+    }
 }
 }
 
 
 /**
 /**
  * @brief Set RX source clock
  * @brief Set RX source clock
  *
  *
  * @param hw Peripheral I2S hardware instance address.
  * @param hw Peripheral I2S hardware instance address.
- * @param src I2S source clock, ESP32-H2 only support `I2S_CLK_SRC_PLL_96M` for now
+ * @param src I2S source clock
  */
  */
 static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
 static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
 {
 {
-    hw->rx_clkm_conf.rx_clk_sel = 2;
+    switch (src)
+    {
+    case I2S_CLK_SRC_XTAL:
+        hw->rx_clkm_conf.rx_clk_sel = 0;
+        break;
+    case I2S_CLK_SRC_PLL_96M:
+        hw->rx_clkm_conf.rx_clk_sel = 2;
+        break;
+    default:
+        HAL_ASSERT(false && "unsupported clock source");
+        break;
+    }
 }
 }
 
 
 /**
 /**
@@ -258,7 +279,7 @@ static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t
  * @brief Configure I2S TX module clock divider
  * @brief Configure I2S TX module clock divider
  *
  *
  * @param hw Peripheral I2S hardware instance address.
  * @param hw Peripheral I2S hardware instance address.
- * @param sclk system clock, 0 means use apll
+ * @param sclk system clock
  * @param mclk module clock
  * @param mclk module clock
  * @param mclk_div integer part of the division from sclk to mclk
  * @param mclk_div integer part of the division from sclk to mclk
  */
  */

+ 2 - 4
components/hal/esp32s2/include/hal/i2s_ll.h

@@ -28,8 +28,6 @@ extern "C" {
 // Get I2S hardware instance with giving i2s num
 // Get I2S hardware instance with giving i2s num
 #define I2S_LL_GET_HW(num)             (((num) == 0) ? (&I2S0) : NULL)
 #define I2S_LL_GET_HW(num)             (((num) == 0) ? (&I2S0) : NULL)
 
 
-#define I2S_LL_BASE_CLK                (2 * APB_CLK_FREQ)
-
 #define I2S_LL_BCK_MAX_PRESCALE  (64)
 #define I2S_LL_BCK_MAX_PRESCALE  (64)
 
 
 #define I2S_LL_MCLK_DIVIDER_BIT_WIDTH  (6)
 #define I2S_LL_MCLK_DIVIDER_BIT_WIDTH  (6)
@@ -280,7 +278,7 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
  * @note mclk on ESP32S2 is shared by both TX and RX channel
  * @note mclk on ESP32S2 is shared by both TX and RX channel
  *
  *
  * @param hw Peripheral I2S hardware instance address.
  * @param hw Peripheral I2S hardware instance address.
- * @param sclk system clock, 0 means use apll
+ * @param sclk system clock
  * @param mclk module clock
  * @param mclk module clock
  * @param mclk_div integer part of the division from sclk to mclk
  * @param mclk_div integer part of the division from sclk to mclk
  */
  */
@@ -356,7 +354,7 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
  * @note mclk on ESP32S2 is shared by both TX and RX channel
  * @note mclk on ESP32S2 is shared by both TX and RX channel
  *
  *
  * @param hw Peripheral I2S hardware instance address.
  * @param hw Peripheral I2S hardware instance address.
- * @param sclk system clock, 0 means use apll
+ * @param sclk system clock
  * @param mclk module clock
  * @param mclk module clock
  * @param mclk_div integer part of the division from sclk to mclk
  * @param mclk_div integer part of the division from sclk to mclk
  */
  */

+ 28 - 9
components/hal/esp32s3/include/hal/i2s_ll.h

@@ -14,6 +14,7 @@
 #pragma once
 #pragma once
 #include <stdbool.h>
 #include <stdbool.h>
 #include "hal/misc.h"
 #include "hal/misc.h"
+#include "hal/assert.h"
 #include "soc/i2s_periph.h"
 #include "soc/i2s_periph.h"
 #include "soc/i2s_struct.h"
 #include "soc/i2s_struct.h"
 #include "hal/i2s_types.h"
 #include "hal/i2s_types.h"
@@ -28,7 +29,6 @@ extern "C" {
 
 
 #define I2S_LL_TDM_CH_MASK (0xffff)
 #define I2S_LL_TDM_CH_MASK (0xffff)
 #define I2S_LL_PDM_BCK_FACTOR          (64)
 #define I2S_LL_PDM_BCK_FACTOR          (64)
-#define I2S_LL_BASE_CLK                (2*APB_CLK_FREQ)
 
 
 #define I2S_LL_MCLK_DIVIDER_BIT_WIDTH  (9)
 #define I2S_LL_MCLK_DIVIDER_BIT_WIDTH  (9)
 #define I2S_LL_MCLK_DIVIDER_MAX        ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
 #define I2S_LL_MCLK_DIVIDER_MAX        ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
@@ -190,26 +190,45 @@ static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw)
  * @brief Set TX source clock
  * @brief Set TX source clock
  *
  *
  * @param hw Peripheral I2S hardware instance address.
  * @param hw Peripheral I2S hardware instance address.
- * @param src I2S source clock,  ESP32-S3 only support `I2S_CLK_SRC_PLL_160M`
- *            TX and RX share the same clock setting
+ * @param src I2S source clock.
  */
  */
 static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
 static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
 {
 {
-    hw->tx_clkm_conf.tx_clk_sel = 2;
+    switch (src)
+    {
+    case I2S_CLK_SRC_XTAL:
+        hw->tx_clkm_conf.tx_clk_sel = 0;
+        break;
+    case I2S_CLK_SRC_PLL_160M:
+        hw->tx_clkm_conf.tx_clk_sel = 2;
+        break;
+    default:
+        HAL_ASSERT(false && "unsupported clock source");
+        break;
+    }
 }
 }
 
 
 /**
 /**
  * @brief Set RX source clock
  * @brief Set RX source clock
  *
  *
  * @param hw Peripheral I2S hardware instance address.
  * @param hw Peripheral I2S hardware instance address.
- * @param src I2S source clock,  ESP32-S3 only support `I2S_CLK_SRC_PLL_160M`
- *            TX and RX share the same clock setting
+ * @param src I2S source clock
  */
  */
 static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
 static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
 {
 {
-    hw->rx_clkm_conf.rx_clk_sel = 2;
+    switch (src)
+    {
+    case I2S_CLK_SRC_XTAL:
+        hw->rx_clkm_conf.rx_clk_sel = 0;
+        break;
+    case I2S_CLK_SRC_PLL_160M:
+        hw->rx_clkm_conf.rx_clk_sel = 2;
+        break;
+    default:
+        HAL_ASSERT(false && "unsupported clock source");
+        break;
+    }
 }
 }
-
 /**
 /**
  * @brief Set I2S tx bck div num
  * @brief Set I2S tx bck div num
  *
  *
@@ -259,7 +278,7 @@ static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t
  * @brief Configure I2S TX module clock divider
  * @brief Configure I2S TX module clock divider
  *
  *
  * @param hw Peripheral I2S hardware instance address.
  * @param hw Peripheral I2S hardware instance address.
- * @param sclk system clock, 0 means use apll
+ * @param sclk system clock
  * @param mclk module clock
  * @param mclk module clock
  * @param mclk_div integer part of the division from sclk to mclk
  * @param mclk_div integer part of the division from sclk to mclk
  */
  */

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

@@ -363,6 +363,10 @@ config SOC_I2S_HW_VERSION_2
     bool
     bool
     default y
     default y
 
 
+config SOC_I2S_SUPPORTS_XTAL
+    bool
+    default y
+
 config SOC_I2S_SUPPORTS_PCM
 config SOC_I2S_SUPPORTS_PCM
     bool
     bool
     default y
     default y

+ 2 - 1
components/soc/esp32c3/include/soc/clk_tree_defs.h

@@ -206,7 +206,7 @@ typedef enum {
 /**
 /**
  * @brief Array initializer for all supported clock sources of I2S
  * @brief Array initializer for all supported clock sources of I2S
  */
  */
-#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL_F160M}
+#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL}
 
 
 /**
 /**
  * @brief I2S clock source enum
  * @brief I2S clock source enum
@@ -214,6 +214,7 @@ typedef enum {
 typedef enum {
 typedef enum {
     I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M,                /*!< Select PLL_F160M as the default source clock  */
     I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M,                /*!< Select PLL_F160M as the default source clock  */
     I2S_CLK_SRC_PLL_160M = SOC_MOD_CLK_PLL_F160M,               /*!< Select PLL_F160M as the source clock */
     I2S_CLK_SRC_PLL_160M = SOC_MOD_CLK_PLL_F160M,               /*!< Select PLL_F160M as the source clock */
+    I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL,                        /*!< Select XTAL as the source clock */
 } soc_periph_i2s_clk_src_t;
 } soc_periph_i2s_clk_src_t;
 
 
 /////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////

+ 2 - 2
components/soc/esp32c3/include/soc/i2s_struct.h

@@ -140,7 +140,7 @@ typedef volatile struct i2s_dev_s {
             uint32_t rx_clkm_div_num: 8;             /*Integral I2S clock divider value*/
             uint32_t rx_clkm_div_num: 8;             /*Integral I2S clock divider value*/
             uint32_t reserved8:      18;             /*Reserved*/
             uint32_t reserved8:      18;             /*Reserved*/
             uint32_t rx_clk_active:   1;             /*I2S Rx module clock enable signal.*/
             uint32_t rx_clk_active:   1;             /*I2S Rx module clock enable signal.*/
-            uint32_t rx_clk_sel:      2;             /*Select I2S Rx module source clock. 0: no clock. 1: APLL. 2: CLK160. 3: I2S_MCLK_in.*/
+            uint32_t rx_clk_sel:      2;             /*Select I2S Rx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3: I2S_MCLK_in.*/
             uint32_t mclk_sel:        1;             /*0: UseI2S Tx module clock as I2S_MCLK_OUT.  1: UseI2S Rx module clock as I2S_MCLK_OUT.*/
             uint32_t mclk_sel:        1;             /*0: UseI2S Tx module clock as I2S_MCLK_OUT.  1: UseI2S Rx module clock as I2S_MCLK_OUT.*/
             uint32_t reserved30:      2;             /*Reserved*/
             uint32_t reserved30:      2;             /*Reserved*/
         };
         };
@@ -151,7 +151,7 @@ typedef volatile struct i2s_dev_s {
             uint32_t tx_clkm_div_num: 8;             /*Integral I2S TX clock divider value. f_I2S_CLK = f_I2S_CLK_S/(N+b/a). There will be (a-b) * n-div and b * (n+1)-div.  So the average combination will be:  for b <= a/2  z * [x * n-div + (n+1)-div] + y * n-div. For b > a/2  z * [n-div + x * (n+1)-div] + y * (n+1)-div.*/
             uint32_t tx_clkm_div_num: 8;             /*Integral I2S TX clock divider value. f_I2S_CLK = f_I2S_CLK_S/(N+b/a). There will be (a-b) * n-div and b * (n+1)-div.  So the average combination will be:  for b <= a/2  z * [x * n-div + (n+1)-div] + y * n-div. For b > a/2  z * [n-div + x * (n+1)-div] + y * (n+1)-div.*/
             uint32_t reserved8:      18;             /*Reserved*/
             uint32_t reserved8:      18;             /*Reserved*/
             uint32_t tx_clk_active:   1;             /*I2S Tx module clock enable signal.*/
             uint32_t tx_clk_active:   1;             /*I2S Tx module clock enable signal.*/
-            uint32_t tx_clk_sel:      2;             /*Select I2S Tx module source clock. 0: XTAL clock. 1: APLL. 2: CLK160. 3: I2S_MCLK_in.*/
+            uint32_t tx_clk_sel:      2;             /*Select I2S Tx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3: I2S_MCLK_in.*/
             uint32_t clk_en:          1;             /*Set this bit to enable clk gate*/
             uint32_t clk_en:          1;             /*Set this bit to enable clk gate*/
             uint32_t reserved30:      2;             /*Reserved*/
             uint32_t reserved30:      2;             /*Reserved*/
         };
         };

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

@@ -179,6 +179,7 @@
 /*-------------------------- I2S CAPS ----------------------------------------*/
 /*-------------------------- I2S CAPS ----------------------------------------*/
 #define SOC_I2S_NUM                 (1)
 #define SOC_I2S_NUM                 (1)
 #define SOC_I2S_HW_VERSION_2        (1)
 #define SOC_I2S_HW_VERSION_2        (1)
+#define SOC_I2S_SUPPORTS_XTAL       (1)
 #define SOC_I2S_SUPPORTS_PCM        (1)
 #define SOC_I2S_SUPPORTS_PCM        (1)
 #define SOC_I2S_SUPPORTS_PDM        (1)
 #define SOC_I2S_SUPPORTS_PDM        (1)
 #define SOC_I2S_SUPPORTS_PDM_TX     (1)
 #define SOC_I2S_SUPPORTS_PDM_TX     (1)

+ 0 - 1
components/soc/esp32c6/CMakeLists.txt

@@ -20,7 +20,6 @@ list(REMOVE_ITEM srcs
         "adc_periph.c"                  # TODO: IDF-5310
         "adc_periph.c"                  # TODO: IDF-5310
         "dedic_gpio_periph.c"           # TODO: IDF-5331
         "dedic_gpio_periph.c"           # TODO: IDF-5331
         "ledc_periph.c"                 # TODO: IDF-5328
         "ledc_periph.c"                 # TODO: IDF-5328
-        "i2s_periph.c"                  # TODO: IDF-5314
         "i2c_periph.c"                  # TODO: IDF-5326
         "i2c_periph.c"                  # TODO: IDF-5326
         "temperature_sensor_periph.c"   # TODO: IDF-5322
         "temperature_sensor_periph.c"   # TODO: IDF-5322
         )
         )

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

@@ -43,6 +43,10 @@ config SOC_RTC_MEM_SUPPORTED
     bool
     bool
     default y
     default y
 
 
+config SOC_I2S_SUPPORTED
+    bool
+    default y
+
 config SOC_SYSTIMER_SUPPORTED
 config SOC_SYSTIMER_SUPPORTED
     bool
     bool
     default y
     default y
@@ -287,6 +291,10 @@ config SOC_I2S_HW_VERSION_2
     bool
     bool
     default y
     default y
 
 
+config SOC_I2S_SUPPORTS_XTAL
+    bool
+    default y
+
 config SOC_I2S_SUPPORTS_PCM
 config SOC_I2S_SUPPORTS_PCM
     bool
     bool
     default y
     default y

+ 10 - 1
components/soc/esp32c6/include/soc/clk_tree_defs.h

@@ -215,14 +215,23 @@ typedef enum {
 /**
 /**
  * @brief Array initializer for all supported clock sources of I2S
  * @brief Array initializer for all supported clock sources of I2S
  */
  */
-#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL_F160M}
+#if CONFIG_IDF_ENV_FPGA
+#define SOC_I2S_CLKS {SOC_MOD_CLK_XTAL}
+#else
+#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL}
+#endif
 
 
 /**
 /**
  * @brief I2S clock source enum
  * @brief I2S clock source enum
  */
  */
 typedef enum {
 typedef enum {
+#if CONFIG_IDF_ENV_FPGA
+    I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL,
+#else
     I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M,                /*!< Select PLL_F160M as the default source clock  */
     I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M,                /*!< Select PLL_F160M as the default source clock  */
+#endif
     I2S_CLK_SRC_PLL_160M = SOC_MOD_CLK_PLL_F160M,               /*!< Select PLL_F160M as the source clock */
     I2S_CLK_SRC_PLL_160M = SOC_MOD_CLK_PLL_F160M,               /*!< Select PLL_F160M as the source clock */
+    I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL,                        /*!< Select XTAL as the source clock */
 } soc_periph_i2s_clk_src_t;
 } soc_periph_i2s_clk_src_t;
 
 
 /////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////

+ 8 - 8
components/soc/esp32c6/include/soc/i2s_struct.h

@@ -255,7 +255,7 @@ typedef union {
          */
          */
         uint32_t rx_clk_active:1;
         uint32_t rx_clk_active:1;
         /** rx_clk_sel : R/W; bitpos: [28:27]; default: 0;
         /** rx_clk_sel : R/W; bitpos: [28:27]; default: 0;
-         *  Select I2S Rx module source clock. 0: no clock. 1: APLL. 2: CLK160. 3: I2S_MCLK_in.
+         *  Select I2S Rx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3: I2S_MCLK_in.
          */
          */
         uint32_t rx_clk_sel:2;
         uint32_t rx_clk_sel:2;
         /** mclk_sel : R/W; bitpos: [29]; default: 0;
         /** mclk_sel : R/W; bitpos: [29]; default: 0;
@@ -448,7 +448,7 @@ typedef union {
     uint32_t val;
     uint32_t val;
 } i2s_rx_tdm_ctrl_reg_t;
 } i2s_rx_tdm_ctrl_reg_t;
 
 
-/** Type of rxeof_num register
+/** Type of rx_eof_num register
  *  I2S RX data number control register.
  *  I2S RX data number control register.
  */
  */
 typedef union {
 typedef union {
@@ -461,7 +461,7 @@ typedef union {
         uint32_t reserved_12:20;
         uint32_t reserved_12:20;
     };
     };
     uint32_t val;
     uint32_t val;
-} i2s_rxeof_num_reg_t;
+} i2s_rx_eof_num_reg_t;
 
 
 
 
 /** Group: TX Control and configuration registers */
 /** Group: TX Control and configuration registers */
@@ -627,7 +627,7 @@ typedef union {
          */
          */
         uint32_t tx_clk_active:1;
         uint32_t tx_clk_active:1;
         /** tx_clk_sel : R/W; bitpos: [28:27]; default: 0;
         /** tx_clk_sel : R/W; bitpos: [28:27]; default: 0;
-         *  Select I2S Tx module source clock. 0: XTAL clock. 1: APLL. 2: CLK160. 3:
+         *  Select I2S Tx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3:
          *  I2S_MCLK_in.
          *  I2S_MCLK_in.
          */
          */
         uint32_t tx_clk_sel:2;
         uint32_t tx_clk_sel:2;
@@ -914,7 +914,7 @@ typedef union {
     uint32_t val;
     uint32_t val;
 } i2s_lc_hung_conf_reg_t;
 } i2s_lc_hung_conf_reg_t;
 
 
-/** Type of conf_sigle_data register
+/** Type of conf_single_data register
  *  I2S signal data register
  *  I2S signal data register
  */
  */
 typedef union {
 typedef union {
@@ -925,7 +925,7 @@ typedef union {
         uint32_t single_data:32;
         uint32_t single_data:32;
     };
     };
     uint32_t val;
     uint32_t val;
-} i2s_conf_sigle_data_reg_t;
+} i2s_conf_single_data_reg_t;
 
 
 
 
 /** Group: TX status registers */
 /** Group: TX status registers */
@@ -1005,8 +1005,8 @@ typedef struct i2s_dev_t {
     volatile i2s_rx_timing_reg_t rx_timing;
     volatile i2s_rx_timing_reg_t rx_timing;
     volatile i2s_tx_timing_reg_t tx_timing;
     volatile i2s_tx_timing_reg_t tx_timing;
     volatile i2s_lc_hung_conf_reg_t lc_hung_conf;
     volatile i2s_lc_hung_conf_reg_t lc_hung_conf;
-    volatile i2s_rxeof_num_reg_t rxeof_num;
-    volatile i2s_conf_sigle_data_reg_t conf_sigle_data;
+    volatile i2s_rx_eof_num_reg_t rx_eof_num;
+    volatile i2s_conf_single_data_reg_t conf_single_data;
     volatile i2s_state_reg_t state;
     volatile i2s_state_reg_t state;
     volatile i2s_etm_conf_reg_t etm_conf;
     volatile i2s_etm_conf_reg_t etm_conf;
     uint32_t reserved_074[3];
     uint32_t reserved_074[3];

+ 2 - 2
components/soc/esp32c6/include/soc/pcr_struct.h

@@ -607,7 +607,7 @@ typedef union {
          */
          */
         uint32_t i2s_tx_clkm_div_num:8;
         uint32_t i2s_tx_clkm_div_num:8;
         /** i2s_tx_clkm_sel : R/W; bitpos: [21:20]; default: 0;
         /** i2s_tx_clkm_sel : R/W; bitpos: [21:20]; default: 0;
-         *  Select I2S Tx module source clock. 0: XTAL clock. 1: APLL. 2: CLK160. 3:
+         *  Select I2S Tx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3:
          *  I2S_MCLK_in.
          *  I2S_MCLK_in.
          */
          */
         uint32_t i2s_tx_clkm_sel:2;
         uint32_t i2s_tx_clkm_sel:2;
@@ -661,7 +661,7 @@ typedef union {
          */
          */
         uint32_t i2s_rx_clkm_div_num:8;
         uint32_t i2s_rx_clkm_div_num:8;
         /** i2s_rx_clkm_sel : R/W; bitpos: [21:20]; default: 0;
         /** i2s_rx_clkm_sel : R/W; bitpos: [21:20]; default: 0;
-         *  Select I2S Rx module source clock. 0: no clock. 1: APLL. 2: CLK160. 3: I2S_MCLK_in.
+         *  Select I2S Rx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3: I2S_MCLK_in.
          */
          */
         uint32_t i2s_rx_clkm_sel:2;
         uint32_t i2s_rx_clkm_sel:2;
         /** i2s_rx_clkm_en : R/W; bitpos: [22]; default: 1;
         /** i2s_rx_clkm_en : R/W; bitpos: [22]; default: 1;

+ 2 - 2
components/soc/esp32c6/include/soc/soc_caps.h

@@ -40,7 +40,7 @@
 #define SOC_EFUSE_KEY_PURPOSE_FIELD     1
 #define SOC_EFUSE_KEY_PURPOSE_FIELD     1
 #define SOC_RTC_FAST_MEM_SUPPORTED      1
 #define SOC_RTC_FAST_MEM_SUPPORTED      1
 #define SOC_RTC_MEM_SUPPORTED           1
 #define SOC_RTC_MEM_SUPPORTED           1
-// #define SOC_I2S_SUPPORTED               1 // TODO: IDF-5314
+#define SOC_I2S_SUPPORTED               1
 // #define SOC_RMT_SUPPORTED               1 // TODO: IDF-5320
 // #define SOC_RMT_SUPPORTED               1 // TODO: IDF-5320
 // #define SOC_SDM_SUPPORTED               1 // TODO: IDF-5318
 // #define SOC_SDM_SUPPORTED               1 // TODO: IDF-5318
 // #define SOC_LEDC_SUPPORTED              1 // TODO: IDF-5328
 // #define SOC_LEDC_SUPPORTED              1 // TODO: IDF-5328
@@ -181,10 +181,10 @@
 #define SOC_I2C_SUPPORT_XTAL        (1)
 #define SOC_I2C_SUPPORT_XTAL        (1)
 #define SOC_I2C_SUPPORT_RTC         (1)
 #define SOC_I2C_SUPPORT_RTC         (1)
 
 
-// TODO: IDF-5314 (Copy from esp32c3, need check)
 /*-------------------------- I2S CAPS ----------------------------------------*/
 /*-------------------------- I2S CAPS ----------------------------------------*/
 #define SOC_I2S_NUM                 (1)
 #define SOC_I2S_NUM                 (1)
 #define SOC_I2S_HW_VERSION_2        (1)
 #define SOC_I2S_HW_VERSION_2        (1)
+#define SOC_I2S_SUPPORTS_XTAL       (1)
 #define SOC_I2S_SUPPORTS_PCM        (1)
 #define SOC_I2S_SUPPORTS_PCM        (1)
 #define SOC_I2S_SUPPORTS_PDM        (1)
 #define SOC_I2S_SUPPORTS_PDM        (1)
 #define SOC_I2S_SUPPORTS_PDM_TX     (1)
 #define SOC_I2S_SUPPORTS_PDM_TX     (1)

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

@@ -339,6 +339,10 @@ config SOC_I2S_HW_VERSION_2
     bool
     bool
     default y
     default y
 
 
+config SOC_I2S_SUPPORTS_XTAL
+    bool
+    default y
+
 config SOC_I2S_SUPPORTS_PCM
 config SOC_I2S_SUPPORTS_PCM
     bool
     bool
     default y
     default y

+ 2 - 1
components/soc/esp32h2/include/soc/clk_tree_defs.h

@@ -211,7 +211,7 @@ typedef enum {
 /**
 /**
  * @brief Array initializer for all supported clock sources of
  * @brief Array initializer for all supported clock sources of
  */
  */
-#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL}
+#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL, SOC_MOD_CLK_XTAL}
 
 
 /**
 /**
  * @brief I2S clock source enum
  * @brief I2S clock source enum
@@ -219,6 +219,7 @@ typedef enum {
 typedef enum {
 typedef enum {
     I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL,        /*!< Select SOC_MOD_CLK_PLL as the default source clock  */
     I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL,        /*!< Select SOC_MOD_CLK_PLL as the default source clock  */
     I2S_CLK_SRC_PLL_96M = SOC_MOD_CLK_PLL,        /*!< Select PLL as the source clock */
     I2S_CLK_SRC_PLL_96M = SOC_MOD_CLK_PLL,        /*!< Select PLL as the source clock */
+    I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL,          /*!< Select XTAL as the source clock */
 } soc_periph_i2s_clk_src_t;
 } soc_periph_i2s_clk_src_t;
 
 
 /////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////

+ 2 - 2
components/soc/esp32h2/include/soc/i2s_struct.h

@@ -141,7 +141,7 @@ typedef volatile struct i2s_dev_s {
             uint32_t rx_clkm_div_num: 8;             /*Integral I2S clock divider value*/
             uint32_t rx_clkm_div_num: 8;             /*Integral I2S clock divider value*/
             uint32_t reserved8:      18;             /*Reserved*/
             uint32_t reserved8:      18;             /*Reserved*/
             uint32_t rx_clk_active:   1;             /*I2S Rx module clock enable signal.*/
             uint32_t rx_clk_active:   1;             /*I2S Rx module clock enable signal.*/
-            uint32_t rx_clk_sel:      2;             /*Select I2S Rx module source clock. 0: no clock. 1: APLL. 2: CLK160. 3: I2S_MCLK_in.*/
+            uint32_t rx_clk_sel:      2;             /*Select I2S Rx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3: I2S_MCLK_in.*/
             uint32_t mclk_sel:        1;             /*0: UseI2S Tx module clock as I2S_MCLK_OUT.  1: UseI2S Rx module clock as I2S_MCLK_OUT.*/
             uint32_t mclk_sel:        1;             /*0: UseI2S Tx module clock as I2S_MCLK_OUT.  1: UseI2S Rx module clock as I2S_MCLK_OUT.*/
             uint32_t reserved30:      2;             /*Reserved*/
             uint32_t reserved30:      2;             /*Reserved*/
         };
         };
@@ -152,7 +152,7 @@ typedef volatile struct i2s_dev_s {
             uint32_t tx_clkm_div_num: 8;             /*Integral I2S TX clock divider value. f_I2S_CLK = f_I2S_CLK_S/(N+b/a). There will be (a-b) * n-div and b * (n+1)-div.  So the average combination will be:  for b <= a/2  z * [x * n-div + (n+1)-div] + y * n-div. For b > a/2  z * [n-div + x * (n+1)-div] + y * (n+1)-div.*/
             uint32_t tx_clkm_div_num: 8;             /*Integral I2S TX clock divider value. f_I2S_CLK = f_I2S_CLK_S/(N+b/a). There will be (a-b) * n-div and b * (n+1)-div.  So the average combination will be:  for b <= a/2  z * [x * n-div + (n+1)-div] + y * n-div. For b > a/2  z * [n-div + x * (n+1)-div] + y * (n+1)-div.*/
             uint32_t reserved8:      18;             /*Reserved*/
             uint32_t reserved8:      18;             /*Reserved*/
             uint32_t tx_clk_active:   1;             /*I2S Tx module clock enable signal.*/
             uint32_t tx_clk_active:   1;             /*I2S Tx module clock enable signal.*/
-            uint32_t tx_clk_sel:      2;             /*Select I2S Tx module source clock. 0: XTAL clock. 1: APLL. 2: CLK160. 3: I2S_MCLK_in.*/
+            uint32_t tx_clk_sel:      2;             /*Select I2S Tx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3: I2S_MCLK_in.*/
             uint32_t clk_en:          1;             /*Set this bit to enable clk gate*/
             uint32_t clk_en:          1;             /*Set this bit to enable clk gate*/
             uint32_t reserved30:      2;             /*Reserved*/
             uint32_t reserved30:      2;             /*Reserved*/
         };
         };

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

@@ -184,6 +184,7 @@
 /*-------------------------- I2S CAPS ----------------------------------------*/
 /*-------------------------- I2S CAPS ----------------------------------------*/
 #define SOC_I2S_NUM                 (1)
 #define SOC_I2S_NUM                 (1)
 #define SOC_I2S_HW_VERSION_2        (1)
 #define SOC_I2S_HW_VERSION_2        (1)
+#define SOC_I2S_SUPPORTS_XTAL       (1)
 #define SOC_I2S_SUPPORTS_PCM        (1)
 #define SOC_I2S_SUPPORTS_PCM        (1)
 #define SOC_I2S_SUPPORTS_PDM        (1)
 #define SOC_I2S_SUPPORTS_PDM        (1)
 #define SOC_I2S_SUPPORTS_PDM_TX     (1)
 #define SOC_I2S_SUPPORTS_PDM_TX     (1)

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

@@ -431,6 +431,10 @@ config SOC_I2S_HW_VERSION_2
     bool
     bool
     default y
     default y
 
 
+config SOC_I2S_SUPPORTS_XTAL
+    bool
+    default y
+
 config SOC_I2S_SUPPORTS_PCM
 config SOC_I2S_SUPPORTS_PCM
     bool
     bool
     default y
     default y

+ 2 - 1
components/soc/esp32s3/include/soc/clk_tree_defs.h

@@ -252,7 +252,7 @@ typedef enum {
 /**
 /**
  * @brief Array initializer for all supported clock sources of I2S
  * @brief Array initializer for all supported clock sources of I2S
  */
  */
-#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL_F160M}
+#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL}
 
 
 /**
 /**
  * @brief I2S clock source enum
  * @brief I2S clock source enum
@@ -260,6 +260,7 @@ typedef enum {
 typedef enum {
 typedef enum {
     I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M,                    /*!< Select PLL_F160M as the default source clock  */
     I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M,                    /*!< Select PLL_F160M as the default source clock  */
     I2S_CLK_SRC_PLL_160M = SOC_MOD_CLK_PLL_F160M,                   /*!< Select PLL_F160M as the source clock */
     I2S_CLK_SRC_PLL_160M = SOC_MOD_CLK_PLL_F160M,                   /*!< Select PLL_F160M as the source clock */
+    I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL,                            /*!< Select XTAL as the source clock */
 } soc_periph_i2s_clk_src_t;
 } soc_periph_i2s_clk_src_t;
 
 
 /////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////

+ 2 - 2
components/soc/esp32s3/include/soc/i2s_struct.h

@@ -142,7 +142,7 @@ typedef volatile struct i2s_dev_s {
             uint32_t rx_clkm_div_num               :    8;  /*Integral I2S clock divider value*/
             uint32_t rx_clkm_div_num               :    8;  /*Integral I2S clock divider value*/
             uint32_t reserved8                     :    18;  /* Reserved*/
             uint32_t reserved8                     :    18;  /* Reserved*/
             uint32_t rx_clk_active                 :    1;  /*I2S Rx module clock enable signal.*/
             uint32_t rx_clk_active                 :    1;  /*I2S Rx module clock enable signal.*/
-            uint32_t rx_clk_sel                    :    2;  /*Select I2S Rx module source clock. 0: no clock. 1: APLL. 2: CLK160. 3: I2S_MCLK_in.*/
+            uint32_t rx_clk_sel                    :    2;  /*Select I2S Rx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3: I2S_MCLK_in.*/
             uint32_t mclk_sel                      :    1;  /* 0: UseI2S Tx module clock as I2S_MCLK_OUT.  1: UseI2S Rx module clock as I2S_MCLK_OUT. */
             uint32_t mclk_sel                      :    1;  /* 0: UseI2S Tx module clock as I2S_MCLK_OUT.  1: UseI2S Rx module clock as I2S_MCLK_OUT. */
             uint32_t reserved30                    :    2;  /* Reserved*/
             uint32_t reserved30                    :    2;  /* Reserved*/
         };
         };
@@ -153,7 +153,7 @@ typedef volatile struct i2s_dev_s {
             uint32_t tx_clkm_div_num               :    8;  /*Integral I2S TX clock divider value. f_I2S_CLK = f_I2S_CLK_S/(N+b/a). There will be (a-b) * n-div and b * (n+1)-div.  So the average combination will be:  for b <= a/2, z * [x * n-div + (n+1)-div] + y * n-div. For b > a/2, z * [n-div + x * (n+1)-div] + y * (n+1)-div. */
             uint32_t tx_clkm_div_num               :    8;  /*Integral I2S TX clock divider value. f_I2S_CLK = f_I2S_CLK_S/(N+b/a). There will be (a-b) * n-div and b * (n+1)-div.  So the average combination will be:  for b <= a/2, z * [x * n-div + (n+1)-div] + y * n-div. For b > a/2, z * [n-div + x * (n+1)-div] + y * (n+1)-div. */
             uint32_t reserved8                     :    18;  /* Reserved*/
             uint32_t reserved8                     :    18;  /* Reserved*/
             uint32_t tx_clk_active                 :    1;  /*I2S Tx module clock enable signal.*/
             uint32_t tx_clk_active                 :    1;  /*I2S Tx module clock enable signal.*/
-            uint32_t tx_clk_sel                    :    2;  /*Select I2S Tx module source clock. 0: XTAL clock. 1: APLL. 2: CLK160. 3: I2S_MCLK_in.*/
+            uint32_t tx_clk_sel                    :    2;  /*Select I2S Tx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3: I2S_MCLK_in.*/
             uint32_t clk_en                        :    1;  /*Set this bit to enable clk gate*/
             uint32_t clk_en                        :    1;  /*Set this bit to enable clk gate*/
             uint32_t reserved30                    :    2;  /* Reserved*/
             uint32_t reserved30                    :    2;  /* Reserved*/
         };
         };

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

@@ -182,6 +182,7 @@
 /*-------------------------- I2S CAPS ----------------------------------------*/
 /*-------------------------- I2S CAPS ----------------------------------------*/
 #define SOC_I2S_NUM                 (2)
 #define SOC_I2S_NUM                 (2)
 #define SOC_I2S_HW_VERSION_2        (1)
 #define SOC_I2S_HW_VERSION_2        (1)
+#define SOC_I2S_SUPPORTS_XTAL       (1)
 #define SOC_I2S_SUPPORTS_PCM        (1)
 #define SOC_I2S_SUPPORTS_PCM        (1)
 #define SOC_I2S_SUPPORTS_PDM        (1)
 #define SOC_I2S_SUPPORTS_PDM        (1)
 #define SOC_I2S_SUPPORTS_PDM_TX     (1)
 #define SOC_I2S_SUPPORTS_PDM_TX     (1)

+ 1 - 1
examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/main/i2s_es7210_record_example.c

@@ -30,7 +30,7 @@
 #define EXAMPLE_SD_SPI_MOSI_IO     (17)
 #define EXAMPLE_SD_SPI_MOSI_IO     (17)
 #define EXAMPLE_SD_SPI_MISO_IO     (16)
 #define EXAMPLE_SD_SPI_MISO_IO     (16)
 #define EXAMPLE_SD_SPI_CS_IO       (15)
 #define EXAMPLE_SD_SPI_CS_IO       (15)
-#elif CONFIG_IDF_TARGET_ESP32C3
+#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
 #define EXAMPLE_I2C_NUM            (0)
 #define EXAMPLE_I2C_NUM            (0)
 #define EXAMPLE_I2C_SDA_IO         (3)
 #define EXAMPLE_I2C_SDA_IO         (3)
 #define EXAMPLE_I2C_SCL_IO         (2)
 #define EXAMPLE_I2C_SCL_IO         (2)