diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts index bc8aca798be9c..03931036894e8 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts @@ -24,6 +24,7 @@ pwm-0 = &sc_timer; i2s-codec-tx = &sai0; i2s-tx = &sai0; + rtc = &rtc0; }; chosen { @@ -245,3 +246,7 @@ zephyr_udc0: &usb0 { }; p3t1755dp_ard_i2c_interface: &flexcomm8_lpi2c8 {}; + +&rtc0 { + status = "okay"; +}; diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts index 78115a84e2281..e8c1010809c61 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts @@ -19,6 +19,7 @@ led0 = &red_led; sw0 = &user_button_1; ambient-temp0 = &p3t1755; + rtc = &rtc1; }; chosen { @@ -97,3 +98,7 @@ status = "okay"; }; }; + +&rtc1 { + status = "okay"; +}; diff --git a/drivers/rtc/rtc_nxp_irtc.c b/drivers/rtc/rtc_nxp_irtc.c index 331def239a75f..4dccc50e943e6 100644 --- a/drivers/rtc/rtc_nxp_irtc.c +++ b/drivers/rtc/rtc_nxp_irtc.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,7 +15,9 @@ struct nxp_irtc_config { RTC_Type *base; void (*irq_config_func)(const struct device *dev); bool is_output_clock_enabled; +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(clock_src) uint8_t clock_src; +#endif uint8_t alarm_match_flag; }; @@ -31,9 +33,8 @@ struct nxp_irtc_data { /* The IRTC Offset is 2112 instead of 1900 [2112 - 1900] -> [212] */ #define RTC_NXP_IRTC_YEAR_OFFSET 212 -#define RTC_NXP_GET_REG_FIELD(_reg, _name, _field) \ - ((_reg->_name & RTC_##_name##_##_field##_MASK) >> \ - RTC_##_name##_##_field##_SHIFT) +#define RTC_NXP_GET_REG_FIELD(_reg, _name, _field) \ + ((_reg->_name & RTC_##_name##_##_field##_MASK) >> RTC_##_name##_##_field##_SHIFT) /* * The runtime where this is accessed is unknown so we force a lock on the registers then force an @@ -62,6 +63,12 @@ static void nxp_irtc_unlock_registers(RTC_Type *reg) static int nxp_irtc_set_time(const struct device *dev, const struct rtc_time *timeptr) { +#if DT_PROP(DT_ALIAS(rtc), share_counter) + ARG_UNUSED(dev); + ARG_UNUSED(timeptr); + + return -EPERM; +#else const struct nxp_irtc_config *config = dev->config; struct nxp_irtc_data *data = dev->data; RTC_Type *irtc_reg = config->base; @@ -79,12 +86,12 @@ static int nxp_irtc_set_time(const struct device *dev, const struct rtc_time *ti nxp_irtc_unlock_registers(irtc_reg); irtc_reg->SECONDS = RTC_SECONDS_SEC_CNT(timeptr->tm_sec); - irtc_reg->HOURMIN = RTC_HOURMIN_MIN_CNT(timeptr->tm_min) | - RTC_HOURMIN_HOUR_CNT(timeptr->tm_hour); + irtc_reg->HOURMIN = + RTC_HOURMIN_MIN_CNT(timeptr->tm_min) | RTC_HOURMIN_HOUR_CNT(timeptr->tm_hour); /* 1 is valid for rtc_time.tm_wday property but is out of bounds for IRTC registers */ irtc_reg->DAYS = RTC_DAYS_DAY_CNT(timeptr->tm_mday) | - (timeptr->tm_wday == -1 ? 0 : RTC_DAYS_DOW(timeptr->tm_wday)); + (timeptr->tm_wday == -1 ? 0 : RTC_DAYS_DOW(timeptr->tm_wday)); irtc_reg->YEARMON = RTC_YEARMON_MON_CNT(calc_month) | RTC_YEARMON_YROFST(calc_year); @@ -96,6 +103,7 @@ static int nxp_irtc_set_time(const struct device *dev, const struct rtc_time *ti irq_unlock(key); return 0; +#endif } static int nxp_irtc_get_time(const struct device *dev, struct rtc_time *timeptr) @@ -112,8 +120,8 @@ static int nxp_irtc_get_time(const struct device *dev, struct rtc_time *timeptr) timeptr->tm_wday = RTC_NXP_GET_REG_FIELD(irtc_reg, DAYS, DOW); timeptr->tm_mday = RTC_NXP_GET_REG_FIELD(irtc_reg, DAYS, DAY_CNT); timeptr->tm_mon = RTC_NXP_GET_REG_FIELD(irtc_reg, YEARMON, MON_CNT) - 1; - timeptr->tm_year = (int8_t)RTC_NXP_GET_REG_FIELD(irtc_reg, YEARMON, YROFST) + - RTC_NXP_IRTC_YEAR_OFFSET; + timeptr->tm_year = + (int8_t)RTC_NXP_GET_REG_FIELD(irtc_reg, YEARMON, YROFST) + RTC_NXP_IRTC_YEAR_OFFSET; if (data->is_dst_enabled) { timeptr->tm_isdst = ((irtc_reg->CTRL & RTC_CTRL_DST_EN_MASK) >> RTC_CTRL_DST_EN_SHIFT); @@ -186,19 +194,24 @@ static int nxp_irtc_alarm_set_time(const struct device *dev, uint16_t id, uint16 } /* Clearing out the ALARM Flag Field then setting the correct value */ - irtc_reg->CTRL &= ~(0xC); - switch (mask) { - case 0x0F: - irtc_reg->CTRL |= RTC_CTRL_ALM_MATCH(0x4); + irtc_reg->CTRL &= ~((uint16_t)RTC_CTRL_ALM_MATCH_MASK); + uint8_t year_month_day_mask = (mask & (BIT(3) | BIT(4) | BIT(5))) >> 3; + switch (year_month_day_mask) { + case 0x00: + irtc_reg->CTRL |= RTC_CTRL_ALM_MATCH(0x0); break; - case 0x1F: - irtc_reg->CTRL |= RTC_CTRL_ALM_MATCH(0x8); + case 0x01: + irtc_reg->CTRL |= RTC_CTRL_ALM_MATCH(0x1); break; - case 0x3F: - irtc_reg->CTRL |= RTC_CTRL_ALM_MATCH(0xC); + case 0x03: + irtc_reg->CTRL |= RTC_CTRL_ALM_MATCH(0x2); + break; + case 0x07: + irtc_reg->CTRL |= RTC_CTRL_ALM_MATCH(0x3); break; default: - irtc_reg->CTRL |= RTC_CTRL_ALM_MATCH(0x0); + irq_unlock(key); + return -EINVAL; } /* Enabling Alarm Interrupts */ @@ -218,39 +231,45 @@ static int nxp_irtc_alarm_get_time(const struct device *dev, uint16_t id, uint16 RTC_Type *irtc_reg = config->base; uint16_t curr_alarm_mask = data->alarm_mask; uint16_t return_mask = 0; + uint16_t tmp_hourmin = irtc_reg->ALM_HOURMIN; + uint16_t tmp_yearmon = irtc_reg->ALM_YEARMON; if (id != 0 || !timeptr) { return -EINVAL; } + memset(timeptr, 0, sizeof(struct rtc_time)); + if (curr_alarm_mask & RTC_ALARM_TIME_MASK_SECOND) { - timeptr->tm_sec = RTC_NXP_GET_REG_FIELD(irtc_reg, ALM_SECONDS, ALM_SEC); + timeptr->tm_sec = (irtc_reg->ALM_SECONDS) & RTC_ALM_SECONDS_ALM_SEC_MASK; return_mask |= RTC_ALARM_TIME_MASK_SECOND; } if (curr_alarm_mask & RTC_ALARM_TIME_MASK_MINUTE) { - timeptr->tm_min = RTC_NXP_GET_REG_FIELD(irtc_reg, HOURMIN, MIN_CNT); + timeptr->tm_min = tmp_hourmin & RTC_ALM_HOURMIN_ALM_MIN_MASK; return_mask |= RTC_ALARM_TIME_MASK_MINUTE; } if (curr_alarm_mask & RTC_ALARM_TIME_MASK_HOUR) { - timeptr->tm_hour = RTC_NXP_GET_REG_FIELD(irtc_reg, HOURMIN, HOUR_CNT); + timeptr->tm_hour = ((tmp_hourmin & RTC_ALM_HOURMIN_ALM_HOUR_MASK) >> + RTC_ALM_HOURMIN_ALM_HOUR_SHIFT); return_mask |= RTC_ALARM_TIME_MASK_HOUR; } if (curr_alarm_mask & RTC_ALARM_TIME_MASK_MONTHDAY) { - timeptr->tm_mday = RTC_NXP_GET_REG_FIELD(irtc_reg, DAYS, DAY_CNT); + timeptr->tm_mday = (irtc_reg->ALM_DAYS) & RTC_ALM_DAYS_ALM_DAY_MASK; return_mask |= RTC_ALARM_TIME_MASK_MONTHDAY; } if (curr_alarm_mask & RTC_ALARM_TIME_MASK_MONTH) { - timeptr->tm_mon = RTC_NXP_GET_REG_FIELD(irtc_reg, YEARMON, MON_CNT) - 1; + timeptr->tm_mon = (tmp_yearmon & RTC_ALM_YEARMON_ALM_MON_MASK) - 1; return_mask |= RTC_ALARM_TIME_MASK_MONTH; } if (curr_alarm_mask & RTC_ALARM_TIME_MASK_YEAR) { - timeptr->tm_year = (int8_t)RTC_NXP_GET_REG_FIELD(irtc_reg, YEARMON, YROFST) + - RTC_NXP_IRTC_YEAR_OFFSET; + timeptr->tm_year = (int8_t)((tmp_yearmon & RTC_ALM_YEARMON_ALM_YEAR_MASK) >> + RTC_ALM_YEARMON_ALM_YEAR_SHIFT) + + RTC_NXP_IRTC_YEAR_OFFSET; return_mask |= RTC_ALARM_TIME_MASK_YEAR; } @@ -261,14 +280,23 @@ static int nxp_irtc_alarm_get_time(const struct device *dev, uint16_t id, uint16 static int nxp_irtc_alarm_is_pending(const struct device *dev, uint16_t id) { - struct nxp_irtc_data *data = dev->data; + const struct nxp_irtc_config *config = dev->config; RTC_Type *irtc_reg = config->base; if (id != 0) { return -EINVAL; } - return RTC_ISR_ALM_IS(0x4); + if ((irtc_reg->ISR & RTC_ISR_ALM_IS_MASK) != 0) { + /* Clear the Alarm Interrupt */ + nxp_irtc_unlock_registers(irtc_reg); + /* Alarm is pending */ + irtc_reg->ISR = RTC_ISR_ALM_IS_MASK; + return 1; + } else { + /* Alarm is not pending */ + return 0; + } } static int nxp_irtc_alarm_set_callback(const struct device *dev, uint16_t id, @@ -325,12 +353,22 @@ static int nxp_irtc_init(const struct device *dev) { const struct nxp_irtc_config *config = dev->config; RTC_Type *irtc_reg = config->base; + uint16_t reg = 0; nxp_irtc_unlock_registers(irtc_reg); - /* set the control register bits */ - irtc_reg->CTRL = RTC_CTRL_CLK_SEL(config->clock_src) | - RTC_CTRL_CLKO_DIS(!config->is_output_clock_enabled); + reg = irtc_reg->CTRL; + reg &= ~(uint16_t)RTC_CTRL_CLKO_DIS_MASK; +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(clock_src) + reg &= ~(uint16_t)RTC_CTRL_CLK_SEL_MASK; +#endif + + reg |= RTC_CTRL_CLKO_DIS(!config->is_output_clock_enabled); +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(clock_src) + reg |= RTC_CTRL_CLK_SEL(config->clock_src); +#endif + + irtc_reg->CTRL = reg; config->irq_config_func(dev); @@ -348,7 +386,6 @@ static void nxp_irtc_isr(const struct device *dev) nxp_irtc_unlock_registers(irtc_reg); /* Clearing ISR Register since w1c */ irtc_reg->ISR = irtc_reg->ISR; - if (data->alarm_callback) { data->alarm_callback(dev, 0, data->alarm_user_data); } @@ -375,17 +412,40 @@ static DEVICE_API(rtc, rtc_nxp_irtc_driver_api) = { #endif /* CONFIG_RTC_CALIBRATION */ }; -#define RTC_NXP_IRTC_DEVICE_INIT(n) \ +#define RTC_NXP_IRTC_IRQ_CONNECT(n, m) \ + do { \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, m, irq), DT_INST_IRQ_BY_IDX(n, m, priority), \ + nxp_irtc_isr, DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQ_BY_IDX(n, m, irq)); \ + } while (false) + +#if DT_INST_IRQ_HAS_IDX(0, 1) +#define NXP_IRTC_CONFIG_FUNC(n) \ static void nxp_irtc_config_func_##n(const struct device *dev) \ { \ - IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), nxp_irtc_isr, \ - DEVICE_DT_INST_GET(n), 0); \ - irq_enable(DT_INST_IRQN(n)); \ - } \ + RTC_NXP_IRTC_IRQ_CONNECT(n, 0); \ + RTC_NXP_IRTC_IRQ_CONNECT(n, 1); \ + } +#else +#define NXP_IRTC_CONFIG_FUNC(n) \ + static void nxp_irtc_config_func_##n(const struct device *dev) \ + { \ + RTC_NXP_IRTC_IRQ_CONNECT(n, 0); \ + } +#endif + +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(clock_src) +#define NXP_IRTC_CLOCK_SELECTION_INIT(n) .clock_src = DT_INST_PROP(n, clock_src), +#else +#define NXP_IRTC_CLOCK_SELECTION_INIT(n) +#endif + +#define RTC_NXP_IRTC_DEVICE_INIT(n) \ + NXP_IRTC_CONFIG_FUNC(n) \ static const struct nxp_irtc_config nxp_irtc_config_##n = { \ .base = (RTC_Type *)DT_INST_REG_ADDR(n), \ - .clock_src = DT_INST_PROP(n, clock_src), \ - .is_output_clock_enabled = DT_INST_PROP(n, output_clk_en), \ + NXP_IRTC_CLOCK_SELECTION_INIT(n).is_output_clock_enabled = \ + DT_INST_PROP(n, output_clk_en), \ .irq_config_func = nxp_irtc_config_func_##n, \ }; \ \ diff --git a/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi b/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi index 80cab28c6b18c..9acdd6516c0c5 100644 --- a/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi +++ b/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi @@ -156,6 +156,16 @@ #reset-cells = <1>; }; + rtc0: rtc@68000 { + compatible = "nxp,irtc"; + reg = <0x68000 0x1000>; + interrupts = <26 0>, <27 0>; + clock-frequency = <32768>; + prescaler = <1>; + alarms-count = <1>; + status = "disabled"; + }; + clkctl0: clkctl@1000 { compatible = "nxp,lpc-syscon"; reg = <0x1000 0x1000>; diff --git a/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi b/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi index 0f42be0607442..7b6816e578d31 100644 --- a/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi +++ b/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi @@ -131,6 +131,17 @@ #reset-cells = <1>; }; + rtc1: rtc@69000 { + compatible = "nxp,irtc"; + reg = <0x69000 0x1000>; + interrupts = <23 0>, <24 0>; + clock-frequency = <32768>; + prescaler = <1>; + alarms-count = <1>; + share-counter; + status = "disabled"; + }; + clkctl1: clkctl@41000 { compatible = "nxp,lpc-syscon"; reg = <0x41000 0x1000>; diff --git a/dts/bindings/rtc/nxp,irtc.yaml b/dts/bindings/rtc/nxp,irtc.yaml index 7b25ce1d4ce93..3cd6c29df5d53 100644 --- a/dts/bindings/rtc/nxp,irtc.yaml +++ b/dts/bindings/rtc/nxp,irtc.yaml @@ -1,4 +1,4 @@ -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # SPDX-License-Identifier: Apache-2.0 description: IRTC @@ -15,7 +15,6 @@ properties: clock-src: type: int - required: true enum: - 0 - 1 @@ -40,3 +39,9 @@ properties: 3 <- Coarse 1Hz Default value ensures the output clock is turned off. This is the reset value. + + share-counter: + type: boolean + description: | + This secondary IRTC instance shares the data and time counters of the primary IRTC instance. + This means the code cannot set the data and time counters, but can only read them. diff --git a/samples/drivers/rtc/README.rst b/samples/drivers/rtc/README.rst index 4b9e30ed86912..5a743d4b6d9e1 100644 --- a/samples/drivers/rtc/README.rst +++ b/samples/drivers/rtc/README.rst @@ -22,6 +22,16 @@ Build and flash as follows, replacing ``stm32f3_disco`` with your board: :goals: build flash :compact: +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/rtc + :board: mimxrt700_evk/mimxrt798s/cm33_cpu0 + :goals: build flash + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/rtc + :board: mimxrt700_evk/mimxrt798s/cm33_cpu1 + :goals: build ram + Sample Output ============= diff --git a/samples/drivers/rtc/sample.yaml b/samples/drivers/rtc/sample.yaml index b7dbd755a7e78..2d57ba0fff0e3 100644 --- a/samples/drivers/rtc/sample.yaml +++ b/samples/drivers/rtc/sample.yaml @@ -4,6 +4,8 @@ tests: sample.drivers.rtc: platform_allow: - stm32f3_disco + - mimxrt700_evk/mimxrt798s/cm33_cpu0 + - mimxrt700_evk/mimxrt798s/cm33_cpu1 integration_platforms: - stm32f3_disco tags: diff --git a/tests/drivers/rtc/rtc_api/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf b/tests/drivers/rtc/rtc_api/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf new file mode 100644 index 0000000000000..6d5262f046fe6 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_ALARM=y +CONFIG_TEST_RTC_ALARM_TIME_MASK=63 diff --git a/tests/drivers/rtc/rtc_api/src/test_alarm.c b/tests/drivers/rtc/rtc_api/src/test_alarm.c index 3b15a0371dd8c..f05df55254ba0 100644 --- a/tests/drivers/rtc/rtc_api/src/test_alarm.c +++ b/tests/drivers/rtc/rtc_api/src/test_alarm.c @@ -174,6 +174,9 @@ ZTEST(rtc_api, test_alarm) } } + /* Disable RTC IRQ, the irq will clear the alarm pending flag thus affects the test */ + irq_disable(DT_IRQN(DT_ALIAS(rtc))); + for (uint8_t k = 0; k < 2; k++) { /* Set RTC time */ ret = rtc_set_time(rtc, &test_rtc_time_set); @@ -212,4 +215,7 @@ ZTEST(rtc_api, test_alarm) ret = rtc_alarm_is_pending(rtc, i); zassert_true(ret > -1, "Failed to clear alarm %d pending state", i); } + + /* Re-enable IRQ after test */ + irq_enable(DT_IRQN(DT_ALIAS(rtc))); }