1 /*
2  * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 #include <stdlib.h>
9 #include <esp_types.h>
10 #include "sdkconfig.h"
11 #include "esp_attr.h"
12 #include "soc/soc.h"
13 #include "soc/soc_caps.h"
14 #include "hal/clk_gate_ll.h"
15 #include "esp_private/esp_modem_clock.h"
16 #include "esp_private/esp_pmu.h"
17 #include "esp_sleep.h"
18 #include "hal/efuse_hal.h"
19 #include "hal/clk_tree_ll.h"
20 
21 #include <zephyr/kernel.h>
22 
23 // Please define the frequently called modules in the low bit,
24 // which will improve the execution efficiency
25 typedef enum {
26     MODEM_CLOCK_MODEM_ADC_COMMON_FE,
27     MODEM_CLOCK_MODEM_PRIVATE_FE,
28     MODEM_CLOCK_COEXIST,
29     MODEM_CLOCK_I2C_MASTER,
30 #if SOC_WIFI_SUPPORTED
31     MODEM_CLOCK_WIFI_MAC,
32     MODEM_CLOCK_WIFI_BB,
33 #endif
34     MODEM_CLOCK_ETM,
35 #if SOC_BT_SUPPORTED
36     MODEM_CLOCK_BLE_MAC,
37     MODEM_CLOCK_BLE_BB,
38 #endif
39 #if SOC_IEEE802154_SUPPORTED
40     MODEM_CLOCK_802154_MAC,
41 #endif
42     MODEM_CLOCK_DATADUMP,
43     MODEM_CLOCK_DEVICE_MAX
44 } modem_clock_device_t;
45 
46 
47 typedef struct modem_clock_context {
48     modem_clock_hal_context_t *hal;
49     unsigned int              lock;
50     struct {
51         int16_t     refs;
52         uint16_t    reserved;   /* reserved for 4 bytes aligned */
53         void (*configure)(struct modem_clock_context *, bool);
54     } dev[MODEM_CLOCK_DEVICE_MAX];
55     /* the low-power clock source for each module */
56     modem_clock_lpclk_src_t lpclk_src[PERIPH_MODEM_MODULE_NUM];
57 } modem_clock_context_t;
58 
59 
60 #if SOC_WIFI_SUPPORTED
modem_clock_wifi_mac_configure(modem_clock_context_t * ctx,bool enable)61 static void IRAM_ATTR modem_clock_wifi_mac_configure(modem_clock_context_t *ctx, bool enable)
62 {
63     if (enable) {
64         modem_syscon_ll_enable_wifi_apb_clock(ctx->hal->syscon_dev, enable);
65         modem_syscon_ll_enable_wifi_mac_clock(ctx->hal->syscon_dev, enable);
66     }
67 }
68 
modem_clock_wifi_bb_configure(modem_clock_context_t * ctx,bool enable)69 static void IRAM_ATTR modem_clock_wifi_bb_configure(modem_clock_context_t *ctx, bool enable)
70 {
71     if (enable) {
72         modem_syscon_ll_clk_wifibb_configure(ctx->hal->syscon_dev, enable);
73     }
74 }
75 #endif // SOC_WIFI_SUPPORTED
76 
77 #if SOC_BT_SUPPORTED
modem_clock_ble_mac_configure(modem_clock_context_t * ctx,bool enable)78 static void IRAM_ATTR modem_clock_ble_mac_configure(modem_clock_context_t *ctx, bool enable)
79 {
80     modem_syscon_ll_enable_modem_sec_clock(ctx->hal->syscon_dev, enable);
81     modem_syscon_ll_enable_ble_timer_clock(ctx->hal->syscon_dev, enable);
82 }
83 
modem_clock_ble_bb_configure(modem_clock_context_t * ctx,bool enable)84 static void IRAM_ATTR modem_clock_ble_bb_configure(modem_clock_context_t *ctx, bool enable)
85 {
86     modem_syscon_ll_enable_bt_apb_clock(ctx->hal->syscon_dev, enable);
87     modem_syscon_ll_enable_bt_clock(ctx->hal->syscon_dev, enable);
88 }
89 
90 #endif // SOC_BT_SUPPORTED
91 
92 #if SOC_IEEE802154_SUPPORTED
modem_clock_ieee802154_mac_configure(modem_clock_context_t * ctx,bool enable)93 static void IRAM_ATTR modem_clock_ieee802154_mac_configure(modem_clock_context_t *ctx, bool enable)
94 {
95     modem_syscon_ll_enable_ieee802154_apb_clock(ctx->hal->syscon_dev, enable);
96     modem_syscon_ll_enable_ieee802154_mac_clock(ctx->hal->syscon_dev, enable);
97 }
98 #endif // SOC_IEEE802154_SUPPORTED
99 
modem_clock_coex_configure(modem_clock_context_t * ctx,bool enable)100 static void IRAM_ATTR modem_clock_coex_configure(modem_clock_context_t *ctx, bool enable)
101 {
102     modem_lpcon_ll_enable_coex_clock(ctx->hal->lpcon_dev, enable);
103 }
104 
modem_clock_modem_adc_common_fe_configure(modem_clock_context_t * ctx,bool enable)105 static void IRAM_ATTR modem_clock_modem_adc_common_fe_configure(modem_clock_context_t *ctx, bool enable)
106 {
107     modem_clock_hal_enable_modem_adc_common_fe_clock(ctx->hal, enable);
108 }
109 
modem_clock_modem_private_fe_configure(modem_clock_context_t * ctx,bool enable)110 static void IRAM_ATTR modem_clock_modem_private_fe_configure(modem_clock_context_t *ctx, bool enable)
111 {
112     modem_clock_hal_enable_modem_private_fe_clock(ctx->hal, enable);
113 }
114 
modem_clock_i2c_master_configure(modem_clock_context_t * ctx,bool enable)115 static void IRAM_ATTR modem_clock_i2c_master_configure(modem_clock_context_t *ctx, bool enable)
116 {
117     modem_lpcon_ll_enable_i2c_master_clock(ctx->hal->lpcon_dev, enable);
118 }
119 
modem_clock_etm_configure(modem_clock_context_t * ctx,bool enable)120 static void IRAM_ATTR modem_clock_etm_configure(modem_clock_context_t *ctx, bool enable)
121 {
122     modem_syscon_ll_enable_etm_clock(ctx->hal->syscon_dev, enable);
123 }
124 
modem_clock_data_dump_configure(modem_clock_context_t * ctx,bool enable)125 static void IRAM_ATTR modem_clock_data_dump_configure(modem_clock_context_t *ctx, bool enable)
126 {
127     modem_syscon_ll_enable_data_dump_clock(ctx->hal->syscon_dev, enable);
128     modem_syscon_ll_enable_data_dump_mux_clock(ctx->hal->syscon_dev, enable);
129 }
130 
MODEM_CLOCK_instance(void)131 modem_clock_context_t * __attribute__((weak)) IRAM_ATTR MODEM_CLOCK_instance(void)
132 {
133     /* It should be explicitly defined in the internal RAM */
134     static DRAM_ATTR modem_clock_hal_context_t modem_clock_hal = { .syscon_dev = &MODEM_SYSCON, .lpcon_dev = &MODEM_LPCON };
135     static DRAM_ATTR modem_clock_context_t modem_clock_context = {
136         .hal = &modem_clock_hal, .lock = 0,
137         .dev = {
138             [MODEM_CLOCK_MODEM_ADC_COMMON_FE]   = { .refs = 0, .configure = modem_clock_modem_adc_common_fe_configure },
139             [MODEM_CLOCK_MODEM_PRIVATE_FE]      = { .refs = 0, .configure = modem_clock_modem_private_fe_configure },
140             [MODEM_CLOCK_COEXIST]               = { .refs = 0, .configure = modem_clock_coex_configure },
141             [MODEM_CLOCK_I2C_MASTER]            = { .refs = 0, .configure = modem_clock_i2c_master_configure },
142 #if SOC_WIFI_SUPPORTED
143             [MODEM_CLOCK_WIFI_MAC]              = { .refs = 0, .configure = modem_clock_wifi_mac_configure },
144             [MODEM_CLOCK_WIFI_BB]               = { .refs = 0, .configure = modem_clock_wifi_bb_configure },
145 #endif
146             [MODEM_CLOCK_ETM]                   = { .refs = 0, .configure = modem_clock_etm_configure },
147 #if SOC_BT_SUPPORTED
148             [MODEM_CLOCK_BLE_MAC]               = { .refs = 0, .configure = modem_clock_ble_mac_configure },
149             [MODEM_CLOCK_BLE_BB]                = { .refs = 0, .configure = modem_clock_ble_bb_configure },
150 #endif
151 #if SOC_IEEE802154_SUPPORTED
152             [MODEM_CLOCK_802154_MAC]            = { .refs = 0, .configure = modem_clock_ieee802154_mac_configure },
153 #endif
154             [MODEM_CLOCK_DATADUMP]              = { .refs = 0, .configure = modem_clock_data_dump_configure }
155         },
156         .lpclk_src = { [0 ... PERIPH_MODEM_MODULE_NUM - 1] = MODEM_CLOCK_LPCLK_SRC_INVALID }
157     };
158     return &modem_clock_context;
159 }
160 
161 #if SOC_PM_SUPPORT_PMU_MODEM_STATE
modem_clock_domain_clk_gate_enable(modem_clock_domain_t domain,pmu_hp_icg_modem_mode_t mode)162 esp_err_t modem_clock_domain_clk_gate_enable(modem_clock_domain_t domain, pmu_hp_icg_modem_mode_t mode)
163 {
164     if (domain >= MODEM_CLOCK_DOMAIN_MAX || domain < MODEM_CLOCK_DOMAIN_MODEM_APB) {
165         return ESP_ERR_INVALID_ARG;
166     }
167     if (mode > PMU_HP_ICG_MODEM_CODE_ACTIVE || mode < PMU_HP_ICG_MODEM_CODE_SLEEP) {
168         return ESP_ERR_INVALID_ARG;
169     }
170 
171     MODEM_CLOCK_instance()->lock = irq_lock();
172     uint32_t code = modem_clock_hal_get_clock_domain_icg_bitmap(MODEM_CLOCK_instance()->hal, domain);
173     modem_clock_hal_set_clock_domain_icg_bitmap(MODEM_CLOCK_instance()->hal, domain, (code & ~BIT(mode)));
174     irq_unlock(MODEM_CLOCK_instance()->lock);
175     return ESP_OK;
176 }
177 
modem_clock_domain_clk_gate_disable(modem_clock_domain_t domain,pmu_hp_icg_modem_mode_t mode)178 esp_err_t modem_clock_domain_clk_gate_disable(modem_clock_domain_t domain, pmu_hp_icg_modem_mode_t mode)
179 {
180     if (domain >= MODEM_CLOCK_DOMAIN_MAX || domain < MODEM_CLOCK_DOMAIN_MODEM_APB) {
181         return ESP_ERR_INVALID_ARG;
182     }
183     if (mode > PMU_HP_ICG_MODEM_CODE_ACTIVE || mode < PMU_HP_ICG_MODEM_CODE_SLEEP) {
184         return ESP_ERR_INVALID_ARG;
185     }
186 
187     MODEM_CLOCK_instance()->lock = irq_lock();
188     uint32_t code = modem_clock_hal_get_clock_domain_icg_bitmap(MODEM_CLOCK_instance()->hal, domain);
189     modem_clock_hal_set_clock_domain_icg_bitmap(MODEM_CLOCK_instance()->hal, domain, (code | BIT(mode)));
190     irq_unlock(MODEM_CLOCK_instance()->lock);
191     return ESP_OK;
192 }
193 #endif // #if SOC_PM_SUPPORT_PMU_MODEM_STATE
194 
modem_clock_device_enable(modem_clock_context_t * ctx,uint32_t dev_map)195 static void IRAM_ATTR modem_clock_device_enable(modem_clock_context_t *ctx, uint32_t dev_map)
196 {
197     int16_t refs = 0;
198     ctx->lock = irq_lock();
199     for (int i = 0; dev_map; dev_map >>= 1, i++)
200     {
201         if (dev_map & BIT(0)) {
202             refs = ctx->dev[i].refs++;
203             if (refs == 0) {
204                 (*ctx->dev[i].configure)(ctx, true);
205             }
206         }
207     }
208     irq_unlock(ctx->lock);
209     assert(refs >= 0);
210 }
211 
modem_clock_device_disable(modem_clock_context_t * ctx,uint32_t dev_map)212 static void IRAM_ATTR modem_clock_device_disable(modem_clock_context_t *ctx, uint32_t dev_map)
213 {
214     int16_t refs = 0;
215     ctx->lock = irq_lock();
216     for (int i = 0; dev_map; dev_map >>= 1, i++) {
217         if (dev_map & BIT(0)) {
218             refs = --ctx->dev[i].refs;
219             if (refs == 0) {
220                 (*ctx->dev[i].configure)(ctx, false);
221             }
222         }
223     }
224     irq_unlock(ctx->lock);
225     assert(refs >= 0);
226 }
227 
modem_clock_module_mac_reset(periph_module_t module)228 void IRAM_ATTR modem_clock_module_mac_reset(periph_module_t module)
229 {
230     modem_clock_context_t *ctx = MODEM_CLOCK_instance();
231     ctx->lock = irq_lock();
232     switch (module)
233     {
234 #if SOC_WIFI_SUPPORTED
235         case PERIPH_WIFI_MODULE:
236             modem_syscon_ll_reset_wifimac(ctx->hal->syscon_dev);
237             break;
238 #endif
239 #if SOC_BT_SUPPORTED
240         case PERIPH_BT_MODULE:
241             modem_syscon_ll_reset_btmac(ctx->hal->syscon_dev);
242             modem_syscon_ll_reset_btmac_apb(ctx->hal->syscon_dev);
243             modem_syscon_ll_reset_ble_timer(ctx->hal->syscon_dev);
244             modem_syscon_ll_reset_modem_sec(ctx->hal->syscon_dev);
245             break;
246 #endif
247 #if SOC_IEEE802154_SUPPORTED
248         case PERIPH_IEEE802154_MODULE:
249             modem_syscon_ll_reset_zbmac(ctx->hal->syscon_dev);
250             break;
251         default:
252 #endif
253             assert(0);
254     }
255     irq_unlock(ctx->lock);
256 }
257 
258 #define WIFI_CLOCK_DEPS         (BIT(MODEM_CLOCK_WIFI_MAC) | BIT(MODEM_CLOCK_WIFI_BB) | BIT(MODEM_CLOCK_COEXIST))
259 #define BLE_CLOCK_DEPS          (BIT(MODEM_CLOCK_BLE_MAC) | BIT(MODEM_CLOCK_BLE_BB) | BIT(MODEM_CLOCK_ETM) | BIT(MODEM_CLOCK_COEXIST))
260 #define IEEE802154_CLOCK_DEPS   (BIT(MODEM_CLOCK_802154_MAC) | BIT(MODEM_CLOCK_BLE_BB) | BIT(MODEM_CLOCK_ETM) | BIT(MODEM_CLOCK_COEXIST))
261 #define COEXIST_CLOCK_DEPS      (BIT(MODEM_CLOCK_COEXIST))
262 #define PHY_CLOCK_DEPS          (BIT(MODEM_CLOCK_I2C_MASTER) | BIT(MODEM_CLOCK_MODEM_ADC_COMMON_FE) | BIT(MODEM_CLOCK_MODEM_PRIVATE_FE))
263 #define I2C_ANA_MST_CLOCK_DEPS  (BIT(MODEM_CLOCK_I2C_MASTER))
264 #define MODEM_ETM_CLOCK_DEPS    (BIT(MODEM_CLOCK_ETM))
265 #define MODEM_ADC_COMMON_FE_CLOCK_DEPS  (BIT(MODEM_CLOCK_MODEM_ADC_COMMON_FE))
266 
modem_clock_get_module_deps(periph_module_t module)267 static IRAM_ATTR uint32_t modem_clock_get_module_deps(periph_module_t module)
268 {
269     uint32_t deps = 0;
270     switch (module) {
271         case PERIPH_ANA_I2C_MASTER_MODULE:      deps = I2C_ANA_MST_CLOCK_DEPS;          break;
272         case PERIPH_PHY_MODULE:                 deps = PHY_CLOCK_DEPS;                  break;
273         case PERIPH_MODEM_ADC_COMMON_FE_MODULE: deps = MODEM_ADC_COMMON_FE_CLOCK_DEPS;  break;
274 #if SOC_WIFI_SUPPORTED || SOC_BT_SUPPORTED || SOC_IEEE802154_SUPPORTED
275         case PERIPH_COEX_MODULE:                deps = COEXIST_CLOCK_DEPS;              break;
276 #endif
277 #if SOC_WIFI_SUPPORTED
278         case PERIPH_WIFI_MODULE:                deps = WIFI_CLOCK_DEPS;                 break;
279 #endif
280 #if SOC_BT_SUPPORTED
281         case PERIPH_BT_MODULE:                  deps = BLE_CLOCK_DEPS;                  break;
282 #endif
283 #if SOC_IEEE802154_SUPPORTED
284         case PERIPH_IEEE802154_MODULE:          deps = IEEE802154_CLOCK_DEPS;           break;
285 #endif
286 #if SOC_BT_SUPPORTED || SOC_IEEE802154_SUPPORTED
287         case PERIPH_MODEM_ETM_MODULE:           deps = MODEM_ETM_CLOCK_DEPS;            break;
288 #endif
289         default:
290             assert(0);
291     }
292     return deps;
293 }
294 
295 #if SOC_PM_SUPPORT_PMU_MODEM_STATE
296 /* the ICG code's bit 0, 1 and 2 indicates the ICG state
297  * of pmu SLEEP, MODEM and ACTIVE mode respectively */
298 #define ICG_NOGATING_SLEEP  (BIT(PMU_HP_ICG_MODEM_CODE_SLEEP))
299 #define ICG_NOGATING_MODEM  (BIT(PMU_HP_ICG_MODEM_CODE_MODEM))
300 #define ICG_NOGATING_ACTIVE (BIT(PMU_HP_ICG_MODEM_CODE_ACTIVE))
301 
302 static const DRAM_ATTR uint32_t initial_gating_mode[MODEM_CLOCK_DOMAIN_MAX] = {
303     [MODEM_CLOCK_DOMAIN_MODEM_APB]      = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
304     [MODEM_CLOCK_DOMAIN_MODEM_PERIPH]   = ICG_NOGATING_ACTIVE,
305     [MODEM_CLOCK_DOMAIN_WIFI]           = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
306     [MODEM_CLOCK_DOMAIN_BT]             = ICG_NOGATING_ACTIVE,
307     [MODEM_CLOCK_DOMAIN_MODEM_FE]       = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
308     [MODEM_CLOCK_DOMAIN_IEEE802154]     = ICG_NOGATING_ACTIVE,
309     [MODEM_CLOCK_DOMAIN_LP_APB]         = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
310     [MODEM_CLOCK_DOMAIN_I2C_MASTER]     = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
311     [MODEM_CLOCK_DOMAIN_COEX]           = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
312     [MODEM_CLOCK_DOMAIN_WIFIPWR]        = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
313 };
314 
modem_clock_module_icg_map_init_all(void)315 static IRAM_ATTR void modem_clock_module_icg_map_init_all(void)
316 {
317     MODEM_CLOCK_instance()->lock = irq_lock();
318     for (int domain = 0; domain < MODEM_CLOCK_DOMAIN_MAX; domain++) {
319         uint32_t code = modem_clock_hal_get_clock_domain_icg_bitmap(MODEM_CLOCK_instance()->hal, domain);
320         modem_clock_hal_set_clock_domain_icg_bitmap(MODEM_CLOCK_instance()->hal, domain, initial_gating_mode[domain] | code);
321     }
322     irq_unlock(MODEM_CLOCK_instance()->lock);
323 }
324 #endif // SOC_PM_SUPPORT_PMU_MODEM_STATE
325 
modem_clock_module_enable(periph_module_t module)326 void IRAM_ATTR modem_clock_module_enable(periph_module_t module)
327 {
328     assert(IS_MODEM_MODULE(module));
329 #if SOC_PM_SUPPORT_PMU_MODEM_STATE
330     modem_clock_module_icg_map_init_all();
331 #endif
332     uint32_t deps = modem_clock_get_module_deps(module);
333     modem_clock_device_enable(MODEM_CLOCK_instance(), deps);
334 }
335 
modem_clock_module_disable(periph_module_t module)336 void IRAM_ATTR modem_clock_module_disable(periph_module_t module)
337 {
338     assert(IS_MODEM_MODULE(module));
339     uint32_t deps = modem_clock_get_module_deps(module);
340     modem_clock_device_disable(MODEM_CLOCK_instance(), deps);
341 }
342 
modem_clock_deselect_all_module_lp_clock_source(void)343 void modem_clock_deselect_all_module_lp_clock_source(void)
344 {
345 #if SOC_WIFI_SUPPORTED
346     modem_clock_hal_deselect_all_wifi_lpclk_source(MODEM_CLOCK_instance()->hal);
347 #endif
348 #if SOC_BT_SUPPORTED
349     modem_clock_hal_deselect_all_ble_rtc_timer_lpclk_source(MODEM_CLOCK_instance()->hal);
350 #endif
351     modem_clock_hal_deselect_all_coex_lpclk_source(MODEM_CLOCK_instance()->hal);
352 }
353 
modem_clock_select_lp_clock_source(periph_module_t module,modem_clock_lpclk_src_t src,uint32_t divider)354 void modem_clock_select_lp_clock_source(periph_module_t module, modem_clock_lpclk_src_t src, uint32_t divider)
355 {
356     assert(IS_MODEM_MODULE(module));
357     MODEM_CLOCK_instance()->lock = irq_lock();
358     switch (module)
359     {
360 #if SOC_WIFI_SUPPORTED
361     case PERIPH_WIFI_MODULE:
362         modem_clock_hal_deselect_all_wifi_lpclk_source(MODEM_CLOCK_instance()->hal);
363         modem_clock_hal_select_wifi_lpclk_source(MODEM_CLOCK_instance()->hal, src);
364         modem_lpcon_ll_set_wifi_lpclk_divisor_value(MODEM_CLOCK_instance()->hal->lpcon_dev, divider);
365         modem_clock_hal_enable_wifipwr_clock(MODEM_CLOCK_instance()->hal, true);
366         break;
367 #endif // SOC_WIFI_SUPPORTED
368 
369 #if SOC_BT_SUPPORTED
370     case PERIPH_BT_MODULE:
371 #if CONFIG_IDF_TARGET_ESP32H2
372         bool rc_clk_en = true;
373         bool selected = (src == MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL) ||
374                         (src == MODEM_CLOCK_LPCLK_SRC_RC_SLOW);
375         if (selected) {
376             rc_clk_en = clk_ll_rc32k_is_enabled();
377             if (!rc_clk_en) {
378                 clk_ll_rc32k_enable();
379             }
380             modem_clock_hal_select_ble_rtc_timer_lpclk_source(MODEM_CLOCK_instance()->hal, MODEM_CLOCK_LPCLK_SRC_RC32K);
381         }
382 #endif // CONFIG_IDF_TARGET_ESP32H2
383         modem_clock_hal_deselect_all_ble_rtc_timer_lpclk_source(MODEM_CLOCK_instance()->hal);
384         modem_clock_hal_select_ble_rtc_timer_lpclk_source(MODEM_CLOCK_instance()->hal, src);
385         modem_clock_hal_set_ble_rtc_timer_divisor_value(MODEM_CLOCK_instance()->hal, divider);
386         modem_clock_hal_enable_ble_rtc_timer_clock(MODEM_CLOCK_instance()->hal, true);
387 #if CONFIG_IDF_TARGET_ESP32H2
388         if (!rc_clk_en) {
389             extern void r_esp_ble_rtc_ticks_delay(uint32_t ticks);
390             r_esp_ble_rtc_ticks_delay(2);
391             clk_ll_rc32k_disable();
392         }
393 #endif // CONFIG_IDF_TARGET_ESP32H2
394 #if SOC_BLE_USE_WIFI_PWR_CLK_WORKAROUND
395         if (efuse_hal_chip_revision() != 0) {
396             if (src == MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL) {
397                 pmu_sleep_enable_hp_sleep_sysclk(true);
398                 modem_clock_hal_enable_wifipwr_clock(MODEM_CLOCK_instance()->hal, true);
399                 modem_clock_domain_clk_gate_disable(MODEM_CLOCK_DOMAIN_WIFIPWR, PMU_HP_ICG_MODEM_CODE_SLEEP);
400             }
401         }
402 #endif
403         break;
404 #endif // SOC_BT_SUPPORTED
405 
406     case PERIPH_COEX_MODULE:
407         modem_clock_hal_deselect_all_coex_lpclk_source(MODEM_CLOCK_instance()->hal);
408         modem_clock_hal_select_coex_lpclk_source(MODEM_CLOCK_instance()->hal, src);
409         modem_lpcon_ll_set_coex_lpclk_divisor_value(MODEM_CLOCK_instance()->hal->lpcon_dev, divider);
410         // modem_lpcon_ll_enable_coex_clock(MODEM_CLOCK_instance()->hal->lpcon_dev, true); // TODO: IDF-5727
411         break;
412     default:
413         break;
414     }
415     modem_clock_lpclk_src_t last_src = MODEM_CLOCK_instance()->lpclk_src[module - PERIPH_MODEM_MODULE_MIN];
416     MODEM_CLOCK_instance()->lpclk_src[module - PERIPH_MODEM_MODULE_MIN] = src;
417     irq_unlock(MODEM_CLOCK_instance()->lock);
418 
419     /* The power domain of the low-power clock source required by the modem
420      * module remains powered on during sleep */
421     esp_sleep_pd_domain_t pd_domain = (esp_sleep_pd_domain_t) ( \
422               (last_src == MODEM_CLOCK_LPCLK_SRC_RC_FAST)  ? ESP_PD_DOMAIN_RC_FAST  \
423             : (last_src == MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL) ? ESP_PD_DOMAIN_XTAL    \
424             : (last_src == MODEM_CLOCK_LPCLK_SRC_RC32K)     ? ESP_PD_DOMAIN_RC32K   \
425             : (last_src == MODEM_CLOCK_LPCLK_SRC_XTAL32K)   ? ESP_PD_DOMAIN_XTAL32K \
426             : ESP_PD_DOMAIN_MAX);
427     esp_sleep_pd_domain_t pu_domain = (esp_sleep_pd_domain_t) ( \
428               (src == MODEM_CLOCK_LPCLK_SRC_RC_FAST)  ? ESP_PD_DOMAIN_RC_FAST  \
429             : (src == MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL) ? ESP_PD_DOMAIN_XTAL    \
430             : (src == MODEM_CLOCK_LPCLK_SRC_RC32K)     ? ESP_PD_DOMAIN_RC32K   \
431             : (src == MODEM_CLOCK_LPCLK_SRC_XTAL32K)   ? ESP_PD_DOMAIN_XTAL32K \
432             : ESP_PD_DOMAIN_MAX);
433     esp_sleep_pd_config(pd_domain, ESP_PD_OPTION_OFF);
434     esp_sleep_pd_config(pu_domain, ESP_PD_OPTION_ON);
435 }
436 
modem_clock_deselect_lp_clock_source(periph_module_t module)437 void modem_clock_deselect_lp_clock_source(periph_module_t module)
438 {
439     assert(IS_MODEM_MODULE(module));
440     MODEM_CLOCK_instance()->lock = irq_lock();
441     modem_clock_lpclk_src_t last_src = MODEM_CLOCK_instance()->lpclk_src[module - PERIPH_MODEM_MODULE_MIN];
442     MODEM_CLOCK_instance()->lpclk_src[module - PERIPH_MODEM_MODULE_MIN] = MODEM_CLOCK_LPCLK_SRC_INVALID;
443     switch (module)
444     {
445 #if SOC_WIFI_SUPPORTED
446     case PERIPH_WIFI_MODULE:
447         modem_clock_hal_deselect_all_wifi_lpclk_source(MODEM_CLOCK_instance()->hal);
448         modem_clock_hal_enable_wifipwr_clock(MODEM_CLOCK_instance()->hal, false);
449         break;
450 #endif // SOC_WIFI_SUPPORTED
451 
452 #if SOC_BT_SUPPORTED
453     case PERIPH_BT_MODULE:
454         modem_clock_hal_deselect_all_ble_rtc_timer_lpclk_source(MODEM_CLOCK_instance()->hal);
455         modem_clock_hal_enable_ble_rtc_timer_clock(MODEM_CLOCK_instance()->hal, false);
456 #if SOC_BLE_USE_WIFI_PWR_CLK_WORKAROUND
457         if (efuse_hal_chip_revision() != 0) {
458             if (last_src == MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL) {
459                 pmu_sleep_enable_hp_sleep_sysclk(false);
460                 modem_clock_hal_enable_wifipwr_clock(MODEM_CLOCK_instance()->hal, false);
461                 modem_clock_domain_clk_gate_enable(MODEM_CLOCK_DOMAIN_WIFIPWR, PMU_HP_ICG_MODEM_CODE_SLEEP);
462             }
463         }
464 #endif
465         break;
466 #endif // SOC_BT_SUPPORTED
467     case PERIPH_COEX_MODULE:
468         modem_clock_hal_deselect_all_coex_lpclk_source(MODEM_CLOCK_instance()->hal);
469         // modem_lpcon_ll_enable_coex_clock(MODEM_CLOCK_instance()->hal->lpcon_dev, false); // TODO: IDF-5727
470         break;
471     default:
472         break;
473     }
474     irq_unlock(MODEM_CLOCK_instance()->lock);
475 
476     esp_sleep_pd_domain_t pd_domain = (esp_sleep_pd_domain_t) ( \
477               (last_src == MODEM_CLOCK_LPCLK_SRC_RC_FAST)  ? ESP_PD_DOMAIN_RC_FAST  \
478             : (last_src == MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL) ? ESP_PD_DOMAIN_XTAL    \
479             : (last_src == MODEM_CLOCK_LPCLK_SRC_RC32K)     ? ESP_PD_DOMAIN_RC32K   \
480             : (last_src == MODEM_CLOCK_LPCLK_SRC_XTAL32K)   ? ESP_PD_DOMAIN_XTAL32K \
481             : ESP_PD_DOMAIN_MAX);
482     esp_sleep_pd_config(pd_domain, ESP_PD_OPTION_OFF);
483 }
484