This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 2cc38e43fb89f475058a014ce5c5c3a4e3c63e4c
Author: dechao_gong <[email protected]>
AuthorDate: Tue Jul 21 19:39:03 2026 +0800

    arch/arm/rtl8721dx: add shared Ameba timer driver
    
    Add a parameterised NuttX timer lower-half for the Realtek Ameba
    general-purpose timers, sitting on the SDK fwlib RTIM register layer and
    registered at /dev/timerN.  The shared driver
    (arch/arm/src/common/ameba/ameba_timer.c) reads a per-chip instance
    table (ameba_timer_chip.h) for each timer's base, input clock, RCC gate
    masks and IRQ; the period is programmed directly in microseconds and
    converted to the 32-bit auto-reload with one clkfreq formula.
    
    On the pke8721daf two of the 32.768 kHz "basic" (LTIM) timers are
    exposed: /dev/timer0 is TIM1 and /dev/timer1 is TIM2.  TIM0 is left
    untouched because the boot ROM claims it as the always-on system timer
    (SYSTIMER); reprogramming it would break every SDK delay.  The RTIM
    time-base entry points resolve to ROM, while the interrupt-clear and
    period-change helpers come from the fwlib RAM source ameba_tim.c (shared
    with the PWM driver).
    
    Verified on hardware with examples/timer against both devices: the
    update interrupt fires at the requested 1 s interval (measured with the
    independent ROM SYSTIMER = 32768 ticks = 1.000 s).
    
    Also whitelist the vendor RTIM_ symbol prefix in tools/nxstyle.c,
    alongside the existing RCC_/SYSTIMER_ Ameba SDK entries.
    
    Assisted-by: Claude <[email protected]>
    Signed-off-by: dechao_gong <[email protected]>
---
 .../arm/rtl8721dx/boards/pke8721daf/index.rst      |  16 +
 arch/arm/src/common/ameba/Kconfig                  |  17 +
 arch/arm/src/common/ameba/ameba_timer.c            | 546 +++++++++++++++++++++
 arch/arm/src/common/ameba/ameba_timer.h            |  72 +++
 arch/arm/src/rtl8721dx/CMakeLists.txt              |   4 +
 arch/arm/src/rtl8721dx/Make.defs                   |   4 +
 arch/arm/src/rtl8721dx/ameba_board.mk              |  11 +-
 arch/arm/src/rtl8721dx/ameba_timer_chip.h          | 111 +++++
 .../rtl8721dx/pke8721daf/configs/timer/defconfig   |  47 ++
 boards/arm/rtl8721dx/pke8721daf/src/CMakeLists.txt |   7 +-
 boards/arm/rtl8721dx/pke8721daf/src/Makefile       |   9 +
 .../rtl8721dx/pke8721daf/src/rtl8721dx_bringup.c   |  10 +
 .../pke8721daf/src/rtl8721dx_pke8721daf.h          |  13 +
 .../arm/rtl8721dx/pke8721daf/src/rtl8721dx_timer.c |  75 +++
 14 files changed, 936 insertions(+), 6 deletions(-)

diff --git a/Documentation/platforms/arm/rtl8721dx/boards/pke8721daf/index.rst 
b/Documentation/platforms/arm/rtl8721dx/boards/pke8721daf/index.rst
index 0e66109df8a..0565b1d1725 100644
--- a/Documentation/platforms/arm/rtl8721dx/boards/pke8721daf/index.rst
+++ b/Documentation/platforms/arm/rtl8721dx/boards/pke8721daf/index.rst
@@ -49,6 +49,8 @@ Supported in this NuttX port:
   alarm support, driven directly on the SDK fwlib register layer
 * On-chip watchdog exposed as a ``/dev/watchdog0`` character device, driven
   directly on the SDK fwlib register layer
+* General-purpose timers exposed as ``/dev/timer0`` and ``/dev/timer1``
+  character devices, driven directly on the SDK fwlib register layer
 
 Buttons and LEDs
 ================
@@ -199,6 +201,20 @@ which opens the device, sets a timeout, and pings it::
 
     nsh> wdog                            # run the watchdog example
 
+timer
+-----
+
+Minimal NSH with the on-chip general-purpose timer driver and the ``timer``
+example enabled (no Wi-Fi). Two 32-bit basic timers clocked at 32.768 kHz are
+registered from the board bring-up
+(``boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_timer.c``) as ``/dev/timer0``
+(TIM1) and ``/dev/timer1`` (TIM2); they have no board wiring (they are
+internal). TIM0 is reserved by the boot ROM as the system timer and is not
+exposed. Exercise a device with the example, which sets an interval and counts
+the update interrupts::
+
+    nsh> timer -d /dev/timer0            # run the timer example on TIM1
+
 Wi-Fi
 =====
 
diff --git a/arch/arm/src/common/ameba/Kconfig 
b/arch/arm/src/common/ameba/Kconfig
index ea74d1435d0..d34a65e2b6d 100644
--- a/arch/arm/src/common/ameba/Kconfig
+++ b/arch/arm/src/common/ameba/Kconfig
@@ -149,4 +149,21 @@ config AMEBA_WDG
                enabled, so stop() arms the WDG early interrupt and refreshes 
the
                counter from its handler to inhibit the reset.
 
+config AMEBA_TIMER
+       bool "Timer"
+       default n
+       select TIMER
+       ---help---
+               Expose the Ameba general-purpose timers as NuttX timer devices 
at
+               /dev/timerN (start/stop/settimeout/getstatus, plus a periodic
+               expiration callback).  The timeout is programmed directly in
+               microseconds.
+
+               The driver (arch/arm/src/common/ameba/ameba_timer.c) is a
+               parameterised lower half sitting on the SDK fwlib RTIM register
+               layer; the board picks which of the twelve on-chip timers to 
expose
+               via the per-chip instance table.  On the pke8721daf /dev/timer0 
is
+               TIM1 and /dev/timer1 is TIM2, both 32.768 kHz basic timers.  
TIM0
+               is reserved by the ROM as the system timer and is not exposed.
+
 endmenu # Ameba Peripheral Support
diff --git a/arch/arm/src/common/ameba/ameba_timer.c 
b/arch/arm/src/common/ameba/ameba_timer.c
new file mode 100644
index 00000000000..a90c2f121ea
--- /dev/null
+++ b/arch/arm/src/common/ameba/ameba_timer.c
@@ -0,0 +1,546 @@
+/****************************************************************************
+ * arch/arm/src/common/ameba/ameba_timer.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
+ ****************************************************************************/
+
+/* NuttX timer lower half for the Realtek Ameba general-purpose timers.  The
+ * chip carries twelve identical 32-bit up-counting timers (TIM0..TIM11);
+ * this driver is a parameterised lower half that binds any of them, by
+ * an instance index into the per-chip AMEBA_TIMER_CONFIG_TABLE.  The board
+ * calls ameba_timer_initialize() once per device, so several timers can be
+ * exposed at once -- on the pke8721daf /dev/timer0 is TIM1 (32.768 kHz, long
+ * low-power intervals) and /dev/timer1 is TIM2 (also 32.768 kHz).  TIM0 is
+ * reserved by the ROM as the system timer (SYSTIMER, 31 us/tick) and is
+ * never exposed as a general-purpose timer here.
+ *
+ * Each timer counts up from 0 to its auto-reload value ARR, raises the
+ * update interrupt on overflow and reloads to 0 automatically, so a running
+ * timer is inherently periodic.  A timeout in microseconds maps to ARR with
+ * the single SDK formula ARR = us * clkfreq / 1e6 - 1 (verified against the
+ * vendor timer_api.c gtimer_reload for the 32.768 kHz basic timers); the
+ * arithmetic is done in 64 bits so a large microsecond timeout scaled by the
+ * clock does not overflow.
+ *
+ * The timer is driven through the SDK fwlib RTIM API.  The time-base setup
+ * (RTIM_TimeBaseStructInit/RTIM_TimeBaseInit/RTIM_Cmd/RTIM_INTConfig/
+ * RTIM_GetCount) resolves to the on-chip ROM symbol table (_LONG_CALL_
+ * entries), while the interrupt-clear and hot period-change helpers
+ * (RTIM_INTClear/RTIM_ChangePeriodImmediate) come from the fwlib RAM source
+ * ameba_tim.c and linked in.  The NuttX interrupt is attached with the
+ * standard irq_attach()/up_enable_irq() (RTIM_TimeBaseInit is passed a NULL
+ * user callback so the vendor HAL installs nothing of its own), matching the
+ * other Ameba drivers on this core.
+ *
+ * The chip-specific wiring (per-instance register base, input clock, RCC
+ * clock masks and IRQ number) lives entirely in the per-chip
+ * ameba_timer_chip.h instance table; the shared driver reads only that table
+ * and is never edited per chip.  As in the PWM driver the one fwlib init
+ * struct layout used here is mirrored locally rather than pulling in the
+ * vendor <ameba_pwmtimer.h>.
+ */
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/timers/timer.h>
+
+#include "ameba_timer.h"
+#include "ameba_timer_chip.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Second/third argument to fwlib "state" style APIs. */
+
+#define AMEBA_DISABLE               0x0
+#define AMEBA_ENABLE                0x1
+
+/* fwlib time-base field values (from ameba_pwmtimer.h). */
+
+#define AMEBA_TIM_IT_UPDATE         0x00000001  /* TIM_IT_Update             */
+#define AMEBA_TIM_UPDATESRC_OVER    0x00000004  /* TIM_UpdateSource_Overflow */
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* One row of the per-chip AMEBA_TIMER_CONFIG_TABLE. */
+
+struct ameba_timer_config_s
+{
+  uintptr_t base;              /* Non-secure timer register base */
+  uint32_t  periph;            /* RCC periph function mask (arg 1) */
+  uint32_t  clk;               /* RCC periph clock mask (arg 2) */
+  uint32_t  clkfreq;           /* Timer input clock (Hz) */
+  int       irq;               /* NuttX IRQ number */
+  uint8_t   idx;               /* Timer index (TIM_Idx) */
+};
+
+/* Layout-compatible mirror of the fwlib RTIM_TimeBaseInitTypeDef (same field
+ * order and types); passed by address to RTIM_TimeBaseStructInit()/
+ * RTIM_TimeBaseInit().
+ */
+
+struct ameba_tim_timebase_s
+{
+  uint32_t prescaler;          /* TIM_Prescaler    */
+  uint32_t period;             /* TIM_Period       */
+  uint32_t updateevent;        /* TIM_UpdateEvent  */
+  uint32_t updatesource;       /* TIM_UpdateSource */
+  uint32_t arrprotection;      /* TIM_ARRProtection */
+  uint8_t  idx;                /* TIM_Idx          */
+  uint32_t securetimer;        /* TIM_SecureTimer  */
+};
+
+struct ameba_timer_lowerhalf_s
+{
+  const struct timer_ops_s *ops; /* Lower half operations (must be first) */
+  struct ameba_timer_config_s cfg;
+  tccb_t    callback;          /* Upper-half expiration callback */
+  void     *arg;               /* Argument for the callback */
+  uint32_t  timeout;           /* Programmed timeout (microseconds) */
+  uint32_t  arr;               /* Auto-reload value for that timeout */
+  bool      started;           /* Time base is running */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* SDK fwlib RTIM/clock API (ROM for the time base, RAM ameba_tim.c for the
+ * interrupt-clear and period-change helpers).  The RTIM_TypeDef pointer is
+ * passed as the raw register base cast to void *.
+ */
+
+extern void RCC_PeriphClockCmd(uint32_t periph, uint32_t clock,
+                               uint8_t newstate);
+extern void RTIM_TimeBaseStructInit(struct ameba_tim_timebase_s *init);
+extern void RTIM_TimeBaseInit(void *timx,
+                              struct ameba_tim_timebase_s *init,
+                              int irqnum, void *usercb, uint32_t cbdata);
+extern void RTIM_Cmd(void *timx, uint32_t newstate);
+extern void RTIM_INTConfig(void *timx, uint32_t tim_it, uint32_t newstate);
+extern void RTIM_INTClear(void *timx);
+extern void RTIM_ChangePeriodImmediate(void *timx, uint32_t autoreload);
+extern uint32_t RTIM_GetCount(void *timx);
+
+/* Timer lower-half operations. */
+
+static int ameba_timer_start(struct timer_lowerhalf_s *lower);
+static int ameba_timer_stop(struct timer_lowerhalf_s *lower);
+static int ameba_timer_getstatus(struct timer_lowerhalf_s *lower,
+                                 struct timer_status_s *status);
+static int ameba_timer_settimeout(struct timer_lowerhalf_s *lower,
+                                  uint32_t timeout);
+static void ameba_timer_setcallback(struct timer_lowerhalf_s *lower,
+                                    tccb_t callback, void *arg);
+static int ameba_timer_maxtimeout(struct timer_lowerhalf_s *lower,
+                                  uint32_t *maxtimeout);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct timer_ops_s g_ameba_timer_ops =
+{
+  .start      = ameba_timer_start,
+  .stop       = ameba_timer_stop,
+  .getstatus  = ameba_timer_getstatus,
+  .settimeout = ameba_timer_settimeout,
+  .setcallback = ameba_timer_setcallback,
+  .maxtimeout = ameba_timer_maxtimeout,
+};
+
+/* Per-chip instance table: { base, periph, clk, clkfreq, irq, idx }. */
+
+static const struct ameba_timer_config_s
+  g_ameba_timer_config[AMEBA_TIMER_NINSTANCES] = AMEBA_TIMER_CONFIG_TABLE;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ameba_timer_us2arr
+ *
+ * Description:
+ *   Convert a timeout in microseconds to the timer's auto-reload value using
+ *   the SDK formula ARR = us * clkfreq / 1e6 - 1, in 64-bit arithmetic so a
+ *   large microsecond timeout scaled by the clock does not overflow.
+ *
+ ****************************************************************************/
+
+static uint32_t ameba_timer_us2arr(uint32_t clkfreq, uint32_t us)
+{
+  uint64_t ticks = ((uint64_t)us * clkfreq) / 1000000ull;
+
+  if (ticks == 0)
+    {
+      ticks = 1;
+    }
+
+  return (uint32_t)(ticks - 1);
+}
+
+/****************************************************************************
+ * Name: ameba_timer_interrupt
+ *
+ * Description:
+ *   Update-event ISR.  Clears the flag, invokes the upper-half callback and
+ *   honours its verdict: a false return stops the timer, a true return keeps
+ *   it periodic and may hot-change the period to the callback's next
+ *   interval (deferred by the ARR protection to the reload just started).
+ *
+ ****************************************************************************/
+
+/* Dummy handler passed to RTIM_TimeBaseInit so the ROM performs its full
+ * timer configuration (some register setup is skipped when UserCB is NULL).
+ * NuttX installs its own vector table, so this is never actually invoked.
+ */
+
+static uint32_t ameba_timer_dummy_cb(void *data)
+{
+  UNUSED(data);
+  return 0;
+}
+
+static int ameba_timer_interrupt(int irq, void *context, void *arg)
+{
+  struct ameba_timer_lowerhalf_s *priv = arg;
+
+  /* Clear the pending update flag via the ROM helper (it polls the timer
+   * clock domain to guarantee the write took effect).
+   */
+
+  RTIM_INTClear((void *)priv->cfg.base);
+
+  if (priv->callback != NULL)
+    {
+      uint32_t next = priv->timeout;
+
+      if (priv->callback(&next, priv->arg))
+        {
+          if (next != priv->timeout && next > 0)
+            {
+              /* The callback asked for a different next interval. */
+
+              priv->timeout = next;
+              priv->arr     = ameba_timer_us2arr(priv->cfg.clkfreq, next);
+              RTIM_ChangePeriodImmediate((void *)priv->cfg.base, priv->arr);
+            }
+        }
+      else
+        {
+          /* The callback asked to stop after this expiration. */
+
+          RTIM_INTConfig((void *)priv->cfg.base, AMEBA_TIM_IT_UPDATE,
+                         AMEBA_DISABLE);
+          RTIM_Cmd((void *)priv->cfg.base, AMEBA_DISABLE);
+          priv->started = false;
+        }
+    }
+
+  /* Clear once more (vendor double-clear guard). */
+
+  RTIM_INTClear((void *)priv->cfg.base);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ameba_timer_start
+ ****************************************************************************/
+
+static int ameba_timer_start(struct timer_lowerhalf_s *lower)
+{
+  struct ameba_timer_lowerhalf_s *priv =
+    (struct ameba_timer_lowerhalf_s *)lower;
+  struct ameba_tim_timebase_s tb;
+
+  if (priv->started)
+    {
+      return -EPERM;
+    }
+
+  if (priv->arr == 0 && priv->timeout == 0)
+    {
+      /* No timeout has been programmed yet. */
+
+      return -EINVAL;
+    }
+
+  memset(&tb, 0, sizeof(tb));
+  RTIM_TimeBaseStructInit(&tb);
+
+  /* Match the vendor gtimer_init exactly: TIM_Period is NOT supplied here.
+   * TimeBaseInit with ARR preload enabled would leave the auto-reload shadow
+   * at its reset value (0) until the first overflow, so arming the interrupt
+   * immediately floods the CPU.  The period is instead programmed by the
+   * RTIM_ChangePeriodImmediate() below, which clears ARPE, writes ARR and
+   * issues a UG so the shadow is loaded before the timer runs.
+   */
+
+  tb.idx           = priv->cfg.idx;
+  tb.updateevent   = AMEBA_ENABLE;
+  tb.updatesource  = AMEBA_TIM_UPDATESRC_OVER;
+  tb.arrprotection = AMEBA_ENABLE;
+
+  /* NULL user callback: the NuttX ISR is attached separately, so the vendor
+   * HAL installs no handler of its own.
+   */
+
+  RTIM_TimeBaseInit((void *)priv->cfg.base, &tb, priv->cfg.irq,
+                    (void *)ameba_timer_dummy_cb, 0);
+
+  /* Program the period and force an immediate shadow reload (vendor
+   * gtimer_reload).  The overflow reload is periodic on this IP whatever the
+   * ARR-preload bit is, so no further CR fix-up is needed here.
+   */
+
+  RTIM_ChangePeriodImmediate((void *)priv->cfg.base, priv->arr);
+
+  /* Only fire the update interrupt when an upper-half callback wants it; a
+   * bare timer just free-runs and reloads for getstatus() polling (vendor
+   * gtimer_start: INTConfig then Cmd).
+   */
+
+  RTIM_INTConfig((void *)priv->cfg.base, AMEBA_TIM_IT_UPDATE,
+                 priv->callback != NULL ? AMEBA_ENABLE : AMEBA_DISABLE);
+
+  RTIM_Cmd((void *)priv->cfg.base, AMEBA_ENABLE);
+
+  priv->started = true;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ameba_timer_stop
+ ****************************************************************************/
+
+static int ameba_timer_stop(struct timer_lowerhalf_s *lower)
+{
+  struct ameba_timer_lowerhalf_s *priv =
+    (struct ameba_timer_lowerhalf_s *)lower;
+
+  if (!priv->started)
+    {
+      return -EPERM;
+    }
+
+  RTIM_INTConfig((void *)priv->cfg.base, AMEBA_TIM_IT_UPDATE, AMEBA_DISABLE);
+  RTIM_Cmd((void *)priv->cfg.base, AMEBA_DISABLE);
+  priv->started = false;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ameba_timer_getstatus
+ ****************************************************************************/
+
+static int ameba_timer_getstatus(struct timer_lowerhalf_s *lower,
+                                 struct timer_status_s *status)
+{
+  struct ameba_timer_lowerhalf_s *priv =
+    (struct ameba_timer_lowerhalf_s *)lower;
+  uint32_t count;
+  uint32_t remaining;
+
+  status->flags = 0;
+  if (priv->started)
+    {
+      status->flags |= TCFLAGS_ACTIVE;
+    }
+
+  if (priv->callback != NULL)
+    {
+      status->flags |= TCFLAGS_HANDLER;
+    }
+
+  status->timeout = priv->timeout;
+
+  /* Time left = (ARR + 1 - current up-count) converted back to microseconds
+   * in 64-bit arithmetic; a stopped timer has the full timeout left.
+   */
+
+  if (priv->started)
+    {
+      count     = RTIM_GetCount((void *)priv->cfg.base);
+      remaining = (count > priv->arr) ? 0 : (priv->arr + 1 - count);
+      status->timeleft =
+        (uint32_t)(((uint64_t)remaining * 1000000ull) / priv->cfg.clkfreq);
+    }
+  else
+    {
+      status->timeleft = priv->timeout;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ameba_timer_settimeout
+ ****************************************************************************/
+
+static int ameba_timer_settimeout(struct timer_lowerhalf_s *lower,
+                                  uint32_t timeout)
+{
+  struct ameba_timer_lowerhalf_s *priv =
+    (struct ameba_timer_lowerhalf_s *)lower;
+
+  if (timeout == 0)
+    {
+      return -EINVAL;
+    }
+
+  priv->timeout = timeout;
+  priv->arr     = ameba_timer_us2arr(priv->cfg.clkfreq, timeout);
+
+  /* Hot-update a running time base; the auto-reload protection defers the
+   * change to the next update event so the count does not glitch.
+   */
+
+  if (priv->started)
+    {
+      RTIM_ChangePeriodImmediate((void *)priv->cfg.base, priv->arr);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ameba_timer_setcallback
+ ****************************************************************************/
+
+static void ameba_timer_setcallback(struct timer_lowerhalf_s *lower,
+                                    tccb_t callback, void *arg)
+{
+  struct ameba_timer_lowerhalf_s *priv =
+    (struct ameba_timer_lowerhalf_s *)lower;
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  priv->callback = callback;
+  priv->arg      = arg;
+
+  /* Track the interrupt enable to the callback while the timer runs, so a
+   * callback set or cleared after start() takes effect immediately.
+   */
+
+  if (priv->started)
+    {
+      RTIM_INTConfig((void *)priv->cfg.base, AMEBA_TIM_IT_UPDATE,
+                     callback != NULL ? AMEBA_ENABLE : AMEBA_DISABLE);
+    }
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: ameba_timer_maxtimeout
+ ****************************************************************************/
+
+static int ameba_timer_maxtimeout(struct timer_lowerhalf_s *lower,
+                                  uint32_t *maxtimeout)
+{
+  struct ameba_timer_lowerhalf_s *priv =
+    (struct ameba_timer_lowerhalf_s *)lower;
+  uint64_t maxus;
+
+  /* Largest microsecond value whose ARR still fits the 32-bit counter:
+   * us = (ARR_max + 1) * 1e6 / clkfreq, capped to the uint32_t API range.
+   */
+
+  maxus = ((uint64_t)0xffffffffull * 1000000ull) / priv->cfg.clkfreq;
+  if (maxus > 0xffffffffull)
+    {
+      maxus = 0xffffffffull;
+    }
+
+  *maxtimeout = (uint32_t)maxus;
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ameba_timer_initialize
+ *
+ * Description:
+ *   See ameba_timer.h.
+ *
+ ****************************************************************************/
+
+int ameba_timer_initialize(const char *devpath, int instance)
+{
+  struct ameba_timer_lowerhalf_s *priv;
+  void *handle;
+
+  if (instance < 0 || instance >= AMEBA_TIMER_NINSTANCES)
+    {
+      return -EINVAL;
+    }
+
+  priv = kmm_zalloc(sizeof(struct ameba_timer_lowerhalf_s));
+  if (priv == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  priv->ops = &g_ameba_timer_ops;
+  priv->cfg = g_ameba_timer_config[instance];
+
+  /* Gate the timer's peripheral clock (function and clock masks are equal on
+   * this chip) and wire the NuttX interrupt.  The time base itself is left
+   * stopped until start(); settimeout() supplies the period first.
+   */
+
+  RCC_PeriphClockCmd(priv->cfg.periph, priv->cfg.clk, AMEBA_ENABLE);
+
+  irq_attach(priv->cfg.irq, ameba_timer_interrupt, priv);
+  up_enable_irq(priv->cfg.irq);
+
+  handle = timer_register(devpath, (struct timer_lowerhalf_s *)priv);
+  if (handle == NULL)
+    {
+      up_disable_irq(priv->cfg.irq);
+      irq_detach(priv->cfg.irq);
+      _err("ERROR: timer_register(%s) failed\n", devpath);
+      kmm_free(priv);
+      return -EEXIST;
+    }
+
+  return OK;
+}
diff --git a/arch/arm/src/common/ameba/ameba_timer.h 
b/arch/arm/src/common/ameba/ameba_timer.h
new file mode 100644
index 00000000000..bec1e529483
--- /dev/null
+++ b/arch/arm/src/common/ameba/ameba_timer.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+ * arch/arm/src/common/ameba/ameba_timer.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_COMMON_AMEBA_AMEBA_TIMER_H
+#define __ARCH_ARM_SRC_COMMON_AMEBA_AMEBA_TIMER_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Name: ameba_timer_initialize
+ *
+ * Description:
+ *   Bind one Ameba general-purpose timer instance to the NuttX timer
+ *   character driver and register it at the given path (typically
+ *   "/dev/timerN").  The instance index selects a row of the per-chip
+ *   AMEBA_TIMER_CONFIG_TABLE (0 == TIM1, 1 == TIM2, both @ 32.768 kHz on the
+ *   pke8721daf); its base, clock, RCC masks and IRQ come from that table, so
+ *   a board only names the device and the instance it wants.
+ *
+ * Input Parameters:
+ *   devpath  - The device path to register, e.g. "/dev/timer0".
+ *   instance - Index into the per-chip timer instance table
+ *              (0 .. AMEBA_TIMER_NINSTANCES - 1).
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int ameba_timer_initialize(const char *devpath, int instance);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ARCH_ARM_SRC_COMMON_AMEBA_AMEBA_TIMER_H */
diff --git a/arch/arm/src/rtl8721dx/CMakeLists.txt 
b/arch/arm/src/rtl8721dx/CMakeLists.txt
index 5e2dda71e14..b9345e0d78f 100644
--- a/arch/arm/src/rtl8721dx/CMakeLists.txt
+++ b/arch/arm/src/rtl8721dx/CMakeLists.txt
@@ -72,6 +72,10 @@ if(CONFIG_AMEBA_WDG)
   list(APPEND SRCS ${AMEBA_COMMON}/ameba_wdg.c)
 endif()
 
+if(CONFIG_AMEBA_TIMER)
+  list(APPEND SRCS ${AMEBA_COMMON}/ameba_timer.c)
+endif()
+
 target_include_directories(arch PRIVATE ${AMEBA_COMMON})
 target_sources(arch PRIVATE ${SRCS})
 
diff --git a/arch/arm/src/rtl8721dx/Make.defs b/arch/arm/src/rtl8721dx/Make.defs
index 0503fce09fb..303d1fc2b82 100644
--- a/arch/arm/src/rtl8721dx/Make.defs
+++ b/arch/arm/src/rtl8721dx/Make.defs
@@ -82,6 +82,10 @@ ifeq ($(CONFIG_AMEBA_WDG),y)
 CHIP_CSRCS += ameba_wdg.c
 endif
 
+ifeq ($(CONFIG_AMEBA_TIMER),y)
+CHIP_CSRCS += ameba_timer.c
+endif
+
 ############################################################################
 # Realtek RTL8721Dx SDK integration
 #
diff --git a/arch/arm/src/rtl8721dx/ameba_board.mk 
b/arch/arm/src/rtl8721dx/ameba_board.mk
index 204699ed8d7..e2710e0eea4 100644
--- a/arch/arm/src/rtl8721dx/ameba_board.mk
+++ b/arch/arm/src/rtl8721dx/ameba_board.mk
@@ -155,12 +155,13 @@ ifeq ($(CONFIG_AMEBA_SPI),y)
 AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_spi.c
 endif
 
-# PWM timer register layer.  The time-base entry points (RTIM_TimeBaseInit/
-# StructInit/Cmd) are in ROM, but the compare/period helpers the PWM driver
-# (arch/.../common/ameba/ameba_pwm.c) calls -- RTIM_CCStructInit/CCxInit/
-# CCRxSet/CCxCmd/ChangePeriod/PrescalerConfig -- are compiled from this RAM
+# PWM/timer register layer.  The time-base entry points (RTIM_TimeBaseInit/
+# StructInit/Cmd/INTConfig/GetCount) are in ROM, but the compare/period and
+# interrupt-clear helpers the PWM driver (ameba_pwm.c: RTIM_CCStructInit/
+# CCxInit/CCRxSet/CCxCmd/ChangePeriod/PrescalerConfig) and the timer driver
+# (ameba_timer.c: RTIM_INTClear/ChangePeriod) call are compiled from this RAM
 # source and linked in (--gc-sections drops the unused input-capture paths).
-ifeq ($(CONFIG_AMEBA_PWM),y)
+ifneq (,$(filter y,$(CONFIG_AMEBA_PWM) $(CONFIG_AMEBA_TIMER)))
 AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_tim.c
 endif
 
diff --git a/arch/arm/src/rtl8721dx/ameba_timer_chip.h 
b/arch/arm/src/rtl8721dx/ameba_timer_chip.h
new file mode 100644
index 00000000000..90e65e096c5
--- /dev/null
+++ b/arch/arm/src/rtl8721dx/ameba_timer_chip.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+ * arch/arm/src/rtl8721dx/ameba_timer_chip.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_RTL8721DX_AMEBA_TIMER_CHIP_H
+#define __ARCH_ARM_SRC_RTL8721DX_AMEBA_TIMER_CHIP_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/irq.h>
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Per-chip general-purpose timer wiring for RTL8721DX (amebadplus).  The
+ * shared driver (arch/arm/src/common/ameba/ameba_timer.c) includes this
+ * header to learn which timer instances it may expose and, for each one, its
+ * register base, input clock, RCC clock masks and interrupt line.  A port to
+ * another Ameba chip supplies a same-named header on the chip include path;
+ * the shared driver is never edited -- it reads only the macros below and
+ * the instance table, computing the period from clkfreq with one formula.
+ *
+ * The Ameba SoC carries twelve timers (TIM0..TIM11) that all share the one
+ * RTIM register layout and fwlib API, so the register access, the
+ * microsecond<->tick conversion and the whole lower-half live in the shared
+ * driver.  What differs per instance -- and per chip -- is only data: the
+ * base address, the clock that feeds it, its RCC gate masks and its NuttX
+ * IRQ number.  These sit in AMEBA_TIMER_CONFIG_TABLE so a new chip (or
+ * a different instance choice) edits this header alone.
+ *
+ * This port exposes two of the twelve, both from the 32-bit "basic" (LTIM)
+ * bank so a single lower-half serves them uniformly (verified against the
+ * SoC hal_platform.h / sysreg_lsys.h / vector table and the vendor
+ * timer_api.c, not guessed):
+ *
+ *   instance  timer   base         clock       RCC gate         NuttX IRQ
+ *   --------  ------   ----------   ---------   --------------   ----------
+ *   0         TIM1     0x41017200   32.768 kHz  APBPeriph_LTIM1  IRQ_TIMER1
+ *   1         TIM2     0x41017400   32.768 kHz  APBPeriph_LTIM2  IRQ_TIMER2
+ *
+ * TIM1 and TIM2 are two of the eight 32-bit "basic" (LTIM) timers clocked
+ * from the 32.768 kHz LS clock: ~30.5 us per tick, up to ~36 h in one shot.
+ * A full 32-bit auto-reload lets them cover the whole microsecond API range,
+ * which is why the driver exposes this bank rather than the four 40 MHz
+ * "high" (HTIM) timers TIM8..TIM11: those have only a 16-bit auto-reload
+ * (max ~1.638 ms at 40 MHz) and no usable prescaler on TIM10/TIM11, so they
+ * suit sub-millisecond fine timing only and are intentionally not exposed.
+ * TIM8/TIM9 additionally drive the PWM/input-capture block.
+ *
+ * TIM0 is deliberately NOT exposed: the boot ROM claims it as the always-on
+ * system timer (see the vendor ameba_delay.h -- "TIM0 is used as systimer,
+ * so TIM0 can not be used for other purpose ... init when boot in rom
+ * code"), and DelayUs/DelayMs/SYSTIMER_* all rely on it.  Reprogramming TIM0
+ * would break every SDK delay, so the driver starts the basic bank at TIM1.
+ *
+ * The RCC gate masks are the fwlib APBPeriph_LTIM1 / APBPeriph_LTIM2 values
+ * (function and clock masks are identical on this chip).  They are written
+ * out here rather than pulled from <sysreg_lsys.h> to keep the vendor
+ * headers out of the NuttX include world (same rule as the PWM chip header).
+ */
+
+/* RCC "function" and "clock" masks, bit30 group selector then bit index. */
+
+#define AMEBA_TIMER_LTIM1_MASK    (((uint32_t)1 << 30) | ((uint32_t)1 << 13))
+#define AMEBA_TIMER_LTIM2_MASK    (((uint32_t)1 << 30) | ((uint32_t)1 << 14))
+
+/* Number of timer instances this chip exposes and the data table that
+ * describes each one.  The shared driver defines struct ameba_timer_config_s
+ * and instantiates this table; each row is
+ * { base, periph, clk, clkfreq, irq, idx }.
+ */
+
+#define AMEBA_TIMER_NINSTANCES    2
+
+#define AMEBA_TIMER_CONFIG_TABLE                                             \
+{                                                                           \
+  {                                                                         \
+    0x41017200ul, AMEBA_TIMER_LTIM1_MASK, AMEBA_TIMER_LTIM1_MASK,           \
+    32768ul, RTL8721DX_IRQ_TIMER1, 1                                        \
+  },                                                                        \
+  {                                                                         \
+    0x41017400ul, AMEBA_TIMER_LTIM2_MASK, AMEBA_TIMER_LTIM2_MASK,           \
+    32768ul, RTL8721DX_IRQ_TIMER2, 2                                        \
+  },                                                                        \
+}
+
+#endif /* __ARCH_ARM_SRC_RTL8721DX_AMEBA_TIMER_CHIP_H */
diff --git a/boards/arm/rtl8721dx/pke8721daf/configs/timer/defconfig 
b/boards/arm/rtl8721dx/pke8721daf/configs/timer/defconfig
new file mode 100644
index 00000000000..22a609302de
--- /dev/null
+++ b/boards/arm/rtl8721dx/pke8721daf/configs/timer/defconfig
@@ -0,0 +1,47 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed 
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that 
includes your
+# modifications.
+#
+CONFIG_AMEBA_TIMER=y
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="pke8721daf"
+CONFIG_ARCH_BOARD_PKE8721DAF=y
+CONFIG_ARCH_CHIP="rtl8721dx"
+CONFIG_ARCH_CHIP_RTL8721DX=y
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARMV8M_SYSTICK=y
+CONFIG_BOARD_LOOPSPERMSEC=43103
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_ASSERTIONS=y
+CONFIG_DEBUG_FEATURES=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DEFAULT_TASK_STACKSIZE=4096
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_EXAMPLES_TIMER=y
+CONFIG_FS_PROCFS=y
+CONFIG_FS_TMPFS=y
+CONFIG_IDLETHREAD_STACKSIZE=4096
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_LIBC_MEMFD_ERROR=y
+CONFIG_MM_DEFAULT_ALIGNMENT=32
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_READLINE=y
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_RAM_SIZE=294912
+CONFIG_RAM_START=0x20020000
+CONFIG_RR_INTERVAL=200
+CONFIG_RTL8721DX_FLASH_FS=y
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_HPWORKPRIORITY=192
+CONFIG_SCHED_LPWORK=y
+CONFIG_STACK_COLORATION=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_SYSTEM_NSH_STACKSIZE=2500
+CONFIG_TIMER_ARCH=y
+CONFIG_USEC_PER_TICK=1000
diff --git a/boards/arm/rtl8721dx/pke8721daf/src/CMakeLists.txt 
b/boards/arm/rtl8721dx/pke8721daf/src/CMakeLists.txt
index b0e12365ffe..6e4a7c921b5 100644
--- a/boards/arm/rtl8721dx/pke8721daf/src/CMakeLists.txt
+++ b/boards/arm/rtl8721dx/pke8721daf/src/CMakeLists.txt
@@ -54,6 +54,10 @@ if(CONFIG_AMEBA_WDG)
   list(APPEND SRCS rtl8721dx_wdg.c)
 endif()
 
+if(CONFIG_AMEBA_TIMER)
+  list(APPEND SRCS rtl8721dx_timer.c)
+endif()
+
 target_sources(board PRIVATE ${SRCS})
 
 if(CONFIG_AMEBA_GPIO
@@ -63,7 +67,8 @@ if(CONFIG_AMEBA_GPIO
    OR CONFIG_AMEBA_PWM
    OR CONFIG_AMEBA_ADC
    OR CONFIG_AMEBA_RTC
-   OR CONFIG_AMEBA_WDG)
+   OR CONFIG_AMEBA_WDG
+   OR CONFIG_AMEBA_TIMER)
   # The board pin/UART tables pull in the shared driver's public headers from
   # arch/arm/src/common/ameba/, not on the default board include path.
   target_include_directories(board
diff --git a/boards/arm/rtl8721dx/pke8721daf/src/Makefile 
b/boards/arm/rtl8721dx/pke8721daf/src/Makefile
index 2fd83e815f3..f5ab3251993 100644
--- a/boards/arm/rtl8721dx/pke8721daf/src/Makefile
+++ b/boards/arm/rtl8721dx/pke8721daf/src/Makefile
@@ -96,4 +96,13 @@ CSRCS += rtl8721dx_wdg.c
 CFLAGS += 
${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)arm$(DELIM)src$(DELIM)common$(DELIM)ameba
 endif
 
+ifeq ($(CONFIG_AMEBA_TIMER),y)
+CSRCS += rtl8721dx_timer.c
+
+# The board timer bring-up pulls in the shared driver's public header from
+# arch/arm/src/common/ameba/, which is not on the default board include path.
+
+CFLAGS += 
${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)arm$(DELIM)src$(DELIM)common$(DELIM)ameba
+endif
+
 include $(TOPDIR)/boards/Board.mk
diff --git a/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_bringup.c 
b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_bringup.c
index d32f19c2062..5a456a7ea69 100644
--- a/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_bringup.c
+++ b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_bringup.c
@@ -188,6 +188,16 @@ int rtl8721dx_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_AMEBA_TIMER
+  /* Register the board's timers at /dev/timer0 and /dev/timer1. */
+
+  ret = rtl8721dx_timer_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: rtl8721dx_timer_initialize failed: %d\n", ret);
+    }
+#endif
+
   /* Install the inter-core HW IPC-semaphore RTOS hooks LAST -- after all the
    * flash / WHC bring-up above, and just before this (board_late_initialize)
    * path returns and nx_start() hands off to the init task.
diff --git a/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_pke8721daf.h 
b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_pke8721daf.h
index 94a3934b73d..6e5b9089410 100644
--- a/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_pke8721daf.h
+++ b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_pke8721daf.h
@@ -173,6 +173,19 @@ int rtl8721dx_rtc_initialize(void);
 int rtl8721dx_wdg_initialize(void);
 #endif
 
+#ifdef CONFIG_AMEBA_TIMER
+/****************************************************************************
+ * Name: rtl8721dx_timer_initialize
+ *
+ * Description:
+ *   Register the board's timers at /dev/timer0 (TIM1) and /dev/timer1
+ *   (TIM2) (boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_timer.c).
+ *
+ ****************************************************************************/
+
+int rtl8721dx_timer_initialize(void);
+#endif
+
 #ifdef CONFIG_RTL8721DX_FLASH_FS
 /****************************************************************************
  * Name: ameba_flash_fs_initialize
diff --git a/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_timer.c 
b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_timer.c
new file mode 100644
index 00000000000..36cf349d25c
--- /dev/null
+++ b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_timer.c
@@ -0,0 +1,75 @@
+/****************************************************************************
+ * boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_timer.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 <syslog.h>
+#include <errno.h>
+
+#include "ameba_timer.h"
+#include "rtl8721dx_pke8721daf.h"
+
+#ifdef CONFIG_AMEBA_TIMER
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rtl8721dx_timer_initialize
+ *
+ * Description:
+ *   Register the board's general-purpose timers.  Both timers are internal
+ *   (no board wiring), so this just binds the two exposed instances to their
+ *   device nodes: /dev/timer0 is TIM1 and /dev/timer1 is TIM2, both 32-bit
+ *   basic timers at 32.768 kHz.  TIM0 is reserved by the ROM as the system
+ *   timer and is not exposed.  A failure on either is logged but does not
+ *   abort the other.
+ *
+ ****************************************************************************/
+
+int rtl8721dx_timer_initialize(void)
+{
+  int ret;
+
+  ret = ameba_timer_initialize("/dev/timer0", 0);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR,
+             "ERROR: ameba_timer_initialize(/dev/timer0) failed: %d\n", ret);
+    }
+
+  ret = ameba_timer_initialize("/dev/timer1", 1);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR,
+             "ERROR: ameba_timer_initialize(/dev/timer1) failed: %d\n", ret);
+    }
+
+  return ret;
+}
+
+#endif /* CONFIG_AMEBA_TIMER */

Reply via email to