1 /*
2  * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 #include "sdkconfig.h"
9 #include "esp_log.h"
10 #include "esp_timer.h"
11 #include "esp_phy_init.h"
12 #include "esp_private/phy.h"
13 
14 #include <zephyr/kernel.h>
15 #if CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP
16 #include "hal/temperature_sensor_ll.h"
17 #endif
18 
19 static volatile uint16_t s_phy_modem_flag = 0;
20 
21 extern void phy_param_track_tot(bool en_wifi, bool en_ble_154);
22 static esp_timer_handle_t phy_track_pll_timer;
23 #if CONFIG_ESP_WIFI_ENABLED
24 static volatile int64_t s_wifi_prev_timestamp;
25 #endif
26 #if CONFIG_IEEE802154_ENABLED || CONFIG_BT_ENABLED
27 static volatile int64_t s_bt_154_prev_timestamp;
28 #endif
29 #define PHY_TRACK_PLL_PERIOD_IN_US 1000000
30 static void phy_track_pll_internal(void);
31 
32 #if CONFIG_IEEE802154_ENABLED || CONFIG_BT_ENABLED || CONFIG_ESP_WIFI_ENABLED
phy_enabled_modem_contains(esp_phy_modem_t modem)33 bool phy_enabled_modem_contains(esp_phy_modem_t modem)
34 {
35     return (s_phy_modem_flag & modem) != 0;
36 }
37 #endif
38 
phy_track_pll(void)39 void phy_track_pll(void)
40 {
41     // Light sleep scenario: enabling and disabling PHY frequently, the timer will not get triggered.
42     // Using a variable to record the previously tracked time when PLL was last called.
43     // If the duration is larger than PHY_TRACK_PLL_PERIOD_IN_US, then track PLL.
44     bool need_track_pll = false;
45 #if CONFIG_ESP_WIFI_ENABLED
46     if (phy_enabled_modem_contains(PHY_MODEM_WIFI)) {
47         need_track_pll = need_track_pll || ((esp_timer_get_time() - s_wifi_prev_timestamp) > PHY_TRACK_PLL_PERIOD_IN_US);
48     }
49 #endif
50 #if CONFIG_IEEE802154_ENABLED || CONFIG_BT_ENABLED
51     if (phy_enabled_modem_contains(PHY_MODEM_BT | PHY_MODEM_IEEE802154)) {
52         need_track_pll = need_track_pll || ((esp_timer_get_time() - s_bt_154_prev_timestamp) > PHY_TRACK_PLL_PERIOD_IN_US);
53     }
54 #endif
55     if (need_track_pll) {
56         phy_track_pll_internal();
57     }
58 }
59 
phy_track_pll_internal(void)60 static void phy_track_pll_internal(void)
61 {
62     bool wifi_track_pll = false;
63     bool ble_154_track_pll = false;
64 #if CONFIG_ESP_WIFI_ENABLED
65     if (phy_enabled_modem_contains(PHY_MODEM_WIFI)) {
66         wifi_track_pll = true;
67         s_wifi_prev_timestamp = esp_timer_get_time();
68     }
69 #endif
70 
71 #if CONFIG_IEEE802154_ENABLED || CONFIG_BT_ENABLED
72     if (phy_enabled_modem_contains(PHY_MODEM_BT | PHY_MODEM_IEEE802154)) {
73         ble_154_track_pll = true;
74         s_bt_154_prev_timestamp = esp_timer_get_time();
75     }
76 #endif
77     if (wifi_track_pll || ble_154_track_pll) {
78 #if CONFIG_ESP_PHY_PLL_TRACK_DEBUG
79 #if CONFIG_IEEE802154_ENABLED || CONFIG_BT_ENABLED
80         ESP_LOGI("PLL_TRACK", "BT or IEEE802154 tracks PLL: %s", ble_154_track_pll ? "True" : "False");
81 #endif
82 #if CONFIG_ESP_WIFI_ENABLED
83         ESP_LOGI("PLL_TRACK", "Wi-Fi tracks PLL: %s", wifi_track_pll ? "True" : "False");
84 #endif
85 #endif
86         phy_param_track_tot(wifi_track_pll, ble_154_track_pll);
87     }
88 }
89 
phy_track_pll_timer_callback(void * arg)90 static void phy_track_pll_timer_callback(void* arg)
91 {
92     struct k_mutex *phy_lock = phy_get_lock();
93     k_mutex_lock(phy_lock, K_FOREVER);
94     phy_track_pll_internal();
95     k_mutex_unlock(phy_lock);
96 }
97 
phy_track_pll_init(void)98 void phy_track_pll_init(void)
99 {
100     const esp_timer_create_args_t phy_track_pll_timer_args = {
101             .callback = &phy_track_pll_timer_callback,
102             .name = "phy-track-pll-timer"
103     };
104     ESP_ERROR_CHECK(esp_timer_create(&phy_track_pll_timer_args, &phy_track_pll_timer));
105     ESP_ERROR_CHECK(esp_timer_start_periodic(phy_track_pll_timer, PHY_TRACK_PLL_PERIOD_IN_US));
106 }
107 
phy_track_pll_deinit(void)108 void phy_track_pll_deinit(void)
109 {
110     ESP_ERROR_CHECK(esp_timer_stop(phy_track_pll_timer));
111     ESP_ERROR_CHECK(esp_timer_delete(phy_track_pll_timer));
112 }
113 
phy_set_modem_flag(esp_phy_modem_t modem)114 void phy_set_modem_flag(esp_phy_modem_t modem)
115 {
116     s_phy_modem_flag |= modem;
117 }
118 
phy_clr_modem_flag(esp_phy_modem_t modem)119 void phy_clr_modem_flag(esp_phy_modem_t modem)
120 {
121     s_phy_modem_flag &= ~modem;
122 }
123 
phy_get_modem_flag(void)124 esp_phy_modem_t phy_get_modem_flag(void)
125 {
126     return s_phy_modem_flag;
127 }
128 
129 #if CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP
phy_wakeup_from_modem_state_extra_init(void)130 void phy_wakeup_from_modem_state_extra_init(void)
131 {
132     temperature_sensor_ll_enable(true);
133 }
134 #endif
135