From 0bd12dcda383bc7e864c967c47380a9f65acc3d2 Mon Sep 17 00:00:00 2001 From: Khoa Tran Date: Wed, 5 Mar 2025 12:35:06 +0700 Subject: [PATCH 1/9] manifest: update rev of hal_renesas to latest Update rev of hal_renesas to add support for RTC driver Signed-off-by: Khoa Tran --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 5a2482649402ca55d55866c9f010977e5498c507 Mon Sep 17 00:00:00 2001 From: Khoa Tran Date: Fri, 25 Jul 2025 10:56:38 +0700 Subject: [PATCH 2/9] dts: bindings: renesas: Add battery backup node bindings for Renesas RA family Add dts bindings for the battery backup (VBAT) node used on the Renesas RA family. Signed-off-by: Khoa Tran --- .../power/renesas,ra-battery-backup.yaml | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 dts/bindings/power/renesas,ra-battery-backup.yaml 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. From 1428b4cc33f9b5925fd539cb848542d5d939775a Mon Sep 17 00:00:00 2001 From: Khoa Tran Date: Fri, 25 Jul 2025 10:54:27 +0700 Subject: [PATCH 3/9] dts: arm: renesas: ra: Add battery backup node for Renesas RA8 family Add a battery backup (VBAT) node to the device tree for the Renesas RA8 family. This enables support for RTC VBAT domain switching when main power is lost. Signed-off-by: Khoa Tran --- dts/arm/renesas/ra/ra8/r7fa8t1xh.dtsi | 1 + dts/arm/renesas/ra/ra8/ra8x1.dtsi | 22 ++++++++++++++++++++++ dts/arm/renesas/ra/ra8/ra8x2.dtsi | 22 ++++++++++++++++++++++ 3 files changed, 45 insertions(+) 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..06dae9db11b17 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 { diff --git a/dts/arm/renesas/ra/ra8/ra8x2.dtsi b/dts/arm/renesas/ra/ra8/ra8x2.dtsi index aedc3a0beff2c..4953c6518f516 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 { From be6b94271a8103e912e6d2b1682f8c89e6a70811 Mon Sep 17 00:00:00 2001 From: Khoa Tran Date: Fri, 25 Jul 2025 10:50:56 +0700 Subject: [PATCH 4/9] soc: renesas: ra: Add battery backup support for RA8 family Add support for the battery backup (VBAT) functionality on Renesas RA8 family. This allows the RTC to retain timekeeping data when the main power supply is lost by switching to the VBAT domain automatically. This commit add support for these SoC series: ra8m1, ra8p1, ra8d1 Signed-off-by: Khoa Tran --- soc/renesas/ra/CMakeLists.txt | 1 + soc/renesas/ra/Kconfig | 8 ++++ soc/renesas/ra/common_fsp/CMakeLists.txt | 5 ++ soc/renesas/ra/common_fsp/battery_backup.c | 56 ++++++++++++++++++++++ soc/renesas/ra/common_fsp/battery_backup.h | 16 +++++++ soc/renesas/ra/common_fsp/cold_start.c | 29 +++++++++++ soc/renesas/ra/common_fsp/cold_start.h | 17 +++++++ soc/renesas/ra/ra8d1/soc.c | 2 + soc/renesas/ra/ra8d1/soc.h | 3 +- soc/renesas/ra/ra8m1/soc.c | 2 + soc/renesas/ra/ra8m1/soc.h | 3 +- soc/renesas/ra/ra8p1/soc.c | 3 ++ soc/renesas/ra/ra8p1/soc.h | 1 + 13 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 soc/renesas/ra/common_fsp/CMakeLists.txt create mode 100644 soc/renesas/ra/common_fsp/battery_backup.c create mode 100644 soc/renesas/ra/common_fsp/battery_backup.h create mode 100644 soc/renesas/ra/common_fsp/cold_start.c create mode 100644 soc/renesas/ra/common_fsp/cold_start.h 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_ */ From 1aa91a2cc3fd4ab9949ca36db561905b2a6ed835 Mon Sep 17 00:00:00 2001 From: Khoa Tran Date: Wed, 2 Jul 2025 16:19:50 +0700 Subject: [PATCH 5/9] drivers: clock_control: Add clock control driver for sub-clock on Renesas RA family Add clock control driver support for sub-clock Renesas RA family Signed-off-by: Khoa Tran --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig.renesas_ra_cgc | 11 ++++ .../clock_control_renesas_ra_cgc_subclk.c | 60 +++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 drivers/clock_control/clock_control_renesas_ra_cgc_subclk.c 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); From 548c6bf9455553b88d865f84bf1aa4f9c4c85d26 Mon Sep 17 00:00:00 2001 From: Khoa Tran Date: Wed, 2 Jul 2025 17:18:35 +0700 Subject: [PATCH 6/9] drivers: rtc: Initial driver support for RTC on Renesas RA Add driver support for RTC on Renesas RA Signed-off-by: Khoa Tran --- drivers/rtc/CMakeLists.txt | 1 + drivers/rtc/Kconfig | 1 + drivers/rtc/Kconfig.renesas_ra | 12 + drivers/rtc/rtc_renesas_ra.c | 635 +++++++++++++++++++++++++++ dts/bindings/rtc/renesas,ra-rtc.yaml | 31 ++ modules/Kconfig.renesas | 5 + 6 files changed, 685 insertions(+) create mode 100644 drivers/rtc/Kconfig.renesas_ra create mode 100644 drivers/rtc/rtc_renesas_ra.c create mode 100644 dts/bindings/rtc/renesas,ra-rtc.yaml 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/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 From 0e1ca2b8edca1e1928ff086b733a0abebf43df45 Mon Sep 17 00:00:00 2001 From: Khoa Tran Date: Wed, 2 Jul 2025 17:19:14 +0700 Subject: [PATCH 7/9] dts: arm: Add rtc device node for Renesas RA family Add rtc device node to support rtc driver on Renesas RA SoCs: - r7fa8d1bhecbd - r7ka8p1kflcac - r7fa8m1ahecbd - r7fa4l1bd4cfp Signed-off-by: Khoa Tran --- dts/arm/renesas/ra/ra4/r7fa4l1bx.dtsi | 8 ++++++++ dts/arm/renesas/ra/ra8/ra8x1.dtsi | 9 ++++++++- dts/arm/renesas/ra/ra8/ra8x2.dtsi | 8 ++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) 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/ra8x1.dtsi b/dts/arm/renesas/ra/ra8/ra8x1.dtsi index 06dae9db11b17..c25b91ef0d3ee 100644 --- a/dts/arm/renesas/ra/ra8/ra8x1.dtsi +++ b/dts/arm/renesas/ra/ra8/ra8x1.dtsi @@ -950,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>; @@ -1018,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 4953c6518f516..3092e46a3813a 100644 --- a/dts/arm/renesas/ra/ra8/ra8x2.dtsi +++ b/dts/arm/renesas/ra/ra8/ra8x2.dtsi @@ -1062,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>; From 7ab793bd2d63c147e6a062d5436c2b41bc0e2ab3 Mon Sep 17 00:00:00 2001 From: Khoa Tran Date: Wed, 2 Jul 2025 17:23:07 +0700 Subject: [PATCH 8/9] samples: drivers: rtc: Add tests support for rtc driver on Renesas RA boards Add samples test support for RTC driver on these Renesas RA boards: - ek_ra8m1 - ek_ra8d1 - ek_ra8p1 - ek_ra4l1 Signed-off-by: Khoa Tran --- samples/drivers/rtc/boards/ek_ra4l1.overlay | 16 ++++++++++++++++ samples/drivers/rtc/boards/ek_ra8d1.overlay | 16 ++++++++++++++++ samples/drivers/rtc/boards/ek_ra8m1.overlay | 16 ++++++++++++++++ .../boards/ek_ra8p1_r7ka8p1kflcac_cm85.overlay | 16 ++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 samples/drivers/rtc/boards/ek_ra4l1.overlay create mode 100644 samples/drivers/rtc/boards/ek_ra8d1.overlay create mode 100644 samples/drivers/rtc/boards/ek_ra8m1.overlay create mode 100644 samples/drivers/rtc/boards/ek_ra8p1_r7ka8p1kflcac_cm85.overlay 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"; +}; From c94a3e8fa236667293be0c084b9a8905da90f7f3 Mon Sep 17 00:00:00 2001 From: Khoa Tran Date: Mon, 7 Jul 2025 10:21:17 +0700 Subject: [PATCH 9/9] tests: drivers: rtc: Add tests support for RTC driver on Renesas RA Add tests support for RTC driver on these Renesas RA boards: - ek_ra8m1 - ek_ra8d1 - ek_ra8p1 - ek_ra4l1 Signed-off-by: Khoa Tran --- tests/drivers/rtc/rtc_api/boards/ek_ra4l1.conf | 6 ++++++ .../drivers/rtc/rtc_api/boards/ek_ra4l1.overlay | 16 ++++++++++++++++ tests/drivers/rtc/rtc_api/boards/ek_ra8d1.conf | 6 ++++++ .../drivers/rtc/rtc_api/boards/ek_ra8d1.overlay | 16 ++++++++++++++++ tests/drivers/rtc/rtc_api/boards/ek_ra8m1.conf | 6 ++++++ .../drivers/rtc/rtc_api/boards/ek_ra8m1.overlay | 16 ++++++++++++++++ .../boards/ek_ra8p1_r7ka8p1kflcac_cm85.conf | 6 ++++++ .../boards/ek_ra8p1_r7ka8p1kflcac_cm85.overlay | 16 ++++++++++++++++ 8 files changed, 88 insertions(+) create mode 100644 tests/drivers/rtc/rtc_api/boards/ek_ra4l1.conf create mode 100644 tests/drivers/rtc/rtc_api/boards/ek_ra4l1.overlay create mode 100644 tests/drivers/rtc/rtc_api/boards/ek_ra8d1.conf create mode 100644 tests/drivers/rtc/rtc_api/boards/ek_ra8d1.overlay create mode 100644 tests/drivers/rtc/rtc_api/boards/ek_ra8m1.conf create mode 100644 tests/drivers/rtc/rtc_api/boards/ek_ra8m1.overlay create mode 100644 tests/drivers/rtc/rtc_api/boards/ek_ra8p1_r7ka8p1kflcac_cm85.conf create mode 100644 tests/drivers/rtc/rtc_api/boards/ek_ra8p1_r7ka8p1kflcac_cm85.overlay 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"; +};