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

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

commit 1e3af48fff6e88cd563fac35e44482344f4edacc
Author: Lucas Saavedra Vaz <[email protected]>
AuthorDate: Fri Feb 3 16:10:19 2023 -0300

    arch/xtensa/esp32s2: Add support for RTC IRQs
---
 arch/xtensa/include/esp32s2/irq.h          |  46 +++++++-
 arch/xtensa/src/esp32s2/Kconfig            |   7 ++
 arch/xtensa/src/esp32s2/esp32s2_irq.c      |   5 +
 arch/xtensa/src/esp32s2/esp32s2_rtc_gpio.c | 183 +++++++++++++++++++++++++++++
 arch/xtensa/src/esp32s2/esp32s2_rtc_gpio.h |  43 +++++++
 arch/xtensa/src/esp32s2/esp32s2_wdt.c      |  78 ++++++++----
 6 files changed, 337 insertions(+), 25 deletions(-)

diff --git a/arch/xtensa/include/esp32s2/irq.h 
b/arch/xtensa/include/esp32s2/irq.h
index 730ddd82be..9028fa850b 100644
--- a/arch/xtensa/include/esp32s2/irq.h
+++ b/arch/xtensa/include/esp32s2/irq.h
@@ -295,9 +295,53 @@
 #  define ESP32S2_NIRQ_GPIO           0
 #endif
 
+#ifdef CONFIG_ESP32S2_RTCIO_IRQ
+
+/* Second level RTC interrupts.  RTC interrupts are decoded and dispatched
+ * as a second level of decoding:  The first level dispatches to the RTC
+ * interrupt handler.  The second to the decoded RTC interrupt handler.
+ * A third level might be required to be implemented on the driver (e.g.
+ * Touch pads)
+ */
+
+#  define ESP32S2_NIRQ_RTCIO_PERIPH       20
+#  define ESP32S2_NIRQ_RTCIO_TOUCHPAD     15
+#  define ESP32S2_NIRQ_RTCIO              
(ESP32S2_NIRQ_RTCIO_PERIPH+ESP32S2_NIRQ_RTCIO_TOUCHPAD)
+
+#  define ESP32S2_FIRST_RTCIOIRQ_PERIPH   
(XTENSA_NIRQ_INTERNAL+ESP32S2_NIRQ_PERIPH+ESP32S2_NIRQ_GPIO)
+#  define ESP32S2_LAST_RTCIOIRQ_PERIPH    
(ESP32S2_FIRST_RTCIOIRQ_PERIPH+ESP32S2_NIRQ_RTCIO_PERIPH-1)
+#  define ESP32S2_IRQ_RTC_SLP_WAKEUP      (ESP32S2_FIRST_RTCIOIRQ_PERIPH+0)
+#  define ESP32S2_IRQ_RTC_SLP_REJECT      (ESP32S2_FIRST_RTCIOIRQ_PERIPH+1)
+#  define ESP32S2_IRQ_RTC_SDIO_IDLE       (ESP32S2_FIRST_RTCIOIRQ_PERIPH+2)
+#  define ESP32S2_IRQ_RTC_WDT             (ESP32S2_FIRST_RTCIOIRQ_PERIPH+3)
+#  define ESP32S2_IRQ_RTC_TOUCH_SCAN_DONE (ESP32S2_FIRST_RTCIOIRQ_PERIPH+4)
+#  define ESP32S2_IRQ_RTC_ULP_CP          (ESP32S2_FIRST_RTCIOIRQ_PERIPH+5)
+#  define ESP32S2_IRQ_RTC_TOUCH_DONE      (ESP32S2_FIRST_RTCIOIRQ_PERIPH+6)
+#  define ESP32S2_IRQ_RTC_TOUCH_ACTIVE    (ESP32S2_FIRST_RTCIOIRQ_PERIPH+7)
+#  define ESP32S2_IRQ_RTC_TOUCH_INACTIVE  (ESP32S2_FIRST_RTCIOIRQ_PERIPH+8)
+#  define ESP32S2_IRQ_RTC_BROWN_OUT       (ESP32S2_FIRST_RTCIOIRQ_PERIPH+9)
+#  define ESP32S2_IRQ_RTC_MAIN_TIMER      (ESP32S2_FIRST_RTCIOIRQ_PERIPH+10)
+#  define ESP32S2_IRQ_RTC_SARADC1         (ESP32S2_FIRST_RTCIOIRQ_PERIPH+11)
+#  define ESP32S2_IRQ_RTC_TSENS           (ESP32S2_FIRST_RTCIOIRQ_PERIPH+12)
+#  define ESP32S2_IRQ_RTC_COCPU           (ESP32S2_FIRST_RTCIOIRQ_PERIPH+13)
+#  define ESP32S2_IRQ_RTC_SARADC2         (ESP32S2_FIRST_RTCIOIRQ_PERIPH+14)
+#  define ESP32S2_IRQ_RTC_SWD             (ESP32S2_FIRST_RTCIOIRQ_PERIPH+15)
+#  define ESP32S2_IRQ_RTC_XTAL32K_DEAD    (ESP32S2_FIRST_RTCIOIRQ_PERIPH+16)
+#  define ESP32S2_IRQ_RTC_COCPU_TRAP      (ESP32S2_FIRST_RTCIOIRQ_PERIPH+17)
+#  define ESP32S2_IRQ_RTC_TOUCH_TIMEOUT   (ESP32S2_FIRST_RTCIOIRQ_PERIPH+18)
+#  define ESP32S2_IRQ_RTC_GLITCH_DET      (ESP32S2_FIRST_RTCIOIRQ_PERIPH+19)
+
+#  define ESP32S2_FIRST_RTCIOIRQ_TOUCHPAD (ESP32S2_LAST_RTCIOIRQ_PERIPH+1)
+#  define ESP32S2_LAST_RTCIOIRQ_TOUCHPAD  
(ESP32S2_FIRST_RTCIOIRQ_TOUCHPAD+ESP32S2_NIRQ_RTCIO_TOUCHPAD-1)
+#  define ESP32S2_TOUCHPAD2IRQ(t)         ((t) + 
ESP32S2_FIRST_RTCIOIRQ_TOUCHPAD)
+#  define ESP32S2_IRQ2TOUCHPAD(i)         ((i) - 
ESP32S2_FIRST_RTCIOIRQ_TOUCHPAD)
+#else
+#  define ESP32S2_NIRQ_RTCIO              0
+#endif
+
 /* Total number of interrupts */
 
-#define NR_IRQS                     (XTENSA_NIRQ_INTERNAL + 
ESP32S2_NIRQ_PERIPH + ESP32S2_NIRQ_GPIO)
+#define NR_IRQS                     (XTENSA_NIRQ_INTERNAL + 
ESP32S2_NIRQ_PERIPH + ESP32S2_NIRQ_GPIO + ESP32S2_NIRQ_RTCIO)
 
 /* Xtensa CPU Interrupts.
  *
diff --git a/arch/xtensa/src/esp32s2/Kconfig b/arch/xtensa/src/esp32s2/Kconfig
index b1b0930bb0..775a83680a 100644
--- a/arch/xtensa/src/esp32s2/Kconfig
+++ b/arch/xtensa/src/esp32s2/Kconfig
@@ -408,6 +408,7 @@ config ESP32S2_RWDT
        bool "RTC Watchdog Timer"
        default n
        select ESP32S2_WDT
+       select ESP32S2_RTCIO_IRQ
        ---help---
                Includes RWDT. This watchdog timer is from the RTC module.
                When it is selected, if the developer sets it to reset on 
expiration
@@ -465,6 +466,12 @@ config ESP32S2_GPIO_IRQ
        ---help---
                Enable support for interrupting GPIO pins.
 
+config ESP32S2_RTCIO_IRQ
+       bool "RTC IO interrupts"
+       default n
+       ---help---
+               Enable support for RTC peripherals interruptions.
+
 menu "SPI configuration"
        depends on ESP32S2_SPI
 
diff --git a/arch/xtensa/src/esp32s2/esp32s2_irq.c 
b/arch/xtensa/src/esp32s2/esp32s2_irq.c
index cf14bb2113..509b32ef67 100644
--- a/arch/xtensa/src/esp32s2/esp32s2_irq.c
+++ b/arch/xtensa/src/esp32s2/esp32s2_irq.c
@@ -40,6 +40,7 @@
 #ifdef CONFIG_ESP32S2_GPIO_IRQ
 #include "esp32s2_gpio.h"
 #endif
+#include "esp32s2_rtc_gpio.h"
 #include "esp32s2_irq.h"
 #include "hardware/esp32s2_soc.h"
 #include "hardware/esp32s2_system.h"
@@ -299,6 +300,10 @@ void up_irqinitialize(void)
   esp32s2_gpioirqinitialize();
 #endif
 
+  /* Initialize RTCIO interrupt support */
+
+  esp32s2_rtcioirqinitialize();
+
 #ifndef CONFIG_SUPPRESS_INTERRUPTS
   /* And finally, enable interrupts.  Also clears PS.EXCM */
 
diff --git a/arch/xtensa/src/esp32s2/esp32s2_rtc_gpio.c 
b/arch/xtensa/src/esp32s2/esp32s2_rtc_gpio.c
index 4da50dcae8..c30531ae17 100644
--- a/arch/xtensa/src/esp32s2/esp32s2_rtc_gpio.c
+++ b/arch/xtensa/src/esp32s2/esp32s2_rtc_gpio.c
@@ -31,8 +31,10 @@
 #include <sys/types.h>
 
 #include <nuttx/arch.h>
+#include <nuttx/irq.h>
 
 #include "xtensa.h"
+#include "esp32s2_irq.h"
 #include "esp32s2_rtc_gpio.h"
 #include "hardware/esp32s2_rtc_io.h"
 #include "hardware/esp32s2_sens.h"
@@ -58,6 +60,11 @@ enum rtcio_lh_out_mode_e
  * Private Data
  ****************************************************************************/
 
+#ifdef CONFIG_ESP32S2_RTCIO_IRQ
+static int g_rtcio_cpuint;
+static uint32_t last_status;
+#endif
+
 static const uint32_t rtc_gpio_to_addr[] =
 {
   RTCIO_RTC_GPIO_PIN0_REG,
@@ -94,6 +101,12 @@ static const uint32_t rtc_gpio_to_addr[] =
  * Description:
  *   Determine if the specified rtcio_num is a valid RTC GPIO.
  *
+ * Input Parameters:
+ *   rtcio_num - RTC GPIO to be checked.
+ *
+ * Returned Value:
+ *   True if valid. False otherwise.
+ *
  ****************************************************************************/
 
 static inline bool is_valid_rtc_gpio(uint32_t rtcio_num)
@@ -101,6 +114,85 @@ static inline bool is_valid_rtc_gpio(uint32_t rtcio_num)
   return (rtcio_num < RTC_GPIO_NUMBER);
 }
 
+/****************************************************************************
+ * Name: rtcio_dispatch
+ *
+ * Description:
+ *   Second level dispatch for the RTC interrupt.
+ *
+ * Input Parameters:
+ *   irq - The IRQ number;
+ *   reg_status - Pointer to a copy of the interrupt status register.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_RTCIO_IRQ
+static void rtcio_dispatch(int irq, uint32_t *reg_status)
+{
+  uint32_t status = *reg_status;
+  uint32_t mask;
+  int i;
+
+  /* Check each bit in the status register */
+
+  for (i = 0; i < ESP32S2_NIRQ_RTCIO_PERIPH && status != 0; i++)
+    {
+      /* Check if there is an interrupt pending for this type */
+
+      mask = (UINT32_C(1) << i);
+      if ((status & mask) != 0)
+        {
+          /* Yes... perform the second level dispatch. The IRQ context will
+           * contain the contents of the status register.
+           */
+
+          irq_dispatch(irq + i, (void *)reg_status);
+
+          /* Clear the bit in the status so that we might execute this loop
+           * sooner.
+           */
+
+          status &= ~mask;
+        }
+    }
+}
+#endif
+
+/****************************************************************************
+ * Name: rtcio_interrupt
+ *
+ * Description:
+ *   RTC interrupt handler.
+ *
+ * Input Parameters:
+ *   irq - The IRQ number;
+ *   context - The interrupt context;
+ *   args - The arguments passed to the handler.
+ *
+ * Returned Value:
+ *   Zero (OK).
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_RTCIO_IRQ
+static int rtcio_interrupt(int irq, void *context, void *arg)
+{
+  /* Read and clear the lower RTC interrupt status */
+
+  last_status = getreg32(RTC_CNTL_INT_ST_RTC_REG);
+  putreg32(last_status, RTC_CNTL_INT_CLR_RTC_REG);
+
+  /* Dispatch pending interrupts in the RTC status register */
+
+  rtcio_dispatch(ESP32S2_FIRST_RTCIOIRQ_PERIPH, &last_status);
+
+  return OK;
+}
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -249,3 +341,94 @@ int esp32s2_configrtcio(int rtcio_num, rtcio_pinattr_t 
attr)
 
   return OK;
 }
+
+/****************************************************************************
+ * Name: esp32s2_rtcioirqinitialize
+ *
+ * Description:
+ *   Initialize logic to support a second level of interrupt decoding for
+ *   RTC interrupts.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_RTCIO_IRQ
+void esp32s2_rtcioirqinitialize(void)
+{
+  /* Setup the RTCIO interrupt. */
+
+  g_rtcio_cpuint = esp32s2_setup_irq(ESP32S2_PERIPH_RTC_CORE,
+                                     1, ESP32S2_CPUINT_LEVEL);
+  DEBUGASSERT(g_rtcio_cpuint >= 0);
+
+  /* Attach and enable the interrupt handler */
+
+  DEBUGVERIFY(irq_attach(ESP32S2_IRQ_RTC_CORE, rtcio_interrupt, NULL));
+  up_enable_irq(ESP32S2_IRQ_RTC_CORE);
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s2_rtcioirqenable
+ *
+ * Description:
+ *   Enable the interrupt for a specified RTC IRQ
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_RTCIO_IRQ
+void esp32s2_rtcioirqenable(int irq)
+{
+  uintptr_t regaddr = RTC_CNTL_INT_ENA_RTC_REG;
+  uint32_t regval;
+  int bit;
+
+  DEBUGASSERT(irq >= ESP32S2_FIRST_RTCIOIRQ_PERIPH &&
+              irq <= ESP32S2_LAST_RTCIOIRQ_PERIPH);
+
+  /* Convert the IRQ number to the corresponding bit */
+
+  bit = irq - ESP32S2_FIRST_RTCIOIRQ_PERIPH;
+
+  /* Get the address of the GPIO PIN register for this pin */
+
+  up_disable_irq(ESP32S2_IRQ_RTC_CORE);
+
+  regval = getreg32(regaddr) | (UINT32_C(1) << bit);
+  putreg32(regval, regaddr);
+
+  up_enable_irq(ESP32S2_IRQ_RTC_CORE);
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s2_rtcioirqdisable
+ *
+ * Description:
+ *   Disable the interrupt for a specified RTC IRQ
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_RTCIO_IRQ
+void esp32s2_rtcioirqdisable(int irq)
+{
+  uintptr_t regaddr = RTC_CNTL_INT_ENA_RTC_REG;
+  uint32_t regval;
+  int bit;
+
+  DEBUGASSERT(irq >= ESP32S2_FIRST_RTCIOIRQ_PERIPH &&
+              irq <= ESP32S2_LAST_RTCIOIRQ_PERIPH);
+
+  /* Convert the IRQ number to the corresponding bit */
+
+  bit = irq - ESP32S2_FIRST_RTCIOIRQ_PERIPH;
+
+  /* Disable IRQ */
+
+  up_disable_irq(ESP32S2_IRQ_RTC_CORE);
+
+  regval = getreg32(regaddr) & (~(UINT32_C(1) << bit));
+  putreg32(regval, regaddr);
+
+  up_enable_irq(ESP32S2_IRQ_RTC_CORE);
+}
+#endif
diff --git a/arch/xtensa/src/esp32s2/esp32s2_rtc_gpio.h 
b/arch/xtensa/src/esp32s2/esp32s2_rtc_gpio.h
index 568dd88f0c..9a91cd4aa9 100644
--- a/arch/xtensa/src/esp32s2/esp32s2_rtc_gpio.h
+++ b/arch/xtensa/src/esp32s2/esp32s2_rtc_gpio.h
@@ -574,5 +574,48 @@ static const rtc_io_desc_t g_rtc_io_desc[RTC_GPIO_NUMBER] =
 
 int esp32s2_configrtcio(int rtcio_num, rtcio_pinattr_t attr);
 
+/****************************************************************************
+ * Name: esp32s2_rtcioirqinitialize
+ *
+ * Description:
+ *   Initialize logic to support a second level of interrupt decoding for
+ *   RTC IRQs.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_RTCIO_IRQ
+void esp32s2_rtcioirqinitialize(void);
+#else
+#  define esp32s2_rtcioirqinitialize()
+#endif
+
+/****************************************************************************
+ * Name: esp32s2_rtcioirqenable
+ *
+ * Description:
+ *   Enable the interrupt for the specified RTC peripheral IRQ
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_RTCIO_IRQ
+void esp32s2_rtcioirqenable(int irq);
+#else
+#  define esp32s2_rtcioirqenable(irq)
+#endif
+
+/****************************************************************************
+ * Name: esp32s2_rtcioirqdisable
+ *
+ * Description:
+ *   Disable the interrupt for the specified RTC peripheral IRQ
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_RTCIO_IRQ
+void esp32s2_rtcioirqdisable(int irq);
+#else
+#  define esp32s2_rtcioirqdisable(irq)
+#endif
+
 #endif /* __ASSEMBLY__ */
 #endif /* __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_RTC_GPIO_H */
diff --git a/arch/xtensa/src/esp32s2/esp32s2_wdt.c 
b/arch/xtensa/src/esp32s2/esp32s2_wdt.c
index 5aa77cc5eb..1fd5f04937 100644
--- a/arch/xtensa/src/esp32s2/esp32s2_wdt.c
+++ b/arch/xtensa/src/esp32s2/esp32s2_wdt.c
@@ -31,6 +31,7 @@
 
 #include "xtensa.h"
 #include "esp32s2_irq.h"
+#include "esp32s2_rtc_gpio.h"
 #include "esp32s2_wdt.h"
 #include "hardware/esp32s2_efuse.h"
 #include "hardware/esp32s2_rtccntl.h"
@@ -166,7 +167,7 @@ struct esp32s2_wdt_priv_s g_esp32s2_rwdt_priv =
   .ops    = &esp32s2_rwdt_ops,
   .base   = RTC_CNTL_OPTIONS0_REG,
   .periph = ESP32S2_PERIPH_RTC_CORE,
-  .irq    = ESP32S2_IRQ_RTC_CORE,
+  .irq    = ESP32S2_IRQ_RTC_WDT,
   .cpuint = -ENOMEM,
   .inuse  = false,
 };
@@ -634,13 +635,23 @@ static int32_t wdt_setisr(struct esp32s2_wdt_dev_s *dev, 
xcpt_t handler,
 
       if (wdt->cpuint >= 0)
         {
-          /* Disable CPU Interrupt, free a previously allocated
-           * CPU Interrupt
-           */
-
-          up_disable_irq(wdt->irq);
-          esp32s2_teardown_irq(wdt->periph, wdt->cpuint);
-          irq_detach(wdt->irq);
+#ifdef CONFIG_ESP32S2_RWDT
+          if (wdt->irq == ESP32S2_IRQ_RTC_WDT)
+            {
+              esp32s2_rtcioirqdisable(wdt->irq);
+              irq_detach(wdt->irq);
+            }
+          else
+#endif
+            {
+              /* Disable CPU Interrupt, free a previously allocated
+               * CPU Interrupt
+               */
+
+              up_disable_irq(wdt->irq);
+              esp32s2_teardown_irq(wdt->periph, wdt->cpuint);
+              irq_detach(wdt->irq);
+            }
         }
 
       goto errout;
@@ -652,27 +663,46 @@ static int32_t wdt_setisr(struct esp32s2_wdt_dev_s *dev, 
xcpt_t handler,
     {
       /* Set up to receive peripheral interrupts on the current CPU */
 
-      wdt->cpuint = esp32s2_setup_irq(wdt->periph, 1, ESP32S2_CPUINT_LEVEL);
-      if (wdt->cpuint < 0)
+#ifdef CONFIG_ESP32S2_RWDT
+      if (wdt->irq == ESP32S2_IRQ_RTC_WDT)
         {
-          wderr("ERROR: No CPU Interrupt available");
-          ret = wdt->cpuint;
-          goto errout;
-        }
+          ret = irq_attach(wdt->irq, handler, arg);
 
-      /* Associate an IRQ Number (from the WDT) to an ISR */
+          if (ret != OK)
+            {
+              esp32s2_rtcioirqdisable(wdt->irq);
+              tmrerr("ERROR: Failed to associate an IRQ Number");
+              goto errout;
+            }
 
-      ret = irq_attach(wdt->irq, handler, arg);
-      if (ret != OK)
+          esp32s2_rtcioirqenable(wdt->irq);
+        }
+      else
+#endif
         {
-          esp32s2_teardown_irq(wdt->periph, wdt->cpuint);
-          wderr("ERROR: Failed to associate an IRQ Number");
-          goto errout;
+          wdt->cpuint = esp32s2_setup_irq(wdt->periph, 1,
+                                          ESP32S2_CPUINT_LEVEL);
+          if (wdt->cpuint < 0)
+            {
+              wderr("ERROR: No CPU Interrupt available");
+              ret = wdt->cpuint;
+              goto errout;
+            }
+
+          /* Associate an IRQ Number (from the WDT) to an ISR */
+
+          ret = irq_attach(wdt->irq, handler, arg);
+          if (ret != OK)
+            {
+              esp32s2_teardown_irq(wdt->periph, wdt->cpuint);
+              wderr("ERROR: Failed to associate an IRQ Number");
+              goto errout;
+            }
+
+          /* Enable the CPU Interrupt that is linked to the WDT */
+
+          up_enable_irq(wdt->irq);
         }
-
-      /* Enable the CPU Interrupt that is linked to the WDT */
-
-      up_enable_irq(wdt->irq);
     }
 
 errout:

Reply via email to