Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/rtc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ zephyr_library_sources_ifdef(CONFIG_RTC_RV3032 rtc_rv3032.c)
zephyr_library_sources_ifdef(CONFIG_RTC_RV8263 rtc_rv8263.c)
zephyr_library_sources_ifdef(CONFIG_RTC_RV8803 rtc_rv8803.c)
zephyr_library_sources_ifdef(CONFIG_RTC_RX8130CE rtc_rx8130ce.c)
zephyr_library_sources_ifdef(CONFIG_RTC_SF32LB rtc_sf32lb.c)
zephyr_library_sources_ifdef(CONFIG_RTC_SILABS_SIWX91X rtc_silabs_siwx91x.c)
zephyr_library_sources_ifdef(CONFIG_RTC_SMARTBOND rtc_smartbond.c)
zephyr_library_sources_ifdef(CONFIG_RTC_STM32 rtc_ll_stm32.c)
Expand Down
1 change: 1 addition & 0 deletions drivers/rtc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ source "drivers/rtc/Kconfig.rv8803"
source "drivers/rtc/Kconfig.rx8130ce"
source "drivers/rtc/Kconfig.sam"
source "drivers/rtc/Kconfig.sam0"
source "drivers/rtc/Kconfig.sf32lb"
source "drivers/rtc/Kconfig.siwx91x"
source "drivers/rtc/Kconfig.smartbond"
source "drivers/rtc/Kconfig.stm32"
Expand Down
9 changes: 9 additions & 0 deletions drivers/rtc/Kconfig.sf32lb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2025 Qingsong Gou <[email protected]>
# SPDX-License-Identifier: Apache-2.0

config RTC_SF32LB
bool "RTC driver for SF32LB family of MCUs"
default y
depends on DT_HAS_SIFLI_SF32LB_RTC_ENABLED
help
Enable RTC driver for SF32LB series of MCUs
159 changes: 159 additions & 0 deletions drivers/rtc/rtc_sf32lb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
* Copyright (c) 2025 Qingsong Gou <[email protected]>
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT sifli_sf32lb_rtc

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/rtc.h>
#include <zephyr/sys/util.h>
#include <zephyr/logging/log.h>

#include <register.h>

LOG_MODULE_REGISTER(rtc_sf32lb, CONFIG_RTC_LOG_LEVEL);

#define RTC_TR offsetof(RTC_TypeDef, TR)
#define RTC_DR offsetof(RTC_TypeDef, DR)
#define RTC_CR offsetof(RTC_TypeDef, CR)
#define RTC_ISR offsetof(RTC_TypeDef, ISR)
#define RTC_PSCLR offsetof(RTC_TypeDef, PSCLR)
#define RTC_WUTR offsetof(RTC_TypeDef, WUTR)
#define RTC_ALRMTR offsetof(RTC_TypeDef, ALRMTR)
#define RTC_ALRMDR offsetof(RTC_TypeDef, ALRMDR)

struct rtc_sf32lb_config {
uintptr_t base;
};

static int rtc_sf32lb_enter_init_mode(const struct device *dev)
{
const struct rtc_sf32lb_config *config = dev->config;

sys_set_bit(config->base + RTC_ISR, RTC_ISR_INIT_Pos);

while (!sys_test_bit(config->base + RTC_ISR, RTC_ISR_INITF_Pos)) {
}

return 0;
}

static int rtc_sf32lb_exit_init_mode(const struct device *dev)
{
const struct rtc_sf32lb_config *config = dev->config;

sys_clear_bit(config->base + RTC_ISR, RTC_ISR_INIT_Pos);

return 0;
}

static void rtc_sf32lb_wait_for_sync(const struct device *dev)
{
const struct rtc_sf32lb_config *config = dev->config;

sys_clear_bit(config->base + RTC_ISR, RTC_ISR_RSF_Pos);

while (!sys_test_bit(config->base + RTC_ISR, RTC_ISR_RSF_Pos)) {
}
}

static int rtc_sf32lb_set_time(const struct device *dev, const struct rtc_time *timeptr)
{
const struct rtc_sf32lb_config *config = dev->config;
uint32_t tr = 0;
uint32_t dr = 0;

__ASSERT_NO_MSG(timeptr != NULL);

tr = (uint32_t)(((uint32_t)bin2bcd(timeptr->tm_hour) << RTC_TR_HU_Pos) |
((uint32_t)bin2bcd(timeptr->tm_min) << RTC_TR_MNU_Pos) |
((uint32_t)bin2bcd(timeptr->tm_sec) << RTC_TR_SU_Pos));

rtc_sf32lb_enter_init_mode(dev);
sys_write32(tr, config->base + RTC_TR);
rtc_sf32lb_exit_init_mode(dev);

if (timeptr->tm_year < 100) {
dr |= RTC_DR_CB;
dr |= (((uint32_t)bin2bcd(timeptr->tm_year) << RTC_DR_YU_Pos) |
((uint32_t)bin2bcd(timeptr->tm_mon + 1) << RTC_DR_MU_Pos) |
((uint32_t)bin2bcd(timeptr->tm_mday)) |
((uint32_t)timeptr->tm_wday << RTC_DR_WD_Pos));
} else {
dr |= (((uint32_t)bin2bcd(timeptr->tm_year - 100) << RTC_DR_YU_Pos) |
((uint32_t)bin2bcd(timeptr->tm_mon + 1) << RTC_DR_MU_Pos) |
((uint32_t)bin2bcd(timeptr->tm_mday)) |
((uint32_t)timeptr->tm_wday << RTC_DR_WD_Pos));
}

rtc_sf32lb_enter_init_mode(dev);
sys_write32(dr, config->base + RTC_DR);
rtc_sf32lb_exit_init_mode(dev);

if (!sys_test_bit(config->base + RTC_CR, RTC_CR_BYPSHAD_Pos)) {
rtc_sf32lb_wait_for_sync(dev);
}

return 0;
}

static int rtc_sf32lb_get_time(const struct device *dev, struct rtc_time *timeptr)
{
const struct rtc_sf32lb_config *config = dev->config;
uint32_t reg;

__ASSERT_NO_MSG(timeptr != NULL);

reg = sys_read32(config->base + RTC_TR);

timeptr->tm_hour = bcd2bin((uint8_t)((reg & (RTC_TR_HT | RTC_TR_HU)) >> RTC_TR_HU_Pos));
timeptr->tm_min = bcd2bin((uint8_t)((reg & (RTC_TR_MNT | RTC_TR_MNU)) >> RTC_TR_MNU_Pos));
timeptr->tm_sec = bcd2bin((uint8_t)((reg & (RTC_TR_ST | RTC_TR_SU)) >> RTC_TR_SU_Pos));

reg = sys_read32(config->base + RTC_DR);
if (reg & RTC_DR_CB) {
timeptr->tm_year =
bcd2bin((uint8_t)((reg & (RTC_DR_YT | RTC_DR_YU)) >> RTC_DR_YU_Pos));
} else {
timeptr->tm_year =
bcd2bin((uint8_t)((reg & (RTC_DR_YT | RTC_DR_YU)) >> RTC_DR_YU_Pos)) + 100;
}
timeptr->tm_mon = bcd2bin((uint8_t)((reg & (RTC_DR_MT | RTC_DR_MU)) >> RTC_DR_MU_Pos)) - 1;
timeptr->tm_mday = bcd2bin((uint8_t)(reg & (RTC_DR_DT | RTC_DR_DU)));
timeptr->tm_wday = bcd2bin((uint8_t)((reg & (RTC_DR_WD)) >> RTC_DR_WD_Pos));

return 0;
}

static int rtc_sf32lb_init(const struct device *dev)
{
const struct rtc_sf32lb_config *config = dev->config;
uint32_t psclr = 0;

psclr |= (38U << RTC_PSCLR_DIVA_INT_Pos) & RTC_PSCLR_DIVA_INT_Msk;
psclr |= (4608U << RTC_PSCLR_DIVA_FRAC_Pos) & RTC_PSCLR_DIVA_FRAC_Msk;
psclr |= (256U << RTC_PSCLR_DIVB_Pos) & RTC_PSCLR_DIVB_Msk;
sys_write32(psclr, config->base + RTC_PSCLR);

if (!sys_test_bit(config->base + RTC_CR, RTC_CR_BYPSHAD_Pos)) {
rtc_sf32lb_wait_for_sync(dev);
}

return 0;
}

static const struct rtc_driver_api rtc_sf32lb_driver_api = {
.set_time = rtc_sf32lb_set_time,
.get_time = rtc_sf32lb_get_time,
};

#define RTC_SF32LB_INIT(n) \
static const struct rtc_sf32lb_config rtc_sf32lb_config_##n = { \
.base = DT_INST_REG_ADDR(n), \
}; \
DEVICE_DT_INST_DEFINE(n, rtc_sf32lb_init, NULL, NULL, &rtc_sf32lb_config_##n, POST_KERNEL, \
CONFIG_RTC_INIT_PRIORITY, &rtc_sf32lb_driver_api);

DT_INST_FOREACH_STATUS_OKAY(RTC_SF32LB_INIT)