1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date         Author        Notes
8  * 2022-01-21   charlown       first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include <sys/time.h>
14 #include "board.h"
15 
16 #ifdef BSP_USING_RTC
17 
18 #define LOG_TAG "drv.rtc"
19 #include "drv_log.h"
20 
21 #ifndef BKP_DR1
22 #define BKP_DR1 RT_NULL
23 #endif
24 
25 #define BKUP_REG_DATA 0xA5A5
26 
27 static struct rt_rtc_device rtc;
28 
rt_rtc_config(void)29 static void rt_rtc_config(void)
30 {
31     /* Allow access to BKP Domain */
32     PWR_BackupAccessCmd(ENABLE);
33 
34 #if defined(BSP_USING_RTC_LSI) && defined(LSI_VALUE)
35     RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
36 #else
37     RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
38 #endif
39 
40     RCC_RTCCLKCmd(ENABLE);
41 
42     RTC_WaitForLastTask();
43 
44     RTC_WaitForSynchro();
45 
46     if (BKP_ReadBackupRegister(BKP_DR1) != BKUP_REG_DATA)
47     {
48         LOG_I("RTC hasn't been configured, please use <date> command to config.");
49         /* Set RTC prescaler: set RTC period to 1sec */
50         RTC_SetPrescaler(32767);
51         /* Wait until last write operation on RTC registers has finished */
52         RTC_WaitForLastTask();
53     }
54 }
55 
ch32f2_rt_rtc_init(void)56 static rt_err_t ch32f2_rt_rtc_init(void)
57 {
58 
59     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
60     PWR_BackupAccessCmd(ENABLE);
61 
62 #if defined(BSP_USING_RTC_LSI) && defined(LSI_VALUE)
63     RCC_LSICmd(ENABLE);
64 
65     while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
66         ;
67 #else
68 
69     RCC_LSEConfig(RCC_LSE_ON);
70     while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
71         ;
72 #endif
73 
74     rt_rtc_config();
75 
76     return RT_EOK;
77 }
78 
ch32f2_get_secs(time_t * args)79 static rt_err_t ch32f2_get_secs(time_t *args)
80 {
81     *(rt_uint32_t *)args = RTC_GetCounter();
82     LOG_D("RTC: get rtc_time %x\n", *(rt_uint32_t *)args);
83 
84     return RT_EOK;
85 }
86 
ch32f2_set_secs(time_t * args)87 static rt_err_t ch32f2_set_secs(time_t *args)
88 {
89     /* Set the RTC counter value */
90     RTC_SetCounter(*(rt_uint32_t *)args);
91     /* Wait until last write operation on RTC registers has finished */
92     RTC_WaitForLastTask();
93 
94     LOG_D("set rtc time.");
95     BKP_WriteBackupRegister(BKP_DR1, BKUP_REG_DATA);
96 
97     LOG_D("RTC: set rtc_time %x\n", *(rt_uint32_t *)args);
98 
99     return RT_EOK;
100 }
101 
102 const static struct rt_rtc_ops rtc_ops =
103     {
104         .init = ch32f2_rt_rtc_init,
105         .get_secs = ch32f2_get_secs,
106         .set_secs = ch32f2_set_secs,
107         .get_alarm = RT_NULL,
108         .set_alarm = RT_NULL,
109         .get_timeval = RT_NULL,
110         .set_timeval = RT_NULL};
111 
rt_hw_rtc_init(void)112 int rt_hw_rtc_init(void)
113 {
114     rt_err_t result;
115 
116     rtc.ops = &rtc_ops;
117 
118     result = rt_hw_rtc_register(&rtc, "rtc", RT_DEVICE_FLAG_RDWR, RT_NULL);
119     if (result != RT_EOK)
120     {
121         LOG_E("rtc register err code: %d", result);
122         return result;
123     }
124     LOG_D("rtc init success");
125 
126     return RT_EOK;
127 }
128 
129 INIT_DEVICE_EXPORT(rt_hw_rtc_init);
130 
131 #endif /* BSP_USING_RTC */
132