Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RTC support to TI cc23x0 SoC #84527

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/counter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
2 changes: 2 additions & 0 deletions drivers/counter/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,6 @@ source "drivers/counter/Kconfig.renesas_ra"

source "drivers/counter/Kconfig.renesas_rz"

source "drivers/counter/Kconfig.cc23x0_rtc"

endif # COUNTER
9 changes: 9 additions & 0 deletions drivers/counter/Kconfig.cc23x0_rtc
Original file line number Diff line number Diff line change
@@ -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
243 changes: 243 additions & 0 deletions drivers/counter/counter_cc23x0_rtc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
/*
* Copyright (c) 2024 BayLibre, SAS
*
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT ti_cc23x0_rtc

#include <zephyr/device.h>
#include <zephyr/drivers/counter.h>
#include <zephyr/spinlock.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/logging/log.h>

#include <inc/hw_rtc.h>
#include <inc/hw_types.h>
#include <inc/hw_evtsvt.h>
#include <inc/hw_memmap.h>

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)
7 changes: 7 additions & 0 deletions dts/arm/ti/cc23x0.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@
clocks = <&sysclk>;
status = "disabled";
};

rtc0: rtc@40002000 {
compatible = "ti,cc23x0-rtc";
reg = <0x40002000 0x64>;
interrupts = <3 0>;
status = "disabled";
};
};
};

Expand Down
15 changes: 15 additions & 0 deletions dts/bindings/counter/ti,cc23x0-rtc.yaml
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions samples/drivers/counter/alarm/boards/lp_em_cc2340r5.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
&rtc0 {
status = "okay";
};
1 change: 1 addition & 0 deletions samples/drivers/counter/alarm/sample.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions samples/drivers/counter/alarm/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading