From d1f5b3b764a3b6f7e184dad48dad29c778710e3e Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Thu, 29 Aug 2024 12:08:48 +0300 Subject: [PATCH 1/3] drivers: counter: Add support for cc23x0 RTC counter Add support for cc23x0 RTC driver in counter. RTC is always ON after device boot. Timer is restared only on POR, and is active during STANDBY and ACTIVE power states. Signed-off-by: Stoyan Bogdanov --- drivers/counter/CMakeLists.txt | 1 + drivers/counter/Kconfig | 2 + drivers/counter/Kconfig.cc23x0_rtc | 9 + drivers/counter/counter_cc23x0_rtc.c | 243 ++++++++++++++++++++++++ dts/bindings/counter/ti,cc23x0-rtc.yaml | 15 ++ 5 files changed, 270 insertions(+) create mode 100644 drivers/counter/Kconfig.cc23x0_rtc create mode 100644 drivers/counter/counter_cc23x0_rtc.c create mode 100644 dts/bindings/counter/ti,cc23x0-rtc.yaml diff --git a/drivers/counter/CMakeLists.txt b/drivers/counter/CMakeLists.txt index 93a51369f572..7914ff476864 100644 --- a/drivers/counter/CMakeLists.txt +++ b/drivers/counter/CMakeLists.txt @@ -54,3 +54,4 @@ zephyr_library_sources_ifdef(CONFIG_COUNTER_RTC_MAX32 counter_max32_rt zephyr_library_sources_ifdef(CONFIG_COUNTER_NXP_MRT counter_nxp_mrt.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_RA_AGT counter_renesas_ra_agt.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_RENESAS_RZ_GTM counter_renesas_rz_gtm.c) +zephyr_library_sources_ifdef(CONFIG_COUNTER_CC23X0_RTC counter_cc23x0_rtc.c) diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index d9d1dcafcc5f..411e5ff5b53f 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -106,4 +106,6 @@ source "drivers/counter/Kconfig.renesas_ra" source "drivers/counter/Kconfig.renesas_rz" +source "drivers/counter/Kconfig.cc23x0_rtc" + endif # COUNTER diff --git a/drivers/counter/Kconfig.cc23x0_rtc b/drivers/counter/Kconfig.cc23x0_rtc new file mode 100644 index 000000000000..5afcbda2d3e8 --- /dev/null +++ b/drivers/counter/Kconfig.cc23x0_rtc @@ -0,0 +1,9 @@ +# Copyright (c) 2024 BayLibre, SAS +# SPDX-License-Identifier: Apache-2.0 + +config COUNTER_CC23X0_RTC + bool "CC23x0 Counter driver based on the RTC Timer" + default y + depends on DT_HAS_TI_CC23X0_RTC_ENABLED + help + Enable counter driver based on RTC timer for cc23x0 diff --git a/drivers/counter/counter_cc23x0_rtc.c b/drivers/counter/counter_cc23x0_rtc.c new file mode 100644 index 000000000000..acac8808a80f --- /dev/null +++ b/drivers/counter/counter_cc23x0_rtc.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_cc23x0_rtc + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(cc23x0_counter_rtc, CONFIG_COUNTER_LOG_LEVEL); + +static void counter_cc23x0_isr(const struct device *dev); + +struct counter_cc23x0_config { + struct counter_config_info counter_info; + uint32_t base; +}; + +struct counter_cc23x0_data { + struct counter_alarm_cfg alarm_cfg0; + uint32_t ticks; + uint32_t clk_src_freq; +}; + +static int counter_cc23x0_get_value(const struct device *dev, uint32_t *ticks) +{ + /* Resolution is 8us and max timeout ~9.5h */ + const struct counter_cc23x0_config *config = dev->config; + + *ticks = HWREG(config->base + RTC_O_TIME8U); + + return 0; +} + +static int counter_cc23x0_get_value_64(const struct device *dev, uint64_t *ticks) +{ + const struct counter_cc23x0_config *config = dev->config; + + /* + * RTC counter register is 67 bits, only part of the bits are accessible. + * They are split in two partially overlapping registers: + * TIME524M [50:19] + * TIME8U [34:3] + */ + + uint64_t rtc_time_now = + ((HWREG(config->base + RTC_O_TIME524M) << 19) & 0xFFFFFFF800000000) | + (HWREG(config->base + RTC_O_TIME8U) << 3); + + *ticks = rtc_time_now; + + return 0; +} + +static void counter_cc23x0_isr(const struct device *dev) +{ + const struct counter_cc23x0_config *config = dev->config; + struct counter_cc23x0_data *data = dev->data; + + /* Clear RTC interrupt regs */ + HWREG(config->base + RTC_O_ICLR) = 0x3; + HWREG(config->base + RTC_O_IMCLR) = 0x3; + + uint32_t now = HWREG(config->base + RTC_O_TIME8U); + + if (data->alarm_cfg0.callback) { + data->alarm_cfg0.callback(dev, 0, now, data->alarm_cfg0.user_data); + } +} + +static int counter_cc23x0_set_alarm(const struct device *dev, uint8_t chan_id, + const struct counter_alarm_cfg *alarm_cfg) +{ + const struct counter_cc23x0_config *config = dev->config; + struct counter_cc23x0_data *data = dev->data; + + /* RTC have resolutiuon of 8us */ + if (counter_ticks_to_us(dev, alarm_cfg->ticks) <= 8) { + return -ENOTSUP; + } + + uint32_t now = HWREG(config->base + RTC_O_TIME8U); + + /* Calculate next alarm relative to current time in us */ + uint32_t next_alarm = now + (counter_ticks_to_us(dev, alarm_cfg->ticks) / 8); + + HWREG(config->base + RTC_O_CH0CC8U) = next_alarm; + HWREG(config->base + RTC_O_IMASK) = 0x1; + HWREG(config->base + RTC_O_ARMSET) = 0x1; + + HWREG(EVTSVT_BASE + EVTSVT_O_CPUIRQ3SEL) = EVTSVT_CPUIRQ16SEL_PUBID_AON_RTC_COMB; + + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), counter_cc23x0_isr, + DEVICE_DT_INST_GET(0), 0); + + irq_enable(DT_INST_IRQN(0)); + + data->alarm_cfg0.flags = 0; + data->alarm_cfg0.ticks = alarm_cfg->ticks; + data->alarm_cfg0.callback = alarm_cfg->callback; + data->alarm_cfg0.user_data = alarm_cfg->user_data; + + return 0; +} + +static int counter_cc23x0_cancel_alarm(const struct device *dev, uint8_t chan_id) +{ + const struct counter_cc23x0_config *config = dev->config; + + /* Unset interrupt source */ + HWREG(EVTSVT_BASE + EVTSVT_O_CPUIRQ3SEL) = 0x0; + + /* Unarm both channels */ + HWREG(config->base + RTC_O_ARMCLR) = 0x3; + + return 0; +} + +static int counter_cc23x0_set_top_value(const struct device *dev, const struct counter_top_cfg *cfg) +{ + return -ENOTSUP; +} + +static uint32_t counter_cc23x0_get_pending_int(const struct device *dev) +{ + const struct counter_cc23x0_config *config = dev->config; + struct counter_cc23x0_data *data = dev->data; + + /* Check interrupt and mask */ + if (HWREG(config->base + RTC_O_RIS) & HWREG(config->base + RTC_O_MIS)) { + /* Clear RTC interrupt regs */ + HWREG(config->base + RTC_O_ICLR) = 0x3; + HWREG(config->base + RTC_O_IMCLR) = 0x3; + + uint32_t now = HWREG(config->base + RTC_O_TIME8U); + + if (data->alarm_cfg0.callback) { + data->alarm_cfg0.callback(dev, 0, now, data->alarm_cfg0.user_data); + } + + return 0; + } + + return -ESRCH; +} + +static uint32_t counter_cc23x0_get_top_value(const struct device *dev) +{ + ARG_UNUSED(dev); + + return -ENOTSUP; +} + +static uint32_t counter_cc23x0_get_freq(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* + * From TRM clock for RTC is 24Mhz handled internally + * which is 1/2 from main 48Mhz clock = 24Mhz + * Accessible for user resolution is 8us per bit + * TIME8U [34:3] ~ 9.5h + */ + + return (DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) / 2); +} + +static int counter_cc23x0_start(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* RTC timer runs after power-on reset */ + + return 0; +} + +static int counter_cc23x0_stop(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* Any reset/sleep mode, except for POR, will not stop or reset the RTC timer */ + + return 0; +} + +static int counter_cc23x0_init(const struct device *dev) +{ + const struct counter_cc23x0_config *config = dev->config; + + /* Clear interrupt Mask */ + HWREG(config->base + RTC_O_IMCLR) = 0x3; + + /* Clear Interrupt */ + HWREG(config->base + RTC_O_ICLR) = 0x3; + + /* Clear Armed */ + HWREG(config->base + RTC_O_ARMCLR) = 0x3; + + return 0; +} + +static const struct counter_driver_api rtc_cc23x0_api = { + .start = counter_cc23x0_start, + .stop = counter_cc23x0_stop, + .get_value = counter_cc23x0_get_value, + .get_value_64 = counter_cc23x0_get_value_64, + .set_alarm = counter_cc23x0_set_alarm, + .cancel_alarm = counter_cc23x0_cancel_alarm, + .get_top_value = counter_cc23x0_get_top_value, + .set_top_value = counter_cc23x0_set_top_value, + .get_pending_int = counter_cc23x0_get_pending_int, + .get_freq = counter_cc23x0_get_freq, +}; + +#define CC23X0_INIT(inst) \ + static const struct counter_cc23x0_config cc23x0_config_##inst = { \ + .counter_info = \ + { \ + .max_top_value = UINT32_MAX, \ + .flags = COUNTER_CONFIG_INFO_COUNT_UP, \ + .channels = 1, \ + }, \ + .base = DT_INST_REG_ADDR(inst), \ + }; \ + \ + static struct counter_cc23x0_data cc23x0_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(0, &counter_cc23x0_init, NULL, &cc23x0_data_##inst, \ + &cc23x0_config_##inst, POST_KERNEL, CONFIG_COUNTER_INIT_PRIORITY, \ + &rtc_cc23x0_api); + +DT_INST_FOREACH_STATUS_OKAY(CC23X0_INIT) diff --git a/dts/bindings/counter/ti,cc23x0-rtc.yaml b/dts/bindings/counter/ti,cc23x0-rtc.yaml new file mode 100644 index 000000000000..e6b046c378f5 --- /dev/null +++ b/dts/bindings/counter/ti,cc23x0-rtc.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2024 BayLibre, SAS +# SPDX-License-Identifier: Apache-2.0 + +description: | + CC23x0 RTC counter driver + Any reset/sleep mode, except for the power-up reset, will not + stop or reset the RTC Timer. This behavior may be handy when + supporting applications that need to keep a timing baseline on + such situations. + There is also no need to enable the RTC Timer node, it starts + running from power-up. + +compatible: "ti,cc23x0-rtc" + +include: base.yaml From 8f788cc37e4030dfac39a192f9c132e07b8b0520 Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Thu, 29 Aug 2024 12:17:23 +0300 Subject: [PATCH 2/3] dts: arm: ti: cc23x0: Add RTC support Add support for RTC counter to cc23x0 SoC. Signed-off-by: Stoyan Bogdanov --- dts/arm/ti/cc23x0.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dts/arm/ti/cc23x0.dtsi b/dts/arm/ti/cc23x0.dtsi index 6b307980ce3e..5966ace83e83 100644 --- a/dts/arm/ti/cc23x0.dtsi +++ b/dts/arm/ti/cc23x0.dtsi @@ -79,6 +79,13 @@ clocks = <&sysclk>; status = "disabled"; }; + + rtc0: rtc@40002000 { + compatible = "ti,cc23x0-rtc"; + reg = <0x40002000 0x64>; + interrupts = <3 0>; + status = "disabled"; + }; }; }; From 9c3be34a9851bf75dae3e7f7367e8349bf4f6c2a Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Thu, 29 Aug 2024 16:14:55 +0300 Subject: [PATCH 3/3] samples: drivers: counter: alarm: Add lp_em_cc2340r5 overlay Add overlay for lp_em_cc2340r5 to counter/alarm sample. Signed-off-by: Stoyan Bogdanov --- samples/drivers/counter/alarm/boards/lp_em_cc2340r5.overlay | 3 +++ samples/drivers/counter/alarm/sample.yaml | 1 + samples/drivers/counter/alarm/src/main.c | 2 ++ 3 files changed, 6 insertions(+) create mode 100644 samples/drivers/counter/alarm/boards/lp_em_cc2340r5.overlay diff --git a/samples/drivers/counter/alarm/boards/lp_em_cc2340r5.overlay b/samples/drivers/counter/alarm/boards/lp_em_cc2340r5.overlay new file mode 100644 index 000000000000..5e37ad9fff92 --- /dev/null +++ b/samples/drivers/counter/alarm/boards/lp_em_cc2340r5.overlay @@ -0,0 +1,3 @@ +&rtc0 { + status = "okay"; +}; diff --git a/samples/drivers/counter/alarm/sample.yaml b/samples/drivers/counter/alarm/sample.yaml index 9807da7ecb93..c3f141f680d1 100644 --- a/samples/drivers/counter/alarm/sample.yaml +++ b/samples/drivers/counter/alarm/sample.yaml @@ -41,6 +41,7 @@ tests: - s32z2xxdc2/s32z270/rtu1 - s32z2xxdc2@D/s32z270/rtu0 - s32z2xxdc2@D/s32z270/rtu1 + - lp_em_cc2340r5 integration_platforms: - nucleo_f746zg sample.drivers.counter.alarm.stm32_rtc: diff --git a/samples/drivers/counter/alarm/src/main.c b/samples/drivers/counter/alarm/src/main.c index d7f577e72c7e..de315c802f3a 100644 --- a/samples/drivers/counter/alarm/src/main.c +++ b/samples/drivers/counter/alarm/src/main.c @@ -61,6 +61,8 @@ struct counter_alarm_cfg alarm_cfg; #define TIMER DT_NODELABEL(counter0) #elif defined(CONFIG_COUNTER_RENESAS_RZ_GTM) #define TIMER DT_INST(0, renesas_rz_gtm_counter) +#elif defined(CONFIG_COUNTER_CC23X0_RTC) +#define TIMER DT_NODELABEL(rtc0) #else #error Unable to find a counter device node in devicetree #endif