Skip to content

Commit 23e8e3b

Browse files
ck-telecomfabiobaltieri
authored andcommitted
drivers: rtc: sf32lb: add rtc alarm support
Add rtc alarm support for sf32lb platform Signed-off-by: Qingsong Gou <[email protected]>
1 parent f730c7c commit 23e8e3b

File tree

2 files changed

+246
-7
lines changed

2 files changed

+246
-7
lines changed

drivers/rtc/rtc_sf32lb.c

Lines changed: 245 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
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+
4065
struct 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+
4590
static 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+
131344
static 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

136356
static 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

161399
DT_INST_FOREACH_STATUS_OKAY(RTC_SF32LB_DEFINE)

dts/arm/sifli/sf32lb52x.dtsi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@
302302
#size-cells = <1>;
303303
interrupts = <49 0>;
304304
sifli,cfg = <&cfg>;
305+
alarms-count = <1>;
305306
status = "disabled";
306307

307308
backup-registers@30 {

0 commit comments

Comments
 (0)