1 /******************************************************************************
2 * Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
3 * All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *****************************************************************************/
18 #include "clock.h"
19 #include "mspi.h"
20 #include "stimer.h"
21 #include "sys.h"
22
23 /**********************************************************************************************************************
24 * local constants *
25 *********************************************************************************************************************/
26
27 /**********************************************************************************************************************
28 * local macro *
29 *********************************************************************************************************************/
30
31 /**********************************************************************************************************************
32 * local data type *
33 *********************************************************************************************************************/
34
35 /**********************************************************************************************************************
36 * global variable *
37 *********************************************************************************************************************/
38 sys_clk_t sys_clk = {
39 .pll_clk = 192,
40 .cclk = 24,
41 .hclk = 24,
42 .pclk = 24,
43 .mspi_clk = 24,
44 };
45 _attribute_data_retention_sec_ unsigned char tl_24mrc_cal;
46 clk_32k_type_e g_clk_32k_src;
47 /**********************************************************************************************************************
48 * local variable *
49 *********************************************************************************************************************/
50
51 /**********************************************************************************************************************
52 * local function prototype *
53 *********************************************************************************************************************/
54
55 /**********************************************************************************************************************
56 * global function implementation *
57 *********************************************************************************************************************/
58
59 /**
60 * @brief This function serves to set 32k clock source.
61 * @param[in] src - variable of 32k type.
62 * @return none.
63 */
clock_32k_init(clk_32k_type_e src)64 void clock_32k_init(clk_32k_type_e src)
65 {
66 unsigned char sel_32k = analog_read_reg8(0x4e) & 0x7f;
67 unsigned char power_32k = analog_read_reg8(0x05) & 0xfc;
68 analog_write_reg8(0x4e, sel_32k | (src << 7));
69 if (src) {
70 analog_write_reg8(0x05, power_32k | 0x1); // 32k xtal
71 } else {
72 analog_write_reg8(0x05, power_32k | 0x2); // 32k rc
73 }
74 g_clk_32k_src = src;
75 }
76
77 /**
78 * @brief This function serves to kick 32k xtal.
79 * @param[in] xtal_times - kick times.
80 * @return 1 success, 0 error.
81 */
clock_kick_32k_xtal(unsigned char xtal_times)82 unsigned char clock_kick_32k_xtal(unsigned char xtal_times)
83 {
84 int last_32k_tick;
85 int curr_32k_tick;
86 for (unsigned char i = 0; i < xtal_times; i++) {
87 if (0xff == g_chip_version) {
88 delay_ms(1000);
89 } else { // **Note that the clock is 24M crystal oscillator. PCLK is 24MHZ
90 // 2.set PD0 as pwm output
91 unsigned char pwm_clk = read_reg8(0x1401d8); // **condition: PCLK is 24MHZ,PCLK = HCLK
92 write_reg8(0x1401d8, ((pwm_clk & 0xfc) | 0x01)); // PCLK = 12M
93 unsigned char reg_31e = read_reg8(0x14031e); // PD0
94 write_reg8(0x14031e, reg_31e & 0xfe);
95 unsigned short reg_418 = read_reg16(0x140418); // pwm1 cmp
96 write_reg16(0x140418, 0x01);
97 unsigned short reg_41a = read_reg16(0x14041a); // pwm1 max
98 write_reg16(0x14041a, 0x02);
99 unsigned char reg_400 = read_reg8(0x140400); // pwm en
100 write_reg8(0x140400, 0x02);
101 write_reg8(0x140402, 0xb6); // 12M/(0xb6 + 1)/2 = 32k
102
103 // 3.wait for PWM wake up Xtal
104 delay_ms(100);
105
106 // 4.Xtal 32k output
107 analog_write_reg8(0x03, 0x4f); // <7:6>current select
108
109 // 5.Recover PD0 as Xtal pin
110 write_reg8(0x1401d8, pwm_clk);
111 write_reg8(0x14031e, reg_31e);
112 write_reg16(0x140418, reg_418);
113 write_reg16(0x14041a, reg_41a);
114 write_reg8(0x140400, reg_400);
115 }
116
117 last_32k_tick = clock_get_32k_tick(); // clock_get_32k_tick()
118 delay_us(305); // for 32k tick accumulator, tick period: 30.5us, dly 10 ticks
119 curr_32k_tick = clock_get_32k_tick();
120 if (last_32k_tick != curr_32k_tick) { // clock_get_32k_tick()
121 return 1; // pwm kick 32k pad success
122 }
123 }
124 return 0;
125 }
126
127 /**
128 * @brief This function performs to select 24M as the system clock source.
129 * 24M RC is inaccurate, and it is greatly affected by temperature, if need use it so real-time calibration
130 * is required
131 * The 24M RC needs to be calibrated before the pm_sleep_wakeup function,
132 * because this clock will be used to kick 24m xtal start after wake up,
133 * The more accurate this time, the faster the crystal will start.Calibration cycle depends on usage
134 * @return none.
135 */
clock_cal_24m_rc(void)136 void clock_cal_24m_rc(void)
137 {
138 analog_write_reg8(0xc8, 0x80);
139
140 analog_write_reg8(0x4f, analog_read_reg8(0x4f) | BIT(7));
141
142 analog_write_reg8(0xc7, 0x0e);
143 analog_write_reg8(0xc7, 0x0f);
144 while ((analog_read_reg8(0xcf) & 0x80) == 0) {
145 }
146 unsigned char cap = analog_read_reg8(0xcb);
147 analog_write_reg8(0x52, cap); // write 24m cap into manual register
148
149 analog_write_reg8(0x4f, analog_read_reg8(0x4f) & (~BIT(7)));
150
151 analog_write_reg8(0xc7, 0x0e);
152 tl_24mrc_cal = analog_read_reg8(0x52);
153 }
154
155 /**
156 * @brief This function performs to select 32K as the system clock source.
157 * @return none.
158 */
clock_cal_32k_rc(void)159 void clock_cal_32k_rc(void)
160 {
161 analog_write_reg8(0x4f, ((analog_read_reg8(0x4f) & 0x3f) | 0x40));
162 analog_write_reg8(0xc6, 0xf6);
163 analog_write_reg8(0xc6, 0xf7);
164 while ((analog_read_reg8(0xcf) & BIT(6)) == 0) {
165 }
166 unsigned char res1 = analog_read_reg8(0xc9); // read 32k res[13:6]
167 analog_write_reg8(0x51, res1); // write 32k res[13:6] into manual register
168 unsigned char res2 = analog_read_reg8(0xca); // read 32k res[5:0]
169 analog_write_reg8(0x4f, (res2 | (analog_read_reg8(0x4f) & 0xc0))); // write 32k res[5:0] into manual register
170 analog_write_reg8(0xc6, 0xf6);
171 analog_write_reg8(0x4f, ((analog_read_reg8(0x4f) & 0x3f) | 0x00)); // manual on
172 }
173
174 /**
175 * @brief This function serves to set the 32k tick.
176 * @param tick - the value of to be set to 32k.
177 * @return none.
178 */
clock_set_32k_tick(unsigned int tick)179 void clock_set_32k_tick(unsigned int tick)
180 {
181 reg_system_ctrl |= FLD_SYSTEM_32K_WR_EN; // r_32k_wr = 1;
182 while (reg_system_st & FLD_SYSTEM_RD_BUSY) {
183 }
184 reg_system_timer_set_32k = tick;
185
186 reg_system_st = FLD_SYSTEM_CMD_SYNC; // cmd_sync = 1,trig write
187 // delay 10us
188 __asm__("nop");
189 __asm__("nop");
190 __asm__("nop");
191 __asm__("nop");
192 __asm__("nop");
193 __asm__("nop");
194 __asm__("nop");
195 __asm__("nop");
196 __asm__("nop");
197 __asm__("nop");
198 __asm__("nop");
199 __asm__("nop");
200 __asm__("nop");
201 __asm__("nop");
202 __asm__("nop");
203 __asm__("nop");
204 while (reg_system_st & FLD_SYSTEM_CMD_SYNC) {
205 } // wait wr_busy = 0
206 }
207
208 /**
209 * @brief This function serves to get the 32k tick.
210 * @return none.
211 */
clock_get_32k_tick(void)212 unsigned int clock_get_32k_tick(void)
213 {
214 unsigned int timer_32k_tick;
215 reg_system_st = FLD_SYSTEM_CLR_RD_DONE; // clr rd_done
216 while ((reg_system_st & FLD_SYSTEM_CLR_RD_DONE) != 0) {
217 }
218 reg_system_ctrl &= ~FLD_SYSTEM_32K_WR_EN; // 1:32k write mode; 0:32k read mode
219 while ((reg_system_st & FLD_SYSTEM_CLR_RD_DONE) == 0) {
220 }
221 timer_32k_tick = reg_system_timer_read_32k;
222 reg_system_ctrl |= FLD_SYSTEM_32K_WR_EN; // 1:32k write mode; 0:32k read mode
223 return timer_32k_tick;
224 }
225
226 /**
227 * @brief This function use to select the system clock source.
228 * @param[in] pll - pll clock.
229 * @param[in] src - cclk source.
230 * @param[in] cclk_div - the cclk divide from pll.it is useless if src is not PAD_PLL_DIV. cclk max is 96M
231 * @param[in] hclk_div - the hclk divide from cclk.hclk max is 48M.
232 * @param[in] pclk_div - the pclk divide from hclk.pclk max is 24M.if hclk = 1/2 * cclk,
233 * the pclk can not be 1/4 of hclk.
234 * @param[in] mspi_clk_div - mspi_clk has two source. pll div and hclk.mspi max is 64M.
235 * @return none
236 */
clock_init(sys_pll_clk_e pll,sys_clock_src_e src,sys_pll_div_to_cclk_e cclk_div,sys_cclk_div_to_hclk_e hclk_div,sys_hclk_div_to_pclk_e pclk_div,sys_pll_div_to_mspi_clk_e mspi_clk_div)237 void clock_init(sys_pll_clk_e pll, sys_clock_src_e src, sys_pll_div_to_cclk_e cclk_div,
238 sys_cclk_div_to_hclk_e hclk_div, sys_hclk_div_to_pclk_e pclk_div,
239 sys_pll_div_to_mspi_clk_e mspi_clk_div)
240 {
241 // pll clk
242 analog_write_reg8(0x80, (analog_read_reg8(0x80) & 0xe0) | ((pll >> 2) & 0x1f));
243 analog_write_reg8(0x09, (analog_read_reg8(0x09) & 0xf3) | ((pll & 0x03) << 2));
244 sys_clk.pll_clk = (pll >> 8);
245
246 // usb clock (192M/4 =48M) pll clock should be the multiple of 48, because USB clock is 48M.
247 write_reg8(0x1401fb, sys_clk.pll_clk / 48);
248
249 // wait for PLL stable
250 analog_write_reg8(0x81, (analog_read_reg8(0x81) | BIT(6)));
251 while (BIT(5) != (analog_read_reg8(0x88) & BIT(5))) {
252 }
253 analog_write_reg8(0x81, (analog_read_reg8(0x81) & ~BIT(6)));
254
255 // ensure mspi is not in busy status before change mspi clock
256 mspi_stop_xip();
257
258 // change mspi clock should be ram code.
259 if (CCLK_TO_MSPI_CLK == mspi_clk_div) {
260 write_reg8(0x1401e8, read_reg8(0x1401e8) & 0x7f); // bit7 0
261 } else {
262 write_reg8(0x1401e9, (read_reg8(0x1401e9) & 0x0f) | (mspi_clk_div << 4));
263 write_reg8(0x1401e8, read_reg8(0x1401e8) |
264 BIT(7)); // if the div is odd, should set two times to ensure the correct sequence.
265 write_reg8(0x1401e8, read_reg8(0x1401e8) | BIT(7));
266 sys_clk.mspi_clk = sys_clk.pll_clk / mspi_clk_div;
267 }
268
269 /*
270 * hclk and pclk should be set ahead of cclk, ensure the hclk and pclk not exceed the max clk
271 * (cclk max 96M, hclk max 48M, pclk max 24M)
272 */
273 if (CCLK_DIV1_TO_HCLK == hclk_div) {
274 write_reg8(0x1401d8, read_reg8(0x1401d8) & ~BIT(2));
275 } else {
276 write_reg8(0x1401d8, read_reg8(0x1401d8) | BIT(2));
277 }
278
279 // pclk can div1/div2/div4 from hclk.
280 if (HCLK_DIV1_TO_PCLK == pclk_div) {
281 write_reg8(0x1401d8, read_reg8(0x1401d8) & 0xfc);
282 } else {
283 write_reg8(0x1401d8, (read_reg8(0x1401d8) & 0xfc) | (pclk_div / 2));
284 }
285
286 // select cclk source(RC24M/PAD24M/PAD_PLL_DIV/PAD_PLL)
287 if (PAD_PLL_DIV == src) {
288 write_reg8(0x1401e8, (read_reg8(0x1401e8) & 0xf0) | cclk_div);
289 sys_clk.cclk = sys_clk.pll_clk / cclk_div;
290 } else if (PAD_PLL == src) {
291 sys_clk.cclk = sys_clk.pll_clk;
292 } else {
293 sys_clk.cclk = 24;
294 }
295 write_reg8(0x1401e8, (read_reg8(0x1401e8) & 0x8f) | (src << 4));
296
297 // clk record.
298 sys_clk.hclk = sys_clk.cclk / hclk_div;
299 sys_clk.pclk = sys_clk.hclk / pclk_div;
300 if (CCLK_TO_MSPI_CLK == mspi_clk_div) {
301 sys_clk.mspi_clk = sys_clk.cclk;
302 }
303 }
304
305 /**********************************************************************************************************************
306 * local function implementation *
307 *********************************************************************************************************************/
308