1 /*
2  * Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author               Notes
8  * 2022-04-28     CDT                  first version
9  * 2022-05-31     CDT                  delete this file
10  * 2022-06-10     xiaoxiaolisunny      re-add this file for F460
11  * 2023-02-14     CDT                  add alarm(precision is 1 minute)
12  * 2024-06-07     CDT                  Add support for F448/F472
13  */
14 
15 #include <board.h>
16 #include <sys/time.h>
17 #include "board_config.h"
18 
19 #if defined(BSP_USING_RTC)
20 
21 //#define DRV_DEBUG
22 #define LOG_TAG             "drv.rtc"
23 #include <drv_log.h>
24 
25 #if defined(HC32F4A0) || defined(HC32F4A8)
26 /* BACKUP REG: 96~127 for RTC used */
27 #define RTC_BACKUP_DATA_SIZE        (32U)
28 #define RTC_BACKUP_REG_OFFSET       (128U - RTC_BACKUP_DATA_SIZE)
29 
30 static const uint8_t m_au8BackupWriteData[RTC_BACKUP_DATA_SIZE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
31                                                                    11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
32                                                                    21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
33                                                                    31
34                                                                   };
35 static uint8_t m_au8BackupReadData[RTC_BACKUP_DATA_SIZE];
36 #endif
37 
38 static rt_rtc_dev_t rtc_dev;
39 
40 #ifdef RT_USING_ALARM
41 struct stc_hc32_alarm_irq
42 {
43     struct hc32_irq_config  irq_config;
44     func_ptr_t              irq_callback;
45 };
46 
47 static void _rtc_alarm_irq_handler(void);
48 
49 #define RTC_ALARM_IRQ_CONFIG                                \
50     {                                                       \
51         .irq_num    = BSP_RTC_ALARM_IRQ_NUM,                \
52         .irq_prio   = BSP_RTC_ALARM_IRQ_PRIO,               \
53         .int_src    = INT_SRC_RTC_ALM,                      \
54     }
55 
56 static struct stc_hc32_alarm_irq hc32_alarm_irq =
57 {
58     .irq_config     = RTC_ALARM_IRQ_CONFIG,
59     .irq_callback   = _rtc_alarm_irq_handler,
60 };
61 #endif
62 
63 #if defined(HC32F4A0) || defined(HC32F4A8)
_bakup_reg_write(void)64 static void _bakup_reg_write(void)
65 {
66     uint8_t u8Num;
67     for (u8Num = 0U; u8Num < RTC_BACKUP_DATA_SIZE; u8Num++)
68     {
69         PWC_BKR_Write(u8Num + RTC_BACKUP_REG_OFFSET, m_au8BackupWriteData[u8Num]);
70     }
71 }
72 
_bakup_reg_check(void)73 static int32_t _bakup_reg_check(void)
74 {
75     uint8_t u8Num;
76     int32_t i32Ret = LL_OK;
77 
78     for (u8Num = 0U; u8Num < RTC_BACKUP_DATA_SIZE; u8Num++)
79     {
80         m_au8BackupReadData[u8Num] = PWC_BKR_Read(u8Num + RTC_BACKUP_REG_OFFSET);
81     }
82 
83     for (u8Num = 0U; u8Num < RTC_BACKUP_DATA_SIZE; u8Num++)
84     {
85         if (m_au8BackupWriteData[u8Num] != m_au8BackupReadData[u8Num])
86         {
87             i32Ret = LL_ERR;
88             break;
89         }
90     }
91 
92     return i32Ret;
93 }
94 
_hc32_rtc_rw_check(void)95 static int32_t _hc32_rtc_rw_check(void)
96 {
97     int32_t i32Ret = LL_ERR;
98 
99     /* Enter read/write mode */
100     if (LL_OK == RTC_EnterRwMode())
101     {
102         /* Exit read/write mode */
103         if (LL_OK == RTC_ExitRwMode())
104         {
105             i32Ret = LL_OK;
106         }
107     }
108 
109     return i32Ret;
110 }
111 #endif
112 
_rtc_get_timeval(struct timeval * tv)113 static rt_err_t _rtc_get_timeval(struct timeval *tv)
114 {
115 
116     stc_rtc_time_t stcRtcTime = {0};
117     stc_rtc_date_t stcRtcDate = {0};
118     struct tm tm_new = {0};
119 
120     if (LL_OK != RTC_GetTime(RTC_DATA_FMT_DEC, &stcRtcTime))
121     {
122         return -RT_ERROR;
123     }
124     if (LL_OK != RTC_GetDate(RTC_DATA_FMT_DEC, &stcRtcDate))
125     {
126         return -RT_ERROR;
127     }
128 
129     tm_new.tm_sec  = stcRtcTime.u8Second;
130     tm_new.tm_min  = stcRtcTime.u8Minute;
131     tm_new.tm_hour = stcRtcTime.u8Hour;
132     tm_new.tm_mday = stcRtcDate.u8Day;
133     tm_new.tm_mon  = stcRtcDate.u8Month - 1;
134     tm_new.tm_year = stcRtcDate.u8Year + 100;
135 
136     tv->tv_sec = timegm(&tm_new);
137 
138     return RT_EOK;
139 }
140 
hc32_rtc_set_time_stamp(time_t time_stamp)141 static rt_err_t hc32_rtc_set_time_stamp(time_t time_stamp)
142 {
143     stc_rtc_time_t stcRtcTime = {0};
144     stc_rtc_date_t stcRtcDate = {0};
145     struct tm tm_set = {0};
146 
147     gmtime_r(&time_stamp, &tm_set);
148 
149     if (tm_set.tm_year < 100)
150     {
151         return -RT_ERROR;
152     }
153 
154     stcRtcTime.u8Second  = tm_set.tm_sec ;
155     stcRtcTime.u8Minute  = tm_set.tm_min ;
156     stcRtcTime.u8Hour    = tm_set.tm_hour;
157     stcRtcDate.u8Day     = tm_set.tm_mday;
158     stcRtcDate.u8Month   = tm_set.tm_mon + 1;
159     stcRtcDate.u8Year    = tm_set.tm_year - 100;
160     stcRtcDate.u8Weekday = tm_set.tm_wday;
161 
162     if (LL_OK != RTC_SetTime(RTC_DATA_FMT_DEC, &stcRtcTime))
163     {
164         return -RT_ERROR;
165     }
166     if (LL_OK != RTC_SetDate(RTC_DATA_FMT_DEC, &stcRtcDate))
167     {
168         return -RT_ERROR;
169     }
170 
171     LOG_D("set rtc time.");
172     return RT_EOK;
173 }
174 
175 #if defined(HC32F4A0) || defined(HC32F460)
176     #if defined(BSP_RTC_USING_XTAL32)
177         #define  RTC_CLK_SRC_SEL            (RTC_CLK_SRC_XTAL32)
178     #else
179         #define  RTC_CLK_SRC_SEL            (RTC_CLK_SRC_LRC)
180     #endif
181 #elif defined(HC32F448) || defined(HC32F4A8)
182     #if defined(BSP_RTC_USING_XTAL32)
183         #define  RTC_CLK_SRC_SEL            (RTC_CLK_SRC_XTAL32)
184     #elif defined(BSP_RTC_USING_XTAL_DIV)
185         #define  RTC_CLK_SRC_SEL            (RTC_CLK_SRC_XTAL_DIV)
186     #else
187         #define  RTC_CLK_SRC_SEL            (RTC_CLK_SRC_LRC)
188     #endif
189 #elif defined(HC32F472)
190     #if defined(BSP_RTC_USING_XTAL32)
191         #define  RTC_CLK_SRC_SEL            (RTC_CLK_SRC_XTAL32)
192     #elif defined(BSP_RTC_USING_XTAL_DIV)
193         #define  RTC_CLK_SRC_SEL            (RTC_CLK_SRC_XTAL_DIV)
194     #elif defined(BSP_RTC_USING_EXTCLK)
195         #define  RTC_CLK_SRC_SEL            (RTC_CLK_SRC_EXTCLK)
196     #else
197         #define  RTC_CLK_SRC_SEL            (RTC_CLK_SRC_LRC)
198     #endif
199 #endif
200 
201 #if defined(HC32F4A8)
VBAT_PowerDownCheck(void)202 static en_flag_status_t VBAT_PowerDownCheck(void)
203 {
204     en_flag_status_t ret;
205     ret = PWC_VBAT_GetStatus(PWC_FLAG_VBAT_POR);
206     if (SET == ret)
207     {
208         PWC_VBAT_ClearStatus(PWC_FLAG_VBAT_POR);
209     }
210     return ret;
211 }
212 #endif
213 
_rtc_init(void)214 static rt_err_t _rtc_init(void)
215 {
216     stc_rtc_init_t stcRtcInit;
217 
218 #if defined(HC32F4A8)
219     if ((SET == VBAT_PowerDownCheck()) || (LL_OK != _bakup_reg_check()) || (LL_OK != _hc32_rtc_rw_check()))
220 #elif defined(HC32F4A0)
221     if ((LL_OK != _bakup_reg_check()) || (LL_OK != _hc32_rtc_rw_check()))
222 #elif  defined(HC32F460) || defined(HC32F448) || defined(HC32F472)
223     if (DISABLE == RTC_GetCounterState())
224 #endif
225     {
226         /* Reset RTC counter */
227         if (LL_ERR_TIMEOUT == RTC_DeInit())
228         {
229             LOG_E("Reset RTC failed!");
230             return -RT_ERROR;
231         }
232         else
233         {
234             /* Stop RTC */
235             RTC_Cmd(DISABLE);
236             /* Configure structure initialization */
237             (void)RTC_StructInit(&stcRtcInit);
238 
239             /* Configuration RTC structure */
240             stcRtcInit.u8ClockSrc = RTC_CLK_SRC_SEL;
241             stcRtcInit.u8HourFormat = RTC_HOUR_FMT_24H;
242             (void)RTC_Init(&stcRtcInit);
243 
244             /* Clear all status */
245             RTC_ClearStatus(RTC_FLAG_CLR_ALL);
246             /* Startup RTC count */
247             RTC_Cmd(ENABLE);
248 
249 #if defined(HC32F4A0) || defined(HC32F4A8)
250             /* Write sequence flag to backup register  */
251             _bakup_reg_write();
252 #endif
253             LOG_D("rtc init success");
254         }
255     }
256     else
257     {
258         LOG_D("rtc does not need to init");
259     }
260 
261     return RT_EOK;
262 }
263 
_rtc_get_secs(time_t * sec)264 static rt_err_t _rtc_get_secs(time_t *sec)
265 {
266     struct timeval tv;
267 
268     _rtc_get_timeval(&tv);
269     *(time_t *) sec = tv.tv_sec;
270     LOG_D("RTC: get rtc_time %d", *sec);
271 
272     return RT_EOK;
273 }
274 
_rtc_set_secs(time_t * sec)275 static rt_err_t _rtc_set_secs(time_t *sec)
276 {
277     rt_err_t result = RT_EOK;
278 
279     if (hc32_rtc_set_time_stamp(*sec))
280     {
281         result = -RT_ERROR;
282     }
283     LOG_D("RTC: set rtc_time %d", *sec);
284 #ifdef RT_USING_ALARM
285     rt_alarm_update(&rtc_dev.parent, 1);
286 #endif
287     return result;
288 }
289 
290 #ifdef RT_USING_ALARM
291 
_rtc_alarm_irq_handler(void)292 static void _rtc_alarm_irq_handler(void)
293 {
294     rt_interrupt_enter();
295     RTC_ClearStatus(RTC_FLAG_ALARM);
296     rt_alarm_update(&rtc_dev.parent, 1);
297     rt_interrupt_leave();
298 }
299 
300 #if defined(HC32F448) || defined(HC32F472)
RTC_Handler(void)301 void RTC_Handler(void)
302 {
303     if (RTC_GetStatus(RTC_FLAG_ALARM) != RESET)
304     {
305         _rtc_alarm_irq_handler();
306     }
307 }
308 #endif
309 
hc32_rtc_alarm_enable(void)310 static void hc32_rtc_alarm_enable(void)
311 {
312     NVIC_EnableIRQ(hc32_alarm_irq.irq_config.irq_num);
313 
314     RTC_IntCmd(RTC_INT_ALARM, ENABLE);
315     RTC_AlarmCmd(ENABLE);
316     LOG_D("hc32 alarm enable");
317 }
318 
hc32_rtc_alarm_disable(void)319 static void hc32_rtc_alarm_disable(void)
320 {
321     RTC_AlarmCmd(DISABLE);
322     RTC_IntCmd(RTC_INT_ALARM, DISABLE);
323 
324     NVIC_DisableIRQ(hc32_alarm_irq.irq_config.irq_num);
325     LOG_D("hc32 alarm disable");
326 }
327 #endif
328 
_rtc_get_alarm(struct rt_rtc_wkalarm * alarm)329 static rt_err_t _rtc_get_alarm(struct rt_rtc_wkalarm *alarm)
330 {
331 #ifdef RT_USING_ALARM
332     stc_rtc_alarm_t stcRtcAlarm;
333     RTC_GetAlarm(RTC_DATA_FMT_DEC, &stcRtcAlarm);
334     alarm->tm_hour = stcRtcAlarm.u8AlarmHour;
335     alarm->tm_min  = stcRtcAlarm.u8AlarmMinute;
336     alarm->tm_sec  = 0; /* alarms precision is 1 minute */
337 
338     LOG_D("GET_ALARM %d:%d:%d", alarm->tm_hour, alarm->tm_min, alarm->tm_sec);
339     return RT_EOK;
340 #else
341     return -RT_ERROR;
342 #endif
343 }
344 
_rtc_set_alarm(struct rt_rtc_wkalarm * alarm)345 static rt_err_t _rtc_set_alarm(struct rt_rtc_wkalarm *alarm)
346 {
347 #ifdef RT_USING_ALARM
348     stc_rtc_alarm_t stcRtcAlarm;
349 
350     LOG_D("RT_DEVICE_CTRL_RTC_SET_ALARM");
351     if (alarm != RT_NULL)
352     {
353         if (alarm->enable)
354         {
355             RTC_AlarmCmd(DISABLE);
356             /* Configuration alarm time: precision is 1 minute */
357             stcRtcAlarm.u8AlarmHour    = alarm->tm_hour;
358             stcRtcAlarm.u8AlarmMinute  = alarm->tm_min;
359             stcRtcAlarm.u8AlarmWeekday = RTC_ALARM_WEEKDAY_EVERYDAY;
360             stcRtcAlarm.u8AlarmAmPm    = RTC_HOUR_24H;
361             RTC_ClearStatus(RTC_FLAG_ALARM);
362             (void)RTC_SetAlarm(RTC_DATA_FMT_DEC, &stcRtcAlarm);
363             hc32_rtc_alarm_enable();
364             LOG_D("SET_ALARM %d:%d:%d", alarm->tm_hour,
365                   alarm->tm_min, 0);
366         }
367         else
368         {
369             hc32_rtc_alarm_disable();
370         }
371 
372     }
373     else
374     {
375         LOG_E("RT_DEVICE_CTRL_RTC_SET_ALARM error!!");
376         return -RT_ERROR;
377     }
378 
379     return RT_EOK;
380 #else
381     return -RT_ERROR;
382 #endif
383 }
384 
385 const static struct rt_rtc_ops _ops =
386 {
387     _rtc_init,
388     _rtc_get_secs,
389     _rtc_set_secs,
390     _rtc_get_alarm,
391     _rtc_set_alarm,
392     _rtc_get_timeval,
393     RT_NULL
394 };
395 
rt_hw_rtc_init(void)396 int rt_hw_rtc_init(void)
397 {
398     rt_err_t result;
399 
400 #ifdef RT_USING_ALARM
401     /* register interrupt */
402     hc32_install_irq_handler(&hc32_alarm_irq.irq_config, hc32_alarm_irq.irq_callback, RT_FALSE);
403 #endif
404     rtc_dev.ops = &_ops;
405     result = rt_hw_rtc_register(&rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR, RT_NULL);
406     if (result != RT_EOK)
407     {
408         LOG_E("rtc register err code: %d", result);
409         return result;
410     }
411     LOG_D("rtc register done");
412     return RT_EOK;
413 }
414 INIT_DEVICE_EXPORT(rt_hw_rtc_init);
415 
416 #endif /* BSP_USING_RTC */
417