1 /*
2 * Copyright (C) 2017-2024 Alibaba Group Holding Limited
3 */
4
5 /*******************************************************
6 * @file rtc.c
7 * @brief source file for rtc csi driver
8 * @version V1.0
9 * @date 23. Sep 2020
10 * ******************************************************/
11
12 #include <drv/rtc.h>
13 #include <drv/irq.h>
14 #include <time.h>
15
16 #define NORMAL_RTC_FREQ (32768U)
17 #define REAL_RTC_FREQ (soc_get_rtc_freq(0U))
18 #define RTC_WAIT_WRITED_10S (10000U)
19
20 #define RTC_WAIT_IS_TIMEOUT(_time_ms_, _result_) { \
21 do { \
22 if (_time_ms_ >= RTC_WAIT_WRITED_10S) { \
23 _result_ = -1; \
24 } \
25 mdelay(1U); \
26 } while(0); \
27 }
28
29 static uint32_t load_time = 0U;
30 static uint32_t int_number = 0U;
31 static uint32_t count = 0U;
32
33 extern int32_t clock_check_tm_ok(const struct tm *rtctime);
34 extern int32_t clock_update_basetime(const struct tm *rtctime);
35 extern time_t mktime(struct tm *tp);
36
37 /**
38 \brief Internal timeout interrupt process function
39 \param[in] rtc handle rtc handle to operate
40 \return None
41 */
qx_rtc_irq_handler(void * arg)42 void qx_rtc_irq_handler(void *arg)
43 {
44 csi_rtc_t *rtc = (csi_rtc_t *)arg;
45 uint32_t timecount = 0, ret = 0, intr_status = 0;
46
47 ///< TODO:获取RTC中断的状态到intr_status
48
49 do {
50 ///< TODO:清除RTC的中断
51 RTC_WAIT_IS_TIMEOUT(++timecount, ret);
52
53 if (ret < 0) {
54 break;
55 }
56 } while (intr_status);
57
58 count++;
59
60 if (count >= (int_number * (REAL_RTC_FREQ / NORMAL_RTC_FREQ))) {
61 count = 0U;
62
63 if (rtc->callback) {
64 rtc->callback(rtc, rtc->arg);
65 }
66 }
67
68 }
69 /**
70 \brief Initialize RTC Interface. Initializes the resources needed for the RTC interface
71 \param[in] rtc rtc handle to operate
72 \param[in] idx rtc index
73 \return error code \ref csi_error_t
74 */
csi_rtc_init(csi_rtc_t * rtc,uint32_t idx)75 csi_error_t csi_rtc_init(csi_rtc_t *rtc, uint32_t idx)
76 {
77 CSI_PARAM_CHK(rtc, CSI_ERROR);
78 csi_error_t ret = CSI_OK;
79
80 ///< 获取中断号、基地址等相关信息
81 if (0 == target_get(DEV_QX_RTC_TAG, idx, &rtc->dev)) {
82 ///< TODO:相关寄存器复位清零
83 } else {
84 ret = CSI_ERROR;
85 }
86
87 return ret;
88 }
89 /**
90 \brief De-initialize RTC Interface. stops operation and releases the software resources used by the interface
91 \param[in] rtc rtc handle to operate
92 \return None
93 */
csi_rtc_uninit(csi_rtc_t * rtc)94 void csi_rtc_uninit(csi_rtc_t *rtc)
95 {
96 CSI_PARAM_CHK_NORETVAL(rtc);
97
98 ///< TODO:相关寄存器复位清零
99 }
100
101 /**
102 \brief Set system date
103 \param[in] rtc handle rtc handle to operate
104 \param[in] rtctime pointer to rtc time
105 \return error code \ref csi_error_t
106 */
csi_rtc_set_time(csi_rtc_t * rtc,const csi_rtc_time_t * rtctime)107 csi_error_t csi_rtc_set_time(csi_rtc_t *rtc, const csi_rtc_time_t *rtctime)
108 {
109 CSI_PARAM_CHK(rtc, CSI_ERROR);
110 CSI_PARAM_CHK(rtctime, CSI_ERROR);
111 csi_error_t ret = CSI_OK;
112 int32_t load_sec;
113
114 do {
115 ret = (csi_error_t)clock_check_tm_ok((const struct tm *)rtctime);
116
117 if (ret < CSI_OK) {
118 break;
119 }
120
121 load_sec = clock_update_basetime((const struct tm *)rtctime);
122
123 if (load_sec <= 0) { ///< Error returned when total seconds overflow is negative
124 ret = CSI_ERROR;
125 break;
126 }
127
128 load_time = (uint32_t)load_sec;
129 ///< TODO:用load_sec设置RTC的加载值寄存器,该处操作有一段等待同步时间
130
131 if (ret < CSI_OK) {
132 break;
133 }
134
135 ///< TODO:使能计数器
136
137 } while (0);
138
139 return ret;
140 }
141 /**
142 \brief Set system date but no wait
143 \param[in] rtc rtc handle to operate
144 \param[in] rtctime pointer to rtc time
145 \return error code \ref csi_error_t
146 */
csi_rtc_set_time_no_wait(csi_rtc_t * rtc,const csi_rtc_time_t * rtctime)147 csi_error_t csi_rtc_set_time_no_wait(csi_rtc_t *rtc, const csi_rtc_time_t *rtctime)
148 {
149 CSI_PARAM_CHK(rtc, CSI_ERROR);
150 CSI_PARAM_CHK(rtctime, CSI_ERROR);
151 csi_error_t ret = CSI_OK;
152 int32_t load_sec;
153
154 do {
155
156 ret = (csi_error_t)clock_check_tm_ok((const struct tm *)rtctime);
157
158 if (ret < CSI_OK) {
159 break;
160 }
161
162 load_sec = clock_update_basetime((const struct tm *)rtctime);
163
164 if (load_sec <= 0) { ///< Error returned when total seconds overflow is negative
165 ret = CSI_ERROR;
166 break;
167 }
168
169 ///< TODO:用load_sec设置RTC的加载值寄存器
170
171 ///< TODO:使能计数器
172
173 } while (0);
174
175 return ret;
176 }
177 /**
178 \brief Get system date
179 \param[in] rtc handle rtc handle to operate
180 \param[out] rtctime pointer to rtc time
181 \return error code \ref csi_error_t
182 */
csi_rtc_get_time(csi_rtc_t * rtc,csi_rtc_time_t * rtctime)183 csi_error_t csi_rtc_get_time(csi_rtc_t *rtc, csi_rtc_time_t *rtctime)
184 {
185 uint32_t cur_time = 0;
186 time_t time;
187
188 CSI_PARAM_CHK(rtc, CSI_ERROR);
189 CSI_PARAM_CHK(rtctime, CSI_ERROR);
190
191 ///< TODO:获取当前时间到cur_time
192 time = (time_t)(((cur_time - load_time) / (REAL_RTC_FREQ / NORMAL_RTC_FREQ)) + load_time);
193 gmtime_r(&time, (struct tm *)rtctime);
194
195 return CSI_OK;
196 }
197
198 /**
199 \brief Get alarm remaining time
200 \param[in] rtc rtc handle to operate
201 \return the remaining time(s)
202 */
csi_rtc_get_alarm_remaining_time(csi_rtc_t * rtc)203 uint32_t csi_rtc_get_alarm_remaining_time(csi_rtc_t *rtc)
204 {
205 CSI_PARAM_CHK(rtc, 0U);
206
207 ///< 返回RTC剩余多长时间产生闹钟中断
208 return (int_number - (count / (REAL_RTC_FREQ / NORMAL_RTC_FREQ)));
209 }
210
211 /**
212 \brief Config RTC alarm ture timer
213 \param[in] rtc handle rtc handle to operate
214 \param[in] rtctime time(s) to wake up
215 \param[in] callback callback function
216 \param[in] arg callback's param
217 \return error code \ref csi_error_t
218 */
csi_rtc_set_alarm(csi_rtc_t * rtc,const csi_rtc_time_t * rtctime,void * callback,void * arg)219 csi_error_t csi_rtc_set_alarm(csi_rtc_t *rtc, const csi_rtc_time_t *rtctime, void *callback, void *arg)
220 {
221 CSI_PARAM_CHK(rtc, CSI_ERROR);
222 CSI_PARAM_CHK(rtctime, CSI_ERROR);
223 csi_error_t ret = (csi_error_t)clock_check_tm_ok((const struct tm *)rtctime);
224 csi_rtc_time_t current_time;
225
226 if (CSI_OK == ret) {
227 rtc->callback = callback;
228 rtc->arg = arg;
229 ///< 注册RTC的中断服务函数,使能中断控制器中对应的中断
230 csi_irq_attach((uint32_t)rtc->dev.irq_num, &qx_rtc_irq_handler, &rtc->dev);
231 csi_irq_enable((uint32_t)rtc->dev.irq_num);
232
233 csi_rtc_get_time(rtc, ¤t_time); ///< get current time
234 count = 0U;
235 int_number = ((uint32_t)mktime((struct tm *)rtctime) - (uint32_t)mktime((struct tm *)¤t_time));
236 ///< TODO:使能RTC的中断
237 }
238
239 return ret;
240 }
241
242 /**
243 \brief Cancel the rtc alarm
244 \param[in] rtc rtc handle to operate
245 \return error code \ref csi_error_t
246 */
csi_rtc_cancel_alarm(csi_rtc_t * rtc)247 csi_error_t csi_rtc_cancel_alarm(csi_rtc_t *rtc)
248 {
249 CSI_PARAM_CHK(rtc, CSI_ERROR);
250
251 rtc->callback = NULL;
252 rtc->arg = NULL;
253
254 ///< TODO:禁止中断
255
256 ///< 关闭中断控制器中对应的使能,注销RTC的中断服务函数
257 csi_irq_disable((uint32_t)rtc->dev.irq_num);
258 csi_irq_detach((uint32_t)rtc->dev.irq_num);
259
260 return CSI_OK;
261 }
262
263 /**
264 \brief Judge rtc is working
265 \param[in] rtc handle rtc handle to operate
266 \return state of work
267 ture - rtc is running
268 false -rtc is not running
269 */
csi_rtc_is_running(csi_rtc_t * rtc)270 bool csi_rtc_is_running(csi_rtc_t *rtc)
271 {
272 CSI_PARAM_CHK(rtc, false);
273
274 bool status = 0;
275
276 ///< TODO:获取RTC运行的状态
277
278 return status;
279 }
280
281 #ifdef CONFIG_PM
csi_rtc_enable_pm(csi_rtc_t * rtc)282 csi_error_t csi_rtc_enable_pm(csi_rtc_t *rtc)
283 {
284 return CSI_UNSUPPORTED;
285 }
286
csi_rtc_disable_pm(csi_rtc_t * rtc)287 void csi_rtc_disable_pm(csi_rtc_t *rtc)
288 {
289 return;
290 }
291 #endif
292