modem_clock.c 17 KB

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