embox

Форк
0
193 строки · 4.3 Кб
1
/**
2
 * @file
3
 *
4
 * @date   13.10.2020
5
 * @author Alexander Kalmuk
6
 */
7

8
#include <embox/unit.h>
9
#include <kernel/time/clock_source.h>
10
#include <hal/ipl.h>
11
#include <hal/clock.h>
12
#include <time.h>
13
#include <kernel/time/time.h>
14
#include <kernel/time/timer.h>
15
#include <drivers/rtc.h>
16

17
#include <config/custom_config_qspi.h>
18
#include <hw_clk.h>
19
#include <hw_gpio.h>
20
#include <hw_bod.h>
21
#include <hw_pmu.h>
22
#include <hw_pdc.h>
23
#include <hw_timer.h>
24
#include <hw_watchdog.h>
25
#include <qspi_automode.h>
26

27
EMBOX_UNIT_INIT(deepsleep_init);
28

29
extern void lp_clock_enable(void);
30
extern void set_wakeup_reset_handler(void);
31
extern bool goto_deepsleep(void);
32

33
static struct clock_source *da1469x_timer;
34
static struct rtc_device *rtc_dev;
35

36
static __RETAINED_CODE void prepare_for_deepsleep(void) {
37
	hw_sys_pd_com_disable();
38
	hw_sys_pd_periph_disable();
39
	qspi_automode_flash_power_down();
40
}
41

42
static __RETAINED_CODE void resume_after_deepsleep(void) {
43
	qspi_automode_flash_power_up();
44
	hw_sys_pd_periph_enable();
45
	hw_sys_pd_com_enable();
46
}
47

48
static int deepsleep_rtc_set(int systimer_ticks) {
49
	time_t time;
50
	struct rtc_wkalrm rtc_wk;
51

52
	if (!rtc_dev) {
53
		rtc_dev = rtc_get_device(NULL);
54
		if (!rtc_dev) {
55
			return -1;
56
		}
57
	}
58

59
	if (systimer_ticks == -1) {
60
	    /* There is no next event, so sleep as long as possible, no alarm.
61
	     * We will be wake up with CMAC interrupt or another trigger. */
62
		return 0;
63
	}
64

65
	rtc_get_time(rtc_dev, &rtc_wk.tm);
66
	time = mktime(&rtc_wk.tm) + systimer_ticks / clock_freq();
67

68
	gmtime_r(&time, &rtc_wk.tm);
69

70
	rtc_set_alarm(rtc_dev, &rtc_wk);
71

72
	return 0;
73
}
74

75
static int deepsleep_gp_timer_set(int systimer_ticks) {
76
	unsigned int lp_timer_ticks;
77

78
	if (!da1469x_timer) {
79
		da1469x_timer = clock_source_get_by_name("da1469x_timer");
80
		if (!da1469x_timer) {
81
			return -1;
82
		}
83
	}
84

85
	lp_timer_ticks =
86
		(systimer_ticks * da1469x_timer->counter_device->cycle_hz) /
87
			clock_freq();
88

89
	clock_source_set_oneshot(da1469x_timer);
90
	clock_source_set_next_event(da1469x_timer, lp_timer_ticks);
91

92
	return 0;
93
}
94

95
__RETAINED_CODE int deepsleep_enter(void) {
96
	bool entered_sleep;
97
	ipl_t ipl;
98
	int systimer_ticks;
99
	clock_t next_event;
100
	int res;
101
	bool use_rtc = false;
102

103
	if (hw_sys_is_debugger_attached()) {
104
		return -1;
105
	}
106

107
	res = timer_strat_get_next_event(&next_event);
108

109
	if (res) {
110
		/* No next event */
111
		systimer_ticks = -1;
112
	} else {
113
		systimer_ticks = next_event - clock_sys_ticks();
114
	}
115

116
	if (res || (systimer_ticks / clock_freq() >= 1)) {
117
		/* Use RTC if want to sleep for more than 1 sec. */
118
		use_rtc = true;
119
	}
120

121
	if (use_rtc) {
122
		if (0 != deepsleep_rtc_set(systimer_ticks)) {
123
			return -1;
124
		}
125
	} else {
126
		if (0 != deepsleep_gp_timer_set(systimer_ticks)) {
127
			return -1;
128
		}
129
	}
130

131
	ipl = ipl_save();
132

133
	prepare_for_deepsleep();
134

135
	entered_sleep = goto_deepsleep();
136

137
	resume_after_deepsleep();
138
	ipl_restore(ipl);
139

140
	if (!entered_sleep) {
141
		/* TODO Stop timer */
142
		return -1;
143
	}
144

145
	hw_watchdog_freeze();                   // Stop watchdog
146
	hw_watchdog_set_pos_val(dg_configWDOG_IDLE_RESET_VALUE);
147

148
	/* Re-enable system timer */
149
	jiffies_init();
150

151
	if (systimer_ticks != -1) {
152
		jiffies_update(systimer_ticks);
153
	}
154

155
	return 0;
156
}
157

158
/* Based on configure_pdc() */
159
static void configure_trigger(void) {
160
	uint32_t pdc_entry_index;
161

162
	REG_SETF(CRG_TOP, PMU_CTRL_REG, TIM_SLEEP, 0);
163
	while (REG_GETF(CRG_TOP, SYS_STAT_REG, TIM_IS_UP) == 0) {
164
	}
165

166
	/* Timer 2 */
167
	pdc_entry_index = hw_pdc_add_entry(HW_PDC_LUT_ENTRY_VAL(
168
	                                        HW_PDC_TRIG_SELECT_PERIPHERAL,
169
	                                        HW_PDC_PERIPH_TRIG_ID_TIMER2,
170
	                                        HW_PDC_MASTER_CM33,
171
	                                        (dg_configENABLE_XTAL32M_ON_WAKEUP ? HW_PDC_LUT_ENTRY_EN_XTAL : 0)));
172
	hw_pdc_set_pending(pdc_entry_index);
173
	hw_pdc_acknowledge(pdc_entry_index);
174

175
	/* RTC */
176
	pdc_entry_index = hw_pdc_add_entry(HW_PDC_LUT_ENTRY_VAL(
177
	                                        HW_PDC_TRIG_SELECT_PERIPHERAL,
178
	                                        HW_PDC_PERIPH_TRIG_ID_RTC_ALARM,
179
	                                        HW_PDC_MASTER_CM33,
180
	                                        (dg_configENABLE_XTAL32M_ON_WAKEUP ? HW_PDC_LUT_ENTRY_EN_XTAL : 0)));
181
	hw_pdc_set_pending(pdc_entry_index);
182
	hw_pdc_acknowledge(pdc_entry_index);
183
}
184

185
static int deepsleep_init(void) {
186
	lp_clock_enable();
187

188
	configure_trigger();
189

190
	set_wakeup_reset_handler();
191

192
	return 0;
193
}
194

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.