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

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

commit e9e3a0ecf78c877eaf0c1199a3e7fba22a1762c3
Author: Eren Terzioglu <eren.terzio...@espressif.com>
AuthorDate: Tue Apr 8 15:47:22 2025 +0200

    arch/xtensa: Add dedicated GPIO support for esp32[-s2|-s3]
    
    Add dedicated GPIO support for Xtensa based Espressif devices
    
    Signed-off-by: Eren Terzioglu <eren.terzio...@espressif.com>
---
 arch/xtensa/src/common/espressif/Kconfig          |  18 +
 arch/xtensa/src/common/espressif/Make.defs        |   4 +
 arch/xtensa/src/common/espressif/esp_dedic_gpio.c | 744 ++++++++++++++++++++++
 arch/xtensa/src/common/espressif/esp_dedic_gpio.h | 182 ++++++
 arch/xtensa/src/esp32s2/hal.mk                    |   1 +
 arch/xtensa/src/esp32s3/hal.mk                    |   1 +
 6 files changed, 950 insertions(+)

diff --git a/arch/xtensa/src/common/espressif/Kconfig 
b/arch/xtensa/src/common/espressif/Kconfig
index cdbbd1b787..1630740716 100644
--- a/arch/xtensa/src/common/espressif/Kconfig
+++ b/arch/xtensa/src/common/espressif/Kconfig
@@ -135,6 +135,24 @@ config ESPRESSIF_SPIFLASH
        depends on ARCH_CHIP_ESP32S2
        default n
 
+config ESPRESSIF_DEDICATED_GPIO
+       bool "Dedicated GPIO"
+       depends on !ARCH_CHIP_ESP32
+       default n
+       ---help---
+               Enable dedicated GPIO support for faster response time.
+               Dedicated GPIO is suitable for faster response times required
+               applications like simulate serial/parallel interfaces in a 
bit-banging way.
+               It can work as pin grouping and you can use any pin up to 8 
pins for
+               input and 8 pins for output for dedicated gpio in total.
+
+config ESPRESSIF_DEDICATED_GPIO_IRQ
+       bool "Dedicated GPIO IRQ"
+       depends on ESPRESSIF_DEDICATED_GPIO && ARCH_CHIP_ESP32S2
+       default n
+       ---help---
+               Enable dedicated GPIO IRQ support
+
 menu "Pulse Counter (PCNT) Configuration"
        depends on ESP_PCNT
 
diff --git a/arch/xtensa/src/common/espressif/Make.defs 
b/arch/xtensa/src/common/espressif/Make.defs
index 47abe04293..225726f4e7 100644
--- a/arch/xtensa/src/common/espressif/Make.defs
+++ b/arch/xtensa/src/common/espressif/Make.defs
@@ -76,6 +76,10 @@ ifeq ($(CONFIG_ESPRESSIF_I2C_PERIPH_SLAVE_MODE),y)
 CHIP_CSRCS += esp_i2c_slave.c
 endif
 
+ifeq ($(CONFIG_ESPRESSIF_DEDICATED_GPIO),y)
+CHIP_CSRCS += esp_dedic_gpio.c
+endif
+
 ifeq ($(CONFIG_SYSTEM_NXDIAG_ESPRESSIF_CHIP_WO_TOOL),y)
 CHIP_CSRCS += esp_nxdiag.c
 endif
diff --git a/arch/xtensa/src/common/espressif/esp_dedic_gpio.c 
b/arch/xtensa/src/common/espressif/esp_dedic_gpio.c
new file mode 100644
index 0000000000..fab561f788
--- /dev/null
+++ b/arch/xtensa/src/common/espressif/esp_dedic_gpio.c
@@ -0,0 +1,744 @@
+/****************************************************************************
+ * arch/xtensa/src/common/espressif/esp_dedic_gpio.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/timers/capture.h>
+#include <nuttx/mutex.h>
+#include <nuttx/nuttx.h>
+#include <nuttx/kmalloc.h>
+#include <arch/irq.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/ioexpander/gpio.h>
+
+#include "chip.h"
+#include "esp_dedic_gpio.h"
+#if defined(CONFIG_ARCH_CHIP_ESP32S3)
+#include "esp32s3_gpio.h"
+#elif defined(CONFIG_ARCH_CHIP_ESP32S2)
+#include "esp32s2_irq.h"
+#include "esp32s2_gpio.h"
+#endif
+
+#if defined(CONFIG_ARCH_CHIP_ESP32S2)
+#include "soc/dedic_gpio_struct.h"
+#include "hal/dedic_gpio_ll.h"
+#endif
+#include "soc/dedic_gpio_periph.h"
+#include "hal/dedic_gpio_cpu_ll.h"
+#include "soc/gpio_sig_map.h"
+#include "periph_ctrl.h"
+#include "soc/soc_caps.h"
+#include "soc/gpio_pins.h"
+#include "esp_clk.h"
+#include "esp_attr.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_ARCH_CHIP_ESP32S3)
+#define esp_configgpio            esp32s3_configgpio
+#define esp_gpio_matrix_in        esp32s3_gpio_matrix_in
+#define esp_gpio_matrix_out       esp32s3_gpio_matrix_out
+#define ESP_IRQ_PRIORITY_DEFAULT  ESP32S3_INT_PRIO_DEF
+#define ESP_IRQ_TRIGGER_LEVEL     ESP32S3_CPUINT_LEVEL
+#elif defined(CONFIG_ARCH_CHIP_ESP32S2)
+#define esp_setup_irq             esp32s2_setup_irq
+#define esp_teardown_irq          esp32s2_teardown_irq
+#define esp_configgpio            esp32s2_configgpio
+#define esp_gpio_matrix_in        esp32s2_gpio_matrix_in
+#define esp_gpio_matrix_out       esp32s2_gpio_matrix_out
+#define ESP_IRQ_PRIORITY_DEFAULT  ESP32S2_INT_PRIO_DEF
+#define ESP_IRQ_TRIGGER_LEVEL     ESP32S2_CPUINT_LEVEL
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ
+enum esp_dedic_gpio_intr_type_t
+{
+  DEDIC_GPIO_INTR_NONE,          /* No interrupt */
+  DEDIC_GPIO_INTR_LOW_LEVEL = 2, /* Interrupt on low level */
+  DEDIC_GPIO_INTR_HIGH_LEVEL,    /* Interrupt on high level */
+  DEDIC_GPIO_INTR_NEG_EDGE,      /* Interrupt on negedge */
+  DEDIC_GPIO_INTR_POS_EDGE,      /* Interrupt on posedge */
+  DEDIC_GPIO_INTR_BOTH_EDGE      /* Interrupt on both negedge and posedge */
+};
+#endif
+
+struct esp_dedic_gpio_bundle_priv_s
+{
+  struct file_operations *ops;  /* Externally visible part of the GPIO 
interface */
+  uint32_t out_offset;          /* Offset of output channels */
+  uint32_t in_offset;           /* Offset of input channels */
+  uint32_t out_mask;            /* Mask of output channels */
+  uint32_t in_mask;             /* Mask of input channels */
+};
+
+struct esp_dedic_gpio_common_priv_s
+{
+  int refs;                       /* Reference count */
+  spinlock_t spinlock;            /* Held while chip is selected for mutual 
exclusion */
+  uint32_t out_occupied_mask;     /* Mask of output channels */
+  uint32_t in_occupied_mask;      /* Mask of input channels */
+#ifdef CONFIG_ARCH_CHIP_ESP32S2
+  dedic_dev_t *dev;
+#endif
+#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ
+  bool isr_init;                   /* ISR register flag for peripheral */
+  int (*cbs[SOC_DEDIC_GPIO_IN_CHANNELS_NUM])(struct file *filep, int pin);
+
+  /* Demonstrate that which bundle belongs to for input channel */
+
+  struct esp_dedic_gpio_bundle_priv_s *
+    in_bundles[SOC_DEDIC_GPIO_IN_CHANNELS_NUM];
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int esp_dedic_gpio_bundle_read(struct file *filep,
+                                      char *buffer,
+                                      size_t buflen);
+static int esp_dedic_gpio_bundle_write(struct file *filep,
+                                       const char *buffer,
+                                       size_t buflen);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct file_operations dedic_gpio_ops =
+{
+  NULL,                               /* open */
+  NULL,                               /* close */
+  esp_dedic_gpio_bundle_read,         /* read */
+  esp_dedic_gpio_bundle_write,        /* write */
+};
+
+static struct esp_dedic_gpio_common_priv_s
+  dedic_gpio_common[SOC_CPU_CORES_NUM] =
+{
+  0
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ
+
+/****************************************************************************
+ * Name: esp_dedic_gpio_pin_get_pin_attr
+ *
+ * Description:
+ *   Convert pin type to dedicated GPIO pin attr.
+ *
+ * Input Parameters:
+ *   pintype - The pin type. See nuttx/ioexpander/gpio.h.
+ *
+ * Returned Value:
+ *   Dedicated gpio driver pin attr if available, 0 otherwise.
+ *
+ ****************************************************************************/
+
+static int esp_dedic_gpio_pin_get_pin_attr(enum gpio_pintype_e pintype)
+{
+  switch (pintype)
+    {
+      case GPIO_INTERRUPT_LOW_PIN:
+        return DEDIC_GPIO_INTR_LOW_LEVEL;
+        break;
+      case GPIO_INTERRUPT_HIGH_PIN:
+        return DEDIC_GPIO_INTR_HIGH_LEVEL;
+        break;
+      case GPIO_INTERRUPT_FALLING_PIN:
+        return DEDIC_GPIO_INTR_NEG_EDGE;
+        break;
+      case GPIO_INTERRUPT_RISING_PIN:
+        return DEDIC_GPIO_INTR_POS_EDGE;
+        break;
+      case GPIO_INTERRUPT_BOTH_PIN:
+        return DEDIC_GPIO_INTR_BOTH_EDGE;
+        break;
+      default:
+        return DEDIC_GPIO_INTR_NONE;
+        break;
+    }
+
+  return DEDIC_GPIO_INTR_NONE;
+}
+
+/****************************************************************************
+ * Name: esp_pcnt_isr_default
+ *
+ * Description:
+ *   Handler for the dedicated GPIO controller interrupt.
+ *
+ * Input Parameters:
+ *   irq     - Number of the IRQ that generated the interrupt
+ *   context - Interrupt register state save info
+ *   arg     - PCNT controller private data
+ *
+ * Returned Value:
+ *   Standard interrupt return value.
+ *
+ ****************************************************************************/
+
+static int IRAM_ATTR esp_dedic_gpio_isr_default(int irq, void *context,
+                                                void *arg)
+{
+  struct esp_dedic_gpio_common_priv_s *platform =
+    (struct  esp_dedic_gpio_common_priv_s *)arg;
+  uint32_t flags = spin_lock_irqsave(dedic_gpio_common->spinlock);
+  uint32_t status = dedic_gpio_ll_get_interrupt_status(platform->dev);
+
+  dedic_gpio_ll_clear_interrupt_status(platform->dev, status);
+  spin_unlock_irqrestore(dedic_gpio_common->spinlock, flags);
+
+  while (status)
+    {
+      uint32_t channel = __builtin_ffs(status) - 1;
+      if (platform->cbs[channel] != NULL)
+        {
+          platform->cbs[channel]((struct file *)
+                                platform->in_bundles[channel],
+                                channel -
+                                  platform->in_bundles[channel]->in_offset);
+        }
+
+      status = status & (status - 1);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp_pcnt_isr_register
+ *
+ * Description:
+ *   This function registers an interrupt service routine (ISR) for the
+ *   peripheral. It allocates a CPU interrupt, attaches the ISR to the
+ *   interrupt, and returns the status of the operation.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   Returns OK on successful registration of the ISR; a negated errno value
+ *   is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int esp_dedic_gpio_isr_register(void)
+{
+  int cpuint;
+  int ret;
+  int cpu = this_cpu();
+  uint32_t status;
+
+  cpuint = esp_setup_irq(dedic_gpio_periph_signals.irq,
+                         ESP_IRQ_PRIORITY_DEFAULT,
+                         ESP_IRQ_TRIGGER_LEVEL);
+  if (cpuint < 0)
+    {
+      cperr("Failed to allocate a CPU interrupt.\n");
+      return ERROR;
+    }
+
+  ret = irq_attach(dedic_gpio_periph_signals.irq + XTENSA_IRQ_FIRSTPERIPH,
+                   esp_dedic_gpio_isr_default,
+                   &dedic_gpio_common[cpu]);
+  if (ret < 0)
+    {
+      cperr("Couldn't attach IRQ to handler.\n");
+      esp_teardown_irq(dedic_gpio_periph_signals.irq, cpuint);
+      return ERROR;
+    }
+
+  status = dedic_gpio_ll_get_interrupt_status(dedic_gpio_common[cpu].dev);
+  dedic_gpio_ll_clear_interrupt_status(dedic_gpio_common[cpu].dev, status);
+  up_enable_irq(dedic_gpio_periph_signals.irq + XTENSA_IRQ_FIRSTPERIPH);
+  return OK;
+}
+
+#endif /* CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ */
+
+/****************************************************************************
+ * Name: esp_dedic_gpio_bundle_read
+ *
+ * Description:
+ *   Read dedicated gpio bundle data.
+ *
+ * Input Parameters:
+ *   filep  - The pointer of file, represents each user using the device.
+ *   buffer - Buffer to read.
+ *   buflen - Not in use, have it for compatibility reasons.
+ *
+ * Returned Value:
+ *   OK
+ *
+ ****************************************************************************/
+
+static int esp_dedic_gpio_bundle_read(struct file *filep,
+                                      char *buffer,
+                                      size_t buflen)
+{
+  struct inode *inode = filep->f_inode;
+  struct esp_dedic_gpio_bundle_priv_s *priv = inode->i_private;
+  uint32_t dedic_value = 0;
+
+  UNUSED(buflen);
+  DEBUGASSERT(priv != NULL && buffer != NULL);
+
+  gpioinfo("Reading pin...\n");
+
+  dedic_value = dedic_gpio_cpu_ll_read_in();
+  *buffer = (dedic_value & priv->in_mask) >> (priv->in_offset);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_dedic_gpio_bundle_write
+ *
+ * Description:
+ *   Write data to the dedicated gpio bundle.
+ *
+ * Input Parameters:
+ *   filep  - The pointer of file, represents each user using the device.
+ *   buffer - Buffer to write value to GPIO bundle.
+ *   buflen - Mask of the value.
+ *
+ * Returned Value:
+ *   OK
+ *
+ ****************************************************************************/
+
+static int esp_dedic_gpio_bundle_write(struct file *filep,
+                                       const char *buffer,
+                                       size_t buflen)
+{
+  struct inode *inode = filep->f_inode;
+  struct esp_dedic_gpio_bundle_priv_s *priv = inode->i_private;
+  uint32_t mask_value = 0;
+  uint32_t write_value = 0;
+
+  DEBUGASSERT(priv != NULL);
+  gpioinfo("Writing %d with mask: %d\n", (int)*buffer, buflen);
+
+  mask_value = priv->out_mask & (buflen << priv->out_offset);
+  write_value = *(buffer) << priv->out_offset;
+
+  dedic_gpio_cpu_ll_write_mask(mask_value, write_value);
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ
+/****************************************************************************
+ * Name: esp_dedic_gpio_set_cb
+ *
+ * Description:
+ *   Set event callbacks
+ *
+ * Input Parameters:
+ *   dev      - Pointer to the dedicated gpio driver struct
+ *   mask     - Mask of the GPIOs to assign callback
+ *   pintype  - Type of interrupt to trigger
+ *   callback - Pointer to the ISR function.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void esp_dedic_gpio_set_cb(struct file *dev,
+                          uint32_t mask,
+                          enum gpio_pintype_e pintype,
+                          int (*callback)(struct file *dev, int pin))
+{
+  struct esp_dedic_gpio_bundle_priv_s *priv =
+    (struct esp_dedic_gpio_bundle_priv_s *)dev;
+  uint32_t channel_mask = priv->in_mask & (mask << priv->in_offset);
+  uint32_t channel = 0;
+  irqstate_t flags;
+  int cpu = this_cpu();
+  int pin_attr = esp_dedic_gpio_pin_get_pin_attr(pintype);
+
+  while (channel_mask)
+    {
+      channel = __builtin_ffs(channel_mask) - 1;
+      flags = spin_lock_irqsave(&dedic_gpio_common[cpu].spinlock);
+
+      dedic_gpio_ll_set_interrupt_type(dedic_gpio_common[cpu].dev,
+                                       channel,
+                                       pin_attr);
+      if (pin_attr != DEDIC_GPIO_INTR_NONE)
+        {
+          dedic_gpio_ll_enable_interrupt(dedic_gpio_common[cpu].dev,
+                                         1 << channel,
+                                         true);
+        }
+      else
+        {
+          dedic_gpio_ll_enable_interrupt(dedic_gpio_common[cpu].dev,
+                                         1 << channel,
+                                         false);
+        }
+
+      spin_unlock_irqrestore(&dedic_gpio_common[cpu].spinlock, flags);
+
+      dedic_gpio_common[cpu].cbs[channel] = callback;
+      dedic_gpio_common[cpu].in_bundles[channel] = priv;
+      channel_mask = channel_mask & (channel_mask - 1);
+    }
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_dedic_gpio_write
+ *
+ * Description:
+ *   Write data to the dedicated gpio bundle with given mask value.
+ *
+ * Input Parameters:
+ *   dev    - Pointer to the dedicated gpio driver struct
+ *   mask   - Mask of the GPIOs to be written
+ *   value  - Value to write
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void esp_dedic_gpio_write(struct file *dev,
+                          uint32_t mask,
+                          uint32_t value)
+{
+  struct esp_dedic_gpio_bundle_priv_s *priv =
+    (struct esp_dedic_gpio_bundle_priv_s *)dev;
+  uint32_t mask_value = priv->out_mask & (mask << priv->out_offset);
+  uint32_t write_value = value << priv->out_offset;
+
+  dedic_gpio_cpu_ll_write_mask(mask_value, write_value);
+}
+
+/****************************************************************************
+ * Name: esp_dedic_gpio_read
+ *
+ * Description:
+ *   Read dedicated gpio bundle data.
+ *
+ * Input Parameters:
+ *   dev    - Pointer to the dedicated gpio driver struct
+ *   value  - Pointer to the read data will be saved
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void esp_dedic_gpio_read(struct file *dev, int *value)
+{
+  struct esp_dedic_gpio_bundle_priv_s *priv =
+    (struct esp_dedic_gpio_bundle_priv_s *)dev;
+
+  *value = dedic_gpio_cpu_ll_read_in();
+  *value = ((*value) & priv->in_mask) >> (priv->in_offset);
+}
+
+/****************************************************************************
+ * Name: esp_dedic_gpio_new_bundle
+ *
+ * Description:
+ *   Request dedicated GPIO bundle and config it with given parameters.
+ *
+ * Input Parameters:
+ *   config - Dedicated GPIO bundle configuration
+ *
+ * Returned Value:
+ *   Valid GPIO device structure reference on success; NULL on failure.
+ *
+ ****************************************************************************/
+
+struct file *esp_dedic_gpio_new_bundle(
+    struct esp_dedic_gpio_config_s *config)
+{
+  struct esp_dedic_gpio_bundle_priv_s *priv = NULL;
+  irqstate_t flags = 0;
+  uint32_t out_mask = 0;
+  uint32_t in_mask = 0;
+  uint32_t pattern = 0;
+  uint32_t out_offset = 0;
+  uint32_t in_offset = 0;
+  gpio_pinattr_t attr = 0;
+  int cpu = this_cpu();
+#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ
+  int ret;
+#endif
+
+  DEBUGASSERT(config != NULL);
+  DEBUGASSERT(config->gpio_array != NULL && config->array_size > 0);
+  DEBUGASSERT(config->path != NULL);
+  DEBUGASSERT(config->flags->input_enable ||
+              config->flags->output_enable > 0);
+
+  if (dedic_gpio_common[cpu].refs == 0)
+    {
+      flags = spin_lock_irqsave(&dedic_gpio_common[cpu].spinlock);
+
+#ifdef CONFIG_ARCH_CHIP_ESP32S2
+      dedic_gpio_common[cpu].dev = &DEDIC_GPIO;
+#endif
+      periph_module_enable(dedic_gpio_periph_signals.module);
+      dedic_gpio_common[cpu].out_occupied_mask =
+        UINT32_MAX & ~((1 << SOC_DEDIC_GPIO_OUT_CHANNELS_NUM) - 1);
+      dedic_gpio_common[cpu].in_occupied_mask =
+        UINT32_MAX & ~((1 << SOC_DEDIC_GPIO_IN_CHANNELS_NUM) - 1);
+
+      spin_unlock_irqrestore(&dedic_gpio_common[cpu].spinlock, flags);
+    }
+
+  priv = kmm_zalloc(sizeof(struct esp_dedic_gpio_bundle_priv_s));
+  if (priv)
+    {
+      pattern = (1 << config->array_size) - 1;
+
+      /* configure outwards channels */
+
+      priv->ops = &dedic_gpio_ops;
+
+      out_offset = 0;
+      if (config->flags->output_enable)
+        {
+          if (config->array_size > SOC_DEDIC_GPIO_OUT_CHANNELS_NUM)
+            {
+              gpioerr("ERROR: array size(%d) exceeds maximum supported out\
+                       channels(%d)\n",
+                       config->array_size, SOC_DEDIC_GPIO_OUT_CHANNELS_NUM);
+              free(priv);
+              return NULL;
+            }
+
+          flags = spin_lock_irqsave(&dedic_gpio_common[cpu].spinlock);
+
+          for (int i = 0;
+                i <= SOC_DEDIC_GPIO_OUT_CHANNELS_NUM - config->array_size;
+                  i++)
+            {
+              if ((dedic_gpio_common[cpu].out_occupied_mask & (pattern << i))
+                   == 0)
+                {
+                  out_mask = pattern << i;
+                  out_offset = i;
+                  break;
+                }
+            }
+
+          if (out_mask)
+            {
+              dedic_gpio_common[cpu].out_occupied_mask |= out_mask;
+            }
+
+          spin_unlock_irqrestore(&dedic_gpio_common[cpu].spinlock, flags);
+          if (out_mask == 0)
+            {
+              gpioerr("ERROR: no free outward channels\n");
+              free(priv);
+              return NULL;
+            }
+
+          attr |= OUTPUT;
+
+#ifdef CONFIG_ARCH_CHIP_ESP32S2
+          dedic_gpio_ll_enable_instruction_access_out(
+            dedic_gpio_common[cpu].dev,
+            out_mask,
+            true);
+#endif
+          gpioinfo("New out bundle(%p), offset=%"PRIu32", mask(%"PRIx32")",
+                    priv, priv->out_offset, priv->out_mask);
+        }
+
+      if (config->flags->input_enable)
+        {
+          if (config->array_size > SOC_DEDIC_GPIO_IN_CHANNELS_NUM)
+            {
+              gpioerr("ERROR: array size(%d) exceeds maximum supported in\
+                       channels(%d)\n",
+                       config->array_size, SOC_DEDIC_GPIO_IN_CHANNELS_NUM);
+              free(priv);
+              return NULL;
+            }
+
+          flags = spin_lock_irqsave(&dedic_gpio_common[cpu].spinlock);
+
+          for (int i = 0;
+                i <= SOC_DEDIC_GPIO_IN_CHANNELS_NUM - config->array_size;
+                  i++)
+            {
+              if ((dedic_gpio_common[cpu].in_occupied_mask &
+                    (pattern << i)) == 0)
+                {
+                  in_mask = pattern << i;
+                  in_offset = i;
+                  break;
+                }
+            }
+
+          if (in_mask)
+            {
+              dedic_gpio_common[cpu].in_occupied_mask |= in_mask;
+            }
+
+          spin_unlock_irqrestore(&dedic_gpio_common[cpu].spinlock, flags);
+          if (in_mask == 0)
+            {
+              gpioerr("ERROR: no free inward channels\n");
+              free(priv);
+              return NULL;
+            }
+
+          attr |= INPUT;
+          gpioinfo("New in bundle(%p), offset=%"PRIu32", mask(%"PRIx32")",
+                    priv, priv->in_offset, priv->in_mask);
+        }
+
+      /* Route dedicated GPIO channel signals to GPIO matrix */
+
+      for (int i = 0; i < config->array_size; i++)
+        {
+          esp_configgpio(config->gpio_array[i], attr);
+          if (config->flags->input_enable)
+            {
+              esp_gpio_matrix_in(config->gpio_array[i],
+  dedic_gpio_periph_signals.cores[cpu].in_sig_per_channel[in_offset + i],
+  config->flags->invert_input_enable);
+            }
+
+          if (config->flags->output_enable)
+            {
+              esp_gpio_matrix_out(config->gpio_array[i],
+  dedic_gpio_periph_signals.cores[cpu].out_sig_per_channel[in_offset + i],
+  config->flags->invert_output_enable, 0);
+            }
+        }
+
+      priv->out_mask = out_mask;
+      priv->in_mask = in_mask;
+      priv->out_offset = out_offset;
+      priv->in_offset = in_offset;
+
+#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ
+      if (config->flags->input_enable &&
+          config->flags->intr_enable &&
+          dedic_gpio_common[cpu].isr_init == false)
+        {
+          ret = esp_dedic_gpio_isr_register();
+          if (ret != OK)
+            {
+              gpioerr("Failed to initialize interrupt\n");
+              free(priv);
+              return NULL;
+            }
+        }
+#endif
+    }
+  else
+    {
+      gpioerr("ERROR: memory allocation failed\n");
+      return NULL;
+    }
+
+  dedic_gpio_common[cpu].refs++;
+
+  register_driver(config->path, &dedic_gpio_ops,
+                  0666, priv);
+  return (struct file *)priv;
+}
+
+/****************************************************************************
+ * Name: esp_dedic_gpio_del_bundle
+ *
+ * Description:
+ *   Delete dedicated gpio bundle.
+ *
+ * Input Parameters:
+ *   dev - Pointer to the dedicated gpio driver struct
+ *
+ * Returned Value:
+ *   OK
+ *
+ ****************************************************************************/
+
+int esp_dedic_gpio_del_bundle(struct file *dev)
+{
+  struct esp_dedic_gpio_bundle_priv_s *priv =
+    (struct esp_dedic_gpio_bundle_priv_s *)dev;
+  int cpu = this_cpu();
+  irqstate_t flags = spin_lock_irqsave(&dedic_gpio_common[cpu].spinlock);
+
+  dedic_gpio_common[cpu].refs--;
+
+  dedic_gpio_common[cpu].out_occupied_mask &= ~(priv->out_mask);
+  dedic_gpio_common[cpu].in_occupied_mask &= ~(priv->in_mask);
+
+  if (dedic_gpio_common[cpu].refs == 0)
+    {
+      periph_module_disable(dedic_gpio_periph_signals.module);
+#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ
+      dedic_gpio_ll_enable_interrupt(dedic_gpio_common[cpu].dev,
+                                     ~0UL,
+                                     false);
+      up_disable_irq(dedic_gpio_periph_signals.irq + XTENSA_IRQ_FIRSTPERIPH);
+      dedic_gpio_common[cpu].isr_init = false;
+#endif
+    }
+
+  free(priv);
+  priv = NULL;
+  spin_unlock_irqrestore(&dedic_gpio_common[cpu].spinlock, flags);
+
+  return OK;
+}
diff --git a/arch/xtensa/src/common/espressif/esp_dedic_gpio.h 
b/arch/xtensa/src/common/espressif/esp_dedic_gpio.h
new file mode 100644
index 0000000000..f914a4ec68
--- /dev/null
+++ b/arch/xtensa/src/common/espressif/esp_dedic_gpio.h
@@ -0,0 +1,182 @@
+/****************************************************************************
+ * arch/xtensa/src/common/espressif/esp_dedic_gpio.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_DEDIC_GPIO_H
+#define __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_DEDIC_GPIO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/ioexpander/gpio.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+struct esp_dedic_gpio_flags_s
+{
+  bool input_enable;
+  bool invert_input_enable;
+  bool output_enable;
+  bool invert_output_enable;
+#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ
+  bool intr_enable;
+#endif
+};
+
+struct esp_dedic_gpio_config_s
+{
+  const int *gpio_array;                /* Array of GPIO numbers */
+  int array_size;                       /* Number of GPIOs in gpio_array */
+  struct esp_dedic_gpio_flags_s *flags; /* Flags to control specific behaviour 
of GPIO bundle */
+  char *path;                           /* Path for character driver */
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ
+/****************************************************************************
+ * Name: esp_dedic_gpio_set_cb
+ *
+ * Description:
+ *   Set event callbacks
+ *
+ * Input Parameters:
+ *   dev      - Pointer to the dedicated gpio driver struct
+ *   mask     - Mask of the GPIOs to assign callback
+ *   pintype  - Type of interrupt to trigger
+ *   callback - Pointer to the ISR function.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void esp_dedic_gpio_set_cb(struct file *dev,
+                          uint32_t mask,
+                          enum gpio_pintype_e pintype,
+                          int (*callback)(struct file *dev, int pin));
+#endif
+
+/****************************************************************************
+ * Name: esp_dedic_gpio_write
+ *
+ * Description:
+ *   Write data to the dedicated gpio bundle with given mask value.
+ *
+ * Input Parameters:
+ *   dev    - Pointer to the dedicated gpio driver struct
+ *   mask   - Mask of the GPIOs to be written
+ *   value  - Value to write
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void esp_dedic_gpio_write(struct file *dev,
+                          uint32_t mask,
+                          uint32_t value);
+
+/****************************************************************************
+ * Name: esp_dedic_gpio_read
+ *
+ * Description:
+ *   Read dedicated gpio bundle data.
+ *
+ * Input Parameters:
+ *   dev    - Pointer to the dedicated gpio driver struct
+ *   value  - Pointer to the read data will be saved
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void esp_dedic_gpio_read(struct file *dev, int *value);
+
+/****************************************************************************
+ * Name: esp_dedic_gpio_new_bundle
+ *
+ * Description:
+ *   Request dedicated GPIO bundle and config it with given parameters.
+ *
+ * Input Parameters:
+ *   config - Dedicated GPIO bundle configuration
+ *
+ * Returned Value:
+ *   Valid GPIO device structure reference on success; NULL on failure.
+ *
+ ****************************************************************************/
+
+struct file *esp_dedic_gpio_new_bundle(
+    struct esp_dedic_gpio_config_s *config);
+
+/****************************************************************************
+ * Name: esp_dedic_gpio_del_bundle
+ *
+ * Description:
+ *   Delete dedicated gpio bundle.
+ *
+ * Input Parameters:
+ *   dev - Pointer to the dedicated gpio driver struct
+ *
+ * Returned Value:
+ *   OK on success; ERROR on failure
+ *
+ ****************************************************************************/
+
+int esp_dedic_gpio_del_bundle(struct file *dev);
+
+#ifdef __cplusplus
+}
+#endif
+#undef EXTERN
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_DEDIC_GPIO_H */
diff --git a/arch/xtensa/src/esp32s2/hal.mk b/arch/xtensa/src/esp32s2/hal.mk
index cab80c3ce1..11471360b6 100644
--- a/arch/xtensa/src/esp32s2/hal.mk
+++ b/arch/xtensa/src/esp32s2/hal.mk
@@ -126,6 +126,7 @@ CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log_noos.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)adc_periph.c
+CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)dedic_gpio_periph.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)pcnt_periph.c
diff --git a/arch/xtensa/src/esp32s3/hal.mk b/arch/xtensa/src/esp32s3/hal.mk
index e7efe93476..19ae6f9b23 100644
--- a/arch/xtensa/src/esp32s3/hal.mk
+++ b/arch/xtensa/src/esp32s3/hal.mk
@@ -139,6 +139,7 @@ CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)uart_hal.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log_noos.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log.c
+CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)dedic_gpio_periph.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gdma_periph.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)adc_periph.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c


Reply via email to