55
66#define DT_DRV_COMPAT sifli_sf32lb_rtc
77
8+ #include "rtc_utils.h"
9+
810#include <zephyr/arch/cpu.h>
911#include <zephyr/device.h>
1012#include <zephyr/drivers/rtc.h>
@@ -37,11 +39,54 @@ LOG_MODULE_REGISTER(rtc_sf32lb, CONFIG_RTC_LOG_LEVEL);
3739#define RC10K_DIVA_FRAC 4608U
3840#define RC10K_DIVB 256U
3941
42+ #ifdef CONFIG_RTC_ALARM
43+ #define RTC_SF32LB_ALRM_MASK_ALL \
44+ (RTC_ALRMDR_MSKS | RTC_ALRMDR_MSKMN | RTC_ALRMDR_MSKH | \
45+ RTC_ALRMDR_MSKD | RTC_ALRMDR_MSKM | RTC_ALRMDR_MSKWD)
46+
47+ #define RTC_SF32LB_SUPPORTED_ALARM_FIELDS \
48+ (RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR | \
49+ RTC_ALARM_TIME_MASK_WEEKDAY | RTC_ALARM_TIME_MASK_MONTH | RTC_ALARM_TIME_MASK_MONTHDAY)
50+ #endif
51+
52+ #ifdef CONFIG_RTC_ALARM
53+ struct rtc_sf32lb_alarm_cb {
54+ rtc_alarm_callback cb ;
55+ void * user_data ;
56+ };
57+ #endif
58+
59+ struct rtc_sf32lb_data {
60+ #ifdef CONFIG_RTC_ALARM
61+ struct rtc_sf32lb_alarm_cb alarm_cb ;
62+ #endif
63+ };
64+
4065struct rtc_sf32lb_config {
4166 uintptr_t base ;
4267 uintptr_t cfg ;
68+ #ifdef CONFIG_RTC_ALARM
69+ void (* irq_config_func )(void );
70+ uint16_t alarms_count ;
71+ #endif
4372};
4473
74+ static void rtc_irq_handler (const struct device * dev )
75+ {
76+ const struct rtc_sf32lb_config * config = dev -> config ;
77+ struct rtc_sf32lb_data * data = dev -> data ;
78+ uint32_t isr = sys_read32 (config -> base + RTC_ISR );
79+
80+ if (isr & RTC_ISR_ALRMF ) {
81+ sys_clear_bit (config -> base + RTC_ISR , RTC_ISR_ALRMF_Pos );
82+ #ifdef CONFIG_RTC_ALARM
83+ if (data -> alarm_cb .cb ) {
84+ data -> alarm_cb .cb (dev , 0 , data -> alarm_cb .user_data );
85+ }
86+ #endif
87+ }
88+ }
89+
4590static inline int rtc_sf32lb_enter_init_mode (const struct device * dev )
4691{
4792 const struct rtc_sf32lb_config * config = dev -> config ;
@@ -90,9 +135,11 @@ static int rtc_sf32lb_set_time(const struct device *dev, const struct rtc_time *
90135
91136 if (timeptr -> tm_year < 100 ) { /* 20th century */
92137 dr |= RTC_DR_CB ;
138+ dr |= FIELD_PREP (RTC_DR_YT_Msk | RTC_DR_YU_Msk , bin2bcd (timeptr -> tm_year ));
139+ } else {
140+ dr |= FIELD_PREP (RTC_DR_YT_Msk | RTC_DR_YU_Msk , bin2bcd (timeptr -> tm_year - 100 ));
93141 }
94- dr |= FIELD_PREP (RTC_DR_YT_Msk | RTC_DR_YU_Msk , bin2bcd (timeptr -> tm_year )) |
95- FIELD_PREP (RTC_DR_MT_Msk | RTC_DR_MU_Msk , bin2bcd (timeptr -> tm_mon )) |
142+ dr |= FIELD_PREP (RTC_DR_MT_Msk | RTC_DR_MU_Msk , bin2bcd (timeptr -> tm_mon + 1 )) |
96143 FIELD_PREP (RTC_DR_DT_Msk | RTC_DR_DU_Msk , bin2bcd (timeptr -> tm_mday )) |
97144 FIELD_PREP (RTC_DR_WD_Msk , timeptr -> tm_wday );
98145
@@ -120,17 +167,190 @@ static int rtc_sf32lb_get_time(const struct device *dev, struct rtc_time *timept
120167
121168 reg = sys_read32 (config -> cfg + SYS_CFG_RTC_DR );
122169
123- timeptr -> tm_year = bcd2bin (FIELD_GET (RTC_DR_YT_Msk | RTC_DR_YU_Msk , reg ));
124- timeptr -> tm_mon = bcd2bin (FIELD_GET (RTC_DR_MT_Msk | RTC_DR_MU_Msk , reg ));
170+ if (reg & RTC_DR_CB ) { /* 20th century */
171+ timeptr -> tm_year = bcd2bin (FIELD_GET (RTC_DR_YT_Msk | RTC_DR_YU_Msk , reg ));
172+ } else {
173+ timeptr -> tm_year = bcd2bin (FIELD_GET (RTC_DR_YT_Msk | RTC_DR_YU_Msk , reg )) + 100 ;
174+ }
175+ timeptr -> tm_mon = bcd2bin (FIELD_GET (RTC_DR_MT_Msk | RTC_DR_MU_Msk , reg )) - 1 ;
125176 timeptr -> tm_mday = bcd2bin (FIELD_GET (RTC_DR_DT_Msk | RTC_DR_DU_Msk , reg ));
126177 timeptr -> tm_wday = FIELD_GET (RTC_DR_WD_Msk , reg );
127178
128179 return 0 ;
129180}
130181
182+ #ifdef CONFIG_RTC_ALARM
183+ static int rtc_sf32lb_alarm_get_supported_fields (const struct device * dev , uint16_t id ,
184+ uint16_t * mask )
185+ {
186+ ARG_UNUSED (dev );
187+
188+ if (id != 0 ) {
189+ return - EINVAL ;
190+ }
191+
192+ * mask = RTC_SF32LB_SUPPORTED_ALARM_FIELDS ;
193+
194+ return 0 ;
195+ }
196+
197+ static int rtc_sf32lb_alarm_set_time (const struct device * dev , uint16_t id , uint16_t mask ,
198+ const struct rtc_time * timeptr )
199+ {
200+ const struct rtc_sf32lb_config * config = dev -> config ;
201+ uint32_t alarm_tr ;
202+ uint32_t alarm_dr ;
203+ uint32_t alarm_mask = RTC_SF32LB_ALRM_MASK_ALL ;
204+
205+ if (id != 0 ) {
206+ return - EINVAL ;
207+ }
208+
209+ if ((mask > 0 ) && (timeptr == NULL )) {
210+ return - EINVAL ;
211+ }
212+
213+ if ((mask & ~RTC_SF32LB_SUPPORTED_ALARM_FIELDS ) != 0 ) {
214+ LOG_ERR ("unsupported alarm %d field mask 0x%04x" , id , mask );
215+ return - EINVAL ;
216+ }
217+
218+ if (!rtc_utils_validate_rtc_time (timeptr , mask )) {
219+ return - EINVAL ;
220+ }
221+
222+ if (mask == 0 ) {
223+ sys_clear_bits (config -> base + RTC_CR , RTC_CR_ALRME | RTC_CR_ALRMIE );
224+ } else {
225+ alarm_tr = FIELD_PREP (RTC_ALRMTR_HT | RTC_ALRMTR_HU , bin2bcd (timeptr -> tm_hour )) |
226+ FIELD_PREP (RTC_ALRMTR_MNT | RTC_ALRMTR_MNU , bin2bcd (timeptr -> tm_min )) |
227+ FIELD_PREP (RTC_ALRMTR_ST | RTC_ALRMTR_SU , bin2bcd (timeptr -> tm_sec ));
228+
229+ alarm_dr = FIELD_PREP (RTC_ALRMDR_DT | RTC_ALRMDR_DU , bin2bcd (timeptr -> tm_mday )) |
230+ FIELD_PREP (RTC_ALRMDR_MT | RTC_ALRMDR_MU , bin2bcd (timeptr -> tm_mon + 1 )) |
231+ FIELD_PREP (RTC_ALRMDR_WD , timeptr -> tm_wday );
232+
233+ sys_write32 (alarm_tr , config -> base + RTC_ALRMTR );
234+
235+ if (mask & RTC_ALARM_TIME_MASK_HOUR ) {
236+ alarm_mask &= ~RTC_ALRMDR_MSKH ;
237+ }
238+ if (mask & RTC_ALARM_TIME_MASK_MINUTE ) {
239+ alarm_mask &= ~RTC_ALRMDR_MSKMN ;
240+ }
241+ if (mask & RTC_ALARM_TIME_MASK_SECOND ) {
242+ alarm_mask &= ~RTC_ALRMDR_MSKS ;
243+ }
244+ if (mask & RTC_ALARM_TIME_MASK_WEEKDAY ) {
245+ alarm_mask &= ~RTC_ALRMDR_MSKWD ;
246+ }
247+ if (mask & RTC_ALARM_TIME_MASK_MONTH ) {
248+ alarm_mask &= ~RTC_ALRMDR_MSKM ;
249+ }
250+ if (mask & RTC_ALARM_TIME_MASK_MONTHDAY ) {
251+ alarm_mask &= ~RTC_ALRMDR_MSKD ;
252+ }
253+
254+ sys_write32 (alarm_dr | alarm_mask , config -> base + RTC_ALRMDR );
255+ sys_set_bits (config -> base + RTC_CR , RTC_CR_ALRME | RTC_CR_ALRMIE );
256+ }
257+
258+ return 0 ;
259+ }
260+
261+ static int rtc_sf32lb_alarm_get_time (const struct device * dev , uint16_t id , uint16_t * mask ,
262+ struct rtc_time * timeptr )
263+ {
264+ const struct rtc_sf32lb_config * config = dev -> config ;
265+ uint32_t reg ;
266+
267+ if (id != 0 || mask == NULL || timeptr == NULL ) {
268+ return - EINVAL ;
269+ }
270+
271+ reg = sys_read32 (config -> base + RTC_ALRMTR );
272+
273+ timeptr -> tm_hour = bcd2bin (FIELD_GET (RTC_ALRMTR_HT | RTC_ALRMTR_HU , reg ));
274+ timeptr -> tm_min = bcd2bin (FIELD_GET (RTC_ALRMTR_MNT | RTC_ALRMTR_MNU , reg ));
275+ timeptr -> tm_sec = bcd2bin (FIELD_GET (RTC_ALRMTR_ST | RTC_ALRMTR_SU , reg ));
276+
277+ reg = sys_read32 (config -> base + RTC_ALRMDR );
278+
279+ timeptr -> tm_mday = bcd2bin (FIELD_GET (RTC_ALRMDR_DT | RTC_ALRMDR_DU , reg ));
280+ timeptr -> tm_mon = bcd2bin (FIELD_GET (RTC_ALRMDR_MT | RTC_ALRMDR_MU , reg )) - 1 ;
281+ timeptr -> tm_wday = FIELD_GET (RTC_ALRMDR_WD , reg );
282+
283+ * mask = 0U ;
284+
285+ if ((reg & RTC_ALRMDR_MSKH ) == 0 ) {
286+ * mask |= RTC_ALARM_TIME_MASK_HOUR ;
287+ }
288+ if ((reg & RTC_ALRMDR_MSKMN ) == 0 ) {
289+ * mask |= RTC_ALARM_TIME_MASK_MINUTE ;
290+ }
291+ if ((reg & RTC_ALRMDR_MSKS ) == 0 ) {
292+ * mask |= RTC_ALARM_TIME_MASK_SECOND ;
293+ }
294+ if ((reg & RTC_ALRMDR_MSKD ) == 0 ) {
295+ * mask |= RTC_ALARM_TIME_MASK_MONTHDAY ;
296+ }
297+ if ((reg & RTC_ALRMDR_MSKM ) == 0 ) {
298+ * mask |= RTC_ALARM_TIME_MASK_MONTH ;
299+ }
300+ if ((reg & RTC_ALRMDR_MSKWD ) == 0 ) {
301+ * mask |= RTC_ALARM_TIME_MASK_WEEKDAY ;
302+ }
303+
304+ return 0 ;
305+ }
306+
307+ static int rtc_sf32lb_alarm_is_pending (const struct device * dev , uint16_t id )
308+ {
309+ const struct rtc_sf32lb_config * config = dev -> config ;
310+
311+ if (id != 0 ) {
312+ return - EINVAL ;
313+ }
314+
315+ if (sys_test_bit (config -> base + RTC_ISR , RTC_ISR_ALRMF_Pos )) {
316+ sys_clear_bit (config -> base + RTC_ISR , RTC_ISR_ALRMF_Pos );
317+ return 1 ;
318+ }
319+
320+ return 0 ;
321+ }
322+
323+ static int rtc_sf32lb_alarm_set_callback (const struct device * dev , uint16_t id ,
324+ rtc_alarm_callback callback , void * user_data )
325+ {
326+ const struct rtc_sf32lb_config * config = dev -> config ;
327+ struct rtc_sf32lb_data * data = dev -> data ;
328+
329+ if (id != 0 ) {
330+ return - EINVAL ;
331+ }
332+
333+ data -> alarm_cb .cb = callback ;
334+ data -> alarm_cb .user_data = user_data ;
335+
336+ if (callback == NULL ) {
337+ sys_clear_bits (config -> base + RTC_CR , RTC_CR_ALRME | RTC_CR_ALRMIE );
338+ }
339+
340+ return 0 ;
341+ }
342+ #endif /* CONFIG_RTC_ALARM */
343+
131344static DEVICE_API (rtc , rtc_sf32lb_driver_api ) = {
132345 .set_time = rtc_sf32lb_set_time ,
133346 .get_time = rtc_sf32lb_get_time ,
347+ #ifdef CONFIG_RTC_ALARM
348+ .alarm_get_supported_fields = rtc_sf32lb_alarm_get_supported_fields ,
349+ .alarm_set_time = rtc_sf32lb_alarm_set_time ,
350+ .alarm_get_time = rtc_sf32lb_alarm_get_time ,
351+ .alarm_is_pending = rtc_sf32lb_alarm_is_pending ,
352+ .alarm_set_callback = rtc_sf32lb_alarm_set_callback ,
353+ #endif
134354};
135355
136356static int rtc_sf32lb_init (const struct device * dev )
@@ -147,15 +367,33 @@ static int rtc_sf32lb_init(const struct device *dev)
147367 rtc_sf32lb_wait_for_sync (dev );
148368 }
149369
370+ #ifdef CONFIG_RTC_ALARM
371+ if (config -> irq_config_func ) {
372+ config -> irq_config_func ();
373+ }
374+ #endif
150375 return 0 ;
151376}
152377
153378#define RTC_SF32LB_DEFINE (n ) \
379+ static void rtc_sf32lb_irq_config_func_##n(void); \
154380 static const struct rtc_sf32lb_config rtc_sf32lb_config_##n = { \
155381 .base = DT_INST_REG_ADDR(n), \
156382 .cfg = DT_REG_ADDR(DT_INST_PHANDLE(n, sifli_cfg)), \
157- }; \
158- DEVICE_DT_INST_DEFINE(n, rtc_sf32lb_init, NULL, NULL, &rtc_sf32lb_config_##n, POST_KERNEL, \
159- CONFIG_RTC_INIT_PRIORITY, &rtc_sf32lb_driver_api);
383+ IF_ENABLED(CONFIG_RTC_ALARM, \
384+ (.irq_config_func = rtc_sf32lb_irq_config_func_##n,)) \
385+ IF_ENABLED(CONFIG_RTC_ALARM, \
386+ (.alarms_count = DT_INST_PROP(n, alarms_count),)) }; \
387+ static struct rtc_sf32lb_data rtc_sf32lb_data##n; \
388+ DEVICE_DT_INST_DEFINE(n, rtc_sf32lb_init, NULL, &rtc_sf32lb_data##n, \
389+ &rtc_sf32lb_config_##n, POST_KERNEL, CONFIG_RTC_INIT_PRIORITY, \
390+ &rtc_sf32lb_driver_api); \
391+ IF_ENABLED(CONFIG_RTC_ALARM, \
392+ (static void rtc_sf32lb_irq_config_func_##n(void) \
393+ { \
394+ IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), rtc_irq_handler, \
395+ DEVICE_DT_INST_GET(n), 0); \
396+ irq_enable(DT_INST_IRQN(n)); \
397+ }));
160398
161399DT_INST_FOREACH_STATUS_OKAY (RTC_SF32LB_DEFINE )
0 commit comments