This is an automated email from the ASF dual-hosted git repository. jerpelea pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 04d2c9013cc87532681f2866a00f7268e5ba53fa Author: raiden00pl <[email protected]> AuthorDate: Sun Sep 20 16:17:55 2026 +0200 arm/nrf54l: add TIMER support arm/nrf54l: add TIMER support Assisted-by: Codex:GPT-6 Signed-off-by: raiden00pl <[email protected]> --- Documentation/platforms/arm/nrf54l/index.rst | 9 +- arch/arm/src/nrf54l/CMakeLists.txt | 6 + arch/arm/src/nrf54l/Kconfig | 39 ++ arch/arm/src/nrf54l/Make.defs | 7 + arch/arm/src/nrf54l/hardware/nrf54l_tim.h | 116 ++++ arch/arm/src/nrf54l/nrf54l_tim.c | 966 +++++++++++++++++++++++++++ arch/arm/src/nrf54l/nrf54l_tim.h | 181 +++++ arch/arm/src/nrf54l/nrf54l_tim_lowerhalf.c | 587 ++++++++++++++++ arch/arm/src/nrf54l/nrf54l_tim_lowerhalf.h | 44 ++ 9 files changed, 1954 insertions(+), 1 deletion(-) diff --git a/Documentation/platforms/arm/nrf54l/index.rst b/Documentation/platforms/arm/nrf54l/index.rst index 366763f5cb1..d4fc86c73fe 100644 --- a/Documentation/platforms/arm/nrf54l/index.rst +++ b/Documentation/platforms/arm/nrf54l/index.rst @@ -23,7 +23,7 @@ RADIO No RRAMC No SAADC No SPIM No -TIMER No +TIMER Yes TWIM No UARTE Yes No hardware flow control USBHS No @@ -35,6 +35,13 @@ GPIO Pins can be configured and operated using ``nrf54l_gpio_*`` functions. +TIMER +----- + +TIMER0 through TIMER6 correspond to TIMER20, TIMER21, TIMER22, TIMER23, +TIMER24, TIMER00 and TIMER10. The timer lower-half driver uses a 1 MHz +counter clock on each instance. + UARTE ----- diff --git a/arch/arm/src/nrf54l/CMakeLists.txt b/arch/arm/src/nrf54l/CMakeLists.txt index a3d56b07470..3d466aa4741 100644 --- a/arch/arm/src/nrf54l/CMakeLists.txt +++ b/arch/arm/src/nrf54l/CMakeLists.txt @@ -36,6 +36,12 @@ endif() if(CONFIG_NRF54L_UART) list(APPEND SRCS nrf54l_serial.c) endif() +if(CONFIG_NRF54L_TIMER) + list(APPEND SRCS nrf54l_tim.c) + if(CONFIG_TIMER) + list(APPEND SRCS nrf54l_tim_lowerhalf.c) + endif() +endif() if(NOT CONFIG_ARCH_IDLE_CUSTOM) list(APPEND SRCS nrf54l_idle.c) endif() diff --git a/arch/arm/src/nrf54l/Kconfig b/arch/arm/src/nrf54l/Kconfig index 15b6a08318b..886fc9921f5 100644 --- a/arch/arm/src/nrf54l/Kconfig +++ b/arch/arm/src/nrf54l/Kconfig @@ -29,6 +29,10 @@ config NRF54L_UART bool default n +config NRF54L_TIMER + bool + default n + menu "nRF54L Peripheral Selection" config NRF54L_UART0 @@ -96,6 +100,41 @@ config NRF54L_UART6 Enable UART6 (UARTE24). The board must provide BOARD_UART6_TX_PIN and BOARD_UART6_RX_PIN. +config NRF54L_TIMER0 + bool "TIMER0 (TIMER20)" + select NRF54L_TIMER + default n + +config NRF54L_TIMER1 + bool "TIMER1 (TIMER21)" + select NRF54L_TIMER + default n + +config NRF54L_TIMER2 + bool "TIMER2 (TIMER22)" + select NRF54L_TIMER + default n + +config NRF54L_TIMER3 + bool "TIMER3 (TIMER23)" + select NRF54L_TIMER + default n + +config NRF54L_TIMER4 + bool "TIMER4 (TIMER24)" + select NRF54L_TIMER + default n + +config NRF54L_TIMER5 + bool "TIMER5 (TIMER00)" + select NRF54L_TIMER + default n + +config NRF54L_TIMER6 + bool "TIMER6 (TIMER10)" + select NRF54L_TIMER + default n + endmenu # nRF54L Peripheral Selection menu "System Timer" diff --git a/arch/arm/src/nrf54l/Make.defs b/arch/arm/src/nrf54l/Make.defs index 79d3db769f7..48ff25988a7 100644 --- a/arch/arm/src/nrf54l/Make.defs +++ b/arch/arm/src/nrf54l/Make.defs @@ -34,6 +34,13 @@ ifeq ($(CONFIG_NRF54L_UART),y) CHIP_CSRCS += nrf54l_serial.c endif +ifeq ($(CONFIG_NRF54L_TIMER),y) +CHIP_CSRCS += nrf54l_tim.c +ifeq ($(CONFIG_TIMER),y) +CHIP_CSRCS += nrf54l_tim_lowerhalf.c +endif +endif + ifneq ($(CONFIG_ARCH_IDLE_CUSTOM),y) CHIP_CSRCS += nrf54l_idle.c endif diff --git a/arch/arm/src/nrf54l/hardware/nrf54l_tim.h b/arch/arm/src/nrf54l/hardware/nrf54l_tim.h new file mode 100644 index 00000000000..d8b525b56c9 --- /dev/null +++ b/arch/arm/src/nrf54l/hardware/nrf54l_tim.h @@ -0,0 +1,116 @@ +/**************************************************************************** + * arch/arm/src/nrf54l/hardware/nrf54l_tim.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF54L_HARDWARE_NRF54L_TIM_H +#define __ARCH_ARM_SRC_NRF54L_HARDWARE_NRF54L_TIM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include "hardware/nrf54l_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register offsets for TIM *************************************************/ + +#define NRF54L_TIM_TASKS_START_OFFSET 0x0000 /* Start Timer */ +#define NRF54L_TIM_TASKS_STOP_OFFSET 0x0004 /* Stop Timer */ +#define NRF54L_TIM_TASKS_COUNT_OFFSET 0x0008 /* Increment Timer */ +#define NRF54L_TIM_TASKS_CLEAR_OFFSET 0x000c /* Clear time */ +#define NRF54L_TIM_TASKS_CAPTURE_OFFSET(x) (0x0040 + ((x) * 4)) /* Capture Timer value to CC[x] */ +#define NRF54L_TIM_SUBSCRIBE_START_OFFSET 0x0080 /* Subscribe to START */ +#define NRF54L_TIM_SUBSCRIBE_STOP_OFFSET 0x0084 /* Subscribe to STOP */ +#define NRF54L_TIM_SUBSCRIBE_COUNT_OFFSET 0x0088 /* Subscribe to COUNT */ +#define NRF54L_TIM_SUBSCRIBE_CLEAR_OFFSET 0x008c /* Subscribe to CLEAR */ +#define NRF54L_TIM_SUBSCRIBE_CAPTURE_OFFSET(x) (0x00c0 + ((x) * 4)) /* Subscribe to CAPTURE[x] */ +#define NRF54L_TIM_EVENTS_COMPARE_OFFSET(x) (0x0140 + ((x) * 4)) /* Compare event on CC[x] */ +#define NRF54L_TIM_PUBLISH_COMPARE_OFFSET(x) (0x01c0 + ((x) * 4)) /* Publish COMPARE[x] */ +#define NRF54L_TIM_SHORTS_OFFSET 0x0200 /* Shortcuts between local events and tasks */ +#define NRF54L_TIM_INTEN_OFFSET 0x0300 /* Enable or disable interrupt */ +#define NRF54L_TIM_INTENSET_OFFSET 0x0304 /* Enable interrupt */ +#define NRF54L_TIM_INTCLR_OFFSET 0x0308 /* Disable interrupt */ +#define NRF54L_TIM_INTPEND_OFFSET 0x030c /* Pending interrupts */ +#define NRF54L_TIM_MODE_OFFSET 0x0504 /* Timer mode selection */ +#define NRF54L_TIM_BITMODE_OFFSET 0x0508 /* Configure the number of bits used by the Timer */ +#define NRF54L_TIM_PRESCALER_OFFSET 0x0510 /* Timer prescaler register */ +#define NRF54L_TIM_CC_OFFSET(x) (0x0540 + ((x) * 4)) /* Capture/Compare register x */ +#define NRF54L_TIM_ONESHOT_OFFSET(x) (0x0580 + ((x) * 4)) /* Enable one-shot operation for Capture/Compare channel x */ + +/* Register offsets for TIM *************************************************/ + +/* TASKS_START Register */ + +#define TIM_TASKS_START (1 << 0) /* Bit 0: Start Timer */ + +/* TASKS_STOP Register */ + +#define TIM_TASKS_STOP (1 << 0) /* Bit 0: Stop Timer */ + +/* TASKS_COUNT Register */ + +#define TIM_TASKS_COUNT (1 << 0) /* Bit 0: Increment Timer */ + +/* TASKS_CLEAR Register */ + +#define TIM_TASKS_CLEAR (1 << 0) /* Bit 0: Clear Timer */ + +/* SHORTS Register */ + +#define TIM_SHORTS_COMPARE_CLEAR(x) (1 << (x)) /* Bits 0-5: */ +#define TIM_SHORTS_COMPARE_STOP(x) (1 << ((x) + 8)) /* Bits 8-15 */ + +/* INTENSET/INTENCLR Register */ + +#define TIM_INT_COMPARE(x) (1 << ((x) + 16)) /* Bits 16-23 */ + +/* MODE Register */ + +#define TIM_MODE_SHIFT (0) /* Bits 0-1: Timer mode */ +#define TIM_MODE_MASK (0x3 << TIM_MODE_SHIFT) +# define TIM_MODE_TIMER (0x0 << TIM_MODE_SHIFT) /* 0: Timer mode */ +# define TIM_MODE_COUNTER (0x1 << TIM_MODE_SHIFT) /* 1: Counter mode */ +# define TIM_MODE_LPCOUNTER (0x2 << TIM_MODE_SHIFT) /* 2: Low Power Counter mode */ + +/* BITMODE Register */ + +#define TIM_BITMODE_SHIFT (0) /* Bits 0-1: Timer bit width */ +#define TIM_BITMODE_MASK (0x3 << TIM_BITMODE_SHIFT) +# define TIM_BITMODE_16B (0x0 << TIM_BITMODE_SHIFT) /* 0: 16 bit */ +# define TIM_BITMODE_8B (0x1 << TIM_BITMODE_SHIFT) /* 1: 8 bit */ +# define TIM_BITMODE_24B (0x2 << TIM_BITMODE_SHIFT) /* 2: 24 bit */ +# define TIM_BITMODE_32B (0x3 << TIM_BITMODE_SHIFT) /* 3: 32 bit */ + +/* PRESCALER Register */ + +#define TIM_PRESCALER_SHIFT (0) /* Bits 0-3: Prescaler value */ +#define TIM_PRESCALER_MAX (9) +#define TIM_PRESCALER_MASK (0xf << TIM_PRESCALER_SHIFT) + +/* ONESHOT Register */ + +#define TIM_ONESHOT_EN (1 << 0) /* Bit 0: Enable one-shot operation */ + +#endif /* __ARCH_ARM_SRC_NRF54L_HARDWARE_NRF54L_TIM_H */ diff --git a/arch/arm/src/nrf54l/nrf54l_tim.c b/arch/arm/src/nrf54l/nrf54l_tim.c new file mode 100644 index 00000000000..36d4b43305d --- /dev/null +++ b/arch/arm/src/nrf54l/nrf54l_tim.c @@ -0,0 +1,966 @@ +/**************************************************************************** + * arch/arm/src/nrf54l/nrf54l_tim.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <assert.h> +#include <nuttx/debug.h> + +#include <nuttx/arch.h> +#include <nuttx/irq.h> + +#include <arch/board/board.h> + +#include "arm_internal.h" +#include "hardware/nrf54l_tim.h" + +#include "nrf54l_tim.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct nrf54l_tim_priv_s +{ + struct nrf54l_tim_ops_s *ops; + uint32_t base; + uint32_t irq; + uint32_t frequency; + uint8_t chan; + bool inuse; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* TIM registers access *****************************************************/ + +static uint32_t nrf54l_tim_getreg(struct nrf54l_tim_dev_s *dev, + uint32_t offset); +static void nrf54l_tim_putreg(struct nrf54l_tim_dev_s *dev, + uint32_t offset, + uint32_t value); + +/* TIM helpers **************************************************************/ + +static uint32_t nrf54l_tim_irq2reg(struct nrf54l_tim_dev_s *dev, + uint8_t s); + +/* TIM operations ***********************************************************/ + +static int nrf54l_tim_start(struct nrf54l_tim_dev_s *dev); +static int nrf54l_tim_stop(struct nrf54l_tim_dev_s *dev); +static int nrf54l_tim_clear(struct nrf54l_tim_dev_s *dev); +static int nrf54l_tim_configure(struct nrf54l_tim_dev_s *dev, uint8_t mode, + uint8_t width); +static int nrf54l_tim_shorts(struct nrf54l_tim_dev_s *dev, uint8_t s, + uint8_t i, bool en); +static int nrf54l_tim_count(struct nrf54l_tim_dev_s *dev); +static int nrf54l_tim_setcc(struct nrf54l_tim_dev_s *dev, uint8_t i, + uint32_t cc); +static int nrf54l_tim_getcc(struct nrf54l_tim_dev_s *dev, uint8_t i, + uint32_t *cc); +static int nrf54l_tim_setpre(struct nrf54l_tim_dev_s *dev, uint8_t pre); +static int nrf54l_tim_setisr(struct nrf54l_tim_dev_s *dev, xcpt_t handler, + void * arg); +static int nrf54l_tim_enableint(struct nrf54l_tim_dev_s *dev, uint8_t s); +static int nrf54l_tim_disableint(struct nrf54l_tim_dev_s *dev, uint8_t s); +static int nrf54l_tim_checkint(struct nrf54l_tim_dev_s *dev, uint8_t s); +static int nrf54l_tim_ackint(struct nrf54l_tim_dev_s *dev, uint8_t s); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* NRF54L TIM ops */ + +struct nrf54l_tim_ops_s nrf54l_tim_ops = +{ + .start = nrf54l_tim_start, + .stop = nrf54l_tim_stop, + .clear = nrf54l_tim_clear, + .configure = nrf54l_tim_configure, + .shorts = nrf54l_tim_shorts, + .count = nrf54l_tim_count, + .setcc = nrf54l_tim_setcc, + .getcc = nrf54l_tim_getcc, + .setpre = nrf54l_tim_setpre, + .setisr = nrf54l_tim_setisr, + .enableint = nrf54l_tim_enableint, + .disableint = nrf54l_tim_disableint, + .checkint = nrf54l_tim_checkint, + .ackint = nrf54l_tim_ackint +}; + +#ifdef CONFIG_NRF54L_TIMER0 +/* TIMER0 */ + +struct nrf54l_tim_priv_s g_nrf54l_tim0_priv = +{ + .ops = &nrf54l_tim_ops, + .base = NRF54L_TIMER20_BASE, + .irq = NRF54L_IRQ_TIMER20, + .frequency = 16000000, + .chan = 6, + .inuse = false, +}; +#endif + +#ifdef CONFIG_NRF54L_TIMER1 +/* TIMER1 */ + +struct nrf54l_tim_priv_s g_nrf54l_tim1_priv = +{ + .ops = &nrf54l_tim_ops, + .base = NRF54L_TIMER21_BASE, + .irq = NRF54L_IRQ_TIMER21, + .frequency = 16000000, + .chan = 6, + .inuse = false, +}; +#endif + +#ifdef CONFIG_NRF54L_TIMER2 +/* TIMER2 */ + +struct nrf54l_tim_priv_s g_nrf54l_tim2_priv = +{ + .ops = &nrf54l_tim_ops, + .base = NRF54L_TIMER22_BASE, + .irq = NRF54L_IRQ_TIMER22, + .frequency = 16000000, + .chan = 6, + .inuse = false, +}; +#endif + +#ifdef CONFIG_NRF54L_TIMER3 +/* TIMER3 */ + +struct nrf54l_tim_priv_s g_nrf54l_tim3_priv = +{ + .ops = &nrf54l_tim_ops, + .base = NRF54L_TIMER23_BASE, + .irq = NRF54L_IRQ_TIMER23, + .frequency = 16000000, + .chan = 6, + .inuse = false, +}; +#endif + +#ifdef CONFIG_NRF54L_TIMER4 +/* TIMER4 */ + +struct nrf54l_tim_priv_s g_nrf54l_tim4_priv = +{ + .ops = &nrf54l_tim_ops, + .base = NRF54L_TIMER24_BASE, + .irq = NRF54L_IRQ_TIMER24, + .frequency = 16000000, + .chan = 6, + .inuse = false, +}; +#endif + +#ifdef CONFIG_NRF54L_TIMER5 +/* TIMER5 */ + +struct nrf54l_tim_priv_s g_nrf54l_tim5_priv = +{ + .ops = &nrf54l_tim_ops, + .base = NRF54L_TIMER00_BASE, + .irq = NRF54L_IRQ_TIMER00, + .frequency = BOARD_SYSTICK_CLOCK, + .chan = 6, + .inuse = false, +}; +#endif + +#ifdef CONFIG_NRF54L_TIMER6 +/* TIMER6 */ + +struct nrf54l_tim_priv_s g_nrf54l_tim6_priv = +{ + .ops = &nrf54l_tim_ops, + .base = NRF54L_TIMER10_BASE, + .irq = NRF54L_IRQ_TIMER10, + .frequency = 32000000, + .chan = 8, + .inuse = false, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf54l_tim_getreg + * + * Description: + * Get a 32-bit register value by offset + * + ****************************************************************************/ + +static uint32_t nrf54l_tim_getreg(struct nrf54l_tim_dev_s *dev, + uint32_t offset) +{ + DEBUGASSERT(dev); + + return getreg32(((struct nrf54l_tim_priv_s *)dev)->base + offset); +} + +/**************************************************************************** + * Name: nrf54l_tim_putreg + * + * Description: + * Put a 32-bit register value by offset + * + ****************************************************************************/ + +static void nrf54l_tim_putreg(struct nrf54l_tim_dev_s *dev, + uint32_t offset, + uint32_t value) +{ + DEBUGASSERT(dev); + + putreg32(value, ((struct nrf54l_tim_priv_s *)dev)->base + offset); +} + +/**************************************************************************** + * Name: nrf54l_tim_irq2reg + * + * Description: + * Get the value of the interrupt register corresponding to the given + * interrupt source + * + ****************************************************************************/ + +static uint32_t nrf54l_tim_irq2reg(struct nrf54l_tim_dev_s *dev, uint8_t s) +{ + uint32_t regval = 0; + + switch (s) + { + case NRF54L_TIM_INT_COMPARE0: + { + regval = TIM_INT_COMPARE(0); + break; + } + + case NRF54L_TIM_INT_COMPARE1: + { + regval = TIM_INT_COMPARE(1); + break; + } + + case NRF54L_TIM_INT_COMPARE2: + { + regval = TIM_INT_COMPARE(2); + break; + } + + case NRF54L_TIM_INT_COMPARE3: + { + regval = TIM_INT_COMPARE(3); + break; + } + + case NRF54L_TIM_INT_COMPARE4: + { + regval = TIM_INT_COMPARE(4); + break; + } + + case NRF54L_TIM_INT_COMPARE5: + { + regval = TIM_INT_COMPARE(5); + break; + } + + case NRF54L_TIM_INT_COMPARE6: + { + regval = TIM_INT_COMPARE(6); + break; + } + + case NRF54L_TIM_INT_COMPARE7: + { + regval = TIM_INT_COMPARE(7); + break; + } + + default: + { + tmrerr("ERROR: unsupported IRQ source %d\n", s); + regval = 0; + goto errout; + } + } + +errout: + return regval; +} + +/**************************************************************************** + * Name: nrf54l_tim_start + ****************************************************************************/ + +static int nrf54l_tim_start(struct nrf54l_tim_dev_s *dev) +{ + DEBUGASSERT(dev); + + nrf54l_tim_putreg(dev, NRF54L_TIM_TASKS_START_OFFSET, TIM_TASKS_START); + + return OK; +} + +/**************************************************************************** + * Name: nrf54l_tim_stop + ****************************************************************************/ + +static int nrf54l_tim_stop(struct nrf54l_tim_dev_s *dev) +{ + DEBUGASSERT(dev); + + nrf54l_tim_putreg(dev, NRF54L_TIM_TASKS_STOP_OFFSET, TIM_TASKS_STOP); + + return OK; +} + +/**************************************************************************** + * Name: nrf54l_tim_clear + ****************************************************************************/ + +static int nrf54l_tim_clear(struct nrf54l_tim_dev_s *dev) +{ + DEBUGASSERT(dev); + + nrf54l_tim_putreg(dev, NRF54L_TIM_TASKS_CLEAR_OFFSET, TIM_TASKS_CLEAR); + + return OK; +} + +/**************************************************************************** + * Name: nrf54l_tim_configure + ****************************************************************************/ + +static int nrf54l_tim_configure(struct nrf54l_tim_dev_s *dev, uint8_t mode, + uint8_t width) +{ + uint32_t regval = 0; + int ret = OK; + + DEBUGASSERT(dev); + + /* Configure TIMER mode */ + + switch (mode) + { + case NRF54L_TIM_MODE_UNUSED: + { + regval = 0; + break; + } + + case NRF54L_TIM_MODE_TIMER: + { + regval = TIM_MODE_TIMER; + break; + } + + case NRF54L_TIM_MODE_COUNTER: + { + regval = TIM_MODE_COUNTER; + break; + } + + case NRF54L_TIM_MODE_LOWPOWER: + { + regval = TIM_MODE_LPCOUNTER; + break; + } + + default: + { + tmrerr("ERROR: unsupported TIMER mode %d\n", mode); + ret = -EINVAL; + goto errout; + } + } + + nrf54l_tim_putreg(dev, NRF54L_TIM_MODE_OFFSET, regval); + + /* Configure TIMER width */ + + switch (width) + { + case NRF54L_TIM_WIDTH_16B: + { + regval = TIM_BITMODE_16B; + break; + } + + case NRF54L_TIM_WIDTH_8B: + { + regval = TIM_BITMODE_8B; + break; + } + + case NRF54L_TIM_WIDTH_24B: + { + regval = TIM_BITMODE_24B; + break; + } + + case NRF54L_TIM_WIDTH_32B: + { + regval = TIM_BITMODE_32B; + break; + } + + default: + { + tmrerr("ERROR: unsupported TIMER width %d\n", width); + ret = -EINVAL; + goto errout; + } + } + + nrf54l_tim_putreg(dev, NRF54L_TIM_BITMODE_OFFSET, regval); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf54l_tim_shorts + ****************************************************************************/ + +static int nrf54l_tim_shorts(struct nrf54l_tim_dev_s *dev, uint8_t s, + uint8_t i, bool en) +{ + uint32_t regval = 0; + uint32_t val = 0; + int ret = OK; + + regval = nrf54l_tim_getreg(dev, NRF54L_TIM_SHORTS_OFFSET); + + switch (s) + { + case NRF54L_TIM_SHORT_COMPARE_CLEAR: + { + val = TIM_SHORTS_COMPARE_CLEAR(i); + break; + } + + case NRF54L_TIM_SHORT_COMPARE_STOP: + { + val = TIM_SHORTS_COMPARE_STOP(i); + break; + } + + default: + { + tmrerr("ERROR: unsupported SHORT %d\n", s); + ret = -EINVAL; + goto errout; + } + } + + if (en == true) + { + regval |= val; + } + else + { + regval &= ~val; + } + + nrf54l_tim_putreg(dev, NRF54L_TIM_SHORTS_OFFSET, regval); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf54l_tim_count + ****************************************************************************/ + +static int nrf54l_tim_count(struct nrf54l_tim_dev_s *dev) +{ + DEBUGASSERT(dev); + + nrf54l_tim_putreg(dev, NRF54L_TIM_TASKS_COUNT_OFFSET, TIM_TASKS_COUNT); + + return OK; +} + +/**************************************************************************** + * Name: nrf54l_tim_setcc + ****************************************************************************/ + +static int nrf54l_tim_setcc(struct nrf54l_tim_dev_s *dev, uint8_t i, + uint32_t cc) +{ + struct nrf54l_tim_priv_s *tim = NULL; + int ret = OK; + + DEBUGASSERT(dev); + + tim = (struct nrf54l_tim_priv_s *)dev; + + /* Is the channel supported? */ + + if (i >= tim->chan) + { + tmrerr("ERROR: unsupported TIMER channel %d\n", i); + ret = -EINVAL; + goto errout; + } + + nrf54l_tim_putreg(dev, NRF54L_TIM_CC_OFFSET(i), cc); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf54l_tim_getcc + ****************************************************************************/ + +static int nrf54l_tim_getcc(struct nrf54l_tim_dev_s *dev, uint8_t i, + uint32_t *cc) +{ + struct nrf54l_tim_priv_s *tim = NULL; + int ret = OK; + + DEBUGASSERT(dev); + DEBUGASSERT(cc); + + tim = (struct nrf54l_tim_priv_s *)dev; + + /* Is the channel supported? */ + + if (i >= tim->chan) + { + tmrerr("ERROR: unsupported TIMER channel %d\n", i); + ret = -EINVAL; + goto errout; + } + + *cc = nrf54l_tim_getreg(dev, NRF54L_TIM_CC_OFFSET(i)); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf54l_tim_setpre + ****************************************************************************/ + +static int nrf54l_tim_setpre(struct nrf54l_tim_dev_s *dev, uint8_t pre) +{ + int ret = OK; + + DEBUGASSERT(dev); + + if (pre > NRF54L_TIM_PRE_DIV512) + { + tmrerr("ERROR: unsupported TIMER prescaler %d\n", pre); + ret = -EINVAL; + goto errout; + } + + nrf54l_tim_putreg(dev, NRF54L_TIM_PRESCALER_OFFSET, pre); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf54l_tim_setisr + ****************************************************************************/ + +static int nrf54l_tim_setisr(struct nrf54l_tim_dev_s *dev, xcpt_t handler, + void *arg) +{ + struct nrf54l_tim_priv_s *tim = NULL; + int ret = OK; + + DEBUGASSERT(dev); + + tim = (struct nrf54l_tim_priv_s *)dev; + + /* Disable interrupt when callback is removed */ + + if (!handler) + { + up_disable_irq(tim->irq); + irq_detach(tim->irq); + ret = OK; + goto errout; + } + + /* Otherwise set callback and enable interrupt */ + + irq_attach(tim->irq, handler, arg); + up_enable_irq(tim->irq); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf54l_tim_enableint + ****************************************************************************/ + +static int nrf54l_tim_enableint(struct nrf54l_tim_dev_s *dev, uint8_t s) +{ + uint32_t regval = 0; + int ret = OK; + + DEBUGASSERT(dev); + + /* Get register value for given interrupt source */ + + regval = nrf54l_tim_irq2reg(dev, s); + if (regval == 0) + { + ret = -EINVAL; + goto errout; + } + + nrf54l_tim_putreg(dev, NRF54L_TIM_INTENSET_OFFSET, regval); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf54l_tim_disableint + ****************************************************************************/ + +static int nrf54l_tim_disableint(struct nrf54l_tim_dev_s *dev, uint8_t s) +{ + uint32_t regval = 0; + int ret = OK; + + DEBUGASSERT(dev); + + /* Get register value for given interrupt source */ + + regval = nrf54l_tim_irq2reg(dev, s); + if (regval == 0) + { + ret = -EINVAL; + goto errout; + } + + nrf54l_tim_putreg(dev, NRF54L_TIM_INTCLR_OFFSET, regval); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf54l_tim_checkint + ****************************************************************************/ + +static int nrf54l_tim_checkint(struct nrf54l_tim_dev_s *dev, uint8_t s) +{ + int ret = 0; + + DEBUGASSERT(dev); + + switch (s) + { + case NRF54L_TIM_INT_COMPARE0: + { + ret = nrf54l_tim_getreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(0)); + break; + } + + case NRF54L_TIM_INT_COMPARE1: + { + ret = nrf54l_tim_getreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(1)); + break; + } + + case NRF54L_TIM_INT_COMPARE2: + { + ret = nrf54l_tim_getreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(2)); + break; + } + + case NRF54L_TIM_INT_COMPARE3: + { + ret = nrf54l_tim_getreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(3)); + break; + } + + case NRF54L_TIM_INT_COMPARE4: + { + ret = nrf54l_tim_getreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(4)); + break; + } + + case NRF54L_TIM_INT_COMPARE5: + { + ret = nrf54l_tim_getreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(5)); + break; + } + + case NRF54L_TIM_INT_COMPARE6: + { + ret = nrf54l_tim_getreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(6)); + break; + } + + case NRF54L_TIM_INT_COMPARE7: + { + ret = nrf54l_tim_getreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(7)); + break; + } + + default: + { + tmrerr("ERROR: unsupported IRQ source %d\n", s); + ret = -EINVAL; + goto errout; + } + } + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf54l_tim_ackint + ****************************************************************************/ + +static int nrf54l_tim_ackint(struct nrf54l_tim_dev_s *dev, uint8_t s) +{ + int ret = 0; + + DEBUGASSERT(dev); + + switch (s) + { + case NRF54L_TIM_INT_COMPARE0: + { + nrf54l_tim_putreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(0), 0); + break; + } + + case NRF54L_TIM_INT_COMPARE1: + { + nrf54l_tim_putreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(1), 0); + break; + } + + case NRF54L_TIM_INT_COMPARE2: + { + nrf54l_tim_putreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(2), 0); + break; + } + + case NRF54L_TIM_INT_COMPARE3: + { + nrf54l_tim_putreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(3), 0); + break; + } + + case NRF54L_TIM_INT_COMPARE4: + { + nrf54l_tim_putreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(4), 0); + break; + } + + case NRF54L_TIM_INT_COMPARE5: + { + nrf54l_tim_putreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(5), 0); + break; + } + + case NRF54L_TIM_INT_COMPARE6: + { + nrf54l_tim_putreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(6), 0); + break; + } + + case NRF54L_TIM_INT_COMPARE7: + { + nrf54l_tim_putreg(dev, NRF54L_TIM_EVENTS_COMPARE_OFFSET(7), 0); + break; + } + + default: + { + tmrerr("ERROR: unsupported IRQ source %d\n", s); + ret = -EINVAL; + goto errout; + } + } + +errout: + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf54l_tim_init + * + * Description: + * Initialize TIMER device + * + ****************************************************************************/ + +struct nrf54l_tim_dev_s *nrf54l_tim_init(int timer) +{ + struct nrf54l_tim_priv_s *tim = NULL; + + /* Get timer instance */ + + switch (timer) + { +#ifdef CONFIG_NRF54L_TIMER0 + case 0: + { + tim = &g_nrf54l_tim0_priv; + break; + } +#endif + +#ifdef CONFIG_NRF54L_TIMER1 + case 1: + { + tim = &g_nrf54l_tim1_priv; + break; + } +#endif + +#ifdef CONFIG_NRF54L_TIMER2 + case 2: + { + tim = &g_nrf54l_tim2_priv; + break; + } +#endif + +#ifdef CONFIG_NRF54L_TIMER3 + case 3: + { + tim = &g_nrf54l_tim3_priv; + break; + } +#endif + +#ifdef CONFIG_NRF54L_TIMER4 + case 4: + { + tim = &g_nrf54l_tim4_priv; + break; + } +#endif + +#ifdef CONFIG_NRF54L_TIMER5 + case 5: + { + tim = &g_nrf54l_tim5_priv; + break; + } +#endif + +#ifdef CONFIG_NRF54L_TIMER6 + case 6: + { + tim = &g_nrf54l_tim6_priv; + break; + } +#endif + + default: + { + tmrerr("ERROR: unsupported TIMER %d\n", timer); + goto errout; + } + } + + if (tim->inuse != false) + { + /* Timer already in use */ + + tim = NULL; + } + else + { + tim->inuse = true; + } + +errout: + return (struct nrf54l_tim_dev_s *)tim; +} + +/**************************************************************************** + * Name: nrf54l_tim_deinit + * + * Description: + * Deinit TIMER device + * + ****************************************************************************/ + +int nrf54l_tim_deinit(struct nrf54l_tim_dev_s *dev) +{ + struct nrf54l_tim_priv_s *tim = NULL; + + DEBUGASSERT(dev); + + tim = (struct nrf54l_tim_priv_s *)dev; + + tim->inuse = false; + + return OK; +} + +/**************************************************************************** + * Name: nrf54l_tim_getbasefreq + * + * Description: + * Return the input clock frequency before the timer prescaler. + * + ****************************************************************************/ + +uint32_t nrf54l_tim_getbasefreq(struct nrf54l_tim_dev_s *dev) +{ + DEBUGASSERT(dev); + + return ((struct nrf54l_tim_priv_s *)dev)->frequency; +} diff --git a/arch/arm/src/nrf54l/nrf54l_tim.h b/arch/arm/src/nrf54l/nrf54l_tim.h new file mode 100644 index 00000000000..c13988c2e1a --- /dev/null +++ b/arch/arm/src/nrf54l/nrf54l_tim.h @@ -0,0 +1,181 @@ +/**************************************************************************** + * arch/arm/src/nrf54l/nrf54l_tim.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF54L_NRF54L_TIM_H +#define __ARCH_ARM_SRC_NRF54L_NRF54L_TIM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdbool.h> + +#include <nuttx/irq.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Helpers ******************************************************************/ + +#define NRF54L_TIM_START(d) ((d)->ops->start(d)) +#define NRF54L_TIM_STOP(d) ((d)->ops->stop(d)) +#define NRF54L_TIM_CLEAR(d) ((d)->ops->clear(d)) +#define NRF54L_TIM_CONFIGURE(d, m, w) ((d)->ops->configure(d, m, w)) +#define NRF54L_TIM_SHORTS(d, s, i, e) ((d)->ops->shorts(d, s, i, e)) +#define NRF54L_TIM_COUNT(d) ((d)->ops->count(d)) +#define NRF54L_TIM_SETCC(d, i, cc) ((d)->ops->setcc(d, i, cc)) +#define NRF54L_TIM_GETCC(d, i, cc) ((d)->ops->getcc(d, i, cc)) +#define NRF54L_TIM_SETPRE(d, pre) ((d)->ops->setpre(d, pre)) +#define NRF54L_TIM_SETISR(d, hnd, arg) ((d)->ops->setisr(d, hnd, arg)) +#define NRF54L_TIM_ENABLEINT(d, s) ((d)->ops->enableint(d, s)) +#define NRF54L_TIM_DISABLEINT(d, s) ((d)->ops->disableint(d, s)) +#define NRF54L_TIM_CHECKINT(d, s) ((d)->ops->checkint(d, s)) +#define NRF54L_TIM_ACKINT(d, s) ((d)->ops->ackint(d, s)) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Timer mode */ + +enum nrf54l_tim_mode_e +{ + NRF54L_TIM_MODE_UNUSED = 0, + NRF54L_TIM_MODE_TIMER = 1, + NRF54L_TIM_MODE_COUNTER = 2, + NRF54L_TIM_MODE_LOWPOWER = 3, +}; + +/* Timer bit width */ + +enum nrf54l_tim_width_e +{ + NRF54L_TIM_WIDTH_16B = 0, + NRF54L_TIM_WIDTH_8B = 1, + NRF54L_TIM_WIDTH_24B = 2, + NRF54L_TIM_WIDTH_32B = 3, +}; + +/* Timer CC index */ + +enum nrf54l_tim_cc_e +{ + NRF54L_TIM_CC0 = 0, + NRF54L_TIM_CC1 = 1, + NRF54L_TIM_CC2 = 2, + NRF54L_TIM_CC3 = 3, + NRF54L_TIM_CC4 = 4, + NRF54L_TIM_CC5 = 5, + NRF54L_TIM_CC6 = 6, + NRF54L_TIM_CC7 = 7 +}; + +/* Timer IRQ source */ + +enum nrf54l_tim_irq_e +{ + NRF54L_TIM_INT_COMPARE0 = 0, + NRF54L_TIM_INT_COMPARE1 = 1, + NRF54L_TIM_INT_COMPARE2 = 2, + NRF54L_TIM_INT_COMPARE3 = 3, + NRF54L_TIM_INT_COMPARE4 = 4, + NRF54L_TIM_INT_COMPARE5 = 5, + NRF54L_TIM_INT_COMPARE6 = 6, + NRF54L_TIM_INT_COMPARE7 = 7, +}; + +/* Timer shorts type */ + +enum nrf54l_tim_shorts_e +{ + NRF54L_TIM_SHORT_COMPARE_CLEAR = 1, + NRF54L_TIM_SHORT_COMPARE_STOP = 2 +}; + +/* Timer frequency prescaler (input frequency / 2^prescaler) */ + +enum nrf54l_tim_pre_e +{ + NRF54L_TIM_PRE_DIV1 = 0, + NRF54L_TIM_PRE_DIV2 = 1, + NRF54L_TIM_PRE_DIV4 = 2, + NRF54L_TIM_PRE_DIV8 = 3, + NRF54L_TIM_PRE_DIV16 = 4, + NRF54L_TIM_PRE_DIV32 = 5, + NRF54L_TIM_PRE_DIV64 = 6, + NRF54L_TIM_PRE_DIV128 = 7, + NRF54L_TIM_PRE_DIV256 = 8, + NRF54L_TIM_PRE_DIV512 = 9 +}; + +/* NRF54L TIM device */ + +struct nrf54l_tim_dev_s +{ + struct nrf54l_tim_ops_s *ops; +}; + +/* NRF54L TIM ops */ + +struct nrf54l_tim_ops_s +{ + /* Timer tasks */ + + int (*start)(struct nrf54l_tim_dev_s *dev); + int (*stop)(struct nrf54l_tim_dev_s *dev); + int (*clear)(struct nrf54l_tim_dev_s *dev); + + /* Timer configuration */ + + int (*configure)(struct nrf54l_tim_dev_s *dev, uint8_t mode, + uint8_t width); + int (*shorts)(struct nrf54l_tim_dev_s *dev, uint8_t s, uint8_t i, bool en); + + /* Timer operations */ + + int (*count)(struct nrf54l_tim_dev_s *dev); + int (*setcc)(struct nrf54l_tim_dev_s *dev, uint8_t i, uint32_t cc); + int (*getcc)(struct nrf54l_tim_dev_s *dev, uint8_t i, uint32_t *cc); + int (*setpre)(struct nrf54l_tim_dev_s *dev, uint8_t pre); + + /* Timer interrupts */ + + int (*setisr)(struct nrf54l_tim_dev_s *dev, xcpt_t handler, void *arg); + int (*enableint)(struct nrf54l_tim_dev_s *dev, uint8_t source); + int (*disableint)(struct nrf54l_tim_dev_s *dev, uint8_t source); + int (*checkint)(struct nrf54l_tim_dev_s *dev, uint8_t source); + int (*ackint)(struct nrf54l_tim_dev_s *dev, uint8_t source); +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +struct nrf54l_tim_dev_s *nrf54l_tim_init(int timer); +int nrf54l_tim_deinit(struct nrf54l_tim_dev_s *dev); +uint32_t nrf54l_tim_getbasefreq(struct nrf54l_tim_dev_s *dev); + +#endif /* __ARCH_ARM_SRC_NRF54L_NRF54L_TIM_H */ diff --git a/arch/arm/src/nrf54l/nrf54l_tim_lowerhalf.c b/arch/arm/src/nrf54l/nrf54l_tim_lowerhalf.c new file mode 100644 index 00000000000..bb611dfc9fb --- /dev/null +++ b/arch/arm/src/nrf54l/nrf54l_tim_lowerhalf.c @@ -0,0 +1,587 @@ +/**************************************************************************** + * arch/arm/src/nrf54l/nrf54l_tim_lowerhalf.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdbool.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <nuttx/debug.h> + +#include <nuttx/arch.h> +#include <nuttx/timers/timer.h> + +#include "arm_internal.h" +#include "nrf54l_tim.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* TIMER configuration */ + +#define NRF54L_TIMER_CC (NRF54L_TIM_CC0) +#define NRF54L_TIMER_INT (NRF54L_TIM_INT_COMPARE0) +#define NRF54L_TIMER_RES (NRF54L_TIM_WIDTH_32B) +#define NRF54L_TIMER_MAX (4294967295ul) +#define NRF54L_TIMER_PER (1000000ull) + +/* Maximum supported timeout */ + +#define NRF54L_TIMER_MAXTIMEOUT \ + (NRF54L_TIMER_MAX * 1000000ull / NRF54L_TIMER_PER) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct nrf54l_timer_lowerhalf_s +{ + const struct timer_ops_s *ops; /* Lower half operations */ + struct nrf54l_tim_dev_s *tim; /* nrf54l timer driver */ + tccb_t callback; /* Current user interrupt callback */ + void *arg; /* Argument passed to upper half callback */ + bool started; /* True: Timer has been started */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int nrf54l_timer_handler(int irq, void *context, void *arg); + +/* "Lower half" driver methods **********************************************/ + +static int nrf54l_timer_start(struct timer_lowerhalf_s *lower); +static int nrf54l_timer_stop(struct timer_lowerhalf_s *lower); +static int nrf54l_timer_getstatus(struct timer_lowerhalf_s *lower, + struct timer_status_s *status); +static int nrf54l_timer_settimeout(struct timer_lowerhalf_s *lower, + uint32_t timeout); +static void nrf54l_timer_setcallback(struct timer_lowerhalf_s *lower, + tccb_t callback, void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* "Lower half" driver methods */ + +static const struct timer_ops_s g_nrf54l_timer_ops = +{ + .start = nrf54l_timer_start, + .stop = nrf54l_timer_stop, + .getstatus = nrf54l_timer_getstatus, + .settimeout = nrf54l_timer_settimeout, + .setcallback = nrf54l_timer_setcallback, + .ioctl = NULL, +}; + +#ifdef CONFIG_NRF54L_TIMER0 +/* TIMER0 lower-half */ + +static struct nrf54l_timer_lowerhalf_s g_nrf54l_timer0_lowerhalf = +{ + .ops = &g_nrf54l_timer_ops, +}; +#endif + +#ifdef CONFIG_NRF54L_TIMER1 +/* TIMER1 lower-half */ + +static struct nrf54l_timer_lowerhalf_s g_nrf54l_timer1_lowerhalf = +{ + .ops = &g_nrf54l_timer_ops, +}; +#endif + +#ifdef CONFIG_NRF54L_TIMER2 +/* TIMER2 lower-half */ + +static struct nrf54l_timer_lowerhalf_s g_nrf54l_timer2_lowerhalf = +{ + .ops = &g_nrf54l_timer_ops, +}; +#endif + +#ifdef CONFIG_NRF54L_TIMER3 +/* TIMER3 lower-half */ + +static struct nrf54l_timer_lowerhalf_s g_nrf54l_timer3_lowerhalf = +{ + .ops = &g_nrf54l_timer_ops, +}; +#endif + +#ifdef CONFIG_NRF54L_TIMER4 +/* TIMER4 lower-half */ + +static struct nrf54l_timer_lowerhalf_s g_nrf54l_timer4_lowerhalf = +{ + .ops = &g_nrf54l_timer_ops, +}; +#endif + +#ifdef CONFIG_NRF54L_TIMER5 +/* TIMER5 lower-half */ + +static struct nrf54l_timer_lowerhalf_s g_nrf54l_timer5_lowerhalf = +{ + .ops = &g_nrf54l_timer_ops, +}; +#endif + +#ifdef CONFIG_NRF54L_TIMER6 +/* TIMER6 lower-half */ + +static struct nrf54l_timer_lowerhalf_s g_nrf54l_timer6_lowerhalf = +{ + .ops = &g_nrf54l_timer_ops, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf54l_timer_handler + * + * Description: + * Timer interrupt handler + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +static int nrf54l_timer_handler(int irq, void *context, void *arg) +{ + struct nrf54l_timer_lowerhalf_s *priv = + (struct nrf54l_timer_lowerhalf_s *)arg; + uint32_t next_interval_us = 0; + + NRF54L_TIM_ACKINT(priv->tim, NRF54L_TIMER_INT); + + if (priv->callback(&next_interval_us, priv->arg)) + { + if (next_interval_us > 0) + { + NRF54L_TIM_SETCC(priv->tim, NRF54L_TIMER_CC, next_interval_us); + } + } + else + { + nrf54l_timer_stop((struct timer_lowerhalf_s *)priv); + } + + return OK; +} + +/**************************************************************************** + * Name: nrf54l_timer_start + * + * Description: + * Start the timer, resetting the time to the current timeout, + * + * Input Parameters: + * lower - A pointer the publicly visible representation of + * the "lower-half" driver state structure. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nrf54l_timer_start(struct timer_lowerhalf_s *lower) +{ + struct nrf54l_timer_lowerhalf_s *priv = + (struct nrf54l_timer_lowerhalf_s *)lower; + int ret = OK; + uint32_t frequency; + uint8_t pre = 0; + + DEBUGASSERT(priv); + + if (priv->started == true) + { + /* Return EBUSY to indicate that the timer was already running */ + + ret = -EBUSY; + goto errout; + } + + /* Configure TIMER mode and resolution */ + + NRF54L_TIM_CONFIGURE(priv->tim, NRF54L_TIM_MODE_TIMER, NRF54L_TIMER_RES); + + /* Clear counter on COMPARE event */ + + NRF54L_TIM_SHORTS(priv->tim, NRF54L_TIM_SHORT_COMPARE_CLEAR, + NRF54L_TIMER_INT, true); + + /* Configure prescaler */ + + frequency = nrf54l_tim_getbasefreq(priv->tim); + while (frequency > NRF54L_TIMER_PER) + { + frequency >>= 1; + pre++; + } + + NRF54L_TIM_SETPRE(priv->tim, pre); + + /* Configure callback */ + + if (priv->callback != NULL) + { + NRF54L_TIM_SETISR(priv->tim, nrf54l_timer_handler, priv); + NRF54L_TIM_ENABLEINT(priv->tim, NRF54L_TIMER_INT); + } + + NRF54L_TIM_CLEAR(priv->tim); + NRF54L_TIM_START(priv->tim); + + priv->started = true; + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf54l_timer_stop + * + * Description: + * Stop the timer + * + * Input Parameters: + * lower - A pointer the publicly visible representation of + * the "lower-half" driver state structure. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nrf54l_timer_stop(struct timer_lowerhalf_s *lower) +{ + struct nrf54l_timer_lowerhalf_s *priv = + (struct nrf54l_timer_lowerhalf_s *)lower; + int ret = OK; + + DEBUGASSERT(priv); + + if (priv->started == false) + { + /* Return ENODEV to indicate that the timer was not running */ + + ret = -ENODEV; + goto errout; + } + + NRF54L_TIM_DISABLEINT(priv->tim, NRF54L_TIMER_INT); + NRF54L_TIM_SETISR(priv->tim, NULL, NULL); + NRF54L_TIM_STOP(priv->tim); + + priv->started = false; + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf54l_timer_getstatus + * + * Description: + * get timer status + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower- + * half" driver state structure. + * status - The location to return the status information. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nrf54l_timer_getstatus(struct timer_lowerhalf_s *lower, + struct timer_status_s *status) +{ + struct nrf54l_timer_lowerhalf_s *priv = + (struct nrf54l_timer_lowerhalf_s *)lower; + + DEBUGASSERT(priv); + DEBUGASSERT(status); + + /* Return the status bit */ + + status->flags = 0; + + if (priv->started == true) + { + status->flags |= TCFLAGS_ACTIVE; + } + + if (priv->callback) + { + status->flags |= TCFLAGS_HANDLER; + } + + /* TODO: timeout and time left */ + + status->timeout = 0; + status->timeleft = 0; + + return OK; +} + +/**************************************************************************** + * Name: nrf54l_timer_settimeout + * + * Description: + * Set a new timeout value (and reset the timer) + * + * Input Parameters: + * lower - A pointer the publicly visible representation of + * the "lower-half" driver state structure. + * timeout - The new timeout value in microseconds. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nrf54l_timer_settimeout(struct timer_lowerhalf_s *lower, + uint32_t timeout) +{ + struct nrf54l_timer_lowerhalf_s *priv = + (struct nrf54l_timer_lowerhalf_s *)lower; + uint32_t cc = 0; + int ret = OK; + + DEBUGASSERT(priv); + + if (priv->started == true) + { + ret = -EPERM; + goto errout; + } + + if (timeout > NRF54L_TIMER_MAXTIMEOUT) + { + ret = -EINVAL; + goto errout; + } + + cc = (uint32_t)(timeout * NRF54L_TIMER_PER / 1000000); + NRF54L_TIM_SETCC(priv->tim, NRF54L_TIMER_CC, cc); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf54l_setcallback + * + * Description: + * Call this user provided timeout handler. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of + * the "lower-half" driver state structure. + * callback - The new timer expiration function pointer. If this + * function pointer is NULL, then the reset-on-expiration + * behavior is restored, + * arg - Argument that will be provided in the callback + * + * Returned Value: + * The previous timer expiration function pointer or NULL is there was + * no previous function pointer. + * + ****************************************************************************/ + +static void nrf54l_timer_setcallback(struct timer_lowerhalf_s *lower, + tccb_t callback, void *arg) +{ + struct nrf54l_timer_lowerhalf_s *priv = + (struct nrf54l_timer_lowerhalf_s *)lower; + irqstate_t flags; + + DEBUGASSERT(priv); + + flags = enter_critical_section(); + + /* Save the new callback */ + + priv->callback = callback; + priv->arg = arg; + + if (callback != NULL && priv->started == true) + { + NRF54L_TIM_SETISR(priv->tim, nrf54l_timer_handler, priv); + NRF54L_TIM_ENABLEINT(priv->tim, NRF54L_TIMER_INT); + } + else + { + NRF54L_TIM_DISABLEINT(priv->tim, NRF54L_TIMER_INT); + NRF54L_TIM_SETISR(priv->tim, NULL, NULL); + } + + leave_critical_section(flags); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf54l_timer_initialize + * + * Description: + * Bind the configuration timer to a timer lower half instance and + * register the timer drivers at 'devpath' + * + * Input Parameters: + * devpath - The full path to the timer device. This should be of the + * form /dev/timer0 + * timer - the timer's number. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +int nrf54l_timer_initialize(const char *devpath, uint8_t timer) +{ + struct nrf54l_timer_lowerhalf_s *lower = NULL; + void *drvr = NULL; + int ret = OK; + + DEBUGASSERT(devpath); + + switch (timer) + { +#ifdef CONFIG_NRF54L_TIMER0 + case 0: + { + lower = &g_nrf54l_timer0_lowerhalf; + break; + } +#endif + +#ifdef CONFIG_NRF54L_TIMER1 + case 1: + { + lower = &g_nrf54l_timer1_lowerhalf; + break; + } +#endif + +#ifdef CONFIG_NRF54L_TIMER2 + case 2: + { + lower = &g_nrf54l_timer2_lowerhalf; + break; + } +#endif + +#ifdef CONFIG_NRF54L_TIMER3 + case 3: + { + lower = &g_nrf54l_timer3_lowerhalf; + break; + } +#endif + +#ifdef CONFIG_NRF54L_TIMER4 + case 4: + { + lower = &g_nrf54l_timer4_lowerhalf; + break; + } +#endif + +#ifdef CONFIG_NRF54L_TIMER5 + case 5: + { + lower = &g_nrf54l_timer5_lowerhalf; + break; + } +#endif + +#ifdef CONFIG_NRF54L_TIMER6 + case 6: + { + lower = &g_nrf54l_timer6_lowerhalf; + break; + } +#endif + + default: + { + ret = -ENODEV; + goto errout; + } + } + + /* Initialize the elements of lower half state structure */ + + lower->started = false; + lower->callback = NULL; + lower->tim = nrf54l_tim_init(timer); + + if (lower->tim == NULL) + { + ret = -EINVAL; + goto errout; + } + + /* Register the timer driver as /dev/timerX. The returned value from + * timer_register is a handle that could be used with timer_unregister(). + * REVISIT: The returned handle is discard here. + */ + + drvr = timer_register(devpath, (struct timer_lowerhalf_s *)lower); + if (drvr == NULL) + { + /* The actual cause of the failure may have been a failure to allocate + * perhaps a failure to register the timer driver (such as if the + * 'depath' were not unique). We know here but we return EEXIST to + * indicate the failure (implying the non-unique devpath). + */ + + ret = -EEXIST; + goto errout; + } + +errout: + return ret; +} diff --git a/arch/arm/src/nrf54l/nrf54l_tim_lowerhalf.h b/arch/arm/src/nrf54l/nrf54l_tim_lowerhalf.h new file mode 100644 index 00000000000..8f6063968bf --- /dev/null +++ b/arch/arm/src/nrf54l/nrf54l_tim_lowerhalf.h @@ -0,0 +1,44 @@ +/**************************************************************************** + * arch/arm/src/nrf54l/nrf54l_tim_lowerhalf.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF54L_NRF54L_TIM_LOWERHALF_H +#define __ARCH_ARM_SRC_NRF54L_NRF54L_TIM_LOWERHALF_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <nrf54l_tim.h> + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf54l_timer_initialize + ****************************************************************************/ + +int nrf54l_timer_initialize(const char *devpath, uint8_t timer); + +#endif /* __ARCH_ARM_SRC_NRF54L_NRF54L_TIM_LOWERHALF_H */
