1 /*
2 * Copyright (c) 2018 Workaround GmbH
3 * Copyright (c) 2018 Allterco Robotics
4 * Copyright (c) 2018 Linaro Limited
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 *
8 * Source file for the STM32 RTC driver
9 *
10 */
11
12 #define DT_DRV_COMPAT st_stm32_rtc
13
14 #include <time.h>
15
16 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
17 #include <zephyr/drivers/clock_control.h>
18 #include <zephyr/sys/util.h>
19 #include <zephyr/kernel.h>
20 #include <soc.h>
21 #include <stm32_ll_exti.h>
22 #include <stm32_ll_pwr.h>
23 #include <stm32_ll_rcc.h>
24 #include <stm32_ll_rtc.h>
25 #include <zephyr/drivers/counter.h>
26 #include <zephyr/sys/timeutil.h>
27
28 #include <zephyr/logging/log.h>
29 #include <zephyr/irq.h>
30
31 #include "stm32_hsem.h"
32
33 LOG_MODULE_REGISTER(counter_rtc_stm32, CONFIG_COUNTER_LOG_LEVEL);
34
35 /* Seconds from 1970-01-01T00:00:00 to 2000-01-01T00:00:00 */
36 #define T_TIME_OFFSET 946684800
37
38 #if defined(CONFIG_SOC_SERIES_STM32L4X)
39 #define RTC_EXTI_LINE LL_EXTI_LINE_18
40 #elif defined(CONFIG_SOC_SERIES_STM32C0X) \
41 || defined(CONFIG_SOC_SERIES_STM32G0X)
42 #define RTC_EXTI_LINE LL_EXTI_LINE_19
43 #elif defined(CONFIG_SOC_SERIES_STM32F4X) \
44 || defined(CONFIG_SOC_SERIES_STM32F0X) \
45 || defined(CONFIG_SOC_SERIES_STM32F1X) \
46 || defined(CONFIG_SOC_SERIES_STM32F2X) \
47 || defined(CONFIG_SOC_SERIES_STM32F3X) \
48 || defined(CONFIG_SOC_SERIES_STM32F7X) \
49 || defined(CONFIG_SOC_SERIES_STM32WBX) \
50 || defined(CONFIG_SOC_SERIES_STM32G4X) \
51 || defined(CONFIG_SOC_SERIES_STM32L0X) \
52 || defined(CONFIG_SOC_SERIES_STM32L1X) \
53 || defined(CONFIG_SOC_SERIES_STM32L5X) \
54 || defined(CONFIG_SOC_SERIES_STM32H7X) \
55 || defined(CONFIG_SOC_SERIES_STM32H5X) \
56 || defined(CONFIG_SOC_SERIES_STM32WLX)
57 #define RTC_EXTI_LINE LL_EXTI_LINE_17
58 #endif
59
60 #if defined(CONFIG_SOC_SERIES_STM32F1X)
61 #define COUNTER_NO_DATE
62 #endif
63
64 struct rtc_stm32_config {
65 struct counter_config_info counter_info;
66 LL_RTC_InitTypeDef ll_rtc_config;
67 const struct stm32_pclken *pclken;
68 };
69
70 struct rtc_stm32_data {
71 counter_alarm_callback_t callback;
72 uint32_t ticks;
73 void *user_data;
74 };
75
ll_func_init_alarm(RTC_TypeDef * rtc,uint32_t format,LL_RTC_AlarmTypeDef * alarmStruct)76 static inline ErrorStatus ll_func_init_alarm(RTC_TypeDef *rtc, uint32_t format,
77 LL_RTC_AlarmTypeDef *alarmStruct)
78 {
79 #if defined(CONFIG_SOC_SERIES_STM32F1X)
80 return LL_RTC_ALARM_Init(rtc, format, alarmStruct);
81 #else
82 return LL_RTC_ALMA_Init(rtc, format, alarmStruct);
83 #endif
84 }
85
ll_func_clear_alarm_flag(RTC_TypeDef * rtc)86 static inline void ll_func_clear_alarm_flag(RTC_TypeDef *rtc)
87 {
88 #if defined(CONFIG_SOC_SERIES_STM32F1X)
89 LL_RTC_ClearFlag_ALR(rtc);
90 #else
91 LL_RTC_ClearFlag_ALRA(rtc);
92 #endif
93 }
94
ll_func_is_active_alarm(RTC_TypeDef * rtc)95 static inline uint32_t ll_func_is_active_alarm(RTC_TypeDef *rtc)
96 {
97 #if defined(CONFIG_SOC_SERIES_STM32F1X)
98 return LL_RTC_IsActiveFlag_ALR(rtc);
99 #else
100 return LL_RTC_IsActiveFlag_ALRA(rtc);
101 #endif
102 }
103
ll_func_enable_interrupt_alarm(RTC_TypeDef * rtc)104 static inline void ll_func_enable_interrupt_alarm(RTC_TypeDef *rtc)
105 {
106 #if defined(CONFIG_SOC_SERIES_STM32F1X)
107 LL_RTC_EnableIT_ALR(rtc);
108 #else
109 LL_RTC_EnableIT_ALRA(rtc);
110 #endif
111 }
112
ll_func_disable_interrupt_alarm(RTC_TypeDef * rtc)113 static inline void ll_func_disable_interrupt_alarm(RTC_TypeDef *rtc)
114 {
115 #if defined(CONFIG_SOC_SERIES_STM32F1X)
116 LL_RTC_DisableIT_ALR(rtc);
117 #else
118 LL_RTC_DisableIT_ALRA(rtc);
119 #endif
120 }
121
ll_func_enable_alarm(RTC_TypeDef * rtc)122 static inline void ll_func_enable_alarm(RTC_TypeDef *rtc)
123 {
124 #if defined(CONFIG_SOC_SERIES_STM32F1X)
125 ARG_UNUSED(rtc);
126 #else
127 LL_RTC_ALMA_Enable(rtc);
128 #endif
129 }
130
ll_func_disable_alarm(RTC_TypeDef * rtc)131 static inline void ll_func_disable_alarm(RTC_TypeDef *rtc)
132 {
133 #if defined(CONFIG_SOC_SERIES_STM32F1X)
134 ARG_UNUSED(rtc);
135 #else
136 LL_RTC_ALMA_Disable(rtc);
137 #endif
138 }
139
140 static void rtc_stm32_irq_config(const struct device *dev);
141
142
rtc_stm32_start(const struct device * dev)143 static int rtc_stm32_start(const struct device *dev)
144 {
145 ARG_UNUSED(dev);
146
147 z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY);
148 LL_RCC_EnableRTC();
149 z_stm32_hsem_unlock(CFG_HW_RCC_SEMID);
150
151 return 0;
152 }
153
154
rtc_stm32_stop(const struct device * dev)155 static int rtc_stm32_stop(const struct device *dev)
156 {
157 ARG_UNUSED(dev);
158
159 z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY);
160 LL_RCC_DisableRTC();
161 z_stm32_hsem_unlock(CFG_HW_RCC_SEMID);
162
163 return 0;
164 }
165
166
rtc_stm32_read(const struct device * dev)167 static uint32_t rtc_stm32_read(const struct device *dev)
168 {
169 #if !defined(COUNTER_NO_DATE)
170 struct tm now = { 0 };
171 time_t ts;
172 uint32_t rtc_date, rtc_time, ticks;
173 #else
174 uint32_t rtc_time, ticks;
175 #endif
176 ARG_UNUSED(dev);
177
178 /* Read time and date registers */
179 rtc_time = LL_RTC_TIME_Get(RTC);
180 #if !defined(COUNTER_NO_DATE)
181 rtc_date = LL_RTC_DATE_Get(RTC);
182 #endif
183
184 #if !defined(COUNTER_NO_DATE)
185 /* Convert calendar datetime to UNIX timestamp */
186 /* RTC start time: 1st, Jan, 2000 */
187 /* time_t start: 1st, Jan, 1970 */
188 now.tm_year = 100 +
189 __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_YEAR(rtc_date));
190 /* tm_mon allowed values are 0-11 */
191 now.tm_mon = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_MONTH(rtc_date)) - 1;
192 now.tm_mday = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_DAY(rtc_date));
193
194 now.tm_hour = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_HOUR(rtc_time));
195 now.tm_min = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_MINUTE(rtc_time));
196 now.tm_sec = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_SECOND(rtc_time));
197
198 ts = timeutil_timegm(&now);
199
200 /* Return number of seconds since RTC init */
201 ts -= T_TIME_OFFSET;
202
203 __ASSERT(sizeof(time_t) == 8, "unexpected time_t definition");
204 ticks = counter_us_to_ticks(dev, ts * USEC_PER_SEC);
205 #else
206 ticks = rtc_time;
207 #endif
208
209 return ticks;
210 }
211
rtc_stm32_get_value(const struct device * dev,uint32_t * ticks)212 static int rtc_stm32_get_value(const struct device *dev, uint32_t *ticks)
213 {
214 *ticks = rtc_stm32_read(dev);
215 return 0;
216 }
217
rtc_stm32_set_alarm(const struct device * dev,uint8_t chan_id,const struct counter_alarm_cfg * alarm_cfg)218 static int rtc_stm32_set_alarm(const struct device *dev, uint8_t chan_id,
219 const struct counter_alarm_cfg *alarm_cfg)
220 {
221 #if !defined(COUNTER_NO_DATE)
222 struct tm alarm_tm;
223 time_t alarm_val;
224 #else
225 uint32_t remain;
226 #endif
227 LL_RTC_AlarmTypeDef rtc_alarm;
228 struct rtc_stm32_data *data = dev->data;
229
230 uint32_t now = rtc_stm32_read(dev);
231 uint32_t ticks = alarm_cfg->ticks;
232
233 if (data->callback != NULL) {
234 LOG_DBG("Alarm busy\n");
235 return -EBUSY;
236 }
237
238
239 data->callback = alarm_cfg->callback;
240 data->user_data = alarm_cfg->user_data;
241
242 #if !defined(COUNTER_NO_DATE)
243 if ((alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) == 0) {
244 /* Add +1 in order to compensate the partially started tick.
245 * Alarm will expire between requested ticks and ticks+1.
246 * In case only 1 tick is requested, it will avoid
247 * that tick+1 event occurs before alarm setting is finished.
248 */
249 ticks += now + 1;
250 alarm_val = (time_t)(counter_ticks_to_us(dev, ticks) / USEC_PER_SEC)
251 + T_TIME_OFFSET;
252 } else {
253 alarm_val = (time_t)(counter_ticks_to_us(dev, ticks) / USEC_PER_SEC);
254 }
255 #else
256 if ((alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) == 0) {
257 remain = ticks + now + 1;
258 } else {
259 remain = ticks;
260 }
261
262 /* In F1X, an interrupt occurs when the counter expires,
263 * not when the counter matches, so set -1
264 */
265 remain--;
266 #endif
267
268 #if !defined(COUNTER_NO_DATE)
269 LOG_DBG("Set Alarm: %d\n", ticks);
270
271 gmtime_r(&alarm_val, &alarm_tm);
272
273 /* Apply ALARM_A */
274 rtc_alarm.AlarmTime.TimeFormat = LL_RTC_TIME_FORMAT_AM_OR_24;
275 rtc_alarm.AlarmTime.Hours = alarm_tm.tm_hour;
276 rtc_alarm.AlarmTime.Minutes = alarm_tm.tm_min;
277 rtc_alarm.AlarmTime.Seconds = alarm_tm.tm_sec;
278
279 rtc_alarm.AlarmMask = LL_RTC_ALMA_MASK_NONE;
280 rtc_alarm.AlarmDateWeekDaySel = LL_RTC_ALMA_DATEWEEKDAYSEL_DATE;
281 rtc_alarm.AlarmDateWeekDay = alarm_tm.tm_mday;
282 #else
283 rtc_alarm.AlarmTime.Hours = remain / 3600;
284 remain -= rtc_alarm.AlarmTime.Hours * 3600;
285 rtc_alarm.AlarmTime.Minutes = remain / 60;
286 remain -= rtc_alarm.AlarmTime.Minutes * 60;
287 rtc_alarm.AlarmTime.Seconds = remain;
288 #endif
289
290 LL_RTC_DisableWriteProtection(RTC);
291 ll_func_disable_alarm(RTC);
292 LL_RTC_EnableWriteProtection(RTC);
293
294 if (ll_func_init_alarm(RTC, LL_RTC_FORMAT_BIN, &rtc_alarm) != SUCCESS) {
295 return -EIO;
296 }
297
298 LL_RTC_DisableWriteProtection(RTC);
299 ll_func_enable_alarm(RTC);
300 ll_func_clear_alarm_flag(RTC);
301 ll_func_enable_interrupt_alarm(RTC);
302 LL_RTC_EnableWriteProtection(RTC);
303
304 return 0;
305 }
306
307
rtc_stm32_cancel_alarm(const struct device * dev,uint8_t chan_id)308 static int rtc_stm32_cancel_alarm(const struct device *dev, uint8_t chan_id)
309 {
310 struct rtc_stm32_data *data = dev->data;
311
312 LL_RTC_DisableWriteProtection(RTC);
313 ll_func_clear_alarm_flag(RTC);
314 ll_func_disable_interrupt_alarm(RTC);
315 ll_func_disable_alarm(RTC);
316 LL_RTC_EnableWriteProtection(RTC);
317
318 data->callback = NULL;
319
320 return 0;
321 }
322
323
rtc_stm32_get_pending_int(const struct device * dev)324 static uint32_t rtc_stm32_get_pending_int(const struct device *dev)
325 {
326 return ll_func_is_active_alarm(RTC) != 0;
327 }
328
329
rtc_stm32_get_top_value(const struct device * dev)330 static uint32_t rtc_stm32_get_top_value(const struct device *dev)
331 {
332 const struct counter_config_info *info = dev->config;
333
334 return info->max_top_value;
335 }
336
337
rtc_stm32_set_top_value(const struct device * dev,const struct counter_top_cfg * cfg)338 static int rtc_stm32_set_top_value(const struct device *dev,
339 const struct counter_top_cfg *cfg)
340 {
341 const struct counter_config_info *info = dev->config;
342
343 if ((cfg->ticks != info->max_top_value) ||
344 !(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)) {
345 return -ENOTSUP;
346 } else {
347 return 0;
348 }
349
350
351 }
352
rtc_stm32_isr(const struct device * dev)353 void rtc_stm32_isr(const struct device *dev)
354 {
355 struct rtc_stm32_data *data = dev->data;
356 counter_alarm_callback_t alarm_callback = data->callback;
357
358 uint32_t now = rtc_stm32_read(dev);
359
360 if (ll_func_is_active_alarm(RTC) != 0) {
361
362 LL_RTC_DisableWriteProtection(RTC);
363 ll_func_clear_alarm_flag(RTC);
364 ll_func_disable_interrupt_alarm(RTC);
365 ll_func_disable_alarm(RTC);
366 LL_RTC_EnableWriteProtection(RTC);
367
368 if (alarm_callback != NULL) {
369 data->callback = NULL;
370 alarm_callback(dev, 0, now, data->user_data);
371 }
372 }
373
374 #if defined(CONFIG_SOC_SERIES_STM32H7X) && defined(CONFIG_CPU_CORTEX_M4)
375 LL_C2_EXTI_ClearFlag_0_31(RTC_EXTI_LINE);
376 #elif defined(CONFIG_SOC_SERIES_STM32C0X) \
377 || defined(CONFIG_SOC_SERIES_STM32G0X) \
378 || defined(CONFIG_SOC_SERIES_STM32L5X) \
379 || defined(CONFIG_SOC_SERIES_STM32H5X)
380 LL_EXTI_ClearRisingFlag_0_31(RTC_EXTI_LINE);
381 #elif defined(CONFIG_SOC_SERIES_STM32U5X)
382 /* in STM32U5 family RTC is not connected to EXTI */
383 #else
384 LL_EXTI_ClearFlag_0_31(RTC_EXTI_LINE);
385 #endif
386 }
387
388
rtc_stm32_init(const struct device * dev)389 static int rtc_stm32_init(const struct device *dev)
390 {
391 const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
392 const struct rtc_stm32_config *cfg = dev->config;
393 struct rtc_stm32_data *data = dev->data;
394
395 data->callback = NULL;
396
397 if (!device_is_ready(clk)) {
398 LOG_ERR("clock control device not ready");
399 return -ENODEV;
400 }
401
402 /* Enable RTC bus clock */
403 if (clock_control_on(clk, (clock_control_subsys_t) &cfg->pclken[0]) != 0) {
404 LOG_ERR("clock op failed\n");
405 return -EIO;
406 }
407
408 /* Enable Backup access */
409 z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY);
410 #if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || \
411 defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP)
412 LL_PWR_EnableBkUpAccess();
413 #endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */
414
415 /* Enable RTC clock source */
416 if (clock_control_configure(clk,
417 (clock_control_subsys_t) &cfg->pclken[1],
418 NULL) != 0) {
419 LOG_ERR("clock configure failed\n");
420 return -EIO;
421 }
422
423 LL_RCC_EnableRTC();
424
425 z_stm32_hsem_unlock(CFG_HW_RCC_SEMID);
426
427 #if !defined(CONFIG_COUNTER_RTC_STM32_SAVE_VALUE_BETWEEN_RESETS)
428 if (LL_RTC_DeInit(RTC) != SUCCESS) {
429 return -EIO;
430 }
431 #endif
432
433 if (LL_RTC_Init(RTC, ((LL_RTC_InitTypeDef *)
434 &cfg->ll_rtc_config)) != SUCCESS) {
435 return -EIO;
436 }
437
438 #ifdef RTC_CR_BYPSHAD
439 LL_RTC_DisableWriteProtection(RTC);
440 LL_RTC_EnableShadowRegBypass(RTC);
441 LL_RTC_EnableWriteProtection(RTC);
442 #endif /* RTC_CR_BYPSHAD */
443
444 #if defined(CONFIG_SOC_SERIES_STM32H7X) && defined(CONFIG_CPU_CORTEX_M4)
445 LL_C2_EXTI_EnableIT_0_31(RTC_EXTI_LINE);
446 LL_EXTI_EnableRisingTrig_0_31(RTC_EXTI_LINE);
447 #elif defined(CONFIG_SOC_SERIES_STM32U5X)
448 /* in STM32U5 family RTC is not connected to EXTI */
449 #else
450 LL_EXTI_EnableIT_0_31(RTC_EXTI_LINE);
451 LL_EXTI_EnableRisingTrig_0_31(RTC_EXTI_LINE);
452 #endif
453
454 rtc_stm32_irq_config(dev);
455
456 return 0;
457 }
458
459 static struct rtc_stm32_data rtc_data;
460
461 #if DT_INST_NUM_CLOCKS(0) == 1
462 #warning STM32 RTC needs a kernel source clock. Please define it in dts file
463 static const struct stm32_pclken rtc_clk[] = {
464 STM32_CLOCK_INFO(0, DT_DRV_INST(0)),
465 /* Use Kconfig to configure source clocks fields (Deprecated) */
466 /* Fortunately, values are consistent across enabled series */
467 #ifdef CONFIG_COUNTER_RTC_STM32_CLOCK_LSE
468 {.bus = STM32_SRC_LSE, .enr = RTC_SEL(1)}
469 #else
470 {.bus = STM32_SRC_LSI, .enr = RTC_SEL(2)}
471 #endif
472 };
473 #else
474 static const struct stm32_pclken rtc_clk[] = STM32_DT_INST_CLOCKS(0);
475 #endif
476
477 static const struct rtc_stm32_config rtc_config = {
478 .counter_info = {
479 .max_top_value = UINT32_MAX,
480 .freq = 1,
481 .flags = COUNTER_CONFIG_INFO_COUNT_UP,
482 .channels = 1,
483 },
484 .ll_rtc_config = {
485 #if !defined(CONFIG_SOC_SERIES_STM32F1X)
486 .HourFormat = LL_RTC_HOURFORMAT_24HOUR,
487 #if DT_INST_CLOCKS_CELL(1, bus) == STM32_SRC_LSI
488 /* prescaler values for LSI @ 32 KHz */
489 .AsynchPrescaler = 0x7F,
490 .SynchPrescaler = 0x00F9,
491 #else /* DT_INST_CLOCKS_CELL(1, bus) == STM32_SRC_LSE */
492 /* prescaler values for LSE @ 32768 Hz */
493 .AsynchPrescaler = 0x7F,
494 .SynchPrescaler = 0x00FF,
495 #endif
496 #else /* CONFIG_SOC_SERIES_STM32F1X */
497 #if DT_INST_CLOCKS_CELL(1, bus) == STM32_SRC_LSI
498 /* prescaler values for LSI @ 40 KHz */
499 .AsynchPrescaler = 0x9C3F,
500 #else /* DT_INST_CLOCKS_CELL(1, bus) == STM32_SRC_LSE */
501 /* prescaler values for LSE @ 32768 Hz */
502 .AsynchPrescaler = 0x7FFF,
503 #endif /* DT_INST_CLOCKS_CELL(1, bus) == STM32_SRC_LSE */
504 .OutPutSource = LL_RTC_CALIB_OUTPUT_NONE,
505 #endif /* CONFIG_SOC_SERIES_STM32F1X */
506 },
507 .pclken = rtc_clk,
508 };
509
510
511 static const struct counter_driver_api rtc_stm32_driver_api = {
512 .start = rtc_stm32_start,
513 .stop = rtc_stm32_stop,
514 .get_value = rtc_stm32_get_value,
515 .set_alarm = rtc_stm32_set_alarm,
516 .cancel_alarm = rtc_stm32_cancel_alarm,
517 .set_top_value = rtc_stm32_set_top_value,
518 .get_pending_int = rtc_stm32_get_pending_int,
519 .get_top_value = rtc_stm32_get_top_value,
520 };
521
522 DEVICE_DT_INST_DEFINE(0, &rtc_stm32_init, NULL,
523 &rtc_data, &rtc_config, PRE_KERNEL_1,
524 CONFIG_COUNTER_INIT_PRIORITY, &rtc_stm32_driver_api);
525
rtc_stm32_irq_config(const struct device * dev)526 static void rtc_stm32_irq_config(const struct device *dev)
527 {
528 IRQ_CONNECT(DT_INST_IRQN(0),
529 DT_INST_IRQ(0, priority),
530 rtc_stm32_isr, DEVICE_DT_INST_GET(0), 0);
531 irq_enable(DT_INST_IRQN(0));
532 }
533