1 /*
2  * Copyright (c) 2006-2025, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author            Notes
8  * 2022-01-25     iysheng           first version
9  */
10 
11 #include <board.h>
12 #include <sys/time.h>
13 
14 #define DBG_TAG             "drv.rtc"
15 #define DBG_LVL             DBG_INFO
16 
17 #include <rtdbg.h>
18 
19 #ifdef RT_USING_RTC
20 
21 typedef struct {
22     struct rt_device rtc_dev;
23 } gd32_rtc_device;
24 
25 static gd32_rtc_device g_gd32_rtc_dev;
26 
27 /**
28  * @brief  Helper function: Convert BCD value to binary.
29  * @param  val: BCD value.
30  * @return Binary value.
31  */
bcd_to_bin(rt_uint8_t val)32 static rt_uint8_t bcd_to_bin(rt_uint8_t val)
33 {
34     return (val & 0x0F) + ((val >> 4) & 0x0F) * 10;
35 }
36 
37 /**
38  * @brief  Helper function: Convert binary to BCD.
39  * @param  val: Binary value.
40  * @return BCD value.
41  */
bin_to_bcd(rt_uint8_t val)42 static rt_uint8_t bin_to_bcd(rt_uint8_t val)
43 {
44     return ((val / 10) << 4) | (val % 10);
45 }
46 
get_rtc_timestamp(void)47 static time_t get_rtc_timestamp(void)
48 {
49     #if defined SOC_SERIES_GD32E23x
50     struct tm tm_new;
51     rtc_parameter_struct rtc_current_time;
52 
53     rtc_current_time_get(&rtc_current_time);
54 
55     tm_new.tm_year = bcd_to_bin(rtc_current_time.rtc_year) + 100; /* tm_year: years since 1900 */
56     tm_new.tm_mon  = bcd_to_bin(rtc_current_time.rtc_month) - 1;  /* tm_mon: month (0 = January, 11 = December) */
57     tm_new.tm_mday = bcd_to_bin(rtc_current_time.rtc_date);
58     tm_new.tm_hour = bcd_to_bin(rtc_current_time.rtc_hour);
59     tm_new.tm_min  = bcd_to_bin(rtc_current_time.rtc_minute);
60     tm_new.tm_sec  = bcd_to_bin(rtc_current_time.rtc_second);
61 
62     return mktime(&tm_new);
63     #else
64     time_t rtc_counter;
65 
66     rtc_counter = (time_t)rtc_counter_get();
67 
68     return rtc_counter;
69     #endif
70 }
71 
set_rtc_timestamp(time_t time_stamp)72 static rt_err_t set_rtc_timestamp(time_t time_stamp)
73 {
74     #if defined SOC_SERIES_GD32E23x
75     struct tm *p_tm;
76     rtc_parameter_struct rtc_init_struct;
77 
78     p_tm = gmtime(&time_stamp);
79 
80     /* GD32 RTC uses year starting from 2000; thus tm_year must be at least 100 (i.e., 2000 - 1900) */
81 
82     if (p_tm->tm_year < 100)
83     {
84         return -RT_ERROR;
85     }
86 
87     rtc_init_struct.rtc_year = bin_to_bcd(p_tm->tm_year - 100);
88     rtc_init_struct.rtc_month = bin_to_bcd(p_tm->tm_mon + 1);
89     rtc_init_struct.rtc_date = bin_to_bcd(p_tm->tm_mday);
90 
91     rtc_init_struct.rtc_day_of_week = bin_to_bcd(p_tm->tm_wday == 0 ? 7 : p_tm->tm_wday);
92     rtc_init_struct.rtc_hour = bin_to_bcd(p_tm->tm_hour);
93     rtc_init_struct.rtc_minute = bin_to_bcd(p_tm->tm_min);
94     rtc_init_struct.rtc_second = bin_to_bcd(p_tm->tm_sec);
95     rtc_init_struct.rtc_display_format = RTC_24HOUR;
96 
97 #if defined(BSP_RTC_USING_LSI)
98     rtc_init_struct.rtc_factor_asyn = 39;
99     rtc_init_struct.rtc_factor_syn = 999;
100 #elif defined(BSP_RTC_USING_LSE)
101     rtc_init_struct.rtc_factor_asyn = 127;
102     rtc_init_struct.rtc_factor_syn = 255;
103 #endif
104 
105     if (rtc_init(&rtc_init_struct) != SUCCESS)
106     {
107         LOG_E("Failed to set RTC time.");
108         return -RT_ERROR;
109     }
110 
111     return RT_EOK;
112     #else
113     uint32_t rtc_counter;
114 
115     rtc_counter = (uint32_t)time_stamp;
116 
117     /* wait until LWOFF bit in RTC_CTL to 1 */
118     rtc_lwoff_wait();
119     /* enter configure mode */
120     rtc_configuration_mode_enter();
121     /* write data to rtc register */
122     rtc_counter_set(rtc_counter);
123     /* exit configure mode */
124     rtc_configuration_mode_exit();
125     /* wait until LWOFF bit in RTC_CTL to 1 */
126     rtc_lwoff_wait();
127 
128     return RT_EOK;
129     #endif
130 }
131 
rt_gd32_rtc_control(rt_device_t dev,int cmd,void * args)132 static rt_err_t rt_gd32_rtc_control(rt_device_t dev, int cmd, void *args)
133 {
134     rt_err_t result = RT_EOK;
135 
136     RT_ASSERT(dev != RT_NULL);
137     switch (cmd)
138     {
139     case RT_DEVICE_CTRL_RTC_GET_TIME:
140         *(rt_uint32_t *)args = get_rtc_timestamp();
141         break;
142 
143     case RT_DEVICE_CTRL_RTC_SET_TIME:
144         if (set_rtc_timestamp(*(rt_uint32_t *)args))
145         {
146             result = -RT_ERROR;
147         }
148         break;
149     }
150 
151     return result;
152 }
153 
154 #ifdef RT_USING_DEVICE_OPS
155 const static struct rt_device_ops g_gd32_rtc_ops =
156 {
157     RT_NULL,
158     RT_NULL,
159     RT_NULL,
160     RT_NULL,
161     RT_NULL,
162     rt_gd32_rtc_control
163 };
164 #endif
165 
rt_hw_rtc_init(void)166 static int rt_hw_rtc_init(void)
167 {
168     rt_err_t ret;
169     time_t rtc_counter;
170 
171     rcu_periph_clock_enable(RCU_PMU);
172     pmu_backup_write_enable();
173 #ifndef SOC_SERIES_GD32E23x
174     rcu_periph_clock_enable(RCU_BKPI);
175 #endif
176 
177     rtc_counter = get_rtc_timestamp();
178     /* once the rtc clock source has been selected, if can't be changed
179      * anymore unless the Backup domain is reset */
180     rcu_bkp_reset_enable();
181     rcu_bkp_reset_disable();
182     rcu_periph_clock_enable(RCU_RTC);
183 #if defined(BSP_RTC_USING_LSE)
184     rcu_osci_on(RCU_LXTAL);
185     if (SUCCESS == rcu_osci_stab_wait(RCU_LXTAL))
186     {
187         /* set lxtal as rtc clock source */
188         rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
189     }
190 #elif defined(BSP_RTC_USING_LSI)
191     rcu_osci_on(RCU_IRC40K);
192     if (SUCCESS == rcu_osci_stab_wait(RCU_IRC40K))
193     {
194         /* set IRC40K as rtc clock source */
195         rcu_rtc_clock_config(RCU_RTCSRC_IRC40K);
196     }
197 #endif
198     set_rtc_timestamp(rtc_counter);
199 
200 #ifdef RT_USING_DEVICE_OPS
201     g_gd32_rtc_dev.rtc_dev.ops         = &g_gd32_rtc_ops;
202 #else
203     g_gd32_rtc_dev.rtc_dev.init        = RT_NULL;
204     g_gd32_rtc_dev.rtc_dev.open        = RT_NULL;
205     g_gd32_rtc_dev.rtc_dev.close       = RT_NULL;
206     g_gd32_rtc_dev.rtc_dev.read        = RT_NULL;
207     g_gd32_rtc_dev.rtc_dev.write       = RT_NULL;
208     g_gd32_rtc_dev.rtc_dev.control     = rt_gd32_rtc_control;
209 #endif
210     g_gd32_rtc_dev.rtc_dev.type        = RT_Device_Class_RTC;
211     g_gd32_rtc_dev.rtc_dev.rx_indicate = RT_NULL;
212     g_gd32_rtc_dev.rtc_dev.tx_complete = RT_NULL;
213     g_gd32_rtc_dev.rtc_dev.user_data   = RT_NULL;
214 
215     ret = rt_device_register(&g_gd32_rtc_dev.rtc_dev, "rtc", \
216         RT_DEVICE_FLAG_RDWR);
217     if (ret != RT_EOK)
218     {
219         LOG_E("failed register internal rtc device, err=%d", ret);
220     }
221 
222     return ret;
223 }
224 INIT_DEVICE_EXPORT(rt_hw_rtc_init);
225 #endif
226 
227