acassis commented on code in PR #11300:
URL: https://github.com/apache/nuttx/pull/11300#discussion_r1410766661


##########
arch/xtensa/src/esp32s2/Kconfig:
##########
@@ -1020,6 +1024,49 @@ config ESP32S2_SPIRAM_IGNORE_NOTFOUND
 
 endmenu # SPI RAM Configuration
 
+menu "RTC Configuration"
+       depends on ESP32S2_RTC
+
+choice ESP32S2_RTC_CLK_SRC
+       prompt "RTC clock source"
+       default ESP32S2_RTC_CLK_INT_RC
+       ---help---
+               Choose which clock is used as RTC clock source.
+
+               - "Internal 90kHz oscillator" option provides lowest deep sleep 
current
+                       consumption, and does not require extra external 
components. However
+                       frequency stability with respect to temperature is 
poor, so time may
+                       drift in deep/light sleep modes.
+               - "External 32kHz crystal" provides better frequency stability, 
at the
+                       expense of slightly higher (1uA) deep sleep current 
consumption.
+               - "External 32kHz oscillator" allows using 32kHz clock 
generated by an
+                       external circuit. In this case, external clock signal 
must be connected
+                       to 32K_XN pin. Amplitude should be <1.2V in case of 
sine wave signal,
+                       and <1V in case of square wave signal. Common mode 
voltage should be
+                       0.1 < Vcm < 0.5Vamp, where Vamp is the signal amplitude.
+                       Additionally, 1nF capacitor must be connected between 
32K_XP pin and
+                       ground. 32K_XP pin can not be used as a GPIO in this 
case.
+               - "Internal 8.5MHz oscillator divided by 256" option results in 
higher
+                       deep sleep current (by 5uA) but has better frequency 
stability than
+                       the internal 90kHz oscillator. It does not require 
external components.
+
+config ESP32S2_RTC_CLK_INT_RC
+       bool "Internal 90kHz RC oscillator"

Review Comment:
   ```suggestion
        bool "Internal 90KHz RC oscillator"



##########
arch/xtensa/src/esp32s2/Kconfig:
##########
@@ -1020,6 +1024,49 @@ config ESP32S2_SPIRAM_IGNORE_NOTFOUND
 
 endmenu # SPI RAM Configuration
 
+menu "RTC Configuration"
+       depends on ESP32S2_RTC
+
+choice ESP32S2_RTC_CLK_SRC
+       prompt "RTC clock source"
+       default ESP32S2_RTC_CLK_INT_RC
+       ---help---
+               Choose which clock is used as RTC clock source.
+
+               - "Internal 90kHz oscillator" option provides lowest deep sleep 
current
+                       consumption, and does not require extra external 
components. However
+                       frequency stability with respect to temperature is 
poor, so time may
+                       drift in deep/light sleep modes.
+               - "External 32kHz crystal" provides better frequency stability, 
at the
+                       expense of slightly higher (1uA) deep sleep current 
consumption.
+               - "External 32kHz oscillator" allows using 32kHz clock 
generated by an
+                       external circuit. In this case, external clock signal 
must be connected
+                       to 32K_XN pin. Amplitude should be <1.2V in case of 
sine wave signal,
+                       and <1V in case of square wave signal. Common mode 
voltage should be
+                       0.1 < Vcm < 0.5Vamp, where Vamp is the signal amplitude.
+                       Additionally, 1nF capacitor must be connected between 
32K_XP pin and
+                       ground. 32K_XP pin can not be used as a GPIO in this 
case.
+               - "Internal 8.5MHz oscillator divided by 256" option results in 
higher
+                       deep sleep current (by 5uA) but has better frequency 
stability than
+                       the internal 90kHz oscillator. It does not require 
external components.
+
+config ESP32S2_RTC_CLK_INT_RC
+       bool "Internal 90kHz RC oscillator"
+
+config ESP32S2_RTC_CLK_EXT_XTAL
+       bool "External 32kHz crystal"
+       select ESP_SYSTEM_RTC_EXT_XTAL
+
+config ESP32S2_RTC_CLK_EXT_OSC
+       bool "External 32kHz oscillator at 32K_XN pin"

Review Comment:
   ```suggestion
        bool "External 32KHz oscillator at 32K_XN pin"



##########
arch/xtensa/src/esp32s2/esp32s2_rtc.c:
##########
@@ -0,0 +1,2690 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_rtc.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 <stdint.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/spinlock.h>
+
+#include "clock/clock.h"
+
+#include "esp32s2_clockconfig.h"
+#include "esp32s2_rt_timer.h"
+
+#include "hardware/esp32s2_rtccntl.h"
+#include "hardware/esp32s2_rtc_io.h"
+#include "hardware/esp32s2_system.h"
+#include "hardware/esp32s2_i2s.h"
+
+#include "hardware/esp32s2_rtccntl.h"
+#include "hardware/esp32s2_rtc_io.h"
+#include "hardware/esp32s2_system.h"
+#include "hardware/esp32s2_tim.h"
+#include "hardware/regi2c_ctrl.h"
+#include "hardware/esp32s2_spi_mem_reg.h"
+#include "hardware/esp32s2_extmem.h"
+#include "hardware/esp32s2_syscon.h"
+#include "hardware/regi2c_bbpll.h"
+#include "hardware/regi2c_lp_bias.h"
+
+#include "xtensa.h"
+#include "xtensa_attr.h"
+
+#include "esp32s2_rtc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Various delays to be programmed into power control state machines */
+
+#define RTC_CNTL_XTL_BUF_WAIT_SLP   2
+#define RTC_CNTL_CK8M_WAIT_SLP      4
+#define OTHER_BLOCKS_POWERUP        1
+#define OTHER_BLOCKS_WAIT           1
+
+#define ROM_RAM_POWERUP_CYCLES   OTHER_BLOCKS_POWERUP
+#define ROM_RAM_WAIT_CYCLES      OTHER_BLOCKS_WAIT
+
+#define WIFI_POWERUP_CYCLES      OTHER_BLOCKS_POWERUP
+#define WIFI_WAIT_CYCLES         OTHER_BLOCKS_WAIT
+
+#define RTC_POWERUP_CYCLES       OTHER_BLOCKS_POWERUP
+#define RTC_WAIT_CYCLES          OTHER_BLOCKS_WAIT
+
+#define DG_WRAP_POWERUP_CYCLES   OTHER_BLOCKS_POWERUP
+#define DG_WRAP_WAIT_CYCLES      OTHER_BLOCKS_WAIT
+
+#define RTC_MEM_POWERUP_CYCLES   OTHER_BLOCKS_POWERUP
+#define RTC_MEM_WAIT_CYCLES      OTHER_BLOCKS_WAIT
+
+#define RTC_CNTL_PLL_BUF_WAIT_SLP   2
+
+#define DELAY_FAST_CLK_SWITCH       3
+
+#define XTAL_32K_DAC_VAL            1
+#define XTAL_32K_DRES_VAL           3
+#define XTAL_32K_DBIAS_VAL          0
+
+#define XTAL_32K_EXT_DAC_VAL        2
+#define XTAL_32K_EXT_DRES_VAL       3
+#define XTAL_32K_EXT_DBIAS_VAL      1
+
+#define DELAY_SLOW_CLK_SWITCH       300
+
+#define DELAY_8M_ENABLE             50
+
+#define RETRY_CAL_EXT               1
+
+/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL.
+ * The ideal value (assuming 32768 Hz frequency)
+ * is 1000000/32768*(2**19) = 16*10^6.
+ */
+
+#define MIN_32K_XTAL_CAL_VAL        15000000L
+
+/* Frequency of the 8M oscillator is 8.5MHz +/- 5%, at the default DCAP
+ * setting
+ */
+
+#define RTC_FAST_CLK_FREQ_8M        8500000
+#define RTC_SLOW_CLK_FREQ_90K       90000
+#define RTC_SLOW_CLK_FREQ_8MD256    (RTC_FAST_CLK_FREQ_8M / 256)
+#define RTC_SLOW_CLK_FREQ_32K       32768
+
+/* Number of fractional bits in values returned by rtc_clk_cal */
+
+#define RTC_CLK_CAL_FRACT           19
+
+/* With the default value of CK8M_DFREQ,
+ * 8M clock frequency is 8.5 MHz +/- 7%
+ */
+
+#define RTC_FAST_CLK_FREQ_APPROX    8500000
+#define RCT_FAST_D256_FREQ_APPROX   (RTC_FAST_CLK_FREQ_APPROX / 256)
+#define RTC_SLOW_CLK_FREQ_APPROX    32768
+
+/* Disable logging from the ROM code. */
+
+#define RTC_DISABLE_ROM_LOG ((1 << 0) | (1 << 16))
+
+#define RTC_SLEEP_PD_DIG                BIT(0)  /* Deep sleep (power down 
digital domain) */
+#define RTC_SLEEP_PD_RTC_PERIPH         BIT(1)  /* Power down RTC peripherals 
*/
+#define RTC_SLEEP_PD_RTC_SLOW_MEM       BIT(2)  /* Power down RTC SLOW memory 
*/
+#define RTC_SLEEP_PD_RTC_FAST_MEM       BIT(3)  /* Power down RTC FAST memory 
*/
+#define RTC_SLEEP_PD_RTC_MEM_FOLLOW_CPU BIT(4)  /* RTC FAST and SLOW memories 
are automatically powered up and down along with the CPU */
+#define RTC_SLEEP_PD_VDDSDIO            BIT(5)  /* Power down VDDSDIO 
regulator */
+#define RTC_SLEEP_PD_WIFI               BIT(6)  /* Power down WIFI */
+#define RTC_SLEEP_PD_INT_8M             BIT(7)  /* Power down Internal 8M 
oscillator */
+#define RTC_SLEEP_PD_XTAL               BIT(8)  /* Power down main XTAL */
+
+/* These flags are not power domains, but will affect some sleep parameters */
+
+#define RTC_SLEEP_DIG_USE_8M            BIT(16)
+#define RTC_SLEEP_USE_ADC_TESEN_MONITOR BIT(17)
+#define RTC_SLEEP_NO_ULTRA_LOW          BIT(18) /* Avoid using ultra low power 
in deep sleep,
+                                                 * in which RTCIO cannot be 
used as input,
+                                                 * and RTCMEM can't work under 
high temperature */
+
+#define is_dslp(pd_flags)   ((pd_flags) & RTC_SLEEP_PD_DIG)
+
+/* set sleep_init default param. */
+
+#define RTC_CNTL_DBG_ATTEN_LIGHTSLEEP_DEFAULT 6
+#define RTC_CNTL_DBG_ATTEN_LIGHTSLEEP_NODROP  0
+#define RTC_CNTL_DBG_ATTEN_DEEPSLEEP_DEFAULT  15
+#define RTC_CNTL_DBG_ATTEN_DEEPSLEEP_NODROP   0
+#define RTC_CNTL_BIASSLP_SLEEP_DEFAULT        1
+#define RTC_CNTL_BIASSLP_SLEEP_ON             0
+#define RTC_CNTL_PD_CUR_SLEEP_DEFAULT         1
+#define RTC_CNTL_PD_CUR_SLEEP_ON              0
+
+#define RTC_CNTL_DBG_ATTEN_MONITOR_DEFAULT  0
+#define RTC_CNTL_BIASSLP_MONITOR_DEFAULT    1
+#define RTC_CNTL_BIASSLP_MONITOR_ON         0
+#define RTC_CNTL_PD_CUR_MONITOR_DEFAULT     1
+#define RTC_CNTL_PD_CUR_MONITOR_ON          0
+
+/* Approximate mapping of voltages to RTC_CNTL_DBIAS_WAK, RTC_CNTL_DBIAS_SLP,
+ * RTC_CNTL_DIG_DBIAS_WAK, RTC_CNTL_DIG_DBIAS_SLP values.
+ * Valid if RTC_CNTL_DBG_ATTEN is 0.
+ */
+
+#define RTC_CNTL_DBIAS_0V90 0   /* sleep dig_dbias & rtc_dbias */
+#define RTC_CNTL_DBIAS_0V95 1   /* digital voltage */
+#define RTC_CNTL_DBIAS_1V00 2
+#define RTC_CNTL_DBIAS_1V05 3
+#define RTC_CNTL_DBIAS_1V10 4
+#define RTC_CNTL_DBIAS_1V15 5
+#define RTC_CNTL_DBIAS_1V20 6
+#define RTC_CNTL_DBIAS_1V25 7   /* voltage is about 1.34v in fact */
+
+/* Default initializer for esp32s2_rtc_sleep_config_t
+ * This initializer sets all fields to "reasonable" values
+ * (e.g. suggested for production use) based on a combination
+ * of RTC_SLEEP_PD_x flags.
+ */
+
+#define RTC_SLEEP_CONFIG_DEFAULT(sleep_flags) {                             \
+  .lslp_mem_inf_fpu = 0,                                                    \
+  .rtc_mem_inf_follow_cpu = ((sleep_flags) &                                \
+                             RTC_SLEEP_PD_RTC_MEM_FOLLOW_CPU) ? 1 : 0,      \
+  .rtc_fastmem_pd_en = ((sleep_flags) & RTC_SLEEP_PD_RTC_FAST_MEM) ? 1 : 0, \
+  .rtc_slowmem_pd_en = ((sleep_flags) & RTC_SLEEP_PD_RTC_SLOW_MEM) ? 1 : 0, \
+  .rtc_peri_pd_en = ((sleep_flags) & RTC_SLEEP_PD_RTC_PERIPH) ? 1 : 0,      \
+  .wifi_pd_en = (sleep_flags & RTC_SLEEP_PD_WIFI) ? 1 : 0,                  \
+  .int_8m_pd_en = (sleep_flags & RTC_SLEEP_PD_INT_8M) ? 1 : 0,              \
+  .deep_slp = ((sleep_flags) & RTC_SLEEP_PD_DIG) ? 1 : 0,                   \
+  .wdt_flashboot_mod_en = 0,                                                \
+  .dig_dbias_wak = RTC_CNTL_DBIAS_1V10,                                     \
+  .dig_dbias_slp = is_dslp(sleep_flags) ? RTC_CNTL_DBIAS_SLP                \
+                   : !((sleep_flags) & RTC_SLEEP_PD_INT_8M) ?               \
+                   RTC_CNTL_DBIAS_1V10 : RTC_CNTL_DBIAS_SLP,                \
+  .rtc_dbias_slp = is_dslp(sleep_flags) ? RTC_CNTL_DBIAS_SLP                \
+                   : !((sleep_flags) & RTC_SLEEP_PD_INT_8M) ?               \
+                   RTC_CNTL_DBIAS_1V10 : RTC_CNTL_DBIAS_SLP,                \
+  .bias_sleep_monitor = 0,                                                  \
+  .dbg_atten_slp = 0,                                                       \
+  .pd_cur_monitor = 0,                                                      \
+  .pd_cur_slp = 0,                                                          \
+  .rtc_regulator_fpu = 0,                                                   \
+  .rtc_dbias_wak = RTC_CNTL_DBIAS_1V10,                                     \
+  .vddsdio_pd_en = ((sleep_flags) & RTC_SLEEP_PD_VDDSDIO) ? 1 : 0,          \
+  .xtal_fpu = ((sleep_flags) & RTC_SLEEP_PD_XTAL) ? 0 : 1,                  \
+  .deep_slp_reject = 1,                                                     \
+  .light_slp_reject = 1,                                                    \
+}
+
+#define X32K_CONFIG_DEFAULT() { \
+  .dac = 3,                     \
+  .dres = 3,                    \
+  .dgm = 3,                     \
+  .dbuf = 1,                    \
+}
+
+/* Initializer for rtc_sleep_pd_config_t which
+ * sets all flags to the same value
+ */
+
+#define RTC_SLEEP_PD_CONFIG_ALL(val) {  \
+  .dig_fpu = (val),                     \
+  .rtc_fpu = (val),                     \
+  .cpu_fpu = (val),                     \
+  .i2s_fpu = (val),                     \
+  .bb_fpu = (val),                      \
+  .nrx_fpu = (val),                     \
+  .fe_fpu = (val),                      \
+}
+
+/* Default initializer of struct esp32s2_rtc_config_s.
+ * This initializer sets all fields to "reasonable" values
+ * (e.g. suggested for production use).
+ */
+
+#define RTC_CONFIG_DEFAULT() {                \
+  .ck8m_wait = RTC_CNTL_CK8M_WAIT_DEFAULT,    \
+  .xtal_wait = RTC_CNTL_XTL_BUF_WAIT_DEFAULT, \
+  .pll_wait  = RTC_CNTL_PLL_BUF_WAIT_DEFAULT, \
+  .clkctl_init = 1,                           \
+  .pwrctl_init = 1,                           \
+  .rtc_dboost_fpd = 1,                        \
+  .xtal_fpu = 0,                              \
+  .bbpll_fpu = 0,                             \
+  .cpu_waiti_clk_gate = 1,                    \
+  .cali_ocode = 0                             \
+}
+
+/* The magic data for the struct esp32s2_rtc_backup_s that is in RTC slow
+ * memory.
+ */
+
+#define MAGIC_RTC_SAVE UINT64_C(0x11223344556677)
+
+/* 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
+ ****************************************************************************/
+
+/* RTC power and clock control initialization settings */
+
+struct esp32s2_rtc_priv_s
+{
+  uint32_t ck8m_wait : 8;          /* Number of rtc_fast_clk cycles to wait 
for 8M clock to be ready */
+  uint32_t xtal_wait : 8;          /* Number of rtc_fast_clk cycles to wait 
for XTAL clock to be ready */
+  uint32_t pll_wait : 8;           /* Number of rtc_fast_clk cycles to wait 
for PLL to be ready */
+  uint32_t clkctl_init : 1;        /* Perform clock control related 
initialization */
+  uint32_t pwrctl_init : 1;        /* Perform power control related 
initialization */
+  uint32_t rtc_dboost_fpd : 1;     /* Force power down RTC_DBOOST */
+  uint32_t xtal_fpu : 1;
+  uint32_t bbpll_fpu : 1;
+  uint32_t cpu_waiti_clk_gate : 1;
+  uint32_t cali_ocode : 1;         /* Calibrate Ocode to make bangap voltage 
more precise. */
+};
+
+/* sleep configuration for rtc_sleep_init function */
+
+struct esp32s2_rtc_sleep_config_s
+{
+  uint32_t lslp_mem_inf_fpu : 1;       /* force normal voltage in sleep mode 
(digital domain memory) */
+  uint32_t rtc_mem_inf_follow_cpu : 1; /* keep low voltage in sleep mode (even 
if ULP/touch is used) */
+  uint32_t rtc_fastmem_pd_en : 1;      /* power down RTC fast memory */
+  uint32_t rtc_slowmem_pd_en : 1;      /* power down RTC slow memory */
+  uint32_t rtc_peri_pd_en : 1;         /* power down RTC peripherals */
+  uint32_t wifi_pd_en : 1;             /* power down WiFi */
+  uint32_t int_8m_pd_en : 1;           /* Power down Internal 8M oscillator */
+  uint32_t deep_slp : 1;               /* power down digital domain */
+  uint32_t wdt_flashboot_mod_en : 1;   /* enable WDT flashboot mode */
+  uint32_t dig_dbias_wak : 3;          /* set bias for digital domain, in 
active mode */
+  uint32_t dig_dbias_slp : 3;          /* set bias for digital domain, in 
sleep mode */
+  uint32_t rtc_dbias_wak : 3;          /* set bias for RTC domain, in active 
mode */
+  uint32_t rtc_dbias_slp : 3;          /* set bias for RTC domain, in sleep 
mode */
+  uint32_t bias_sleep_monitor : 1;     /* circuit control parameter, in 
monitor mode */
+  uint32_t dbg_atten_slp : 4;          /* voltage parameter, in sleep mode */
+  uint32_t bias_sleep_slp : 1;         /* circuit control parameter, in sleep 
mode */
+  uint32_t pd_cur_monitor : 1;         /* circuit control parameter, in 
monitor mode */
+  uint32_t pd_cur_slp : 1;             /* circuit control parameter, in sleep 
mode */
+  uint32_t vddsdio_pd_en : 1;          /* power down VDDSDIO regulator */
+  uint32_t xtal_fpu : 1;               /* keep main XTAL powered up in sleep */
+  uint32_t rtc_regulator_fpu  : 1;     /* keep rtc regulator powered up in 
sleep */
+  uint32_t deep_slp_reject : 1;        /* enable deep sleep reject */
+  uint32_t light_slp_reject : 1;       /* enable light sleep reject */
+};
+
+/* Power down flags for rtc_sleep_pd function */
+
+struct esp32s2_rtc_sleep_pd_config_s
+{
+  uint32_t dig_fpu : 1;    /* Set to 1 to power down digital part in sleep */
+  uint32_t rtc_fpu : 1;    /* Set to 1 to power down RTC memories in sleep */
+  uint32_t cpu_fpu : 1;    /* Set to 1 to power down digital memories and CPU 
in sleep */
+  uint32_t i2s_fpu : 1;    /* Set to 1 to power down I2S in sleep */
+  uint32_t bb_fpu : 1;     /* Set to 1 to power down Wi-Fi in sleep */
+  uint32_t nrx_fpu : 1;    /* Set to 1 to power down Wi-Fi in sleep */
+  uint32_t fe_fpu : 1;     /* Set to 1 to power down Wi-Fi in sleep */
+};
+
+#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 void *ac_arg;         /* Argument to pass with the callback 
function */
+  uint64_t deadline_us;
+  uint8_t index;
+};
+#endif
+
+/* crystal configuration */
+
+struct esp32s2_rtc_x32k_config_s
+{
+  uint32_t dac : 6;
+  uint32_t dres : 3;
+  uint32_t dgm : 3;
+  uint32_t dbuf: 1;
+};
+
+struct esp32s2_rtc_backup_s
+{
+  uint64_t magic;
+  int64_t  offset;              /* Offset time from RTC HW value */
+  int64_t  reserved0;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* APB Frequency */
+
+static uint32_t g_apb_freq;
+
+/* 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 esp32s2_rtc_backup_s rtc_saved_data;
+
+/* Saved data for persistent RTC time */
+
+static struct esp32s2_rtc_backup_s *g_rtc_save;
+static bool g_rt_timer_enabled = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void IRAM_ATTR esp32s2_rtc_sleep_pd(
+                      struct esp32s2_rtc_sleep_pd_config_s cfg);
+static inline bool esp32s2_clk_val_is_valid(uint32_t val);
+static void IRAM_ATTR esp32s2_rtc_clk_fast_freq_set(
+                      enum esp32s2_rtc_fast_freq_e fast_freq);
+static uint32_t IRAM_ATTR esp32s2_rtc_clk_cal_internal(
+                enum esp32s2_rtc_cal_sel_e cal_clk,
+                uint32_t slowclk_cycles);
+static int  IRAM_ATTR esp32s2_rtc_clk_slow_freq_get(void);
+static void IRAM_ATTR esp32s2_rtc_clk_slow_freq_set(
+                      enum esp32s2_rtc_slow_freq_e slow_freq);
+static void esp32s2_select_rtc_slow_clk(enum esp32s2_slow_clk_sel_e
+                                        slow_clk);
+static void esp32s2_rtc_clk_32k_enable(bool enable);
+static void IRAM_ATTR esp32s2_rtc_clk_8m_enable(bool clk_8m_en,
+                                                bool d256_en);
+static void esp32s2_rtc_calibrate_ocode(void);
+static void IRAM_ATTR esp32s2_rtc_clk_bbpll_disable(void);
+static void IRAM_ATTR esp32s2_rtc_bbpll_configure(
+                     enum esp32s2_rtc_xtal_freq_e xtal_freq, int pll_freq);
+static void IRAM_ATTR esp32s2_rtc_clk_cpu_freq_to_8m(void);
+static void IRAM_ATTR esp32s2_rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz);
+
+void IRAM_ATTR esp32s2_rtc_bbpll_disable(void);
+void esp32s2_rtc_clk_apb_freq_update(uint32_t apb_freq);
+void IRAM_ATTR esp32s2_rtc_update_to_xtal(int freq, int div);
+static void esp32s2_wait_dig_dbias_valid(uint64_t rtc_cycles);
+uint32_t esp32s2_rtc_clk_apb_freq_get(void);
+
+#ifdef CONFIG_RTC_ALARM
+static void IRAM_ATTR esp32s2_rt_cb_handler(void *arg);
+#endif
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+volatile bool g_rtc_enabled = false;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Set the real CPU ticks per us to the ets, so that ets_delay_us
+ * will be accurate. Call this function when CPU frequency is changed.
+ */
+
+extern void ets_update_cpu_frequency(uint32_t ticks_per_us);
+
+/****************************************************************************
+ * Name: esp32s2_rtc_sleep_pd
+ *
+ * Description:
+ *   Configure whether certain peripherals are powered up in deep sleep.
+ *
+ * Input Parameters:
+ *   cfg - power down flags as rtc_sleep_pu_config_t structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void IRAM_ATTR
+        esp32s2_rtc_sleep_pd(struct esp32s2_rtc_sleep_pd_config_s cfg)
+{
+  REG_SET_FIELD(RTC_CNTL_DIG_PWC_REG,
+                RTC_CNTL_LSLP_MEM_FORCE_PU, cfg.dig_fpu);
+  REG_SET_FIELD(RTC_CNTL_PWC_REG,
+                RTC_CNTL_FASTMEM_FORCE_LPU, cfg.rtc_fpu);
+  REG_SET_FIELD(RTC_CNTL_PWC_REG,
+                RTC_CNTL_SLOWMEM_FORCE_LPU, cfg.rtc_fpu);
+  REG_SET_FIELD(SYSCON_FRONT_END_MEM_PD_REG,
+                SYSCON_DC_MEM_FORCE_PU, cfg.fe_fpu);
+  REG_SET_FIELD(SYSCON_FRONT_END_MEM_PD_REG,
+                SYSCON_PBUS_MEM_FORCE_PU, cfg.fe_fpu);
+  REG_SET_FIELD(SYSCON_FRONT_END_MEM_PD_REG,
+                SYSCON_AGC_MEM_FORCE_PU, cfg.fe_fpu);
+  REG_SET_FIELD(BBPD_CTRL, BB_FFT_FORCE_PU, cfg.bb_fpu);
+  REG_SET_FIELD(BBPD_CTRL, BB_DC_EST_FORCE_PU, cfg.bb_fpu);
+  REG_SET_FIELD(NRXPD_CTRL, NRX_RX_ROT_FORCE_PU, cfg.nrx_fpu);
+  REG_SET_FIELD(NRXPD_CTRL, NRX_VIT_FORCE_PU, cfg.nrx_fpu);
+  REG_SET_FIELD(NRXPD_CTRL, NRX_DEMAP_FORCE_PU, cfg.nrx_fpu);
+  REG_SET_FIELD(FE_GEN_CTRL, FE_IQ_EST_FORCE_PU, cfg.fe_fpu);
+  REG_SET_FIELD(FE2_TX_INTERP_CTRL, FE2_TX_INF_FORCE_PU, cfg.fe_fpu);
+}
+
+/****************************************************************************
+ * Name: esp32s2_rtc_clk_fast_freq_set
+ *
+ * Description:
+ *   Select source for RTC_FAST_CLK.
+ *
+ * Input Parameters:
+ *   fast_freq - Clock source (one of enum esp32s2_rtc_fast_freq_e values)
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void IRAM_ATTR esp32s2_rtc_clk_fast_freq_set(
+                      enum esp32s2_rtc_fast_freq_e fast_freq)
+{
+  REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL,
+                fast_freq);
+  up_udelay(DELAY_FAST_CLK_SWITCH);
+}
+
+/****************************************************************************
+ * Name: esp32s2_clk_val_is_valid
+ *
+ * Description:
+ *   Values of RTC_XTAL_FREQ_REG and RTC_APB_FREQ_REG are
+ *   stored as two copies in lower and upper 16-bit halves.
+ *   These are the routines to work with such a representation.
+ *
+ * Input Parameters:
+ *   val - register value
+ *
+ * Returned Value:
+ *   true:  Valid register value.
+ *   false: Invalid register value.
+ *
+ ****************************************************************************/
+
+static inline bool esp32s2_clk_val_is_valid(uint32_t val)
+{
+  return (val & 0xffff) == ((val >> 16) & 0xffff)
+                        && val != 0 && val != UINT32_MAX;
+}
+
+/****************************************************************************
+ * Name: esp32s2_rtc_clk_cal_internal
+ *
+ * Description:
+ *   Clock calibration function used by rtc_clk_cal and rtc_clk_cal_ratio
+ *
+ * Input Parameters:
+ *   cal_clk        - which clock to calibrate
+ *   slowclk_cycles - number of slow clock cycles to count.
+ *
+ * Returned Value:
+ *   Number of XTAL clock cycles within the given number of slow clock
+ *   cycles.
+ *   In case of error, return 0 cycle.
+ *
+ ****************************************************************************/
+
+static uint32_t IRAM_ATTR esp32s2_rtc_clk_cal_internal(
+                enum esp32s2_rtc_cal_sel_e cal_clk, uint32_t slowclk_cycles)
+{
+  uint32_t expected_freq;
+  uint32_t us_time_estimate;
+  uint32_t clks_state;
+  uint32_t clks_mask;
+  uint32_t cal_val;
+  enum esp32s2_rtc_slow_freq_e slow_freq;
+
+  /* Get the current state */
+
+  clks_mask  = (RTC_CNTL_DIG_XTAL32K_EN_M | RTC_CNTL_DIG_CLK8M_D256_EN_M);
+  clks_state = getreg32(RTC_CNTL_CLK_CONF_REG);
+  clks_state &= clks_mask;
+
+  /* On ESP32S2, choosing RTC_CAL_RTC_MUX results in calibration of
+   * the 150k RTC clock regardless of the currenlty selected SLOW_CLK.
+   * The following code emulates ESP32 behavior
+   */
+
+  if (cal_clk == RTC_CAL_RTC_MUX)
+    {
+      slow_freq = esp32s2_rtc_clk_slow_freq_get();
+      if (slow_freq == RTC_SLOW_FREQ_32K_XTAL)
+        {
+          cal_clk = RTC_CAL_32K_XTAL;
+        }
+      else if (slow_freq == RTC_SLOW_FREQ_8MD256)
+        {
+          cal_clk = RTC_CAL_8MD256;
+        }
+    }
+  else if (cal_clk == RTC_CAL_INTERNAL_OSC)
+        {
+          cal_clk = RTC_CAL_RTC_MUX;
+        }
+
+  /* Enable requested clock (150k clock is always on) */
+
+  if (cal_clk == RTC_CAL_32K_XTAL && !(clks_state & RTC_CNTL_DIG_XTAL32K_EN))
+    {
+      REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, 1);
+    }
+  else if (cal_clk == RTC_CAL_8MD256 &&
+           !(clks_state & RTC_CNTL_DIG_CLK8M_D256_EN))
+    {
+      modifyreg32(RTC_CNTL_CLK_CONF_REG, 0, RTC_CNTL_DIG_CLK8M_D256_EN);
+    }
+
+  /* Prepare calibration */
+
+  REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cal_clk);
+  modifyreg32(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING, 0);
+  REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, slowclk_cycles);
+
+  /* Figure out how long to wait for calibration to finish */
+
+  slow_freq = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG,
+                            RTC_CNTL_ANA_CLK_RTC_SEL);
+
+  if (cal_clk == RTC_CAL_32K_XTAL || slow_freq == RTC_SLOW_FREQ_32K_XTAL)
+    {
+      expected_freq = 32768; /* standard 32k XTAL */
+    }
+  else if (cal_clk == RTC_CAL_8MD256 || slow_freq == RTC_SLOW_FREQ_8MD256)
+    {
+      expected_freq = RTC_FAST_CLK_FREQ_APPROX / 256;
+    }
+  else
+    {
+      expected_freq = 150000; /* 150k internal oscillator */
+    }
+
+  us_time_estimate = (uint32_t) (((uint64_t)slowclk_cycles) *
+                                           MHZ / expected_freq);
+
+  /* Start calibration */
+
+  modifyreg32(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START, 0);
+  modifyreg32(TIMG_RTCCALICFG_REG(0), 0, TIMG_RTC_CALI_START);
+
+  /* Wait the expected time calibration should take */
+
+  up_udelay(us_time_estimate);
+
+  /* Wait for calibration to finish up to another us_time_estimate */
+
+  while (true)
+    {
+      if (getreg32(TIMG_RTCCALICFG_REG(0)) & TIMG_RTC_CALI_RDY)
+        {
+          cal_val = REG_GET_FIELD(TIMG_RTCCALICFG1_REG(0),
+                                  TIMG_RTC_CALI_VALUE);
+          break;
+        }
+
+      if (GET_PERI_REG_MASK(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT))
+        {
+          cal_val = 0;
+          break;
+        }
+    }
+
+  CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
+
+  /* Restore the previous clocks states */
+
+  modifyreg32(RTC_CNTL_CLK_CONF_REG, clks_mask, clks_state);
+
+  return cal_val;
+}
+
+static void esp32s2_wait_dig_dbias_valid(uint64_t rtc_cycles)
+{
+  int slow_clk_freq = esp32s2_rtc_clk_slow_freq_get();
+  int cal_clk = RTC_CAL_RTC_MUX;
+
+  if (slow_clk_freq == RTC_SLOW_FREQ_32K_XTAL)
+    {
+      cal_clk = RTC_CAL_32K_XTAL;
+    }
+  else if (slow_clk_freq == RTC_SLOW_FREQ_8MD256)
+    {
+      cal_clk = RTC_CAL_8MD256;
+    }
+
+  esp32s2_rtc_clk_cal(cal_clk, rtc_cycles);
+}
+
+/****************************************************************************
+ * Name: esp32s2_rtc_update_to_xtal
+ *
+ * Description:
+ *   Switch to XTAL frequency, does not disable the PLL
+ *
+ * Input Parameters:
+ *   freq -  XTAL frequency
+ *   div  -  REF_TICK divider
+ *
+ * Returned Value:
+ *   none
+ *
+ ****************************************************************************/
+
+void IRAM_ATTR esp32s2_rtc_update_to_xtal(int freq, int div)
+{
+  ets_update_cpu_frequency(freq);
+  esp32s2_wait_dig_dbias_valid(2);
+
+  /* Set divider from XTAL to APB clock.
+   * Need to set divider to 1 (reg. value 0) first.
+   */
+
+  REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
+  REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, div - 1);
+
+  /* No need to adjust the REF_TICK.
+   * Switch clock source.
+   */
+
+  REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG,
+                SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_XTAL);
+
+  esp32s2_rtc_clk_apb_freq_update(freq * MHZ);
+}
+
+/****************************************************************************
+ * Name: esp32s2_rtc_clk_slow_freq_set
+ *
+ * Description:
+ *   Select source for RTC_SLOW_CLK
+ *
+ * Input Parameters:
+ *   slow_freq - Select source for RTC_SLOW_CLK
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void IRAM_ATTR esp32s2_rtc_clk_slow_freq_set(
+                      enum esp32s2_rtc_slow_freq_e slow_freq)
+{
+  REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL,
+                slow_freq);
+
+  REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN,
+               (slow_freq == RTC_SLOW_FREQ_32K_XTAL) ? 1 : 0);
+
+  up_udelay(DELAY_SLOW_CLK_SWITCH);
+}
+
+/****************************************************************************
+ * Name: esp32s2_rtc_clk_32k_enable
+ *
+ * Description:
+ *   Enable 32 kHz XTAL oscillator
+ *
+ * Input Parameters:
+ *   enable - boolean Enable/Disable
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void IRAM_ATTR esp32s2_rtc_clk_32k_enable(bool enable)
+{
+  if (enable)
+    {
+      struct esp32s2_rtc_x32k_config_s cfg = X32K_CONFIG_DEFAULT();
+
+      modifyreg32(RTCIO_XTAL_32P_PAD_REG, 0, RTCIO_X32P_MUX_SEL);
+      modifyreg32(RTCIO_XTAL_32N_PAD_REG, 0, RTCIO_X32N_MUX_SEL);
+
+      REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG,
+                    RTC_CNTL_DAC_XTAL_32K, cfg.dac);
+      REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG,
+                    RTC_CNTL_DRES_XTAL_32K, cfg.dres);
+      REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG,
+                    RTC_CNTL_DGM_XTAL_32K, cfg.dgm);
+      REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG,
+                    RTC_CNTL_DBUF_XTAL_32K, cfg.dbuf);
+      modifyreg32(RTC_CNTL_EXT_XTL_CONF_REG, 0,
+                  RTC_CNTL_XPD_XTAL_32K);
+    }
+  else
+    {
+      modifyreg32(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K,
+                  RTC_CNTL_XTAL32K_XPD_FORCE);
+    }
+}
+
+/****************************************************************************
+ * Name: esp32s2_rtc_clk_8m_enable
+ *
+ * Description:
+ *   Enable or disable 8 MHz internal oscillator
+ *
+ * Input Parameters:
+ *   clk_8m_en - true to enable 8MHz generator, false to disable
+ *   d256_en   - true to enable /256 divider, false to disable
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void IRAM_ATTR esp32s2_rtc_clk_8m_enable(bool clk_8m_en, bool d256_en)
+{
+  if (clk_8m_en)
+    {
+      modifyreg32(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M, 0);
+
+      /* no need to wait once enabled by software */
+
+      REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, 1);
+      if (d256_en)
+        {
+          modifyreg32(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV, 0);
+        }
+      else
+        {
+          modifyreg32(RTC_CNTL_CLK_CONF_REG, 0, RTC_CNTL_ENB_CK8M_DIV);
+        }
+
+      up_udelay(DELAY_8M_ENABLE);
+    }
+  else
+    {
+      modifyreg32(RTC_CNTL_CLK_CONF_REG, 0, RTC_CNTL_ENB_CK8M);
+      REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT,
+                    RTC_CNTL_CK8M_WAIT_DEFAULT);
+    }
+}
+
+/****************************************************************************
+ * Name: esp32s2_select_rtc_slow_clk
+ *
+ * Description:
+ *   Selects an clock source for RTC.
+ *
+ * Input Parameters:
+ *   slow_clk - RTC SLOW_CLK frequency values
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp32s2_select_rtc_slow_clk(enum esp32s2_slow_clk_sel_e slow_clk)
+{
+  /* Number of times to repeat 32k XTAL calibration before giving up and
+   * switching to the internal RC.
+   */
+
+  int retry_32k_xtal = 0;
+  uint32_t cal_val = 0;
+  uint64_t cal_dividend;
+  enum esp32s2_rtc_slow_freq_e rtc_slow_freq = slow_clk &
+                                               RTC_CNTL_ANA_CLK_RTC_SEL_V;
+
+  do
+    {
+      if (rtc_slow_freq == RTC_SLOW_FREQ_32K_XTAL)
+        {
+          /* 32k XTAL oscillator needs to be enabled and running before

Review Comment:
   ```suggestion
             /* 32KHz XTAL oscillator needs to be enabled and running before



##########
arch/xtensa/src/esp32s2/Kconfig:
##########
@@ -1020,6 +1024,49 @@ config ESP32S2_SPIRAM_IGNORE_NOTFOUND
 
 endmenu # SPI RAM Configuration
 
+menu "RTC Configuration"
+       depends on ESP32S2_RTC
+
+choice ESP32S2_RTC_CLK_SRC
+       prompt "RTC clock source"
+       default ESP32S2_RTC_CLK_INT_RC
+       ---help---
+               Choose which clock is used as RTC clock source.
+
+               - "Internal 90kHz oscillator" option provides lowest deep sleep 
current
+                       consumption, and does not require extra external 
components. However
+                       frequency stability with respect to temperature is 
poor, so time may
+                       drift in deep/light sleep modes.
+               - "External 32kHz crystal" provides better frequency stability, 
at the
+                       expense of slightly higher (1uA) deep sleep current 
consumption.
+               - "External 32kHz oscillator" allows using 32kHz clock 
generated by an
+                       external circuit. In this case, external clock signal 
must be connected
+                       to 32K_XN pin. Amplitude should be <1.2V in case of 
sine wave signal,
+                       and <1V in case of square wave signal. Common mode 
voltage should be
+                       0.1 < Vcm < 0.5Vamp, where Vamp is the signal amplitude.
+                       Additionally, 1nF capacitor must be connected between 
32K_XP pin and
+                       ground. 32K_XP pin can not be used as a GPIO in this 
case.
+               - "Internal 8.5MHz oscillator divided by 256" option results in 
higher
+                       deep sleep current (by 5uA) but has better frequency 
stability than
+                       the internal 90kHz oscillator. It does not require 
external components.
+
+config ESP32S2_RTC_CLK_INT_RC
+       bool "Internal 90kHz RC oscillator"
+
+config ESP32S2_RTC_CLK_EXT_XTAL
+       bool "External 32kHz crystal"

Review Comment:
   ```suggestion
        bool "External 32KHz crystal"



##########
arch/xtensa/src/esp32s2/esp32s2_rtc.c:
##########
@@ -0,0 +1,2690 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_rtc.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 <stdint.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/spinlock.h>
+
+#include "clock/clock.h"
+
+#include "esp32s2_clockconfig.h"
+#include "esp32s2_rt_timer.h"
+
+#include "hardware/esp32s2_rtccntl.h"
+#include "hardware/esp32s2_rtc_io.h"
+#include "hardware/esp32s2_system.h"
+#include "hardware/esp32s2_i2s.h"
+
+#include "hardware/esp32s2_rtccntl.h"
+#include "hardware/esp32s2_rtc_io.h"
+#include "hardware/esp32s2_system.h"
+#include "hardware/esp32s2_tim.h"
+#include "hardware/regi2c_ctrl.h"
+#include "hardware/esp32s2_spi_mem_reg.h"
+#include "hardware/esp32s2_extmem.h"
+#include "hardware/esp32s2_syscon.h"
+#include "hardware/regi2c_bbpll.h"
+#include "hardware/regi2c_lp_bias.h"
+
+#include "xtensa.h"
+#include "xtensa_attr.h"
+
+#include "esp32s2_rtc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Various delays to be programmed into power control state machines */
+
+#define RTC_CNTL_XTL_BUF_WAIT_SLP   2
+#define RTC_CNTL_CK8M_WAIT_SLP      4
+#define OTHER_BLOCKS_POWERUP        1
+#define OTHER_BLOCKS_WAIT           1
+
+#define ROM_RAM_POWERUP_CYCLES   OTHER_BLOCKS_POWERUP
+#define ROM_RAM_WAIT_CYCLES      OTHER_BLOCKS_WAIT
+
+#define WIFI_POWERUP_CYCLES      OTHER_BLOCKS_POWERUP
+#define WIFI_WAIT_CYCLES         OTHER_BLOCKS_WAIT
+
+#define RTC_POWERUP_CYCLES       OTHER_BLOCKS_POWERUP
+#define RTC_WAIT_CYCLES          OTHER_BLOCKS_WAIT
+
+#define DG_WRAP_POWERUP_CYCLES   OTHER_BLOCKS_POWERUP
+#define DG_WRAP_WAIT_CYCLES      OTHER_BLOCKS_WAIT
+
+#define RTC_MEM_POWERUP_CYCLES   OTHER_BLOCKS_POWERUP
+#define RTC_MEM_WAIT_CYCLES      OTHER_BLOCKS_WAIT
+
+#define RTC_CNTL_PLL_BUF_WAIT_SLP   2
+
+#define DELAY_FAST_CLK_SWITCH       3
+
+#define XTAL_32K_DAC_VAL            1
+#define XTAL_32K_DRES_VAL           3
+#define XTAL_32K_DBIAS_VAL          0
+
+#define XTAL_32K_EXT_DAC_VAL        2
+#define XTAL_32K_EXT_DRES_VAL       3
+#define XTAL_32K_EXT_DBIAS_VAL      1
+
+#define DELAY_SLOW_CLK_SWITCH       300
+
+#define DELAY_8M_ENABLE             50
+
+#define RETRY_CAL_EXT               1
+
+/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL.
+ * The ideal value (assuming 32768 Hz frequency)
+ * is 1000000/32768*(2**19) = 16*10^6.
+ */
+
+#define MIN_32K_XTAL_CAL_VAL        15000000L
+
+/* Frequency of the 8M oscillator is 8.5MHz +/- 5%, at the default DCAP
+ * setting
+ */
+
+#define RTC_FAST_CLK_FREQ_8M        8500000
+#define RTC_SLOW_CLK_FREQ_90K       90000
+#define RTC_SLOW_CLK_FREQ_8MD256    (RTC_FAST_CLK_FREQ_8M / 256)
+#define RTC_SLOW_CLK_FREQ_32K       32768
+
+/* Number of fractional bits in values returned by rtc_clk_cal */
+
+#define RTC_CLK_CAL_FRACT           19
+
+/* With the default value of CK8M_DFREQ,
+ * 8M clock frequency is 8.5 MHz +/- 7%
+ */
+
+#define RTC_FAST_CLK_FREQ_APPROX    8500000
+#define RCT_FAST_D256_FREQ_APPROX   (RTC_FAST_CLK_FREQ_APPROX / 256)
+#define RTC_SLOW_CLK_FREQ_APPROX    32768
+
+/* Disable logging from the ROM code. */
+
+#define RTC_DISABLE_ROM_LOG ((1 << 0) | (1 << 16))
+
+#define RTC_SLEEP_PD_DIG                BIT(0)  /* Deep sleep (power down 
digital domain) */
+#define RTC_SLEEP_PD_RTC_PERIPH         BIT(1)  /* Power down RTC peripherals 
*/
+#define RTC_SLEEP_PD_RTC_SLOW_MEM       BIT(2)  /* Power down RTC SLOW memory 
*/
+#define RTC_SLEEP_PD_RTC_FAST_MEM       BIT(3)  /* Power down RTC FAST memory 
*/
+#define RTC_SLEEP_PD_RTC_MEM_FOLLOW_CPU BIT(4)  /* RTC FAST and SLOW memories 
are automatically powered up and down along with the CPU */
+#define RTC_SLEEP_PD_VDDSDIO            BIT(5)  /* Power down VDDSDIO 
regulator */
+#define RTC_SLEEP_PD_WIFI               BIT(6)  /* Power down WIFI */
+#define RTC_SLEEP_PD_INT_8M             BIT(7)  /* Power down Internal 8M 
oscillator */
+#define RTC_SLEEP_PD_XTAL               BIT(8)  /* Power down main XTAL */
+
+/* These flags are not power domains, but will affect some sleep parameters */
+
+#define RTC_SLEEP_DIG_USE_8M            BIT(16)
+#define RTC_SLEEP_USE_ADC_TESEN_MONITOR BIT(17)
+#define RTC_SLEEP_NO_ULTRA_LOW          BIT(18) /* Avoid using ultra low power 
in deep sleep,
+                                                 * in which RTCIO cannot be 
used as input,
+                                                 * and RTCMEM can't work under 
high temperature */
+
+#define is_dslp(pd_flags)   ((pd_flags) & RTC_SLEEP_PD_DIG)
+
+/* set sleep_init default param. */
+
+#define RTC_CNTL_DBG_ATTEN_LIGHTSLEEP_DEFAULT 6
+#define RTC_CNTL_DBG_ATTEN_LIGHTSLEEP_NODROP  0
+#define RTC_CNTL_DBG_ATTEN_DEEPSLEEP_DEFAULT  15
+#define RTC_CNTL_DBG_ATTEN_DEEPSLEEP_NODROP   0
+#define RTC_CNTL_BIASSLP_SLEEP_DEFAULT        1
+#define RTC_CNTL_BIASSLP_SLEEP_ON             0
+#define RTC_CNTL_PD_CUR_SLEEP_DEFAULT         1
+#define RTC_CNTL_PD_CUR_SLEEP_ON              0
+
+#define RTC_CNTL_DBG_ATTEN_MONITOR_DEFAULT  0
+#define RTC_CNTL_BIASSLP_MONITOR_DEFAULT    1
+#define RTC_CNTL_BIASSLP_MONITOR_ON         0
+#define RTC_CNTL_PD_CUR_MONITOR_DEFAULT     1
+#define RTC_CNTL_PD_CUR_MONITOR_ON          0
+
+/* Approximate mapping of voltages to RTC_CNTL_DBIAS_WAK, RTC_CNTL_DBIAS_SLP,
+ * RTC_CNTL_DIG_DBIAS_WAK, RTC_CNTL_DIG_DBIAS_SLP values.
+ * Valid if RTC_CNTL_DBG_ATTEN is 0.
+ */
+
+#define RTC_CNTL_DBIAS_0V90 0   /* sleep dig_dbias & rtc_dbias */
+#define RTC_CNTL_DBIAS_0V95 1   /* digital voltage */
+#define RTC_CNTL_DBIAS_1V00 2
+#define RTC_CNTL_DBIAS_1V05 3
+#define RTC_CNTL_DBIAS_1V10 4
+#define RTC_CNTL_DBIAS_1V15 5
+#define RTC_CNTL_DBIAS_1V20 6
+#define RTC_CNTL_DBIAS_1V25 7   /* voltage is about 1.34v in fact */
+
+/* Default initializer for esp32s2_rtc_sleep_config_t
+ * This initializer sets all fields to "reasonable" values
+ * (e.g. suggested for production use) based on a combination
+ * of RTC_SLEEP_PD_x flags.
+ */
+
+#define RTC_SLEEP_CONFIG_DEFAULT(sleep_flags) {                             \
+  .lslp_mem_inf_fpu = 0,                                                    \
+  .rtc_mem_inf_follow_cpu = ((sleep_flags) &                                \
+                             RTC_SLEEP_PD_RTC_MEM_FOLLOW_CPU) ? 1 : 0,      \
+  .rtc_fastmem_pd_en = ((sleep_flags) & RTC_SLEEP_PD_RTC_FAST_MEM) ? 1 : 0, \
+  .rtc_slowmem_pd_en = ((sleep_flags) & RTC_SLEEP_PD_RTC_SLOW_MEM) ? 1 : 0, \
+  .rtc_peri_pd_en = ((sleep_flags) & RTC_SLEEP_PD_RTC_PERIPH) ? 1 : 0,      \
+  .wifi_pd_en = (sleep_flags & RTC_SLEEP_PD_WIFI) ? 1 : 0,                  \
+  .int_8m_pd_en = (sleep_flags & RTC_SLEEP_PD_INT_8M) ? 1 : 0,              \
+  .deep_slp = ((sleep_flags) & RTC_SLEEP_PD_DIG) ? 1 : 0,                   \
+  .wdt_flashboot_mod_en = 0,                                                \
+  .dig_dbias_wak = RTC_CNTL_DBIAS_1V10,                                     \
+  .dig_dbias_slp = is_dslp(sleep_flags) ? RTC_CNTL_DBIAS_SLP                \
+                   : !((sleep_flags) & RTC_SLEEP_PD_INT_8M) ?               \
+                   RTC_CNTL_DBIAS_1V10 : RTC_CNTL_DBIAS_SLP,                \
+  .rtc_dbias_slp = is_dslp(sleep_flags) ? RTC_CNTL_DBIAS_SLP                \
+                   : !((sleep_flags) & RTC_SLEEP_PD_INT_8M) ?               \
+                   RTC_CNTL_DBIAS_1V10 : RTC_CNTL_DBIAS_SLP,                \
+  .bias_sleep_monitor = 0,                                                  \
+  .dbg_atten_slp = 0,                                                       \
+  .pd_cur_monitor = 0,                                                      \
+  .pd_cur_slp = 0,                                                          \
+  .rtc_regulator_fpu = 0,                                                   \
+  .rtc_dbias_wak = RTC_CNTL_DBIAS_1V10,                                     \
+  .vddsdio_pd_en = ((sleep_flags) & RTC_SLEEP_PD_VDDSDIO) ? 1 : 0,          \
+  .xtal_fpu = ((sleep_flags) & RTC_SLEEP_PD_XTAL) ? 0 : 1,                  \
+  .deep_slp_reject = 1,                                                     \
+  .light_slp_reject = 1,                                                    \
+}
+
+#define X32K_CONFIG_DEFAULT() { \
+  .dac = 3,                     \
+  .dres = 3,                    \
+  .dgm = 3,                     \
+  .dbuf = 1,                    \
+}
+
+/* Initializer for rtc_sleep_pd_config_t which
+ * sets all flags to the same value
+ */
+
+#define RTC_SLEEP_PD_CONFIG_ALL(val) {  \
+  .dig_fpu = (val),                     \
+  .rtc_fpu = (val),                     \
+  .cpu_fpu = (val),                     \
+  .i2s_fpu = (val),                     \
+  .bb_fpu = (val),                      \
+  .nrx_fpu = (val),                     \
+  .fe_fpu = (val),                      \
+}
+
+/* Default initializer of struct esp32s2_rtc_config_s.
+ * This initializer sets all fields to "reasonable" values
+ * (e.g. suggested for production use).
+ */
+
+#define RTC_CONFIG_DEFAULT() {                \
+  .ck8m_wait = RTC_CNTL_CK8M_WAIT_DEFAULT,    \
+  .xtal_wait = RTC_CNTL_XTL_BUF_WAIT_DEFAULT, \
+  .pll_wait  = RTC_CNTL_PLL_BUF_WAIT_DEFAULT, \
+  .clkctl_init = 1,                           \
+  .pwrctl_init = 1,                           \
+  .rtc_dboost_fpd = 1,                        \
+  .xtal_fpu = 0,                              \
+  .bbpll_fpu = 0,                             \
+  .cpu_waiti_clk_gate = 1,                    \
+  .cali_ocode = 0                             \
+}
+
+/* The magic data for the struct esp32s2_rtc_backup_s that is in RTC slow
+ * memory.
+ */
+
+#define MAGIC_RTC_SAVE UINT64_C(0x11223344556677)
+
+/* 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
+ ****************************************************************************/
+
+/* RTC power and clock control initialization settings */
+
+struct esp32s2_rtc_priv_s
+{
+  uint32_t ck8m_wait : 8;          /* Number of rtc_fast_clk cycles to wait 
for 8M clock to be ready */
+  uint32_t xtal_wait : 8;          /* Number of rtc_fast_clk cycles to wait 
for XTAL clock to be ready */
+  uint32_t pll_wait : 8;           /* Number of rtc_fast_clk cycles to wait 
for PLL to be ready */
+  uint32_t clkctl_init : 1;        /* Perform clock control related 
initialization */
+  uint32_t pwrctl_init : 1;        /* Perform power control related 
initialization */
+  uint32_t rtc_dboost_fpd : 1;     /* Force power down RTC_DBOOST */
+  uint32_t xtal_fpu : 1;
+  uint32_t bbpll_fpu : 1;
+  uint32_t cpu_waiti_clk_gate : 1;
+  uint32_t cali_ocode : 1;         /* Calibrate Ocode to make bangap voltage 
more precise. */
+};
+
+/* sleep configuration for rtc_sleep_init function */
+
+struct esp32s2_rtc_sleep_config_s
+{
+  uint32_t lslp_mem_inf_fpu : 1;       /* force normal voltage in sleep mode 
(digital domain memory) */
+  uint32_t rtc_mem_inf_follow_cpu : 1; /* keep low voltage in sleep mode (even 
if ULP/touch is used) */
+  uint32_t rtc_fastmem_pd_en : 1;      /* power down RTC fast memory */
+  uint32_t rtc_slowmem_pd_en : 1;      /* power down RTC slow memory */
+  uint32_t rtc_peri_pd_en : 1;         /* power down RTC peripherals */
+  uint32_t wifi_pd_en : 1;             /* power down WiFi */
+  uint32_t int_8m_pd_en : 1;           /* Power down Internal 8M oscillator */
+  uint32_t deep_slp : 1;               /* power down digital domain */
+  uint32_t wdt_flashboot_mod_en : 1;   /* enable WDT flashboot mode */
+  uint32_t dig_dbias_wak : 3;          /* set bias for digital domain, in 
active mode */
+  uint32_t dig_dbias_slp : 3;          /* set bias for digital domain, in 
sleep mode */
+  uint32_t rtc_dbias_wak : 3;          /* set bias for RTC domain, in active 
mode */
+  uint32_t rtc_dbias_slp : 3;          /* set bias for RTC domain, in sleep 
mode */
+  uint32_t bias_sleep_monitor : 1;     /* circuit control parameter, in 
monitor mode */
+  uint32_t dbg_atten_slp : 4;          /* voltage parameter, in sleep mode */
+  uint32_t bias_sleep_slp : 1;         /* circuit control parameter, in sleep 
mode */
+  uint32_t pd_cur_monitor : 1;         /* circuit control parameter, in 
monitor mode */
+  uint32_t pd_cur_slp : 1;             /* circuit control parameter, in sleep 
mode */
+  uint32_t vddsdio_pd_en : 1;          /* power down VDDSDIO regulator */
+  uint32_t xtal_fpu : 1;               /* keep main XTAL powered up in sleep */
+  uint32_t rtc_regulator_fpu  : 1;     /* keep rtc regulator powered up in 
sleep */
+  uint32_t deep_slp_reject : 1;        /* enable deep sleep reject */
+  uint32_t light_slp_reject : 1;       /* enable light sleep reject */
+};
+
+/* Power down flags for rtc_sleep_pd function */
+
+struct esp32s2_rtc_sleep_pd_config_s
+{
+  uint32_t dig_fpu : 1;    /* Set to 1 to power down digital part in sleep */
+  uint32_t rtc_fpu : 1;    /* Set to 1 to power down RTC memories in sleep */
+  uint32_t cpu_fpu : 1;    /* Set to 1 to power down digital memories and CPU 
in sleep */
+  uint32_t i2s_fpu : 1;    /* Set to 1 to power down I2S in sleep */
+  uint32_t bb_fpu : 1;     /* Set to 1 to power down Wi-Fi in sleep */
+  uint32_t nrx_fpu : 1;    /* Set to 1 to power down Wi-Fi in sleep */
+  uint32_t fe_fpu : 1;     /* Set to 1 to power down Wi-Fi in sleep */
+};
+
+#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 void *ac_arg;         /* Argument to pass with the callback 
function */
+  uint64_t deadline_us;
+  uint8_t index;
+};
+#endif
+
+/* crystal configuration */
+
+struct esp32s2_rtc_x32k_config_s
+{
+  uint32_t dac : 6;
+  uint32_t dres : 3;
+  uint32_t dgm : 3;
+  uint32_t dbuf: 1;
+};
+
+struct esp32s2_rtc_backup_s
+{
+  uint64_t magic;
+  int64_t  offset;              /* Offset time from RTC HW value */
+  int64_t  reserved0;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* APB Frequency */
+
+static uint32_t g_apb_freq;
+
+/* 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 esp32s2_rtc_backup_s rtc_saved_data;
+
+/* Saved data for persistent RTC time */
+
+static struct esp32s2_rtc_backup_s *g_rtc_save;
+static bool g_rt_timer_enabled = false;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void IRAM_ATTR esp32s2_rtc_sleep_pd(
+                      struct esp32s2_rtc_sleep_pd_config_s cfg);
+static inline bool esp32s2_clk_val_is_valid(uint32_t val);
+static void IRAM_ATTR esp32s2_rtc_clk_fast_freq_set(
+                      enum esp32s2_rtc_fast_freq_e fast_freq);
+static uint32_t IRAM_ATTR esp32s2_rtc_clk_cal_internal(
+                enum esp32s2_rtc_cal_sel_e cal_clk,
+                uint32_t slowclk_cycles);
+static int  IRAM_ATTR esp32s2_rtc_clk_slow_freq_get(void);
+static void IRAM_ATTR esp32s2_rtc_clk_slow_freq_set(
+                      enum esp32s2_rtc_slow_freq_e slow_freq);
+static void esp32s2_select_rtc_slow_clk(enum esp32s2_slow_clk_sel_e
+                                        slow_clk);
+static void esp32s2_rtc_clk_32k_enable(bool enable);
+static void IRAM_ATTR esp32s2_rtc_clk_8m_enable(bool clk_8m_en,
+                                                bool d256_en);
+static void esp32s2_rtc_calibrate_ocode(void);
+static void IRAM_ATTR esp32s2_rtc_clk_bbpll_disable(void);
+static void IRAM_ATTR esp32s2_rtc_bbpll_configure(
+                     enum esp32s2_rtc_xtal_freq_e xtal_freq, int pll_freq);
+static void IRAM_ATTR esp32s2_rtc_clk_cpu_freq_to_8m(void);
+static void IRAM_ATTR esp32s2_rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz);
+
+void IRAM_ATTR esp32s2_rtc_bbpll_disable(void);
+void esp32s2_rtc_clk_apb_freq_update(uint32_t apb_freq);
+void IRAM_ATTR esp32s2_rtc_update_to_xtal(int freq, int div);
+static void esp32s2_wait_dig_dbias_valid(uint64_t rtc_cycles);
+uint32_t esp32s2_rtc_clk_apb_freq_get(void);
+
+#ifdef CONFIG_RTC_ALARM
+static void IRAM_ATTR esp32s2_rt_cb_handler(void *arg);
+#endif
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+volatile bool g_rtc_enabled = false;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Set the real CPU ticks per us to the ets, so that ets_delay_us
+ * will be accurate. Call this function when CPU frequency is changed.
+ */
+
+extern void ets_update_cpu_frequency(uint32_t ticks_per_us);
+
+/****************************************************************************
+ * Name: esp32s2_rtc_sleep_pd
+ *
+ * Description:
+ *   Configure whether certain peripherals are powered up in deep sleep.
+ *
+ * Input Parameters:
+ *   cfg - power down flags as rtc_sleep_pu_config_t structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void IRAM_ATTR
+        esp32s2_rtc_sleep_pd(struct esp32s2_rtc_sleep_pd_config_s cfg)
+{
+  REG_SET_FIELD(RTC_CNTL_DIG_PWC_REG,
+                RTC_CNTL_LSLP_MEM_FORCE_PU, cfg.dig_fpu);
+  REG_SET_FIELD(RTC_CNTL_PWC_REG,
+                RTC_CNTL_FASTMEM_FORCE_LPU, cfg.rtc_fpu);
+  REG_SET_FIELD(RTC_CNTL_PWC_REG,
+                RTC_CNTL_SLOWMEM_FORCE_LPU, cfg.rtc_fpu);
+  REG_SET_FIELD(SYSCON_FRONT_END_MEM_PD_REG,
+                SYSCON_DC_MEM_FORCE_PU, cfg.fe_fpu);
+  REG_SET_FIELD(SYSCON_FRONT_END_MEM_PD_REG,
+                SYSCON_PBUS_MEM_FORCE_PU, cfg.fe_fpu);
+  REG_SET_FIELD(SYSCON_FRONT_END_MEM_PD_REG,
+                SYSCON_AGC_MEM_FORCE_PU, cfg.fe_fpu);
+  REG_SET_FIELD(BBPD_CTRL, BB_FFT_FORCE_PU, cfg.bb_fpu);
+  REG_SET_FIELD(BBPD_CTRL, BB_DC_EST_FORCE_PU, cfg.bb_fpu);
+  REG_SET_FIELD(NRXPD_CTRL, NRX_RX_ROT_FORCE_PU, cfg.nrx_fpu);
+  REG_SET_FIELD(NRXPD_CTRL, NRX_VIT_FORCE_PU, cfg.nrx_fpu);
+  REG_SET_FIELD(NRXPD_CTRL, NRX_DEMAP_FORCE_PU, cfg.nrx_fpu);
+  REG_SET_FIELD(FE_GEN_CTRL, FE_IQ_EST_FORCE_PU, cfg.fe_fpu);
+  REG_SET_FIELD(FE2_TX_INTERP_CTRL, FE2_TX_INF_FORCE_PU, cfg.fe_fpu);
+}
+
+/****************************************************************************
+ * Name: esp32s2_rtc_clk_fast_freq_set
+ *
+ * Description:
+ *   Select source for RTC_FAST_CLK.
+ *
+ * Input Parameters:
+ *   fast_freq - Clock source (one of enum esp32s2_rtc_fast_freq_e values)
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void IRAM_ATTR esp32s2_rtc_clk_fast_freq_set(
+                      enum esp32s2_rtc_fast_freq_e fast_freq)
+{
+  REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL,
+                fast_freq);
+  up_udelay(DELAY_FAST_CLK_SWITCH);
+}
+
+/****************************************************************************
+ * Name: esp32s2_clk_val_is_valid
+ *
+ * Description:
+ *   Values of RTC_XTAL_FREQ_REG and RTC_APB_FREQ_REG are
+ *   stored as two copies in lower and upper 16-bit halves.
+ *   These are the routines to work with such a representation.
+ *
+ * Input Parameters:
+ *   val - register value
+ *
+ * Returned Value:
+ *   true:  Valid register value.
+ *   false: Invalid register value.
+ *
+ ****************************************************************************/
+
+static inline bool esp32s2_clk_val_is_valid(uint32_t val)
+{
+  return (val & 0xffff) == ((val >> 16) & 0xffff)
+                        && val != 0 && val != UINT32_MAX;
+}
+
+/****************************************************************************
+ * Name: esp32s2_rtc_clk_cal_internal
+ *
+ * Description:
+ *   Clock calibration function used by rtc_clk_cal and rtc_clk_cal_ratio
+ *
+ * Input Parameters:
+ *   cal_clk        - which clock to calibrate
+ *   slowclk_cycles - number of slow clock cycles to count.
+ *
+ * Returned Value:
+ *   Number of XTAL clock cycles within the given number of slow clock
+ *   cycles.
+ *   In case of error, return 0 cycle.
+ *
+ ****************************************************************************/
+
+static uint32_t IRAM_ATTR esp32s2_rtc_clk_cal_internal(
+                enum esp32s2_rtc_cal_sel_e cal_clk, uint32_t slowclk_cycles)
+{
+  uint32_t expected_freq;
+  uint32_t us_time_estimate;
+  uint32_t clks_state;
+  uint32_t clks_mask;
+  uint32_t cal_val;
+  enum esp32s2_rtc_slow_freq_e slow_freq;
+
+  /* Get the current state */
+
+  clks_mask  = (RTC_CNTL_DIG_XTAL32K_EN_M | RTC_CNTL_DIG_CLK8M_D256_EN_M);
+  clks_state = getreg32(RTC_CNTL_CLK_CONF_REG);
+  clks_state &= clks_mask;
+
+  /* On ESP32S2, choosing RTC_CAL_RTC_MUX results in calibration of
+   * the 150k RTC clock regardless of the currenlty selected SLOW_CLK.
+   * The following code emulates ESP32 behavior
+   */
+
+  if (cal_clk == RTC_CAL_RTC_MUX)
+    {
+      slow_freq = esp32s2_rtc_clk_slow_freq_get();
+      if (slow_freq == RTC_SLOW_FREQ_32K_XTAL)
+        {
+          cal_clk = RTC_CAL_32K_XTAL;
+        }
+      else if (slow_freq == RTC_SLOW_FREQ_8MD256)
+        {
+          cal_clk = RTC_CAL_8MD256;
+        }
+    }
+  else if (cal_clk == RTC_CAL_INTERNAL_OSC)
+        {
+          cal_clk = RTC_CAL_RTC_MUX;
+        }
+
+  /* Enable requested clock (150k clock is always on) */
+
+  if (cal_clk == RTC_CAL_32K_XTAL && !(clks_state & RTC_CNTL_DIG_XTAL32K_EN))
+    {
+      REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, 1);
+    }
+  else if (cal_clk == RTC_CAL_8MD256 &&
+           !(clks_state & RTC_CNTL_DIG_CLK8M_D256_EN))
+    {
+      modifyreg32(RTC_CNTL_CLK_CONF_REG, 0, RTC_CNTL_DIG_CLK8M_D256_EN);
+    }
+
+  /* Prepare calibration */
+
+  REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cal_clk);
+  modifyreg32(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING, 0);
+  REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, slowclk_cycles);
+
+  /* Figure out how long to wait for calibration to finish */
+
+  slow_freq = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG,
+                            RTC_CNTL_ANA_CLK_RTC_SEL);
+
+  if (cal_clk == RTC_CAL_32K_XTAL || slow_freq == RTC_SLOW_FREQ_32K_XTAL)
+    {
+      expected_freq = 32768; /* standard 32k XTAL */
+    }
+  else if (cal_clk == RTC_CAL_8MD256 || slow_freq == RTC_SLOW_FREQ_8MD256)
+    {
+      expected_freq = RTC_FAST_CLK_FREQ_APPROX / 256;
+    }
+  else
+    {
+      expected_freq = 150000; /* 150k internal oscillator */
+    }
+
+  us_time_estimate = (uint32_t) (((uint64_t)slowclk_cycles) *
+                                           MHZ / expected_freq);
+
+  /* Start calibration */
+
+  modifyreg32(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START, 0);
+  modifyreg32(TIMG_RTCCALICFG_REG(0), 0, TIMG_RTC_CALI_START);
+
+  /* Wait the expected time calibration should take */
+
+  up_udelay(us_time_estimate);
+
+  /* Wait for calibration to finish up to another us_time_estimate */
+
+  while (true)
+    {
+      if (getreg32(TIMG_RTCCALICFG_REG(0)) & TIMG_RTC_CALI_RDY)
+        {
+          cal_val = REG_GET_FIELD(TIMG_RTCCALICFG1_REG(0),
+                                  TIMG_RTC_CALI_VALUE);
+          break;
+        }
+
+      if (GET_PERI_REG_MASK(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT))
+        {
+          cal_val = 0;
+          break;
+        }
+    }
+
+  CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
+
+  /* Restore the previous clocks states */
+
+  modifyreg32(RTC_CNTL_CLK_CONF_REG, clks_mask, clks_state);
+
+  return cal_val;
+}
+
+static void esp32s2_wait_dig_dbias_valid(uint64_t rtc_cycles)
+{
+  int slow_clk_freq = esp32s2_rtc_clk_slow_freq_get();
+  int cal_clk = RTC_CAL_RTC_MUX;
+
+  if (slow_clk_freq == RTC_SLOW_FREQ_32K_XTAL)
+    {
+      cal_clk = RTC_CAL_32K_XTAL;
+    }
+  else if (slow_clk_freq == RTC_SLOW_FREQ_8MD256)
+    {
+      cal_clk = RTC_CAL_8MD256;
+    }
+
+  esp32s2_rtc_clk_cal(cal_clk, rtc_cycles);
+}
+
+/****************************************************************************
+ * Name: esp32s2_rtc_update_to_xtal
+ *
+ * Description:
+ *   Switch to XTAL frequency, does not disable the PLL
+ *
+ * Input Parameters:
+ *   freq -  XTAL frequency
+ *   div  -  REF_TICK divider
+ *
+ * Returned Value:
+ *   none
+ *
+ ****************************************************************************/
+
+void IRAM_ATTR esp32s2_rtc_update_to_xtal(int freq, int div)
+{
+  ets_update_cpu_frequency(freq);
+  esp32s2_wait_dig_dbias_valid(2);
+
+  /* Set divider from XTAL to APB clock.
+   * Need to set divider to 1 (reg. value 0) first.
+   */
+
+  REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
+  REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, div - 1);
+
+  /* No need to adjust the REF_TICK.
+   * Switch clock source.
+   */
+
+  REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG,
+                SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_XTAL);
+
+  esp32s2_rtc_clk_apb_freq_update(freq * MHZ);
+}
+
+/****************************************************************************
+ * Name: esp32s2_rtc_clk_slow_freq_set
+ *
+ * Description:
+ *   Select source for RTC_SLOW_CLK
+ *
+ * Input Parameters:
+ *   slow_freq - Select source for RTC_SLOW_CLK
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void IRAM_ATTR esp32s2_rtc_clk_slow_freq_set(
+                      enum esp32s2_rtc_slow_freq_e slow_freq)
+{
+  REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL,
+                slow_freq);
+
+  REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN,
+               (slow_freq == RTC_SLOW_FREQ_32K_XTAL) ? 1 : 0);
+
+  up_udelay(DELAY_SLOW_CLK_SWITCH);
+}
+
+/****************************************************************************
+ * Name: esp32s2_rtc_clk_32k_enable
+ *
+ * Description:
+ *   Enable 32 kHz XTAL oscillator
+ *
+ * Input Parameters:
+ *   enable - boolean Enable/Disable
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void IRAM_ATTR esp32s2_rtc_clk_32k_enable(bool enable)
+{
+  if (enable)
+    {
+      struct esp32s2_rtc_x32k_config_s cfg = X32K_CONFIG_DEFAULT();
+
+      modifyreg32(RTCIO_XTAL_32P_PAD_REG, 0, RTCIO_X32P_MUX_SEL);
+      modifyreg32(RTCIO_XTAL_32N_PAD_REG, 0, RTCIO_X32N_MUX_SEL);
+
+      REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG,
+                    RTC_CNTL_DAC_XTAL_32K, cfg.dac);
+      REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG,
+                    RTC_CNTL_DRES_XTAL_32K, cfg.dres);
+      REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG,
+                    RTC_CNTL_DGM_XTAL_32K, cfg.dgm);
+      REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG,
+                    RTC_CNTL_DBUF_XTAL_32K, cfg.dbuf);
+      modifyreg32(RTC_CNTL_EXT_XTL_CONF_REG, 0,
+                  RTC_CNTL_XPD_XTAL_32K);
+    }
+  else
+    {
+      modifyreg32(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K,
+                  RTC_CNTL_XTAL32K_XPD_FORCE);
+    }
+}
+
+/****************************************************************************
+ * Name: esp32s2_rtc_clk_8m_enable
+ *
+ * Description:
+ *   Enable or disable 8 MHz internal oscillator
+ *
+ * Input Parameters:
+ *   clk_8m_en - true to enable 8MHz generator, false to disable
+ *   d256_en   - true to enable /256 divider, false to disable
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void IRAM_ATTR esp32s2_rtc_clk_8m_enable(bool clk_8m_en, bool d256_en)
+{
+  if (clk_8m_en)
+    {
+      modifyreg32(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M, 0);
+
+      /* no need to wait once enabled by software */
+
+      REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, 1);
+      if (d256_en)
+        {
+          modifyreg32(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV, 0);
+        }
+      else
+        {
+          modifyreg32(RTC_CNTL_CLK_CONF_REG, 0, RTC_CNTL_ENB_CK8M_DIV);
+        }
+
+      up_udelay(DELAY_8M_ENABLE);
+    }
+  else
+    {
+      modifyreg32(RTC_CNTL_CLK_CONF_REG, 0, RTC_CNTL_ENB_CK8M);
+      REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT,
+                    RTC_CNTL_CK8M_WAIT_DEFAULT);
+    }
+}
+
+/****************************************************************************
+ * Name: esp32s2_select_rtc_slow_clk
+ *
+ * Description:
+ *   Selects an clock source for RTC.
+ *
+ * Input Parameters:
+ *   slow_clk - RTC SLOW_CLK frequency values
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp32s2_select_rtc_slow_clk(enum esp32s2_slow_clk_sel_e slow_clk)
+{
+  /* Number of times to repeat 32k XTAL calibration before giving up and
+   * switching to the internal RC.
+   */
+
+  int retry_32k_xtal = 0;
+  uint32_t cal_val = 0;
+  uint64_t cal_dividend;
+  enum esp32s2_rtc_slow_freq_e rtc_slow_freq = slow_clk &
+                                               RTC_CNTL_ANA_CLK_RTC_SEL_V;
+
+  do
+    {
+      if (rtc_slow_freq == RTC_SLOW_FREQ_32K_XTAL)
+        {
+          /* 32k XTAL oscillator needs to be enabled and running before
+           * it can be used. Hardware doesn't have a direct way of checking
+           * if the oscillator is running. Here we use rtc_clk_cal function
+           * to count the number of main XTAL cycles in the given number of
+           * 32k XTAL oscillator cycles. If the 32k XTAL has not started up,
+           * calibration will time out, returning 0.
+           */
+
+          rtcinfo("Waiting for 32k oscillator to start up\n");

Review Comment:
   ```suggestion
             rtcinfo("Waiting for 32KHz oscillator to start up\n");



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to