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

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

commit 024364ebbd0b0cac0cd467a7ad232616f8c22c45
Author: Gustavo Henrique Nihei <[email protected]>
AuthorDate: Fri Mar 18 17:35:05 2022 -0300

    xtensa/esp32s3: Add support for GPIO pin interrupts
    
    Signed-off-by: Gustavo Henrique Nihei <[email protected]>
---
 arch/xtensa/include/esp32s3/irq.h      |  27 ++--
 arch/xtensa/src/esp32s3/Kconfig        |   6 +
 arch/xtensa/src/esp32s3/esp32s3_gpio.c | 223 +++++++++++++++++++++++++++++++++
 arch/xtensa/src/esp32s3/esp32s3_gpio.h |  82 ++++++++++--
 arch/xtensa/src/esp32s3/esp32s3_irq.c  |   5 +
 5 files changed, 323 insertions(+), 20 deletions(-)

diff --git a/arch/xtensa/include/esp32s3/irq.h 
b/arch/xtensa/include/esp32s3/irq.h
index fecdb3c..b379a22 100644
--- a/arch/xtensa/include/esp32s3/irq.h
+++ b/arch/xtensa/include/esp32s3/irq.h
@@ -26,6 +26,12 @@
 #define __ARCH_XTENSA_INCLUDE_ESP32S3_IRQ_H
 
 /****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
 
@@ -309,19 +315,20 @@
 
 #define ESP32S3_NIRQ_PERIPH                             ESP32S3_NPERIPHERALS
 
-/* Second level GPIO interrupts.  GPIO interrupts are decoded and dispatched
- * as a second level of decoding:  The first level dispatches to the GPIO
- * interrupt handler.  The second to the decoded GPIO interrupt handler.
+#ifdef CONFIG_ESP32S3_GPIO_IRQ
+
+/* Second level GPIO interrupts. GPIO interrupts are decoded and dispatched
+ * as a second level of decoding: The first level dispatches to the GPIO
+ * interrupt handler. The second to the decoded GPIO interrupt handler.
  */
 
-#ifdef CONFIG_ESP32S3_GPIO_IRQ
-#  define ESP32S3_NIRQ_GPIO           40
-#  define ESP32S3_FIRST_GPIOIRQ       (XTENSA_NIRQ_INTERNAL + 
ESP32S3_NIRQ_PERIPH)
-#  define ESP32S3_LAST_GPIOIRQ        (ESP32S3_FIRST_GPIOIRQ + 
ESP32S3_NIRQ_GPIO - 1)
-#  define ESP32S3_PIN2IRQ(p)          ((p) + ESP32S3_FIRST_GPIOIRQ)
-#  define ESP32S3_IRQ2PIN(i)          ((i) - ESP32S3_FIRST_GPIOIRQ)
+#  define ESP32S3_NIRQ_GPIO             49
+#  define ESP32S3_FIRST_GPIOIRQ         (XTENSA_NIRQ_INTERNAL + 
ESP32S3_NIRQ_PERIPH)
+#  define ESP32S3_LAST_GPIOIRQ          (ESP32S3_FIRST_GPIOIRQ + 
ESP32S3_NIRQ_GPIO - 1)
+#  define ESP32S3_PIN2IRQ(p)            ((p) + ESP32S3_FIRST_GPIOIRQ)
+#  define ESP32S3_IRQ2PIN(i)            ((i) - ESP32S3_FIRST_GPIOIRQ)
 #else
-#  define ESP32S3_NIRQ_GPIO           0
+#  define ESP32S3_NIRQ_GPIO             0
 #endif
 
 /* Total number of interrupts */
diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig
index ab7a142..d9896ab 100644
--- a/arch/xtensa/src/esp32s3/Kconfig
+++ b/arch/xtensa/src/esp32s3/Kconfig
@@ -511,6 +511,12 @@ config ESP32S3_SPIRAM_IGNORE_NOTFOUND
 
 endmenu # SPI RAM Configuration
 
+config ESP32S3_GPIO_IRQ
+       bool "GPIO pin interrupts"
+       default n
+       ---help---
+               Enable support for interrupting GPIO pins.
+
 menu "UART Configuration"
        depends on ESP32S3_UART
 
diff --git a/arch/xtensa/src/esp32s3/esp32s3_gpio.c 
b/arch/xtensa/src/esp32s3/esp32s3_gpio.c
index c8f499d..c10948a 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_gpio.c
+++ b/arch/xtensa/src/esp32s3/esp32s3_gpio.c
@@ -49,6 +49,10 @@
  * Private Data
  ****************************************************************************/
 
+#ifdef CONFIG_ESP32S3_GPIO_IRQ
+static int g_gpio_cpuint;
+#endif
+
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -75,6 +79,94 @@ static inline bool is_valid_gpio(uint32_t pin)
 }
 
 /****************************************************************************
+ * Name: gpio_dispatch
+ *
+ * Description:
+ *   Second level dispatch for GPIO interrupt handling.
+ *
+ * Input Parameters:
+ *   irq           - GPIO IRQ number.
+ *   status        - Value from the GPIO interrupt status clear register.
+ *   regs          - Saved CPU context.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_GPIO_IRQ
+static void gpio_dispatch(int irq, uint32_t status, uint32_t *regs)
+{
+  uint32_t mask;
+  int i;
+
+  /* Check each bit in the status register */
+
+  for (i = 0; i < 32 && status != 0; i++)
+    {
+      /* Check if there is an interrupt pending for this pin */
+
+      mask = UINT32_C(1) << i;
+      if ((status & mask) != 0)
+        {
+          /* Yes... perform the second level dispatch */
+
+          irq_dispatch(irq + i, regs);
+
+          /* Clear the bit in the status so that we might execute this loop
+           * sooner.
+           */
+
+          status &= ~mask;
+        }
+    }
+}
+#endif
+
+/****************************************************************************
+ * Name: gpio_interrupt
+ *
+ * Description:
+ *   GPIO interrupt handler.
+ *
+ * Input Parameters:
+ *   irq           - Identifier of the interrupt request.
+ *   context       - Context data from the ISR.
+ *   arg           - Opaque pointer to the internal driver state structure.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_GPIO_IRQ
+static int gpio_interrupt(int irq, void *context, void *arg)
+{
+  uint32_t status;
+
+  /* Read and clear the lower GPIO interrupt status */
+
+  status = getreg32(GPIO_STATUS_REG);
+  putreg32(status, GPIO_STATUS_W1TC_REG);
+
+  /* Dispatch pending interrupts in the lower GPIO status register */
+
+  gpio_dispatch(ESP32S3_FIRST_GPIOIRQ, status, (uint32_t *)context);
+
+  /* Read and clear the upper GPIO interrupt status */
+
+  status = getreg32(GPIO_STATUS1_REG);
+  putreg32(status, GPIO_STATUS1_W1TC_REG);
+
+  /* Dispatch pending interrupts in the lower GPIO status register */
+
+  gpio_dispatch(ESP32S3_FIRST_GPIOIRQ + 32, status, (uint32_t *)context);
+  return OK;
+}
+#endif
+
+/****************************************************************************
  * Public Functions
  ****************************************************************************/
 
@@ -275,6 +367,137 @@ bool esp32s3_gpioread(int pin)
 }
 
 /****************************************************************************
+ * Name: esp32s3_gpioirqinitialize
+ *
+ * Description:
+ *   Initialize logic to support a second level of interrupt decoding for
+ *   GPIO pins.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_GPIO_IRQ
+void esp32s3_gpioirqinitialize(void)
+{
+  int cpu;
+
+  /* Setup the GPIO interrupt. */
+
+  cpu = up_cpu_index();
+
+  g_gpio_cpuint = esp32s3_setup_irq(cpu, ESP32S3_PERIPH_GPIO_INT_CPU, 1,
+                                    ESP32S3_CPUINT_LEVEL);
+  DEBUGASSERT(g_gpio_cpuint >= 0);
+
+  /* Attach and enable the interrupt handler */
+
+  DEBUGVERIFY(irq_attach(ESP32S3_IRQ_GPIO_INT_CPU, gpio_interrupt, NULL));
+  up_enable_irq(ESP32S3_IRQ_GPIO_INT_CPU);
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s3_gpioirqenable
+ *
+ * Description:
+ *   Enable the interrupt for the specified GPIO IRQ.
+ *
+ * Input Parameters:
+ *   irq           - Identifier of the interrupt request.
+ *   intrtype      - Interrupt type, select from gpio_intrtype_t.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_GPIO_IRQ
+void esp32s3_gpioirqenable(int irq, gpio_intrtype_t intrtype)
+{
+  uintptr_t regaddr;
+  uint32_t regval;
+  int pin;
+
+  DEBUGASSERT(irq >= ESP32S3_FIRST_GPIOIRQ && irq <= ESP32S3_LAST_GPIOIRQ);
+
+  /* Convert the IRQ number to a pin number */
+
+  pin = ESP32S3_IRQ2PIN(irq);
+
+  /* Disable the GPIO interrupt during the configuration. */
+
+  up_disable_irq(ESP32S3_IRQ_GPIO_INT_CPU);
+
+  /* Get the address of the GPIO PIN register for this pin */
+
+  regaddr = GPIO_REG(pin);
+  regval  = getreg32(regaddr);
+  regval &= ~(GPIO_PIN0_INT_ENA_M | GPIO_PIN0_INT_TYPE_M);
+
+  /* Set the pin ENA field.
+   * On ESP32-S3, CPU0 and CPU1 share the same interrupt enable bit.
+   */
+
+  regval |= GPIO_PIN0_INT_ENA_M;
+  regval |= (uint32_t)intrtype << GPIO_PIN0_INT_TYPE_S;
+  putreg32(regval, regaddr);
+
+  /* Configuration done. Re-enable the GPIO interrupt. */
+
+  up_enable_irq(ESP32S3_IRQ_GPIO_INT_CPU);
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s3_gpioirqdisable
+ *
+ * Description:
+ *   Disable the interrupt for the specified GPIO IRQ.
+ *
+ * Input Parameters:
+ *   irq           - Identifier of the interrupt request.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_GPIO_IRQ
+void esp32s3_gpioirqdisable(int irq)
+{
+  uintptr_t regaddr;
+  uint32_t regval;
+  int pin;
+
+  DEBUGASSERT(irq >= ESP32S3_FIRST_GPIOIRQ && irq <= ESP32S3_LAST_GPIOIRQ);
+
+  /* Convert the IRQ number to a pin number */
+
+  pin = ESP32S3_IRQ2PIN(irq);
+
+  /* Disable the GPIO interrupt during the configuration. */
+
+  up_disable_irq(ESP32S3_IRQ_GPIO_INT_CPU);
+
+  /* Reset the pin ENA and TYPE fields */
+
+  regaddr = GPIO_REG(pin);
+  regval  = getreg32(regaddr);
+  regval &= ~(GPIO_PIN0_INT_ENA_M | GPIO_PIN0_INT_TYPE_M);
+  putreg32(regval, regaddr);
+
+  /* Configuration done. Re-enable the GPIO interrupt. */
+
+  up_enable_irq(ESP32S3_IRQ_GPIO_INT_CPU);
+}
+#endif
+
+/****************************************************************************
  * Name: esp32s3_gpio_matrix_in
  *
  * Description:
diff --git a/arch/xtensa/src/esp32s3/esp32s3_gpio.h 
b/arch/xtensa/src/esp32s3/esp32s3_gpio.h
index 35367d2..7d2c203 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_gpio.h
+++ b/arch/xtensa/src/esp32s3/esp32s3_gpio.h
@@ -93,15 +93,6 @@
 #  define OUTPUT_FUNCTION_5 (OUTPUT_FUNCTION | FUNCTION_5)
 #  define OUTPUT_FUNCTION_6 (OUTPUT_FUNCTION | FUNCTION_6)
 
-/* Interrupt type used with esp32s3_gpioirqenable() */
-
-#define DISABLED          0x00
-#define RISING            0x01
-#define FALLING           0x02
-#define CHANGE            0x03
-#define ONLOW             0x04
-#define ONHIGH            0x05
-
 /****************************************************************************
  * Public Types
  ****************************************************************************/
@@ -111,7 +102,16 @@
 /* Must be big enough to hold the above encodings */
 
 typedef uint16_t gpio_pinattr_t;
-typedef uint8_t gpio_intrtype_t;
+
+typedef enum gpio_intrtype_e
+{
+  GPIO_INTR_DISABLE    = 0,     /* Disable GPIO interrupt       */
+  GPIO_INTR_POSEDGE    = 1,     /* Rising edge                  */
+  GPIO_INTR_NEGEDGE    = 2,     /* Falling edge                 */
+  GPIO_INTR_ANYEDGE    = 3,     /* Both rising and falling edge */
+  GPIO_INTR_LOW_LEVEL  = 4,     /* Input low level trigger      */
+  GPIO_INTR_HIGH_LEVEL = 5      /* Input high level trigger     */
+} gpio_intrtype_t;
 
 /****************************************************************************
  * Public Data
@@ -131,6 +131,27 @@ extern "C"
  ****************************************************************************/
 
 /****************************************************************************
+ * Name: esp32s3_gpioirqinitialize
+ *
+ * Description:
+ *   Initialize logic to support a second level of interrupt decoding for
+ *   GPIO pins.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_GPIO_IRQ
+void esp32s3_gpioirqinitialize(void);
+#else
+#  define esp32s3_gpioirqinitialize()
+#endif
+
+/****************************************************************************
  * Name: esp32s3_configgpio
  *
  * Description:
@@ -190,6 +211,47 @@ void esp32s3_gpiowrite(int pin, bool value);
 bool esp32s3_gpioread(int pin);
 
 /****************************************************************************
+ * Name: esp32s3_gpioirqenable
+ *
+ * Description:
+ *   Enable the interrupt for the specified GPIO IRQ.
+ *
+ * Input Parameters:
+ *   irq           - Identifier of the interrupt request.
+ *   intrtype      - Interrupt type, select from gpio_intrtype_t.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_GPIO_IRQ
+void esp32s3_gpioirqenable(int irq, gpio_intrtype_t intrtype);
+#else
+#  define esp32s3_gpioirqenable(irq,intrtype)
+#endif
+
+/****************************************************************************
+ * Name: esp32s3_gpioirqdisable
+ *
+ * Description:
+ *   Disable the interrupt for the specified GPIO IRQ.
+ *
+ * Input Parameters:
+ *   irq           - Identifier of the interrupt request.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_GPIO_IRQ
+void esp32s3_gpioirqdisable(int irq);
+#else
+#  define esp32s3_gpioirqdisable(irq)
+#endif
+
+/****************************************************************************
  * Name: esp32s3_gpio_matrix_in
  *
  * Description:
diff --git a/arch/xtensa/src/esp32s3/esp32s3_irq.c 
b/arch/xtensa/src/esp32s3/esp32s3_irq.c
index 5e98d4b..c9f1d8e 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_irq.c
+++ b/arch/xtensa/src/esp32s3/esp32s3_irq.c
@@ -38,6 +38,7 @@
 
 #include "xtensa.h"
 
+#include "esp32s3_gpio.h"
 #include "esp32s3_irq.h"
 #ifdef CONFIG_SMP
 #include "esp32s3_smp.h"
@@ -446,6 +447,10 @@ void up_irqinitialize(void)
   xtensa_attach_fromcpu1_interrupt();
 #endif
 
+  /* Initialize GPIO interrupt support */
+
+  esp32s3_gpioirqinitialize();
+
 #ifndef CONFIG_SUPPRESS_INTERRUPTS
   /* And finally, enable interrupts.  Also clears PS.EXCM */
 

Reply via email to