drivers: timer: Add ULPT timer for power management on Renesas RA MCUs
drivers: - Added ULPT timer driver in `renesas_ra_ulpt_timer.c`. - Updated `clock_control_renesas_ra_cgc.c` for ULPT clock settings. - Updated `uart_renesas_ra8_sci_b.c` for power management support. - Updated `CMakeLists.txt` and `Kconfig` to integrate ULPT timer. - Added `Kconfig.renesas_ra_ulpt` for ULPT-specific configurations. dts bindings: - Added `renesas,ra-ulpt.yaml` for ULPT node bindings. - Added `renesas,ra-ulpt-timer.yaml` for ULPT timer bindings. modules: - Updated `Kconfig.renesas_fsp` to support ULPT and LPM. Signed-off-by: Khanh Nguyen <khanh.nguyen.wz@bp.renesas.com>
This commit is contained in:
parent
8f2879a156
commit
7ae800a0c9
9 changed files with 413 additions and 2 deletions
|
@ -23,7 +23,7 @@ static volatile uint32_t *mstp_regs[] = {
|
||||||
static volatile uint32_t *mstp_regs[] = {};
|
static volatile uint32_t *mstp_regs[] = {};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(CONFIG_PM)
|
#if defined(CONFIG_CORTEX_M_SYSTICK)
|
||||||
/* If a CPU clock exists in the system, it will be the source for the CPU */
|
/* If a CPU clock exists in the system, it will be the source for the CPU */
|
||||||
#if BSP_FEATURE_CGC_HAS_CPUCLK
|
#if BSP_FEATURE_CGC_HAS_CPUCLK
|
||||||
#define sys_clk DT_NODELABEL(cpuclk)
|
#define sys_clk DT_NODELABEL(cpuclk)
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
#include <zephyr/drivers/pinctrl.h>
|
#include <zephyr/drivers/pinctrl.h>
|
||||||
#include <zephyr/sys/util.h>
|
#include <zephyr/sys/util.h>
|
||||||
#include <zephyr/irq.h>
|
#include <zephyr/irq.h>
|
||||||
|
#include <zephyr/pm/device.h>
|
||||||
|
#include <zephyr/pm/policy.h>
|
||||||
|
#include <zephyr/pm/device_runtime.h>
|
||||||
#include <soc.h>
|
#include <soc.h>
|
||||||
#include "r_sci_b_uart.h"
|
#include "r_sci_b_uart.h"
|
||||||
#include "r_dtc.h"
|
#include "r_dtc.h"
|
||||||
|
@ -73,8 +76,78 @@ struct uart_ra_sci_b_data {
|
||||||
uart_callback_t async_user_cb;
|
uart_callback_t async_user_cb;
|
||||||
void *async_user_cb_data;
|
void *async_user_cb_data;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
bool rx_ongoing;
|
||||||
|
bool tx_ongoing;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if CONFIG_PM
|
||||||
|
static inline void uart_ra_sci_b_rx_pm_policy_state_lock_get(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct uart_ra_sci_b_data *data = dev->data;
|
||||||
|
|
||||||
|
if (!data->rx_ongoing) {
|
||||||
|
data->rx_ongoing = true;
|
||||||
|
#if CONFIG_PM_NEED_ALL_DEVICES_IDLE
|
||||||
|
pm_device_busy_set(dev);
|
||||||
|
#else
|
||||||
|
pm_policy_state_lock_get(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
|
||||||
|
pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void uart_ra_sci_b_rx_pm_policy_state_lock_put(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct uart_ra_sci_b_data *data = dev->data;
|
||||||
|
|
||||||
|
if (data->rx_ongoing) {
|
||||||
|
data->rx_ongoing = false;
|
||||||
|
#if CONFIG_PM_NEED_ALL_DEVICES_IDLE
|
||||||
|
if (!data->tx_ongoing) {
|
||||||
|
pm_device_busy_clear(dev);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
pm_policy_state_lock_put(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
|
||||||
|
pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void uart_ra_sci_b_tx_pm_policy_state_lock_get(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct uart_ra_sci_b_data *data = dev->data;
|
||||||
|
|
||||||
|
if (!data->tx_ongoing) {
|
||||||
|
data->tx_ongoing = true;
|
||||||
|
#if CONFIG_PM_NEED_ALL_DEVICES_IDLE
|
||||||
|
pm_device_busy_set(dev);
|
||||||
|
#else
|
||||||
|
pm_policy_state_lock_get(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
|
||||||
|
pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void uart_ra_sci_b_tx_pm_policy_state_lock_put(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct uart_ra_sci_b_data *data = dev->data;
|
||||||
|
|
||||||
|
if (data->tx_ongoing) {
|
||||||
|
data->tx_ongoing = false;
|
||||||
|
#if CONFIG_PM_NEED_ALL_DEVICES_IDLE
|
||||||
|
if (!data->rx_ongoing) {
|
||||||
|
pm_device_busy_clear(dev);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
pm_policy_state_lock_put(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
|
||||||
|
pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int uart_ra_sci_b_poll_in(const struct device *dev, unsigned char *c)
|
static int uart_ra_sci_b_poll_in(const struct device *dev, unsigned char *c)
|
||||||
{
|
{
|
||||||
const struct uart_ra_sci_b_config *cfg = dev->config;
|
const struct uart_ra_sci_b_config *cfg = dev->config;
|
||||||
|
@ -100,10 +173,21 @@ static void uart_ra_sci_b_poll_out(const struct device *dev, unsigned char c)
|
||||||
{
|
{
|
||||||
const struct uart_ra_sci_b_config *cfg = dev->config;
|
const struct uart_ra_sci_b_config *cfg = dev->config;
|
||||||
|
|
||||||
|
#if CONFIG_PM
|
||||||
|
uart_ra_sci_b_tx_pm_policy_state_lock_get(dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
while (cfg->regs->CSR_b.TEND == 0U) {
|
while (cfg->regs->CSR_b.TEND == 0U) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg->regs->TDR_BY = c;
|
cfg->regs->TDR_BY = c;
|
||||||
|
|
||||||
|
while (cfg->regs->CSR_b.TEND == 0U) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_PM
|
||||||
|
uart_ra_sci_b_tx_pm_policy_state_lock_put(dev);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int uart_ra_sci_b_err_check(const struct device *dev)
|
static int uart_ra_sci_b_err_check(const struct device *dev)
|
||||||
|
@ -311,6 +395,10 @@ static void uart_ra_sci_b_irq_tx_enable(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct uart_ra_sci_b_config *cfg = dev->config;
|
const struct uart_ra_sci_b_config *cfg = dev->config;
|
||||||
|
|
||||||
|
#if CONFIG_PM
|
||||||
|
uart_ra_sci_b_tx_pm_policy_state_lock_get(dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
cfg->regs->CCR0 |= (BIT(R_SCI_B0_CCR0_TIE_Pos) | BIT(R_SCI_B0_CCR0_TEIE_Pos));
|
cfg->regs->CCR0 |= (BIT(R_SCI_B0_CCR0_TIE_Pos) | BIT(R_SCI_B0_CCR0_TEIE_Pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,6 +407,10 @@ static void uart_ra_sci_b_irq_tx_disable(const struct device *dev)
|
||||||
const struct uart_ra_sci_b_config *cfg = dev->config;
|
const struct uart_ra_sci_b_config *cfg = dev->config;
|
||||||
|
|
||||||
cfg->regs->CCR0 &= ~(BIT(R_SCI_B0_CCR0_TIE_Pos) | BIT(R_SCI_B0_CCR0_TEIE_Pos));
|
cfg->regs->CCR0 &= ~(BIT(R_SCI_B0_CCR0_TIE_Pos) | BIT(R_SCI_B0_CCR0_TEIE_Pos));
|
||||||
|
|
||||||
|
#if CONFIG_PM
|
||||||
|
uart_ra_sci_b_tx_pm_policy_state_lock_put(dev);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int uart_ra_sci_b_irq_tx_ready(const struct device *dev)
|
static int uart_ra_sci_b_irq_tx_ready(const struct device *dev)
|
||||||
|
@ -342,6 +434,10 @@ static void uart_ra_sci_b_irq_rx_enable(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct uart_ra_sci_b_config *cfg = dev->config;
|
const struct uart_ra_sci_b_config *cfg = dev->config;
|
||||||
|
|
||||||
|
#if CONFIG_PM
|
||||||
|
uart_ra_sci_b_rx_pm_policy_state_lock_get(dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
cfg->regs->CCR0_b.RIE = 1U;
|
cfg->regs->CCR0_b.RIE = 1U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,6 +446,10 @@ static void uart_ra_sci_b_irq_rx_disable(const struct device *dev)
|
||||||
const struct uart_ra_sci_b_config *cfg = dev->config;
|
const struct uart_ra_sci_b_config *cfg = dev->config;
|
||||||
|
|
||||||
cfg->regs->CCR0_b.RIE = 0U;
|
cfg->regs->CCR0_b.RIE = 0U;
|
||||||
|
|
||||||
|
#if CONFIG_PM
|
||||||
|
uart_ra_sci_b_rx_pm_policy_state_lock_put(dev);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int uart_ra_sci_b_irq_rx_ready(const struct device *dev)
|
static int uart_ra_sci_b_irq_rx_ready(const struct device *dev)
|
||||||
|
@ -637,6 +737,10 @@ static int uart_ra_sci_b_async_tx(const struct device *dev, const uint8_t *buf,
|
||||||
data->tx_buffer = (uint8_t *)buf;
|
data->tx_buffer = (uint8_t *)buf;
|
||||||
data->tx_buffer_cap = len;
|
data->tx_buffer_cap = len;
|
||||||
|
|
||||||
|
#if CONFIG_PM
|
||||||
|
uart_ra_sci_b_tx_pm_policy_state_lock_get(dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
uart_ra_sci_b_async_timer_start(&data->tx_timeout_work, timeout);
|
uart_ra_sci_b_async_timer_start(&data->tx_timeout_work, timeout);
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
|
@ -687,6 +791,10 @@ static int uart_ra_sci_b_async_tx_abort(const struct device *dev)
|
||||||
|
|
||||||
async_tx_abort(dev);
|
async_tx_abort(dev);
|
||||||
|
|
||||||
|
#if CONFIG_PM
|
||||||
|
uart_ra_sci_b_tx_pm_policy_state_lock_put(dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -720,6 +828,10 @@ static int uart_ra_sci_b_async_rx_enable(const struct device *dev, uint8_t *buf,
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_PM
|
||||||
|
uart_ra_sci_b_rx_pm_policy_state_lock_get(dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
data->rx_timeout = timeout;
|
data->rx_timeout = timeout;
|
||||||
data->rx_buffer = buf;
|
data->rx_buffer = buf;
|
||||||
data->rx_buffer_cap = len;
|
data->rx_buffer_cap = len;
|
||||||
|
@ -772,6 +884,10 @@ static int uart_ra_sci_b_async_rx_disable(const struct device *dev)
|
||||||
cfg->regs->CFCLR_b.RDRFC = 1U;
|
cfg->regs->CFCLR_b.RDRFC = 1U;
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
|
#if CONFIG_PM
|
||||||
|
uart_ra_sci_b_rx_pm_policy_state_lock_put(dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
irq_unlock(key);
|
irq_unlock(key);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -833,6 +949,40 @@ static void uart_ra_sci_b_callback_adapter(struct st_uart_callback_arg *fsp_args
|
||||||
|
|
||||||
#endif /* CONFIG_UART_ASYNC_API */
|
#endif /* CONFIG_UART_ASYNC_API */
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_DEVICE
|
||||||
|
static int uart_ra_sci_b_pm_action(const struct device *dev, enum pm_device_action action)
|
||||||
|
{
|
||||||
|
struct uart_ra_sci_b_data *data = dev->data;
|
||||||
|
fsp_err_t fsp_err;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case PM_DEVICE_ACTION_SUSPEND:
|
||||||
|
/* Deinitialize the device */
|
||||||
|
fsp_err = R_SCI_B_UART_Close(&data->sci);
|
||||||
|
__ASSERT(fsp_err == 0, "sci_uart: initialization: close failed");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PM_DEVICE_ACTION_RESUME:
|
||||||
|
/* Reinitialize the device */
|
||||||
|
int ret = uart_ra_sci_b_apply_config(&data->uart_config, &data->fsp_config,
|
||||||
|
&data->fsp_config_extend,
|
||||||
|
&data->fsp_baud_setting);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
fsp_err = R_SCI_B_UART_Open(&data->sci, &data->fsp_config);
|
||||||
|
__ASSERT(fsp_err == 0, "sci_uart: initialization: open failed");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_PM_DEVICE */
|
||||||
|
|
||||||
static DEVICE_API(uart, uart_ra_sci_b_driver_api) = {
|
static DEVICE_API(uart, uart_ra_sci_b_driver_api) = {
|
||||||
.poll_in = uart_ra_sci_b_poll_in,
|
.poll_in = uart_ra_sci_b_poll_in,
|
||||||
.poll_out = uart_ra_sci_b_poll_out,
|
.poll_out = uart_ra_sci_b_poll_out,
|
||||||
|
@ -971,6 +1121,9 @@ static void uart_ra_sci_b_tei_isr(const struct device *dev)
|
||||||
#if defined(CONFIG_UART_ASYNC_API)
|
#if defined(CONFIG_UART_ASYNC_API)
|
||||||
k_work_cancel_delayable(&data->tx_timeout_work);
|
k_work_cancel_delayable(&data->tx_timeout_work);
|
||||||
sci_b_uart_tei_isr();
|
sci_b_uart_tei_isr();
|
||||||
|
#if CONFIG_PM
|
||||||
|
uart_ra_sci_b_tx_pm_policy_state_lock_put(dev);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
R_ICU->IELSR_b[data->fsp_config.tei_irq].IR = 0U;
|
R_ICU->IELSR_b[data->fsp_config.tei_irq].IR = 0U;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1152,7 +1305,8 @@ static void uart_ra_sci_b_eri_isr(const struct device *dev)
|
||||||
return 0; \
|
return 0; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
DEVICE_DT_INST_DEFINE(index, uart_ra_sci_b_init_##index, NULL, \
|
PM_DEVICE_DT_INST_DEFINE(index, uart_ra_sci_b_pm_action); \
|
||||||
|
DEVICE_DT_INST_DEFINE(index, uart_ra_sci_b_init_##index, PM_DEVICE_DT_INST_GET(index), \
|
||||||
&uart_ra_sci_b_data_##index, &uart_ra_sci_b_config_##index, \
|
&uart_ra_sci_b_data_##index, &uart_ra_sci_b_config_##index, \
|
||||||
PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
|
PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
|
||||||
&uart_ra_sci_b_driver_api);
|
&uart_ra_sci_b_driver_api);
|
||||||
|
|
|
@ -32,6 +32,7 @@ zephyr_library_sources_ifdef(CONFIG_NPCX_ITIM_TIMER npcx_itim_timer.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_NRF_GRTC_TIMER nrf_grtc_timer.c)
|
zephyr_library_sources_ifdef(CONFIG_NRF_GRTC_TIMER nrf_grtc_timer.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_NRF_RTC_TIMER nrf_rtc_timer.c)
|
zephyr_library_sources_ifdef(CONFIG_NRF_RTC_TIMER nrf_rtc_timer.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_RCAR_CMT_TIMER rcar_cmt_timer.c)
|
zephyr_library_sources_ifdef(CONFIG_RCAR_CMT_TIMER rcar_cmt_timer.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_RENESAS_RA_ULPT_TIMER renesas_ra_ulpt_timer.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_RISCV_MACHINE_TIMER riscv_machine_timer.c)
|
zephyr_library_sources_ifdef(CONFIG_RISCV_MACHINE_TIMER riscv_machine_timer.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_RV32M1_LPTMR_TIMER rv32m1_lptmr_timer.c)
|
zephyr_library_sources_ifdef(CONFIG_RV32M1_LPTMR_TIMER rv32m1_lptmr_timer.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_REALTEK_RTS5912_RTMR realtek_rts5912_rtmr.c)
|
zephyr_library_sources_ifdef(CONFIG_REALTEK_RTS5912_RTMR realtek_rts5912_rtmr.c)
|
||||||
|
|
|
@ -102,6 +102,7 @@ source "drivers/timer/Kconfig.xlnx_psttc"
|
||||||
source "drivers/timer/Kconfig.xtensa"
|
source "drivers/timer/Kconfig.xtensa"
|
||||||
source "drivers/timer/Kconfig.mtk_adsp"
|
source "drivers/timer/Kconfig.mtk_adsp"
|
||||||
source "drivers/timer/Kconfig.sy1xx_sys_timer"
|
source "drivers/timer/Kconfig.sy1xx_sys_timer"
|
||||||
|
source "drivers/timer/Kconfig.renesas_ra_ulpt"
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
|
|
11
drivers/timer/Kconfig.renesas_ra_ulpt
Normal file
11
drivers/timer/Kconfig.renesas_ra_ulpt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# Copyright (c) 2025 Renesas Electronics Corporation
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
config RENESAS_RA_ULPT_TIMER
|
||||||
|
bool "Renesas RA Series ULPT Timer"
|
||||||
|
default y if PM
|
||||||
|
depends on DT_HAS_RENESAS_RA_ULPT_TIMER_ENABLED
|
||||||
|
select TICKLESS_CAPABLE
|
||||||
|
help
|
||||||
|
This module implements a kernel device driver for the Renesas RA series
|
||||||
|
ULPT timer and provides the standard "system clock driver" interfaces.
|
194
drivers/timer/renesas_ra_ulpt_timer.c
Normal file
194
drivers/timer/renesas_ra_ulpt_timer.c
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Renesas Electronics Corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <zephyr/drivers/timer/system_timer.h>
|
||||||
|
#include <zephyr/irq.h>
|
||||||
|
#include <zephyr/spinlock.h>
|
||||||
|
#include <zephyr/sys_clock.h>
|
||||||
|
#include <soc.h>
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT renesas_ra_ulpt_timer
|
||||||
|
|
||||||
|
/* Ensure there are exactly two ULPT timer instances
|
||||||
|
* enabled in the device tree.
|
||||||
|
*/
|
||||||
|
BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 2,
|
||||||
|
"Requires two instances of the ULPT timer to be enabled.");
|
||||||
|
|
||||||
|
/* ULPT instance 0: Used to announce ticks to the kernel. */
|
||||||
|
#define RA_ULPT_INST0_NODE DT_INST_PARENT(0)
|
||||||
|
#define RA_ULPT_INST0_REG ((R_ULPT0_Type *)DT_REG_ADDR(RA_ULPT_INST0_NODE))
|
||||||
|
#define RA_ULPT_INST0_IRQN DT_IRQ_BY_NAME(RA_ULPT_INST0_NODE, ulpti, irq)
|
||||||
|
#define RA_ULPT_INST0_IRQP 0U
|
||||||
|
#define RA_ULPT_INST0_CHANNEL DT_PROP(RA_ULPT_INST0_NODE, channel)
|
||||||
|
|
||||||
|
/* ULPT instance 1: Used for synchronization with hardware cycle clock. */
|
||||||
|
#define RA_ULPT_INST1_NODE DT_INST_PARENT(1)
|
||||||
|
#define RA_ULPT_INST1_REG ((R_ULPT0_Type *)DT_REG_ADDR(RA_ULPT_INST1_NODE))
|
||||||
|
#define RA_ULPT_INST1_CHANNEL DT_PROP(RA_ULPT_INST1_NODE, channel)
|
||||||
|
|
||||||
|
/* Constants for timer configuration and behavior. */
|
||||||
|
#define RA_ULPT_RELOAD_DELAY 4U
|
||||||
|
#define RA_ULPT_RELOAD_MIN 4U
|
||||||
|
#define RA_ULPT_RELOAD_MAX UINT32_MAX
|
||||||
|
|
||||||
|
#define RA_ULPT_PRV_ULPTCR_STATUS_FLAGS 0xE0U
|
||||||
|
#define RA_ULPT_PRV_ULPTCR_START_TIMER 0xE1U
|
||||||
|
|
||||||
|
/* Macro to get ELC event for ULPT interrupt based on the channel. */
|
||||||
|
#define ELC_EVENT_ULPT_INT(channel) CONCAT(ELC_EVENT_ULPT, channel, _INT)
|
||||||
|
|
||||||
|
/* Calculated constants for timer operation. */
|
||||||
|
#define CYCLE_PER_TICK ((sys_clock_hw_cycles_per_sec() / CONFIG_SYS_CLOCK_TICKS_PER_SEC))
|
||||||
|
#define MAX_TICKS ((k_ticks_t)(RA_ULPT_RELOAD_MAX / CYCLE_PER_TICK) - 1)
|
||||||
|
|
||||||
|
/* Static variables for maintaining timer state. */
|
||||||
|
static uint32_t cycle_announced;
|
||||||
|
static struct k_spinlock lock;
|
||||||
|
|
||||||
|
static void ra_ulpt_timer_isr(void)
|
||||||
|
{
|
||||||
|
uint32_t cycles;
|
||||||
|
uint32_t dcycles;
|
||||||
|
uint32_t dticks;
|
||||||
|
IRQn_Type irq = R_FSP_CurrentIrqGet();
|
||||||
|
|
||||||
|
/* Clear pending IRQ to prevent re-triggering. */
|
||||||
|
R_BSP_IrqStatusClear(irq);
|
||||||
|
|
||||||
|
if (RA_ULPT_INST0_REG->ULPTCR_b.TUNDF) {
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
|
||||||
|
/* Calculate elapsed cycles and ticks. */
|
||||||
|
cycles = ~RA_ULPT_INST1_REG->ULPTCNT;
|
||||||
|
dcycles = cycles - cycle_announced;
|
||||||
|
dticks = dcycles / CYCLE_PER_TICK;
|
||||||
|
cycle_announced += dticks * CYCLE_PER_TICK;
|
||||||
|
} else {
|
||||||
|
/* In tickful mode, announce one tick at a time. */
|
||||||
|
dticks = 1;
|
||||||
|
}
|
||||||
|
/* Clear the underflow flag. */
|
||||||
|
RA_ULPT_INST0_REG->ULPTCR_b.TUNDF = 0;
|
||||||
|
k_spin_unlock(&lock, key);
|
||||||
|
|
||||||
|
/* Announce the elapsed ticks to the kernel. */
|
||||||
|
sys_clock_announce(dticks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sys_clock_set_timeout(int32_t ticks, bool idle)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(idle);
|
||||||
|
|
||||||
|
/* Timeout configuration is unsupported in tickful mode. */
|
||||||
|
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No timeout change for K_TICKS_FOREVER or INT32_MAX. */
|
||||||
|
if (ticks == K_TICKS_FOREVER || ticks == INT32_MAX) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clamp the ticks value to a valid range. */
|
||||||
|
ticks = CLAMP(ticks - 1, 0, (int32_t)MAX_TICKS);
|
||||||
|
|
||||||
|
/* Calculate the timer delay in cycles. */
|
||||||
|
uint32_t cycles = ~RA_ULPT_INST1_REG->ULPTCNT;
|
||||||
|
uint32_t unannounced = cycles - cycle_announced;
|
||||||
|
uint32_t delay = ticks * CYCLE_PER_TICK;
|
||||||
|
|
||||||
|
/* Adjust delay to align with tick boundaries. */
|
||||||
|
delay += unannounced;
|
||||||
|
delay = DIV_ROUND_UP(delay, CYCLE_PER_TICK) * CYCLE_PER_TICK;
|
||||||
|
delay -= unannounced;
|
||||||
|
delay = MAX(delay, RA_ULPT_RELOAD_MIN + RA_ULPT_RELOAD_DELAY);
|
||||||
|
delay -= RA_ULPT_RELOAD_DELAY;
|
||||||
|
|
||||||
|
/* Update the timer counter. */
|
||||||
|
RA_ULPT_INST0_REG->ULPTCNT = delay - 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sys_clock_elapsed(void)
|
||||||
|
{
|
||||||
|
/* Elapsed time calculation is unsupported in tickful mode. */
|
||||||
|
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate and return the number of elapsed cycles. */
|
||||||
|
uint32_t cycles = ~RA_ULPT_INST1_REG->ULPTCNT - cycle_announced;
|
||||||
|
|
||||||
|
return (cycles / CYCLE_PER_TICK);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sys_clock_cycle_get_32(void)
|
||||||
|
{
|
||||||
|
return ~RA_ULPT_INST1_REG->ULPTCNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sys_clock_driver_init(void)
|
||||||
|
{
|
||||||
|
/* Power on ULPT modules. */
|
||||||
|
R_BSP_MODULE_START(FSP_IP_ULPT, RA_ULPT_INST0_CHANNEL);
|
||||||
|
R_BSP_MODULE_START(FSP_IP_ULPT, RA_ULPT_INST1_CHANNEL);
|
||||||
|
|
||||||
|
/* Stop timers and reset control registers. */
|
||||||
|
RA_ULPT_INST0_REG->ULPTCR = 0U;
|
||||||
|
RA_ULPT_INST1_REG->ULPTCR = 0U;
|
||||||
|
|
||||||
|
/* Wait for timers to stop. */
|
||||||
|
FSP_HARDWARE_REGISTER_WAIT(0U, RA_ULPT_INST0_REG->ULPTCR_b.TCSTF);
|
||||||
|
FSP_HARDWARE_REGISTER_WAIT(0U, RA_ULPT_INST1_REG->ULPTCR_b.TCSTF);
|
||||||
|
|
||||||
|
/* Clear configuration registers before setup. */
|
||||||
|
RA_ULPT_INST0_REG->ULPTMR2 = 0U;
|
||||||
|
RA_ULPT_INST1_REG->ULPTMR2 = 0U;
|
||||||
|
|
||||||
|
/* Configure timer instance 0. */
|
||||||
|
RA_ULPT_INST0_REG->ULPTMR1 = 0U;
|
||||||
|
RA_ULPT_INST0_REG->ULPTMR2 = 0U;
|
||||||
|
RA_ULPT_INST0_REG->ULPTMR3 = 0U;
|
||||||
|
RA_ULPT_INST0_REG->ULPTIOC = 0U;
|
||||||
|
RA_ULPT_INST0_REG->ULPTISR = 0U;
|
||||||
|
RA_ULPT_INST0_REG->ULPTCMSR = 0U;
|
||||||
|
|
||||||
|
/* Configure timer instance 1. */
|
||||||
|
RA_ULPT_INST1_REG->ULPTMR1 = 0U;
|
||||||
|
RA_ULPT_INST1_REG->ULPTMR2 = 0U;
|
||||||
|
RA_ULPT_INST1_REG->ULPTMR3 = 0U;
|
||||||
|
RA_ULPT_INST1_REG->ULPTIOC = 0U;
|
||||||
|
RA_ULPT_INST1_REG->ULPTISR = 0U;
|
||||||
|
RA_ULPT_INST1_REG->ULPTCMSR = 0U;
|
||||||
|
|
||||||
|
/* Initialize timer counters. */
|
||||||
|
RA_ULPT_INST0_REG->ULPTCNT = CYCLE_PER_TICK - 1U;
|
||||||
|
RA_ULPT_INST1_REG->ULPTCNT = RA_ULPT_RELOAD_MAX;
|
||||||
|
|
||||||
|
/* Set up interrupts for timer instance 0. */
|
||||||
|
R_ICU->IELSR[RA_ULPT_INST0_IRQN] = ELC_EVENT_ULPT_INT(RA_ULPT_INST0_CHANNEL);
|
||||||
|
IRQ_CONNECT(RA_ULPT_INST0_IRQN, RA_ULPT_INST0_IRQP, ra_ulpt_timer_isr, NULL, 0);
|
||||||
|
irq_enable(RA_ULPT_INST0_IRQN);
|
||||||
|
|
||||||
|
/* Start both timers. */
|
||||||
|
RA_ULPT_INST0_REG->ULPTCR = RA_ULPT_PRV_ULPTCR_START_TIMER;
|
||||||
|
RA_ULPT_INST1_REG->ULPTCR = RA_ULPT_PRV_ULPTCR_START_TIMER;
|
||||||
|
|
||||||
|
/* Wait for timers to start completely. */
|
||||||
|
FSP_HARDWARE_REGISTER_WAIT(RA_ULPT_INST0_REG->ULPTCR_b.TSTART,
|
||||||
|
RA_ULPT_INST0_REG->ULPTCR_b.TCSTF);
|
||||||
|
FSP_HARDWARE_REGISTER_WAIT(RA_ULPT_INST1_REG->ULPTCR_b.TSTART,
|
||||||
|
RA_ULPT_INST1_REG->ULPTCR_b.TCSTF);
|
||||||
|
cycle_announced = 0U;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the system timer driver during pre-kernel stage 2. */
|
||||||
|
SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);
|
30
dts/bindings/misc/renesas,ra-ulpt.yaml
Normal file
30
dts/bindings/misc/renesas,ra-ulpt.yaml
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# Copyright (c) 2025 Renesas Electronics Corporation
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
description: Renesas RA ULPT
|
||||||
|
|
||||||
|
compatible: "renesas,ra-ulpt"
|
||||||
|
|
||||||
|
include: base.yaml
|
||||||
|
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
channel:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: |
|
||||||
|
ULPT channel number.
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
description: |
|
||||||
|
IRQ number and priority to use for ULPT.
|
||||||
|
|
||||||
|
interrupt-names:
|
||||||
|
enum:
|
||||||
|
- "ulpti"
|
||||||
|
- "ulptcmai"
|
||||||
|
- "ulptcmbi"
|
||||||
|
description: |
|
||||||
|
Interrupts must be given corresponding names so that the timer driver can recognize them.
|
8
dts/bindings/timer/renesas,ra-ulpt-timer.yaml
Normal file
8
dts/bindings/timer/renesas,ra-ulpt-timer.yaml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Copyright (c) 2025 Renesas Electronics Corporation
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
description: Renesas RA ULPT TIMER
|
||||||
|
|
||||||
|
compatible: "renesas,ra-ulpt-timer"
|
||||||
|
|
||||||
|
include: base.yaml
|
|
@ -169,6 +169,18 @@ config USE_RA_FSP_WDT
|
||||||
help
|
help
|
||||||
Enable RA FSP WDT driver
|
Enable RA FSP WDT driver
|
||||||
|
|
||||||
|
config USE_RA_FSP_ULPT
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
Enable RA FSP ULPT driver
|
||||||
|
|
||||||
|
config USE_RA_FSP_LPM
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
depends on PM
|
||||||
|
help
|
||||||
|
Enable RA FSP LPM driver
|
||||||
|
|
||||||
endif # HAS_RENESAS_RA_FSP
|
endif # HAS_RENESAS_RA_FSP
|
||||||
|
|
||||||
if HAS_RENESAS_RZ_FSP
|
if HAS_RENESAS_RZ_FSP
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue