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

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

commit d3e856c56e2b17ab66dec6f145a3295c9acfcfcb
Author: Marco Casaroli <[email protected]>
AuthorDate: Fri Jul 31 15:49:42 2026 +0200

    arch/arm/rp23xx: Add RTC alarm support on the POWMAN always-on timer.
    
    The always-on timer has an alarm comparator, but the RTC driver did not
    use it: rp23xx_rtc.c implemented only up_rtc_initialize(),
    up_rtc_time() and up_rtc_settime().
    
    Add the alarm and an RTC lower half for /dev/rtc0:
    
    - rp23xx_rtc_setalarm(), rp23xx_rtc_cancelalarm() and
      rp23xx_rtc_rdalarm() on the ALARM_TIME registers and the POWMAN
      timer interrupt.
    - An RTC lower half with rdtime, settime, setalarm, setrelative,
      cancelalarm and rdalarm, registered by the common board bringup.
    
    The comparator asserts while the time is past the alarm time, not on
    a transition.  So the interrupt handler disables the alarm before it
    does anything else; clearing only the status makes the interrupt
    repeat.  The arming sequence is the one of
    powman_timer_enable_alarm_at_ms() in the Pico SDK.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 arch/arm/src/rp23xx/CMakeLists.txt                 |   3 +
 arch/arm/src/rp23xx/Kconfig                        |   3 +
 arch/arm/src/rp23xx/Make.defs                      |   3 +
 arch/arm/src/rp23xx/rp23xx_rtc.c                   | 181 +++++++++
 arch/arm/src/rp23xx/rp23xx_rtc.h                   | 170 ++++++++
 arch/arm/src/rp23xx/rp23xx_rtc_lowerhalf.c         | 432 +++++++++++++++++++++
 .../arm/rp23xx/common/src/rp23xx_common_bringup.c  |  26 ++
 7 files changed, 818 insertions(+)

diff --git a/arch/arm/src/rp23xx/CMakeLists.txt 
b/arch/arm/src/rp23xx/CMakeLists.txt
index 84c46b22374..4fd9afd4055 100644
--- a/arch/arm/src/rp23xx/CMakeLists.txt
+++ b/arch/arm/src/rp23xx/CMakeLists.txt
@@ -110,6 +110,9 @@ endif()
 
 if(CONFIG_RP23XX_RTC)
   list(APPEND SRCS rp23xx_rtc.c)
+  if(CONFIG_RTC_DRIVER)
+    list(APPEND SRCS rp23xx_rtc_lowerhalf.c)
+  endif()
 endif()
 
 if(CONFIG_RP23XX_OTP)
diff --git a/arch/arm/src/rp23xx/Kconfig b/arch/arm/src/rp23xx/Kconfig
index 39c79b3d08d..7c3e4180c53 100644
--- a/arch/arm/src/rp23xx/Kconfig
+++ b/arch/arm/src/rp23xx/Kconfig
@@ -878,6 +878,9 @@ config RP23XX_RTC
                timer is a 64-bit millisecond counter clocked from the low-power
                oscillator, so it keeps running across warm resets.
 
+               The always-on timer also has one alarm comparator.  Select
+               RTC_ALARM to expose it through /dev/rtc0.
+
 config RP23XX_ADC
        bool "Enable ADC Support"
        default n
diff --git a/arch/arm/src/rp23xx/Make.defs b/arch/arm/src/rp23xx/Make.defs
index 1efbfeaabb3..a7371fd01ac 100644
--- a/arch/arm/src/rp23xx/Make.defs
+++ b/arch/arm/src/rp23xx/Make.defs
@@ -114,6 +114,9 @@ endif
 
 ifeq ($(CONFIG_RP23XX_RTC),y)
 CHIP_CSRCS += rp23xx_rtc.c
+ifeq ($(CONFIG_RTC_DRIVER),y)
+CHIP_CSRCS += rp23xx_rtc_lowerhalf.c
+endif
 endif
 
 ifeq ($(CONFIG_RP23XX_OTP),y)
diff --git a/arch/arm/src/rp23xx/rp23xx_rtc.c b/arch/arm/src/rp23xx/rp23xx_rtc.c
index be78ad3f64d..88c5d051992 100644
--- a/arch/arm/src/rp23xx/rp23xx_rtc.c
+++ b/arch/arm/src/rp23xx/rp23xx_rtc.c
@@ -49,6 +49,7 @@
 #include <nuttx/irq.h>
 
 #include "arm_internal.h"
+#include "rp23xx_rtc.h"
 #include "hardware/rp23xx_powman.h"
 
 #ifdef CONFIG_RTC
@@ -73,6 +74,18 @@
 
 #define LPOSC_FREQ_HZ     32768
 
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_ALARM
+
+/* The always-on timer has one alarm comparator */
+
+static struct rp23xx_alarm_state_s g_alarm;
+
+#endif
+
 /****************************************************************************
  * Public Data
  ****************************************************************************/
@@ -151,10 +164,169 @@ static void powman_set_ms(uint64_t ms)
     }
 }
 
+#ifdef CONFIG_RTC_ALARM
+
+/* Disarm the comparator, mask its interrupt and clear its status.  The
+ * comparator asserts while the time is past the alarm, so it must be
+ * disabled, not only acknowledged.
+ */
+
+static void powman_alarm_disable(void)
+{
+  powman_clrbits(RP23XX_POWMAN_INTE, RP23XX_POWMAN_INTE_TIMER);
+  powman_clrbits(RP23XX_POWMAN_TIMER, RP23XX_POWMAN_TIMER_ALARM_ENAB);
+  powman_clrbits(RP23XX_POWMAN_TIMER, RP23XX_POWMAN_TIMER_ALARM);
+}
+
+/* Program the comparator, disabled while the time is written, as
+ * powman_timer_enable_alarm_at_ms() in the Pico SDK does.
+ */
+
+static void powman_set_alarm_ms(uint64_t ms)
+{
+  powman_setbits(RP23XX_POWMAN_INTE, RP23XX_POWMAN_INTE_TIMER);
+  powman_clrbits(RP23XX_POWMAN_TIMER, RP23XX_POWMAN_TIMER_ALARM_ENAB);
+
+  powman_write(RP23XX_POWMAN_ALARM_TIME_15TO0,  (uint32_t)(ms));
+  powman_write(RP23XX_POWMAN_ALARM_TIME_31TO16, (uint32_t)(ms >> 16));
+  powman_write(RP23XX_POWMAN_ALARM_TIME_47TO32, (uint32_t)(ms >> 32));
+  powman_write(RP23XX_POWMAN_ALARM_TIME_63TO48, (uint32_t)(ms >> 48));
+
+  /* Drop any status latched from a previous alarm before re-enabling. */
+
+  powman_clrbits(RP23XX_POWMAN_TIMER, RP23XX_POWMAN_TIMER_ALARM);
+  powman_setbits(RP23XX_POWMAN_TIMER, RP23XX_POWMAN_TIMER_ALARM_ENAB);
+}
+
+/****************************************************************************
+ * Name: rp23xx_alarm_interrupt
+ *
+ * Description:
+ *   POWMAN timer interrupt handler.  Fires when the always-on timer reaches
+ *   the programmed alarm time.
+ *
+ ****************************************************************************/
+
+static int rp23xx_alarm_interrupt(int irq, FAR void *context, FAR void *arg)
+{
+  rp23xx_alarm_callback_t cb;
+  FAR void *cbarg;
+
+  /* Disarm first, so that the callback can arm a new alarm */
+
+  powman_alarm_disable();
+
+  cb    = g_alarm.cb;
+  cbarg = g_alarm.arg;
+
+  g_alarm.active = false;
+  g_alarm.cb     = NULL;
+  g_alarm.arg    = NULL;
+
+  if (cb != NULL)
+    {
+      cb(cbarg);
+    }
+
+  return OK;
+}
+
+#endif /* CONFIG_RTC_ALARM */
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: rp23xx_rtc_getms
+ *
+ * Description:
+ *   Read the POWMAN always-on timer, in milliseconds since the epoch.
+ *
+ ****************************************************************************/
+
+uint64_t rp23xx_rtc_getms(void)
+{
+  return powman_get_ms();
+}
+
+#ifdef CONFIG_RTC_ALARM
+
+/****************************************************************************
+ * Name: rp23xx_rtc_setalarm
+ *
+ * Description:
+ *   Arm the POWMAN alarm at an absolute time in milliseconds.
+ *
+ ****************************************************************************/
+
+int rp23xx_rtc_setalarm(uint64_t time, rp23xx_alarm_callback_t cb,
+                        FAR void *arg)
+{
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  if (time <= powman_get_ms())
+    {
+      leave_critical_section(flags);
+      return -EINVAL;
+    }
+
+  g_alarm.time   = time;
+  g_alarm.cb     = cb;
+  g_alarm.arg    = arg;
+  g_alarm.active = true;
+
+  powman_set_alarm_ms(time);
+
+  leave_critical_section(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: rp23xx_rtc_cancelalarm
+ ****************************************************************************/
+
+int rp23xx_rtc_cancelalarm(void)
+{
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  powman_alarm_disable();
+
+  g_alarm.active = false;
+  g_alarm.cb     = NULL;
+  g_alarm.arg    = NULL;
+
+  leave_critical_section(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: rp23xx_rtc_rdalarm
+ ****************************************************************************/
+
+int rp23xx_rtc_rdalarm(FAR uint64_t *time)
+{
+  irqstate_t flags;
+  int ret = -ENODATA;
+
+  flags = enter_critical_section();
+
+  if (g_alarm.active)
+    {
+      *time = g_alarm.time;
+      ret   = OK;
+    }
+
+  leave_critical_section(flags);
+  return ret;
+}
+
+#endif /* CONFIG_RTC_ALARM */
+
 /****************************************************************************
  * Name: up_rtc_initialize
  *
@@ -189,6 +361,15 @@ int up_rtc_initialize(void)
         }
     }
 
+#ifdef CONFIG_RTC_ALARM
+  /* The alarm stays disarmed until it is set */
+
+  powman_alarm_disable();
+
+  irq_attach(RP23XX_POWMAN_IRQ_TIMER, rp23xx_alarm_interrupt, NULL);
+  up_enable_irq(RP23XX_POWMAN_IRQ_TIMER);
+#endif
+
   g_rtc_enabled = true;
   return OK;
 }
diff --git a/arch/arm/src/rp23xx/rp23xx_rtc.h b/arch/arm/src/rp23xx/rp23xx_rtc.h
new file mode 100644
index 00000000000..3a94c8240ad
--- /dev/null
+++ b/arch/arm/src/rp23xx/rp23xx_rtc.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+ * arch/arm/src/rp23xx/rp23xx_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_RP23XX_RP23XX_RTC_H
+#define __ARCH_ARM_SRC_RP23XX_RP23XX_RTC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef CONFIG_RP23XX_RTC
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+#ifdef CONFIG_RTC_ALARM
+
+/* The always-on timer has one alarm comparator, so there is one alarm */
+
+enum rp23xx_alarm_id_e
+{
+  RP23XX_ALARM0 = 0,
+  RP23XX_ALARM_LAST
+};
+
+/* Callback invoked from the POWMAN timer interrupt when the alarm fires. */
+
+typedef CODE void (*rp23xx_alarm_callback_t)(FAR void *arg);
+
+/* State of the alarm */
+
+struct rp23xx_alarm_state_s
+{
+  uint64_t                 time;    /* Absolute alarm time, milliseconds */
+  rp23xx_alarm_callback_t  cb;      /* Callback, NULL when none */
+  FAR void                *arg;     /* Callback argument */
+  bool                     active;  /* True when the alarm was armed */
+};
+
+#endif /* CONFIG_RTC_ALARM */
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rp23xx_rtc_getms
+ *
+ * Description:
+ *   Read the POWMAN always-on timer, in milliseconds since the epoch.
+ *
+ ****************************************************************************/
+
+uint64_t rp23xx_rtc_getms(void);
+
+#ifdef CONFIG_RTC_ALARM
+
+/****************************************************************************
+ * Name: rp23xx_rtc_setalarm
+ *
+ * Description:
+ *   Arm the POWMAN alarm at an absolute time.  This replaces any alarm
+ *   already armed.
+ *
+ * Input Parameters:
+ *   time - Absolute alarm time in milliseconds since the epoch.
+ *   cb   - Called from the interrupt when the alarm fires, or NULL.
+ *   arg  - Argument passed back to the callback.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno on failure.  -EINVAL is returned when
+ *   the requested time is not in the future.
+ *
+ ****************************************************************************/
+
+int rp23xx_rtc_setalarm(uint64_t time, rp23xx_alarm_callback_t cb,
+                        FAR void *arg);
+
+/****************************************************************************
+ * Name: rp23xx_rtc_cancelalarm
+ *
+ * Description:
+ *   Disarm the POWMAN alarm.  Safe to call when no alarm is armed.
+ *
+ ****************************************************************************/
+
+int rp23xx_rtc_cancelalarm(void);
+
+/****************************************************************************
+ * Name: rp23xx_rtc_rdalarm
+ *
+ * Description:
+ *   Read back the absolute time of the armed alarm.
+ *
+ * Returned Value:
+ *   Zero on success, -ENODATA when no alarm is armed.
+ *
+ ****************************************************************************/
+
+int rp23xx_rtc_rdalarm(FAR uint64_t *time);
+
+#endif /* CONFIG_RTC_ALARM */
+
+/****************************************************************************
+ * Name: rp23xx_rtc_lowerhalf
+ *
+ * Description:
+ *   Instantiate the RTC lower half driver for the POWMAN always-on timer.
+ *   General usage:
+ *
+ *     #include <nuttx/timers/rtc.h>
+ *     #include "rp23xx_rtc.h"
+ *
+ *     struct rtc_lowerhalf_s *lower;
+ *     lower = rp23xx_rtc_lowerhalf();
+ *     rtc_initialize(0, lower);
+ *
+ * Returned Value:
+ *   On success, a non-NULL RTC lower interface is returned.  NULL is
+ *   returned on any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_DRIVER
+FAR struct rtc_lowerhalf_s *rp23xx_rtc_lowerhalf(void);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_RP23XX_RTC */
+#endif /* __ARCH_ARM_SRC_RP23XX_RP23XX_RTC_H */
diff --git a/arch/arm/src/rp23xx/rp23xx_rtc_lowerhalf.c 
b/arch/arm/src/rp23xx/rp23xx_rtc_lowerhalf.c
new file mode 100644
index 00000000000..29e2f329b36
--- /dev/null
+++ b/arch/arm/src/rp23xx/rp23xx_rtc_lowerhalf.c
@@ -0,0 +1,432 @@
+/****************************************************************************
+ * arch/arm/src/rp23xx/rp23xx_rtc_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 <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/mutex.h>
+#include <nuttx/timers/rtc.h>
+
+#include "rp23xx_rtc.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_ALARM
+
+/* Bridges the chip-level alarm callback, which carries only an opaque
+ * argument, to the RTC upper-half callback, which also wants an alarm id.
+ */
+
+struct rp23xx_cbinfo_s
+{
+  volatile rtc_alarm_callback_t cb;  /* Upper-half callback */
+  volatile FAR void *priv;           /* Upper-half argument */
+};
+#endif
+
+struct rp23xx_lowerhalf_s
+{
+  /* This is the contained reference to the read-only, lower-half operations
+   * vtable (which may lie in FLASH).
+   */
+
+  FAR const struct rtc_ops_s *ops;
+
+  /* Data following is private to this driver and not visible outside of
+   * this file.
+   */
+
+  mutex_t devlock;                   /* Threads accessing the device */
+
+#ifdef CONFIG_RTC_ALARM
+  struct rp23xx_cbinfo_s cbinfo;     /* Alarm callback information */
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int rp23xx_rdtime(FAR struct rtc_lowerhalf_s *lower,
+                         FAR struct rtc_time *rtctime);
+static int rp23xx_settime(FAR struct rtc_lowerhalf_s *lower,
+                          FAR const struct rtc_time *rtctime);
+static bool rp23xx_havesettime(FAR struct rtc_lowerhalf_s *lower);
+
+#ifdef CONFIG_RTC_ALARM
+static int rp23xx_setalarm(FAR struct rtc_lowerhalf_s *lower,
+                           FAR const struct lower_setalarm_s *alarminfo);
+static int rp23xx_setrelative(FAR struct rtc_lowerhalf_s *lower,
+                              FAR const struct lower_setrelative_s *info);
+static int rp23xx_cancelalarm(FAR struct rtc_lowerhalf_s *lower,
+                              int alarmid);
+static int rp23xx_rdalarm(FAR struct rtc_lowerhalf_s *lower,
+                          FAR struct lower_rdalarm_s *alarminfo);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* RP2350 RTC driver operations */
+
+static const struct rtc_ops_s g_rtc_ops =
+{
+  .rdtime      = rp23xx_rdtime,
+  .settime     = rp23xx_settime,
+  .havesettime = rp23xx_havesettime,
+#ifdef CONFIG_RTC_ALARM
+  .setalarm    = rp23xx_setalarm,
+  .setrelative = rp23xx_setrelative,
+  .cancelalarm = rp23xx_cancelalarm,
+  .rdalarm     = rp23xx_rdalarm,
+#endif
+};
+
+/* RP2350 RTC device state */
+
+static struct rp23xx_lowerhalf_s g_rtc_lowerhalf =
+{
+  .ops     = &g_rtc_ops,
+  .devlock = NXMUTEX_INITIALIZER,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_ALARM
+
+/****************************************************************************
+ * Name: rp23xx_alarm_callback
+ *
+ * Description:
+ *   Invoked from the POWMAN timer interrupt when the alarm expires.
+ *
+ ****************************************************************************/
+
+static void rp23xx_alarm_callback(FAR void *arg)
+{
+  FAR struct rp23xx_lowerhalf_s *priv = arg;
+  FAR struct rp23xx_cbinfo_s *cbinfo = &priv->cbinfo;
+  rtc_alarm_callback_t cb;
+  FAR void *cbarg;
+
+  /* Sample and clear the callback before invoking it, so that the callback
+   * is free to arm a new alarm.
+   */
+
+  cb    = (rtc_alarm_callback_t)cbinfo->cb;
+  cbarg = (FAR void *)cbinfo->priv;
+
+  cbinfo->cb   = NULL;
+  cbinfo->priv = NULL;
+
+  if (cb != NULL)
+    {
+      cb(cbarg, RP23XX_ALARM0);
+    }
+}
+#endif /* CONFIG_RTC_ALARM */
+
+/****************************************************************************
+ * Name: rp23xx_rdtime
+ *
+ * Description:
+ *   Implements the rdtime() method of the RTC driver interface.
+ *
+ ****************************************************************************/
+
+static int rp23xx_rdtime(FAR struct rtc_lowerhalf_s *lower,
+                         FAR struct rtc_time *rtctime)
+{
+  time_t secs;
+
+  secs = (time_t)(rp23xx_rtc_getms() / MSEC_PER_SEC);
+
+  if (gmtime_r(&secs, (FAR struct tm *)rtctime) == NULL)
+    {
+      return -EINVAL;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: rp23xx_settime
+ *
+ * Description:
+ *   Implements the settime() method of the RTC driver interface.
+ *
+ ****************************************************************************/
+
+static int rp23xx_settime(FAR struct rtc_lowerhalf_s *lower,
+                          FAR const struct rtc_time *rtctime)
+{
+  struct timespec ts;
+
+  /* timegm() normalises its argument, so convert a copy */
+
+  struct tm tm = *(FAR const struct tm *)rtctime;
+
+  ts.tv_sec  = timegm(&tm);
+  ts.tv_nsec = 0;
+
+  return up_rtc_settime(&ts);
+}
+
+/****************************************************************************
+ * Name: rp23xx_havesettime
+ *
+ * Description:
+ *   Implements the havesettime() method of the RTC driver interface.
+ *
+ ****************************************************************************/
+
+static bool rp23xx_havesettime(FAR struct rtc_lowerhalf_s *lower)
+{
+  /* POWMAN has no flag that the time was set; report the counter running */
+
+  return g_rtc_enabled;
+}
+
+#ifdef CONFIG_RTC_ALARM
+
+/****************************************************************************
+ * Name: rp23xx_setalarm
+ *
+ * Description:
+ *   Implements the setalarm() method of the RTC driver interface.
+ *
+ ****************************************************************************/
+
+static int rp23xx_setalarm(FAR struct rtc_lowerhalf_s *lower,
+                           FAR const struct lower_setalarm_s *alarminfo)
+{
+  FAR struct rp23xx_lowerhalf_s *priv;
+  FAR struct rp23xx_cbinfo_s *cbinfo;
+  struct tm tm;
+  uint64_t ms;
+  int ret;
+
+  DEBUGASSERT(lower != NULL && alarminfo != NULL);
+  priv = (FAR struct rp23xx_lowerhalf_s *)lower;
+
+  if (alarminfo->id != RP23XX_ALARM0)
+    {
+      return -EINVAL;
+    }
+
+  ret = nxmutex_lock(&priv->devlock);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  tm = *(FAR const struct tm *)&alarminfo->time;
+  ms = (uint64_t)timegm(&tm) * MSEC_PER_SEC;
+
+  /* Remember the callback information before arming: the alarm can in
+   * principle fire the moment it is enabled.
+   */
+
+  cbinfo       = &priv->cbinfo;
+  cbinfo->cb   = alarminfo->cb;
+  cbinfo->priv = alarminfo->priv;
+
+  ret = rp23xx_rtc_setalarm(ms, rp23xx_alarm_callback, priv);
+  if (ret < 0)
+    {
+      cbinfo->cb   = NULL;
+      cbinfo->priv = NULL;
+    }
+
+  nxmutex_unlock(&priv->devlock);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rp23xx_setrelative
+ *
+ * Description:
+ *   Implements the setrelative() method of the RTC driver interface.
+ *
+ ****************************************************************************/
+
+static int rp23xx_setrelative(FAR struct rtc_lowerhalf_s *lower,
+                              FAR const struct lower_setrelative_s *info)
+{
+  FAR struct rp23xx_lowerhalf_s *priv;
+  FAR struct rp23xx_cbinfo_s *cbinfo;
+  uint64_t ms;
+  int ret;
+
+  DEBUGASSERT(lower != NULL && info != NULL);
+  priv = (FAR struct rp23xx_lowerhalf_s *)lower;
+
+  if (info->id != RP23XX_ALARM0 || info->reltime <= 0)
+    {
+      return -EINVAL;
+    }
+
+  ret = nxmutex_lock(&priv->devlock);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Use the millisecond counter, not the system time in whole seconds */
+
+  ms = rp23xx_rtc_getms() + (uint64_t)info->reltime * MSEC_PER_SEC;
+
+  cbinfo       = &priv->cbinfo;
+  cbinfo->cb   = info->cb;
+  cbinfo->priv = info->priv;
+
+  ret = rp23xx_rtc_setalarm(ms, rp23xx_alarm_callback, priv);
+  if (ret < 0)
+    {
+      cbinfo->cb   = NULL;
+      cbinfo->priv = NULL;
+    }
+
+  nxmutex_unlock(&priv->devlock);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rp23xx_cancelalarm
+ *
+ * Description:
+ *   Implements the cancelalarm() method of the RTC driver interface.
+ *
+ ****************************************************************************/
+
+static int rp23xx_cancelalarm(FAR struct rtc_lowerhalf_s *lower,
+                              int alarmid)
+{
+  FAR struct rp23xx_lowerhalf_s *priv;
+  FAR struct rp23xx_cbinfo_s *cbinfo;
+  int ret;
+
+  DEBUGASSERT(lower != NULL);
+  priv = (FAR struct rp23xx_lowerhalf_s *)lower;
+
+  if (alarmid != RP23XX_ALARM0)
+    {
+      return -EINVAL;
+    }
+
+  ret = nxmutex_lock(&priv->devlock);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  cbinfo       = &priv->cbinfo;
+  cbinfo->cb   = NULL;
+  cbinfo->priv = NULL;
+
+  ret = rp23xx_rtc_cancelalarm();
+
+  nxmutex_unlock(&priv->devlock);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rp23xx_rdalarm
+ *
+ * Description:
+ *   Implements the rdalarm() method of the RTC driver interface.
+ *
+ ****************************************************************************/
+
+static int rp23xx_rdalarm(FAR struct rtc_lowerhalf_s *lower,
+                          FAR struct lower_rdalarm_s *alarminfo)
+{
+  uint64_t ms;
+  time_t secs;
+  int ret;
+
+  DEBUGASSERT(lower != NULL && alarminfo != NULL &&
+              alarminfo->time != NULL);
+
+  if (alarminfo->id != RP23XX_ALARM0)
+    {
+      return -EINVAL;
+    }
+
+  /* An alarm that is not armed is not an error: the upper half reports it
+   * as inactive.
+   */
+
+  ret = rp23xx_rtc_rdalarm(&ms);
+  if (ret == -ENODATA)
+    {
+      ms = 0;
+    }
+  else if (ret < 0)
+    {
+      return ret;
+    }
+
+  secs = (time_t)(ms / MSEC_PER_SEC);
+
+  if (gmtime_r(&secs, (FAR struct tm *)alarminfo->time) == NULL)
+    {
+      return -EINVAL;
+    }
+
+  return OK;
+}
+#endif /* CONFIG_RTC_ALARM */
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rp23xx_rtc_lowerhalf
+ *
+ * Description:
+ *   Instantiate the RTC lower half driver for the POWMAN always-on timer.
+ *
+ ****************************************************************************/
+
+FAR struct rtc_lowerhalf_s *rp23xx_rtc_lowerhalf(void)
+{
+  return (FAR struct rtc_lowerhalf_s *)&g_rtc_lowerhalf;
+}
diff --git a/boards/arm/rp23xx/common/src/rp23xx_common_bringup.c 
b/boards/arm/rp23xx/common/src/rp23xx_common_bringup.c
index 7d0d47506a5..634899a1095 100644
--- a/boards/arm/rp23xx/common/src/rp23xx_common_bringup.c
+++ b/boards/arm/rp23xx/common/src/rp23xx_common_bringup.c
@@ -58,6 +58,11 @@
 #  include "rp23xx_flash_mtd.h"
 #endif
 
+#if defined(CONFIG_RP23XX_RTC) && defined(CONFIG_RTC_DRIVER)
+#  include <nuttx/timers/rtc.h>
+#  include "rp23xx_rtc.h"
+#endif
+
 #ifdef CONFIG_RP23XX_OTP
 #  include "rp23xx_otp.h"
 #endif
@@ -462,6 +467,27 @@ int rp23xx_common_bringup(void)
     }
 #endif
 
+#if defined(CONFIG_RP23XX_RTC) && defined(CONFIG_RTC_DRIVER)
+  /* Register the always-on timer as /dev/rtc0 */
+
+  {
+    FAR struct rtc_lowerhalf_s *rtclower = rp23xx_rtc_lowerhalf();
+
+    if (rtclower == NULL)
+      {
+        syslog(LOG_ERR, "Failed to instantiate the RTC lower half\n");
+      }
+    else
+      {
+        ret = rtc_initialize(0, rtclower);
+        if (ret < 0)
+          {
+            syslog(LOG_ERR, "Failed to bind /dev/rtc0: %d\n", ret);
+          }
+      }
+  }
+#endif
+
 #ifdef CONFIG_RP23XX_I2S
   ret = board_i2sdev_initialize(0);
   if (ret < 0)

Reply via email to