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, &current_time);            ///< get current time
234         count = 0U;
235         int_number = ((uint32_t)mktime((struct tm *)rtctime) - (uint32_t)mktime((struct tm *)&current_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