diff --git a/drivers/clock_control/clock_control_silabs_siwx91x.c b/drivers/clock_control/clock_control_silabs_siwx91x.c index 2c8bdcd7c0b..b64654d581f 100644 --- a/drivers/clock_control/clock_control_silabs_siwx91x.c +++ b/drivers/clock_control/clock_control_silabs_siwx91x.c @@ -85,6 +85,10 @@ static int siwx91x_clock_on(const struct device *dev, clock_control_subsys_t sys case SIWX91X_CLK_QSPI: RSI_CLK_Qspi2ClkConfig(M4CLK, QSPI_ULPREFCLK, 0, 0, 0); break; + case SIWX91X_CLK_RTC: + /* Already done in sl_calendar_init()*/ + RSI_PS_NpssPeriPowerUp(SLPSS_PWRGATE_ULP_MCURTC | SLPSS_PWRGATE_ULP_TIMEPERIOD); + break; default: return -EINVAL; } diff --git a/drivers/rtc/CMakeLists.txt b/drivers/rtc/CMakeLists.txt index 703ada100a7..c2f9e90d770 100644 --- a/drivers/rtc/CMakeLists.txt +++ b/drivers/rtc/CMakeLists.txt @@ -35,3 +35,4 @@ zephyr_library_sources_ifdef(CONFIG_RTC_RV8803 rtc_rv8803.c) zephyr_library_sources_ifdef(CONFIG_RTC_BQ32002 rtc_bq32002.c) zephyr_library_sources_ifdef(CONFIG_RTC_RX8130CE rtc_rx8130ce.c) zephyr_library_sources_ifdef(CONFIG_RTC_DS1337 rtc_ds1337.c) +zephyr_library_sources_ifdef(CONFIG_RTC_SILABS_SIWX91X rtc_silabs_siwx91x.c) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index d84003ec3a1..05a08b5c6bb 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -67,5 +67,6 @@ source "drivers/rtc/Kconfig.rv8803" source "drivers/rtc/Kconfig.bq32002" source "drivers/rtc/Kconfig.rx8130ce" source "drivers/rtc/Kconfig.ds1337" +source "drivers/rtc/Kconfig.siwx91x" endif # RTC diff --git a/drivers/rtc/Kconfig.siwx91x b/drivers/rtc/Kconfig.siwx91x new file mode 100644 index 00000000000..eb680683d82 --- /dev/null +++ b/drivers/rtc/Kconfig.siwx91x @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +config RTC_SILABS_SIWX91X + bool "Silabs siwx91x RTC driver" + default y + depends on DT_HAS_SILABS_SIWX91X_RTC_ENABLED + help + Build the RTC driver for the Silabs SIWX91X SoC (Calendar + hardware block as described in the reference manual). diff --git a/drivers/rtc/rtc_silabs_siwx91x.c b/drivers/rtc/rtc_silabs_siwx91x.c new file mode 100644 index 00000000000..7b6bfbc0289 --- /dev/null +++ b/drivers/rtc/rtc_silabs_siwx91x.c @@ -0,0 +1,153 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 Silicon Laboratories Inc. + */ + +#include +#include +#include +#include +#include +#include +#include "rtc_utils.h" +#include "sl_si91x_calendar.h" + +#define DT_DRV_COMPAT silabs_siwx91x_rtc + +LOG_MODULE_REGISTER(siwx91x_rtc, CONFIG_RTC_LOG_LEVEL); + +#define TM_YEAR_REF 1900 +#define SIWX91X_RTC_YEAR_MAX 2399 +#define SIWX91X_RTC_YEAR_MIN 2000 + +struct siwx91x_rtc_config { + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; +}; +struct siwx91x_rtc_data { + struct k_spinlock lock; +}; + +static void rtc_time_to_siwx91x_time_set(const struct rtc_time *tm, + sl_calendar_datetime_config_t *cldr) +{ + int full_year = tm->tm_year + TM_YEAR_REF; + + cldr->Year = (full_year % 100); + cldr->Century = (full_year >= 2000) ? (full_year - 2000) / 100 : 0; + cldr->Month = tm->tm_mon + 1; + cldr->Day = tm->tm_mday; + cldr->DayOfWeek = (RTC_DAY_OF_WEEK_T)tm->tm_wday; + cldr->Hour = tm->tm_hour; + cldr->Minute = tm->tm_min; + cldr->Second = tm->tm_sec; + cldr->MilliSeconds = tm->tm_nsec / NSEC_PER_MSEC; +} + +static void siwx91x_time_to_rtc_time_set(const sl_calendar_datetime_config_t *cldr, + struct rtc_time *tm) +{ + int full_year = 2000 + (cldr->Century * 100) + cldr->Year; + + tm->tm_year = full_year - TM_YEAR_REF; + tm->tm_mon = cldr->Month - 1; + tm->tm_mday = cldr->Day; + tm->tm_wday = (int)cldr->DayOfWeek; + tm->tm_hour = cldr->Hour; + tm->tm_min = cldr->Minute; + tm->tm_sec = cldr->Second; + tm->tm_nsec = cldr->MilliSeconds * NSEC_PER_MSEC; +} + +static int siwx91x_rtc_set_time(const struct device *dev, const struct rtc_time *timeptr) +{ + sl_calendar_datetime_config_t siwx91x_time = {}; + struct siwx91x_rtc_data *data = dev->data; + int year; + int ret; + + year = timeptr->tm_year + TM_YEAR_REF; + if (year < SIWX91X_RTC_YEAR_MIN || year > SIWX91X_RTC_YEAR_MAX) { + return -EINVAL; + } + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + LOG_DBG("Set RTC time: year = %d, mon = %d, mday = %d, wday = %d, hour = %d, " + "min = %d, sec = %d", + timeptr->tm_year, timeptr->tm_mon, timeptr->tm_mday, timeptr->tm_wday, + timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec); + + rtc_time_to_siwx91x_time_set(timeptr, &siwx91x_time); + + ret = sl_si91x_calendar_set_date_time(&siwx91x_time); + if (ret) { + LOG_WRN("Set Timer returned an error - %d!", ret); + } + + k_spin_unlock(&data->lock, key); + + return ret; +} + +static int siwx91x_rtc_get_time(const struct device *dev, struct rtc_time *timeptr) +{ + sl_calendar_datetime_config_t siwx91x_time = {}; + struct siwx91x_rtc_data *data = dev->data; + int ret; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + ret = sl_si91x_calendar_get_date_time(&siwx91x_time); + if (ret != 0) { + LOG_WRN("Get Timer returned an error - %d!", ret); + goto unlock; + } + + siwx91x_time_to_rtc_time_set(&siwx91x_time, timeptr); + + LOG_DBG("get time: year = %d, mon = %d, mday = %d, wday = %d, hour = %d, " + "min = %d, sec = %d", + timeptr->tm_year, timeptr->tm_mon, timeptr->tm_mday, timeptr->tm_wday, + timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec); + +unlock: + k_spin_unlock(&data->lock, key); + + return ret; +} + +static int siwx91x_rtc_init(const struct device *dev) +{ + const struct siwx91x_rtc_config *config = dev->config; + int ret; + + ret = clock_control_on(config->clock_dev, config->clock_subsys); + if (ret) { + return ret; + } + + sl_si91x_calendar_init(); + + return 0; +} + +static DEVICE_API(rtc, siwx91x_rtc_driver_api) = { + .set_time = siwx91x_rtc_set_time, + .get_time = siwx91x_rtc_get_time, +}; + +#define SIWX91X_RTC_INIT(inst) \ + static const struct siwx91x_rtc_config siwx91x_rtc_config_##inst = { \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ + .clock_subsys = (clock_control_subsys_t)DT_INST_PHA(inst, clocks, clkid), \ + }; \ + \ + static struct siwx91x_rtc_data siwx91x_rtc_data##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, &siwx91x_rtc_init, NULL, &siwx91x_rtc_data##inst, \ + &siwx91x_rtc_config_##inst, POST_KERNEL, CONFIG_RTC_INIT_PRIORITY, \ + &siwx91x_rtc_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(SIWX91X_RTC_INIT) diff --git a/dts/bindings/rtc/silabs,siwx91x-rtc.yaml b/dts/bindings/rtc/silabs,siwx91x-rtc.yaml new file mode 100644 index 00000000000..964e51173ed --- /dev/null +++ b/dts/bindings/rtc/silabs,siwx91x-rtc.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Silicon Labatoratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: Silabs Siwx91x RTC (Real-Time Counter) + +compatible: "silabs,siwx91x-rtc" + +include: rtc.yaml + +properties: + reg: + required: true diff --git a/include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h b/include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h index 9c47ccab519..cc9b8740975 100644 --- a/include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h +++ b/include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h @@ -16,5 +16,6 @@ #define SIWX91X_CLK_PWM 9 #define SIWX91X_CLK_GSPI 10 #define SIWX91X_CLK_QSPI 11 +#define SIWX91X_CLK_RTC 12 #endif diff --git a/modules/hal_silabs/wiseconnect/CMakeLists.txt b/modules/hal_silabs/wiseconnect/CMakeLists.txt index db7fe9c3d6a..52a029dedcf 100644 --- a/modules/hal_silabs/wiseconnect/CMakeLists.txt +++ b/modules/hal_silabs/wiseconnect/CMakeLists.txt @@ -49,7 +49,10 @@ zephyr_library_sources( ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/systemlevel/src/rsi_pll.c ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/systemlevel/src/rsi_ulpss_clk.c ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/systemlevel/src/rsi_wwdt.c + ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/systemlevel/src/rsi_rtc.c + ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/systemlevel/src/rsi_time_period.c ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/service/clock_manager/src/sl_si91x_clock_manager.c + ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/unified_api/src/sl_si91x_calendar.c ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/unified_api/src/sl_si91x_driver_gpio.c ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/unified_api/src/sl_si91x_pwm.c ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/unified_peripheral_drivers/src/sl_si91x_peripheral_gpio.c