From d398723f09c49a1eb968b52eeab9989699c91c72 Mon Sep 17 00:00:00 2001 From: Saravanan Sekar Date: Mon, 12 May 2025 16:05:26 +0530 Subject: [PATCH] driver: timer: mspm0: Add timer as sysclock Add a support for timer as sysclock Signed-off-by: Saravanan Sekar --- drivers/timer/CMakeLists.txt | 1 + drivers/timer/Kconfig | 1 + drivers/timer/Kconfig.ti_mspm0_timer | 12 ++ drivers/timer/ti_mspm0_timer.c | 118 ++++++++++++++++++ .../timer/ti,mspm0-timer-sysclock.yaml | 8 ++ 5 files changed, 140 insertions(+) create mode 100644 drivers/timer/Kconfig.ti_mspm0_timer create mode 100644 drivers/timer/ti_mspm0_timer.c create mode 100644 dts/bindings/timer/ti,mspm0-timer-sysclock.yaml diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index 3c488da9a3e72..a6c2cfd548d25 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -42,6 +42,7 @@ zephyr_library_sources_ifdef(CONFIG_SAM0_RTC_TIMER sam0_rtc_timer.c) zephyr_library_sources_ifdef(CONFIG_SILABS_SLEEPTIMER_TIMER silabs_sleeptimer_timer.c) zephyr_library_sources_ifdef(CONFIG_STM32_LPTIM_TIMER stm32_lptim_timer.c) zephyr_library_sources_ifdef(CONFIG_TI_DM_TIMER ti_dmtimer.c) +zephyr_library_sources_ifdef(CONFIG_TI_MSPM0_TIMER ti_mspm0_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) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index c154370c45630..4c68dd8b970cc 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -100,6 +100,7 @@ source "drivers/timer/Kconfig.silabs" source "drivers/timer/Kconfig.smartbond" source "drivers/timer/Kconfig.stm32_lptim" source "drivers/timer/Kconfig.ti_dm_timer" +source "drivers/timer/Kconfig.ti_mspm0_timer" source "drivers/timer/Kconfig.xlnx_psttc" source "drivers/timer/Kconfig.xtensa" source "drivers/timer/Kconfig.mtk_adsp" diff --git a/drivers/timer/Kconfig.ti_mspm0_timer b/drivers/timer/Kconfig.ti_mspm0_timer new file mode 100644 index 0000000000000..e0e82fba268e4 --- /dev/null +++ b/drivers/timer/Kconfig.ti_mspm0_timer @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Linumiz GmbH +# SPDX-License-Identifier: Apache-2.0 + +config TI_MSPM0_TIMER + bool "TI MSPM0 timer" + default n + depends on DT_HAS_TI_MSPM0_TIMER_SYSCLOCK_ENABLED + select SYSTEM_TIMER_HAS_DISABLE_SUPPORT + help + This module implements a kernel device driver for the TI MSPM0 + Timer and provides the standard "system clock driver" + interfaces. diff --git a/drivers/timer/ti_mspm0_timer.c b/drivers/timer/ti_mspm0_timer.c new file mode 100644 index 0000000000000..e64982c7b096d --- /dev/null +++ b/drivers/timer/ti_mspm0_timer.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2025 Linumiz GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DT_DRV_COMPAT ti_mspm0_timer_sysclock + +#define MSPM0_TMR_PRESCALE DT_PROP(DT_INST_PARENT(0), clk_prescaler) +#define MSPM0_TMR_IRQN DT_IRQN(DT_INST_PARENT(0)) +#define MSPM0_TMR_IRQ_PRIO DT_IRQ(DT_INST_PARENT(0), priority) +#define MSPM0_TMR_BASE ((GPTIMER_Regs *)(DT_REG_ADDR(DT_INST_PARENT(0)))) +#define MSPM0_TMR_CLK (DT_CLOCKS_CELL_BY_IDX(DT_INST_PARENT(0), 0, bus) & \ + MSPM0_CLOCK_SEL_MASK) +#define MSPM0_CLK_DIV(div) DT_CAT(DL_TIMER_CLOCK_DIVIDE_, div) +#define MSPM0_TMR_CLK_DIV MSPM0_CLK_DIV(DT_PROP(DT_INST_PARENT(0), clk_div)) + +/* Timer cycles per tick */ +#define CYC_PER_TICK ((uint32_t)((uint64_t)sys_clock_hw_cycles_per_sec() \ + / (uint64_t)CONFIG_SYS_CLOCK_TICKS_PER_SEC)) + +static uint32_t cycles; + +static void mspm0_timer_isr(void *arg) +{ + uint32_t status; + ARG_UNUSED(arg); + + status = DL_Timer_getPendingInterrupt(MSPM0_TMR_BASE); + if ((status & DL_TIMER_IIDX_LOAD) == 0) { + return; + } + + cycles += CYC_PER_TICK; + sys_clock_announce(1); +} + +void sys_clock_set_timeout(int32_t ticks, bool idle) +{ + ARG_UNUSED(idle); + + if (idle && (ticks == K_TICKS_FOREVER)) { + DL_Timer_disableInterrupt(MSPM0_TMR_BASE, + DL_TIMER_INTERRUPT_LOAD_EVENT); + } +} + +void sys_clock_idle_exit(void) +{ + if (DL_Timer_getEnabledInterruptStatus(MSPM0_TMR_BASE, + DL_TIMER_INTERRUPT_LOAD_EVENT) == 0) { + DL_Timer_enableInterrupt(MSPM0_TMR_BASE, + DL_TIMER_INTERRUPT_LOAD_EVENT); + } +} + +void sys_clock_disable(void) +{ + DL_Timer_disableInterrupt(MSPM0_TMR_BASE, + DL_TIMER_INTERRUPT_LOAD_EVENT); + DL_Timer_stopCounter(MSPM0_TMR_BASE); +} + +uint32_t sys_clock_elapsed(void) +{ + return 0; +} + +uint32_t sys_clock_cycle_get_32(void) +{ + return DL_Timer_getTimerCount(MSPM0_TMR_BASE) + cycles; +} + +static int mspm0_sysclock_init(void) +{ + DL_Timer_TimerConfig tim_config = { + .period = CYC_PER_TICK, + .timerMode = DL_TIMER_TIMER_MODE_PERIODIC_UP, + .startTimer = DL_TIMER_START, + }; + + DL_Timer_ClockConfig clk_config = { + .clockSel = MSPM0_TMR_CLK, + .divideRatio = MSPM0_TMR_CLK_DIV, + .prescale = MSPM0_TMR_PRESCALE, + }; + + DL_Timer_reset(MSPM0_TMR_BASE); + DL_Timer_enablePower(MSPM0_TMR_BASE); + + delay_cycles(16); + DL_Timer_setClockConfig(MSPM0_TMR_BASE, &clk_config); + DL_Timer_initTimerMode(MSPM0_TMR_BASE, &tim_config); + DL_Timer_setCounterRepeatMode(MSPM0_TMR_BASE, + DL_TIMER_REPEAT_MODE_ENABLED); + + IRQ_CONNECT(MSPM0_TMR_IRQN, MSPM0_TMR_IRQ_PRIO, mspm0_timer_isr, 0, 0); + irq_enable(MSPM0_TMR_IRQN); + + DL_Timer_clearInterruptStatus(MSPM0_TMR_BASE, + DL_TIMER_INTERRUPT_LOAD_EVENT); + DL_Timer_enableInterrupt(MSPM0_TMR_BASE, + DL_TIMER_INTERRUPT_LOAD_EVENT); + + return 0; +} + +SYS_INIT(mspm0_sysclock_init, PRE_KERNEL_2, + CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); diff --git a/dts/bindings/timer/ti,mspm0-timer-sysclock.yaml b/dts/bindings/timer/ti,mspm0-timer-sysclock.yaml new file mode 100644 index 0000000000000..b6b5ac4e926c2 --- /dev/null +++ b/dts/bindings/timer/ti,mspm0-timer-sysclock.yaml @@ -0,0 +1,8 @@ +# Copyright 2025 Linumiz GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: TI MSPM0 Timer used as sysclock + +compatible: "ti,mspm0-timer-sysclock" + +include: base.yaml