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 2b65c77adb9dd4832ca2bdbb068a7f714cd444fe
Author: dechao_gong <[email protected]>
AuthorDate: Mon Jul 20 17:15:52 2026 +0800

    arch/arm/rtl8721dx: add shared Ameba RTC driver
    
    Expose the Ameba on-chip RTC as a NuttX date/time RTC at /dev/rtc0
    (rdtime/settime) with a single one-shot alarm (setalarm/rdalarm/
    cancelalarm/setrelative) that fires the RTC interrupt and the upper-half
    callback.  The same hardware also backs the arch date/time RTC hooks
    (up_rtc_initialize/getdatetime/settime, g_rtc_enabled) so the NuttX
    system time is seeded from it.
    
    The driver sits on the SDK fwlib RTC API (mirrored structures + local
    externs, no vendor headers pulled into the NuttX include world).  The
    fwlib RTC API lives in the RAM source ameba_rtc.c, so it is added to the
    board fwlib build under CONFIG_AMEBA_RTC.  The hardware keeps a year plus
    a day-of-year (no month/day register); the driver bridges that to the
    NuttX month/day calendar with the libc UTC routines (timegm/gmtime_r),
    which is exact and reversible.
    
    The only per-chip fact -- the RTC interrupt vector -- lives in the
    per-chip ameba_rtc_chip.h; the shared driver is never edited for a new
    Ameba chip.  A configs/rtc profile (examples/alarm) is added for
    verification.
    
    Signed-off-by: dechao_gong <[email protected]>
    Assisted-by: Claude <[email protected]>
---
 .../arm/rtl8721dx/boards/pke8721daf/index.rst      |  16 +
 arch/arm/src/common/ameba/Kconfig                  |  17 +
 arch/arm/src/common/ameba/ameba_rtc.c              | 742 +++++++++++++++++++++
 arch/arm/src/common/ameba/ameba_rtc.h              |  89 +++
 arch/arm/src/rtl8721dx/CMakeLists.txt              |  11 +
 arch/arm/src/rtl8721dx/Make.defs                   |   4 +
 arch/arm/src/rtl8721dx/ameba_board.mk              |   9 +
 arch/arm/src/rtl8721dx/ameba_rtc_chip.h            |  85 +++
 .../arm/rtl8721dx/pke8721daf/configs/rtc/defconfig |  51 ++
 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_rtc.c   |  66 ++
 14 files changed, 1128 insertions(+), 1 deletion(-)

diff --git a/Documentation/platforms/arm/rtl8721dx/boards/pke8721daf/index.rst 
b/Documentation/platforms/arm/rtl8721dx/boards/pke8721daf/index.rst
index 3861744e7a2..c2a71f6c085 100644
--- a/Documentation/platforms/arm/rtl8721dx/boards/pke8721daf/index.rst
+++ b/Documentation/platforms/arm/rtl8721dx/boards/pke8721daf/index.rst
@@ -45,6 +45,8 @@ Supported in this NuttX port:
   the SDK fwlib timer register layer
 * ADC channels exposed as an ``/dev/adc0`` character device, driven directly
   on the SDK fwlib register layer
+* On-chip RTC exposed as a ``/dev/rtc0`` date/time character device with
+  alarm support, driven directly on the SDK fwlib register layer
 
 Buttons and LEDs
 ================
@@ -170,6 +172,20 @@ example::
 
     nsh> adc -n 1                        # one sweep of /dev/adc0
 
+rtc
+---
+
+Minimal NSH with the on-chip RTC driver and the ``alarm`` example enabled
+(no Wi-Fi). The RTC is registered at ``/dev/rtc0`` from the board bring-up
+(``boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_rtc.c``); it has no board
+wiring (it is an internal clock). The hardware stores year + day-of-year, so
+the shared driver bridges to a full calendar. Read and set the clock with the
+NSH ``date`` command, and arm a one-shot wakeup with the example::
+
+    nsh> date                            # read /dev/rtc0
+    nsh> date -s "Jun 16 12:00:00 2026"  # set the RTC
+    nsh> alarm 10                        # fire an alarm in 10 seconds
+
 Wi-Fi
 =====
 
diff --git a/arch/arm/src/common/ameba/Kconfig 
b/arch/arm/src/common/ameba/Kconfig
index 64775022448..d49164a70d4 100644
--- a/arch/arm/src/common/ameba/Kconfig
+++ b/arch/arm/src/common/ameba/Kconfig
@@ -117,4 +117,21 @@ config AMEBA_ADC
                polling in task context (the chip does not enable a hardware
                software-trigger path).
 
+config AMEBA_RTC
+       bool "RTC"
+       default n
+       select RTC
+       select RTC_DRIVER
+       select RTC_DATETIME
+       ---help---
+               Expose the Ameba on-chip real-time clock as a NuttX date/time 
RTC
+               at /dev/rtc0 (rdtime/settime).  Enable RTC_ALARM as well to get 
a
+               single one-shot alarm whose expiry fires the RTC interrupt and 
the
+               registered upper-half callback.
+
+               The driver (arch/arm/src/common/ameba/ameba_rtc.c) sits on the 
SDK
+               fwlib RTC register layer.  The hardware keeps a year plus a
+               day-of-year (no month/day register); the driver bridges that to 
the
+               NuttX month/day calendar with the libc UTC calendar routines.
+
 endmenu # Ameba Peripheral Support
diff --git a/arch/arm/src/common/ameba/ameba_rtc.c 
b/arch/arm/src/common/ameba/ameba_rtc.c
new file mode 100644
index 00000000000..f22fc3ab8f5
--- /dev/null
+++ b/arch/arm/src/common/ameba/ameba_rtc.c
@@ -0,0 +1,742 @@
+/****************************************************************************
+ * arch/arm/src/common/ameba/ameba_rtc.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 RTC lower half for the Realtek Ameba RTC.  It exposes the on-chip
+ * real-time clock as a NuttX date/time RTC at /dev/rtc0 (rdtime/settime)
+ * and, when CONFIG_RTC_ALARM is set, a single one-shot alarm (setalarm/
+ * rdalarm/cancelalarm/setrelative) whose expiry fires the RTC interrupt and
+ * calls the upper-half callback.  The same hardware also backs the arch RTC
+ * hooks (up_rtc_*) so the NuttX system time is seeded from it.
+ *
+ * The RTC is driven through the SDK fwlib RTC API.  Those routines are
+ * marked _LONG_CALL_ but are linked from the fwlib RAM source ameba_rtc.c
+ * (added to the board build), and none of them take a register base: the
+ * fwlib selects the secure/non-secure RTC alias itself, so this driver
+ * never touches a base address.  To keep the vendor headers out of the
+ * NuttX include world the few fwlib symbols, constants and structures used
+ * here are declared locally (layout-compatible mirrors) rather than pulled
+ * in from the SDK <ameba_rtc.h>.
+ *
+ * Calendar model: the Ameba RTC stores a year (1900..2155) plus a
+ * day-of-year (0..511) and h:m:s -- it has no month/day-of-month register.
+ * NuttX works in struct rtc_time (cast-compatible with struct tm: month +
+ * day-of-month).  The two are bridged with the libc calendar routines: to
+ * program the RTC we normalise the incoming time and take tm_yday; to read
+ * it back we place the day-of-year as "day tm_yday+1 of month 0" and let
+ * timegm()/gmtime_r() carry it into the correct month and day.  No timezone
+ * is involved (timegm() is UTC), so the conversion is exact and reversible.
+ *
+ * The only genuinely chip-specific fact -- the RTC interrupt vector -- lives
+ * in the per-chip ameba_rtc_chip.h, together with the clock masks and the
+ * calendar base year.  The shared driver here is never edited per chip.
+ */
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/mutex.h>
+#include <nuttx/timers/rtc.h>
+
+#include "ameba_rtc.h"
+#include "ameba_rtc_chip.h"
+
+#ifdef CONFIG_RTC_DRIVER
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* "state" argument for fwlib enable/disable style APIs. */
+
+#define AMEBA_DISABLE               0x0
+#define AMEBA_ENABLE                0x1
+
+/* fwlib RTC constants (from the SDK ameba_rtc.h; identical on every current
+ * Ameba chip).  BIN input format, 24-hour clock, AM indicator, and the alarm
+ * mask values that mean "match every field" (nothing masked out).
+ */
+
+#define AMEBA_RTC_FORMAT_BIN        0x0        /* RTC_Format_BIN          */
+#define AMEBA_RTC_HOURFMT_24        0x0        /* RTC_HourFormat_24       */
+#define AMEBA_RTC_H12_AM            0x0        /* RTC_H12_AM              */
+#define AMEBA_RTC_ALARMMASK_NONE    0x0        /* RTC_AlarmMask_None      */
+#define AMEBA_RTC_ALARM2MASK_NONE   0x0        /* RTC_Alarm2Mask_None     */
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Layout-compatible mirrors of the fwlib RTC structures (same field order
+ * and types); passed by address to the fwlib RTC API.
+ */
+
+/* RTC_InitTypeDef */
+
+struct ameba_rtc_init_s
+{
+  uint32_t hourformat;               /* RTC_HourFormat      */
+  uint32_t asynchprediv;             /* RTC_AsynchPrediv    */
+  uint32_t synchprediv;              /* RTC_SynchPrediv     */
+  uint32_t daythreshold;             /* RTC_DayThreshold    */
+};
+
+/* RTC_TimeTypeDef: year + day-of-year, not month/day. */
+
+struct ameba_rtc_time_s
+{
+  uint16_t year;                     /* 1900..2155          */
+  uint16_t days;                     /* day-of-year, 0..511 */
+  uint8_t  hours;                    /* 0..23 (24h format)  */
+  uint8_t  minutes;                  /* 0..59               */
+  uint8_t  seconds;                  /* 0..59               */
+  uint8_t  h12_pmam;                 /* RTC_H12_AM/PM       */
+};
+
+/* RTC_AlarmTypeDef */
+
+struct ameba_rtc_alarm_s
+{
+  struct ameba_rtc_time_s time;      /* Alarm match time    */
+  uint32_t mask;                     /* RTC_AlarmMask  (HMS) */
+  uint32_t mask2;                    /* RTC_Alarm2Mask (Day) */
+};
+
+/* This is the private RTC lower-half state.  It must be cast-compatible with
+ * struct rtc_lowerhalf_s (the ops pointer is first).
+ */
+
+struct ameba_rtc_lowerhalf_s
+{
+  const struct rtc_ops_s *ops;       /* Lower-half operations vtable */
+
+  mutex_t devlock;                   /* Exclusive access to the alarm */
+
+#ifdef CONFIG_RTC_ALARM
+  volatile rtc_alarm_callback_t cb;  /* Callback when the alarm expires */
+  volatile void *priv;               /* Argument to accompany the callback */
+  bool irqattached;                  /* RTC IRQ has been attached */
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* SDK fwlib RTC / clock API (linked from fwlib RAM ameba_rtc.c).  None of
+ * the RTC calls take a register base -- the fwlib picks the secure/non-
+ * secure alias internally.
+ */
+
+extern void RCC_PeriphClockCmd(uint32_t periph, uint32_t clock,
+                               uint8_t newstate);
+extern void RTC_StructInit(struct ameba_rtc_init_s *init);
+extern uint32_t RTC_Init(struct ameba_rtc_init_s *init);
+extern uint32_t RTC_SetTime(uint32_t format,
+                            struct ameba_rtc_time_s *time);
+extern void RTC_GetTime(uint32_t format, struct ameba_rtc_time_s *time);
+extern uint32_t RTC_SetAlarm(uint32_t format,
+                             struct ameba_rtc_alarm_s *alarm);
+extern void RTC_GetAlarm(uint32_t format, struct ameba_rtc_alarm_s *alarm);
+extern void RTC_AlarmStructInit(struct ameba_rtc_alarm_s *alarm);
+extern void RTC_AlarmCmd(uint32_t newstate);
+extern void RTC_AlarmClear(void);
+
+/* Internal helpers. */
+
+static void ameba_time_to_hw(const struct rtc_time *rtctime,
+                             struct ameba_rtc_time_s *hw);
+
+/* RTC lower-half operations. */
+
+static int  ameba_rdtime(struct rtc_lowerhalf_s *lower,
+                         struct rtc_time *rtctime);
+static int  ameba_settime(struct rtc_lowerhalf_s *lower,
+                          const struct rtc_time *rtctime);
+static bool ameba_havesettime(struct rtc_lowerhalf_s *lower);
+
+#ifdef CONFIG_RTC_ALARM
+static int  ameba_setalarm(struct rtc_lowerhalf_s *lower,
+                           const struct lower_setalarm_s *alarminfo);
+static int  ameba_setrelative(struct rtc_lowerhalf_s *lower,
+                              const struct lower_setrelative_s *alarminfo);
+static int  ameba_cancelalarm(struct rtc_lowerhalf_s *lower, int alarmid);
+static int  ameba_rdalarm(struct rtc_lowerhalf_s *lower,
+                          struct lower_rdalarm_s *alarminfo);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct rtc_ops_s g_rtc_ops =
+{
+  .rdtime      = ameba_rdtime,
+  .settime     = ameba_settime,
+  .havesettime = ameba_havesettime,
+#ifdef CONFIG_RTC_ALARM
+  .setalarm    = ameba_setalarm,
+  .setrelative = ameba_setrelative,
+  .cancelalarm = ameba_cancelalarm,
+  .rdalarm     = ameba_rdalarm,
+#endif
+};
+
+static struct ameba_rtc_lowerhalf_s g_rtc_lowerhalf =
+{
+  .ops     = &g_rtc_ops,
+  .devlock = NXMUTEX_INITIALIZER,
+};
+
+/* Set true once the clock/RTC has been brought up (from either the early
+ * arch up_rtc_initialize() or the later ameba_rtc_lowerhalf()), and true by
+ * settime() so havesettime() can report it.
+ */
+
+static bool g_rtc_started;
+static bool g_rtc_timeset;
+
+/* Consumed by the NuttX clock layer: set once the RTC is running so system
+ * time updates are written through to the RTC (see sched/clock).
+ */
+
+volatile bool g_rtc_enabled = false;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ameba_rtc_hwstart
+ *
+ * Description:
+ *   Gate the RTC clock and initialise the fwlib RTC (24-hour format) exactly
+ *   once.  Called from both the early arch up_rtc_initialize() and the later
+ *   ameba_rtc_lowerhalf(); whichever runs first does the work.
+ *
+ ****************************************************************************/
+
+static void ameba_rtc_hwstart(void)
+{
+  struct ameba_rtc_init_s init;
+  struct ameba_rtc_time_s hw;
+
+  if (g_rtc_started)
+    {
+      return;
+    }
+
+  RCC_PeriphClockCmd(AMEBA_RTC_APBPERIPH, AMEBA_RTC_APBPERIPH_CLK,
+                     AMEBA_ENABLE);
+
+  RTC_StructInit(&init);
+  init.hourformat = AMEBA_RTC_HOURFMT_24;
+  RTC_Init(&init);
+
+  /* On a cold start the RTC year sits at its power-on default (near the
+   * calendar base year, 1900), which predates the POSIX epoch and cannot be
+   * represented as a time_t -- reads would return a garbage negative time.
+   * Seed it with the configured build date so the clock is sane before any
+   * application sets the time.  A warm RTC that already holds a later year
+   * (kept running across a reset) is left untouched.
+   */
+
+  RTC_GetTime(AMEBA_RTC_FORMAT_BIN, &hw);
+  if (hw.year < CONFIG_START_YEAR)
+    {
+      struct rtc_time rtctime;
+
+      memset(&rtctime, 0, sizeof(rtctime));
+      rtctime.tm_year = CONFIG_START_YEAR - AMEBA_RTC_BASE_YEAR;
+      rtctime.tm_mon  = CONFIG_START_MONTH - 1;
+      rtctime.tm_mday = CONFIG_START_DAY;
+
+      ameba_time_to_hw(&rtctime, &hw);
+      RTC_SetTime(AMEBA_RTC_FORMAT_BIN, &hw);
+    }
+
+  g_rtc_started = true;
+}
+
+/****************************************************************************
+ * Name: ameba_time_to_hw
+ *
+ * Description:
+ *   Convert a struct rtc_time (month + day-of-month, tm-compatible) into the
+ *   fwlib year + day-of-year form.  The incoming time is normalised
+ *   through timegm()/gmtime_r() (UTC, no timezone) so tm_yday is exact.
+ *
+ ****************************************************************************/
+
+static void ameba_time_to_hw(const struct rtc_time *rtctime,
+                             struct ameba_rtc_time_s *hw)
+{
+  struct tm tmp;
+  time_t secs;
+
+  /* struct rtc_time is cast-compatible with struct tm. */
+
+  memcpy(&tmp, rtctime, sizeof(struct tm));
+  tmp.tm_isdst = 0;
+
+  /* Normalise and recover the day-of-year. */
+
+  secs = timegm(&tmp);
+  gmtime_r(&secs, &tmp);
+
+  hw->year     = (uint16_t)(tmp.tm_year + AMEBA_RTC_BASE_YEAR);
+  hw->days     = (uint16_t)tmp.tm_yday;
+  hw->hours    = (uint8_t)tmp.tm_hour;
+  hw->minutes  = (uint8_t)tmp.tm_min;
+  hw->seconds  = (uint8_t)tmp.tm_sec;
+  hw->h12_pmam = AMEBA_RTC_H12_AM;
+}
+
+/****************************************************************************
+ * Name: ameba_hw_to_time
+ *
+ * Description:
+ *   Convert the fwlib year + day-of-year representation back into a struct
+ *   rtc_time.  The day-of-year is placed as "day (days + 1) of month 0" and
+ *   timegm()/gmtime_r() carry it into the correct month, day and (on a
+ *   day-of-year overflow) year.
+ *
+ ****************************************************************************/
+
+static void ameba_hw_to_time(const struct ameba_rtc_time_s *hw,
+                             struct rtc_time *rtctime)
+{
+  struct tm tmp;
+  time_t secs;
+
+  memset(&tmp, 0, sizeof(tmp));
+  tmp.tm_year  = (int)hw->year - AMEBA_RTC_BASE_YEAR;
+  tmp.tm_mon   = 0;
+  tmp.tm_mday  = (int)hw->days + 1;
+  tmp.tm_hour  = hw->hours;
+  tmp.tm_min   = hw->minutes;
+  tmp.tm_sec   = hw->seconds;
+  tmp.tm_isdst = 0;
+
+  secs = timegm(&tmp);
+  gmtime_r(&secs, (struct tm *)rtctime);
+}
+
+/****************************************************************************
+ * Name: ameba_rtc_interrupt
+ *
+ * Description:
+ *   RTC interrupt handler.  Clears the alarm flag, disables the (one-shot)
+ *   alarm and invokes the upper-half callback recorded at setalarm() time.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_ALARM
+static int ameba_rtc_interrupt(int irq, void *context, void *arg)
+{
+  struct ameba_rtc_lowerhalf_s *priv =
+    (struct ameba_rtc_lowerhalf_s *)arg;
+  rtc_alarm_callback_t cb;
+  void *cbarg;
+
+  /* Acknowledge and disable the alarm (this driver's alarm is one-shot). */
+
+  RTC_AlarmClear();
+  RTC_AlarmCmd(AMEBA_DISABLE);
+
+  /* Sample and clear the callback so a re-arm from within it is clean. */
+
+  cb    = (rtc_alarm_callback_t)priv->cb;
+  cbarg = (void *)priv->priv;
+
+  priv->cb   = NULL;
+  priv->priv = NULL;
+
+  if (cb != NULL)
+    {
+      cb(cbarg, 0);
+    }
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: ameba_rdtime
+ *
+ * Description:
+ *   Implement the rdtime() method: return the current RTC date/time.
+ *
+ ****************************************************************************/
+
+static int ameba_rdtime(struct rtc_lowerhalf_s *lower,
+                         struct rtc_time *rtctime)
+{
+  struct ameba_rtc_time_s hw;
+
+  RTC_GetTime(AMEBA_RTC_FORMAT_BIN, &hw);
+  ameba_hw_to_time(&hw, rtctime);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ameba_settime
+ *
+ * Description:
+ *   Implement the settime() method: set the RTC date/time.
+ *
+ ****************************************************************************/
+
+static int ameba_settime(struct rtc_lowerhalf_s *lower,
+                          const struct rtc_time *rtctime)
+{
+  struct ameba_rtc_time_s hw;
+
+  ameba_time_to_hw(rtctime, &hw);
+
+  if (RTC_SetTime(AMEBA_RTC_FORMAT_BIN, &hw) != AMEBA_ENABLE)
+    {
+      return -EIO;
+    }
+
+  g_rtc_timeset = true;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ameba_havesettime
+ *
+ * Description:
+ *   Implement the havesettime() method: has the RTC time ever been set?
+ *
+ ****************************************************************************/
+
+static bool ameba_havesettime(struct rtc_lowerhalf_s *lower)
+{
+  return g_rtc_timeset;
+}
+
+/****************************************************************************
+ * Name: ameba_setalarm
+ *
+ * Description:
+ *   Implement the setalarm() method: program a one-shot alarm at an absolute
+ *   time and arm the RTC interrupt.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_ALARM
+static int ameba_setalarm(struct rtc_lowerhalf_s *lower,
+                          const struct lower_setalarm_s *alarminfo)
+{
+  struct ameba_rtc_lowerhalf_s *priv =
+    (struct ameba_rtc_lowerhalf_s *)lower;
+  struct ameba_rtc_alarm_s alarm;
+  struct ameba_rtc_time_s hw;
+  int ret;
+
+  DEBUGASSERT(priv != NULL && alarminfo != NULL);
+
+  /* This RTC has a single alarm. */
+
+  if (alarminfo->id != 0)
+    {
+      return -EINVAL;
+    }
+
+  ret = nxmutex_lock(&priv->devlock);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Attach the RTC interrupt on first use. */
+
+  if (!priv->irqattached)
+    {
+      ret = irq_attach(AMEBA_RTC_IRQ, ameba_rtc_interrupt, priv);
+      if (ret < 0)
+        {
+          nxmutex_unlock(&priv->devlock);
+          return ret;
+        }
+
+      up_enable_irq(AMEBA_RTC_IRQ);
+      priv->irqattached = true;
+    }
+
+  /* Remember the callback, then program the alarm.  The alarm hardware
+   * matches day-of-year + h:m:s, so nothing is masked out.
+   */
+
+  priv->cb   = alarminfo->cb;
+  priv->priv = alarminfo->priv;
+
+  ameba_time_to_hw(&alarminfo->time, &hw);
+
+  RTC_AlarmStructInit(&alarm);
+  alarm.time  = hw;
+  alarm.time.h12_pmam = AMEBA_RTC_H12_AM;
+  alarm.mask  = AMEBA_RTC_ALARMMASK_NONE;
+  alarm.mask2 = AMEBA_RTC_ALARM2MASK_NONE;
+
+  if (RTC_SetAlarm(AMEBA_RTC_FORMAT_BIN, &alarm) != AMEBA_ENABLE)
+    {
+      priv->cb   = NULL;
+      priv->priv = NULL;
+      nxmutex_unlock(&priv->devlock);
+      return -EIO;
+    }
+
+  RTC_AlarmCmd(AMEBA_ENABLE);
+
+  nxmutex_unlock(&priv->devlock);
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: ameba_setrelative
+ *
+ * Description:
+ *   Implement the setrelative() method: program a one-shot alarm relative to
+ *   the current time by folding it onto setalarm().
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_ALARM
+static int ameba_setrelative(struct rtc_lowerhalf_s *lower,
+                             const struct lower_setrelative_s *alarminfo)
+{
+  struct lower_setalarm_s setalarm;
+  struct ameba_rtc_time_s hw;
+  struct tm tmp;
+  time_t secs;
+
+  DEBUGASSERT(alarminfo != NULL);
+
+  if (alarminfo->id != 0 || alarminfo->reltime == 0)
+    {
+      return -EINVAL;
+    }
+
+  /* Current time + reltime, via the calendar routines. */
+
+  RTC_GetTime(AMEBA_RTC_FORMAT_BIN, &hw);
+  ameba_hw_to_time(&hw, (struct rtc_time *)&tmp);
+  secs = timegm(&tmp) + (time_t)alarminfo->reltime;
+  gmtime_r(&secs, (struct tm *)&setalarm.time);
+
+  setalarm.id   = alarminfo->id;
+  setalarm.cb   = alarminfo->cb;
+  setalarm.priv = alarminfo->priv;
+
+  return ameba_setalarm(lower, &setalarm);
+}
+#endif
+
+/****************************************************************************
+ * Name: ameba_cancelalarm
+ *
+ * Description:
+ *   Implement the cancelalarm() method: disable the alarm and forget the
+ *   callback.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_ALARM
+static int ameba_cancelalarm(struct rtc_lowerhalf_s *lower, int alarmid)
+{
+  struct ameba_rtc_lowerhalf_s *priv =
+    (struct ameba_rtc_lowerhalf_s *)lower;
+  int ret;
+
+  if (alarmid != 0)
+    {
+      return -EINVAL;
+    }
+
+  ret = nxmutex_lock(&priv->devlock);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  RTC_AlarmCmd(AMEBA_DISABLE);
+  RTC_AlarmClear();
+
+  priv->cb   = NULL;
+  priv->priv = NULL;
+
+  nxmutex_unlock(&priv->devlock);
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: ameba_rdalarm
+ *
+ * Description:
+ *   Implement the rdalarm() method: return the programmed alarm time.  The
+ *   hardware alarm stores only day-of-year + h:m:s, so the year is borrowed
+ *   from the current RTC time to build a full calendar time.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_ALARM
+static int ameba_rdalarm(struct rtc_lowerhalf_s *lower,
+                         struct lower_rdalarm_s *alarminfo)
+{
+  struct ameba_rtc_alarm_s alarm;
+  struct ameba_rtc_time_s now;
+
+  DEBUGASSERT(alarminfo != NULL && alarminfo->time != NULL);
+
+  if (alarminfo->id != 0)
+    {
+      return -EINVAL;
+    }
+
+  RTC_GetAlarm(AMEBA_RTC_FORMAT_BIN, &alarm);
+
+  /* The alarm carries no year; borrow it from the current RTC time. */
+
+  RTC_GetTime(AMEBA_RTC_FORMAT_BIN, &now);
+  alarm.time.year = now.year;
+
+  ameba_hw_to_time(&alarm.time, alarminfo->time);
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ameba_rtc_lowerhalf
+ ****************************************************************************/
+
+struct rtc_lowerhalf_s *ameba_rtc_lowerhalf(void)
+{
+  /* Bring the RTC up exactly once (arch up_rtc_initialize() may have done it
+   * already during the early clock init).
+   */
+
+  ameba_rtc_hwstart();
+
+  return (struct rtc_lowerhalf_s *)&g_rtc_lowerhalf;
+}
+
+/****************************************************************************
+ * Name: up_rtc_initialize
+ *
+ * Description:
+ *   Arch RTC hook: bring the RTC up during the early clock initialisation so
+ *   the NuttX system time can be seeded from it.  The /dev/rtc0 lower half
+ *   is layered on top of this same hardware.
+ *
+ ****************************************************************************/
+
+int up_rtc_initialize(void)
+{
+  ameba_rtc_hwstart();
+  g_rtc_enabled = true;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: up_rtc_getdatetime
+ *
+ * Description:
+ *   Arch RTC hook (date/time RTC): return the current RTC time as a broken-
+ *   out struct tm.  Used by the clock layer to seed the system time.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_DATETIME
+int up_rtc_getdatetime(struct tm *tp)
+{
+  struct ameba_rtc_time_s hw;
+
+  RTC_GetTime(AMEBA_RTC_FORMAT_BIN, &hw);
+  ameba_hw_to_time(&hw, (struct rtc_time *)tp);
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: up_rtc_settime
+ *
+ * Description:
+ *   Arch RTC hook: set the RTC from a timespec (one-second resolution).
+ *
+ ****************************************************************************/
+
+int up_rtc_settime(const struct timespec *tp)
+{
+  struct ameba_rtc_time_s hw;
+  struct tm tmp;
+  time_t secs = tp->tv_sec;
+
+  gmtime_r(&secs, &tmp);
+  ameba_time_to_hw((struct rtc_time *)&tmp, &hw);
+
+  if (RTC_SetTime(AMEBA_RTC_FORMAT_BIN, &hw) != AMEBA_ENABLE)
+    {
+      return -EIO;
+    }
+
+  g_rtc_timeset = true;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ameba_rtc_initialize
+ ****************************************************************************/
+
+int ameba_rtc_initialize(void)
+{
+  struct rtc_lowerhalf_s *lower;
+
+  lower = ameba_rtc_lowerhalf();
+  if (lower == NULL)
+    {
+      return -ENODEV;
+    }
+
+  return rtc_initialize(0, lower);
+}
+
+#endif /* CONFIG_RTC_DRIVER */
diff --git a/arch/arm/src/common/ameba/ameba_rtc.h 
b/arch/arm/src/common/ameba/ameba_rtc.h
new file mode 100644
index 00000000000..4ed9c790cc6
--- /dev/null
+++ b/arch/arm/src/common/ameba/ameba_rtc.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+ * arch/arm/src/common/ameba/ameba_rtc.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_RTC_H
+#define __ARCH_ARM_SRC_COMMON_AMEBA_AMEBA_RTC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+struct rtc_lowerhalf_s;
+
+/****************************************************************************
+ * Name: ameba_rtc_lowerhalf
+ *
+ * Description:
+ *   Instantiate the Ameba RTC lower-half driver.  General usage:
+ *
+ *     #include <nuttx/timers/rtc.h>
+ *     #include "ameba_rtc.h"
+ *
+ *     struct rtc_lowerhalf_s *lower = ameba_rtc_lowerhalf();
+ *     rtc_initialize(0, lower);
+ *
+ *   The first call also gates the RTC clock and initialises the fwlib RTC
+ *   (24-hour format).  The returned interface is a singleton; the board
+ *   normally hands it straight to rtc_initialize() to create /dev/rtc0.
+ *
+ * Returned Value:
+ *   On success a non-NULL RTC lower-half interface is returned.  NULL is
+ *   returned on any failure.
+ *
+ ****************************************************************************/
+
+struct rtc_lowerhalf_s *ameba_rtc_lowerhalf(void);
+
+/****************************************************************************
+ * Name: ameba_rtc_initialize
+ *
+ * Description:
+ *   Convenience wrapper that instantiates the Ameba RTC lower half and binds
+ *   it to the NuttX RTC character driver at "/dev/rtc0" (minor 0).
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int ameba_rtc_initialize(void);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ARCH_ARM_SRC_COMMON_AMEBA_AMEBA_RTC_H */
diff --git a/arch/arm/src/rtl8721dx/CMakeLists.txt 
b/arch/arm/src/rtl8721dx/CMakeLists.txt
index 71b7f7203a9..0fadd6e5190 100644
--- a/arch/arm/src/rtl8721dx/CMakeLists.txt
+++ b/arch/arm/src/rtl8721dx/CMakeLists.txt
@@ -64,6 +64,10 @@ if(CONFIG_AMEBA_ADC)
   list(APPEND SRCS ${AMEBA_COMMON}/ameba_adc.c)
 endif()
 
+if(CONFIG_AMEBA_RTC)
+  list(APPEND SRCS ${AMEBA_COMMON}/ameba_rtc.c)
+endif()
+
 target_include_directories(arch PRIVATE ${AMEBA_COMMON})
 target_sources(arch PRIVATE ${SRCS})
 
@@ -120,6 +124,13 @@ if(CONFIG_AMEBA_GPIO)
   list(APPEND AMEBA_FWLIB_SRCS ${AMEBA_SOC}/fwlib/ram_common/ameba_gpio.c)
 endif()
 
+# RTC register layer.  The RTC driver (arch/.../common/ameba/ameba_rtc.c) calls
+# the fwlib RTC API; the data tables and helpers it indexes live in this RAM
+# source and must be compiled in (mirrors the make build's ameba_board.mk).
+if(CONFIG_AMEBA_RTC)
+  list(APPEND AMEBA_FWLIB_SRCS ${AMEBA_SOC}/fwlib/ram_common/ameba_rtc.c)
+endif()
+
 # Silence a couple of warnings the vendored SDK sources trip under NuttX's
 # warning set, scoped to this fwlib compile only (never relaxing NuttX's own):
 # -Wno-int-conversion: the SDK passes NULL to irq_register()'s u32 "Data"
diff --git a/arch/arm/src/rtl8721dx/Make.defs b/arch/arm/src/rtl8721dx/Make.defs
index 60ebeface1d..113622164d8 100644
--- a/arch/arm/src/rtl8721dx/Make.defs
+++ b/arch/arm/src/rtl8721dx/Make.defs
@@ -74,6 +74,10 @@ ifeq ($(CONFIG_AMEBA_ADC),y)
 CHIP_CSRCS += ameba_adc.c
 endif
 
+ifeq ($(CONFIG_AMEBA_RTC),y)
+CHIP_CSRCS += ameba_rtc.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 bd665af7bf5..204699ed8d7 100644
--- a/arch/arm/src/rtl8721dx/ameba_board.mk
+++ b/arch/arm/src/rtl8721dx/ameba_board.mk
@@ -164,6 +164,15 @@ ifeq ($(CONFIG_AMEBA_PWM),y)
 AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_tim.c
 endif
 
+# RTC register layer.  The whole fwlib RTC API the RTC driver
+# (arch/.../common/ameba/ameba_rtc.c) calls -- RTC_Init/StructInit,
+# RTC_SetTime/GetTime and RTC_SetAlarm/GetAlarm/AlarmStructInit/AlarmCmd/
+# AlarmClear -- is compiled from this RAM source (the _LONG_CALL_ prototypes
+# resolve here, not to ROM) and must be linked in.
+ifeq ($(CONFIG_AMEBA_RTC),y)
+AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_rtc.c
+endif
+
 # -Wno-int-conversion: the vendored SDK passes NULL to irq_register()'s u32
 # "Data" (interrupt context) argument in many places -- an intentional
 # NULL-as-context idiom.  Silence -Wint-conversion for the SDK fwlib sources
diff --git a/arch/arm/src/rtl8721dx/ameba_rtc_chip.h 
b/arch/arm/src/rtl8721dx/ameba_rtc_chip.h
new file mode 100644
index 00000000000..8e3efd5fcaa
--- /dev/null
+++ b/arch/arm/src/rtl8721dx/ameba_rtc_chip.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+ * arch/arm/src/rtl8721dx/ameba_rtc_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_RTC_CHIP_H
+#define __ARCH_ARM_SRC_RTL8721DX_AMEBA_RTC_CHIP_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/irq.h>
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Per-chip RTC wiring for RTL8721DX (amebadplus).  The shared driver
+ * (arch/arm/src/common/ameba/ameba_rtc.c) includes this header to learn the
+ * RTC interrupt line, the peripheral-clock masks and the calendar base year.
+ * 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 it drives the RTC through the SDK fwlib API, which takes
+ * no register base (it selects the secure/non-secure alias internally), so
+ * no register address appears here at all.
+ *
+ * The RTC register model, structures and constants (year + day-of-year time,
+ * RTC_Format_BIN, the alarm mask values, RTC_BASE_YEAR = 1900) are identical
+ * on every current Ameba chip (verified against amebadplus/amebalite/
+ * amebasmart/amebagreen2/RTL8720F fwlib ameba_rtc.h), so they live in the
+ * shared driver.  The one thing that genuinely differs per chip is the RTC
+ * interrupt vector, so only that is abstracted here:
+ *
+ *   chip         RTC_IRQ vector (SDK ameba_vector_table.h)
+ *   -----------  -----------------------------------------
+ *   amebadplus   46   (this header: RTL8721DX_IRQ_RTC)
+ *   amebalite    53
+ *   amebasmart   12
+ *   amebagreen2  41
+ *   RTL8720F     33
+ *
+ * A new chip only edits this header: AMEBA_RTC_IRQ carries the NuttX IRQ
+ * number of its RTC line -- see the ADC/PWM chip headers for the same
+ * data-driven, never-computed pattern.
+ */
+
+#define AMEBA_RTC_IRQ             RTL8721DX_IRQ_RTC
+
+/* APBPeriph_RTC (function) and APBPeriph_RTC_CLOCK masks, from the SDK
+ * sysreg_aon.h: bit group selector (3 << 30) plus the RTC enable bit
+ * (1 << 3).  Both are equal on this chip.  The driver gates the RTC clock
+ * with these before the first fwlib call.
+ */
+
+#define AMEBA_RTC_APBPERIPH       (((uint32_t)3 << 30) | ((uint32_t)1 << 3))
+#define AMEBA_RTC_APBPERIPH_CLK   (((uint32_t)3 << 30) | ((uint32_t)1 << 3))
+
+/* Calendar base year the fwlib RTC uses for RTC_TimeTypeDef.RTC_Year
+ * (RTC_BASE_YEAR); the hardware stores year + day-of-year, not month/day.
+ */
+
+#define AMEBA_RTC_BASE_YEAR       1900
+
+#endif /* __ARCH_ARM_SRC_RTL8721DX_AMEBA_RTC_CHIP_H */
diff --git a/boards/arm/rtl8721dx/pke8721daf/configs/rtc/defconfig 
b/boards/arm/rtl8721dx/pke8721daf/configs/rtc/defconfig
new file mode 100644
index 00000000000..7564fd8f1ce
--- /dev/null
+++ b/boards/arm/rtl8721dx/pke8721daf/configs/rtc/defconfig
@@ -0,0 +1,51 @@
+#
+# 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_RTC=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_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_ALARM=y
+CONFIG_EXAMPLES_HELLO=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_RTC_ALARM=y
+CONFIG_RTL8721DX_FLASH_FS=y
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_HPWORKPRIORITY=192
+CONFIG_SCHED_LPWORK=y
+CONFIG_STACK_COLORATION=y
+CONFIG_START_DAY=16
+CONFIG_START_MONTH=6
+CONFIG_START_YEAR=2026
+CONFIG_SYSTEM_NSH=y
+CONFIG_SYSTEM_NSH_STACKSIZE=2500
+CONFIG_TIMER=y
+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 44926ad4edb..e47cd695f39 100644
--- a/boards/arm/rtl8721dx/pke8721daf/src/CMakeLists.txt
+++ b/boards/arm/rtl8721dx/pke8721daf/src/CMakeLists.txt
@@ -46,6 +46,10 @@ if(CONFIG_AMEBA_ADC)
   list(APPEND SRCS rtl8721dx_adc.c)
 endif()
 
+if(CONFIG_AMEBA_RTC)
+  list(APPEND SRCS rtl8721dx_rtc.c)
+endif()
+
 target_sources(board PRIVATE ${SRCS})
 
 if(CONFIG_AMEBA_GPIO
@@ -53,7 +57,8 @@ if(CONFIG_AMEBA_GPIO
    OR CONFIG_AMEBA_I2C
    OR CONFIG_AMEBA_SPI
    OR CONFIG_AMEBA_PWM
-   OR CONFIG_AMEBA_ADC)
+   OR CONFIG_AMEBA_ADC
+   OR CONFIG_AMEBA_RTC)
   # 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 c841ac4da3d..c857ec97da6 100644
--- a/boards/arm/rtl8721dx/pke8721daf/src/Makefile
+++ b/boards/arm/rtl8721dx/pke8721daf/src/Makefile
@@ -78,4 +78,13 @@ CSRCS += rtl8721dx_adc.c
 CFLAGS += 
${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)arm$(DELIM)src$(DELIM)common$(DELIM)ameba
 endif
 
+ifeq ($(CONFIG_AMEBA_RTC),y)
+CSRCS += rtl8721dx_rtc.c
+
+# The board RTC 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 69a45c44ccc..85d69f261ed 100644
--- a/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_bringup.c
+++ b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_bringup.c
@@ -168,6 +168,16 @@ int rtl8721dx_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_AMEBA_RTC
+  /* Register the board's RTC at /dev/rtc0. */
+
+  ret = rtl8721dx_rtc_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: rtl8721dx_rtc_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 f185ef3ab9a..174499a2d26 100644
--- a/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_pke8721daf.h
+++ b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_pke8721daf.h
@@ -147,6 +147,19 @@ int rtl8721dx_pwm_initialize(void);
 int rtl8721dx_adc_initialize(void);
 #endif
 
+#ifdef CONFIG_AMEBA_RTC
+/****************************************************************************
+ * Name: rtl8721dx_rtc_initialize
+ *
+ * Description:
+ *   Register the board's RTC at /dev/rtc0
+ *   (boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_rtc.c).
+ *
+ ****************************************************************************/
+
+int rtl8721dx_rtc_initialize(void);
+#endif
+
 #ifdef CONFIG_RTL8721DX_FLASH_FS
 /****************************************************************************
  * Name: ameba_flash_fs_initialize
diff --git a/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_rtc.c 
b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_rtc.c
new file mode 100644
index 00000000000..0276d3ae856
--- /dev/null
+++ b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_rtc.c
@@ -0,0 +1,66 @@
+/****************************************************************************
+ * boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_rtc.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_rtc.h"
+#include "rtl8721dx_pke8721daf.h"
+
+#ifdef CONFIG_AMEBA_RTC
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rtl8721dx_rtc_initialize
+ *
+ * Description:
+ *   Bring up the on-chip RTC and register it at /dev/rtc0.  The RTC has no
+ *   board wiring (it is an internal clock), so this simply defers to the
+ *   shared driver.
+ *
+ ****************************************************************************/
+
+int rtl8721dx_rtc_initialize(void)
+{
+  int ret;
+
+  ret = ameba_rtc_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR,
+             "ERROR: ameba_rtc_initialize(/dev/rtc0) failed: %d\n", ret);
+      return ret;
+    }
+
+  return OK;
+}
+
+#endif /* CONFIG_AMEBA_RTC */

Reply via email to