drivers: timer: Add timer driver to Renesas SmartBond(tm)
This adds timer driver for Renesas SmartBond(tm) family. It uses TIMER2 block which is in PD_TIM power domain so it can work even if ARM core is disabled, thus can work as a sleep timer. Signed-off-by: Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl> Signed-off-by: Jerzy Kasenberg <jerzy.kasenberg@codecoup.pl>
This commit is contained in:
parent
3247a1db81
commit
6307d8de78
|
@ -33,3 +33,4 @@ zephyr_library_sources_ifdef(CONFIG_SAM0_RTC_TIMER sam0_rtc_timer.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_STM32_LPTIM_TIMER stm32_lptim_timer.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_XLNX_PSTTC_TIMER xlnx_psttc_timer.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_XTENSA_TIMER xtensa_sys_timer.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SMARTBOND_TIMER smartbond_timer.c)
|
||||
|
|
|
@ -90,6 +90,7 @@ source "drivers/timer/Kconfig.rcar_cmt"
|
|||
source "drivers/timer/Kconfig.riscv_machine"
|
||||
source "drivers/timer/Kconfig.rv32m1_lptmr"
|
||||
source "drivers/timer/Kconfig.sam0_rtc"
|
||||
source "drivers/timer/Kconfig.smartbond"
|
||||
source "drivers/timer/Kconfig.stm32_lptim"
|
||||
source "drivers/timer/Kconfig.xlnx_psttc"
|
||||
source "drivers/timer/Kconfig.xtensa"
|
||||
|
|
13
drivers/timer/Kconfig.smartbond
Normal file
13
drivers/timer/Kconfig.smartbond
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Copyright (c) 2023 Renesas Electronics Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config SMARTBOND_TIMER
|
||||
bool "Renesas SmartBond(tm) timer"
|
||||
default y
|
||||
depends on SOC_FAMILY_RENESAS_SMARTBOND
|
||||
depends on CLOCK_CONTROL
|
||||
depends on !$(dt_nodelabel_enabled,timer2)
|
||||
select TICKLESS_CAPABLE
|
||||
help
|
||||
This module implements a kernel device driver for the TIMER2 timer
|
||||
and provides the standard "system clock driver" interfaces.
|
161
drivers/timer/smartbond_timer.c
Normal file
161
drivers/timer/smartbond_timer.c
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Renesas Electronics Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/timer/system_timer.h>
|
||||
#include <zephyr/sys_clock.h>
|
||||
#include <zephyr/spinlock.h>
|
||||
#include <cmsis_core.h>
|
||||
#include <zephyr/irq.h>
|
||||
#include <da1469x_pdc.h>
|
||||
|
||||
#define COUNTER_SPAN BIT(24)
|
||||
#define CYC_PER_TICK k_ticks_to_cyc_ceil32(1)
|
||||
#define TICK_TO_CYC(tick) k_ticks_to_cyc_ceil32(tick)
|
||||
#define CYC_TO_TICK(cyc) k_cyc_to_ticks_ceil32(cyc)
|
||||
#define MAX_TICKS (((COUNTER_SPAN / 2) - CYC_PER_TICK) / (CYC_PER_TICK))
|
||||
|
||||
static uint32_t last_timer_val_reg;
|
||||
static uint32_t timer_val_31_24;
|
||||
|
||||
static uint32_t last_isr_val;
|
||||
static uint32_t last_isr_val_rounded;
|
||||
static uint32_t announced_ticks;
|
||||
|
||||
static void set_reload(uint32_t val)
|
||||
{
|
||||
TIMER2->TIMER2_RELOAD_REG = val & TIMER2_TIMER2_RELOAD_REG_TIM_RELOAD_Msk;
|
||||
}
|
||||
|
||||
static uint32_t timer_val_32(void)
|
||||
{
|
||||
uint32_t timer_val_reg;
|
||||
uint32_t val;
|
||||
|
||||
timer_val_reg = TIMER2->TIMER2_TIMER_VAL_REG &
|
||||
TIMER2_TIMER2_TIMER_VAL_REG_TIM_TIMER_VALUE_Msk;
|
||||
if (timer_val_reg < last_timer_val_reg) {
|
||||
timer_val_31_24 += COUNTER_SPAN;
|
||||
}
|
||||
last_timer_val_reg = timer_val_reg;
|
||||
|
||||
val = timer_val_31_24 + timer_val_reg;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t timer_val_32_noupdate(void)
|
||||
{
|
||||
uint32_t timer_val_reg;
|
||||
uint32_t val;
|
||||
|
||||
timer_val_reg = TIMER2->TIMER2_TIMER_VAL_REG &
|
||||
TIMER2_TIMER2_TIMER_VAL_REG_TIM_TIMER_VALUE_Msk;
|
||||
val = timer_val_31_24 + timer_val_reg;
|
||||
if (timer_val_reg < last_timer_val_reg) {
|
||||
val += COUNTER_SPAN;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void sys_clock_set_timeout(int32_t ticks, bool idle)
|
||||
{
|
||||
uint32_t target_val;
|
||||
uint32_t timer_val;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ticks == K_TICKS_FOREVER) {
|
||||
/* FIXME we could disable timer here */
|
||||
}
|
||||
|
||||
ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks;
|
||||
ticks = CLAMP(ticks - 1, 0, (int32_t)MAX_TICKS);
|
||||
|
||||
timer_val = timer_val_32_noupdate();
|
||||
|
||||
/* Calculate target timer value and align to full tick */
|
||||
target_val = timer_val + TICK_TO_CYC(ticks);
|
||||
target_val = ((target_val + CYC_PER_TICK - 1) / CYC_PER_TICK) * CYC_PER_TICK;
|
||||
|
||||
set_reload(target_val);
|
||||
}
|
||||
|
||||
uint32_t sys_clock_elapsed(void)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return CYC_TO_TICK(timer_val_32_noupdate() - last_isr_val);
|
||||
}
|
||||
|
||||
uint32_t sys_clock_cycle_get_32(void)
|
||||
{
|
||||
return timer_val_32_noupdate();
|
||||
}
|
||||
|
||||
void sys_clock_idle_exit(void)
|
||||
{
|
||||
TIMER2->TIMER2_CTRL_REG |= TIMER2_TIMER2_CTRL_REG_TIM_EN_Msk;
|
||||
}
|
||||
|
||||
void sys_clock_disable(void)
|
||||
{
|
||||
TIMER2->TIMER2_CTRL_REG &= ~TIMER2_TIMER2_CTRL_REG_TIM_EN_Msk;
|
||||
}
|
||||
|
||||
static void timer2_isr(const void *arg)
|
||||
{
|
||||
uint32_t val;
|
||||
int32_t delta;
|
||||
int32_t dticks;
|
||||
|
||||
ARG_UNUSED(arg);
|
||||
|
||||
TIMER2->TIMER2_CLEAR_IRQ_REG = 1;
|
||||
|
||||
val = timer_val_32();
|
||||
delta = (int32_t)(val - last_isr_val_rounded);
|
||||
last_isr_val = val;
|
||||
dticks = CYC_TO_TICK(delta);
|
||||
last_isr_val_rounded += TICK_TO_CYC(dticks);
|
||||
announced_ticks += dticks;
|
||||
sys_clock_announce(dticks);
|
||||
}
|
||||
|
||||
static int sys_clock_driver_init(void)
|
||||
{
|
||||
#if CONFIG_PM
|
||||
uint8_t pdc_idx;
|
||||
uint8_t en_xtal;
|
||||
|
||||
en_xtal = DT_NODE_HAS_STATUS(DT_NODELABEL(xtal32m), okay) ? MCU_PDC_EN_XTAL : 0;
|
||||
|
||||
/* Enable wakeup by TIMER2 */
|
||||
pdc_idx = da1469x_pdc_add(MCU_PDC_TRIGGER_TIMER2, MCU_PDC_MASTER_M33, en_xtal);
|
||||
__ASSERT_NO_MSG(pdc_idx >= 0);
|
||||
da1469x_pdc_set(pdc_idx);
|
||||
da1469x_pdc_ack(pdc_idx);
|
||||
#endif
|
||||
|
||||
TIMER2->TIMER2_CTRL_REG = 0;
|
||||
TIMER2->TIMER2_PRESCALER_REG = 0;
|
||||
TIMER2->TIMER2_CTRL_REG |= TIMER2_TIMER2_CTRL_REG_TIM_CLK_EN_Msk;
|
||||
TIMER2->TIMER2_CTRL_REG |= TIMER2_TIMER2_CTRL_REG_TIM_FREE_RUN_MODE_EN_Msk |
|
||||
TIMER2_TIMER2_CTRL_REG_TIM_IRQ_EN_Msk |
|
||||
TIMER2_TIMER2_CTRL_REG_TIM_EN_Msk;
|
||||
|
||||
IRQ_CONNECT(TIMER2_IRQn, _IRQ_PRIO_OFFSET, timer2_isr, 0, 0);
|
||||
irq_enable(TIMER2_IRQn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);
|
|
@ -3,11 +3,21 @@
|
|||
|
||||
if SOC_SERIES_DA1469X
|
||||
|
||||
config SMARTBOND_TIMER
|
||||
default y if PM
|
||||
|
||||
config CORTEX_M_SYSTICK
|
||||
default n if SMARTBOND_TIMER
|
||||
|
||||
config NUM_IRQS
|
||||
default 40
|
||||
|
||||
config SYS_CLOCK_HW_CYCLES_PER_SEC
|
||||
default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency)
|
||||
default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) if CORTEX_M_SYSTICK
|
||||
default 32768 if SMARTBOND_TIMER
|
||||
|
||||
config SYS_CLOCK_TICKS_PER_SEC
|
||||
default 32768 if SMARTBOND_TIMER
|
||||
|
||||
config SRAM_VECTOR_TABLE
|
||||
default y
|
||||
|
|
Loading…
Reference in a new issue