diff --git a/components/esp_driver_i2s/i2s_common.c b/components/esp_driver_i2s/i2s_common.c index 8659694466..6586c3f1f0 100644 --- a/components/esp_driver_i2s/i2s_common.c +++ b/components/esp_driver_i2s/i2s_common.c @@ -41,6 +41,7 @@ #include "esp_private/i2s_platform.h" #include "esp_private/esp_clk.h" +#include "esp_private/sleep_retention.h" #include "driver/gpio.h" #include "esp_private/gpio.h" @@ -85,6 +86,34 @@ inline void *i2s_dma_calloc(i2s_chan_handle_t handle, size_t num, size_t size) Scope: This file only ----------------------------------------------------------------------------*/ +#if I2S_USE_RETENTION_LINK +static esp_err_t s_i2s_create_sleep_retention_link_cb(void *arg) +{ + i2s_controller_t *i2s_obj = (i2s_controller_t *)arg; + ESP_RETURN_ON_ERROR(sleep_retention_entries_create(i2s_reg_retention_info[i2s_obj->id].entry_array, + i2s_reg_retention_info[i2s_obj->id].array_size, + REGDMA_LINK_PRI_I2S, i2s_obj->slp_retention_mod), + TAG, "create retention link failed"); + return ESP_OK; +} + +static void s_i2s_create_retention_module(i2s_controller_t *i2s_obj) +{ + sleep_retention_module_t module = i2s_obj->slp_retention_mod; + + _lock_acquire(&i2s_obj->mutex); + if (i2s_obj->retention_link_created == false) { + if (sleep_retention_module_allocate(module) != ESP_OK) { + // even though the sleep retention module create failed, I2S driver should still work, so just warning here + ESP_LOGW(TAG, "create retention module failed, power domain can't turn off"); + } else { + i2s_obj->retention_link_created = true; + } + } + _lock_release(&i2s_obj->mutex); +} +#endif // I2S_USE_RETENTION_LINK + static void i2s_tx_channel_start(i2s_chan_handle_t handle) { i2s_hal_tx_reset(&(handle->controller->hal)); @@ -175,6 +204,14 @@ static esp_err_t i2s_destroy_controller_obj(i2s_controller_t **i2s_obj) #if SOC_I2S_HW_VERSION_1 i2s_ll_enable_dma((*i2s_obj)->hal.dev, false); #endif +#if I2S_USE_RETENTION_LINK + if ((*i2s_obj)->slp_retention_mod) { + if ((*i2s_obj)->retention_link_created) { + sleep_retention_module_free((*i2s_obj)->slp_retention_mod); + } + sleep_retention_module_deinit((*i2s_obj)->slp_retention_mod); + } +#endif // I2S_USE_RETENTION_LINK free(*i2s_obj); *i2s_obj = NULL; return i2s_platform_release_occupation(I2S_CTLR_HP, id); @@ -219,6 +256,25 @@ static i2s_controller_t *i2s_acquire_controller_obj(int id) adc_ll_digi_set_data_source(0); } #endif + +#if I2S_USE_RETENTION_LINK + sleep_retention_module_t module = i2s_periph_signal[id].retention_module; + sleep_retention_module_init_param_t init_param = { + .cbs = { + .create = { + .handle = s_i2s_create_sleep_retention_link_cb, + .arg = i2s_obj, + }, + }, + .depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM) + }; + if (sleep_retention_module_init(module, &init_param) == ESP_OK) { + i2s_obj->slp_retention_mod = module; + } else { + // even the sleep retention module init failed, I2S driver should still work, so just warning here + ESP_LOGW(TAG, "init sleep retention failed for I2S%d, power domain may be turned off during sleep", id); + } +#endif // I2S_USE_RETENTION_LINK } else { free(pre_alloc); portENTER_CRITICAL(&g_i2s.spinlock); @@ -879,6 +935,9 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t * ESP_RETURN_ON_FALSE(chan_cfg->id < SOC_I2S_NUM || chan_cfg->id == I2S_NUM_AUTO, ESP_ERR_INVALID_ARG, TAG, "invalid I2S port id"); ESP_RETURN_ON_FALSE(chan_cfg->dma_desc_num >= 2, ESP_ERR_INVALID_ARG, TAG, "there should be at least 2 DMA buffers"); ESP_RETURN_ON_FALSE(chan_cfg->intr_priority >= 0 && chan_cfg->intr_priority <= 7, ESP_ERR_INVALID_ARG, TAG, "intr_priority should be within 0~7"); +#if !SOC_I2S_SUPPORT_SLEEP_RETENTION + ESP_RETURN_ON_FALSE(!chan_cfg->backup_before_sleep, ESP_ERR_NOT_SUPPORTED, TAG, "register back up is not supported"); +#endif esp_err_t ret = ESP_OK; i2s_controller_t *i2s_obj = NULL; @@ -937,6 +996,11 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t * if ((tx_handle != NULL) && (rx_handle != NULL)) { i2s_obj->full_duplex = true; } +#if I2S_USE_RETENTION_LINK + if (chan_cfg->backup_before_sleep) { + s_i2s_create_retention_module(i2s_obj); + } +#endif return ESP_OK; /* i2s_obj allocated but register channel failed */ diff --git a/components/esp_driver_i2s/i2s_private.h b/components/esp_driver_i2s/i2s_private.h index 40ff52fce5..0cfccbaf94 100644 --- a/components/esp_driver_i2s/i2s_private.h +++ b/components/esp_driver_i2s/i2s_private.h @@ -6,6 +6,7 @@ #pragma once +#include #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "freertos/queue.h" @@ -25,6 +26,7 @@ #endif #include "esp_private/periph_ctrl.h" #include "esp_private/esp_gpio_reserve.h" +#include "esp_private/sleep_retention.h" #include "esp_pm.h" #include "esp_err.h" #include "sdkconfig.h" @@ -56,6 +58,8 @@ extern "C" { #define I2S_RCC_ATOMIC() #endif +#define I2S_USE_RETENTION_LINK (SOC_I2S_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP) + #define I2S_NULL_POINTER_CHECK(tag, p) ESP_RETURN_ON_FALSE((p), ESP_ERR_INVALID_ARG, tag, "input parameter '"#p"' is NULL") /** @@ -130,6 +134,9 @@ typedef struct { bool full_duplex; /*!< is full_duplex */ i2s_chan_handle_t tx_chan; /*!< tx channel handler */ i2s_chan_handle_t rx_chan; /*!< rx channel handler */ + _lock_t mutex; /*!< mutex for controller */ + sleep_retention_module_t slp_retention_mod; /*!< Sleep retention module */ + bool retention_link_created; /*!< Whether the retention link is created */ int mclk; /*!< MCK out pin, shared by tx/rx*/ #if CONFIG_IDF_TARGET_ESP32 esp_clock_output_mapping_handle_t mclk_out_hdl; /*!< The handle of MCLK output signal */ diff --git a/components/esp_driver_i2s/include/driver/i2s_common.h b/components/esp_driver_i2s/include/driver/i2s_common.h index eaeb397a0d..10c0f5211e 100644 --- a/components/esp_driver_i2s/include/driver/i2s_common.h +++ b/components/esp_driver_i2s/include/driver/i2s_common.h @@ -26,6 +26,7 @@ extern "C" { .dma_frame_num = 240, \ .auto_clear_after_cb = false, \ .auto_clear_before_cb = false, \ + .backup_before_sleep = false, \ .intr_priority = 0, \ } @@ -73,6 +74,9 @@ typedef struct { bool auto_clear_before_cb; /*!< Set to auto clear DMA TX buffer before `on_sent` callback, I2S will always send zero automatically if no data to send * So that user can access data in the callback that just finished to send. */ + bool backup_before_sleep; /*!< If set, the driver will backup/restore the I2S registers before/after entering/exist sleep mode. + By this approach, the system can power off I2S's power domain. + This can save power, but at the expense of more RAM being consumed */ int intr_priority; /*!< I2S interrupt priority, range [0, 7], if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */ } i2s_chan_config_t; diff --git a/components/esp_driver_i2s/test_apps/i2s/main/CMakeLists.txt b/components/esp_driver_i2s/test_apps/i2s/main/CMakeLists.txt index 34b5a6d39f..63623c66c7 100644 --- a/components/esp_driver_i2s/test_apps/i2s/main/CMakeLists.txt +++ b/components/esp_driver_i2s/test_apps/i2s/main/CMakeLists.txt @@ -6,6 +6,10 @@ if(CONFIG_SOC_I2S_SUPPORTS_ETM AND CONFIG_SOC_GPIO_SUPPORT_ETM) set(srcs ${srcs} "test_i2s_etm.c") endif() +if(CONFIG_SOC_I2S_SUPPORT_SLEEP_RETENTION) + list(APPEND srcs "test_i2s_slp_retention.c") +endif() + idf_component_register(SRCS ${srcs} - PRIV_REQUIRES unity esp_driver_pcnt spi_flash esp_driver_gpio esp_driver_i2s + PRIV_REQUIRES unity esp_driver_pcnt spi_flash esp_driver_gpio esp_driver_i2s esp_driver_uart WHOLE_ARCHIVE) diff --git a/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c b/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c index bf1172c3c7..dc86526b16 100644 --- a/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c +++ b/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c @@ -94,7 +94,7 @@ static void i2s_test_io_config(int mode) } } -static void i2s_read_write_test(i2s_chan_handle_t tx_chan, i2s_chan_handle_t rx_chan) +void i2s_read_write_test(i2s_chan_handle_t tx_chan, i2s_chan_handle_t rx_chan) { #define I2S_SEND_BUF_LEN 100 #define I2S_RECV_BUF_LEN 10000 diff --git a/components/esp_driver_i2s/test_apps/i2s/main/test_i2s_slp_retention.c b/components/esp_driver_i2s/test_apps/i2s/main/test_i2s_slp_retention.c new file mode 100644 index 0000000000..22d94ac7c8 --- /dev/null +++ b/components/esp_driver_i2s/test_apps/i2s/main/test_i2s_slp_retention.c @@ -0,0 +1,101 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "unity.h" +#include "unity_test_utils.h" +#include "driver/i2s_std.h" +#include "driver/uart.h" +#include "soc/i2s_struct.h" +#include "esp_sleep.h" +#include "esp_private/sleep_cpu.h" +#include "esp_private/esp_sleep_internal.h" +#include "esp_private/esp_pmu.h" +#include "../../test_inc/test_i2s.h" + +#if SOC_I2S_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + +extern void i2s_read_write_test(i2s_chan_handle_t tx_chan, i2s_chan_handle_t rx_chan); + +static void test_i2s_enter_light_sleep(int sec) +{ + esp_sleep_context_t sleep_ctx; + esp_sleep_set_sleep_context(&sleep_ctx); + printf("Entering light sleep for %d seconds\n", sec); +#if ESP_SLEEP_POWER_DOWN_CPU + printf("Enable CPU power down\n"); + TEST_ESP_OK(sleep_cpu_configure(true)); +#endif + uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM); + TEST_ESP_OK(esp_sleep_enable_timer_wakeup(sec * 1000 * 1000)); + TEST_ESP_OK(esp_light_sleep_start()); + +#if ESP_SLEEP_POWER_DOWN_CPU + TEST_ESP_OK(sleep_cpu_configure(false)); +#endif + printf("Woke up from light sleep\n"); + + TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result); + TEST_ASSERT_EQUAL(PMU_SLEEP_PD_TOP, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP); + esp_sleep_set_sleep_context(NULL); +} + +TEST_CASE("I2S_sleep_retention_test", "[i2s]") +{ + i2s_chan_handle_t tx_handle; + i2s_chan_handle_t rx_handle; + + i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER); + chan_cfg.backup_before_sleep = true; + i2s_std_config_t std_cfg = { + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE), + .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO), + .gpio_cfg = I2S_TEST_MASTER_DEFAULT_PIN, + }; + std_cfg.gpio_cfg.din = std_cfg.gpio_cfg.dout; + TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle)); + TEST_ESP_OK(i2s_channel_init_std_mode(tx_handle, &std_cfg)); + TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg)); + + /* I2S retention is depended on GDMA retention. + * Only take two registers as sample to check the I2S retention when GDMA retention has not been supported. */ +#if !SOC_GDMA_SUPPORT_SLEEP_RETENTION + i2s_tx_conf_reg_t tx_reg_before_slp = I2S0.tx_conf; + i2s_rx_conf_reg_t rx_reg_before_slp = I2S0.rx_conf; +#endif + + /* Enter light sleep and wake up after 1 second */ + test_i2s_enter_light_sleep(1); + +#if SOC_GDMA_SUPPORT_SLEEP_RETENTION + /* Check whether I2S can work correctly after light sleep */ + TEST_ESP_OK(i2s_channel_enable(tx_handle)); + TEST_ESP_OK(i2s_channel_enable(rx_handle)); + i2s_read_write_test(tx_handle, rx_handle); +#else + /* Only check whether the register values are restored if GDMA retention has not been supported */ + i2s_tx_conf_reg_t tx_reg_after_slp = I2S0.tx_conf; + i2s_rx_conf_reg_t rx_reg_after_slp = I2S0.rx_conf; + + TEST_ASSERT_EQUAL_UINT32(tx_reg_before_slp.val, tx_reg_after_slp.val); + TEST_ASSERT_EQUAL_UINT32(rx_reg_before_slp.val, rx_reg_after_slp.val); + + TEST_ESP_OK(i2s_channel_enable(tx_handle)); + TEST_ESP_OK(i2s_channel_enable(rx_handle)); +#endif + + printf("I2S works as expected after light sleep\n"); + + TEST_ESP_OK(i2s_channel_disable(tx_handle)); + TEST_ESP_OK(i2s_channel_disable(rx_handle)); + TEST_ESP_OK(i2s_del_channel(tx_handle)); + TEST_ESP_OK(i2s_del_channel(rx_handle)); +} + +#endif // SOC_I2S_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP diff --git a/components/esp_driver_i2s/test_apps/i2s/pytest_i2s.py b/components/esp_driver_i2s/test_apps/i2s/pytest_i2s.py index eeb7eefaaf..455fe049da 100644 --- a/components/esp_driver_i2s/test_apps/i2s/pytest_i2s.py +++ b/components/esp_driver_i2s/test_apps/i2s/pytest_i2s.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 import pytest from pytest_embedded import Dut diff --git a/components/esp_driver_i2s/test_apps/i2s/sdkconfig.ci.release b/components/esp_driver_i2s/test_apps/i2s/sdkconfig.ci.release index 91d93f163e..998cfb51f8 100644 --- a/components/esp_driver_i2s/test_apps/i2s/sdkconfig.ci.release +++ b/components/esp_driver_i2s/test_apps/i2s/sdkconfig.ci.release @@ -3,3 +3,4 @@ CONFIG_FREERTOS_USE_TICKLESS_IDLE=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y +CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y diff --git a/components/esp_driver_i2s/test_apps/i2s/sdkconfig.defaults b/components/esp_driver_i2s/test_apps/i2s/sdkconfig.defaults index b56409727b..0f8b7b2f54 100644 --- a/components/esp_driver_i2s/test_apps/i2s/sdkconfig.defaults +++ b/components/esp_driver_i2s/test_apps/i2s/sdkconfig.defaults @@ -1,2 +1,4 @@ CONFIG_I2S_ENABLE_DEBUG_LOG=y CONFIG_ESP_TASK_WDT_EN=n +# primitives for checking sleep internal state +CONFIG_ESP_SLEEP_DEBUG=y diff --git a/components/soc/esp32/i2s_periph.c b/components/soc/esp32/i2s_periph.c index 83c2920af6..9f06c85f40 100644 --- a/components/soc/esp32/i2s_periph.c +++ b/components/soc/esp32/i2s_periph.c @@ -29,7 +29,6 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sig = I2S0I_DATA_IN15_IDX, .irq = ETS_I2S0_INTR_SOURCE, - .module = PERIPH_I2S0_MODULE, }, { .mck_out_sig = -1, // Unavailable @@ -49,6 +48,5 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sig = I2S1I_DATA_IN15_IDX, .irq = ETS_I2S1_INTR_SOURCE, - .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32c3/i2s_periph.c b/components/soc/esp32c3/i2s_periph.c index ec14aa72a2..ff597698b5 100644 --- a/components/soc/esp32c3/i2s_periph.c +++ b/components/soc/esp32c3/i2s_periph.c @@ -30,6 +30,5 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sig = I2SI_SD_IN_IDX, .irq = ETS_I2S1_INTR_SOURCE, - .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32c5/i2s_periph.c b/components/soc/esp32c5/i2s_periph.c index dbd1fdc816..ff683a2f81 100644 --- a/components/soc/esp32c5/i2s_periph.c +++ b/components/soc/esp32c5/i2s_periph.c @@ -5,6 +5,7 @@ */ #include "soc/i2s_periph.h" +#include "soc/i2s_reg.h" #include "soc/gpio_sig_map.h" /* @@ -30,6 +31,48 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sig = I2SI_SD_IN_IDX, .irq = ETS_I2S1_INTR_SOURCE, - .module = -1, + .retention_module = SLEEP_RETENTION_MODULE_I2S0, } }; + +/** + * I2S Registers to be saved during sleep retention + * - I2S_RX_CONF_REG + * - I2S_TX_CONF_REG + * - I2S_RX_CONF1_REG + * - I2S_TX_CONF1_REG + * - I2S_TX_PCM2PDM_CONF_REG + * - I2S_TX_PCM2PDM_CONF1_REG + * - I2S_RX_TDM_CTRL_REG + * - I2S_TX_TDM_CTRL_REG + * - I2S_RXEOF_NUM_REG + * - I2S_ETM_CONF_REG +*/ +#define I2S_RETENTION_REGS_CNT 10 +#define I2S_RETENTION_REGS_BASE(i) I2S_RX_CONF_REG(i) +static const uint32_t i2s_regs_map[4] = {0x12360f, 0x0, 0x0, 0x0}; +#define I2S_SLEEP_RETENTION_ENTRIES(i2s_port) { \ + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \ + REGDMA_I2S_LINK(0x00), \ + I2S_RETENTION_REGS_BASE(i2s_port), \ + I2S_RETENTION_REGS_BASE(i2s_port), \ + I2S_RETENTION_REGS_CNT, 0, 0, \ + i2s_regs_map[0], i2s_regs_map[1], \ + i2s_regs_map[2], i2s_regs_map[3]), \ + .owner = ENTRY(0) | ENTRY(2)}, \ + [1] = { .config = REGDMA_LINK_WRITE_INIT( \ + REGDMA_I2S_LINK(0x01), I2S_RX_CONF_REG(i2s_port), I2S_RX_UPDATE, I2S_RX_UPDATE_M, 1, 0), \ + .owner = ENTRY(0) | ENTRY(2)}, \ + [2] = { .config = REGDMA_LINK_WRITE_INIT( \ + REGDMA_I2S_LINK(0x02), I2S_TX_CONF_REG(i2s_port), I2S_TX_UPDATE, I2S_TX_UPDATE_M, 1, 0), \ + .owner = ENTRY(0) | ENTRY(2)} \ +}; + +static const regdma_entries_config_t i2s0_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(0); + +const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_NUM] = { + [0] = { + .entry_array = i2s0_regs_retention, + .array_size = ARRAY_SIZE(i2s0_regs_retention) + }, +}; diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index de44eb10f0..8943b4f279 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -675,6 +675,10 @@ config SOC_I2S_TDM_FULL_DATA_WIDTH bool default y +config SOC_I2S_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK bool default y diff --git a/components/soc/esp32c5/include/soc/retention_periph_defs.h b/components/soc/esp32c5/include/soc/retention_periph_defs.h index 6fd2cdda6c..02002a7d0f 100644 --- a/components/soc/esp32c5/include/soc/retention_periph_defs.h +++ b/components/soc/esp32c5/include/soc/retention_periph_defs.h @@ -36,6 +36,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_RMT0 = 13, SLEEP_RETENTION_MODULE_UART0 = 14, SLEEP_RETENTION_MODULE_UART1 = 15, + SLEEP_RETENTION_MODULE_I2S0 = 16, /* modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_WIFI_MAC = 26, @@ -74,6 +75,7 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_RMT0 = BIT(SLEEP_RETENTION_MODULE_RMT0), SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0), SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1), + SLEEP_RETENTION_MODULE_BM_I2S0 = BIT(SLEEP_RETENTION_MODULE_I2S0), SLEEP_RETENTION_MODULE_BM_GDMA_CH0 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH0), SLEEP_RETENTION_MODULE_BM_GDMA_CH1 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH1), @@ -94,6 +96,7 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_RMT0 \ | SLEEP_RETENTION_MODULE_BM_UART0 \ | SLEEP_RETENTION_MODULE_BM_UART1 \ + | SLEEP_RETENTION_MODULE_BM_I2S0 \ ) #ifdef __cplusplus } diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 1fde2ac0a3..5badeefac1 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -288,6 +288,7 @@ #define SOC_I2S_PDM_MAX_TX_LINES (2) #define SOC_I2S_SUPPORTS_TDM (1) #define SOC_I2S_TDM_FULL_DATA_WIDTH (1) /*!< No limitation to data bit width when using multiple slots */ +#define SOC_I2S_SUPPORT_SLEEP_RETENTION 1 /*!< The sleep retention feature can help back up I2S registers before sleep */ /*-------------------------- LEDC CAPS ---------------------------------------*/ #define SOC_LEDC_SUPPORT_PLL_DIV_CLOCK (1) diff --git a/components/soc/esp32c6/i2s_periph.c b/components/soc/esp32c6/i2s_periph.c index cb0a6a14ff..3f3ed3974a 100644 --- a/components/soc/esp32c6/i2s_periph.c +++ b/components/soc/esp32c6/i2s_periph.c @@ -1,10 +1,11 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "soc/i2s_periph.h" +#include "soc/i2s_reg.h" #include "soc/gpio_sig_map.h" /* @@ -30,6 +31,48 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sig = I2SI_SD_IN_IDX, .irq = ETS_I2S1_INTR_SOURCE, - .module = PERIPH_I2S1_MODULE, + .retention_module = SLEEP_RETENTION_MODULE_I2S0, } }; + +/** + * I2S Registers to be saved during sleep retention + * - I2S_RX_CONF_REG + * - I2S_TX_CONF_REG + * - I2S_RX_CONF1_REG + * - I2S_TX_CONF1_REG + * - I2S_TX_PCM2PDM_CONF_REG + * - I2S_TX_PCM2PDM_CONF1_REG + * - I2S_RX_TDM_CTRL_REG + * - I2S_TX_TDM_CTRL_REG + * - I2S_RXEOF_NUM_REG + * - I2S_ETM_CONF_REG +*/ +#define I2S_RETENTION_REGS_CNT 10 +#define I2S_RETENTION_REGS_BASE(i) I2S_RX_CONF_REG(i) +static const uint32_t i2s_regs_map[4] = {0x12330f, 0x0, 0x0, 0x0}; +#define I2S_SLEEP_RETENTION_ENTRIES(i2s_port) { \ + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \ + REGDMA_I2S_LINK(0x00), \ + I2S_RETENTION_REGS_BASE(i2s_port), \ + I2S_RETENTION_REGS_BASE(i2s_port), \ + I2S_RETENTION_REGS_CNT, 0, 0, \ + i2s_regs_map[0], i2s_regs_map[1], \ + i2s_regs_map[2], i2s_regs_map[3]), \ + .owner = ENTRY(0) | ENTRY(2)}, \ + [1] = { .config = REGDMA_LINK_WRITE_INIT( \ + REGDMA_I2S_LINK(0x01), I2S_RX_CONF_REG(i2s_port), I2S_RX_UPDATE, I2S_RX_UPDATE_M, 1, 0), \ + .owner = ENTRY(0) | ENTRY(2)}, \ + [2] = { .config = REGDMA_LINK_WRITE_INIT( \ + REGDMA_I2S_LINK(0x02), I2S_TX_CONF_REG(i2s_port), I2S_TX_UPDATE, I2S_TX_UPDATE_M, 1, 0), \ + .owner = ENTRY(0) | ENTRY(2)} \ +}; + +static const regdma_entries_config_t i2s0_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(0); + +const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_NUM] = { + [0] = { + .entry_array = i2s0_regs_retention, + .array_size = ARRAY_SIZE(i2s0_regs_retention) + }, +}; diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 47dc43d9d5..9493c491a5 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -671,6 +671,10 @@ config SOC_I2S_SUPPORTS_TDM bool default y +config SOC_I2S_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK bool default y diff --git a/components/soc/esp32c6/include/soc/retention_periph_defs.h b/components/soc/esp32c6/include/soc/retention_periph_defs.h index a1dee8299a..5cdbc108e8 100644 --- a/components/soc/esp32c6/include/soc/retention_periph_defs.h +++ b/components/soc/esp32c6/include/soc/retention_periph_defs.h @@ -36,6 +36,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_RMT0 = 13, SLEEP_RETENTION_MODULE_UART0 = 14, SLEEP_RETENTION_MODULE_UART1 = 15, + SLEEP_RETENTION_MODULE_I2S0 = 16, /* Modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_WIFI_MAC = 26, @@ -68,6 +69,7 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_RMT0 = BIT(SLEEP_RETENTION_MODULE_RMT0), SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0), SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1), + SLEEP_RETENTION_MODULE_BM_I2S0 = BIT(SLEEP_RETENTION_MODULE_I2S0), /* modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BM_WIFI_MAC = BIT(SLEEP_RETENTION_MODULE_WIFI_MAC), SLEEP_RETENTION_MODULE_BM_WIFI_BB = BIT(SLEEP_RETENTION_MODULE_WIFI_BB), @@ -90,6 +92,7 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_RMT0 \ | SLEEP_RETENTION_MODULE_BM_UART0 \ | SLEEP_RETENTION_MODULE_BM_UART1 \ + | SLEEP_RETENTION_MODULE_BM_I2S0 \ ) #ifdef __cplusplus diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index b997a19b90..58463193d0 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -273,6 +273,7 @@ #define SOC_I2S_SUPPORTS_PDM_TX (1) #define SOC_I2S_PDM_MAX_TX_LINES (2) #define SOC_I2S_SUPPORTS_TDM (1) +#define SOC_I2S_SUPPORT_SLEEP_RETENTION 1 /*!< The sleep retention feature can help back up I2S registers before sleep */ /*-------------------------- LEDC CAPS ---------------------------------------*/ #define SOC_LEDC_SUPPORT_PLL_DIV_CLOCK (1) diff --git a/components/soc/esp32h2/i2s_periph.c b/components/soc/esp32h2/i2s_periph.c index cf70f2cb94..582e624c4f 100644 --- a/components/soc/esp32h2/i2s_periph.c +++ b/components/soc/esp32h2/i2s_periph.c @@ -1,10 +1,11 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "soc/i2s_periph.h" +#include "soc/i2s_reg.h" #include "soc/gpio_sig_map.h" /* @@ -29,6 +30,48 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sig = I2SI_SD_IN_IDX, .irq = ETS_I2S1_INTR_SOURCE, - .module = PERIPH_I2S1_MODULE, + .retention_module = SLEEP_RETENTION_MODULE_I2S0, } }; + +/** + * I2S Registers to be saved during sleep retention + * - I2S_RX_CONF_REG + * - I2S_TX_CONF_REG + * - I2S_RX_CONF1_REG + * - I2S_TX_CONF1_REG + * - I2S_TX_PCM2PDM_CONF_REG + * - I2S_TX_PCM2PDM_CONF1_REG + * - I2S_RX_TDM_CTRL_REG + * - I2S_TX_TDM_CTRL_REG + * - I2S_RXEOF_NUM_REG + * - I2S_ETM_CONF_REG +*/ +#define I2S_RETENTION_REGS_CNT 10 +#define I2S_RETENTION_REGS_BASE(i) I2S_RX_CONF_REG +static const uint32_t i2s_regs_map[4] = {0x12330f, 0x0, 0x0, 0x0}; +#define I2S_SLEEP_RETENTION_ENTRIES(i2s_port) { \ + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \ + REGDMA_I2S_LINK(0x00), \ + I2S_RETENTION_REGS_BASE(i2s_port), \ + I2S_RETENTION_REGS_BASE(i2s_port), \ + I2S_RETENTION_REGS_CNT, 0, 0, \ + i2s_regs_map[0], i2s_regs_map[1], \ + i2s_regs_map[2], i2s_regs_map[3]), \ + .owner = ENTRY(0) | ENTRY(2)}, \ + [1] = { .config = REGDMA_LINK_WRITE_INIT( \ + REGDMA_I2S_LINK(0x01), I2S_RX_CONF_REG(i2s_port), I2S_RX_UPDATE, I2S_RX_UPDATE_M, 1, 0), \ + .owner = ENTRY(0) | ENTRY(2)}, \ + [2] = { .config = REGDMA_LINK_WRITE_INIT( \ + REGDMA_I2S_LINK(0x02), I2S_TX_CONF_REG(i2s_port), I2S_TX_UPDATE, I2S_TX_UPDATE_M, 1, 0), \ + .owner = ENTRY(0) | ENTRY(2)} \ +}; + +static const regdma_entries_config_t i2s0_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(0); + +const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_NUM] = { + [0] = { + .entry_array = i2s0_regs_retention, + .array_size = ARRAY_SIZE(i2s0_regs_retention) + }, +}; diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index f66714fbae..ab71115106 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -675,6 +675,10 @@ config SOC_I2S_TDM_FULL_DATA_WIDTH bool default y +config SOC_I2S_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK bool default y diff --git a/components/soc/esp32h2/include/soc/retention_periph_defs.h b/components/soc/esp32h2/include/soc/retention_periph_defs.h index 9c8ea0ea05..819af3a2b3 100644 --- a/components/soc/esp32h2/include/soc/retention_periph_defs.h +++ b/components/soc/esp32h2/include/soc/retention_periph_defs.h @@ -37,6 +37,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_RMT0 = 14, SLEEP_RETENTION_MODULE_UART0 = 15, SLEEP_RETENTION_MODULE_UART1 = 16, + SLEEP_RETENTION_MODULE_I2S0 = 17, /* Modem module, which includes BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BLE_MAC = 28, @@ -68,6 +69,7 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_RMT0 = BIT(SLEEP_RETENTION_MODULE_RMT0), SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0), SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1), + SLEEP_RETENTION_MODULE_BM_I2S0 = BIT(SLEEP_RETENTION_MODULE_I2S0), /* modem module, which includes BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BM_BLE_MAC = BIT(SLEEP_RETENTION_MODULE_BLE_MAC), SLEEP_RETENTION_MODULE_BM_BT_BB = BIT(SLEEP_RETENTION_MODULE_BT_BB), @@ -89,6 +91,7 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_RMT0 \ | SLEEP_RETENTION_MODULE_BM_UART0 \ | SLEEP_RETENTION_MODULE_BM_UART1 \ + | SLEEP_RETENTION_MODULE_BM_I2S0 \ ) #ifdef __cplusplus diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 8831aa1a3c..d5ae0377d1 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -274,6 +274,7 @@ #define SOC_I2S_PDM_MAX_TX_LINES (2) #define SOC_I2S_SUPPORTS_TDM (1) #define SOC_I2S_TDM_FULL_DATA_WIDTH (1) /*!< No limitation to data bit width when using multiple slots */ +#define SOC_I2S_SUPPORT_SLEEP_RETENTION 1 /*!< The sleep retention feature can help back up I2S registers before sleep */ /*-------------------------- LEDC CAPS ---------------------------------------*/ #define SOC_LEDC_SUPPORT_PLL_DIV_CLOCK (1) diff --git a/components/soc/esp32p4/i2s_periph.c b/components/soc/esp32p4/i2s_periph.c index a0208659f1..5f623aea53 100644 --- a/components/soc/esp32p4/i2s_periph.c +++ b/components/soc/esp32p4/i2s_periph.c @@ -5,6 +5,7 @@ */ #include "soc/i2s_periph.h" +#include "soc/i2s_reg.h" #include "soc/gpio_sig_map.h" #include "soc/lp_gpio_sig_map.h" @@ -34,7 +35,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sigs[3] = I2S0_I_SD3_PAD_IN_IDX, .irq = ETS_I2S0_INTR_SOURCE, - .module = PERIPH_I2S0_MODULE, + .retention_module = SLEEP_RETENTION_MODULE_I2S0, }, [1] = { .mck_out_sig = I2S1_MCLK_PAD_OUT_IDX, @@ -58,7 +59,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sigs[3] = -1, .irq = ETS_I2S1_INTR_SOURCE, - .module = PERIPH_I2S1_MODULE, + .retention_module = SLEEP_RETENTION_MODULE_I2S1, }, [2] = { .mck_out_sig = I2S2_MCLK_PAD_OUT_IDX, @@ -82,7 +83,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sigs[3] = -1, .irq = ETS_I2S2_INTR_SOURCE, - .module = PERIPH_I2S2_MODULE, + .retention_module = SLEEP_RETENTION_MODULE_I2S2, }, }; @@ -111,3 +112,56 @@ const i2s_signal_conn_t lp_i2s_periph_signal[SOC_LP_I2S_NUM] = { .irq = ETS_LP_I2S_INTR_SOURCE, }, }; + +/** + * I2S Registers to be saved during sleep retention + * - I2S_RX_CONF_REG + * - I2S_TX_CONF_REG + * - I2S_RX_CONF1_REG + * - I2S_TX_CONF1_REG + * - I2S_TX_PCM2PDM_CONF_REG + * - I2S_TX_PCM2PDM_CONF1_REG + * - I2S_RX_PDM2PCM_CONF_REG + * - I2S_RX_TDM_CTRL_REG + * - I2S_TX_TDM_CTRL_REG + * - I2S_RXEOF_NUM_REG + * - I2S_ETM_CONF_REG +*/ +#define I2S_RETENTION_REGS_CNT 11 +#define I2S_RETENTION_REGS_BASE(i) I2S_RX_CONF_REG(i) +static const uint32_t i2s_regs_map[4] = {0x12370f, 0x0, 0x0, 0x0}; +#define I2S_SLEEP_RETENTION_ENTRIES(i2s_port) { \ + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \ + REGDMA_I2S_LINK(0x00), \ + I2S_RETENTION_REGS_BASE(i2s_port), \ + I2S_RETENTION_REGS_BASE(i2s_port), \ + I2S_RETENTION_REGS_CNT, 0, 0, \ + i2s_regs_map[0], i2s_regs_map[1], \ + i2s_regs_map[2], i2s_regs_map[3]), \ + .owner = ENTRY(0)}, \ + [1] = { .config = REGDMA_LINK_WRITE_INIT( \ + REGDMA_I2S_LINK(0x01), I2S_RX_CONF_REG(i2s_port), I2S_RX_UPDATE, I2S_RX_UPDATE_M, 1, 0), \ + .owner = ENTRY(0) | ENTRY(2)}, \ + [2] = { .config = REGDMA_LINK_WRITE_INIT( \ + REGDMA_I2S_LINK(0x02), I2S_TX_CONF_REG(i2s_port), I2S_TX_UPDATE, I2S_TX_UPDATE_M, 1, 0), \ + .owner = ENTRY(0) | ENTRY(2)} \ +}; + +static const regdma_entries_config_t i2s0_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(0); +static const regdma_entries_config_t i2s1_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(1); +static const regdma_entries_config_t i2s2_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(2); + +const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_NUM] = { + [0] = { + .entry_array = i2s0_regs_retention, + .array_size = ARRAY_SIZE(i2s0_regs_retention) + }, + [1] = { + .entry_array = i2s1_regs_retention, + .array_size = ARRAY_SIZE(i2s1_regs_retention) + }, + [2] = { + .entry_array = i2s2_regs_retention, + .array_size = ARRAY_SIZE(i2s2_regs_retention) + }, +}; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 32f555421e..a883653c74 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -843,6 +843,10 @@ config SOC_I2S_TDM_FULL_DATA_WIDTH bool default y +config SOC_I2S_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_LP_I2S_NUM int default 1 diff --git a/components/soc/esp32p4/include/soc/retention_periph_defs.h b/components/soc/esp32p4/include/soc/retention_periph_defs.h index f70293e0f7..b069f7babd 100644 --- a/components/soc/esp32p4/include/soc/retention_periph_defs.h +++ b/components/soc/esp32p4/include/soc/retention_periph_defs.h @@ -41,6 +41,10 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_AXI_DMA_CH1 = 17, SLEEP_RETENTION_MODULE_AXI_DMA_CH2 = 18, + SLEEP_RETENTION_MODULE_I2S0 = 19, + SLEEP_RETENTION_MODULE_I2S1 = 20, + SLEEP_RETENTION_MODULE_I2S2 = 21, + SLEEP_RETENTION_MODULE_MAX = 31 } periph_retention_module_t; @@ -70,6 +74,9 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_UART3 = BIT(SLEEP_RETENTION_MODULE_UART3), SLEEP_RETENTION_MODULE_BM_UART4 = BIT(SLEEP_RETENTION_MODULE_UART4), SLEEP_RETENTION_MODULE_BM_RMT0 = BIT(SLEEP_RETENTION_MODULE_RMT0), + SLEEP_RETENTION_MODULE_BM_I2S0 = BIT(SLEEP_RETENTION_MODULE_I2S0), + SLEEP_RETENTION_MODULE_BM_I2S1 = BIT(SLEEP_RETENTION_MODULE_I2S1), + SLEEP_RETENTION_MODULE_BM_I2S2 = BIT(SLEEP_RETENTION_MODULE_I2S2), SLEEP_RETENTION_MODULE_BM_ALL = (uint32_t)-1 } periph_retention_module_bitmap_t; @@ -91,6 +98,9 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_UART3 \ | SLEEP_RETENTION_MODULE_BM_UART4 \ | SLEEP_RETENTION_MODULE_BM_RMT0 \ + | SLEEP_RETENTION_MODULE_BM_I2S0 \ + | SLEEP_RETENTION_MODULE_BM_I2S1 \ + | SLEEP_RETENTION_MODULE_BM_I2S2 \ ) #ifdef __cplusplus diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 33cf1c070a..d7dcd4200f 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -328,6 +328,7 @@ #define SOC_I2S_PDM_MAX_TX_LINES (2) // On I2S0 #define SOC_I2S_PDM_MAX_RX_LINES (4) // On I2S0 #define SOC_I2S_TDM_FULL_DATA_WIDTH (1) /*!< No limitation to data bit width when using multiple slots */ +#define SOC_I2S_SUPPORT_SLEEP_RETENTION 1 /*!< The sleep retention feature can help back up I2S registers before sleep */ /*-------------------------- LP_I2S CAPS -------------------------------------*/ #define SOC_LP_I2S_NUM (1U) diff --git a/components/soc/esp32s2/i2s_periph.c b/components/soc/esp32s2/i2s_periph.c index 25b4804cb2..c13b47926d 100644 --- a/components/soc/esp32s2/i2s_periph.c +++ b/components/soc/esp32s2/i2s_periph.c @@ -29,6 +29,5 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sig = I2S0I_DATA_IN15_IDX, .irq = ETS_I2S0_INTR_SOURCE, - .module = PERIPH_I2S0_MODULE, } }; diff --git a/components/soc/esp32s3/i2s_periph.c b/components/soc/esp32s3/i2s_periph.c index 853541bd9e..9d040cfc54 100644 --- a/components/soc/esp32s3/i2s_periph.c +++ b/components/soc/esp32s3/i2s_periph.c @@ -33,7 +33,6 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sigs[3] = I2S0I_SD3_IN_IDX, .irq = ETS_I2S0_INTR_SOURCE, - .module = PERIPH_I2S0_MODULE, }, { .mck_out_sig = I2S1_MCLK_OUT_IDX, @@ -57,6 +56,5 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sigs[3] = -1, .irq = ETS_I2S1_INTR_SOURCE, - .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/include/soc/i2s_periph.h b/components/soc/include/soc/i2s_periph.h index cf2d483f48..8100bb9a18 100644 --- a/components/soc/include/soc/i2s_periph.h +++ b/components/soc/include/soc/i2s_periph.h @@ -1,13 +1,15 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include "soc/soc.h" -#include "soc/periph_defs.h" +#include "soc/retention_periph_defs.h" +#include "soc/interrupts.h" #include "soc/soc_caps.h" +#include "soc/regdma.h" #if SOC_I2S_SUPPORTED #include "soc/i2s_struct.h" @@ -51,7 +53,9 @@ typedef struct { }; const uint8_t irq; - const periph_module_t module; +#if SOC_I2S_SUPPORT_SLEEP_RETENTION + const periph_retention_module_t retention_module; +#endif } i2s_signal_conn_t; extern const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM]; @@ -62,6 +66,15 @@ extern const i2s_signal_conn_t lp_i2s_periph_signal[SOC_LP_I2S_NUM]; #endif // SOC_I2S_SUPPORTED +#if SOC_I2S_SUPPORT_SLEEP_RETENTION +typedef struct { + const regdma_entries_config_t *entry_array; + uint32_t array_size; +} i2s_reg_retention_info_t; + +extern const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_NUM]; +#endif // SOC_I2S_SUPPORT_SLEEP_RETENTION + #ifdef __cplusplus } #endif diff --git a/components/soc/include/soc/regdma.h b/components/soc/include/soc/regdma.h index c48c66d0eb..c3c62081f0 100644 --- a/components/soc/include/soc/regdma.h +++ b/components/soc/include/soc/regdma.h @@ -53,6 +53,7 @@ extern "C" { #define REGDMA_TG1_WDT_LINK(_pri) ((0x1B << 8) | _pri) #define REGDMA_TG0_TIMER_LINK(_pri) ((0x1C << 8) | _pri) #define REGDMA_TG1_TIMER_LINK(_pri) ((0x1D << 8) | _pri) +#define REGDMA_I2S_LINK(_pri) ((0x1E << 8) | _pri) #define REGDMA_MODEM_FE_LINK(_pri) ((0xFF << 8) | _pri) #define REGDMA_LINK_PRI_SYS_CLK REGDMA_LINK_PRI_0 @@ -69,6 +70,7 @@ extern "C" { #define REGDMA_LINK_PRI_RMT REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_GPTIMER REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_I2C REGDMA_LINK_PRI_GENERAL_PERIPH +#define REGDMA_LINK_PRI_I2S REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_UART REGDMA_LINK_PRI_GENERAL_PERIPH typedef enum { diff --git a/docs/en/api-reference/system/power_management.rst b/docs/en/api-reference/system/power_management.rst index da52d19b09..8a7b9c37ba 100644 --- a/docs/en/api-reference/system/power_management.rst +++ b/docs/en/api-reference/system/power_management.rst @@ -153,6 +153,7 @@ The following peripheral drivers are not aware of DFS yet. Applications need to - SYSTIMER :SOC_RMT_SUPPORT_SLEEP_RETENTION: - RMT :SOC_I2C_SUPPORT_SLEEP_RETENTION: - I2C + :SOC_I2S_SUPPORT_SLEEP_RETENTION: - I2S :SOC_UART_SUPPORT_SLEEP_RETENTION: - All UARTs The following peripherals are not yet supported: @@ -164,7 +165,6 @@ The following peripheral drivers are not aware of DFS yet. Applications need to - Trace - Crypto: AES/ECC/HMAC/RSA/SHA/DS/XTA_AES/ECDSA - SPI2 - - I2S - PCNT - USB-Serial-JTAG - TWAI diff --git a/docs/zh_CN/api-reference/system/power_management.rst b/docs/zh_CN/api-reference/system/power_management.rst index 3762008505..6d1e464abc 100644 --- a/docs/zh_CN/api-reference/system/power_management.rst +++ b/docs/zh_CN/api-reference/system/power_management.rst @@ -152,7 +152,8 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求, - SPI0/1 - SYSTIMER :SOC_RMT_SUPPORT_SLEEP_RETENTION: - RMT - :SOC_I2C_SUPPORT_SLEEP_RETENTION:- I2C + :SOC_I2C_SUPPORT_SLEEP_RETENTION: - I2C + :SOC_I2S_SUPPORT_SLEEP_RETENTION: - I2S :SOC_UART_SUPPORT_SLEEP_RETENTION: - All UARTs 以下外设尚未支持: @@ -164,7 +165,6 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求, - Trace - Crypto: AES/ECC/HMAC/RSA/SHA/DS/XTA_AES/ECDSA - SPI2 - - I2S - PCNT - USB-Serial-JTAG - TWAI