1 /*
2  * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * ADC is shared by multiple components, including:
9  * - esp_phy
10  * - esp_wifi
11  * - driver
12  *
13  * However, usages of above components are different.
14  * Therefore, we put the common used parts into `esp_hw_support`, including:
15  * - adc power maintainance
16  * - adc hw calibration settings
17  * - adc locks, to prevent concurrently using adc hw
18  */
19 
20 #include <zephyr/kernel.h>
21 #include <zephyr/logging/log.h>
22 
23 #include <esp_types.h>
24 #include "sdkconfig.h"
25 #include "sys/lock.h"
26 #include "esp_log.h"
27 #include "esp_check.h"
28 #include "hal/adc_types.h"
29 #include "hal/adc_hal.h"
30 #include "hal/adc_hal_common.h"
31 #include "esp_private/adc_share_hw_ctrl.h"
32 #include "esp_private/sar_periph_ctrl.h"
33 #include "esp_private/periph_ctrl.h"
34 #include "soc/periph_defs.h"
35 //For calibration
36 #if CONFIG_IDF_TARGET_ESP32S2
37 #include "esp_efuse_rtc_table.h"
38 #elif SOC_ADC_CALIBRATION_V1_SUPPORTED
39 #include "esp_efuse_rtc_calib.h"
40 #endif
41 
42 
43 static const char *TAG = "adc_share_hw_ctrl";
44 
45 extern int rtc_spinlock;
46 
47 #define RTC_ENTER_CRITICAL()    do { rtc_spinlock = irq_lock(); } while(0)
48 #define RTC_EXIT_CRITICAL()    irq_unlock(rtc_spinlock);
49 
50 #if SOC_ADC_CALIBRATION_V1_SUPPORTED
51 /*---------------------------------------------------------------
52             ADC Hardware Calibration
53 ---------------------------------------------------------------*/
54 #if CONFIG_IDF_TARGET_ESP32S2
55 #define esp_efuse_rtc_calib_get_ver()     esp_efuse_rtc_table_read_calib_version()
56 
esp_efuse_rtc_calib_get_init_code(int version,uint32_t adc_unit,int atten)57 static inline uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int atten)
58 {
59     int tag = esp_efuse_rtc_table_get_tag(version, adc_unit, atten, RTCCALIB_V2_PARAM_VINIT);
60     return esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
61 }
62 #endif
63 
64 static uint32_t s_adc_cali_param[SOC_ADC_PERIPH_NUM][SOC_ADC_ATTEN_NUM] = {};
65 
adc_calc_hw_calibration_code(adc_unit_t adc_n,adc_atten_t atten)66 void adc_calc_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten)
67 {
68     if (s_adc_cali_param[adc_n][atten]) {
69         ESP_EARLY_LOGV(TAG, "Use calibrated val ADC%d atten=%d: %04X", adc_n + 1, atten, s_adc_cali_param[adc_n][atten]);
70         return ;
71     }
72 
73     // check if we can fetch the values from eFuse.
74     int version = esp_efuse_rtc_calib_get_ver();
75 
76     uint32_t init_code = 0;
77 
78     if ((version >= ESP_EFUSE_ADC_CALIB_VER_MIN) &&
79         (version <= ESP_EFUSE_ADC_CALIB_VER_MAX)) {
80         // Guarantee the calibration version before calling efuse function
81         init_code = esp_efuse_rtc_calib_get_init_code(version, adc_n, atten);
82     }
83 #if SOC_ADC_SELF_HW_CALI_SUPPORTED
84     else {
85         ESP_EARLY_LOGD(TAG, "Calibration eFuse is not configured, use self-calibration for ICode");
86         sar_periph_ctrl_adc_oneshot_power_acquire();
87         RTC_ENTER_CRITICAL();
88         adc_ll_pwdet_set_cct(ADC_LL_PWDET_CCT_DEFAULT);
89         const bool internal_gnd = true;
90         init_code = adc_hal_self_calibration(adc_n, atten, internal_gnd);
91         RTC_EXIT_CRITICAL();
92         sar_periph_ctrl_adc_oneshot_power_release();
93     }
94 #else
95     else {
96         ESP_EARLY_LOGD(TAG, "ICode self-calibration isn't supported");
97     }
98 #endif  //SOC_ADC_SELF_HW_CALI_SUPPORTED
99 
100     s_adc_cali_param[adc_n][atten] = init_code;
101     ESP_EARLY_LOGV(TAG, "Calib(V%d) ADC%d atten=%d: %04X", version, adc_n + 1, atten, init_code);
102 }
103 
adc_set_hw_calibration_code(adc_unit_t adc_n,adc_atten_t atten)104 void IRAM_ATTR adc_set_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten)
105 {
106     adc_hal_set_calibration_param(adc_n, s_adc_cali_param[adc_n][atten]);
107 }
108 
109 #if SOC_ADC_CALIB_CHAN_COMPENS_SUPPORTED
110 static int s_adc_cali_chan_compens[SOC_ADC_MAX_CHANNEL_NUM][SOC_ADC_ATTEN_NUM] = {};
adc_load_hw_calibration_chan_compens(adc_unit_t adc_n,adc_channel_t chan,adc_atten_t atten)111 void adc_load_hw_calibration_chan_compens(adc_unit_t adc_n, adc_channel_t chan, adc_atten_t atten)
112 {
113     int version = esp_efuse_rtc_calib_get_ver();
114     if ((version >= ESP_EFUSE_ADC_CALIB_VER_MIN) &&
115         (version <= ESP_EFUSE_ADC_CALIB_VER_MAX)) {
116         // Guarantee the calibration version before calling efuse function
117         s_adc_cali_chan_compens[chan][atten] = esp_efuse_rtc_calib_get_chan_compens(version, adc_n, chan, atten);
118     }
119     // No warning when version doesn't match because should has warned in adc_calc_hw_calibration_code
120 }
121 
adc_get_hw_calibration_chan_compens(adc_unit_t adc_n,adc_channel_t chan,adc_atten_t atten)122 int IRAM_ATTR adc_get_hw_calibration_chan_compens(adc_unit_t adc_n, adc_channel_t chan, adc_atten_t atten)
123 {
124     return s_adc_cali_chan_compens[chan][atten];
125 }
126 #endif  // SOC_ADC_CALIB_CHAN_COMPENS_SUPPORTED
127 #endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED
128 
129 /*---------------------------------------------------------------
130             ADC Hardware Locks
131 ---------------------------------------------------------------*/
132 K_MUTEX_DEFINE(adc1_lock);
133 K_MUTEX_DEFINE(adc2_lock);
134 
135 #define ADC_LOCK_ACQUIRE(lock) do { k_mutex_lock(lock, K_FOREVER); } while(0)
136 #define ADC_LOCK_RELEASE(lock) do { k_mutex_unlock(lock); } while(0)
137 #define ADC_LOCK_TRY_ACQUIRE(lock) k_mutex_lock(lock, K_NO_WAIT)
138 
adc_lock_acquire(adc_unit_t adc_unit)139 esp_err_t adc_lock_acquire(adc_unit_t adc_unit)
140 {
141     if (adc_unit == ADC_UNIT_1) {
142         ADC_LOCK_ACQUIRE(&adc1_lock);
143     }
144 
145     if (adc_unit == ADC_UNIT_2) {
146         ADC_LOCK_ACQUIRE(&adc2_lock);
147     }
148 
149     return ESP_OK;
150 }
151 
adc_lock_release(adc_unit_t adc_unit)152 esp_err_t adc_lock_release(adc_unit_t adc_unit)
153 {
154     if (adc_unit == ADC_UNIT_2) {
155         ESP_RETURN_ON_FALSE((adc2_lock.lock_count != 0), ESP_ERR_INVALID_STATE, TAG, "adc2 lock release without acquiring");
156         ADC_LOCK_RELEASE(&adc2_lock);
157     }
158 
159     if (adc_unit == ADC_UNIT_1) {
160         ESP_RETURN_ON_FALSE((adc1_lock.lock_count != 0), ESP_ERR_INVALID_STATE, TAG, "adc2 lock release without acquiring");
161         ADC_LOCK_RELEASE(&adc1_lock);
162     }
163 
164     return ESP_OK;
165 }
166 
adc_lock_try_acquire(adc_unit_t adc_unit)167 esp_err_t adc_lock_try_acquire(adc_unit_t adc_unit)
168 {
169     if (adc_unit == ADC_UNIT_1) {
170         if (ADC_LOCK_TRY_ACQUIRE(&adc1_lock) == -1) {
171             return ESP_ERR_TIMEOUT;
172         }
173     }
174 
175     if (adc_unit == ADC_UNIT_2) {
176         if (ADC_LOCK_TRY_ACQUIRE(&adc2_lock) == -1) {
177             return ESP_ERR_TIMEOUT;
178         }
179     }
180 
181     return ESP_OK;
182 }
183 
adc2_wifi_acquire(void)184 esp_err_t adc2_wifi_acquire(void)
185 {
186 #if CONFIG_IDF_TARGET_ESP32
187     /* Wi-Fi module will use adc2. Use locks to avoid conflicts. */
188     adc_lock_acquire(ADC_UNIT_2);
189     ESP_LOGD(TAG, "Wi-Fi takes adc2 lock.");
190 #endif
191 
192     return ESP_OK;
193 }
194 
adc2_wifi_release(void)195 esp_err_t adc2_wifi_release(void)
196 {
197 #if CONFIG_IDF_TARGET_ESP32
198     return adc_lock_release(ADC_UNIT_2);
199 #endif
200 
201     return ESP_OK;
202 }
203 
204 static unsigned int s_spinlock = 0;
205 
206 /*------------------------------------------------------------------------------
207 * For those who use APB_SARADC periph
208 *----------------------------------------------------------------------------*/
209 static int s_adc_digi_ctrlr_cnt;
210 
adc_apb_periph_claim(void)211 void adc_apb_periph_claim(void)
212 {
213     s_spinlock = irq_lock();
214     s_adc_digi_ctrlr_cnt++;
215     if (s_adc_digi_ctrlr_cnt == 1) {
216         //enable ADC digital part
217         periph_module_enable(PERIPH_SARADC_MODULE);
218         //reset ADC digital part
219         periph_module_reset(PERIPH_SARADC_MODULE);
220     }
221 
222     irq_unlock(s_spinlock);
223 }
224 
adc_apb_periph_free(void)225 void adc_apb_periph_free(void)
226 {
227     s_spinlock = irq_lock();
228     s_adc_digi_ctrlr_cnt--;
229     if (s_adc_digi_ctrlr_cnt == 0) {
230         periph_module_disable(PERIPH_SARADC_MODULE);
231     } else if (s_adc_digi_ctrlr_cnt < 0) {
232         irq_unlock(s_spinlock);
233         ESP_LOGE(TAG, "%s called, but `s_adc_digi_ctrlr_cnt == 0`", __func__);
234         abort();
235     }
236 
237     irq_unlock(s_spinlock);
238 }
239