You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/06/19 03:01:42 UTC

[incubator-nuttx] branch master updated: xtensa/esp32: Support ESP32 RTC driver

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

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


The following commit(s) were added to refs/heads/master by this push:
     new c3792f0  xtensa/esp32: Support ESP32 RTC driver
c3792f0 is described below

commit c3792f0aaeb067ccf64f793e94b3cb68fd175290
Author: chenwen <ch...@espressif.com>
AuthorDate: Thu Jun 17 19:14:33 2021 +0800

    xtensa/esp32: Support ESP32 RTC driver
---
 arch/xtensa/src/esp32/Kconfig                      |   1 +
 arch/xtensa/src/esp32/Make.defs                    |   4 +
 arch/xtensa/src/esp32/esp32_rtc.c                  | 593 ++++++++++++++++++++-
 arch/xtensa/src/esp32/esp32_rtc.h                  | 225 ++++++++
 arch/xtensa/src/esp32/esp32_rtc_lowerhalf.c        | 565 ++++++++++++++++++++
 arch/xtensa/src/esp32/esp32_rtc_lowerhalf.h        |  56 ++
 .../esp32/esp32-devkitc/configs/rtc/defconfig      |  53 ++
 .../xtensa/esp32/esp32-devkitc/src/esp32_bringup.c |  15 +
 .../esp32/esp32-ethernet-kit/configs/rtc/defconfig |  52 ++
 .../esp32/esp32-ethernet-kit/src/esp32_bringup.c   |  15 +
 .../esp32/esp32-wrover-kit/configs/rtc/defconfig   |  53 ++
 .../esp32/esp32-wrover-kit/src/esp32_bringup.c     |  15 +
 12 files changed, 1644 insertions(+), 3 deletions(-)

diff --git a/arch/xtensa/src/esp32/Kconfig b/arch/xtensa/src/esp32/Kconfig
index bdfa9a7..14dfb0f 100644
--- a/arch/xtensa/src/esp32/Kconfig
+++ b/arch/xtensa/src/esp32/Kconfig
@@ -214,6 +214,7 @@ endchoice # On-board Crystal Frequency
 config ESP32_RT_TIMER
 	bool "Real-time Timer"
 	default n
+	select ESP32_TIMER0
 
 config ESP32_PARTITION
 	bool "ESP32 Partition"
diff --git a/arch/xtensa/src/esp32/Make.defs b/arch/xtensa/src/esp32/Make.defs
index 964468a..113edd9 100644
--- a/arch/xtensa/src/esp32/Make.defs
+++ b/arch/xtensa/src/esp32/Make.defs
@@ -193,6 +193,10 @@ ifeq ($(CONFIG_ESP32_AES_ACCELERATOR),y)
 CHIP_CSRCS += esp32_aes.c
 endif
 
+ifeq ($(CONFIG_RTC_DRIVER),y)
+CHIP_CSRCS += esp32_rtc_lowerhalf.c
+endif
+
 ifeq ($(CONFIG_ESP32_WIRELESS),y)
 WIRELESS_DRV_UNPACK  = esp-wireless-drivers-3rdparty
 WIRELESS_DRV_ID      = 2b53111
diff --git a/arch/xtensa/src/esp32/esp32_rtc.c b/arch/xtensa/src/esp32/esp32_rtc.c
index 0c4be46..47cd168 100644
--- a/arch/xtensa/src/esp32/esp32_rtc.c
+++ b/arch/xtensa/src/esp32/esp32_rtc.c
@@ -24,13 +24,19 @@
 
 #include <stdint.h>
 #include <assert.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/spinlock.h>
 
 #include "esp32_rtc.h"
 #include "esp32_clockconfig.h"
+#include "esp32_rt_timer.h"
+
 #include "hardware/esp32_rtccntl.h"
 #include "hardware/esp32_dport.h"
 #include "hardware/esp32_i2s.h"
-#include "esp32_rtc.h"
+
 #include "xtensa.h"
 #include "xtensa_attr.h"
 
@@ -124,6 +130,25 @@
   .fe_pd = (val), \
 }
 
+#ifdef CONFIG_RTC_DRIVER
+/* The magic data for the struct esp32_rtc_backup_s that is in RTC slow
+ * memory.
+ */
+
+#  define MAGIC_RTC_SAVE (UINT64_C(0x11223344556677))
+#endif
+
+/* RTC Memory & Store Register usage */
+
+#define RTC_SLOW_CLK_CAL_REG    RTC_CNTL_STORE1_REG /* RTC_SLOW_CLK calibration value */
+#define RTC_BOOT_TIME_LOW_REG   RTC_CNTL_STORE2_REG /* Boot time, low word */
+#define RTC_BOOT_TIME_HIGH_REG  RTC_CNTL_STORE3_REG /* Boot time, high word */
+#define RTC_XTAL_FREQ_REG       RTC_CNTL_STORE4_REG /* External XTAL frequency */
+#define RTC_APB_FREQ_REG        RTC_CNTL_STORE5_REG /* APB bus frequency */
+#define RTC_ENTRY_ADDR_REG      RTC_CNTL_STORE6_REG /* FAST_RTC_MEMORY_ENTRY */
+#define RTC_RESET_CAUSE_REG     RTC_CNTL_STORE6_REG
+#define RTC_MEMORY_CRC_REG      RTC_CNTL_STORE7_REG /* FAST_RTC_MEMORY_CRC */
+
 /****************************************************************************
  * Private Types
  ****************************************************************************/
@@ -176,6 +201,28 @@ struct esp32_rtc_sleep_pd_config_s
   uint32_t fe_pd : 1;     /* Set to 1 to power down WiFi in sleep */
 };
 
+#ifdef CONFIG_RTC_DRIVER
+
+#ifdef CONFIG_RTC_ALARM
+struct alm_cbinfo_s
+{
+  struct rt_timer_s *alarm_hdl;  /* Timer id point to here */
+  volatile alm_callback_t ac_cb; /* Client callback function */
+  volatile FAR void *ac_arg;     /* Argument to pass with the callback function */
+  uint64_t deadline_us;
+  uint8_t index;
+};
+#endif
+
+struct esp32_rtc_backup_s
+{
+  uint64_t magic;
+  int64_t  offset;              /* Offset time from RTC HW value */
+  int64_t  reserved0;
+};
+
+#endif
+
 /****************************************************************************
  * Private Function Prototypes
  ****************************************************************************/
@@ -191,6 +238,10 @@ static void IRAM_ATTR esp32_rtc_clk_slow_freq_set(
                       enum esp32_rtc_slow_freq_e slow_freq);
 static void esp32_select_rtc_slow_clk(enum esp32_slow_clk_sel_e slow_clk);
 
+#ifdef CONFIG_RTC_DRIVER
+static void IRAM_ATTR esp32_rt_cb_handler(FAR void *arg);
+#endif
+
 /****************************************************************************
  * Private Data
  ****************************************************************************/
@@ -205,6 +256,31 @@ static struct esp32_rtc_priv_s esp32_rtc_priv =
   .rtc_dboost_fpd = 1
 };
 
+#ifdef CONFIG_RTC_DRIVER
+
+/* Callback to use when the alarm expires */
+
+#ifdef CONFIG_RTC_ALARM
+static struct alm_cbinfo_s g_alarmcb[RTC_ALARM_LAST];
+#endif
+
+static RTC_DATA_ATTR struct esp32_rtc_backup_s rtc_saved_data;
+
+/* Saved data for persistent RTC time */
+
+static struct esp32_rtc_backup_s *g_rtc_save;
+static bool g_rt_timer_enabled = false;
+
+#endif
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_DRIVER
+volatile bool g_rtc_enabled = false;
+#endif
+
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -475,6 +551,49 @@ static void esp32_select_rtc_slow_clk(enum esp32_slow_clk_sel_e slow_clk)
   putreg32((uint32_t)cal_val, RTC_SLOW_CLK_CAL_REG);
 }
 
+#ifdef CONFIG_RTC_DRIVER
+
+/****************************************************************************
+ * Name: esp32_rt_cb_handler
+ *
+ * Description:
+ *   RT-Timer service routine
+ *
+ * Input Parameters:
+ *   arg - Information about the RT-Timer configuration.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void IRAM_ATTR esp32_rt_cb_handler(FAR void *arg)
+{
+  FAR struct alm_cbinfo_s *cbinfo = (struct alm_cbinfo_s *)arg;
+  alm_callback_t cb;
+  FAR void *cb_arg;
+  int alminfo_id;
+
+  DEBUGASSERT(cbinfo != NULL);
+  alminfo_id = cbinfo->index;
+  DEBUGASSERT((RTC_ALARM0 <= alminfo_id) &&
+              (alminfo_id < RTC_ALARM_LAST));
+
+  if (cbinfo->ac_cb != NULL)
+    {
+      /* Alarm callback */
+
+      cb = cbinfo->ac_cb;
+      cb_arg = (FAR void *)cbinfo->ac_arg;
+      cbinfo->ac_cb  = NULL;
+      cbinfo->ac_arg = NULL;
+      cbinfo->deadline_us = 0;
+      cb(cb_arg, alminfo_id);
+    }
+}
+
+#endif /* CONFIG_RTC_DRIVER */
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -826,7 +945,7 @@ void IRAM_ATTR esp32_rtc_bbpll_configure(
  *
  ****************************************************************************/
 
-void esp32_rtc_clk_set()
+void esp32_rtc_clk_set(void)
 {
   enum esp32_rtc_fast_freq_e fast_freq = RTC_FAST_FREQ_8M;
   enum esp32_slow_clk_sel_e slow_clk = RTC_SLOW_FREQ_RTC;
@@ -848,7 +967,7 @@ void esp32_rtc_clk_set()
  *
  ****************************************************************************/
 
-void IRAM_ATTR esp32_rtc_init()
+void IRAM_ATTR esp32_rtc_init(void)
 {
   struct esp32_rtc_priv_s *priv = &esp32_rtc_priv;
 
@@ -1473,3 +1592,471 @@ int IRAM_ATTR esp32_rtc_sleep_start(uint32_t wakeup_opt,
                 RTC_CNTL_DBG_ATTEN_DEFAULT);
   return reject;
 }
+
+/****************************************************************************
+ * Name: esp32_rtc_get_time_us
+ *
+ * Description:
+ *   Get current value of RTC counter in microseconds
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Current value of RTC counter in microseconds
+ *
+ ****************************************************************************/
+
+uint64_t esp32_rtc_get_time_us(void)
+{
+  const uint32_t cal = getreg32(RTC_SLOW_CLK_CAL_REG);
+  const uint64_t rtc_this_ticks = esp32_rtc_time_get();
+
+  /* RTC counter result is up to 2^48, calibration factor is up to 2^24,
+   * for a 32kHz clock. We need to calculate (assuming no overflow):
+   * (ticks * cal) >> RTC_CLK_CAL_FRACT. An overflow in the (ticks * cal)
+   * multiplication would cause time to wrap around after approximately
+   * 13 days, which is probably not enough for some applications.
+   * Therefore multiplication is split into two terms, for the lower 32-bit
+   * and the upper 16-bit parts of "ticks", i.e.:
+   * ((ticks_low + 2^32 * ticks_high) * cal) >> RTC_CLK_CAL_FRACT
+   */
+
+  const uint64_t ticks_low = rtc_this_ticks & UINT32_MAX;
+  const uint64_t ticks_high = rtc_this_ticks >> 32;
+  const uint64_t delta_time_us = ((ticks_low * cal) >> RTC_CLK_CAL_FRACT) +
+          ((ticks_high * cal) << (32 - RTC_CLK_CAL_FRACT));
+
+  return delta_time_us;
+}
+
+/****************************************************************************
+ * Name: esp32_rtc_set_boot_time
+ *
+ * Description:
+ *   Set time to RTC register to replace the original boot time.
+ *
+ * Input Parameters:
+ *   time_us - set time in microseconds.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void IRAM_ATTR esp32_rtc_set_boot_time(uint64_t time_us)
+{
+  putreg32((uint32_t)(time_us & UINT32_MAX), RTC_BOOT_TIME_LOW_REG);
+  putreg32((uint32_t)(time_us >> 32), RTC_BOOT_TIME_HIGH_REG);
+}
+
+/****************************************************************************
+ * Name: esp32_rtc_get_boot_time
+ *
+ * Description:
+ *   Get time of RTC register to indicate the original boot time.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   time_us - get time in microseconds.
+ *
+ ****************************************************************************/
+
+uint64_t IRAM_ATTR esp32_rtc_get_boot_time(void)
+{
+  return ((uint64_t)getreg32(RTC_BOOT_TIME_LOW_REG))
+        + (((uint64_t)getreg32(RTC_BOOT_TIME_HIGH_REG)) << 32);
+}
+
+#ifdef CONFIG_RTC_DRIVER
+
+/****************************************************************************
+ * Name: up_rtc_time
+ *
+ * Description:
+ *   Get the current time in seconds.  This is similar to the standard time()
+ *   function.  This interface is only required if the low-resolution
+ *   RTC/counter hardware implementation is selected.  It is only used by the
+ *   RTOS during initialization to set up the system time when CONFIG_RTC is
+ *   set but CONFIG_RTC_HIRES is not set.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   The current time in seconds
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_RTC_HIRES
+time_t up_rtc_time(void)
+{
+  uint64_t time_us;
+  irqstate_t flags;
+
+  flags = spin_lock_irqsave(NULL);
+
+  /* NOTE: RT-Timer starts to work after the board is initialized, and the
+   * RTC controller starts works after up_rtc_initialize is initialized.
+   * Since the system clock starts to work before the board is initialized,
+   * if CONFIG_RTC is enabled, the system time must be matched by the time
+   * of the RTC controller (up_rtc_initialize has already been initialized,
+   * and RT-Timer cannot work).
+   */
+
+  /* Determine if RT-Timer is started */
+
+  if (g_rt_timer_enabled == true)
+    {
+      /* Get the time from RT-Timer, the time interval between RTC
+       * controller and RT-Timer is stored in g_rtc_save->offset.
+       */
+
+      time_us = rt_timer_time_us() + g_rtc_save->offset +
+                              esp32_rtc_get_boot_time();
+    }
+  else
+    {
+      /* Get the time from RTC controller. */
+
+      time_us = esp32_rtc_get_time_us() +
+                  esp32_rtc_get_boot_time();
+    }
+
+  spin_unlock_irqrestore(NULL, flags);
+
+  return (time_t)(time_us / USEC_PER_SEC);
+}
+#endif /* !CONFIG_RTC_HIRES */
+
+/****************************************************************************
+ * Name: up_rtc_settime
+ *
+ * Description:
+ *   Set the RTC to the provided time. All RTC implementations must be
+ *   able to set their time based on a standard timespec.
+ *
+ * Input Parameters:
+ *   ts - the time to use
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int up_rtc_settime(FAR const struct timespec *ts)
+{
+  irqstate_t flags;
+  uint64_t now_us;
+  uint64_t rtc_offset_us;
+
+  DEBUGASSERT(ts != NULL && ts->tv_nsec < NSEC_PER_SEC);
+  flags = spin_lock_irqsave(NULL);
+
+  now_us = ((uint64_t) ts->tv_sec) * USEC_PER_SEC +
+          ts->tv_nsec / NSEC_PER_USEC;
+  if (g_rt_timer_enabled == true)
+    {
+      /* Set based on RT-Timer offset value. */
+
+      rtc_offset_us = now_us - rt_timer_time_us();
+    }
+  else
+    {
+      /* Set based on the offset value of the RT controller. */
+
+      rtc_offset_us = now_us - esp32_rtc_get_time_us();
+    }
+
+  g_rtc_save->offset = 0;
+  esp32_rtc_set_boot_time(rtc_offset_us);
+
+  spin_unlock_irqrestore(NULL, flags);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: up_rtc_initialize
+ *
+ * Description:
+ *   Initialize the hardware RTC per the selected configuration.
+ *   This function is called once during the OS initialization sequence
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int up_rtc_initialize(void)
+{
+#ifndef CONFIG_PM
+  /* Initialize RTC controller parameters */
+
+  esp32_rtc_init();
+  esp32_rtc_clk_set();
+#endif
+
+  g_rtc_save = &rtc_saved_data;
+
+  /* If saved data is invalid, clear offset information */
+
+  if (g_rtc_save->magic != MAGIC_RTC_SAVE)
+    {
+      g_rtc_save->magic = MAGIC_RTC_SAVE;
+      g_rtc_save->offset = 0;
+      esp32_rtc_set_boot_time(0);
+    }
+
+#ifdef CONFIG_RTC_HIRES
+  /* Synchronize the base time to the RTC time */
+
+  up_rtc_gettime(&g_basetime);
+#endif
+
+  g_rtc_enabled = true;
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: up_rtc_gettime
+ *
+ * Description:
+ *   Get the current time from the high resolution RTC time or RT-Timer. This
+ *   interface is only supported by the high-resolution RTC/counter hardware
+ *   implementation. It is used to replace the system timer.
+ *
+ * Input Parameters:
+ *   tp - The location to return the RTC time or RT-Timer value.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_HIRES
+int up_rtc_gettime(FAR struct timespec *tp)
+{
+  irqstate_t flags;
+  uint64_t time_us;
+
+  flags = spin_lock_irqsave(NULL);
+
+  if (g_rt_timer_enabled == true)
+    {
+      time_us = rt_timer_time_us() + g_rtc_save->offset +
+                              esp32_rtc_get_boot_time();
+    }
+  else
+    {
+      time_us = = esp32_rtc_get_time_us() +
+                    esp32_rtc_get_boot_time();
+    }
+
+  tp->tv_sec  = time_us / USEC_PER_SEC;
+  tp->tv_nsec = (time_us % USEC_PER_SEC) * NSEC_PER_USEC;
+
+  spin_unlock_irqrestore(NULL, flags);
+
+  return OK;
+}
+#endif /* CONFIG_RTC_HIRES */
+
+#ifdef CONFIG_RTC_ALARM
+
+/****************************************************************************
+ * Name: up_rtc_setalarm
+ *
+ * Description:
+ *   Set up an alarm.
+ *
+ * Input Parameters:
+ *   alminfo - Information about the alarm configuration.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int up_rtc_setalarm(FAR struct alm_setalarm_s *alminfo)
+{
+  struct rt_timer_args_s rt_timer_args;
+  FAR struct alm_cbinfo_s *cbinfo;
+  irqstate_t flags;
+  int ret = -EBUSY;
+  int id;
+
+  DEBUGASSERT(alminfo != NULL);
+  DEBUGASSERT((RTC_ALARM0 <= alminfo->as_id) &&
+              (alminfo->as_id < RTC_ALARM_LAST));
+
+  /* Set the alarm in RT-Timer */
+
+  id = alminfo->as_id;
+  cbinfo = &g_alarmcb[id];
+
+  if (cbinfo->ac_cb == NULL)
+    {
+      /* Create the RT-Timer alarm */
+
+      flags = spin_lock_irqsave(NULL);
+
+      if (cbinfo->alarm_hdl == NULL)
+        {
+          cbinfo->index = id;
+          rt_timer_args.arg = cbinfo;
+          rt_timer_args.callback = esp32_rt_cb_handler;
+          ret = rt_timer_create(&rt_timer_args, &cbinfo->alarm_hdl);
+          if (ret < 0)
+            {
+              rtcerr("ERROR: Failed to create rt_timer error=%d\n", ret);
+              spin_unlock_irqrestore(NULL, flags);
+              return ret;
+            }
+        }
+
+      cbinfo->ac_cb  = alminfo->as_cb;
+      cbinfo->ac_arg = alminfo->as_arg;
+      cbinfo->deadline_us = alminfo->as_time.tv_sec * USEC_PER_SEC +
+                            alminfo->as_time.tv_nsec / NSEC_PER_USEC;
+
+      if (cbinfo->alarm_hdl == NULL)
+        {
+          rtcerr("ERROR: failed to create alarm timer\n");
+        }
+      else
+        {
+          rtcinfo("Start RTC alarm.\n");
+          rt_timer_start(cbinfo->alarm_hdl, cbinfo->deadline_us, false);
+          ret = OK;
+        }
+
+      spin_unlock_irqrestore(NULL, flags);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: up_rtc_cancelalarm
+ *
+ * Description:
+ *   Cancel an alarm.
+ *
+ * Input Parameters:
+ *   alarmid - Identifies the alarm to be cancelled
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int up_rtc_cancelalarm(enum alm_id_e alarmid)
+{
+  FAR struct alm_cbinfo_s *cbinfo;
+  irqstate_t flags;
+  int ret = -ENODATA;
+
+  DEBUGASSERT((RTC_ALARM0 <= alarmid) &&
+              (alarmid < RTC_ALARM_LAST));
+
+  /* Set the alarm in hardware and enable interrupts */
+
+  cbinfo = &g_alarmcb[alarmid];
+
+  if (cbinfo->ac_cb != NULL)
+    {
+      flags = spin_lock_irqsave(NULL);
+
+      /* Stop and delete the alarm */
+
+      rtcinfo("Cancel RTC alarm.\n");
+      rt_timer_stop(cbinfo->alarm_hdl);
+      rt_timer_delete(cbinfo->alarm_hdl);
+      cbinfo->ac_cb = NULL;
+      cbinfo->deadline_us = 0;
+      cbinfo->alarm_hdl = NULL;
+
+      spin_unlock_irqrestore(NULL, flags);
+
+      ret = OK;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: up_rtc_rdalarm
+ *
+ * Description:
+ *   Query an alarm configured in hardware.
+ *
+ * Input Parameters:
+ *   tp      - Location to return the timer match register.
+ *   alarmid - Identifies the alarm to get.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int up_rtc_rdalarm(FAR struct timespec *tp, uint32_t alarmid)
+{
+  irqstate_t flags;
+  FAR struct alm_cbinfo_s *cbinfo;
+  DEBUGASSERT(tp != NULL);
+  DEBUGASSERT((RTC_ALARM0 <= alarmid) &&
+              (alarmid < RTC_ALARM_LAST));
+
+  flags = spin_lock_irqsave(NULL);
+
+  /* Get the alarm according to the alarmid */
+
+  cbinfo = &g_alarmcb[alarmid];
+
+  tp->tv_sec = (rt_timer_time_us() + g_rtc_save->offset +
+              cbinfo->deadline_us) / USEC_PER_SEC;
+  tp->tv_nsec = ((rt_timer_time_us() + g_rtc_save->offset +
+              cbinfo->deadline_us) % USEC_PER_SEC) * NSEC_PER_USEC;
+
+  spin_unlock_irqrestore(NULL, flags);
+
+  return OK;
+}
+
+#endif /* CONFIG_RTC_ALARM */
+
+/****************************************************************************
+ * Name: up_rtc_timer_init
+ *
+ * Description:
+ *   Init RTC timer.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int up_rtc_timer_init(void)
+{
+  /* RT-Timer enabled */
+
+  g_rt_timer_enabled = true;
+
+  /* Get the time difference between rt_timer and RTC timer */
+
+  g_rtc_save->offset = esp32_rtc_get_time_us() - rt_timer_time_us();
+
+  return OK;
+}
+
+#endif /* CONFIG_RTC_DRIVER */
\ No newline at end of file
diff --git a/arch/xtensa/src/esp32/esp32_rtc.h b/arch/xtensa/src/esp32/esp32_rtc.h
index 025c878..3ce469b 100644
--- a/arch/xtensa/src/esp32/esp32_rtc.h
+++ b/arch/xtensa/src/esp32/esp32_rtc.h
@@ -30,6 +30,9 @@
  ****************************************************************************/
 
 #include <nuttx/config.h>
+#include <nuttx/timers/rtc.h>
+#include <sys/types.h>
+#include <time.h>
 #include "hardware/esp32_soc.h"
 
 #ifndef __ASSEMBLY__
@@ -127,6 +130,31 @@ enum esp32_rtc_cal_sel_e
   RTC_CAL_32K_XTAL = 2       /* External 32 kHz XTAL */
 };
 
+#ifdef CONFIG_RTC_ALARM
+
+/* The form of an alarm callback */
+
+typedef CODE void (*alm_callback_t)(FAR void *arg, unsigned int alarmid);
+
+enum alm_id_e
+{
+  RTC_ALARM0 = 0,           /* RTC ALARM 0 */
+  RTC_ALARM1 = 1,           /* RTC ALARM 1 */
+  RTC_ALARM_LAST,
+};
+
+/* Structure used to pass parameters to set an alarm */
+
+struct alm_setalarm_s
+{
+  int               as_id;     /* enum alm_id_e */
+  struct timespec   as_time;   /* Alarm expiration time */
+  alm_callback_t    as_cb;     /* Callback (if non-NULL) */
+  FAR void          *as_arg;   /* Argument for callback */
+};
+
+#endif /* CONFIG_RTC_ALARM */
+
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
@@ -447,6 +475,203 @@ void esp32_rtc_sleep_init(uint32_t flags);
 
 int esp32_rtc_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt);
 
+/****************************************************************************
+ * Name: esp32_rtc_get_time_us
+ *
+ * Description:
+ *   Get current value of RTC counter in microseconds
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Current value of RTC counter in microseconds
+ *
+ ****************************************************************************/
+
+uint64_t esp32_rtc_get_time_us(void);
+
+/****************************************************************************
+ * Name: esp32_rtc_set_boot_time
+ *
+ * Description:
+ *   Set time to RTC register to replace the original boot time.
+ *
+ * Input Parameters:
+ *   time_us - set time in microseconds.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void esp32_rtc_set_boot_time(uint64_t time_us);
+
+/****************************************************************************
+ * Name: esp32_rtc_get_boot_time
+ *
+ * Description:
+ *   Get time of RTC register to indicate the original boot time.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   time_us - get time in microseconds.
+ *
+ ****************************************************************************/
+
+uint64_t esp32_rtc_get_boot_time(void);
+
+#ifdef CONFIG_RTC_DRIVER
+
+/****************************************************************************
+ * Name: up_rtc_time
+ *
+ * Description:
+ *   Get the current time in seconds.  This is similar to the standard time()
+ *   function.  This interface is only required if the low-resolution
+ *   RTC/counter hardware implementation selected.  It is only used by the
+ *   RTOS during initialization to set up the system time when CONFIG_RTC is
+ *   set but neither CONFIG_RTC_HIRES nor CONFIG_RTC_DATETIME are set.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   The current time in seconds
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_RTC_HIRES
+time_t up_rtc_time(void);
+#endif
+
+/****************************************************************************
+ * Name: up_rtc_settime
+ *
+ * Description:
+ *   Set the RTC to the provided time.  All RTC implementations must be
+ *   able to set their time based on a standard timespec.
+ *
+ * Input Parameters:
+ *   tp - the time to use
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int up_rtc_settime(FAR const struct timespec *ts);
+
+/****************************************************************************
+ * Name: up_rtc_initialize
+ *
+ * Description:
+ *   Initialize the hardware RTC per the selected configuration.
+ *   This function is called once during the OS initialization sequence
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int up_rtc_initialize(void);
+
+/****************************************************************************
+ * Name: up_rtc_gettime
+ *
+ * Description:
+ *   Get the current time from the high resolution RTC clock/counter.  This
+ *   interface is only supported by the high-resolution RTC/counter hardware
+ *   implementation.  It is used to replace the system timer.
+ *
+ * Input Parameters:
+ *   tp - The location to return the high resolution time value.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_HIRES
+int up_rtc_gettime(FAR struct timespec *tp);
+#endif
+
+#ifdef CONFIG_RTC_ALARM
+
+/****************************************************************************
+ * Name: up_rtc_setalarm
+ *
+ * Description:
+ *   Set up an alarm.
+ *
+ * Input Parameters:
+ *   alminfo - Information about the alarm configuration.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int up_rtc_setalarm(FAR struct alm_setalarm_s *alminfo);
+
+/****************************************************************************
+ * Name: up_rtc_cancelalarm
+ *
+ * Description:
+ *   Cancel an alaram.
+ *
+ * Input Parameters:
+ *  alarmid - Identifies the alarm to be cancelled
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int up_rtc_cancelalarm(enum alm_id_e alarmid);
+
+/****************************************************************************
+ * Name: up_rtc_rdalarm
+ *
+ * Description:
+ *   Query an alarm configured in hardware.
+ *
+ * Input Parameters:
+ *  tp      - Location to return the timer match register.
+ *  alarmid - Identifies the alarm to be cancelled
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int up_rtc_rdalarm(FAR struct timespec *tp, uint32_t alarmid);
+
+#endif /* CONFIG_RTC_ALARM */
+
+/****************************************************************************
+ * Name: up_rtc_timer_init
+ *
+ * Description:
+ *   Init RTC timer.
+ *
+ * Input Parameters:
+ *  None
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int up_rtc_timer_init(void);
+
+#endif /* CONFIG_RTC_DRIVER */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/arch/xtensa/src/esp32/esp32_rtc_lowerhalf.c b/arch/xtensa/src/esp32/esp32_rtc_lowerhalf.c
new file mode 100644
index 0000000..e2ca2ed
--- /dev/null
+++ b/arch/xtensa/src/esp32/esp32_rtc_lowerhalf.c
@@ -0,0 +1,565 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_rtc_lowerhalf.c
+ *
+ * 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 <nuttx/spinlock.h>
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/timers/rtc.h>
+
+#include "esp32_rtc.h"
+#include "hardware/esp32_tim.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_ALARM
+struct esp32_cbinfo_s
+{
+  volatile rtc_alarm_callback_t cb;  /* Callback when the alarm expires */
+  volatile FAR void *priv;           /* Private argurment to accompany callback */
+};
+#endif
+
+/* This is the private type for the RTC state.  It must be cast compatible
+ * with struct rtc_lowerhalf_s.
+ */
+
+struct esp32_lowerhalf_s
+{
+  /* This is the contained reference to the read-only, lower-half
+   * operations vtable (which may lie in FLASH or ROM)
+   */
+
+  FAR const struct rtc_ops_s *ops;
+#ifdef CONFIG_RTC_ALARM
+  /* Alarm callback information */
+
+  struct esp32_cbinfo_s cbinfo[RTC_ALARM_LAST];
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Prototypes for static methods in struct rtc_ops_s */
+
+static int rtc_lh_rdtime(FAR struct rtc_lowerhalf_s *lower,
+                         FAR struct rtc_time *rtctime);
+static int rtc_lh_settime(FAR struct rtc_lowerhalf_s *lower,
+                          FAR const struct rtc_time *rtctime);
+static bool rtc_lh_havesettime(FAR struct rtc_lowerhalf_s *lower);
+
+#ifdef CONFIG_RTC_ALARM
+static void rtc_lh_alarm_callback(FAR void *arg, unsigned int alarmid);
+static int rtc_lh_setalarm(FAR struct rtc_lowerhalf_s *lower,
+                           FAR const struct lower_setalarm_s *alarminfo);
+static int rtc_lh_setrelative(FAR struct rtc_lowerhalf_s *lower,
+                           FAR const struct lower_setrelative_s *alarminfo);
+static int rtc_lh_cancelalarm(FAR struct rtc_lowerhalf_s *lower,
+                              int alarmid);
+static int rtc_lh_rdalarm(FAR struct rtc_lowerhalf_s *lower,
+                          FAR struct lower_rdalarm_s *alarminfo);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* ESP32 RTC driver operations */
+
+static const struct rtc_ops_s g_rtc_ops =
+{
+  .rdtime      = rtc_lh_rdtime,
+  .settime     = rtc_lh_settime,
+  .havesettime = rtc_lh_havesettime,
+#ifdef CONFIG_RTC_ALARM
+  .setalarm    = rtc_lh_setalarm,
+  .setrelative = rtc_lh_setrelative,
+  .cancelalarm = rtc_lh_cancelalarm,
+  .rdalarm     = rtc_lh_rdalarm,
+#endif
+#ifdef CONFIG_RTC_PERIODIC
+  .setperiodic    = NULL,
+  .cancelperiodic = NULL,
+#endif
+#ifdef CONFIG_RTC_IOCTL
+  .ioctl       = NULL,
+#endif
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+  .destroy     = NULL,
+#endif
+};
+
+/* ESP32 RTC device state */
+
+static struct esp32_lowerhalf_s g_rtc_lowerhalf =
+{
+  .ops = &g_rtc_ops,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rtc_lh_alarm_callback
+ *
+ * Description:
+ *   This is the function that is called from the RTC driver when the alarm
+ *   goes off. It just invokes the upper half drivers callback.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_ALARM
+static void rtc_lh_alarm_callback(FAR void *arg, unsigned int alarmid)
+{
+  FAR struct esp32_lowerhalf_s *lower;
+  FAR struct esp32_cbinfo_s *cbinfo;
+  rtc_alarm_callback_t cb;
+  FAR void *priv;
+
+  DEBUGASSERT((RTC_ALARM0 <= alarmid) && (alarmid < RTC_ALARM_LAST));
+
+  lower        = (struct esp32_lowerhalf_s *)arg;
+  cbinfo       = &lower->cbinfo[alarmid];
+
+  /* Sample and clear the callback information to minimize the window in
+   * time in which race conditions can occur.
+   */
+
+  cb           = (rtc_alarm_callback_t)cbinfo->cb;
+  priv         = (FAR void *)cbinfo->priv;
+
+  cbinfo->cb   = NULL;
+  cbinfo->priv = NULL;
+
+  /* Perform the callback */
+
+  if (cb != NULL)
+    {
+      cb(priv, alarmid);
+    }
+}
+#endif /* CONFIG_RTC_ALARM */
+
+/****************************************************************************
+ * Name: rtc_lh_rdtime
+ *
+ * Description:
+ *   Returns the current RTC time.
+ *
+ * Input Parameters:
+ *   lower   - A reference to RTC lower half driver state structure
+ *   rcttime - The location in which to return the current RTC time.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on any failure.
+ *
+ ****************************************************************************/
+
+static int rtc_lh_rdtime(FAR struct rtc_lowerhalf_s *lower,
+                         FAR struct rtc_time *rtctime)
+{
+#if defined(CONFIG_RTC_HIRES)
+  FAR struct timespec ts;
+  int ret;
+
+  /* Get the higher resolution time */
+
+  ret = up_rtc_gettime(&ts);
+  if (ret < 0)
+    {
+      goto errout;
+    }
+
+  /* Convert the one second epoch time to a struct tm.  This operation
+   * depends on the fact that struct rtc_time and struct tm are cast
+   * compatible.
+   */
+
+  if (!gmtime_r(&ts.tv_sec, (FAR struct tm *)rtctime))
+    {
+      ret = -get_errno();
+      goto errout;
+    }
+
+  return OK;
+
+errout:
+  rtcerr("ERROR: failed to get RTC time: %d\n", ret);
+  return ret;
+
+#else
+  time_t timer;
+
+  /* The resolution of time is only 1 second */
+
+  timer = up_rtc_time();
+
+  /* Convert the one second epoch time to a struct tm */
+
+  if (gmtime_r(&timer, (FAR struct tm *)rtctime) == 0)
+    {
+      int errcode = get_errno();
+      DEBUGASSERT(errcode > 0);
+
+      rtcerr("ERROR: gmtime_r failed: %d\n", errcode);
+      return -errcode;
+    }
+
+  return OK;
+#endif
+}
+
+/****************************************************************************
+ * Name: rtc_lh_settime
+ *
+ * Description:
+ *   Implements the settime() method of the RTC driver interface
+ *
+ * Input Parameters:
+ *   lower   - A reference to RTC lower half driver state structure
+ *   rcttime - The new time to set
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on any failure.
+ *
+ ****************************************************************************/
+
+static int rtc_lh_settime(FAR struct rtc_lowerhalf_s *lower,
+                          FAR const struct rtc_time *rtctime)
+{
+  struct timespec ts;
+
+  /* Convert the struct rtc_time to a time_t.  Here we assume that struct
+   * rtc_time is cast compatible with struct tm.
+   */
+
+  ts.tv_sec  = mktime((FAR struct tm *)rtctime);
+  ts.tv_nsec = 0;
+
+  /* Now set the time (with a accuracy of seconds) */
+
+  return up_rtc_settime(&ts);
+}
+
+/****************************************************************************
+ * Name: rtc_lh_havesettime
+ *
+ * Description:
+ *   Implements the havesettime() method of the RTC driver interface
+ *
+ * Input Parameters:
+ *   lower - A reference to RTC lower half driver state structure
+ *
+ * Returned Value:
+ *   Returns true if RTC date-time have been previously set.
+ *
+ ****************************************************************************/
+
+static bool rtc_lh_havesettime(FAR struct rtc_lowerhalf_s *lower)
+{
+  if (esp32_rtc_get_boot_time() == 0)
+    {
+      return false;
+    }
+
+  return true;
+}
+
+/****************************************************************************
+ * Name: rtc_lh_setalarm
+ *
+ * Description:
+ *   Set a new alarm. This function implements the setalarm() method of the
+ *   RTC driver interface
+ *
+ * Input Parameters:
+ *   lower - A reference to RTC lower half driver state structure
+ *   alarminfo - Provided information needed to set the alarm
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_ALARM
+static int rtc_lh_setalarm(FAR struct rtc_lowerhalf_s *lower,
+                           FAR const struct lower_setalarm_s *alarminfo)
+{
+  FAR struct esp32_lowerhalf_s *priv;
+  FAR struct esp32_cbinfo_s *cbinfo;
+  struct alm_setalarm_s lowerinfo;
+  int ret;
+
+  DEBUGASSERT(lower != NULL && alarminfo != NULL);
+  DEBUGASSERT((RTC_ALARM0 <= alarminfo->id) &&
+              (alarminfo->id < RTC_ALARM_LAST));
+
+  priv = (FAR struct esp32_lowerhalf_s *)lower;
+
+  /* Remember the callback information */
+
+  cbinfo            = &priv->cbinfo[alarminfo->id];
+  cbinfo->cb        = alarminfo->cb;
+  cbinfo->priv      = alarminfo->priv;
+
+  /* Set the alarm */
+
+  lowerinfo.as_id   = alarminfo->id;
+  lowerinfo.as_cb   = rtc_lh_alarm_callback;
+  lowerinfo.as_arg  = priv;
+
+  /* Convert the RTC time to a timespec (1 second accuracy) */
+
+  lowerinfo.as_time.tv_sec  = mktime((FAR struct tm *)&alarminfo->time);
+  lowerinfo.as_time.tv_nsec = 0;
+
+  /* And set the alarm */
+
+  ret = up_rtc_setalarm(&lowerinfo);
+  if (ret < 0)
+    {
+      cbinfo->cb   = NULL;
+      cbinfo->priv = NULL;
+    }
+
+  return ret;
+}
+#endif /* CONFIG_RTC_ALARM */
+
+/****************************************************************************
+ * Name: rtc_lh_setrelative
+ *
+ * Description:
+ *   Set a new alarm relative to the current time. This function implements
+ *   the setrelative() method of the RTC driver interface
+ *
+ * Input Parameters:
+ *   lower - A reference to RTC lower half driver state structure
+ *   alarminfo - Provided information needed to set the alarm
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_ALARM
+static int rtc_lh_setrelative(FAR struct rtc_lowerhalf_s *lower,
+                            FAR const struct lower_setrelative_s *alarminfo)
+{
+  struct lower_setalarm_s setalarm;
+  time_t seconds;
+  int ret = -EINVAL;
+  irqstate_t flags;
+
+  DEBUGASSERT(lower != NULL && alarminfo != NULL);
+  DEBUGASSERT((RTC_ALARM0 <= alarminfo->id) &&
+              (alarminfo->id < RTC_ALARM_LAST));
+
+  if (alarminfo->reltime > 0)
+    {
+      flags = spin_lock_irqsave(NULL);
+
+      seconds = alarminfo->reltime;
+      gmtime_r(&seconds, (FAR struct tm *)&setalarm.time);
+
+      /* The set the alarm using this absolute time */
+
+      setalarm.id   = alarminfo->id;
+      setalarm.cb   = alarminfo->cb;
+      setalarm.priv = alarminfo->priv;
+      ret = rtc_lh_setalarm(lower, &setalarm);
+
+      spin_unlock_irqrestore(NULL, flags);
+    }
+
+  return ret;
+}
+#endif /* CONFIG_RTC_ALARM */
+
+/****************************************************************************
+ * Name: rtc_lh_cancelalarm
+ *
+ * Description:
+ *   Cancel the current alarm.  This function implements the cancelalarm()
+ *   method of the RTC driver interface
+ *
+ * Input Parameters:
+ *   lower - A reference to RTC lower half driver state structure
+ *   alarmid - the alarm id
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_ALARM
+static int rtc_lh_cancelalarm(FAR struct rtc_lowerhalf_s *lower, int alarmid)
+{
+  FAR struct esp32_lowerhalf_s *priv;
+  FAR struct esp32_cbinfo_s *cbinfo;
+
+  DEBUGASSERT(lower != NULL);
+  DEBUGASSERT((RTC_ALARM0 <= alarmid) && (alarmid < RTC_ALARM_LAST));
+
+  priv = (FAR struct esp32_lowerhalf_s *)lower;
+
+  /* Nullify callback information to reduce window for race conditions */
+
+  cbinfo       = &priv->cbinfo[alarmid];
+  cbinfo->cb   = NULL;
+  cbinfo->priv = NULL;
+
+  /* Then cancel the alarm */
+
+  return up_rtc_cancelalarm((enum alm_id_e)alarmid);
+}
+#endif /* CONFIG_RTC_ALARM */
+
+/****************************************************************************
+ * Name: rtc_lh_rdalarm
+ *
+ * Description:
+ *   Query the RTC alarm.
+ *
+ * Input Parameters:
+ *   lower     - A reference to RTC lower half driver state structure
+ *   alarminfo - Provided information needed to query the alarm
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_ALARM
+static int rtc_lh_rdalarm(FAR struct rtc_lowerhalf_s *lower,
+                          FAR struct lower_rdalarm_s *alarminfo)
+{
+  struct timespec ts;
+  int ret;
+  irqstate_t flags;
+
+  DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->time != NULL);
+  DEBUGASSERT((RTC_ALARM0 <= alarminfo->id) &&
+              (alarminfo->id < RTC_ALARM_LAST));
+
+  flags = spin_lock_irqsave(NULL);
+
+  ret = up_rtc_rdalarm(&ts, alarminfo->id);
+  localtime_r((FAR const time_t *)&ts.tv_sec,
+              (FAR struct tm *)alarminfo->time);
+
+  spin_unlock_irqrestore(NULL, flags);
+
+  return ret;
+}
+#endif /* CONFIG_RTC_ALARM */
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32_rtc_lowerhalf
+ *
+ * Description:
+ *   Instantiate the RTC lower half driver for the ESP32.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   On success, a non-NULL RTC lower interface is returned.  NULL is
+ *   returned on any failure.
+ *
+ ****************************************************************************/
+
+FAR struct rtc_lowerhalf_s *esp32_rtc_lowerhalf(void)
+{
+  return (FAR struct rtc_lowerhalf_s *)&g_rtc_lowerhalf;
+}
+
+/****************************************************************************
+ * Name: esp32_rtc_driverinit
+ *
+ * Description:
+ *   Bind the configuration timer to a timer lower half instance and register
+ *   the timer drivers at 'devpath'
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned
+ *   to indicate the nature of any failure.
+ *
+ ****************************************************************************/
+
+int esp32_rtc_driverinit(void)
+{
+  int ret;
+  FAR struct rtc_lowerhalf_s *lower;
+
+  /* Instantiate the ESP32 lower-half RTC driver */
+
+  lower = esp32_rtc_lowerhalf();
+  if (lower == NULL)
+    {
+      return ret;
+    }
+  else
+    {
+      /* Bind the lower half driver and register the combined RTC driver
+       * as /dev/rtc0
+       */
+
+      ret = rtc_initialize(0, lower);
+    }
+
+  /* Init RTC timer */
+
+  up_rtc_timer_init();
+
+  return ret;
+}
diff --git a/arch/xtensa/src/esp32/esp32_rtc_lowerhalf.h b/arch/xtensa/src/esp32/esp32_rtc_lowerhalf.h
new file mode 100644
index 0000000..a5ef77e
--- /dev/null
+++ b/arch/xtensa/src/esp32/esp32_rtc_lowerhalf.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_rtc_lowerhalf.h
+ *
+ * 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_XTENSA_SRC_ESP32_ESP32_RTC_LOWERHALF_H
+#define __ARCH_XTENSA_SRC_ESP32_ESP32_RTC_LOWERHALF_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifdef CONFIG_RTC_DRIVER
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32_rtc_driverinit
+ *
+ * Description:
+ *   Bind the configuration timer to a timer lower half instance and register
+ *   the timer drivers at 'devpath'
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned
+ *   to indicate the nature of any failure.
+ *
+ ****************************************************************************/
+
+int esp32_rtc_driverinit(void);
+
+#endif /* CONFIG_RTC_DRIVER */
+
+#endif /* __ARCH_XTENSA_SRC_ESP32_ESP32_RTC_LOWERHALF_H */
diff --git a/boards/xtensa/esp32/esp32-devkitc/configs/rtc/defconfig b/boards/xtensa/esp32/esp32-devkitc/configs/rtc/defconfig
new file mode 100644
index 0000000..da35167
--- /dev/null
+++ b/boards/xtensa/esp32/esp32-devkitc/configs/rtc/defconfig
@@ -0,0 +1,53 @@
+#
+# 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_ARCH_LEDS is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_NSH_CMDPARMS is not set
+CONFIG_ARCH="xtensa"
+CONFIG_ARCH_BOARD="esp32-devkitc"
+CONFIG_ARCH_BOARD_ESP32_DEVKITC=y
+CONFIG_ARCH_CHIP="esp32"
+CONFIG_ARCH_CHIP_ESP32=y
+CONFIG_ARCH_CHIP_ESP32WROVER=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_XTENSA=y
+CONFIG_BOARD_LOOPSPERMSEC=16717
+CONFIG_BUILTIN=y
+CONFIG_ESP32_RT_TIMER=y
+CONFIG_ESP32_UART0=y
+CONFIG_EXAMPLES_ALARM=y
+CONFIG_FS_PROCFS=y
+CONFIG_HAVE_CXX=y
+CONFIG_HAVE_CXXINITIALIZE=y
+CONFIG_IDLETHREAD_STACKSIZE=3072
+CONFIG_INTELHEX_BINARY=y
+CONFIG_MAX_TASKS=16
+CONFIG_MM_REGIONS=3
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_LINELEN=64
+CONFIG_NSH_READLINE=y
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_RAM_SIZE=114688
+CONFIG_RAM_START=0x20000000
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_RTC=y
+CONFIG_RTC_ALARM=y
+CONFIG_RTC_DRIVER=y
+CONFIG_RTC_NALARMS=2
+CONFIG_SCHED_WAITPID=y
+CONFIG_SDCLONE_DISABLE=y
+CONFIG_START_DAY=6
+CONFIG_START_MONTH=12
+CONFIG_START_YEAR=2011
+CONFIG_SYSTEM_NSH=y
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_USER_ENTRYPOINT="nsh_main"
diff --git a/boards/xtensa/esp32/esp32-devkitc/src/esp32_bringup.c b/boards/xtensa/esp32/esp32-devkitc/src/esp32_bringup.c
index 75a61da..ca844a6 100644
--- a/boards/xtensa/esp32/esp32-devkitc/src/esp32_bringup.c
+++ b/boards/xtensa/esp32/esp32-devkitc/src/esp32_bringup.c
@@ -90,6 +90,10 @@
 #  include <nuttx/input/buttons.h>
 #endif
 
+#ifdef CONFIG_RTC_DRIVER
+#  include "esp32_rtc_lowerhalf.h"
+#endif
+
 #include "esp32-devkitc.h"
 
 /****************************************************************************
@@ -375,6 +379,17 @@ int esp32_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_RTC_DRIVER
+  /* Instantiate the ESP32 RTC driver */
+
+  ret = esp32_rtc_driverinit();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR,
+             "ERROR: Failed to Instantiate the RTC driver: %d\n", ret);
+    }
+#endif
+
   /* If we got here then perhaps not all initialization was successful, but
    * at least enough succeeded to bring-up NSH with perhaps reduced
    * capabilities.
diff --git a/boards/xtensa/esp32/esp32-ethernet-kit/configs/rtc/defconfig b/boards/xtensa/esp32/esp32-ethernet-kit/configs/rtc/defconfig
new file mode 100644
index 0000000..ec05862
--- /dev/null
+++ b/boards/xtensa/esp32/esp32-ethernet-kit/configs/rtc/defconfig
@@ -0,0 +1,52 @@
+#
+# 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_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_NSH_CMDPARMS is not set
+CONFIG_ARCH="xtensa"
+CONFIG_ARCH_BOARD="esp32-ethernet-kit"
+CONFIG_ARCH_BOARD_ESP32_ETHERNETKIT=y
+CONFIG_ARCH_CHIP="esp32"
+CONFIG_ARCH_CHIP_ESP32=y
+CONFIG_ARCH_CHIP_ESP32WROVER=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_XTENSA=y
+CONFIG_BOARD_LOOPSPERMSEC=16717
+CONFIG_BUILTIN=y
+CONFIG_ESP32_RT_TIMER=y
+CONFIG_ESP32_UART0=y
+CONFIG_EXAMPLES_ALARM=y
+CONFIG_FS_PROCFS=y
+CONFIG_HAVE_CXX=y
+CONFIG_HAVE_CXXINITIALIZE=y
+CONFIG_IDLETHREAD_STACKSIZE=3072
+CONFIG_INTELHEX_BINARY=y
+CONFIG_MAX_TASKS=16
+CONFIG_MM_REGIONS=3
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_LINELEN=64
+CONFIG_NSH_READLINE=y
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_RAM_SIZE=114688
+CONFIG_RAM_START=0x20000000
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_RTC=y
+CONFIG_RTC_ALARM=y
+CONFIG_RTC_DRIVER=y
+CONFIG_RTC_NALARMS=2
+CONFIG_SCHED_WAITPID=y
+CONFIG_SDCLONE_DISABLE=y
+CONFIG_START_DAY=6
+CONFIG_START_MONTH=12
+CONFIG_START_YEAR=2011
+CONFIG_SYSTEM_NSH=y
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_USER_ENTRYPOINT="nsh_main"
diff --git a/boards/xtensa/esp32/esp32-ethernet-kit/src/esp32_bringup.c b/boards/xtensa/esp32/esp32-ethernet-kit/src/esp32_bringup.c
index 20b3309..e1875b5 100644
--- a/boards/xtensa/esp32/esp32-ethernet-kit/src/esp32_bringup.c
+++ b/boards/xtensa/esp32/esp32-ethernet-kit/src/esp32_bringup.c
@@ -70,6 +70,10 @@
 #  include <nuttx/input/buttons.h>
 #endif
 
+#ifdef CONFIG_RTC_DRIVER
+#  include "esp32_rtc_lowerhalf.h"
+#endif
+
 #include "esp32-ethernet-kit.h"
 
 /****************************************************************************
@@ -271,6 +275,17 @@ int esp32_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_RTC_DRIVER
+  /* Instantiate the ESP32 RTC driver */
+
+  ret = esp32_rtc_driverinit();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR,
+             "ERROR: Failed to Instantiate the RTC driver: %d\n", ret);
+    }
+#endif
+
   /* If we got here then perhaps not all initialization was successful, but
    * at least enough succeeded to bring-up NSH with perhaps reduced
    * capabilities.
diff --git a/boards/xtensa/esp32/esp32-wrover-kit/configs/rtc/defconfig b/boards/xtensa/esp32/esp32-wrover-kit/configs/rtc/defconfig
new file mode 100644
index 0000000..4d87cf8
--- /dev/null
+++ b/boards/xtensa/esp32/esp32-wrover-kit/configs/rtc/defconfig
@@ -0,0 +1,53 @@
+#
+# 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_ARCH_LEDS is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_NSH_CMDPARMS is not set
+CONFIG_ARCH="xtensa"
+CONFIG_ARCH_BOARD="esp32-wrover-kit"
+CONFIG_ARCH_BOARD_ESP32_WROVERKIT=y
+CONFIG_ARCH_CHIP="esp32"
+CONFIG_ARCH_CHIP_ESP32=y
+CONFIG_ARCH_CHIP_ESP32WROVER=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_XTENSA=y
+CONFIG_BOARD_LOOPSPERMSEC=16717
+CONFIG_BUILTIN=y
+CONFIG_ESP32_RT_TIMER=y
+CONFIG_ESP32_UART0=y
+CONFIG_EXAMPLES_ALARM=y
+CONFIG_FS_PROCFS=y
+CONFIG_HAVE_CXX=y
+CONFIG_HAVE_CXXINITIALIZE=y
+CONFIG_IDLETHREAD_STACKSIZE=3072
+CONFIG_INTELHEX_BINARY=y
+CONFIG_MAX_TASKS=16
+CONFIG_MM_REGIONS=3
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_LINELEN=64
+CONFIG_NSH_READLINE=y
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_RAM_SIZE=114688
+CONFIG_RAM_START=0x20000000
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_RTC=y
+CONFIG_RTC_ALARM=y
+CONFIG_RTC_DRIVER=y
+CONFIG_RTC_NALARMS=2
+CONFIG_SCHED_WAITPID=y
+CONFIG_SDCLONE_DISABLE=y
+CONFIG_START_DAY=6
+CONFIG_START_MONTH=12
+CONFIG_START_YEAR=2011
+CONFIG_SYSTEM_NSH=y
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_USER_ENTRYPOINT="nsh_main"
diff --git a/boards/xtensa/esp32/esp32-wrover-kit/src/esp32_bringup.c b/boards/xtensa/esp32/esp32-wrover-kit/src/esp32_bringup.c
index 5012d2e..a9ee883 100644
--- a/boards/xtensa/esp32/esp32-wrover-kit/src/esp32_bringup.c
+++ b/boards/xtensa/esp32/esp32-wrover-kit/src/esp32_bringup.c
@@ -90,6 +90,10 @@
 #  include <nuttx/lcd/lcd_dev.h>
 #endif
 
+#ifdef CONFIG_RTC_DRIVER
+#  include "esp32_rtc_lowerhalf.h"
+#endif
+
 #include "esp32-wrover-kit.h"
 
 /****************************************************************************
@@ -358,6 +362,17 @@ int esp32_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_RTC_DRIVER
+  /* Instantiate the ESP32 RTC driver */
+
+  ret = esp32_rtc_driverinit();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR,
+             "ERROR: Failed to Instantiate the RTC driver: %d\n", ret);
+    }
+#endif
+
   /* If we got here then perhaps not all initialization was successful, but
    * at least enough succeeded to bring-up NSH with perhaps reduced
    * capabilities.