|
41 | 41 |
|
42 | 42 | #include "esp_private/i2s_platform.h" |
43 | 43 | #include "esp_private/esp_clk.h" |
| 44 | +#include "esp_private/sleep_retention.h" |
44 | 45 |
|
45 | 46 | #include "driver/gpio.h" |
46 | 47 | #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) |
85 | 86 | Scope: This file only |
86 | 87 | ----------------------------------------------------------------------------*/ |
87 | 88 |
|
| 89 | +#if I2S_USE_RETENTION_LINK |
| 90 | +static esp_err_t s_i2s_create_sleep_retention_link_cb(void *arg) |
| 91 | +{ |
| 92 | + i2s_controller_t *i2s_obj = (i2s_controller_t *)arg; |
| 93 | + ESP_RETURN_ON_ERROR(sleep_retention_entries_create(i2s_reg_retention_info[i2s_obj->id].entry_array, |
| 94 | + i2s_reg_retention_info[i2s_obj->id].array_size, |
| 95 | + REGDMA_LINK_PRI_I2S, i2s_obj->slp_retention_mod), |
| 96 | + TAG, "create retention link failed"); |
| 97 | + return ESP_OK; |
| 98 | +} |
| 99 | + |
| 100 | +static void s_i2s_create_retention_module(i2s_controller_t *i2s_obj) |
| 101 | +{ |
| 102 | + sleep_retention_module_t module = i2s_obj->slp_retention_mod; |
| 103 | + |
| 104 | + _lock_acquire(&i2s_obj->mutex); |
| 105 | + if (i2s_obj->retention_link_created == false) { |
| 106 | + if (sleep_retention_module_allocate(module) != ESP_OK) { |
| 107 | + // even though the sleep retention module create failed, I2S driver should still work, so just warning here |
| 108 | + ESP_LOGW(TAG, "create retention module failed, power domain can't turn off"); |
| 109 | + } else { |
| 110 | + i2s_obj->retention_link_created = true; |
| 111 | + } |
| 112 | + } |
| 113 | + _lock_release(&i2s_obj->mutex); |
| 114 | +} |
| 115 | +#endif // I2S_USE_RETENTION_LINK |
| 116 | + |
88 | 117 | static void i2s_tx_channel_start(i2s_chan_handle_t handle) |
89 | 118 | { |
90 | 119 | i2s_hal_tx_reset(&(handle->controller->hal)); |
@@ -175,6 +204,14 @@ static esp_err_t i2s_destroy_controller_obj(i2s_controller_t **i2s_obj) |
175 | 204 | #if SOC_I2S_HW_VERSION_1 |
176 | 205 | i2s_ll_enable_dma((*i2s_obj)->hal.dev, false); |
177 | 206 | #endif |
| 207 | +#if I2S_USE_RETENTION_LINK |
| 208 | + if ((*i2s_obj)->slp_retention_mod) { |
| 209 | + if ((*i2s_obj)->retention_link_created) { |
| 210 | + sleep_retention_module_free((*i2s_obj)->slp_retention_mod); |
| 211 | + } |
| 212 | + sleep_retention_module_deinit((*i2s_obj)->slp_retention_mod); |
| 213 | + } |
| 214 | +#endif // I2S_USE_RETENTION_LINK |
178 | 215 | free(*i2s_obj); |
179 | 216 | *i2s_obj = NULL; |
180 | 217 | return i2s_platform_release_occupation(I2S_CTLR_HP, id); |
@@ -219,6 +256,25 @@ static i2s_controller_t *i2s_acquire_controller_obj(int id) |
219 | 256 | adc_ll_digi_set_data_source(0); |
220 | 257 | } |
221 | 258 | #endif |
| 259 | + |
| 260 | +#if I2S_USE_RETENTION_LINK |
| 261 | + sleep_retention_module_t module = i2s_periph_signal[id].retention_module; |
| 262 | + sleep_retention_module_init_param_t init_param = { |
| 263 | + .cbs = { |
| 264 | + .create = { |
| 265 | + .handle = s_i2s_create_sleep_retention_link_cb, |
| 266 | + .arg = i2s_obj, |
| 267 | + }, |
| 268 | + }, |
| 269 | + .depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM) |
| 270 | + }; |
| 271 | + if (sleep_retention_module_init(module, &init_param) == ESP_OK) { |
| 272 | + i2s_obj->slp_retention_mod = module; |
| 273 | + } else { |
| 274 | + // even the sleep retention module init failed, I2S driver should still work, so just warning here |
| 275 | + ESP_LOGW(TAG, "init sleep retention failed for I2S%d, power domain may be turned off during sleep", id); |
| 276 | + } |
| 277 | +#endif // I2S_USE_RETENTION_LINK |
222 | 278 | } else { |
223 | 279 | free(pre_alloc); |
224 | 280 | 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 * |
879 | 935 | 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"); |
880 | 936 | ESP_RETURN_ON_FALSE(chan_cfg->dma_desc_num >= 2, ESP_ERR_INVALID_ARG, TAG, "there should be at least 2 DMA buffers"); |
881 | 937 | 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"); |
| 938 | +#if !SOC_I2S_SUPPORT_SLEEP_RETENTION |
| 939 | + ESP_RETURN_ON_FALSE(!chan_cfg->backup_before_sleep, ESP_ERR_NOT_SUPPORTED, TAG, "register back up is not supported"); |
| 940 | +#endif |
882 | 941 |
|
883 | 942 | esp_err_t ret = ESP_OK; |
884 | 943 | 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 * |
937 | 996 | if ((tx_handle != NULL) && (rx_handle != NULL)) { |
938 | 997 | i2s_obj->full_duplex = true; |
939 | 998 | } |
| 999 | +#if I2S_USE_RETENTION_LINK |
| 1000 | + if (chan_cfg->backup_before_sleep) { |
| 1001 | + s_i2s_create_retention_module(i2s_obj); |
| 1002 | + } |
| 1003 | +#endif |
940 | 1004 |
|
941 | 1005 | return ESP_OK; |
942 | 1006 | /* i2s_obj allocated but register channel failed */ |
|
0 commit comments