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 */

Reply via email to