diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index f649af13c46e2..13cbcdad98683 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -42,6 +42,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SMARTBOND clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NUMAKER_SCC clock_control_numaker_scc.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NXP_S32 clock_control_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RENESAS_RA_CGC clock_control_renesas_ra_cgc.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RENESAS_RA_SUBCLK clock_control_renesas_ra_cgc_subclk.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RENESAS_RX_ROOT clock_control_renesas_rx_root_cgc.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RENESAS_RX_PLL clock_control_renesas_rx_pll_cgc.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RENESAS_RX_PCLK clock_control_renesas_rx_pclk_cgc.c) diff --git a/drivers/clock_control/Kconfig.renesas_ra_cgc b/drivers/clock_control/Kconfig.renesas_ra_cgc index 806d56fe8fe7f..ec4489b315f33 100644 --- a/drivers/clock_control/Kconfig.renesas_ra_cgc +++ b/drivers/clock_control/Kconfig.renesas_ra_cgc @@ -8,3 +8,14 @@ config CLOCK_CONTROL_RENESAS_RA_CGC depends on HAS_RENESAS_RA_FSP help Enable support for Renesas RA CGC driver. + +if CLOCK_CONTROL_RENESAS_RA_CGC + +config CLOCK_CONTROL_RENESAS_RA_SUBCLK + bool "Renesas RA sub clock source" + default y + depends on DT_HAS_RENESAS_RA_CGC_SUBCLK_ENABLED + help + Enable Renesas RA sub clock driver + +endif diff --git a/drivers/clock_control/clock_control_renesas_ra_cgc_subclk.c b/drivers/clock_control/clock_control_renesas_ra_cgc_subclk.c new file mode 100644 index 0000000000000..76c5169b3a6e7 --- /dev/null +++ b/drivers/clock_control/clock_control_renesas_ra_cgc_subclk.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_ra_cgc_subclk + +#include +#include +#include +#include + +struct clock_control_ra_subclk_cfg { + uint32_t rate; +}; + +static int clock_control_renesas_ra_subclk_on(const struct device *dev, clock_control_subsys_t sys) +{ + ARG_UNUSED(dev); + ARG_UNUSED(sys); + + return -ENOTSUP; +} + +static int clock_control_renesas_ra_subclk_off(const struct device *dev, clock_control_subsys_t sys) +{ + ARG_UNUSED(dev); + ARG_UNUSED(sys); + + return -ENOTSUP; +} + +static int clock_control_renesas_ra_subclk_get_rate(const struct device *dev, + clock_control_subsys_t sys, uint32_t *rate) +{ + const struct clock_control_ra_subclk_cfg *config = dev->config; + + ARG_UNUSED(dev); + ARG_UNUSED(sys); + + *rate = config->rate; + return 0; +} + +static DEVICE_API(clock_control, clock_control_renesas_ra_subclk_api) = { + .on = clock_control_renesas_ra_subclk_on, + .off = clock_control_renesas_ra_subclk_off, + .get_rate = clock_control_renesas_ra_subclk_get_rate, +}; + +#define RENESAS_RA_SUBCLK_INIT(idx) \ + static const struct clock_control_ra_subclk_cfg clock_control_ra_subclk_cfg##idx = { \ + .rate = DT_INST_PROP(idx, clock_frequency), \ + }; \ + DEVICE_DT_INST_DEFINE(idx, NULL, NULL, NULL, &clock_control_ra_subclk_cfg##idx, \ + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \ + &clock_control_renesas_ra_subclk_api); + +DT_INST_FOREACH_STATUS_OKAY(RENESAS_RA_SUBCLK_INIT); diff --git a/drivers/rtc/CMakeLists.txt b/drivers/rtc/CMakeLists.txt index ec726381cee07..6676daba45526 100644 --- a/drivers/rtc/CMakeLists.txt +++ b/drivers/rtc/CMakeLists.txt @@ -27,6 +27,7 @@ zephyr_library_sources_ifdef(CONFIG_RTC_NXP_IRTC rtc_nxp_irtc.c) zephyr_library_sources_ifdef(CONFIG_RTC_PCF2123 rtc_pcf2123.c) zephyr_library_sources_ifdef(CONFIG_RTC_PCF8523 rtc_pcf8523.c) zephyr_library_sources_ifdef(CONFIG_RTC_PCF8563 rtc_pcf8563.c) +zephyr_library_sources_ifdef(CONFIG_RTC_RENESAS_RA rtc_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_RTC_RPI_PICO rtc_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_RTC_RTS5912 rtc_rts5912.c) zephyr_library_sources_ifdef(CONFIG_RTC_RV3028 rtc_rv3028.c) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 8b68524b6b0bb..7897a1f63621b 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -57,6 +57,7 @@ source "drivers/rtc/Kconfig.nxp_irtc" source "drivers/rtc/Kconfig.pcf2123" source "drivers/rtc/Kconfig.pcf8523" source "drivers/rtc/Kconfig.pcf8563" +source "drivers/rtc/Kconfig.renesas_ra" source "drivers/rtc/Kconfig.rpi_pico" source "drivers/rtc/Kconfig.rts5912" source "drivers/rtc/Kconfig.rv3028" diff --git a/drivers/rtc/Kconfig.renesas_ra b/drivers/rtc/Kconfig.renesas_ra new file mode 100644 index 0000000000000..461df785ede79 --- /dev/null +++ b/drivers/rtc/Kconfig.renesas_ra @@ -0,0 +1,12 @@ +# Renesas RA Family + +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config RTC_RENESAS_RA + bool "Renesas RA RTC" + default y + depends on DT_HAS_RENESAS_RA_RTC_ENABLED + select USE_RA_FSP_RTC + help + Enable Renesas RA RTC Driver. diff --git a/drivers/rtc/rtc_renesas_ra.c b/drivers/rtc/rtc_renesas_ra.c new file mode 100644 index 0000000000000..27ef0ed32bde0 --- /dev/null +++ b/drivers/rtc/rtc_renesas_ra.c @@ -0,0 +1,635 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_ra_rtc + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "rtc_utils.h" +#include + +LOG_MODULE_REGISTER(renesas_ra_rtc, CONFIG_RTC_LOG_LEVEL); + +/* Zephyr mask supported by RTC Renesas RA device, values from RTC_ALARM_TIME_MASK */ +#define RTC_RENESAS_RA_SUPPORTED_ALARM_FIELDS \ + (RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR | \ + RTC_ALARM_TIME_MASK_WEEKDAY | RTC_ALARM_TIME_MASK_MONTHDAY | RTC_ALARM_TIME_MASK_MONTH | \ + RTC_ALARM_TIME_MASK_YEAR) + +#define RTC_RENESAS_RA_MAX_ERROR_ADJUSTMENT_VALUE (63) + +/* RTC Renesas RA start year: 2000 */ +#define RTC_RENESAS_RA_YEAR_REF 2000 + +/* struct tm start year: 1900 */ +#define TM_YEAR_REF 1900 + +struct rtc_renesas_ra_config { + void (*irq_config_func)(const struct device *dev); + const struct device *clock_dev; +#ifdef CONFIG_RTC_ALARM + uint16_t alarms_count; +#endif +}; + +struct rtc_renesas_ra_data { + rtc_instance_ctrl_t fsp_ctrl; + rtc_cfg_t fsp_cfg; + rtc_error_adjustment_cfg_t fsp_err_cfg; +#ifdef CONFIG_RTC_ALARM + rtc_alarm_callback alarm_cb; + void *alarm_cb_data; + bool is_alarm_pending; +#endif /* CONFIG_RTC_ALARM */ +#ifdef CONFIG_RTC_UPDATE + rtc_update_callback update_cb; + void *update_cb_data; +#endif /* CONFIG_RTC_UPDATE */ +}; + +/* FSP ISR */ +extern void rtc_alarm_periodic_isr(void); +extern void rtc_carry_isr(void); + +#if defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_UPDATE) +static void renesas_ra_rtc_callback(rtc_callback_args_t *p_args) +{ + const struct device *dev = p_args->p_context; + __maybe_unused struct rtc_renesas_ra_data *data = dev->data; +#ifdef CONFIG_RTC_ALARM + rtc_alarm_callback alarm_cb = data->alarm_cb; + void *alarm_cb_data = data->alarm_cb_data; +#endif /* CONFIG_RTC_ALARM */ + +#ifdef CONFIG_RTC_UPDATE + rtc_update_callback update_cb = data->update_cb; + void *update_cb_data = data->update_cb_data; +#endif /* CONFIG_RTC_UPDATE */ + + if (RTC_EVENT_ALARM_IRQ == p_args->event) { +#ifdef CONFIG_RTC_ALARM + if (alarm_cb) { + data->alarm_cb(dev, RTC_EVENT_ALARM_IRQ, alarm_cb_data); + data->is_alarm_pending = false; + } else { + data->is_alarm_pending = true; + } +#endif /* CONFIG_RTC_ALARM */ + } +#ifdef CONFIG_RTC_UPDATE + else if (RTC_EVENT_PERIODIC_IRQ == p_args->event) { + if (update_cb) { + update_cb(dev, update_cb_data); + } + } +#endif /* CONFIG_RTC_UPDATE */ + else { + LOG_ERR("Invalid callback event"); + } +} +#endif /* CONFIG_RTC_ALARM || CONFIG_RTC_UPDATE */ + +static int rtc_renesas_ra_init(const struct device *dev) +{ + struct rtc_renesas_ra_data *data = dev->data; + const struct rtc_renesas_ra_config *config = dev->config; + const char *clock_dev_name = config->clock_dev->name; + fsp_err_t fsp_err; + uint32_t rate; + int ret; + + if (!device_is_ready(config->clock_dev)) { + return -ENODEV; + } + + if (strcmp(clock_dev_name, "clock-loco") == 0) { + data->fsp_cfg.clock_source = RTC_CLOCK_SOURCE_LOCO; + ret = clock_control_get_rate(config->clock_dev, (clock_control_subsys_t)0, &rate); + if (ret) { + return ret; + } + + /* The RTC time counter operates on a 128-Hz clock signal as the base clock. + * Therefore, when LOCO is selected, LOCO is divided by the prescaler to + * generate a 128-Hz clock signal. Calculation method of frequency + * comparison value: (LOCO clock frequency) / 128 - 1 + */ + data->fsp_cfg.freq_compare_value = (rate / 128) - 1; + } else { + data->fsp_cfg.clock_source = RTC_CLOCK_SOURCE_SUBCLK; + } + +#if defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_UPDATE) + data->fsp_cfg.p_callback = renesas_ra_rtc_callback; + +#if defined(CONFIG_RTC_ALARM) + data->alarm_cb = NULL; + data->alarm_cb_data = NULL; + data->is_alarm_pending = false; +#endif /* CONFIG_RTC_ALARM */ +#if defined(CONFIG_RTC_UPDATE) + data->update_cb = NULL; + data->update_cb_data = NULL; +#endif /* CONFIG_RTC_UPDATE */ + +#else + data->fsp_cfg.p_callback = NULL; +#endif + + fsp_err = R_RTC_Open(&data->fsp_ctrl, &data->fsp_cfg); + if (fsp_err != FSP_SUCCESS) { + LOG_ERR("Failed to initialize the device"); + return -EIO; + } + +#if defined(CONFIG_RENESAS_RA_BATTERY_BACKUP_MANUAL_CONFIGURE) + if (is_backup_domain_reset_happen()) { + R_RTC_ClockSourceSet(&data->fsp_ctrl); + } +#else + if (is_power_on_reset_happen()) { + R_RTC_ClockSourceSet(&data->fsp_ctrl); + } +#endif /* CONFIG_RENESAS_RA_BATTERY_BACKUP_MANUAL_CONFIGURE */ + +#ifdef CONFIG_RTC_UPDATE + fsp_err = R_RTC_PeriodicIrqRateSet(&data->fsp_ctrl, RTC_PERIODIC_IRQ_SELECT_1_SECOND); + if (fsp_err != FSP_SUCCESS) { + LOG_ERR("Failed to configure update interrupt"); + return -EIO; + } +#endif /* CONFIG_RTC_UPDATE */ + + config->irq_config_func(dev); + + return 0; +} + +static int rtc_renesas_ra_set_time(const struct device *dev, const struct rtc_time *timeptr) +{ + struct rtc_renesas_ra_data *data = dev->data; + fsp_err_t fsp_err; + + if (timeptr == NULL) { + LOG_ERR("No pointer is provided to set time"); + return -EINVAL; + } + + if (timeptr->tm_year + TM_YEAR_REF < RTC_RENESAS_RA_YEAR_REF) { + LOG_ERR("RTC time exceeds HW capabilities. Year must be 2000-2099"); + return -EINVAL; + } + + if (!rtc_utils_validate_rtc_time(timeptr, RTC_RENESAS_RA_SUPPORTED_ALARM_FIELDS)) { + LOG_ERR("RTC time is invalid"); + return -EINVAL; + } + + fsp_err = R_RTC_CalendarTimeSet(&data->fsp_ctrl, (struct tm *const)timeptr); + if (fsp_err != FSP_SUCCESS) { + LOG_ERR("Time set operation was not successful."); + return -EIO; + } + + return 0; +} + +static int rtc_renesas_ra_get_time(const struct device *dev, struct rtc_time *timeptr) +{ + struct rtc_renesas_ra_data *data = dev->data; + fsp_err_t fsp_err; + rtc_info_t rtc_info; + + if (timeptr == NULL) { + LOG_ERR("Pointer provided to store the requested time is NULL"); + return -EINVAL; + } + + fsp_err = R_RTC_InfoGet(&data->fsp_ctrl, &rtc_info); + if (fsp_err != FSP_SUCCESS) { + return -EIO; + } + + if (rtc_info.status != RTC_STATUS_RUNNING) { + LOG_ERR("RTC time has not been set"); + return -ENODATA; + } + + fsp_err = R_RTC_CalendarTimeGet(&data->fsp_ctrl, rtc_time_to_tm(timeptr)); + if (fsp_err != FSP_SUCCESS) { + return -EIO; + } + + /* value for unsupported fields */ + timeptr->tm_yday = -1; + timeptr->tm_isdst = -1; + timeptr->tm_nsec = 0; + + return 0; +} + +#ifdef CONFIG_RTC_ALARM +static int rtc_renesas_ra_alarm_get_supported_fields(const struct device *dev, uint16_t id, + uint16_t *mask) +{ + const struct rtc_renesas_ra_config *config = dev->config; + + if (mask == NULL) { + LOG_ERR("Mask pointer is NULL"); + return -EINVAL; + } + + if (id > config->alarms_count) { + LOG_ERR("Invalid alarm ID %d", id); + return -EINVAL; + } + + *mask = (uint16_t)RTC_RENESAS_RA_SUPPORTED_ALARM_FIELDS; + + return 0; +} + +#define ALARM_FIELD_CHECK_ENABLE(mask, field) (mask & field) + +static int rtc_renesas_ra_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask, + const struct rtc_time *timeptr) +{ + struct rtc_renesas_ra_data *data = dev->data; + const struct rtc_renesas_ra_config *config = dev->config; + fsp_err_t fsp_err; + rtc_alarm_time_t fsp_alarm_cfg; + + if ((timeptr == NULL) && (mask != 0)) { + LOG_ERR("No pointer is provided to set alarm"); + return -EINVAL; + } + + if (id > config->alarms_count) { + LOG_ERR("Invalid alarm ID %d", id); + return -EINVAL; + } + + if (mask & ~RTC_RENESAS_RA_SUPPORTED_ALARM_FIELDS) { + LOG_ERR("Invalid alarm mask"); + return -EINVAL; + } + + if (mask > 0) { + if (!rtc_utils_validate_rtc_time(timeptr, mask)) { + LOG_ERR("Invalid alarm fields values"); + return -EINVAL; + } + + fsp_alarm_cfg.time.tm_sec = timeptr->tm_sec; + fsp_alarm_cfg.time.tm_min = timeptr->tm_min; + fsp_alarm_cfg.time.tm_hour = timeptr->tm_hour; + fsp_alarm_cfg.time.tm_mday = timeptr->tm_mday; + fsp_alarm_cfg.time.tm_mon = timeptr->tm_mon; + fsp_alarm_cfg.time.tm_year = timeptr->tm_year; + fsp_alarm_cfg.time.tm_wday = timeptr->tm_wday; + } + + fsp_alarm_cfg.channel = id; + fsp_alarm_cfg.sec_match = ALARM_FIELD_CHECK_ENABLE(mask, RTC_ALARM_TIME_MASK_SECOND); + fsp_alarm_cfg.min_match = ALARM_FIELD_CHECK_ENABLE(mask, RTC_ALARM_TIME_MASK_MINUTE); + fsp_alarm_cfg.hour_match = ALARM_FIELD_CHECK_ENABLE(mask, RTC_ALARM_TIME_MASK_HOUR); + fsp_alarm_cfg.mday_match = ALARM_FIELD_CHECK_ENABLE(mask, RTC_ALARM_TIME_MASK_MONTHDAY); + fsp_alarm_cfg.mon_match = ALARM_FIELD_CHECK_ENABLE(mask, RTC_ALARM_TIME_MASK_MONTH); + fsp_alarm_cfg.year_match = ALARM_FIELD_CHECK_ENABLE(mask, RTC_ALARM_TIME_MASK_YEAR); + fsp_alarm_cfg.dayofweek_match = ALARM_FIELD_CHECK_ENABLE(mask, RTC_ALARM_TIME_MASK_WEEKDAY); + + fsp_err = R_RTC_CalendarAlarmSet(&data->fsp_ctrl, &fsp_alarm_cfg); + if (fsp_err != FSP_SUCCESS) { + LOG_ERR("Alarm time set is not successful!"); + return -EIO; + } + + return 0; +} + +static int rtc_renesas_ra_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask, + struct rtc_time *timeptr) +{ + struct rtc_renesas_ra_data *data = dev->data; + const struct rtc_renesas_ra_config *config = dev->config; + fsp_err_t fsp_err; + rtc_alarm_time_t fsp_alarm_cfg; + + if ((mask == NULL) || (timeptr == NULL)) { + LOG_ERR("No pointer is provided to store the requested alarm time/mask"); + return -EINVAL; + } + + if (id > config->alarms_count) { + LOG_ERR("Invalid alarm ID %d", id); + return -EINVAL; + } + + fsp_err = R_RTC_CalendarAlarmGet(&data->fsp_ctrl, &fsp_alarm_cfg); + if (fsp_err != FSP_SUCCESS) { + LOG_ERR("Alarm time get is not successful!"); + return -EIO; + } + + timeptr->tm_sec = fsp_alarm_cfg.time.tm_sec; + timeptr->tm_min = fsp_alarm_cfg.time.tm_min; + timeptr->tm_hour = fsp_alarm_cfg.time.tm_hour; + timeptr->tm_mday = fsp_alarm_cfg.time.tm_mday; + timeptr->tm_mon = fsp_alarm_cfg.time.tm_mon; + timeptr->tm_year = fsp_alarm_cfg.time.tm_year; + timeptr->tm_wday = fsp_alarm_cfg.time.tm_wday; + + /* value for unsupported fields */ + timeptr->tm_yday = -1; + timeptr->tm_isdst = -1; + timeptr->tm_nsec = 0; + + *mask = 0; + + if (fsp_alarm_cfg.sec_match) { + *mask |= RTC_ALARM_TIME_MASK_SECOND; + } + if (fsp_alarm_cfg.min_match) { + *mask |= RTC_ALARM_TIME_MASK_MINUTE; + } + if (fsp_alarm_cfg.hour_match) { + *mask |= RTC_ALARM_TIME_MASK_HOUR; + } + if (fsp_alarm_cfg.mday_match) { + *mask |= RTC_ALARM_TIME_MASK_MONTHDAY; + } + if (fsp_alarm_cfg.mon_match) { + *mask |= RTC_ALARM_TIME_MASK_MONTH; + } + if (fsp_alarm_cfg.year_match) { + *mask |= RTC_ALARM_TIME_MASK_YEAR; + } + if (fsp_alarm_cfg.dayofweek_match) { + *mask |= RTC_ALARM_TIME_MASK_WEEKDAY; + } + + return 0; +} + +static int rtc_renesas_ra_alarm_set_callback(const struct device *dev, uint16_t id, + rtc_alarm_callback callback, void *user_data) +{ + struct rtc_renesas_ra_data *data = dev->data; + const struct rtc_renesas_ra_config *config = dev->config; + unsigned int key; + + if (id > config->alarms_count) { + LOG_ERR("invalid alarm ID %d", id); + return -EINVAL; + } + + key = irq_lock(); + data->alarm_cb = callback; + data->alarm_cb_data = user_data; + irq_unlock(key); + + return 0; +} + +static int rtc_renesas_ra_alarm_is_pending(const struct device *dev, uint16_t id) +{ + struct rtc_renesas_ra_data *data = dev->data; + const struct rtc_renesas_ra_config *config = dev->config; + unsigned int key; + int ret; + + if (id > config->alarms_count) { + LOG_ERR("invalid alarm ID %d", id); + return -EINVAL; + } + + key = irq_lock(); + ret = data->is_alarm_pending ? 1 : 0; + data->is_alarm_pending = false; + irq_unlock(key); + + return ret; +} + +#endif /* CONFIG_RTC_ALARM */ + +#ifdef CONFIG_RTC_UPDATE +static int rtc_renesas_ra_update_set_callback(const struct device *dev, + rtc_update_callback callback, void *user_data) +{ + struct rtc_renesas_ra_data *data = dev->data; + unsigned int key; + + key = irq_lock(); + data->update_cb = callback; + data->update_cb_data = user_data; + irq_unlock(key); + + return 0; +} +#endif /* CONFIG_RTC_UPDATE */ + +#ifdef CONFIG_RTC_CALIBRATION + +/* Convert number of clock cycles added or removed in 10 seconds or 1 minute + * For each 10 second (total 327,680 clock cycles): + * ppb = cycles * 10^9 / total_cycles = cycles * 10^9 / 327,680 + * = cycles * 390625 / 128 + */ +#define CYCLES_TO_PPB_EACH_10_SECOND(cycles) DIV_ROUND_CLOSEST((cycles) * 390625, 128) + +/* For each 1 minute (total 1,966,080 clock cycles): + * ppb = cycles * 10^9 / total_cycles = cycles * 10^9 / 1,966,080 + * = cycles * 390625 / 768 + */ +#define CYCLES_TO_PPB_EACH_1_MINUTE(cycles) DIV_ROUND_CLOSEST((cycles) * 390625, 768) + +/* Convert part per billion calibration value to a number of clock cycles added or removed + * to part per billion calibration value. + * For each 10 second (total 327,680 clock cycles): + * cycles = ppb * total_cycles / 10^9 = ppb * 327,680 / 10^9 + * = ppb * 128 / 390625 + */ +#define PPB_TO_CYCLES_PER_10_SECOND(ppb) DIV_ROUND_CLOSEST((ppb) * 128, 390625) +/* + * For each 1 minute (total 1,966,080 clock cycles): + * cycles = ppb * total_cycles / 10^9 = ppb * 1,966,080 / 10^9 + * = ppb * 768 / 390625 + */ +#define PPB_TO_CYCLES_PER_1_MINUTE(ppb) DIV_ROUND_CLOSEST((ppb) * 768, 390625) + +static int rtc_renesas_ra_set_calibration(const struct device *dev, int32_t calibration) +{ + struct rtc_renesas_ra_data *data = dev->data; + fsp_err_t fsp_err; + uint32_t adjustment_cycles = 0; + uint32_t adjustment_cycles_ten_seconds = 0; + uint32_t adjustment_cycles_one_minute = 0; + int32_t abs_calibration = abs(calibration); + + /* Calibration is not available while using the LOCO clock */ + if (data->fsp_cfg.clock_source == RTC_CLOCK_SOURCE_LOCO) { + LOG_DBG("Calibration is not available while using the LOCO clock"); + return -ENOTSUP; + } + + if (calibration == 0) { + data->fsp_err_cfg.adjustment_type = RTC_ERROR_ADJUSTMENT_NONE; + data->fsp_err_cfg.adjustment_value = 0; + } else { + adjustment_cycles_ten_seconds = PPB_TO_CYCLES_PER_10_SECOND(abs_calibration); + adjustment_cycles_one_minute = PPB_TO_CYCLES_PER_1_MINUTE(abs_calibration); + + if ((adjustment_cycles_ten_seconds > RTC_RENESAS_RA_MAX_ERROR_ADJUSTMENT_VALUE) && + (adjustment_cycles_one_minute > RTC_RENESAS_RA_MAX_ERROR_ADJUSTMENT_VALUE)) { + LOG_ERR("Calibration out of HW range"); + return -EINVAL; + } + + /* 1 minute period has low range part per bilion than 10 minute period when transfer + * from ppb to cycles. So check it first. + */ + if (adjustment_cycles_one_minute > RTC_RENESAS_RA_MAX_ERROR_ADJUSTMENT_VALUE) { + adjustment_cycles = adjustment_cycles_ten_seconds; + data->fsp_err_cfg.adjustment_period = RTC_ERROR_ADJUSTMENT_PERIOD_10_SECOND; + } else { + int32_t err_ten_seconds = + abs(CYCLES_TO_PPB_EACH_10_SECOND(adjustment_cycles_ten_seconds) - + abs_calibration); + int32_t err_one_minute = + abs(CYCLES_TO_PPB_EACH_1_MINUTE(adjustment_cycles_one_minute) - + abs_calibration); + LOG_DBG("10 sendconds error: %d; 1 minute error: %d", err_ten_seconds, + err_one_minute); + + if (err_one_minute < err_ten_seconds) { + data->fsp_err_cfg.adjustment_period = + RTC_ERROR_ADJUSTMENT_PERIOD_1_MINUTE; + adjustment_cycles = adjustment_cycles_one_minute; + } else { + data->fsp_err_cfg.adjustment_period = + RTC_ERROR_ADJUSTMENT_PERIOD_10_SECOND; + adjustment_cycles = adjustment_cycles_ten_seconds; + } + } + + data->fsp_err_cfg.adjustment_type = + (calibration > 0) ? RTC_ERROR_ADJUSTMENT_ADD_PRESCALER + : RTC_ERROR_ADJUSTMENT_SUBTRACT_PRESCALER; + data->fsp_err_cfg.adjustment_value = adjustment_cycles; + } + + data->fsp_err_cfg.adjustment_mode = RTC_ERROR_ADJUSTMENT_MODE_AUTOMATIC; + fsp_err = R_RTC_ErrorAdjustmentSet(&data->fsp_ctrl, &data->fsp_err_cfg); + if (fsp_err != FSP_SUCCESS) { + return -EIO; + } + + return 0; +} + +#endif /* CONFIG_RTC_CALIBRATION */ + +static DEVICE_API(rtc, rtc_renesas_ra_driver_api) = { + .set_time = rtc_renesas_ra_set_time, + .get_time = rtc_renesas_ra_get_time, +#ifdef CONFIG_RTC_ALARM + .alarm_get_supported_fields = rtc_renesas_ra_alarm_get_supported_fields, + .alarm_set_time = rtc_renesas_ra_alarm_set_time, + .alarm_get_time = rtc_renesas_ra_alarm_get_time, + .alarm_set_callback = rtc_renesas_ra_alarm_set_callback, + .alarm_is_pending = rtc_renesas_ra_alarm_is_pending, +#endif /* CONFIG_RTC_ALARM */ +#ifdef CONFIG_RTC_UPDATE + .update_set_callback = rtc_renesas_ra_update_set_callback, +#endif /* CONFIG_RTC_UPDATE */ +#ifdef CONFIG_RTC_CALIBRATION + .set_calibration = rtc_renesas_ra_set_calibration, +#endif /* CONFIG_RTC_CALIBRATION */ +}; + +#define RTC_RENESAS_RA_ALARM_COUNT_GET(index) \ + IF_ENABLED(CONFIG_RTC_ALARM, \ + (.alarms_count = DT_INST_PROP(index, alarms_count),)) + +#define RTC_RENESAS_RA_CALIBRATION_MODE \ + COND_CODE_1(CONFIG_RTC_CALIBRATION, (RTC_ERROR_ADJUSTMENT_MODE_AUTOMATIC), \ + (RTC_ERROR_ADJUSTMENT_MODE_MANUAL)) + +#define RTC_RENESAS_RA_CALIBRATION_PERIOD \ + COND_CODE_1(CONFIG_RTC_CALIBRATION, (RTC_ERROR_ADJUSTMENT_PERIOD_1_MINUTE), \ + (RTC_ERROR_ADJUSTMENT_PERIOD_NONE)) + +#define RTC_RENESAS_RA_IRQ_GET(id, name, cell) \ + COND_CODE_1(DT_INST_IRQ_HAS_NAME(id, name), \ + (DT_INST_IRQ_BY_NAME(id, name, cell)), \ + ((IRQn_Type) BSP_IRQ_DISABLED)) + +#define ALARM_IRQ_ENABLE(index) \ + R_ICU->IELSR[DT_INST_IRQ_BY_NAME(index, alm, irq)] = ELC_EVENT_RTC_ALARM; \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(index, alm, irq), \ + DT_INST_IRQ_BY_NAME(index, alm, priority), rtc_alarm_periodic_isr, (NULL), 0); + +#define PERODIC_IRQ_ENABLE(index) \ + R_ICU->IELSR[DT_INST_IRQ_BY_NAME(index, prd, irq)] = ELC_EVENT_RTC_PERIOD; \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(index, prd, irq), \ + DT_INST_IRQ_BY_NAME(index, prd, priority), rtc_alarm_periodic_isr, (NULL), 0); + +#define ALARM_IRQ_INIT(index) IF_ENABLED(CONFIG_RTC_ALARM, (ALARM_IRQ_ENABLE(index))) +#define PERODIC_IRQ_INIT(index) IF_ENABLED(CONFIG_RTC_UPDATE, (PERODIC_IRQ_ENABLE(index))) + +#define RTC_RENESAS_RA_INIT(index) \ + static void rtc_renesas_ra_irq_config_func##index(const struct device *dev) \ + { \ + R_ICU->IELSR[DT_INST_IRQ_BY_NAME(index, cup, irq)] = ELC_EVENT_RTC_CARRY; \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(index, cup, irq), \ + DT_INST_IRQ_BY_NAME(index, cup, priority), rtc_carry_isr, (NULL), 0); \ + irq_enable(DT_INST_IRQ_BY_NAME(index, cup, irq)); \ + \ + ALARM_IRQ_INIT(index) \ + PERODIC_IRQ_INIT(index) \ + } \ + static const struct rtc_renesas_ra_config rtc_renesas_ra_config_##index = { \ + .irq_config_func = rtc_renesas_ra_irq_config_func##index, \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(index)), \ + RTC_RENESAS_RA_ALARM_COUNT_GET(index)}; \ + static struct rtc_renesas_ra_data rtc_renesas_ra_data_##index = { \ + .fsp_err_cfg = \ + { \ + .adjustment_mode = RTC_RENESAS_RA_CALIBRATION_MODE, \ + .adjustment_period = RTC_RENESAS_RA_CALIBRATION_PERIOD, \ + .adjustment_type = RTC_ERROR_ADJUSTMENT_NONE, \ + .adjustment_value = 0x00, \ + }, \ + .fsp_cfg = \ + { \ + .p_err_cfg = &rtc_renesas_ra_data_##index.fsp_err_cfg, \ + .alarm_irq = RTC_RENESAS_RA_IRQ_GET(index, alm, irq), \ + .alarm_ipl = RTC_RENESAS_RA_IRQ_GET(index, alm, priority), \ + .periodic_irq = RTC_RENESAS_RA_IRQ_GET(index, prd, irq), \ + .periodic_ipl = RTC_RENESAS_RA_IRQ_GET(index, prd, priority), \ + .carry_irq = RTC_RENESAS_RA_IRQ_GET(index, cup, irq), \ + .carry_irq = RTC_RENESAS_RA_IRQ_GET(index, cup, priority), \ + .p_context = (void *)DEVICE_DT_INST_GET(index), \ + .p_extend = NULL, \ + }, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(index, &rtc_renesas_ra_init, NULL, &rtc_renesas_ra_data_##index, \ + &rtc_renesas_ra_config_##index, PRE_KERNEL_1, \ + CONFIG_RTC_INIT_PRIORITY, &rtc_renesas_ra_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(RTC_RENESAS_RA_INIT) diff --git a/dts/arm/renesas/ra/ra4/r7fa4l1bx.dtsi b/dts/arm/renesas/ra/ra4/r7fa4l1bx.dtsi index 8eaeda35f91c8..bc5e8987afb13 100644 --- a/dts/arm/renesas/ra/ra4/r7fa4l1bx.dtsi +++ b/dts/arm/renesas/ra/ra4/r7fa4l1bx.dtsi @@ -559,6 +559,14 @@ status = "disabled"; }; + rtc: rtc@40083000 { + compatible = "renesas,ra-rtc"; + reg = <40083000 0x80>; + clocks = <&subclk>; + alarms-count = <1>; + status = "disabled"; + }; + option_setting_ofs_conf: option-setting-ofs-conf@100a100 { compatible = "zephyr,memory-region"; reg = <0x0100a100 0x200>; diff --git a/dts/arm/renesas/ra/ra8/r7fa8t1xh.dtsi b/dts/arm/renesas/ra/ra8/r7fa8t1xh.dtsi index c4b6ac5935eba..e13515f37a68b 100644 --- a/dts/arm/renesas/ra/ra8/r7fa8t1xh.dtsi +++ b/dts/arm/renesas/ra/ra8/r7fa8t1xh.dtsi @@ -10,6 +10,7 @@ /delete-node/ &i2s0; /delete-node/ &i2s1; +/delete-node/ &battery_backup; / { clocks: clocks { diff --git a/dts/arm/renesas/ra/ra8/ra8x1.dtsi b/dts/arm/renesas/ra/ra8/ra8x1.dtsi index 20d102e11fb02..c25b91ef0d3ee 100644 --- a/dts/arm/renesas/ra/ra8/ra8x1.dtsi +++ b/dts/arm/renesas/ra/ra8/ra8x1.dtsi @@ -57,7 +57,29 @@ system: system@4001e000 { compatible = "renesas,ra-system"; reg = <0x4001e000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; status = "okay"; + + battery_backup: battery-backup@3b0{ + compatible = "renesas,ra-battery-backup"; + reg = <0x3b0 0x2>, <0x3d0 0x4>, + <0xa84 0x1>, <0xa88 0x1>, + <0xc40 0x1>, <0xc45 0x1>, + <0xc46 0x1>, <0xc48 0x1>, + <0xc49 0x1>, <0xc4a 0x1>, + <0xc4c 0x1>, <0xc4d 0x1>, + <0xc4e 0x1>, <0xd00 0x80>; + reg-names = "vbrsabar", "bbfsar", + "vbattmnselr", "vbtbpcr1", + "vbtber", "vbtbpcr2", + "vbtbpsr", "vbtadsr", + "vbtadcr1", "vbtadcr2", + "vbtictlr", "vbtictlr2", + "vbtimonr" , "vbtbkrn"; + manual-configure; + status = "disabled"; + }; }; elc: elc@40201000 { @@ -928,6 +950,14 @@ status = "disabled"; }; + rtc: rtc@40202000 { + compatible = "renesas,ra-rtc"; + reg = <0x40202000 0x80>; + clocks = <&subclk>; + alarms-count = <1>; + status = "disabled"; + }; + option_setting_ofs_cf_sec: option-setting-ofs-cf-sec@300a100 { compatible = "zephyr,memory-region"; reg = <0x0300a100 0x200>; @@ -996,7 +1026,6 @@ status = "okay"; }; }; - }; usbfs_phy: usbfs-phy { diff --git a/dts/arm/renesas/ra/ra8/ra8x2.dtsi b/dts/arm/renesas/ra/ra8/ra8x2.dtsi index aedc3a0beff2c..3092e46a3813a 100644 --- a/dts/arm/renesas/ra/ra8/ra8x2.dtsi +++ b/dts/arm/renesas/ra/ra8/ra8x2.dtsi @@ -69,7 +69,29 @@ system: system@4001e000 { compatible = "renesas,ra-system"; reg = <0x4001e000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; status = "okay"; + + battery_backup: battery-backup@3b0{ + compatible = "renesas,ra-battery-backup"; + reg = <0x3b0 0x2>, <0x3d0 0x4>, + <0xa84 0x1>, <0xa88 0x1>, + <0xc40 0x1>, <0xc45 0x1>, + <0xc46 0x1>, <0xc48 0x1>, + <0xc49 0x1>, <0xc4a 0x1>, + <0xc4c 0x1>, <0xc4d 0x1>, + <0xc4e 0x1>, <0xd00 0x80>; + reg-names = "vbrsabar", "bbfsar", + "vbattmnselr", "vbtbpcr1", + "vbtber", "vbtbpcr2", + "vbtbpsr", "vbtadsr", + "vbtadcr1", "vbtadcr2", + "vbtictlr", "vbtictlr2", + "vbtimonr" , "vbtbkrn"; + manual-configure; + status = "disabled"; + }; }; pinctrl: pin-controller@40400800 { @@ -1040,6 +1062,14 @@ status = "disabled"; }; + rtc: rtc@40202000 { + compatible = "renesas,ra-rtc"; + reg = <0x40202000 0x80>; + clocks = <&subclk>; + alarms-count = <1>; + status = "disabled"; + }; + option_setting_ofs_conf_sec: option-setting-ofs-conf-sec@2c9f040 { compatible = "zephyr,memory-region"; reg = <0x02c9f040 0x3c0>; diff --git a/dts/bindings/power/renesas,ra-battery-backup.yaml b/dts/bindings/power/renesas,ra-battery-backup.yaml new file mode 100644 index 0000000000000..245c0e4d7f5bf --- /dev/null +++ b/dts/bindings/power/renesas,ra-battery-backup.yaml @@ -0,0 +1,38 @@ +description: Renesas RA battery backup domain + +compatible: "renesas,ra-battery-backup" + +include: base.yaml + +properties: + reg: + required: true + + reg-names: + required: true + + switch-threshold: + type: string + enum: + - "2.80V" + - "2.53V" + - "2.10V" + - "1.95V" + - "1.85V" + - "1.75V" + description: | + VBATT detection threshold (VDETLVL). Below this threshold, + battery backup domain will change from VCC to VBATT. Here is + an example of configuring it: + + &battery_backup { + switch-threshold = "2.10V"; + status = "okay"; + }; + + manual-configure: + type: boolean + description: | + Battery backup need to configure to use. + For those do not have this property, hardware + is automatically switch. diff --git a/dts/bindings/rtc/renesas,ra-rtc.yaml b/dts/bindings/rtc/renesas,ra-rtc.yaml new file mode 100644 index 0000000000000..c64e74db4e1ed --- /dev/null +++ b/dts/bindings/rtc/renesas,ra-rtc.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RA RTC + +compatible: "renesas,ra-rtc" + +include: + - rtc.yaml + - rtc-device.yaml + +properties: + reg: + required: true + + clocks: + required: true + + interrupts: + required: true + + interrupt-names: + required: true + enum: + - "cup" + - "prd" + - "alm" + description: | + - "cup": carry interrupt + - "prd": perodic interrupt + - "alm": alarm interrupt diff --git a/modules/Kconfig.renesas b/modules/Kconfig.renesas index 11fea132c319d..d0c89b07bebec 100644 --- a/modules/Kconfig.renesas +++ b/modules/Kconfig.renesas @@ -218,6 +218,11 @@ config USE_RA_FSP_TOUCH help Enable RA FSP TOUCH library +config USE_RA_FSP_RTC + bool + help + Enable RA FSP RTC driver + endif # HAS_RENESAS_RA_FSP if HAS_RENESAS_RZ_FSP diff --git a/samples/drivers/rtc/boards/ek_ra4l1.overlay b/samples/drivers/rtc/boards/ek_ra4l1.overlay new file mode 100644 index 0000000000000..89b258c05cbf8 --- /dev/null +++ b/samples/drivers/rtc/boards/ek_ra4l1.overlay @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; + +&rtc { + interrupts = <63 1>; + interrupt-names = "cup"; + status = "okay"; +}; diff --git a/samples/drivers/rtc/boards/ek_ra8d1.overlay b/samples/drivers/rtc/boards/ek_ra8d1.overlay new file mode 100644 index 0000000000000..58ff24717860c --- /dev/null +++ b/samples/drivers/rtc/boards/ek_ra8d1.overlay @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; + +&rtc { + interrupts = <95 1>; + interrupt-names = "cup"; + status = "okay"; +}; diff --git a/samples/drivers/rtc/boards/ek_ra8m1.overlay b/samples/drivers/rtc/boards/ek_ra8m1.overlay new file mode 100644 index 0000000000000..58ff24717860c --- /dev/null +++ b/samples/drivers/rtc/boards/ek_ra8m1.overlay @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; + +&rtc { + interrupts = <95 1>; + interrupt-names = "cup"; + status = "okay"; +}; diff --git a/samples/drivers/rtc/boards/ek_ra8p1_r7ka8p1kflcac_cm85.overlay b/samples/drivers/rtc/boards/ek_ra8p1_r7ka8p1kflcac_cm85.overlay new file mode 100644 index 0000000000000..58ff24717860c --- /dev/null +++ b/samples/drivers/rtc/boards/ek_ra8p1_r7ka8p1kflcac_cm85.overlay @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; + +&rtc { + interrupts = <95 1>; + interrupt-names = "cup"; + status = "okay"; +}; diff --git a/soc/renesas/ra/CMakeLists.txt b/soc/renesas/ra/CMakeLists.txt index b6f913513a341..a7b5d2c2dc5b0 100644 --- a/soc/renesas/ra/CMakeLists.txt +++ b/soc/renesas/ra/CMakeLists.txt @@ -5,4 +5,5 @@ zephyr_include_directories(common) zephyr_include_directories_ifdef(CONFIG_HAS_RENESAS_RA_FSP common_fsp) +add_subdirectory_ifdef(CONFIG_HAS_RENESAS_RA_FSP common_fsp) add_subdirectory(${SOC_SERIES}) diff --git a/soc/renesas/ra/Kconfig b/soc/renesas/ra/Kconfig index f7fb24c03f4c3..91d421875c152 100644 --- a/soc/renesas/ra/Kconfig +++ b/soc/renesas/ra/Kconfig @@ -24,4 +24,12 @@ config CPU_HAS_RENESAS_RA_IDAU rsource "*/Kconfig" +config RENESAS_RA_BATTERY_BACKUP_MANUAL_CONFIGURE + bool "VBAT switching manual" + default y + depends on DT_HAS_RENESAS_RA_BATTERY_BACKUP_ENABLED && $(dt_compat_any_has_prop,$(DT_COMPAT_RENESAS_RA_BATTERY_BACKUP),manual-configure) + help + Enable if this SoC's battery backup domain allows switching to VBAT manually. + Leave disabled if switching is automatic. + endif # SOC_FAMILY_RENESAS_RA diff --git a/soc/renesas/ra/common_fsp/CMakeLists.txt b/soc/renesas/ra/common_fsp/CMakeLists.txt new file mode 100644 index 0000000000000..5e407d6d50eae --- /dev/null +++ b/soc/renesas/ra/common_fsp/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_RENESAS_RA_BATTERY_BACKUP_MANUAL_CONFIGURE battery_backup.c) +zephyr_sources(cold_start.c) diff --git a/soc/renesas/ra/common_fsp/battery_backup.c b/soc/renesas/ra/common_fsp/battery_backup.c new file mode 100644 index 0000000000000..741337a53953c --- /dev/null +++ b/soc/renesas/ra/common_fsp/battery_backup.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "battery_backup.h" + +#define VCC_DROP_DETECTION_STABILIZATION_WAIT_TIME_US 20 +#define VBTBPSR_VBPORF_IS_SET BIT(0) +#define VBTBPCR2_VDETLVL_SETTING_NOT_USED 0x6 + +static uint8_t vbtbpsr_state_at_boot; + +bool is_backup_domain_reset_happen(void) +{ + return (vbtbpsr_state_at_boot & VBTBPSR_VBPORF_IS_SET); +} + +void battery_backup_init(void) +{ +#if DT_NODE_HAS_PROP(DT_NODELABEL(battery_backup), switch_threshold) + /* Check VBPORM bit. If VBPORM flag is 0, wait until it changes to 1 */ + while (R_SYSTEM->VBTBPSR_b.VBPORM == 0) { + } + vbtbpsr_state_at_boot = R_SYSTEM->VBTBPSR; + if (R_SYSTEM->VBTBPSR_b.VBPORF == 1) { + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_OM_LPC_BATT); + R_SYSTEM->VBTBPSR_b.VBPORF = 0; + R_SYSTEM->VBTBPCR2_b.VDETLVL = + DT_ENUM_IDX(DT_NODELABEL(battery_backup), switch_threshold); + R_BSP_SoftwareDelay(VCC_DROP_DETECTION_STABILIZATION_WAIT_TIME_US, + BSP_DELAY_UNITS_MICROSECONDS); + R_SYSTEM->VBTBPCR2_b.VDETE = 1; + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_OM_LPC_BATT); + } +#else + /* Set the BPWSWSTP bit to 1. The power supply switch is stopped */ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_OM_LPC_BATT); + R_SYSTEM->VBTBPCR1_b.BPWSWSTP = 1; + + /* Check VBPORM flag. If VBPORM flag is 0, wait until it changes to 1 */ + while (R_SYSTEM->VBTBPSR_b.VBPORM == 0) { + } + vbtbpsr_state_at_boot = R_SYSTEM->VBTBPSR; + R_SYSTEM->VBTBPSR_b.VBPORF = 0; + R_SYSTEM->VBTBPCR2_b.VDETE = 0; + R_SYSTEM->VBTBPCR2_b.VDETLVL = DT_ENUM_IDX_OR( + DT_NODELABEL(battery_backup), switch_threshold, VBTBPCR2_VDETLVL_SETTING_NOT_USED); + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_OM_LPC_BATT); + + /* Set the SOSTP bit to 1 regardless of its value. Stop Sub-Clock Oscillator */ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_CGC); + R_SYSTEM->SOSCCR_b.SOSTP = 1; + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_CGC); +#endif /* BATTERY_BACKUP_CONFIGURATION_NOT_USED */ +} diff --git a/soc/renesas/ra/common_fsp/battery_backup.h b/soc/renesas/ra/common_fsp/battery_backup.h new file mode 100644 index 0000000000000..2757a9d47a371 --- /dev/null +++ b/soc/renesas/ra/common_fsp/battery_backup.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_RENESAS_RA_BATTERY_BACKUP_H_ +#define ZEPHYR_SOC_RENESAS_RA_BATTERY_BACKUP_H_ + +#include +#include + +bool is_backup_domain_reset_happen(void); +void battery_backup_init(void); + +#endif /* ZEPHYR_SOC_RENESAS_RA_BATTERY_BACKUP_H_ */ diff --git a/soc/renesas/ra/common_fsp/cold_start.c b/soc/renesas/ra/common_fsp/cold_start.c new file mode 100644 index 0000000000000..a176e07805bf2 --- /dev/null +++ b/soc/renesas/ra/common_fsp/cold_start.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "cold_start.h" + +#define RSTSR2_CWSF_BIT_MASK BIT(0) + +static uint8_t rstsr2_state_at_boot; + +bool is_power_on_reset_happen(void) +{ + return ((rstsr2_state_at_boot & RSTSR2_CWSF_BIT_MASK) == 0); +} + +void cold_start_handler(void) +{ + /* Detect power on reset */ + rstsr2_state_at_boot = R_SYSTEM->RSTSR2; + if (R_SYSTEM->RSTSR2_b.CWSF == 0) { +#if defined(CONFIG_RENESAS_RA_BATTERY_BACKUP_MANUAL_CONFIGURE) + battery_backup_init(); +#endif /* CONFIG_RENESAS_RA_BATTERY_BACKUP_MANUAL_CONFIGURE */ + R_SYSTEM->RSTSR2_b.CWSF = 1; + } +} diff --git a/soc/renesas/ra/common_fsp/cold_start.h b/soc/renesas/ra/common_fsp/cold_start.h new file mode 100644 index 0000000000000..5b818b9941827 --- /dev/null +++ b/soc/renesas/ra/common_fsp/cold_start.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_RENESAS_RA_COLD_START_H_ +#define ZEPHYR_SOC_RENESAS_RA_COLD_START_H_ + +#include +#include +#include "battery_backup.h" + +bool is_power_on_reset_happen(void); +void cold_start_handler(void); + +#endif /* ZEPHYR_SOC_RENESAS_RA_COLD_START_H_ */ diff --git a/soc/renesas/ra/ra8d1/soc.c b/soc/renesas/ra/ra8d1/soc.c index afde75b266abb..fea9ddd312e4e 100644 --- a/soc/renesas/ra/ra8d1/soc.c +++ b/soc/renesas/ra/ra8d1/soc.c @@ -74,4 +74,6 @@ void soc_early_init_hook(void) z_arm_nmi_set_handler(NMI_Handler); #endif /* CONFIG_RUNTIME_NMI */ + + cold_start_handler(); } diff --git a/soc/renesas/ra/ra8d1/soc.h b/soc/renesas/ra/ra8d1/soc.h index 5b0ce25896718..b878fe60a3aec 100644 --- a/soc/renesas/ra/ra8d1/soc.h +++ b/soc/renesas/ra/ra8d1/soc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Renesas Electronics Corporation + * Copyright (c) 2024-2025 Renesas Electronics Corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,5 +12,6 @@ #define ZEPHYR_SOC_RENESAS_RA8D1_SOC_H_ #include +#include #endif /* ZEPHYR_SOC_RENESAS_RA8D1_SOC_H_ */ diff --git a/soc/renesas/ra/ra8m1/soc.c b/soc/renesas/ra/ra8m1/soc.c index d898ab3957c81..35bafdbdfafd3 100644 --- a/soc/renesas/ra/ra8m1/soc.c +++ b/soc/renesas/ra/ra8m1/soc.c @@ -47,4 +47,6 @@ void soc_early_init_hook(void) z_arm_nmi_set_handler(NMI_Handler); #endif /* CONFIG_RUNTIME_NMI */ + + cold_start_handler(); } diff --git a/soc/renesas/ra/ra8m1/soc.h b/soc/renesas/ra/ra8m1/soc.h index e142833db84f7..1d817c563dc90 100644 --- a/soc/renesas/ra/ra8m1/soc.h +++ b/soc/renesas/ra/ra8m1/soc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Renesas Electronics Corporation + * Copyright (c) 2024-2025 Renesas Electronics Corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,5 +12,6 @@ #define ZEPHYR_SOC_RENESAS_RA8M1_SOC_H_ #include +#include #endif /* ZEPHYR_SOC_RENESAS_RA8M1_SOC_H_ */ diff --git a/soc/renesas/ra/ra8p1/soc.c b/soc/renesas/ra/ra8p1/soc.c index b8704093d7694..4f8b8292dfce1 100644 --- a/soc/renesas/ra/ra8p1/soc.c +++ b/soc/renesas/ra/ra8p1/soc.c @@ -28,6 +28,8 @@ uint32_t SystemCoreClock BSP_SECTION_EARLY_INIT; volatile uint32_t g_protect_pfswe_counter BSP_SECTION_EARLY_INIT; +extern void cold_start_handler(void); + /** * @brief Perform basic hardware initialization at boot. * @@ -90,4 +92,5 @@ void soc_early_init_hook(void) R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_SAR); #endif #endif /*CONFIG_CPU_CORTEX_M33*/ + cold_start_handler(); } diff --git a/soc/renesas/ra/ra8p1/soc.h b/soc/renesas/ra/ra8p1/soc.h index c7eab8aebd8a8..56172f7de5a08 100644 --- a/soc/renesas/ra/ra8p1/soc.h +++ b/soc/renesas/ra/ra8p1/soc.h @@ -12,5 +12,6 @@ #define ZEPHYR_SOC_RENESAS_RA8P1_SOC_H_ #include +#include #endif /* ZEPHYR_SOC_RENESAS_RA8P1_SOC_H_ */ diff --git a/tests/drivers/rtc/rtc_api/boards/ek_ra4l1.conf b/tests/drivers/rtc/rtc_api/boards/ek_ra4l1.conf new file mode 100644 index 0000000000000..7bbade27c1889 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/ek_ra4l1.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_RTC_ALARM=y +CONFIG_RTC_UPDATE=y +CONFIG_TEST_RTC_ALARM_TIME_MASK=63 diff --git a/tests/drivers/rtc/rtc_api/boards/ek_ra4l1.overlay b/tests/drivers/rtc/rtc_api/boards/ek_ra4l1.overlay new file mode 100644 index 0000000000000..ea18c0aae6925 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/ek_ra4l1.overlay @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; + +&rtc { + interrupts = <61 1>, <62 1>, <63 1>; + interrupt-names = "alm", "prd", "cup"; + status = "okay"; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/ek_ra8d1.conf b/tests/drivers/rtc/rtc_api/boards/ek_ra8d1.conf new file mode 100644 index 0000000000000..7bbade27c1889 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/ek_ra8d1.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_RTC_ALARM=y +CONFIG_RTC_UPDATE=y +CONFIG_TEST_RTC_ALARM_TIME_MASK=63 diff --git a/tests/drivers/rtc/rtc_api/boards/ek_ra8d1.overlay b/tests/drivers/rtc/rtc_api/boards/ek_ra8d1.overlay new file mode 100644 index 0000000000000..4ad1324fc408e --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/ek_ra8d1.overlay @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; + +&rtc { + interrupts = <95 1>, <94 1>, <93 1>; + interrupt-names = "alm", "prd", "cup"; + status = "okay"; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/ek_ra8m1.conf b/tests/drivers/rtc/rtc_api/boards/ek_ra8m1.conf new file mode 100644 index 0000000000000..7bbade27c1889 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/ek_ra8m1.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_RTC_ALARM=y +CONFIG_RTC_UPDATE=y +CONFIG_TEST_RTC_ALARM_TIME_MASK=63 diff --git a/tests/drivers/rtc/rtc_api/boards/ek_ra8m1.overlay b/tests/drivers/rtc/rtc_api/boards/ek_ra8m1.overlay new file mode 100644 index 0000000000000..4ad1324fc408e --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/ek_ra8m1.overlay @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; + +&rtc { + interrupts = <95 1>, <94 1>, <93 1>; + interrupt-names = "alm", "prd", "cup"; + status = "okay"; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/ek_ra8p1_r7ka8p1kflcac_cm85.conf b/tests/drivers/rtc/rtc_api/boards/ek_ra8p1_r7ka8p1kflcac_cm85.conf new file mode 100644 index 0000000000000..7bbade27c1889 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/ek_ra8p1_r7ka8p1kflcac_cm85.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_RTC_ALARM=y +CONFIG_RTC_UPDATE=y +CONFIG_TEST_RTC_ALARM_TIME_MASK=63 diff --git a/tests/drivers/rtc/rtc_api/boards/ek_ra8p1_r7ka8p1kflcac_cm85.overlay b/tests/drivers/rtc/rtc_api/boards/ek_ra8p1_r7ka8p1kflcac_cm85.overlay new file mode 100644 index 0000000000000..4ad1324fc408e --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/ek_ra8p1_r7ka8p1kflcac_cm85.overlay @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; + +&rtc { + interrupts = <95 1>, <94 1>, <93 1>; + interrupt-names = "alm", "prd", "cup"; + status = "okay"; +}; diff --git a/west.yml b/west.yml index 945fa7fed0b44..49173215fc7d0 100644 --- a/west.yml +++ b/west.yml @@ -226,7 +226,7 @@ manifest: - hal - name: hal_renesas path: modules/hal/renesas - revision: 0cdd997d9f39aa24099ecbc4dcba051546788619 + revision: pull/134/head groups: - hal - name: hal_rpi_pico