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 
19 /********************************************************************************************************
20  * @file	pm.c
21  *
22  * @brief	This is the source file for B91
23  *
24  * @author	Driver Group
25  *
26  *******************************************************************************************************/
27 #include "pm.h"
28 #include "gpio.h"
29 #include "compiler.h"
30 #include "core.h"
31 #include "mspi.h"
32 #include "clock.h"
33 #include "flash.h"
34 #include "stimer.h"
35 
36 
37 _attribute_data_retention_sec_ _attribute_aligned_(4) pm_status_info_s g_pm_status_info;
38 
39 //system timer clock source is constant 16M, never change
40 //NOTICE:We think that the external 32k crystal clk is very accurate, does not need to read through TIMER_32K_LAT_CAL.
41 //register, the conversion error(use 32k:16 cycle, count 16M sys tmr's ticks), at least the introduction of 64ppm.
42 #define CRYSTAL32768_TICK_PER_32CYCLE		15625  // 7812.5 * 2
43 
44 _attribute_data_retention_sec_	unsigned int 		g_pm_tick_32k_calib;
45 _attribute_data_retention_sec_	unsigned int 		g_pm_tick_cur;
46 _attribute_data_retention_sec_	unsigned int 		g_pm_tick_32k_cur;
47 _attribute_data_retention_sec_  unsigned char       g_pm_long_suspend;
48 _attribute_data_retention_sec_  unsigned char       g_pm_vbat_v;
49 _attribute_data_retention_sec_  unsigned char       g_pm_tick_update_en;
50 _attribute_data_retention_sec_  unsigned char       g_pm_suspend_power_cfg=0x87;
51 _attribute_data_retention_sec_  unsigned int 		g_pm_multi_addr=0;
52 
53 _attribute_data_retention_sec_
54 volatile pm_early_wakeup_time_us_s g_pm_early_wakeup_time_us = {
55 	.suspend_early_wakeup_time_us = 100 + 188 + 109 + 200 + 225,	//188(r_delay) + 109(3.5*(1/32k)) + 200(XTAL_delay) + 225(code)
56 	.deep_ret_early_wakeup_time_us = 188 + 109,				//188(r_delay) + 109(3.5*(1/32k))
57 	.deep_early_wakeup_time_us = 688 + 259,					//688(r_delay) + 109(3.5*(1/32k)) + 150(boot_rom)
58 	.sleep_min_time_us = 100 + 688 + 259 + 200,					//(the maximum value of suspend and deep) + 200. 200 means more margin, >32 is enough.
59 };
60 
61 _attribute_data_retention_sec_
62 volatile pm_early_wakeup_time_us_s g_pm_longsleep_early_wakeup_time_us = {
63 	.suspend_early_wakeup_time_us = 23,
64 	.deep_ret_early_wakeup_time_us = 10 ,
65 	.deep_early_wakeup_time_us = 32 ,
66 	.sleep_min_time_us = 25,
67 
68 };
69 
70 _attribute_data_retention_sec_
71 volatile pm_r_delay_cycle_s g_pm_r_delay_cycle = {
72 
73 	.deep_r_delay_cycle = 3 + 8,	// 11 * (1/16k) = 687.5
74 	.suspend_ret_r_delay_cycle = 3,	// 2 * 1/16k = 125 uS, 3 * 1/16k = 187.5 uS  4*1/16k = 250 uS
75 };
76 
77 /**
78  * @brief		This function configures pm wakeup time parameter.
79  * @param[in]	param - pm wakeup time parameter.
80  * @return		none.
81  */
pm_set_wakeup_time_param(pm_r_delay_cycle_s param)82 void pm_set_wakeup_time_param(pm_r_delay_cycle_s param)
83 {
84 	g_pm_r_delay_cycle.deep_r_delay_cycle = param.deep_r_delay_cycle;
85 	g_pm_r_delay_cycle.suspend_ret_r_delay_cycle = param.suspend_ret_r_delay_cycle;
86 
87 	int deep_rx_delay_us = g_pm_r_delay_cycle.deep_r_delay_cycle *1000 /16;
88 	int suspend_ret_rx_delay_us = g_pm_r_delay_cycle.suspend_ret_r_delay_cycle *1000 /16;
89 	g_pm_early_wakeup_time_us.suspend_early_wakeup_time_us = suspend_ret_rx_delay_us + 120 + 200 + 220;
90 	g_pm_early_wakeup_time_us.deep_ret_early_wakeup_time_us = suspend_ret_rx_delay_us + 120 ;//64
91 	g_pm_early_wakeup_time_us.deep_early_wakeup_time_us = deep_rx_delay_us + 259;
92 	if(g_pm_early_wakeup_time_us.deep_early_wakeup_time_us < g_pm_early_wakeup_time_us.suspend_early_wakeup_time_us)
93 	{
94 		g_pm_early_wakeup_time_us.sleep_min_time_us = g_pm_early_wakeup_time_us.suspend_early_wakeup_time_us + 200;
95 	}
96 	else
97 	{
98 		g_pm_early_wakeup_time_us.sleep_min_time_us = g_pm_early_wakeup_time_us.deep_early_wakeup_time_us + 200;
99 	}
100 }
101 
102 /**
103  * @brief		This function serves to recover system timer.
104  * 				The code is placed in the ram code section, in order to shorten the time.
105  * @return		none.
106  */
pm_stimer_recover(void)107 void pm_stimer_recover(void)
108 {
109 #if SYS_TIMER_AUTO_MODE
110 	REG_ADDR8(0x140218) = 0x02;	//sys tick 16M set upon next 32k posedge
111 	reg_system_ctrl		|=(FLD_SYSTEM_TIMER_AUTO|FLD_SYSTEM_32K_TRACK_EN) ;
112 	unsigned int now_tick_32k = clock_get_32k_tick();
113 	if(g_pm_long_suspend){
114 		g_pm_tick_cur = pmcd.ref_tick + (unsigned int)(now_tick_32k + 1 - pmcd.ref_tick_32k) / 32 * g_pm_tick_32k_calib;
115 	}else{
116 		g_pm_tick_cur = pmcd.ref_tick + (unsigned int)(now_tick_32k + 1 - pmcd.ref_tick_32k) * g_pm_tick_32k_calib / 32;		// current clock
117 	}
118 	pmcd.rc32_wakeup = now_tick_32k + 1;
119 	pmcd.rc32 = now_tick_32k + 1 - pmcd.ref_tick_32k;
120 	reg_system_tick = g_pm_tick_cur + 1;
121 	//wait cmd set dly done upon next 32k posedge
122 	//if not using status bit, wait at least 1 32k cycle to set register r_run_upon_next_32k back to 0, or before next normal set
123 	while((reg_system_st & BIT(7)) == 0);	//system timer set done status upon next 32k posedge
124 	REG_ADDR8(0x140218) = 0;//normal sys tick (16/sys) update
125 #else
126 	unsigned int now_tick_32k = clock_get_32k_tick();
127 	if(g_pm_long_suspend){
128 		g_pm_tick_cur = pmcd.ref_tick + (unsigned int)(now_tick_32k - pmcd.ref_tick_32k) / 32 * g_pm_tick_32k_calib;
129 	}else{
130 		g_pm_tick_cur = pmcd.ref_tick + (unsigned int)(now_tick_32k - pmcd.ref_tick_32k) * g_pm_tick_32k_calib / 32;		// current clock
131 	}
132 	pmcd.rc32_wakeup = now_tick_32k;
133 	pmcd.rc32 = now_tick_32k - pmcd.ref_tick_32k;
134 	reg_system_tick = g_pm_tick_cur;
135 	reg_system_ctrl	|= FLD_SYSTEM_32K_TRACK_EN | FLD_SYSTEM_TIMER_EN;
136 #endif
137 }
138 
139 /**
140  * @brief		This function configures a GPIO pin as the wakeup pin.
141  * @param[in]	pin	- the pin needs to be configured as wakeup pin.
142  * @param[in]	pol - the wakeup polarity of the pad pin(0: low-level wakeup, 1: high-level wakeup).
143  * @param[in]	en  - enable or disable the wakeup function for the pan pin(1: enable, 0: disable).
144  * @return		none.
145  */
pm_set_gpio_wakeup(gpio_pin_e pin,pm_gpio_wakeup_level_e pol,int en)146 void pm_set_gpio_wakeup (gpio_pin_e pin, pm_gpio_wakeup_level_e pol, int en)
147 {
148 	///////////////////////////////////////////////////////////
149 	// 		  PA[7:0]	    	PB[7:0]			PC[7:0]			PD[7:0]  	PE[7:0]
150 	// en: 	ana_0x41<7:0>	 ana_0x42<7:0>  ana_0x43<7:0>  ana_0x44<7:0>  ana_0x45<7:0>
151 	// pol:	ana_0x46<7:0>	 ana_0x47<7:0>  ana_0x48<7:0>  ana_0x49<7:0>  ana_0x4a<7:0>
152     unsigned char mask = pin & 0xff;
153 	unsigned char areg;
154 	unsigned char val;
155 
156 	////////////////////////// polarity ////////////////////////
157 	areg = ((pin>>8) + 0x41);
158 	val = analog_read_reg8(areg);
159 	if (pol) {
160 		val &= ~mask;
161 	}
162 	else {
163 		val |= mask;
164 	}
165 	analog_write_reg8 (areg, val);
166 
167 	/////////////////////////// enable /////////////////////
168 	areg = ((pin>>8) + 0x46);
169 	val = analog_read_reg8(areg);
170 	if (en) {
171 		val |= mask;
172 	}
173 	else {
174 		val &= ~mask;
175 	}
176 	analog_write_reg8 (areg, val);
177 }
178 
179 /**
180  * @brief		this function servers to wait bbpll clock lock.
181  * @return		none.
182  */
pm_wait_bbpll_done(void)183 _attribute_ram_code_ void pm_wait_bbpll_done(void)
184 {
185 	unsigned char ana_81 = analog_read_reg8(0x81);
186 	analog_write_reg8(0x81, ana_81 | BIT(6));
187 	for(unsigned char j = 0; j < 3; j++)
188 	{
189 		for(volatile unsigned char i = 0; i < 30; i++){	//20us
190 			__asm__("nop");
191 		}
192 		if(BIT(5) == (analog_read_reg8(0x88) & BIT(5)))
193 		{
194 			analog_write_reg8(0x81, ana_81 & 0xbf);
195 			break;
196 		}
197 		else
198 		{
199 			if(j == 0){
200 				analog_write_reg8(0x01, 0x46);
201 			}
202 			else if(j == 1){
203 				analog_write_reg8(0x01, 0x43);
204 			}
205 			else{
206 				analog_write_reg8(0x81, ana_81 & 0xbf);
207 			}
208 		}
209 	}
210 }
211 
212 /**
213  * @brief		This function serves to update wakeup status.
214  * @return		none.
215  */
pm_update_status_info(void)216 void pm_update_status_info(void)
217 {
218 	unsigned char analog_38 = analog_read_reg8(PM_ANA_REG_WD_CLR_BUF0);
219 	unsigned char analog_39 = analog_read_reg8(PM_ANA_REG_POWER_ON_CLR_BUF0);
220 
221 	if(analog_38 & BIT(0)){
222 		if(analog_39 & BIT(0)){
223 			g_pm_status_info.mcu_status = MCU_STATUS_REBOOT_BACK;
224 			analog_write_reg8(PM_ANA_REG_WD_CLR_BUF0, analog_38 & 0xfe);
225 		}else{
226 			g_pm_status_info.mcu_status = MCU_STATUS_POWER_ON;
227 			analog_write_reg8(PM_ANA_REG_WD_CLR_BUF0,analog_38 & 0xfe);
228 			analog_write_reg8(PM_ANA_REG_POWER_ON_CLR_BUF0, analog_39 | BIT(0));
229 		}
230 	}else{
231 		if(pm_get_deep_retention_flag()){
232 			g_pm_status_info.mcu_status = MCU_STATUS_DEEPRET_BACK;
233 		}else if(analog_39 & BIT(1)){
234 			g_pm_status_info.mcu_status = MCU_STATUS_REBOOT_DEEP_BACK;
235 			analog_write_reg8(PM_ANA_REG_POWER_ON_CLR_BUF0, analog_39 & 0xfd);
236 		}else{
237 			g_pm_status_info.mcu_status = MCU_STATUS_DEEP_BACK;
238 		}
239 	}
240 	analog_write_reg8(0x7f, 0x01);
241 	g_pm_status_info.wakeup_src = pm_get_wakeup_src();
242 	g_pm_status_info.is_pad_wakeup = (g_pm_status_info.wakeup_src & BIT(3)) >> 3;
243 }
244 
245 /**
246  * @brief		this function srevers to start sleep mode.
247  * @return		none.
248  */
pm_sleep_start(void)249 _attribute_ram_code_sec_noinline_ void  pm_sleep_start(void)
250 {
251 	//This is 1.4V and 1.8V power supply during sleep. Do not power on during initialization, because after power on,
252 	//there will be two power supplies at the same time, which may cause abnormalities.add by weihua.zhang, confirmed by haitao 20210107
253 	analog_write_reg8(0x0b, analog_read_reg8(0x0b) & ~(BIT(0) | BIT(1)));	//<0>:pd_nvt_1p4,	power on native 1P4.
254 																			//<1>:pd_nvt_1p8,	power on native 1P8.
255 	//A0 chip cann't disable baseband,A1 need disable baseband.See sys_init for specific instructions.(add by weihua zhang, confirmed by junwen 20200925)
256 	if(0xff == g_chip_version){	//A0
257 		analog_write_reg8(0x7d, g_pm_suspend_power_cfg&0xfe);
258 	}else{
259 		analog_write_reg8(0x7d, g_pm_suspend_power_cfg);
260 	}
261 
262 	mspi_low();
263 	mspi_write(0xb9);	//flash deep
264 	mspi_wait();
265 	mspi_high();
266 	write_reg8(0x140329, 0x00);	//MSPI ie disable
267 	analog_write_reg8(0x81, analog_read_reg8(0x81) | BIT(7));
268 
269     write_reg8(0x1401ef,0x80);	//trig pwdn
270 
271     //After being triggered, the MCU needs to wait for a period of time before it actually goes to sleep,
272     //during which time the MCU will continue to execute code. If the following code is executed
273     //and some modules are awakened, the current will be larger than normal. About 20 empty instructions are fine,
274     //but to be on the safe side, add 64 empty instructions.
275 	for(volatile unsigned int i = 0; i < 64; i++){
276 		__asm__("nop");
277 	    }
278 
279 	analog_write_reg8(0x81, analog_read_reg8(0x81) & (~BIT(7)));
280 	//The flash two-wire system uses clk+cn+ two communication lines, and the flash four-wire system uses
281 	//clk+cn+ four communication lines. Before suspend sleep, the input of the six lines (PF0-PF5) used
282 	//by flash will be disabled. After suspend wakes up, the six lines will be set to input function.
283 	//(changed by weihua.zhang, confirmed by jianzhi 20201201)
284 	write_reg8(0x140329, 0x3f);	//MSPI(PF0-PF5) ie enable
285 	mspi_low();
286 	mspi_write(0xab);	//flash wakeup
287 	mspi_wait();
288 	mspi_high();
289 
290 	analog_write_reg8(0x7d, 0x80); // enable digital bb, usb, npe
291 	analog_write_reg8(0x0b, analog_read_reg8(0x0b) | (BIT(0) | BIT(1)));	//<0>:pd_nvt_1p4,	power down native 1P4.
292 																			//<1>:pd_nvt_1p8,	power down native 1P8.
293 	//wait for xtal stable
294     for(volatile unsigned int i = 0; i < 300; i++){	//200us
295     	__asm__("nop");
296     }
297     //check 3 times for safety
298 	while( BIT(7) != (analog_read_reg8(0x88) & (BIT(7)))); //0x88<7>: xo_ready_ana
299 	while( BIT(7) != (analog_read_reg8(0x88) & (BIT(7)))); //0x88<7>: xo_ready_ana
300 	while( BIT(7) != (analog_read_reg8(0x88) & (BIT(7)))); //0x88<7>: xo_ready_ana
301 
302 	pm_wait_bbpll_done();
303 }
304 
305 /**
306  * @brief		This function serves to switch external 32k pad to internal 32k rc.
307  * @return		none.
308  */
pm_switch_ext32kpad_to_int32krc(void)309 void pm_switch_ext32kpad_to_int32krc(void)
310 {
311 	//switch 32k clk src: select internal 32k rc, if not do this, when deep+pad wakeup: there's no stable 32k clk(therefore, the pad wake-up time
312 	//is a bit long, the need for external 32k crystal vibration time) to count DCDC dly and XTAL dly. High temperatures even make it impossible
313 	//to vibrate, as the code for PWM excitation crystals has not yet been effectively executed. SO, we can switch 32k clk to the internal 32k rc.
314 	analog_write_reg8(0x4e, analog_read_reg8(0x4e) & (~BIT(7))); //32k select:[7]:0 sel 32k rc,1:32k pad
315 	analog_write_reg8(0x05, 0x02); //[0]:32k rc;[1]:32k xtal (1->pwdn,0->pwup). Power up 32k rc.
316 
317 	//deep + no tmr wakeup(we need  32k clk to count dcdc dly and xtal dly, but this case, ext 32k clk need close, here we use 32k rc instead)
318 	analog_write_reg8(0x4c, 0xef);
319 }
320 
321 _attribute_data_retention_sec_ pm_clock_drift_t	pmcd = {0, 0, 0, 0, 0, 0};
322 /**
323  * @brief		When 32k rc sleeps, the calibration function is initialized.
324  * @return		none.
325  */
pm_32k_rc_offset_init(void)326 void pm_32k_rc_offset_init(void)
327 {
328 	pmcd.offset = 0;
329 	pmcd.tc = 0;
330 	pmcd.ref_tick = 0;
331 }
332 
pm_update_32k_rc_sleep_tick(unsigned int tick_32k,unsigned int tick)333 _attribute_ram_code_ void pm_update_32k_rc_sleep_tick (unsigned int tick_32k, unsigned int tick)
334 {
335 	pmcd.rc32_rt = tick_32k - pmcd.rc32_wakeup; //rc32_rt not used
336 	if (pmcd.calib || pmcd.ref_no > 20 || !pmcd.ref_tick || ((tick_32k - pmcd.ref_tick_32k) & 0xfffffff) > 32 * 3000)//3 mS
337 	{
338 		pmcd.calib = 0;
339 		pmcd.ref_tick_32k = tick_32k;
340 		pmcd.ref_tick = tick | 1;
341 		pmcd.ref_no = 0;
342 	}
343 	else
344 	{
345 		pmcd.ref_no++;
346 	}
347 }
348 
pm_ble_32k_rc_cal_reset(void)349 _attribute_ram_code_sec_noinline_ void pm_ble_32k_rc_cal_reset(void)
350 {
351 	pmcd.offset = 0;
352 	pmcd.tc = 0;
353 	pmcd.ref_tick = 0;
354 	pmcd.offset_cal_tick = 0;
355 }
356 
357 
pm_ble_cal_32k_rc_offset(int offset_tick,int rc32_cnt)358 _attribute_ram_code_sec_noinline_ void pm_ble_cal_32k_rc_offset (int offset_tick, int rc32_cnt)
359 {
360 	int offset = offset_tick * (256 * 31) / rc32_cnt;		//256mS / sleep_period
361 	int thres = rc32_cnt/9600;  //240*32=7680  300*32= 9600  400*32= 12800
362 	if(!thres){
363 		thres = 1;
364 	}
365 	thres *= 0x100;
366 
367 	if (offset > thres)
368 	{
369 		offset = thres;
370 	}
371 	else if (offset < -thres)
372 	{
373 		offset = -thres;
374 	}
375 	pmcd.calib = 1;
376 	pmcd.offset += (offset - pmcd.offset) >> 4;
377 	pmcd.offset_cal_tick  = clock_time() | 1;
378 }
379 
pm_cal_32k_rc_offset(int offset_tick)380 _attribute_ram_code_sec_noinline_ void pm_cal_32k_rc_offset (int offset_tick)
381 {
382 	int offset = offset_tick * (240 * 31) / pmcd.rc32;		//240ms / sleep_period
383 	if (offset > 0x100)
384 	{
385 		offset = 0x100;
386 	}
387 	else if (offset < -0x100)
388 	{
389 		offset = -0x100;
390 	}
391 	pmcd.calib = 1;
392 	pmcd.offset += (offset - pmcd.offset) >> 4;
393 	pmcd.offset_dc += (offset_tick - pmcd.offset_dc) >> 3;
394 }
395 
396 /**
397  * @brief		32k rc calibration clock compensation.
398  * @return		32k calibration value after compensation.
399  */
pm_get_32k_rc_calib(void)400 _attribute_ram_code_ unsigned int pm_get_32k_rc_calib (void)
401 {
402 	while(!read_reg32(0x140214));	//Wait for the 32k clock calibration to complete.
403 
404 	int tc = read_reg32(0x140214);
405 	pmcd.s0 = tc;
406 	tc = tc << 4;
407 	if (!pmcd.tc)
408 	{
409 		pmcd.tc = tc;
410 	}
411 	else
412 	{
413 		pmcd.tc += (tc - pmcd.tc) >> (4 - pmcd.calib);
414 	}
415 
416 	int offset = (pmcd.offset * (pmcd.tc >> 4)) >> 18;		//offset : tick per 256ms
417 	offset = (pmcd.tc >> 4) + offset;
418 	return (unsigned int)offset;
419 }
420 
421 /**
422  * @brief		This function serves to set the working mode of MCU based on 32k crystal,e.g. suspend mode, deepsleep mode, deepsleep with SRAM retention mode and shutdown mode.
423  * @param[in]	sleep_mode 			- sleep mode type select.
424  * @param[in]	wakeup_src 			- wake up source select.
425  * @param[in]	wakeup_tick_type	- tick type select. For long timer sleep.currently only 16M is supported(PM_TICK_STIMER_16M).
426  * @param[in]	wakeup_tick			- the time of short sleep, which means MCU can sleep for less than 5 minutes.
427  * @return		indicate whether the cpu is wake up successful.
428  */
pm_sleep_wakeup(pm_sleep_mode_e sleep_mode,pm_sleep_wakeup_src_e wakeup_src,pm_wakeup_tick_type_e wakeup_tick_type,unsigned int wakeup_tick)429 int pm_sleep_wakeup(pm_sleep_mode_e sleep_mode,  pm_sleep_wakeup_src_e wakeup_src, pm_wakeup_tick_type_e wakeup_tick_type, unsigned int  wakeup_tick)
430 {
431 	int timer_wakeup_enable = (wakeup_src & PM_WAKEUP_TIMER);
432 	if(CLK_32K_RC == g_clk_32k_src){
433 		g_pm_tick_32k_calib = pm_get_32k_rc_calib()*2;
434 	}else{
435 		//NOTICE:We think that the external 32k crystal clk is very accurate
436 		g_pm_tick_32k_calib = CRYSTAL32768_TICK_PER_32CYCLE;
437 
438 	}
439 	unsigned int  tick_32k_halfCalib = g_pm_tick_32k_calib>>1;
440 	unsigned int span = (unsigned int)(wakeup_tick - ((wakeup_tick_type == PM_TICK_STIMER_16M)?stimer_get_tick ():0));
441 	if(timer_wakeup_enable && (wakeup_tick_type == PM_TICK_STIMER_16M)){
442 		if (span > 0xE0000000){ //BIT(31)+BIT(30)+BIT(29)   7/8 cylce of 32bit, 268.44*7/8 = 234.88 S
443 			return  analog_read_reg8 (0x64) & 0x1f;
444 		}
445 		else if (span < g_pm_early_wakeup_time_us.sleep_min_time_us * SYSTEM_TIMER_TICK_1US){ // 0 us base
446 			unsigned int t = stimer_get_tick ();
447 			analog_write_reg8 (0x64, 0x1f);
448 			unsigned char st;
449 			do {
450 				st = analog_read_reg8 (0x64) & 0x1f;
451 			} while ( ((unsigned int)stimer_get_tick () - t < span) && !st);
452 
453 			return st;
454 		}
455 	}
456 	////////// disable IRQ //////////////////////////////////////////
457 	unsigned int r= core_interrupt_disable();
458 
459 #if SYS_TIMER_AUTO_MODE
460 	BM_CLR(reg_system_irq_mask,BIT(0));
461 	REG_ADDR8(0x140218) = 0x01;		//system tick only update upon 32k posedge, must set before enable 32k read update!!!
462 	BM_CLR(reg_system_ctrl,FLD_SYSTEM_32K_TRACK_EN);//disable 32k track
463 	g_pm_tick_32k_cur = clock_get_32k_tick();
464 	g_pm_tick_cur = stimer_get_tick();
465 	BM_SET(reg_system_st,FLD_SYSTEM_CMD_STOP);	//write 1, stop system timer when using auto mode
466 #else
467 	g_pm_tick_cur = stimer_get_tick() + 37 * SYSTEM_TIMER_TICK_1US;  //cpu_get_32k_tick will cost 30~40 us//15
468 	BM_CLR(reg_system_irq_mask,BIT(0));
469 	BM_CLR(reg_system_ctrl,FLD_SYSTEM_TIMER_EN | FLD_SYSTEM_TIMER_AUTO | FLD_SYSTEM_32K_TRACK_EN);//disable 32k track and stimer
470 	g_pm_tick_32k_cur = clock_get_32k_tick ();
471 #endif
472 
473 	pm_update_32k_rc_sleep_tick (g_pm_tick_32k_cur, g_pm_tick_cur);
474 
475 	/////////////////// set wakeup source /////////////////////////////////
476 	analog_write_reg8 (0x4b, wakeup_src);
477 	analog_write_reg8 (0x64, 0x1f);				//clear all flag
478 
479 	unsigned char cclk_reg = read_reg8(0x1401e8);
480 	write_reg8(0x1401e8, cclk_reg & 0x8f );//change cclk to 24M rc clock
481 	analog_write_reg8(0x7e, sleep_mode);//sram retention
482 	unsigned int earlyWakeup_us;
483 
484 	if(sleep_mode & DEEPSLEEP_RETENTION_FLAG) { //deepsleep with retention
485 		//0x00->0xd1
486 		//<0>pd_rc32k_auto=1 <4>pwdn power suspend ldo=1
487 		//<6>power down sequence enable=1 <7>enable isolation=1
488 		if(wakeup_src & PM_WAKEUP_COMPARATOR)
489 		{
490 			analog_write_reg8(0x4d,0xd0);//retention
491 		}
492 		else
493 		{
494 			analog_write_reg8(0x4d,0xd1);//retention
495 		}
496 #if (!WDT_REBOOT_RESET_ANA7F_WORK_AROUND)
497 		analog_write_reg8(0x7f, 0x00);
498 #endif
499 		//0x140104 mspi_set_l: mutiboot address offset option, 0:0k;  1:128k;  2:256k;  4:256k
500 		//0x140105 mspi_set_h: program space size = mspi_set_h*4k
501 		//0x140106 mspi_cmd_AHB: xip read command
502 		//0x140107 mspi_fm_AHB: [3:0] dummy_h  [5:4] dat_line_h  [6] addr_line_h  [7] cmd_line_h
503 		g_pm_multi_addr = read_reg32(0x140104);
504 
505 		if(wakeup_tick_type == PM_TICK_STIMER_16M){
506 			earlyWakeup_us = g_pm_early_wakeup_time_us.deep_ret_early_wakeup_time_us;
507 		}else{
508 			earlyWakeup_us = g_pm_longsleep_early_wakeup_time_us.deep_ret_early_wakeup_time_us;
509 		}
510 
511 	}
512 	else if(sleep_mode == DEEPSLEEP_MODE){  //deepsleep no retention
513 		//0x00->0xf9
514 		//<0>pd_rc32k_auto=1 <3>rst_xtal_quickstart_cnt=1 <4>pwdn power suspend ldo=1
515 		//<5>pwdn power retention ldo=1 <6>power down sequence enable=1 <7>enable isolation=1
516 		if(wakeup_src & PM_WAKEUP_COMPARATOR)
517 		{
518 			analog_write_reg8(0x4d,0xf8);//deep
519 		}
520 		else
521 		{
522 			analog_write_reg8(0x4d,0xf9);//deep
523 		}
524 		analog_write_reg8(0x7f, 0x01);
525 		if(wakeup_tick_type == PM_TICK_STIMER_16M){
526 			earlyWakeup_us = g_pm_early_wakeup_time_us.deep_early_wakeup_time_us;
527 		}else{
528 			earlyWakeup_us = g_pm_longsleep_early_wakeup_time_us.deep_early_wakeup_time_us;
529 		}
530 
531 	}
532 	else{  //suspend
533 		//0x00->0x61
534 		//<0>pd_rc32k_auto=1 <5>pwdn power retention ldo=1 <6>power down sequence enable=1
535 		if(wakeup_src & PM_WAKEUP_COMPARATOR)
536 		{
537 			analog_write_reg8(0x4d,0x60);//suspend
538 		}
539 		else
540 		{
541 			analog_write_reg8(0x4d,0x61);//suspend
542 		}
543 		analog_write_reg8(0x7f, 0x01);
544 
545 		if(wakeup_tick_type == PM_TICK_STIMER_16M){
546 			earlyWakeup_us = g_pm_early_wakeup_time_us.suspend_early_wakeup_time_us;
547 		}else{
548 			earlyWakeup_us = g_pm_longsleep_early_wakeup_time_us.suspend_early_wakeup_time_us;
549 		}
550 	}
551 	unsigned int tick_wakeup_reset = wakeup_tick - ((wakeup_tick_type == PM_TICK_STIMER_16M)?(earlyWakeup_us * SYSTEM_TIMER_TICK_1US):earlyWakeup_us);
552 	if(CLK_32K_RC == g_clk_32k_src){
553 		//auto power down
554 		if((wakeup_src & PM_WAKEUP_TIMER) || (wakeup_src & PM_WAKEUP_MDEC) || (wakeup_src & PM_WAKEUP_COMPARATOR)){
555 			analog_write_reg8(0x4c,0xee);//disable auto power down 32KRC
556 		}
557 		else{
558 			analog_write_reg8(0x4c, 0xef);//en auto power down 32KRC
559 		}
560 
561 	}else{
562 
563 		if(sleep_mode == DEEPSLEEP_MODE && !timer_wakeup_enable){ //if deep mode and no tmr wakeup
564 			pm_switch_ext32kpad_to_int32krc();
565 		}
566 		else{ //suspend mode or deepretn mode or tmr wakup (we don't pwdn ext 32k pad clk,even though three's no tmr wakup src in susped or deepretn mode)
567 			analog_write_reg8(0x4c, 0xed);//if use tmr wakeup, auto pad 32k pwdn shoule be disabled
568 		}
569 	}
570 
571 	if(sleep_mode == DEEPSLEEP_MODE){
572 		analog_write_reg8 (0x40, g_pm_r_delay_cycle.deep_r_delay_cycle);//(n):  if timer wake up : (n*2) 32k cycle; else pad wake up: (n*2-1) ~ (n*2)32k cycle
573 	}else{
574 		analog_write_reg8 (0x40, g_pm_r_delay_cycle.suspend_ret_r_delay_cycle);//(n):  if timer wake up : (n*2) 32k cycle; else pad wake up: (n*2-1) ~ (n*2)32k cycle
575 	}
576 
577 	unsigned int tick_reset;
578 	//The variable pmcd.ref_tick is added, replacing the original variable g_pm_tick_cur. Because pmcd.ref_tick directly affects the value of
579 	//g_pm_long_suspend, g_pm_long_suspend can be assigned after pmcd.ref_tick is updated.changed by weihua,confirmed by biao.li.20201204.
580 	if(timer_wakeup_enable && (wakeup_tick_type == PM_TICK_STIMER_16M)){
581 		if( (unsigned int)(tick_wakeup_reset - pmcd.ref_tick) > 0x07ff0000 ){ //CLK_32K_RC:BIT(28) = 0x10000000 16M:16S;CLK_32K_XTAL:BIT(28) = 0x08000000   16M:8.389S
582 			g_pm_long_suspend = 1;
583 		}
584 		else{
585 			g_pm_long_suspend = 0;
586 		}
587 	}
588 	if(wakeup_tick_type == PM_TICK_STIMER_16M){
589 		if(g_pm_long_suspend){
590 			tick_reset = pmcd.ref_tick_32k + (unsigned int)(tick_wakeup_reset - pmcd.ref_tick)/ g_pm_tick_32k_calib * 32;
591 		}
592 		else{
593 			tick_reset = pmcd.ref_tick_32k + ((unsigned int)(tick_wakeup_reset - pmcd.ref_tick) * 32 + tick_32k_halfCalib) / g_pm_tick_32k_calib;
594 		}
595 	}else{
596 		tick_reset = g_pm_tick_32k_cur + tick_wakeup_reset;
597 	}
598 	clock_set_32k_tick(tick_reset);
599 
600 	if(pm_get_wakeup_src()&0x1f){
601 
602 	}
603 	else{
604 #if (WDT_REBOOT_RESET_ANA7F_WORK_AROUND)
605 		if(sleep_mode & DEEPSLEEP_RETENTION_FLAG)
606 			analog_write_reg8(0x7f, 0x00);
607 #endif
608 		pm_sleep_start();
609 #if (WDT_REBOOT_RESET_ANA7F_WORK_AROUND)
610 		analog_write_reg8(0x7f, 0x01);
611 #endif
612 	}
613 	if(sleep_mode == DEEPSLEEP_MODE){
614 	   write_reg8 (0x1401ef, 0x20);  //reboot
615 	}
616 #if SYS_TIMER_AUTO_MODE
617 	REG_ADDR8(0x140218) = 0x02;	//sys tick 16M set upon next 32k posedge
618 	reg_system_ctrl		|=(FLD_SYSTEM_TIMER_AUTO|FLD_SYSTEM_32K_TRACK_EN) ;
619 	unsigned int now_tick_32k = clock_get_32k_tick();
620 	if(g_pm_long_suspend){
621 		g_pm_tick_cur = pmcd.ref_tick + (unsigned int)(now_tick_32k + 1 - pmcd.ref_tick_32k) / 32 * g_pm_tick_32k_calib;
622 	}else{
623 		g_pm_tick_cur = pmcd.ref_tick + (unsigned int)(now_tick_32k + 1 - pmcd.ref_tick_32k) * g_pm_tick_32k_calib / 32;		// current clock
624 	}
625 	pmcd.rc32_wakeup = now_tick_32k + 1;
626 	pmcd.rc32 = now_tick_32k + 1 - pmcd.ref_tick_32k;
627 	reg_system_tick = g_pm_tick_cur + 1;
628 
629 	//wait cmd set dly done upon next 32k posedge
630 	//if not using status bit, wait at least 1 32k cycle to set register r_run_upon_next_32k back to 0, or before next normal set
631 	while((reg_system_st & BIT(7)) == 0);	//system timer set done status upon next 32k posedge
632 	REG_ADDR8(0x140218) = 0;				//normal sys tick (16/sys) update
633 	reg_system_irq_mask |= BIT(0);   		//enable system timer irq
634 #else
635 	unsigned int now_tick_32k = clock_get_32k_tick();
636 	if(g_pm_long_suspend){
637 		g_pm_tick_cur = pmcd.ref_tick + (unsigned int)(now_tick_32k - pmcd.ref_tick_32k) / 32 * g_pm_tick_32k_calib;
638 	}else{
639 		g_pm_tick_cur = pmcd.ref_tick + (unsigned int)(now_tick_32k - pmcd.ref_tick_32k) * g_pm_tick_32k_calib / 32;		// current clock
640 	}
641 	pmcd.rc32_wakeup = now_tick_32k;
642 	pmcd.rc32 = now_tick_32k - pmcd.ref_tick_32k;
643 
644 	reg_system_tick = g_pm_tick_cur + 20 * SYSTEM_TIMER_TICK_1US;
645 	reg_system_ctrl	|= FLD_SYSTEM_TIMER_EN | FLD_SYSTEM_32K_TRACK_EN;    //enable 32k cal and stimer
646 	reg_system_irq_mask |= BIT(0);   										//enable system timer irq
647 #endif
648 
649 	write_reg8(0x1401e8, cclk_reg );//restore cclk
650 
651 	unsigned char anareg64 = pm_get_wakeup_src();
652 	//	DBG_CHN2_HIGH;
653 	if ( (anareg64 & WAKEUP_STATUS_TIMER) && timer_wakeup_enable )	//wakeup from timer only
654 	{
655 		if(wakeup_tick_type == PM_TICK_STIMER_16M){
656 			while ((unsigned int)(stimer_get_tick () -  wakeup_tick) > BIT(30));
657 		}else{
658 			while ((unsigned int)(clock_get_32k_tick() -  wakeup_tick - g_pm_tick_32k_cur + 37*16) > BIT(30));
659 		}
660 	}
661 
662 	//	DBG_CHN2_LOW;
663 	core_restore_interrupt(r);
664 	return (anareg64 ? (anareg64 | STATUS_ENTER_SUSPEND) : STATUS_GPIO_ERR_NO_ENTER_PM );
665 }
666 
667