1 /*
2 * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8
9 #include "clk_ctrl_os.h"
10 #include "soc/rtc.h"
11 #include "esp_private/esp_clk_tree_common.h"
12 #include "esp_check.h"
13
14 static int periph_spinlock;
15
16 #define ENTER_CRITICAL_SECTION() do { periph_spinlock = irq_lock(); } while(0)
17 #define LEAVE_CRITICAL_SECTION() irq_unlock(periph_spinlock);
18
19 static uint8_t s_periph_ref_counts = 0;
20 static uint32_t s_rc_fast_freq = 0; // Frequency of the RC_FAST clock in Hz
21 #if SOC_CLK_APLL_SUPPORTED
22 static const char *TAG = "clk_ctrl_os";
23 // Current APLL frequency, in HZ. Zero if APLL is not enabled.
24 static uint32_t s_cur_apll_freq = 0;
25 static int s_apll_ref_cnt = 0;
26 #endif
27
28
periph_rtc_dig_clk8m_enable(void)29 bool periph_rtc_dig_clk8m_enable(void)
30 {
31 ENTER_CRITICAL_SECTION();
32 if (s_periph_ref_counts == 0) {
33 rtc_dig_clk8m_enable();
34 #if SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
35 s_rc_fast_freq = esp_clk_tree_rc_fast_get_freq_hz(ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT);
36 if (s_rc_fast_freq == 0) {
37 rtc_dig_clk8m_disable();
38 LEAVE_CRITICAL_SECTION();
39 return false;
40 }
41 #endif //SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
42 }
43 s_periph_ref_counts++;
44 LEAVE_CRITICAL_SECTION();
45 return true;
46 }
47
periph_rtc_dig_clk8m_get_freq(void)48 uint32_t periph_rtc_dig_clk8m_get_freq(void)
49 {
50 #if !SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
51 /* Workaround: CLK8M calibration cannot be performed, we can only return its theoretic value */
52 return SOC_CLK_RC_FAST_FREQ_APPROX;
53 #else
54 return s_rc_fast_freq;
55 #endif
56 }
57
periph_rtc_dig_clk8m_disable(void)58 void periph_rtc_dig_clk8m_disable(void)
59 {
60 ENTER_CRITICAL_SECTION();
61 assert(s_periph_ref_counts > 0);
62 s_periph_ref_counts--;
63 if (s_periph_ref_counts == 0) {
64 s_rc_fast_freq = 0;
65 rtc_dig_clk8m_disable();
66 }
67 LEAVE_CRITICAL_SECTION();
68 }
69
70 #if SOC_CLK_APLL_SUPPORTED
periph_rtc_apll_acquire(void)71 void periph_rtc_apll_acquire(void)
72 {
73 ENTER_CRITICAL_SECTION();
74 s_apll_ref_cnt++;
75 if (s_apll_ref_cnt == 1) {
76 // For the first time enable APLL, need to set power up
77 rtc_clk_apll_enable(true);
78 }
79 LEAVE_CRITICAL_SECTION();
80 }
81
periph_rtc_apll_release(void)82 void periph_rtc_apll_release(void)
83 {
84 ENTER_CRITICAL_SECTION();
85 assert(s_apll_ref_cnt > 0);
86 s_apll_ref_cnt--;
87 if (s_apll_ref_cnt == 0) {
88 // If there is no peripheral using APLL, shut down the power
89 s_cur_apll_freq = 0;
90 rtc_clk_apll_enable(false);
91 }
92 LEAVE_CRITICAL_SECTION();
93 }
94
periph_rtc_apll_freq_set(uint32_t expt_freq,uint32_t * real_freq)95 esp_err_t periph_rtc_apll_freq_set(uint32_t expt_freq, uint32_t *real_freq)
96 {
97 uint32_t o_div = 0;
98 uint32_t sdm0 = 0;
99 uint32_t sdm1 = 0;
100 uint32_t sdm2 = 0;
101 // Guarantee 'periph_rtc_apll_acquire' has been called before set apll freq
102 assert(s_apll_ref_cnt > 0);
103 uint32_t apll_freq = rtc_clk_apll_coeff_calc(expt_freq, &o_div, &sdm0, &sdm1, &sdm2);
104
105 ESP_RETURN_ON_FALSE(apll_freq, ESP_ERR_INVALID_ARG, TAG, "APLL coefficients calculate failed");
106 bool need_config = true;
107 ENTER_CRITICAL_SECTION();
108 /* If APLL is not in use or only one peripheral in use, its frequency can be changed as will
109 * But when more than one peripheral refers APLL, its frequency is not allowed to change once it is set */
110 if (s_cur_apll_freq == 0 || s_apll_ref_cnt < 2) {
111 s_cur_apll_freq = apll_freq;
112 } else {
113 apll_freq = s_cur_apll_freq;
114 need_config = false;
115 }
116 LEAVE_CRITICAL_SECTION();
117 *real_freq = apll_freq;
118
119 if (need_config) {
120 ESP_LOGD(TAG, "APLL will working at %d Hz with coefficients [sdm0] %d [sdm1] %d [sdm2] %d [o_div] %d",
121 apll_freq, sdm0, sdm1, sdm2, o_div);
122 /* Set coefficients for APLL, notice that it doesn't mean APLL will start */
123 rtc_clk_apll_coeff_set(o_div, sdm0, sdm1, sdm2);
124 } else {
125 return ESP_ERR_INVALID_STATE;
126 }
127
128 return ESP_OK;
129 }
130 #endif // SOC_CLK_APLL_SUPPORTED
131