You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2023/06/16 19:07:11 UTC

[nuttx] branch master updated: xtensa/esp32s3: SPI support quad I/O mode

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


The following commit(s) were added to refs/heads/master by this push:
     new 8f25329260 xtensa/esp32s3: SPI support quad I/O mode
8f25329260 is described below

commit 8f25329260c5b34f413d3ac331e3a8a54a7b20c6
Author: Dong Heng <do...@espressif.com>
AuthorDate: Sat May 6 15:20:48 2023 +0800

    xtensa/esp32s3: SPI support quad I/O mode
---
 arch/xtensa/src/esp32s3/Kconfig             |   80 +-
 arch/xtensa/src/esp32s3/Make.defs           |   13 +-
 arch/xtensa/src/esp32s3/esp32s3_qspi.c      | 1610 +++++++++++++++++++++++++++
 arch/xtensa/src/esp32s3/esp32s3_qspi.h      |  126 +++
 arch/xtensa/src/esp32s3/esp32s3_spi.c       |  105 +-
 arch/xtensa/src/esp32s3/esp32s3_spi_slave.c |  380 +++++--
 6 files changed, 2127 insertions(+), 187 deletions(-)

diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig
index 9f3b569616..d9424a85d8 100644
--- a/arch/xtensa/src/esp32s3/Kconfig
+++ b/arch/xtensa/src/esp32s3/Kconfig
@@ -594,9 +594,22 @@ config ESP32S3_RTCIO_IRQ
 menu "SPI configuration"
 	depends on ESP32S3_SPI
 
+choice
+	prompt "SPI I/O Mode"
+	default ESP32S3_SPI_IO_SPI
+
+config ESP32S3_SPI_IO_SPI
+	bool "SPI (4-line)"
+
+config ESP32S3_SPI_IO_QIO
+	bool "QIO (6-line)"
+
+endchoice # SPI I/O Mode
+
 config ESP32S3_SPI_SWCS
 	bool "SPI software CS"
 	default n
+	depends on ESP32S3_SPI_IO_SPI
 	---help---
 		Use SPI software CS.
 
@@ -607,36 +620,34 @@ config ESP32S3_SPI_UDCS
 	---help---
 		Use user-defined CS.
 
-config ESP32S3_SPI_SLAVE_BUFSIZE
-	int "SPI slave buffer size"
-	default 2048
-	depends on SPI_SLAVE
-
-if ESP32S3_SPI2
-
-config ESP32S3_SPI2_DMA
-	bool "SPI2 use GDMA"
+config ESP32S3_SPI_DMA
+	bool "SPI use GDMA"
 	default n
-	depends on ESP32S3_DMA
+	select ESP32S3_DMA
 	---help---
 		Enable support for transfers using the GDMA engine.
 
-config ESP32S3_SPI2_DMADESC_NUM
-	int "SPI2 Master GDMA maximum number of descriptors"
-	default 2
-	depends on ESP32S3_SPI2_DMA
+config ESP32S3_SPI_DMA_BUFSIZE
+	int "SPI Master GDMA buffer size"
+	default 2048
+	depends on ESP32S3_SPI_DMA
 	---help---
-		Configure the maximum number of out-link/in-link descriptors to
-		be chained for a GDMA transfer.
+		This is used to calculate and allocate DMA description buffer,
+		not really allocate TX/RX buffer.
 
-config ESP32S3_SPI2_DMATHRESHOLD
-	int "SPI2 Master GDMA threshold"
+config ESP32S3_SPI_DMATHRESHOLD
+	int "SPI Master GDMA threshold"
 	default 64
-	depends on ESP32S3_SPI2_DMA
+	depends on ESP32S3_SPI_DMA && ESP32S3_SPI_IO_SPI
 	---help---
 		When SPI GDMA is enabled, GDMA transfers whose size are below the
 		defined threshold will be performed by polling logic.
 
+config ESP32S3_SPI_SLAVE_BUFSIZE
+	int "SPI Slave buffer size"
+	default 2048
+	depends on SPI_SLAVE
+
 config ESP32S3_SPI2_CSPIN
 	int "SPI2 CS Pin"
 	default 10
@@ -657,16 +668,17 @@ config ESP32S3_SPI2_MISOPIN
 	default 13
 	range 0 48
 
-endif # ESP32S3_SPI2
-
-if ESP32S3_SPI3
+config ESP32S3_SPI2_IO2PIN
+	int "SPI2 IO2 Pin"
+	default 14
+	range 0 48
+	depends on ESP32S3_SPI_IO_QIO
 
-config ESP32S3_SPI3_DMA
-	bool "SPI3 use GDMA"
-	default n
-	depends on ESP32S3_DMA
-	---help---
-		Enable support for transfers using the GDMA engine.
+config ESP32S3_SPI2_IO3PIN
+	int "SPI2 IO3 Pin"
+	default 9
+	range 0 48
+	depends on ESP32S3_SPI_IO_QIO
 
 config ESP32S3_SPI3_CSPIN
 	int "SPI3 CS Pin"
@@ -688,7 +700,17 @@ config ESP32S3_SPI3_MISOPIN
 	default 2
 	range 0 48
 
-endif # ESP32S3_SPI3
+config ESP32S3_SPI3_IO2PIN
+	int "SPI3 IO2 Pin"
+	default 3
+	range 0 48
+	depends on ESP32S3_SPI_IO_QIO
+
+config ESP32S3_SPI3_IO3PIN
+	int "SPI3 IO3 Pin"
+	default 4
+	range 0 48
+	depends on ESP32S3_SPI_IO_QIO
 
 endmenu # SPI configuration
 
diff --git a/arch/xtensa/src/esp32s3/Make.defs b/arch/xtensa/src/esp32s3/Make.defs
index 65a6a301de..9aee50cb9e 100644
--- a/arch/xtensa/src/esp32s3/Make.defs
+++ b/arch/xtensa/src/esp32s3/Make.defs
@@ -106,10 +106,15 @@ CHIP_CSRCS += esp32s3_i2c.c
 endif
 
 ifeq ($(CONFIG_ESP32S3_SPI),y)
-CHIP_CSRCS += esp32s3_spi.c
-ifeq ($(CONFIG_SPI_SLAVE),y)
-CHIP_CSRCS += esp32s3_spi_slave.c
-endif
+  ifeq ($(CONFIG_ESP32S3_SPI_IO_SPI),y)
+    CHIP_CSRCS += esp32s3_spi.c
+  else
+    CHIP_CSRCS += esp32s3_qspi.c
+  endif
+
+  ifeq ($(CONFIG_SPI_SLAVE),y)
+    CHIP_CSRCS += esp32s3_spi_slave.c
+  endif
 endif
 
 ifeq ($(CONFIG_ESP32S3_SPIFLASH),y)
diff --git a/arch/xtensa/src/esp32s3/esp32s3_qspi.c b/arch/xtensa/src/esp32s3/esp32s3_qspi.c
new file mode 100644
index 0000000000..9ac7f1b655
--- /dev/null
+++ b/arch/xtensa/src/esp32s3/esp32s3_qspi.c
@@ -0,0 +1,1610 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s3/esp32s3_qspi.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifdef CONFIG_ESP32S3_SPI
+
+#include <assert.h>
+#include <debug.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+#include <nuttx/mutex.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/spi/qspi.h>
+
+#include <arch/board/board.h>
+
+#include "xtensa.h"
+#include "hardware/esp32s3_gpio_sigmap.h"
+#include "hardware/esp32s3_pinmap.h"
+#include "hardware/esp32s3_spi.h"
+#include "hardware/esp32s3_soc.h"
+#include "hardware/esp32s3_system.h"
+
+#include "esp32s3_irq.h"
+#include "esp32s3_gpio.h"
+#include "esp32s3_qspi.h"
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+#include "esp32s3_dma.h"
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+
+/* QSPI maximum DMA buffer size in bytes */
+
+#define QSPI_DMA_BUFSIZE CONFIG_ESP32S3_SPI_DMA_BUFSIZE
+
+/* QSPI DMA RX/TX number of descriptors */
+
+#  if (QSPI_DMA_BUFSIZE % ESP32S3_DMA_BUFLEN_MAX) > 0
+#    define QSPI_DMA_DESC_NUM (QSPI_DMA_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX + 1)
+#  else
+#    define QSPI_DMA_DESC_NUM (QSPI_DMA_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX)
+#  endif
+
+/* QSPI DMA reset before exchange */
+
+#  define QSPI_DMA_RESET_MASK (SPI_DMA_AFIFO_RST_M | SPI_RX_AFIFO_RST_M)
+
+#endif /* CONFIG_ESP32S3_SPI_DMA */
+
+/* QSPI default frequency (limited by clock divider) */
+
+#define QSPI_DEFAULT_FREQ   (400000)
+
+/* QSPI default width */
+
+#define QSPI_DEFAULT_WIDTH  (8)
+
+/* QSPI default mode */
+
+#define QSPI_DEFAULT_MODE   (QSPIDEV_MODE0)
+
+/* QSPI maximum non-DMA buffer size in bytes */
+
+#define QSPI_CMD_BUFSIZE    (64)
+
+/* Verify whether QSPI has been assigned IOMUX pins.
+ * Otherwise, QSPI signals will be routed via GPIO Matrix.
+ */
+
+#ifdef CONFIG_ESP32S3_SPI2
+
+/* In quad QSPI mode, data IO map is:
+ *    MOSI -> IO0
+ *    MISO -> IO1
+ *    WP   -> IO2
+ *    Hold -> IO3
+ */
+
+#  define QSPI_IS_CS_IOMUX    (CONFIG_ESP32S3_SPI2_CSPIN == SPI2_IOMUX_CSPIN)
+#  define QSPI_IS_CLK_IOMUX   (CONFIG_ESP32S3_SPI2_CLKPIN == SPI2_IOMUX_CLKPIN)
+#  define QSPI_IS_MOSI_IOMUX  (CONFIG_ESP32S3_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN)
+#  define QSPI_IS_MISO_IOMUX  (CONFIG_ESP32S3_SPI2_MISOPIN == SPI2_IOMUX_MISOPIN)
+#  define QSPI_IS_IO2_IOMUX   (CONFIG_ESP32S3_SPI2_IO2PIN == SPI2_IOMUX_WPPIN)
+#  define QSPI_IS_IO3_IOMUX   (CONFIG_ESP32S3_SPI2_IO3PIN == SPI2_IOMUX_HDPIN)
+
+#  define QSPI_VIA_IOMUX      ((QSPI_IS_CS_IOMUX) && \
+                               (QSPI_IS_CLK_IOMUX) && \
+                               (QSPI_IS_MOSI_IOMUX) && \
+                               (QSPI_IS_MISO_IOMUX) && \
+                               (QSPI_IS_IO2_IOMUX) && \
+                               (QSPI_IS_IO3_IOMUX))
+#else
+#  define QSPI_VIA_IOMUX      0
+#endif
+
+/* Check if 16-bit command or 8 bit command and return its bits */
+
+#define QSPI_CMD_BITS(cmd)    ((cmd) & 0xff00 ? 16 : 8)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* QSPI Device hardware configuration */
+
+struct esp32s3_qspi_config_s
+{
+  uint8_t id;                 /* ESP32-S3 QSPI device ID: SPIx {2,3} */
+
+  uint8_t cs_pin;             /* GPIO configuration for CS */
+  uint8_t mosi_pin;           /* GPIO configuration for MOSI */
+  uint8_t miso_pin;           /* GPIO configuration for MISO */
+  uint8_t clk_pin;            /* GPIO configuration for CLK */
+  uint8_t io2_pin;            /* GPIO configuration for IO2 */
+  uint8_t io3_pin;            /* GPIO configuration for IO3 */
+
+  int8_t periph;              /* Peripheral ID */
+  uint8_t irq;                /* Interrupt ID */
+
+  uint32_t clk_bit;           /* Clock enable bit */
+  uint32_t rst_bit;           /* QSPI reset bit */
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+
+  /* Peripheral for which the DMA channel request */
+
+  enum esp32s3_dma_periph_e dma_periph;
+  uint32_t dma_clk_bit;       /* DMA clock enable bit */
+  uint32_t dma_rst_bit;       /* DMA reset bit */
+#endif
+
+  uint32_t cs_insig;          /* QSPI CS input signal index */
+  uint32_t cs_outsig;         /* QSPI CS output signal index */
+  uint32_t mosi_insig;        /* QSPI MOSI input signal index */
+  uint32_t mosi_outsig;       /* QSPI MOSI output signal index */
+  uint32_t miso_insig;        /* QSPI MISO input signal index */
+  uint32_t miso_outsig;       /* QSPI MISO output signal index */
+  uint32_t clk_insig;         /* QSPI CLK input signal index */
+  uint32_t clk_outsig;        /* QSPI CLK output signal index */
+  uint32_t io2_insig;         /* QSPI IO2 input signal index */
+  uint32_t io2_outsig;        /* QSPI IO2 output signal index */
+  uint32_t io3_insig;         /* QSPI IO3 input signal index */
+  uint32_t io3_outsig;        /* QSPI IO3 output signal index */
+};
+
+struct esp32s3_qspi_priv_s
+{
+  /* Externally visible part of the (Q)QSPI interface */
+
+  struct qspi_dev_s spi_dev;
+
+  /* Port configuration */
+
+  const struct esp32s3_qspi_config_s *config;
+
+  int refs;               /* Reference count */
+  mutex_t lock;           /* Held while chip is selected for mutual exclusion */
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  sem_t sem_isr;          /* Interrupt wait semaphore */
+
+  int cpu;                /* CPU ID */
+  int cpuint;             /* QSPI interrupt ID */
+
+  int32_t dma_channel;    /* Channel assigned by the GDMA driver */
+
+  /* DMA description */
+
+  struct esp32s3_dmadesc_s *dma_desc;
+#endif
+
+  uint32_t frequency;     /* Requested clock frequency */
+  uint32_t actual;        /* Actual clock frequency */
+  enum qspi_mode_e mode;  /* Actual QSPI hardware mode */
+  uint8_t nbits;          /* Actual QSPI send/receive bits once transmission */
+
+  uint8_t dummies;        /* Number of dummy cycles of command transfer */
+  uint8_t addr_lines;     /* Number of address transmiting I/O pins */
+  uint8_t data_lines;     /* Number of data transmiting I/O pins */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int esp32s3_qspi_lock(struct qspi_dev_s *dev, bool lock);
+static uint32_t esp32s3_qspi_setfrequency(struct qspi_dev_s *dev,
+                                          uint32_t frequency);
+static void esp32s3_qspi_setmode(struct qspi_dev_s *dev,
+                                 enum qspi_mode_e mode);
+static void esp32s3_qspi_setbits(struct qspi_dev_s *dev, int nbits);
+static int esp32s3_qspi_command(struct qspi_dev_s *dev,
+                                struct qspi_cmdinfo_s *cmdinfo);
+static int esp32s3_qspi_memory(struct qspi_dev_s *dev,
+                               struct qspi_meminfo_s *meminfo);
+static void *esp32s3_qspi_alloc(struct qspi_dev_s *dev, size_t buflen);
+static void esp32s3_qspi_free(struct qspi_dev_s *dev, void *buffer);
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+static int esp32s3_qspi_interrupt(int irq, void *context, void *arg);
+static int esp32s3_qspi_wait_sem(struct esp32s3_qspi_priv_s *priv);
+static void esp32s3_qspi_init_dma(struct esp32s3_qspi_priv_s *priv);
+#endif
+static void esp32s3_qspi_init(struct esp32s3_qspi_priv_s *priv);
+static void esp32s3_qspi_deinit(struct esp32s3_qspi_priv_s *priv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_SPI2
+static const struct esp32s3_qspi_config_s esp32s3_spi2_config =
+{
+  .id           = 2,
+
+  .cs_pin       = CONFIG_ESP32S3_SPI2_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S3_SPI2_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S3_SPI2_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S3_SPI2_CLKPIN,
+  .io2_pin      = CONFIG_ESP32S3_SPI2_IO2PIN,
+  .io3_pin      = CONFIG_ESP32S3_SPI2_IO3PIN,
+
+  .periph       = ESP32S3_PERIPH_SPI2,
+  .irq          = ESP32S3_IRQ_SPI2,
+
+  .clk_bit      = SYSTEM_SPI2_CLK_EN,
+  .rst_bit      = SYSTEM_SPI2_RST,
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  .dma_periph   = ESP32S3_DMA_PERIPH_SPI2,
+  .dma_clk_bit  = SYSTEM_SPI2_DMA_CLK_EN,
+  .dma_rst_bit  = SYSTEM_SPI2_DMA_RST,
+#endif
+
+  .cs_insig     = FSPICS0_IN_IDX,
+  .cs_outsig    = FSPICS0_OUT_IDX,
+  .mosi_insig   = FSPID_IN_IDX,
+  .mosi_outsig  = FSPID_OUT_IDX,
+  .miso_insig   = FSPIQ_IN_IDX,
+  .miso_outsig  = FSPIQ_OUT_IDX,
+  .clk_insig    = FSPICLK_IN_IDX,
+  .clk_outsig   = FSPICLK_OUT_IDX,
+  .io2_insig    = FSPIWP_IN_IDX,
+  .io2_outsig   = FSPIWP_OUT_IDX,
+  .io3_insig    = FSPIHD_IN_IDX,
+  .io3_outsig   = FSPIHD_OUT_IDX,
+};
+
+static const struct qspi_ops_s esp32s3_spi2_ops =
+{
+  .lock         = esp32s3_qspi_lock,
+  .setfrequency = esp32s3_qspi_setfrequency,
+  .setmode      = esp32s3_qspi_setmode,
+  .setbits      = esp32s3_qspi_setbits,
+  .command      = esp32s3_qspi_command,
+  .memory       = esp32s3_qspi_memory,
+  .alloc        = esp32s3_qspi_alloc,
+  .free         = esp32s3_qspi_free,
+};
+
+#  ifdef CONFIG_ESP32S3_SPI_DMA
+
+/* QSPI 2 DMA RX/TX description */
+
+static struct esp32s3_dmadesc_s esp32s3_spi2_dma_desc[QSPI_DMA_DESC_NUM];
+#  endif
+
+static struct esp32s3_qspi_priv_s esp32s3_spi2_priv =
+{
+  .spi_dev     =
+    {
+      .ops     = &esp32s3_spi2_ops
+    },
+
+  .config      = &esp32s3_spi2_config,
+
+  .refs        = 0,
+  .lock        = NXMUTEX_INITIALIZER,
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  .sem_isr     = SEM_INITIALIZER(0),
+
+  .cpu         = 0,
+  .cpuint      = -ENOMEM,
+
+  .dma_channel = -1,
+  .dma_desc    = esp32s3_spi2_dma_desc,
+#endif
+
+  .frequency   = 0,
+  .actual      = 0,
+  .mode        = QSPIDEV_MODE0,
+  .nbits       = 0,
+
+  .dummies     = 0,
+  .addr_lines  = 4,
+  .data_lines  = 4,
+};
+#endif /* CONFIG_ESP32S3_SPI2 */
+
+#ifdef CONFIG_ESP32S3_SPI3
+static const struct esp32s3_qspi_config_s esp32s3_spi3_config =
+{
+  .id           = 3,
+
+  .cs_pin       = CONFIG_ESP32S3_SPI3_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S3_SPI3_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S3_SPI3_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S3_SPI3_CLKPIN,
+  .io2_pin      = CONFIG_ESP32S3_SPI3_IO2PIN,
+  .io3_pin      = CONFIG_ESP32S3_SPI3_IO3PIN,
+
+  .periph       = ESP32S3_PERIPH_SPI3,
+  .irq          = ESP32S3_IRQ_SPI3,
+
+  .clk_bit      = SYSTEM_SPI3_CLK_EN,
+  .rst_bit      = SYSTEM_SPI3_RST,
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  .dma_periph   = ESP32S3_DMA_PERIPH_SPI3,
+  .dma_clk_bit  = SYSTEM_SPI3_DMA_CLK_EN,
+  .dma_rst_bit  = SYSTEM_SPI3_DMA_RST,
+#endif
+
+  .cs_insig     = SPI3_CS0_IN_IDX,
+  .cs_outsig    = SPI3_CS0_OUT_IDX,
+  .mosi_insig   = SPI3_D_IN_IDX,
+  .mosi_outsig  = SPI3_D_OUT_IDX,
+  .miso_insig   = SPI3_Q_IN_IDX,
+  .miso_outsig  = SPI3_Q_OUT_IDX,
+  .clk_insig    = SPI3_CLK_IN_IDX,
+  .clk_outsig   = SPI3_CLK_OUT_IDX,
+  .io2_insig    = SPI3_WP_IN_IDX,
+  .io2_outsig   = SPI3_WP_OUT_IDX,
+  .io3_insig    = SPI3_HD_IN_IDX,
+  .io3_outsig   = SPI3_HD_OUT_IDX,
+};
+
+static const struct qspi_ops_s esp32s3_spi3_ops =
+{
+  .lock         = esp32s3_qspi_lock,
+  .setfrequency = esp32s3_qspi_setfrequency,
+  .setmode      = esp32s3_qspi_setmode,
+  .setbits      = esp32s3_qspi_setbits,
+  .command      = esp32s3_qspi_command,
+  .memory       = esp32s3_qspi_memory,
+  .alloc        = esp32s3_qspi_alloc,
+  .free         = esp32s3_qspi_free,
+};
+
+#  ifdef CONFIG_ESP32S3_SPI_DMA
+
+/* QSPI 3 DMA description */
+
+static struct esp32s3_dmadesc_s esp32s3_spi3_dma_desc[QSPI_DMA_DESC_NUM];
+#  endif
+
+static struct esp32s3_qspi_priv_s esp32s3_spi3_priv =
+{
+  .spi_dev     =
+    {
+      .ops     = &esp32s3_spi3_ops
+    },
+
+  .config      = &esp32s3_spi3_config,
+
+  .refs        = 0,
+  .lock        = NXMUTEX_INITIALIZER,
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  .sem_isr     = SEM_INITIALIZER(0),
+
+  .cpu         = 0,
+  .cpuint      = -ENOMEM,
+
+  .dma_channel = -1,
+  .dma_desc    = esp32s3_spi3_dma_desc,
+#endif
+
+  .frequency   = 0,
+  .actual      = 0,
+  .mode        = QSPIDEV_MODE0,
+  .nbits       = 0,
+
+  .dummies     = 0,
+  .addr_lines  = 4,
+  .data_lines  = 4,
+};
+#endif /* CONFIG_ESP32S3_SPI3 */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s3_qspi_lock
+ *
+ * Description:
+ *   Lock or unlock the QSPI device.
+ *
+ * Input Parameters:
+ *   dev  - Device-specific state data
+ *   lock - true: Lock QSPI bus, false: unlock QSPI bus
+ *
+ * Returned Value:
+ *   The result of lock or unlock the QSPI device.
+ *
+ ****************************************************************************/
+
+static int esp32s3_qspi_lock(struct qspi_dev_s *dev, bool lock)
+{
+  int ret;
+  struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+
+  if (lock)
+    {
+      ret = nxmutex_lock(&priv->lock);
+    }
+  else
+    {
+      ret = nxmutex_unlock(&priv->lock);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_setfrequency
+ *
+ * Description:
+ *   Set the QSPI frequency.
+ *
+ * Input Parameters:
+ *   dev       - Device-specific state data
+ *   frequency - The requested QSPI frequency
+ *
+ * Returned Value:
+ *   Returns the current selected frequency.
+ *
+ ****************************************************************************/
+
+static uint32_t esp32s3_qspi_setfrequency(struct qspi_dev_s *dev,
+                                          uint32_t frequency)
+{
+  uint32_t regval;
+  struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+  const uint32_t duty_cycle = 128;
+
+  if (priv->frequency == frequency)
+    {
+      /* Requested frequency is the same as the current frequency. */
+
+      return priv->actual;
+    }
+
+  /* In HW, n, h and l fields range from 1 to 64, pre ranges from 1 to 8K.
+   * The value written to register is one lower than the used value.
+   */
+
+  if (frequency > ((APB_CLK_FREQ / 4) * 3))
+    {
+      /* Using APB frequency directly will give us the best result here. */
+
+      regval = SPI_CLK_EQU_SYSCLK_M;
+      priv->actual = APB_CLK_FREQ;
+    }
+  else
+    {
+      /* For best duty cycle resolution, we want n to be as close to 32 as
+       * possible, but we also need a pre/n combo that gets us as close as
+       * possible to the intended frequency. To do this, we bruteforce n and
+       * calculate the best pre to go along with that. If there's a choice
+       * between pre/n combos that give the same result, use the one with the
+       * higher n.
+       */
+
+      int32_t pre;
+      int32_t n;
+      int32_t h;
+      int32_t l;
+      int32_t bestn = -1;
+      int32_t bestpre = -1;
+      int32_t besterr = 0;
+      int32_t errval;
+
+      /* Start at n = 2. We need to be able to set h/l so we have at least
+       * one high and one low pulse.
+       */
+
+      for (n = 2; n <= 64; n++)
+        {
+          /* Effectively, this does:
+           *   pre = round((APB_CLK_FREQ / n) / frequency)
+           */
+
+          pre = ((APB_CLK_FREQ / n) + (frequency / 2)) / frequency;
+
+          if (pre <= 0)
+            {
+              pre = 1;
+            }
+
+          if (pre > 16)
+            {
+              pre = 16;
+            }
+
+          errval = abs(APB_CLK_FREQ / (pre * n) - frequency);
+          if (bestn == -1 || errval <= besterr)
+            {
+              besterr = errval;
+              bestn = n;
+              bestpre = pre;
+            }
+        }
+
+      n = bestn;
+      pre = bestpre;
+      l = n;
+
+      /* Effectively, this does:
+       *   h = round((duty_cycle * n) / 256)
+       */
+
+      h = (duty_cycle * n + 127) / 256;
+      if (h <= 0)
+        {
+          h = 1;
+        }
+
+      regval = ((l - 1) << SPI_CLKCNT_L_S) |
+               ((h - 1) << SPI_CLKCNT_H_S) |
+               ((n - 1) << SPI_CLKCNT_N_S) |
+               ((pre - 1) << SPI_CLKDIV_PRE_S);
+
+      priv->actual = APB_CLK_FREQ / (n * pre);
+    }
+
+  priv->frequency = frequency;
+
+  putreg32(regval, SPI_CLOCK_REG(priv->config->id));
+
+  spiinfo("frequency=%" PRIu32 ", actual=%" PRIu32 "\n",
+          priv->frequency, priv->actual);
+
+  return priv->actual;
+}
+
+/****************************************************************************
+ * Name:  esp32s3_qspi_setmode
+ *
+ * Description:
+ *   Set the QSPI mode.
+ *
+ * Input Parameters:
+ *   dev  - Device-specific state data
+ *   mode - The requested QSPI mode
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void esp32s3_qspi_setmode(struct qspi_dev_s *dev,
+                                 enum qspi_mode_e mode)
+{
+  uint32_t regval;
+  struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+  uint8_t id = priv->config->id;
+
+  spiinfo("mode=%d\n", mode);
+
+  /* Has the mode changed? */
+
+  if (mode != priv->mode)
+    {
+      uint32_t ck_idle_edge;
+      uint32_t ck_out_edge;
+
+      switch (mode)
+        {
+          case QSPIDEV_MODE0: /* CPOL=0; CPHA=0 */
+            ck_idle_edge = 0;
+            ck_out_edge = 0;
+            break;
+
+          case QSPIDEV_MODE1: /* CPOL=0; CPHA=1 */
+            ck_idle_edge = 0;
+            ck_out_edge = 1;
+            break;
+
+          case QSPIDEV_MODE2: /* CPOL=1; CPHA=0 */
+            ck_idle_edge = 1;
+            ck_out_edge = 1;
+            break;
+
+          case QSPIDEV_MODE3: /* CPOL=1; CPHA=1 */
+            ck_idle_edge = 1;
+            ck_out_edge = 0;
+            break;
+
+          default:
+            spierr("Invalid mode: %d\n", mode);
+            DEBUGPANIC();
+            return;
+        }
+
+      regval  = getreg32(SPI_MISC_REG(id));
+      regval &= SPI_CK_IDLE_EDGE_M;
+      regval |= ck_idle_edge << SPI_CK_IDLE_EDGE_S;
+      putreg32(regval, SPI_MISC_REG(id));
+
+      regval  = getreg32(SPI_USER_REG(id));
+      regval &= SPI_CK_OUT_EDGE_M;
+      regval |= ck_out_edge << SPI_CK_OUT_EDGE_S;
+      putreg32(regval, SPI_USER_REG(id));
+
+      priv->mode = mode;
+    }
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_setbits
+ *
+ * Description:
+ *   Set the number of bits per word.
+ *
+ * Input Parameters:
+ *   dev   - Device-specific state data
+ *   nbits - The number of bits in an QSPI word.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void esp32s3_qspi_setbits(struct qspi_dev_s *dev, int nbits)
+{
+  struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+
+  spiinfo("nbits=%d\n", nbits);
+
+  priv->nbits = nbits;
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_command
+ *
+ * Description:
+ *   Perform one QSPI data transfer
+ *
+ * Input Parameters:
+ *   dev     - Device-specific state data
+ *   cmdinfo - Describes the command transfer to be performed.
+ *
+ * Returned Value:
+ *   Zero (OK) on SUCCESS, a negated errno on value of failure
+ *
+ ****************************************************************************/
+
+static int esp32s3_qspi_command(struct qspi_dev_s *dev,
+                                struct qspi_cmdinfo_s *cmdinfo)
+{
+  uint32_t regval;
+  uint8_t *data;
+  struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+  uint8_t id = priv->config->id;
+  uint32_t user1_reg = getreg32(SPI_USER1_REG(id));
+  uint32_t user_reg = getreg32(SPI_USER_REG(id));
+
+  if (QSPICMD_ISWRITE(cmdinfo->flags) || QSPICMD_ISREAD(cmdinfo->flags))
+    {
+      if (cmdinfo->buflen > QSPI_CMD_BUFSIZE)
+        {
+          return -EINVAL;
+        }
+      else
+        {
+          putreg32(cmdinfo->buflen * 8 - 1, SPI_MS_DLEN_REG(id));
+        }
+    }
+
+  /* Initiliaze QSPI user register */
+
+  user_reg &= ~(SPI_USR_ADDR_M |
+                SPI_USR_MOSI_M |
+                SPI_USR_MISO_M |
+                SPI_USR_DUMMY_M |
+                SPI_FWRITE_DUAL_M |
+                SPI_FWRITE_OCT_M |
+                SPI_FWRITE_QUAD_M);
+  user_reg |= SPI_USR_COMMAND_M;
+
+  /* Set command bits and value, and command is always needed */
+
+  regval  = getreg32(SPI_USER2_REG(id));
+  regval &= ~(SPI_USR_COMMAND_BITLEN_M |
+              SPI_USR_COMMAND_VALUE_M |
+              SPI_MST_REMPTY_ERR_END_EN_M);
+  regval |= ((QSPI_CMD_BITS(cmdinfo->cmd) - 1) << SPI_USR_COMMAND_BITLEN_S) |
+            (cmdinfo->cmd << SPI_USR_COMMAND_VALUE_S);
+  putreg32(regval, SPI_USER2_REG(id));
+
+  /* Set address bits and value */
+
+  if (QSPICMD_ISADDRESS(cmdinfo->flags))
+    {
+      user1_reg &= ~SPI_USR_ADDR_BITLEN_M;
+      user1_reg |= (cmdinfo->addrlen * 8 - 1) << SPI_USR_ADDR_BITLEN_S;
+
+      user_reg |= SPI_USR_ADDR_M;
+
+      putreg32(cmdinfo->addr, SPI_ADDR_REG(id));
+    }
+
+  /* Set dummy */
+
+  if (priv->dummies)
+    {
+      user1_reg &= ~SPI_USR_DUMMY_CYCLELEN_M;
+      user1_reg |= (priv->dummies - 1) << SPI_USR_DUMMY_CYCLELEN_S;
+
+      user_reg |= SPI_USR_DUMMY_M;
+    }
+
+  /* Set TX data */
+
+  if (QSPICMD_ISWRITE(cmdinfo->flags))
+    {
+      data = (uint8_t *)cmdinfo->buffer;
+
+      for (int i = 0; i < cmdinfo->buflen; i += 4)
+        {
+          memcpy(&regval, data + i, 4);
+          putreg32(regval, SPI_W0_REG(id) + i);
+        }
+
+      user_reg |= SPI_USR_MOSI_M;
+
+      if (priv->data_lines == 2)
+        {
+          user_reg |= SPI_FWRITE_DUAL_M;
+        }
+      else if (priv->data_lines == 4)
+        {
+          user_reg |= SPI_FWRITE_QUAD_M;
+        }
+    }
+  else if (QSPICMD_ISREAD(cmdinfo->flags))
+    {
+      user_reg |= SPI_USR_MISO_M;
+    }
+
+  putreg32(user_reg,  SPI_USER_REG(id));
+  putreg32(user1_reg, SPI_USER1_REG(id));
+
+  /* Set command and address I/O mode */
+
+  regval  = getreg32(SPI_CTRL_REG(id));
+  regval &= ~(SPI_FCMD_OCT_M | SPI_FADDR_OCT_M | SPI_FREAD_OCT_M |
+              SPI_FCMD_DUAL_M | SPI_FADDR_DUAL_M | SPI_FREAD_DUAL_M |
+              SPI_FCMD_QUAD_M | SPI_FADDR_QUAD_M | SPI_FREAD_QUAD_M);
+  if (QSPICMD_ISIDUAL(cmdinfo->flags))
+    {
+      regval |= SPI_FCMD_DUAL_M;
+    }
+  else if (QSPICMD_ISIQUAD(cmdinfo->flags))
+    {
+      regval |= SPI_FCMD_QUAD_M;
+    }
+
+  if (priv->addr_lines == 2)
+    {
+      regval |= SPI_FADDR_DUAL_M;
+    }
+  else if (priv->addr_lines == 4)
+    {
+      regval |= SPI_FADDR_QUAD_M;
+    }
+
+  if (QSPICMD_ISREAD(cmdinfo->flags))
+    {
+      if (priv->data_lines == 2)
+        {
+          regval |= SPI_FREAD_DUAL_M;
+        }
+      else if (priv->data_lines == 4)
+        {
+          regval |= SPI_FREAD_QUAD_M;
+        }
+    }
+
+  putreg32(regval, SPI_CTRL_REG(id));
+
+  /* Update QSPI master registers value */
+
+  regval = getreg32(SPI_CMD_REG(id));
+  regval |= SPI_UPDATE_M;
+  putreg32(regval, SPI_CMD_REG(id));
+
+  while ((getreg32(SPI_CMD_REG(id)) & SPI_UPDATE_M) != 0)
+    {
+      ;
+    }
+
+  /* Start transmision */
+
+  regval = getreg32(SPI_CMD_REG(id));
+  regval |= SPI_USR_M;
+  putreg32(regval, SPI_CMD_REG(id));
+
+  /* Wait until transmission is done */
+
+  while ((getreg32(SPI_CMD_REG(id)) & SPI_USR_M) != 0)
+    {
+      ;
+    }
+
+  if (QSPICMD_ISREAD(cmdinfo->flags))
+    {
+      data = (uint8_t *)cmdinfo->buffer;
+
+      for (int i = 0; i < cmdinfo->buflen; i += 4)
+        {
+          regval = getreg32(SPI_W0_REG(id) + i);
+          memcpy(data + i, &regval, MIN(4, cmdinfo->buflen - i));
+        }
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_memory
+ *
+ * Description:
+ *   Perform one QSPI memory transfer
+ *
+ * Input Parameters:
+ *   dev     - Device-specific state data
+ *   meminfo - Describes the memory transfer to be performed.
+ *
+ * Returned Value:
+ *   Zero (OK) on SUCCESS, a negated errno on value of failure
+ *
+ ****************************************************************************/
+
+static int esp32s3_qspi_memory(struct qspi_dev_s *dev,
+                               struct qspi_meminfo_s *meminfo)
+{
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  uint32_t regval;
+  struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+  uint8_t id = priv->config->id;
+  uint32_t user1_reg = getreg32(SPI_USER1_REG(id));
+  uint32_t user_reg = getreg32(SPI_USER_REG(id));
+
+  if (QSPIMEM_ISWRITE(meminfo->flags) || QSPIMEM_ISREAD(meminfo->flags))
+    {
+      if (meminfo->buflen > QSPI_DMA_BUFSIZE)
+        {
+          return -EINVAL;
+        }
+      else
+        {
+          putreg32(meminfo->buflen * 8 - 1, SPI_MS_DLEN_REG(id));
+        }
+    }
+
+  /* Reset SPI DMA FIFO */
+
+  regval  = getreg32(SPI_DMA_CONF_REG(id));
+  regval |= QSPI_DMA_RESET_MASK;
+  putreg32(regval, SPI_DMA_CONF_REG(id));
+
+  regval &= ~QSPI_DMA_RESET_MASK;
+  putreg32(regval, SPI_DMA_CONF_REG(id));
+
+  /* Initiliaze QSPI user register */
+
+  user_reg &= ~(SPI_USR_MOSI_M |
+                SPI_USR_MISO_M |
+                SPI_USR_DUMMY_M |
+                SPI_FWRITE_DUAL_M |
+                SPI_FWRITE_OCT_M |
+                SPI_FWRITE_QUAD_M);
+  user_reg |= SPI_USR_COMMAND_M | SPI_USR_ADDR_M;
+
+  /* Set command bits and value, and command is always needed */
+
+  regval  = getreg32(SPI_USER2_REG(id));
+  regval &= ~(SPI_USR_COMMAND_BITLEN_M |
+              SPI_USR_COMMAND_VALUE_M |
+              SPI_MST_REMPTY_ERR_END_EN_M);
+  regval |= ((QSPI_CMD_BITS(meminfo->cmd) - 1) << SPI_USR_COMMAND_BITLEN_S) |
+            (meminfo->cmd << SPI_USR_COMMAND_VALUE_S);
+  putreg32(regval, SPI_USER2_REG(id));
+
+  /* Set address bits and value */
+
+  user1_reg &= ~SPI_USR_ADDR_BITLEN_M;
+  user1_reg |= (meminfo->addrlen * 8 - 1) << SPI_USR_ADDR_BITLEN_S;
+
+  putreg32(meminfo->addr, SPI_ADDR_REG(id));
+
+  /* Set dummy */
+
+  if (meminfo->dummies)
+    {
+      user1_reg &= ~SPI_USR_DUMMY_CYCLELEN_M;
+      user1_reg |= (meminfo->dummies - 1) << SPI_USR_DUMMY_CYCLELEN_S;
+
+      user_reg |= SPI_USR_DUMMY_M;
+    }
+
+  /* Enable SPI DMA TX */
+
+  if (QSPIMEM_ISWRITE(meminfo->flags))
+    {
+      regval  = getreg32(SPI_DMA_CONF_REG(id));
+      regval |= SPI_DMA_TX_ENA_M;
+      putreg32(regval, SPI_DMA_CONF_REG(id));
+
+      user_reg |= SPI_USR_MOSI_M;
+
+      if (priv->data_lines == 2)
+        {
+          user_reg |= SPI_FWRITE_DUAL_M;
+        }
+      else if (priv->data_lines == 4)
+        {
+          user_reg |= SPI_FWRITE_QUAD_M;
+        }
+
+      esp32s3_dma_setup(priv->dma_channel,
+                        true,
+                        priv->dma_desc,
+                        QSPI_DMA_DESC_NUM,
+                        (uint8_t *)meminfo->buffer,
+                        meminfo->buflen);
+      esp32s3_dma_enable(priv->dma_channel, true);
+    }
+  else if (QSPIMEM_ISREAD(meminfo->flags))
+    {
+      regval  = getreg32(SPI_DMA_CONF_REG(id));
+      regval |= SPI_DMA_RX_ENA_M;
+      putreg32(regval, SPI_DMA_CONF_REG(id));
+
+      user_reg |= SPI_USR_MISO_M;
+
+      esp32s3_dma_setup(priv->dma_channel,
+                        false,
+                        priv->dma_desc,
+                        QSPI_DMA_DESC_NUM,
+                        (uint8_t *)meminfo->buffer,
+                        meminfo->buflen);
+      esp32s3_dma_enable(priv->dma_channel, false);
+    }
+
+  putreg32(user_reg,  SPI_USER_REG(id));
+  putreg32(user1_reg, SPI_USER1_REG(id));
+
+  /* Set command and address I/O mode */
+
+  regval  = getreg32(SPI_CTRL_REG(id));
+  regval &= ~(SPI_FCMD_OCT_M | SPI_FADDR_OCT_M | SPI_FREAD_OCT_M |
+              SPI_FCMD_DUAL_M | SPI_FADDR_DUAL_M | SPI_FREAD_DUAL_M |
+              SPI_FCMD_QUAD_M | SPI_FADDR_QUAD_M | SPI_FREAD_QUAD_M);
+  if (QSPIMEM_ISIDUAL(meminfo->flags))
+    {
+      regval |= SPI_FCMD_DUAL_M;
+    }
+  else if (QSPIMEM_ISIQUAD(meminfo->flags))
+    {
+      regval |= SPI_FCMD_QUAD_M;
+    }
+
+  if (priv->addr_lines == 2)
+    {
+      regval |= SPI_FADDR_DUAL_M;
+    }
+  else if (priv->addr_lines == 4)
+    {
+      regval |= SPI_FADDR_QUAD_M;
+    }
+
+  if (QSPIMEM_ISREAD(meminfo->flags))
+    {
+      if (priv->data_lines == 2)
+        {
+          regval |= SPI_FREAD_DUAL_M;
+        }
+      else if (priv->data_lines == 4)
+        {
+          regval |= SPI_FREAD_QUAD_M;
+        }
+    }
+
+  putreg32(regval, SPI_CTRL_REG(id));
+
+  /* Set interrupt */
+
+  putreg32(SPI_TRANS_DONE_INT_CLR_M, SPI_DMA_INT_CLR_REG(id));
+  putreg32(SPI_TRANS_DONE_INT_ENA_M, SPI_DMA_INT_ENA_REG(id));
+
+  /* Update QSPI master registers value */
+
+  regval = getreg32(SPI_CMD_REG(id));
+  regval |= SPI_UPDATE_M;
+  putreg32(regval, SPI_CMD_REG(id));
+
+  while ((getreg32(SPI_CMD_REG(id)) & SPI_UPDATE_M) != 0)
+    {
+      ;
+    }
+
+  /* Start transmision */
+
+  regval = getreg32(SPI_CMD_REG(id));
+  regval |= SPI_USR_M;
+  putreg32(regval, SPI_CMD_REG(id));
+
+  /* Wait for transmision done */
+
+  esp32s3_qspi_wait_sem(priv);
+
+  /* Reset interrupt */
+
+  putreg32(0, SPI_DMA_INT_ENA_REG(id));
+
+  return 0;
+#else
+  return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_alloc
+ *
+ * Description:
+ *   Allocate a buffer suitable for DMA data transfer
+ *
+ * Input Parameters:
+ *   dev    - Device-specific state data
+ *   buflen - Buffer length to allocate in bytes
+ *
+ * Returned Value:
+ *   Address of the allocated memory on success; NULL is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+static void *esp32s3_qspi_alloc(struct qspi_dev_s *dev, size_t buflen)
+{
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  return kmm_malloc(ALIGN_UP(buflen, 4));
+#else
+  return NULL;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_free
+ *
+ * Description:
+ *   Free memory returned by QSPI_ALLOC
+ *
+ * Input Parameters:
+ *   dev    - Device-specific state data
+ *   buffer - Buffer previously allocated via QSPI_ALLOC
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void esp32s3_qspi_free(struct qspi_dev_s *dev, void *buffer)
+{
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  if (buffer)
+    {
+      kmm_free(buffer);
+    }
+#endif
+}
+
+/****************************************************************************
+ * Name:  esp32s3_qspi_wait_sem
+ *
+ * Description:
+ *   Wait for a transfer to complete.
+ *
+ * Input Parameters:
+ *   priv - QSPI private state data
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+static int esp32s3_qspi_wait_sem(struct esp32s3_qspi_priv_s *priv)
+{
+  return nxsem_tickwait_uninterruptible(&priv->sem_isr, SEC2TICK(10));
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s3_qspi_init_dma
+ *
+ * Description:
+ *   Initialize ESP32-S3 QSPI connection to GDMA engine.
+ *
+ * Input Parameters:
+ *   priv - QSPI private state data
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+void esp32s3_qspi_init_dma(struct esp32s3_qspi_priv_s *priv)
+{
+  const struct esp32s3_qspi_config_s *config = priv->config;
+
+  /* Enable GDMA clock for the QSPI peripheral */
+
+  modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, 0, config->dma_clk_bit);
+
+  /* Reset GDMA for the QSPI peripheral */
+
+  modifyreg32(SYSTEM_PERIP_RST_EN0_REG, config->dma_rst_bit, 0);
+
+  /* Initialize GDMA controller */
+
+  esp32s3_dma_init();
+
+  /* Request a GDMA channel for QSPI peripheral */
+
+  priv->dma_channel = esp32s3_dma_request(config->dma_periph, 1, 1, true);
+  if (priv->dma_channel < 0)
+    {
+      spierr("Failed to allocate GDMA channel\n");
+
+      DEBUGPANIC();
+    }
+
+  /* Disable segment transaction mode for QSPI Master */
+
+  putreg32((SPI_SLV_RX_SEG_TRANS_CLR_EN_M | SPI_SLV_TX_SEG_TRANS_CLR_EN_M),
+           SPI_DMA_CONF_REG(config->id));
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s3_qspi_init_iomux
+ *
+ * Description:
+ *   Initialize ESP32-S3 QSPI GPIO by IO MUX.
+ *
+ * Input Parameters:
+ *   priv - QSPI private state data
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#if QSPI_VIA_IOMUX != 0
+static void esp32s3_qspi_init_iomux(struct esp32s3_qspi_priv_s *priv)
+{
+  uint32_t attr = OUTPUT_FUNCTION_5;
+  const struct esp32s3_qspi_config_s *config = priv->config;
+
+  esp32s3_configgpio(config->cs_pin,  attr);
+  esp32s3_configgpio(config->clk_pin, attr);
+
+  attr |= INPUT;
+
+  esp32s3_configgpio(config->mosi_pin, attr);
+  esp32s3_configgpio(config->miso_pin, attr);
+  esp32s3_configgpio(config->io2_pin,  attr);
+  esp32s3_configgpio(config->io3_pin,  attr);
+
+  esp32s3_gpio_matrix_out(config->cs_pin,   SIG_GPIO_OUT_IDX, 0, 0);
+  esp32s3_gpio_matrix_out(config->clk_pin,  SIG_GPIO_OUT_IDX, 0, 0);
+  esp32s3_gpio_matrix_out(config->mosi_pin, SIG_GPIO_OUT_IDX, 0, 0);
+  esp32s3_gpio_matrix_out(config->miso_pin, SIG_GPIO_OUT_IDX, 0, 0);
+  esp32s3_gpio_matrix_out(config->io2_pin,  SIG_GPIO_OUT_IDX, 0, 0);
+  esp32s3_gpio_matrix_out(config->io3_pin,  SIG_GPIO_OUT_IDX, 0, 0);
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s3_qspi_init_iomatrix
+ *
+ * Description:
+ *   Initialize ESP32-S3 QSPI GPIO by IO matrix.
+ *
+ * Input Parameters:
+ *   priv - QSPI private state data
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#if QSPI_VIA_IOMUX == 0 || defined(CONFIG_ESP32S3_SPI3)
+static void esp32s3_qspi_init_iomatrix(struct esp32s3_qspi_priv_s *priv)
+{
+  uint32_t attr = OUTPUT;
+  const struct esp32s3_qspi_config_s *config = priv->config;
+
+  esp32s3_configgpio(config->cs_pin, OUTPUT);
+  esp32s3_gpio_matrix_out(config->cs_pin, config->cs_outsig, 0, 0);
+
+  esp32s3_configgpio(config->clk_pin, OUTPUT);
+  esp32s3_gpio_matrix_out(config->clk_pin, config->clk_outsig, 0, 0);
+
+  attr |= INPUT;
+
+  esp32s3_configgpio(config->mosi_pin, attr);
+  esp32s3_gpio_matrix_in(config->mosi_pin, config->mosi_insig, 0);
+  esp32s3_gpio_matrix_out(config->mosi_pin, config->mosi_outsig, 0, 0);
+
+  esp32s3_configgpio(config->miso_pin, attr);
+  esp32s3_gpio_matrix_in(config->miso_pin, config->miso_insig, 0);
+  esp32s3_gpio_matrix_out(config->miso_pin, config->miso_outsig, 0, 0);
+
+  esp32s3_configgpio(config->io2_pin, attr);
+  esp32s3_gpio_matrix_in(config->io2_pin, config->io2_insig, 0);
+  esp32s3_gpio_matrix_out(config->io2_pin, config->io2_outsig, 0, 0);
+
+  esp32s3_configgpio(config->io3_pin, attr);
+  esp32s3_gpio_matrix_in(config->io3_pin, config->io3_insig, 0);
+  esp32s3_gpio_matrix_out(config->io3_pin, config->io3_outsig, 0, 0);
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s3_qspi_init_gpio
+ *
+ * Description:
+ *   Initialize ESP32-S3 QSPI GPIO
+ *
+ * Input Parameters:
+ *   priv - QSPI private state data
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void esp32s3_qspi_init_gpio(struct esp32s3_qspi_priv_s *priv)
+{
+  /* SPI3 doesn't have IOMUX  */
+
+#if QSPI_VIA_IOMUX != 0
+  if (priv->config->id == 2)
+    {
+      esp32s3_qspi_init_iomux(priv);
+    }
+#ifdef CONFIG_ESP32S3_SPI3
+  else
+    {
+      esp32s3_qspi_init_iomatrix(priv);
+    }
+#endif
+#else
+  esp32s3_qspi_init_iomatrix(priv);
+#endif
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_init
+ *
+ * Description:
+ *   Initialize ESP32-S3 QSPI hardware interface.
+ *
+ * Input Parameters:
+ *   priv - QSPI private state data
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void esp32s3_qspi_init(struct esp32s3_qspi_priv_s *priv)
+{
+  const struct esp32s3_qspi_config_s *config = priv->config;
+  uint8_t id = config->id;
+
+  esp32s3_qspi_init_gpio(priv);
+
+  modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, 0, config->clk_bit);
+  modifyreg32(SYSTEM_PERIP_RST_EN0_REG, config->rst_bit, 0);
+
+  putreg32(SPI_USR_MOSI_M | SPI_CS_HOLD_M, SPI_USER_REG(id));
+
+  putreg32(0, SPI_USER1_REG(id));
+  putreg32(0, SPI_SLAVE_REG(id));
+  putreg32(SPI_CS1_DIS_M | SPI_CS2_DIS_M, SPI_MISC_REG(id));
+
+  putreg32(SPI_CLK_EN_M | SPI_MST_CLK_ACTIVE_M | SPI_MST_CLK_SEL_M,
+           SPI_CLK_GATE_REG(id));
+
+  putreg32(0, SPI_CTRL_REG(id));
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  esp32s3_qspi_init_dma(priv);
+#endif
+
+  esp32s3_qspi_setfrequency(&priv->spi_dev, QSPI_DEFAULT_FREQ);
+  esp32s3_qspi_setbits(&priv->spi_dev, QSPI_DEFAULT_WIDTH);
+  esp32s3_qspi_setmode(&priv->spi_dev, QSPI_DEFAULT_MODE);
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_deinit
+ *
+ * Description:
+ *   Deinitialize ESP32-S3 QSPI hardware interface.
+ *
+ * Input Parameters:
+ *   priv - QSPI private state data
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void esp32s3_qspi_deinit(struct esp32s3_qspi_priv_s *priv)
+{
+  const struct esp32s3_qspi_config_s *config = priv->config;
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  modifyreg32(SYSTEM_PERIP_RST_EN0_REG, 0, config->dma_rst_bit);
+  modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, config->dma_clk_bit, 0);
+#endif
+
+  modifyreg32(SYSTEM_PERIP_RST_EN0_REG, 0, config->rst_bit);
+  modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, config->clk_bit, 0);
+
+  priv->frequency  = 0;
+  priv->actual     = 0;
+  priv->mode       = QSPIDEV_MODE0;
+  priv->nbits      = 0;
+  priv->dummies    = 0;
+  priv->addr_lines = 4;
+  priv->data_lines = 4;
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_interrupt
+ *
+ * Description:
+ *   Common QSPI DMA interrupt handler.
+ *
+ * Input Parameters:
+ *   irq     - Number of the IRQ that generated the interrupt
+ *   context - Interrupt register state save info
+ *   arg     - QSPI controller private data
+ *
+ * Returned Value:
+ *   Standard interrupt return value.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+static int esp32s3_qspi_interrupt(int irq, void *context, void *arg)
+{
+  struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)arg;
+
+  /* Write 1 to clear interrupt bit */
+
+  putreg32(SPI_TRANS_DONE_INT_CLR_M, SPI_DMA_INT_CLR_REG(priv->config->id));
+
+  nxsem_post(&priv->sem_isr);
+
+  return 0;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s3_qspibus_set_attr
+ *
+ * Description:
+ *   Set attribution of QSPI bus transfer.
+ *
+ * Input Parameters:
+ *   dev        - Device-specific state data
+ *   dummies    - Number of dummy cycles, this only works in command
+ *                transfer, not works in memory transfer
+ *   addr_lines - Number of address transmiting I/O pins
+ *   data_lines - Number of data transmiting I/O pins
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success.  Otherwise -1 (ERROR).
+ *
+ ****************************************************************************/
+
+int esp32s3_qspibus_set_attr(struct qspi_dev_s *dev,
+                             uint8_t dummies,
+                             uint8_t addr_lines,
+                             uint8_t data_lines)
+{
+  struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+
+  DEBUGASSERT(dev);
+
+  if (priv->refs == 0)
+    {
+      return ERROR;
+    }
+
+  if ((addr_lines != 1) &&
+      (addr_lines != 2) &&
+      (addr_lines != 4))
+    {
+      return ERROR;
+    }
+
+  if ((data_lines != 1) &&
+      (data_lines != 2) &&
+      (data_lines != 4))
+    {
+      return ERROR;
+    }
+
+  priv->dummies = dummies;
+  priv->addr_lines = addr_lines;
+  priv->data_lines = data_lines;
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspibus_initialize
+ *
+ * Description:
+ *   Initialize the selected QSPI bus.
+ *
+ * Input Parameters:
+ *   port - Port number (for hardware that has multiple QSPI interfaces)
+ *
+ * Returned Value:
+ *   Valid QSPI device structure reference on success; NULL on failure.
+ *
+ ****************************************************************************/
+
+struct qspi_dev_s *esp32s3_qspibus_initialize(int port)
+{
+  struct qspi_dev_s *spi_dev;
+  struct esp32s3_qspi_priv_s *priv;
+
+  switch (port)
+    {
+#ifdef CONFIG_ESP32S3_SPI2
+      case ESP32S3_SPI2:
+        priv = &esp32s3_spi2_priv;
+        break;
+#endif
+#ifdef CONFIG_ESP32S3_SPI3
+      case ESP32S3_SPI3:
+        priv = &esp32s3_spi3_priv;
+        break;
+#endif
+      default:
+        return NULL;
+    }
+
+  spi_dev = (struct qspi_dev_s *)priv;
+
+  nxmutex_lock(&priv->lock);
+  if (priv->refs != 0)
+    {
+      priv->refs++;
+      nxmutex_unlock(&priv->lock);
+      return spi_dev;
+    }
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+
+  /* Set up to receive peripheral interrupts on the current CPU */
+
+  priv->cpu = up_cpu_index();
+  priv->cpuint = esp32s3_setup_irq(priv->cpu, priv->config->periph,
+                                   ESP32S3_INT_PRIO_DEF,
+                                   ESP32S3_CPUINT_LEVEL);
+  if (priv->cpuint < 0)
+    {
+      /* Failed to allocate a CPU interrupt of this type. */
+
+      nxmutex_unlock(&priv->lock);
+      return NULL;
+    }
+
+  /* Attach and enable the IRQ */
+
+  if (irq_attach(priv->config->irq, esp32s3_qspi_interrupt, priv) != OK)
+    {
+      /* Failed to attach IRQ, so CPU interrupt must be freed. */
+
+      esp32s3_teardown_irq(priv->cpu, priv->config->periph, priv->cpuint);
+      priv->cpuint = -ENOMEM;
+      nxmutex_unlock(&priv->lock);
+
+      return NULL;
+    }
+
+  /* Enable the CPU interrupt that is linked to the QSPI device. */
+
+  up_enable_irq(priv->config->irq);
+#endif
+
+  esp32s3_qspi_init(priv);
+  priv->refs++;
+  nxmutex_unlock(&priv->lock);
+  return spi_dev;
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspibus_uninitialize
+ *
+ * Description:
+ *   Uninitialize an QSPI bus.
+ *
+ * Input Parameters:
+ *   dev - Device-specific state data
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success. Otherwise -1 (ERROR).
+ *
+ ****************************************************************************/
+
+int esp32s3_qspibus_uninitialize(struct qspi_dev_s *dev)
+{
+  struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+
+  DEBUGASSERT(dev);
+
+  if (priv->refs == 0)
+    {
+      return ERROR;
+    }
+
+  nxmutex_lock(&priv->lock);
+  if (--priv->refs != 0)
+    {
+      nxmutex_unlock(&priv->lock);
+      return OK;
+    }
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  up_disable_irq(priv->config->irq);
+  esp32s3_teardown_irq(priv->cpu, priv->config->periph, priv->cpuint);
+  irq_detach(priv->config->irq);
+
+  priv->cpuint = -ENOMEM;
+#endif
+
+  esp32s3_qspi_deinit(priv);
+  nxmutex_unlock(&priv->lock);
+
+  return OK;
+}
+
+#endif /* CONFIG_ESP32S3_SPI */
diff --git a/arch/xtensa/src/esp32s3/esp32s3_qspi.h b/arch/xtensa/src/esp32s3/esp32s3_qspi.h
new file mode 100644
index 0000000000..fd60fa66f0
--- /dev/null
+++ b/arch/xtensa/src/esp32s3/esp32s3_qspi.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s3/esp32s3_qspi.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#ifndef __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_QSPI_H
+#define __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_QSPI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/spi/qspi.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_SPI
+
+#ifdef CONFIG_ESP32S3_SPI2
+#  define ESP32S3_SPI2 2
+#endif
+
+#ifdef CONFIG_ESP32S3_SPI3
+#  define ESP32S3_SPI3 3
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Name: esp32s3_qspibus_set_attr
+ *
+ * Description:
+ *   Set attribution of QSPI bus transfer.
+ *
+ * Input Parameters:
+ *   dev        - Device-specific state data
+ *   dummies    - Number of dummy cycles, this only works in command
+ *                transfer, not works in memory transfer
+ *   addr_lines - Number of address transmiting I/O pins
+ *   data_lines - Number of data transmiting I/O pins
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success.  Otherwise -1 (ERROR).
+ *
+ ****************************************************************************/
+
+int esp32s3_qspibus_set_attr(struct qspi_dev_s *dev,
+                             uint8_t dummies,
+                             uint8_t addr_lines,
+                             uint8_t data_lines);
+
+/****************************************************************************
+ * Name: esp32s3_qspibus_initialize
+ *
+ * Description:
+ *   Initialize the selected QSPI bus.
+ *
+ * Input Parameters:
+ *   port - Port number (for hardware that has multiple QSPI interfaces)
+ *
+ * Returned Value:
+ *   Valid QSPI device structure reference on success; NULL on failure
+ *
+ ****************************************************************************/
+
+struct qspi_dev_s *esp32s3_qspibus_initialize(int port);
+
+/****************************************************************************
+ * Name: esp32s3_qspibus_uninitialize
+ *
+ * Description:
+ *   Uninitialize an QSPI bus.
+ *
+ * Input Parameters:
+ *   dev - Device-specific state data
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success.  Otherwise -1 (ERROR).
+ *
+ ****************************************************************************/
+
+int esp32s3_qspibus_uninitialize(struct qspi_dev_s *dev);
+
+#ifdef __cplusplus
+}
+#endif
+#undef EXTERN
+
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_ESP32S3_SPI */
+#endif /* __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_QSPI_H */
diff --git a/arch/xtensa/src/esp32s3/esp32s3_spi.c b/arch/xtensa/src/esp32s3/esp32s3_spi.c
index 9cb529f684..b7f048599d 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_spi.c
+++ b/arch/xtensa/src/esp32s3/esp32s3_spi.c
@@ -48,7 +48,7 @@
 #include "esp32s3_irq.h"
 #include "esp32s3_gpio.h"
 
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 #include "esp32s3_dma.h"
 #endif
 
@@ -71,11 +71,15 @@
 #  define SPI_HAVE_SWCS 0
 #endif
 
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 
-/* SPI DMA RX/TX number of descriptors */
+/* QSPI DMA RX/TX number of descriptors */
 
-#define SPI_DMA_DESC_NUM    (CONFIG_ESP32S3_SPI2_DMADESC_NUM)
+#  if (CONFIG_ESP32S3_SPI_DMA_BUFSIZE % ESP32S3_DMA_BUFLEN_MAX) > 0
+#    define SPI_DMA_DESC_NUM (CONFIG_ESP32S3_SPI_DMA_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX + 1)
+#  else
+#    define SPI_DMA_DESC_NUM (CONFIG_ESP32S3_SPI_DMA_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX)
+#  endif
 
 /* SPI DMA reset before exchange */
 
@@ -123,13 +127,13 @@ struct esp32s3_spi_config_s
   uint8_t mosi_pin;           /* GPIO configuration for MOSI */
   uint8_t miso_pin;           /* GPIO configuration for MISO */
   uint8_t clk_pin;            /* GPIO configuration for CLK */
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
   uint8_t periph;             /* Peripheral ID */
   uint8_t irq;                /* Interrupt ID */
 #endif
   uint32_t clk_bit;           /* Clock enable bit */
   uint32_t rst_bit;           /* SPI reset bit */
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
   uint32_t dma_clk_bit;       /* DMA clock enable bit */
   uint32_t dma_rst_bit;       /* DMA reset bit */
 #endif
@@ -154,11 +158,16 @@ struct esp32s3_spi_priv_s
   const struct esp32s3_spi_config_s *config;
   int refs;             /* Reference count */
   mutex_t lock;         /* Held while chip is selected for mutual exclusion */
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
   sem_t sem_isr;        /* Interrupt wait semaphore */
   int cpu;              /* CPU ID */
   int cpuint;           /* SPI interrupt ID */
   int32_t dma_channel;  /* Channel assigned by the GDMA driver */
+
+  /* DMA RX/TX description */
+
+  struct esp32s3_dmadesc_s *dma_rxdesc;
+  struct esp32s3_dmadesc_s *dma_txdesc;
 #endif
   uint32_t frequency;   /* Requested clock frequency */
   uint32_t actual;      /* Actual clock frequency */
@@ -188,7 +197,7 @@ static uint32_t esp32s3_spi_send(struct spi_dev_s *dev, uint32_t wd);
 static void esp32s3_spi_exchange(struct spi_dev_s *dev,
                                  const void *txbuffer,
                                  void *rxbuffer, size_t nwords);
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 static int esp32s3_spi_interrupt(int irq, void *context, void *arg);
 static int esp32s3_spi_sem_waitdone(struct esp32s3_spi_priv_s *priv);
 static void esp32s3_spi_dma_exchange(struct esp32s3_spi_priv_s *priv,
@@ -212,7 +221,7 @@ static void esp32s3_spi_recvblock(struct spi_dev_s *dev,
 #ifdef CONFIG_SPI_TRIGGER
 static int esp32s3_spi_trigger(struct spi_dev_s *dev);
 #endif
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 static void esp32s3_spi_dma_init(struct spi_dev_s *dev);
 #endif
 static void esp32s3_spi_init(struct spi_dev_s *dev);
@@ -233,13 +242,13 @@ static const struct esp32s3_spi_config_s esp32s3_spi2_config =
   .mosi_pin     = CONFIG_ESP32S3_SPI2_MOSIPIN,
   .miso_pin     = CONFIG_ESP32S3_SPI2_MISOPIN,
   .clk_pin      = CONFIG_ESP32S3_SPI2_CLKPIN,
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
   .periph       = ESP32S3_PERIPH_SPI2,
   .irq          = ESP32S3_IRQ_SPI2,
 #endif
   .clk_bit      = SYSTEM_SPI2_CLK_EN,
   .rst_bit      = SYSTEM_SPI2_RST,
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
   .dma_clk_bit  = SYSTEM_SPI2_DMA_CLK_EN,
   .dma_rst_bit  = SYSTEM_SPI2_DMA_RST,
 #endif
@@ -284,6 +293,15 @@ static const struct spi_ops_s esp32s3_spi2_ops =
   .registercallback  = NULL,
 };
 
+#ifdef CONFIG_ESP32S3_SPI_DMA
+
+/* SPI DMA RX/TX description */
+
+static struct esp32s3_dmadesc_s esp32s3_spi2_dma_txdesc[SPI_DMA_DESC_NUM];
+static struct esp32s3_dmadesc_s esp32s3_spi2_dma_rxdesc[SPI_DMA_DESC_NUM];
+
+#endif
+
 static struct esp32s3_spi_priv_s esp32s3_spi2_priv =
 {
   .spi_dev     =
@@ -293,10 +311,12 @@ static struct esp32s3_spi_priv_s esp32s3_spi2_priv =
   .config      = &esp32s3_spi2_config,
   .refs        = 0,
   .lock        = NXMUTEX_INITIALIZER,
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
   .sem_isr     = SEM_INITIALIZER(0),
   .cpuint      = -ENOMEM,
   .dma_channel = -1,
+  .dma_rxdesc  = esp32s3_spi2_dma_rxdesc,
+  .dma_txdesc  = esp32s3_spi2_dma_txdesc,
 #endif
   .frequency   = 0,
   .actual      = 0,
@@ -316,8 +336,16 @@ static const struct esp32s3_spi_config_s esp32s3_spi3_config =
   .mosi_pin     = CONFIG_ESP32S3_SPI3_MOSIPIN,
   .miso_pin     = CONFIG_ESP32S3_SPI3_MISOPIN,
   .clk_pin      = CONFIG_ESP32S3_SPI3_CLKPIN,
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  .periph       = ESP32S3_PERIPH_SPI3,
+  .irq          = ESP32S3_IRQ_SPI3,
+#endif
   .clk_bit      = SYSTEM_SPI3_CLK_EN,
   .rst_bit      = SYSTEM_SPI3_RST,
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  .dma_clk_bit  = SYSTEM_SPI3_DMA_CLK_EN,
+  .dma_rst_bit  = SYSTEM_SPI3_DMA_RST,
+#endif
   .cs_insig     = FSPICS0_IN_IDX,
   .cs_outsig    = FSPICS0_OUT_IDX,
   .mosi_insig   = FSPID_IN_IDX,
@@ -359,6 +387,15 @@ static const struct spi_ops_s esp32s3_spi3_ops =
   .registercallback  = NULL,
 };
 
+#ifdef CONFIG_ESP32S3_SPI_DMA
+
+/* SPI DMA RX/TX description */
+
+static struct esp32s3_dmadesc_s esp32s3_spi3_dma_txdesc[SPI_DMA_DESC_NUM];
+static struct esp32s3_dmadesc_s esp32s3_spi3_dma_rxdesc[SPI_DMA_DESC_NUM];
+
+#endif
+
 static struct esp32s3_spi_priv_s esp32s3_spi3_priv =
 {
   .spi_dev     =
@@ -368,6 +405,13 @@ static struct esp32s3_spi_priv_s esp32s3_spi3_priv =
   .config      = &esp32s3_spi3_config,
   .refs        = 0,
   .lock        = NXMUTEX_INITIALIZER,
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  .sem_isr     = SEM_INITIALIZER(0),
+  .cpuint      = -ENOMEM,
+  .dma_channel = -1,
+  .dma_rxdesc  = esp32s3_spi3_dma_rxdesc,
+  .dma_txdesc  = esp32s3_spi3_dma_txdesc,
+#endif
   .frequency   = 0,
   .actual      = 0,
   .mode        = 0,
@@ -375,15 +419,6 @@ static struct esp32s3_spi_priv_s esp32s3_spi3_priv =
 };
 #endif /* CONFIG_ESP32S3_SPI3 */
 
-#ifdef CONFIG_ESP32S3_SPI2_DMA
-
-/* SPI DMA RX/TX description */
-
-static struct esp32s3_dmadesc_s dma_rxdesc[SPI_DMA_DESC_NUM];
-static struct esp32s3_dmadesc_s dma_txdesc[SPI_DMA_DESC_NUM];
-
-#endif
-
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -515,7 +550,7 @@ static int esp32s3_spi_lock(struct spi_dev_s *dev, bool lock)
  *
  ****************************************************************************/
 
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 static int esp32s3_spi_sem_waitdone(struct esp32s3_spi_priv_s *priv)
 {
   return nxsem_tickwait_uninterruptible(&priv->sem_isr, SEC2TICK(10));
@@ -824,7 +859,7 @@ static int esp32s3_spi_hwfeatures(struct spi_dev_s *dev,
  *
  ****************************************************************************/
 
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 static void esp32s3_spi_dma_exchange(struct esp32s3_spi_priv_s *priv,
                                      const void *txbuffer,
                                      void *rxbuffer,
@@ -869,8 +904,8 @@ static void esp32s3_spi_dma_exchange(struct esp32s3_spi_priv_s *priv,
       esp32s3_spi_set_regbits(SPI_DMA_CONF_REG(priv->config->id),
                               SPI_DMA_TX_ENA_M);
 
-      n = esp32s3_dma_setup(channel, true, dma_txdesc, SPI_DMA_DESC_NUM,
-                            tp, bytes);
+      n = esp32s3_dma_setup(channel, true, priv->dma_txdesc,
+                            SPI_DMA_DESC_NUM, tp, bytes);
       esp32s3_dma_enable(channel, true);
 
       putreg32((n * 8 - 1), SPI_MS_DLEN_REG(priv->config->id));
@@ -886,8 +921,8 @@ static void esp32s3_spi_dma_exchange(struct esp32s3_spi_priv_s *priv,
           esp32s3_spi_set_regbits(SPI_DMA_CONF_REG(priv->config->id),
                                   SPI_DMA_RX_ENA_M);
 
-          esp32s3_dma_setup(channel, false, dma_rxdesc, SPI_DMA_DESC_NUM,
-                            rp, bytes);
+          esp32s3_dma_setup(channel, false, priv->dma_rxdesc,
+                            SPI_DMA_DESC_NUM, rp, bytes);
           esp32s3_dma_enable(channel, false);
 
           esp32s3_spi_set_regbits(SPI_USER_REG(priv->config->id),
@@ -1158,8 +1193,8 @@ static void esp32s3_spi_exchange(struct spi_dev_s *dev,
 {
   struct esp32s3_spi_priv_s *priv = (struct esp32s3_spi_priv_s *)dev;
 
-#ifdef CONFIG_ESP32S3_SPI2_DMA
-  size_t thld = CONFIG_ESP32S3_SPI2_DMATHRESHOLD;
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  size_t thld = CONFIG_ESP32S3_SPI_DMATHRESHOLD;
 
   if (nwords > thld)
     {
@@ -1270,7 +1305,7 @@ static int esp32s3_spi_trigger(struct spi_dev_s *dev)
  *
  ****************************************************************************/
 
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 void esp32s3_spi_dma_init(struct spi_dev_s *dev)
 {
   struct esp32s3_spi_priv_s *priv = (struct esp32s3_spi_priv_s *)dev;
@@ -1389,7 +1424,7 @@ static void esp32s3_spi_init(struct spi_dev_s *dev)
   putreg32(VALUE_MASK(0, SPI_CS_HOLD_TIME),
            SPI_USER1_REG(priv->config->id));
 
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
   esp32s3_spi_dma_init(dev);
 #endif
 
@@ -1416,7 +1451,7 @@ static void esp32s3_spi_deinit(struct spi_dev_s *dev)
 {
   struct esp32s3_spi_priv_s *priv = (struct esp32s3_spi_priv_s *)dev;
 
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
   modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, priv->config->dma_clk_bit, 0);
 #endif
 
@@ -1445,7 +1480,7 @@ static void esp32s3_spi_deinit(struct spi_dev_s *dev)
  *
  ****************************************************************************/
 
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 static int esp32s3_spi_interrupt(int irq, void *context, void *arg)
 {
   struct esp32s3_spi_priv_s *priv = (struct esp32s3_spi_priv_s *)arg;
@@ -1505,7 +1540,7 @@ struct spi_dev_s *esp32s3_spibus_initialize(int port)
       return spi_dev;
     }
 
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
   /* If a CPU Interrupt was previously allocated, then deallocate it */
 
   if (priv->cpuint != -ENOMEM)
@@ -1591,7 +1626,7 @@ int esp32s3_spibus_uninitialize(struct spi_dev_s *dev)
       return OK;
     }
 
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
   up_disable_irq(priv->config->irq);
   esp32s3_teardown_irq(priv->cpu, priv->config->periph, priv->cpuint);
   irq_detach(priv->config->irq);
diff --git a/arch/xtensa/src/esp32s3/esp32s3_spi_slave.c b/arch/xtensa/src/esp32s3/esp32s3_spi_slave.c
index 9b8edf2678..27ba2257f4 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_spi_slave.c
+++ b/arch/xtensa/src/esp32s3/esp32s3_spi_slave.c
@@ -48,7 +48,7 @@
 #include "esp32s3_irq.h"
 #include "esp32s3_gpio.h"
 
-#if defined(CONFIG_ESP32S3_SPI2_DMA) || defined(CONFIG_ESP32S3_SPI3_DMA)
+#ifdef CONFIG_ESP32S3_SPI_DMA
 #include "esp32s3_dma.h"
 #endif
 
@@ -65,20 +65,27 @@
 
 #define SPI_SLAVE_BUFSIZE (CONFIG_ESP32S3_SPI_SLAVE_BUFSIZE)
 
-#if defined(CONFIG_ESP32S3_SPI2_DMA) || defined(CONFIG_ESP32S3_SPI3_DMA)
-#  define ESP32S3_SPI_DMA
-#endif
-
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 /* SPI DMA RX/TX number of descriptors */
 
-#if (SPI_SLAVE_BUFSIZE % ESP32S3_DMA_BUFLEN_MAX) > 0
-#  define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX + 1)
+#  if (SPI_SLAVE_BUFSIZE % ESP32S3_DMA_BUFLEN_MAX) > 0
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX + 1)
+#  else
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX)
+#  endif
+
+#  define SPI_SLV_INT_EN      (SPI_SLV_WR_DMA_DONE_INT_ENA_M | SPI_SLV_RD_DMA_DONE_INT_ENA_M)
+#  define SPI_SLV_INT_RX      SPI_SLV_WR_DMA_DONE_INT_ST_M
+#  define SPI_SLV_INT_CLR_RX  SPI_SLV_WR_DMA_DONE_INT_CLR_M
+#  define SPI_SLV_INT_TX      SPI_SLV_RD_DMA_DONE_INT_ST_M
+#  define SPI_SLV_INT_CLR_TX  SPI_SLV_RD_DMA_DONE_INT_CLR_M
 #else
-#  define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX)
-#endif
-
-#endif /* ESP32S3_SPI_DMA */
+#  define SPI_SLV_INT_EN      (SPI_SLV_WR_BUF_DONE_INT_ENA_M | SPI_SLV_RD_BUF_DONE_INT_ENA_M)
+#  define SPI_SLV_INT_RX      SPI_SLV_WR_BUF_DONE_INT_ST_M
+#  define SPI_SLV_INT_CLR_RX  SPI_SLV_WR_BUF_DONE_INT_CLR_M
+#  define SPI_SLV_INT_TX      SPI_SLV_RD_BUF_DONE_INT_ST_M
+#  define SPI_SLV_INT_CLR_TX  SPI_SLV_RD_BUF_DONE_INT_CLR_M
+#endif /* CONFIG_ESP32S3_SPI_DMA */
 
 /* Verify whether SPI has been assigned IOMUX pins.
  * Otherwise, SPI signals will be routed via GPIO Matrix.
@@ -90,10 +97,29 @@
 #  define SPI_IS_MOSI_IOMUX (CONFIG_ESP32S3_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN)
 #  define SPI_IS_MISO_IOMUX (CONFIG_ESP32S3_SPI2_MISOPIN == SPI2_IOMUX_MISOPIN)
 
-#  define SPI_VIA_IOMUX     ((SPI_IS_CS_IOMUX) && \
-                             (SPI_IS_CLK_IOMUX) && \
-                             (SPI_IS_MOSI_IOMUX) && \
-                             (SPI_IS_MISO_IOMUX))
+/* In quad SPI mode, flash's IO map is:
+ *    MOSI -> IO0
+ *    MISO -> IO1
+ *    WP   -> IO2
+ *    Hold -> IO3
+ */
+
+#  ifdef CONFIG_ESP32S3_SPI_IO_QIO
+#    define SPI_IS_IO2_IOMUX  (CONFIG_ESP32S3_SPI2_IO2PIN == SPI2_IOMUX_WPPIN)
+#    define SPI_IS_IO3_IOMUX  (CONFIG_ESP32S3_SPI2_IO3PIN == SPI2_IOMUX_HDPIN)
+
+#    define SPI_VIA_IOMUX     ((SPI_IS_CS_IOMUX) && \
+                               (SPI_IS_CLK_IOMUX) && \
+                               (SPI_IS_MOSI_IOMUX) && \
+                               (SPI_IS_MISO_IOMUX) && \
+                               (SPI_IS_IO2_IOMUX) && \
+                               (SPI_IS_IO3_IOMUX))
+#  else
+#    define SPI_VIA_IOMUX     ((SPI_IS_CS_IOMUX) && \
+                               (SPI_IS_CLK_IOMUX) && \
+                               (SPI_IS_MOSI_IOMUX) && \
+                               (SPI_IS_MISO_IOMUX))
+#  endif
 #else
 #  define SPI_VIA_IOMUX     0
 #endif
@@ -136,12 +162,15 @@ struct spislave_config_s
   uint8_t mosi_pin;           /* GPIO configuration for MOSI */
   uint8_t miso_pin;           /* GPIO configuration for MISO */
   uint8_t clk_pin;            /* GPIO configuration for CLK */
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+  uint8_t io2_pin;            /* GPIO configuration for IO2 */
+  uint8_t io3_pin;            /* GPIO configuration for IO3 */
+#endif
   uint8_t periph;             /* Peripheral ID */
   uint8_t irq;                /* Interrupt ID */
   uint32_t clk_bit;           /* Clock enable bit */
   uint32_t rst_bit;           /* SPI reset bit */
-#ifdef ESP32S3_SPI_DMA
-  bool dma_used;              /* Enable DMA channel */
+#ifdef CONFIG_ESP32S3_SPI_DMA
   uint32_t dma_clk_bit;       /* DMA clock enable bit */
   uint32_t dma_rst_bit;       /* DMA reset bit */
   uint8_t dma_periph;         /* DMA peripheral */
@@ -154,6 +183,12 @@ struct spislave_config_s
   uint32_t miso_outsig;       /* SPI MISO output signal index */
   uint32_t clk_insig;         /* SPI CLK input signal index */
   uint32_t clk_outsig;        /* SPI CLK output signal index */
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+  uint32_t io2_insig;
+  uint32_t io2_outsig;
+  uint32_t io3_insig;
+  uint32_t io3_outsig;
+#endif
 };
 
 struct spislave_priv_s
@@ -172,7 +207,7 @@ struct spislave_priv_s
   int refs;                   /* Reference count */
   int cpu;                    /* CPU ID */
   int cpuint;                 /* SPI interrupt ID */
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
   int32_t dma_channel;        /* Channel assigned by the GDMA driver */
 
   /* DMA RX/TX description */
@@ -224,7 +259,7 @@ static void spislave_store_result(struct spislave_priv_s *priv,
                                   uint32_t recv_bytes);
 static void spislave_evict_sent_data(struct spislave_priv_s *priv,
                                      uint32_t sent_bytes);
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 static void spislave_setup_rx_dma(struct spislave_priv_s *priv);
 static void spislave_setup_tx_dma(struct spislave_priv_s *priv);
 static void spislave_prepare_next_rx(struct spislave_priv_s *priv);
@@ -265,12 +300,15 @@ static const struct spislave_config_s esp32s3_spi2slave_config =
   .mosi_pin     = CONFIG_ESP32S3_SPI2_MOSIPIN,
   .miso_pin     = CONFIG_ESP32S3_SPI2_MISOPIN,
   .clk_pin      = CONFIG_ESP32S3_SPI2_CLKPIN,
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+  .io2_pin      = CONFIG_ESP32S3_SPI2_IO2PIN,
+  .io3_pin      = CONFIG_ESP32S3_SPI2_IO3PIN,
+#endif
   .periph       = ESP32S3_PERIPH_SPI2,
   .irq          = ESP32S3_IRQ_SPI2,
   .clk_bit      = SYSTEM_SPI2_CLK_EN,
   .rst_bit      = SYSTEM_SPI2_RST,
-#ifdef CONFIG_ESP32S3_SPI2_DMA
-  .dma_used     = true,
+#ifdef CONFIG_ESP32S3_SPI_DMA
   .dma_clk_bit  = SYSTEM_SPI2_DMA_CLK_EN,
   .dma_rst_bit  = SYSTEM_SPI2_DMA_RST,
   .dma_periph   = ESP32S3_DMA_PERIPH_SPI2,
@@ -282,7 +320,13 @@ static const struct spislave_config_s esp32s3_spi2slave_config =
   .miso_insig   = FSPIQ_IN_IDX,
   .miso_outsig  = FSPIQ_OUT_IDX,
   .clk_insig    = FSPICLK_IN_IDX,
-  .clk_outsig   = FSPICLK_OUT_IDX
+  .clk_outsig   = FSPICLK_OUT_IDX,
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+  .io2_insig    = FSPIWP_IN_IDX,
+  .io2_outsig   = FSPIWP_OUT_IDX,
+  .io3_insig    = FSPIHD_IN_IDX,
+  .io3_outsig   = FSPIHD_OUT_IDX,
+#endif
 };
 
 static const struct spi_slave_ctrlrops_s esp32s3_spi2slave_ops =
@@ -295,7 +339,7 @@ static const struct spi_slave_ctrlrops_s esp32s3_spi2slave_ops =
   .qpoll    = spislave_qpoll
 };
 
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 
 /* SPI DMA RX/TX description buffer */
 
@@ -314,7 +358,7 @@ static struct spislave_priv_s esp32s3_spi2slave_priv =
   .refs          = 0,
   .cpu           = -1,
   .cpuint        = -ENOMEM,
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
   .dma_channel   = -ENOMEM,
   .dma_rxdesc    = esp32s3_spi2_dma_rxdesc,
   .dma_txdesc    = esp32s3_spi2_dma_txdesc,
@@ -347,12 +391,15 @@ static const struct spislave_config_s esp32s3_spi3slave_config =
   .mosi_pin     = CONFIG_ESP32S3_SPI3_MOSIPIN,
   .miso_pin     = CONFIG_ESP32S3_SPI3_MISOPIN,
   .clk_pin      = CONFIG_ESP32S3_SPI3_CLKPIN,
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+  .io2_pin      = CONFIG_ESP32S3_SPI3_IO2PIN,
+  .io3_pin      = CONFIG_ESP32S3_SPI3_IO3PIN,
+#endif
   .periph       = ESP32S3_PERIPH_SPI3,
   .irq          = ESP32S3_IRQ_SPI3,
   .clk_bit      = SYSTEM_SPI3_CLK_EN,
   .rst_bit      = SYSTEM_SPI3_RST,
-#ifdef CONFIG_ESP32S3_SPI3_DMA
-  .dma_used     = true,
+#ifdef CONFIG_ESP32S3_SPI_DMA
   .dma_clk_bit  = SYSTEM_SPI3_DMA_CLK_EN,
   .dma_rst_bit  = SYSTEM_SPI3_DMA_RST,
   .dma_periph   = ESP32S3_DMA_PERIPH_SPI3,
@@ -364,7 +411,13 @@ static const struct spislave_config_s esp32s3_spi3slave_config =
   .miso_insig   = SPI3_Q_IN_IDX,
   .miso_outsig  = SPI3_Q_OUT_IDX,
   .clk_insig    = SPI3_CLK_IN_IDX,
-  .clk_outsig   = SPI3_CLK_OUT_IDX
+  .clk_outsig   = SPI3_CLK_OUT_IDX,
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+  .io2_insig    = SPI3_WP_IN_IDX,
+  .io2_outsig   = SPI3_WP_OUT_IDX,
+  .io3_insig    = SPI3_HD_IN_IDX,
+  .io3_outsig   = SPI3_HD_OUT_IDX,
+#endif
 };
 
 static const struct spi_slave_ctrlrops_s esp32s3_spi3slave_ops =
@@ -377,7 +430,7 @@ static const struct spi_slave_ctrlrops_s esp32s3_spi3slave_ops =
   .qpoll    = spislave_qpoll
 };
 
-#ifdef CONFIG_ESP32S3_SPI3_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 
 /* SPI DMA RX/TX description buffer */
 
@@ -396,7 +449,7 @@ static struct spislave_priv_s esp32s3_spi3slave_priv =
   .refs          = 0,
   .cpu           = -1,
   .cpuint        = -ENOMEM,
-#ifdef CONFIG_ESP32S3_SPI3_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
   .dma_channel   = -ENOMEM,
   .dma_rxdesc    = esp32s3_spi3_dma_rxdesc,
   .dma_txdesc    = esp32s3_spi3_dma_txdesc,
@@ -479,7 +532,7 @@ static inline void spislave_cpu_tx_fifo_reset(struct spislave_priv_s *priv)
  *
  ****************************************************************************/
 
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 static inline void spislave_dma_tx_fifo_reset(struct spislave_priv_s *priv)
 {
   setbits(SPI_DMA_AFIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
@@ -502,7 +555,7 @@ static inline void spislave_dma_tx_fifo_reset(struct spislave_priv_s *priv)
  *
  ****************************************************************************/
 
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 static inline void spislave_dma_rx_fifo_reset(struct spislave_priv_s *priv)
 {
   setbits(SPI_RX_AFIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
@@ -678,7 +731,7 @@ static void spislave_store_result(struct spislave_priv_s *priv,
       bytes_to_copy = remaining_space;
     }
 
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
   if (bytes_to_copy)
     {
       if ((priv->rx_dma_offset != priv->rx_length))
@@ -739,7 +792,7 @@ static void spislave_store_result(struct spislave_priv_s *priv,
  *
  ****************************************************************************/
 
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 static void spislave_prepare_next_rx(struct spislave_priv_s *priv)
 {
   if (priv->rx_length < SPI_SLAVE_BUFSIZE)
@@ -797,7 +850,7 @@ static void spislave_evict_sent_data(struct spislave_priv_s *priv,
  *
  ****************************************************************************/
 
-#ifndef ESP32S3_SPI_DMA
+#ifndef CONFIG_ESP32S3_SPI_DMA
 static void spislave_write_tx_buffer(struct spislave_priv_s *priv)
 {
   /* Initialize data_buf_reg with the address of the first data buffer
@@ -842,7 +895,7 @@ static void spislave_write_tx_buffer(struct spislave_priv_s *priv)
  *
  ****************************************************************************/
 
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 static void spislave_setup_rx_dma(struct spislave_priv_s *priv)
 {
   uint32_t length = SPI_SLAVE_BUFSIZE - priv->rx_length;
@@ -888,7 +941,7 @@ static void spislave_setup_rx_dma(struct spislave_priv_s *priv)
  *
  ****************************************************************************/
 
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 static void spislave_setup_tx_dma(struct spislave_priv_s *priv)
 {
   esp32s3_dma_setup(priv->dma_channel,
@@ -934,11 +987,8 @@ static void spislave_prepare_next_tx(struct spislave_priv_s *priv)
 {
   if (priv->tx_length != 0)
     {
-#ifdef ESP32S3_SPI_DMA
-      if (priv->config->dma_used)
-        {
-          spislave_setup_tx_dma(priv);
-        }
+#ifdef CONFIG_ESP32S3_SPI_DMA
+      spislave_setup_tx_dma(priv);
 #else
       spislave_peripheral_reset(priv);
 
@@ -953,14 +1003,7 @@ static void spislave_prepare_next_tx(struct spislave_priv_s *priv)
     {
       spiwarn("TX buffer empty! Disabling TX for next transaction\n");
 
-#ifdef ESP32S3_SPI_DMA
-      if (!priv->config->dma_used)
-        {
-          spislave_cpu_tx_fifo_reset(priv);
-        }
-#else
       spislave_cpu_tx_fifo_reset(priv);
-#endif
 
       priv->is_tx_enabled = false;
     }
@@ -986,10 +1029,16 @@ static void spislave_prepare_next_tx(struct spislave_priv_s *priv)
 static int spislave_periph_interrupt(int irq, void *context, void *arg)
 {
   struct spislave_priv_s *priv = (struct spislave_priv_s *)arg;
-
   uint32_t regval = getreg32(SPI_SLAVE1_REG(priv->config->id));
   uint32_t transfer_size = REG_MASK(regval, SPI_SLV_DATA_BITLEN) / 8;
 
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+  uint32_t int_clear = 0;
+  uint32_t int_status = getreg32(SPI_DMA_INT_ST_REG(priv->config->id));
+#else
+  uint32_t int_clear = SPI_TRANS_DONE_INT_CLR_M;
+#endif
+
   if (!priv->is_processing)
     {
       SPIS_DEV_SELECT(priv->dev, true);
@@ -998,26 +1047,41 @@ static int spislave_periph_interrupt(int irq, void *context, void *arg)
 
   /* RX process */
 
-  if (transfer_size > 0)
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+  if (int_status & SPI_SLV_INT_RX)
     {
-      spislave_store_result(priv, transfer_size);
-    }
+#endif
+      if (transfer_size > 0)
+        {
+          spislave_store_result(priv, transfer_size);
+        }
 
-#ifdef ESP32S3_SPI_DMA
-  if (priv->config->dma_used)
-    {
+#ifdef CONFIG_ESP32S3_SPI_DMA
       spislave_prepare_next_rx(priv);
+#endif
+
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+      int_clear |= SPI_SLV_INT_CLR_RX;
     }
 #endif
 
   /* TX process */
 
-  if (priv->is_tx_enabled && transfer_size > 0)
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+  if (int_status & SPI_SLV_INT_TX)
     {
-      spislave_evict_sent_data(priv, transfer_size);
-    }
+#endif
+      if (priv->is_tx_enabled && transfer_size > 0)
+        {
+          spislave_evict_sent_data(priv, transfer_size);
+        }
 
-  spislave_prepare_next_tx(priv);
+      spislave_prepare_next_tx(priv);
+
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+      int_clear |= SPI_SLV_INT_CLR_TX;
+    }
+#endif
 
   if (priv->is_processing && esp32s3_gpioread(priv->config->cs_pin))
     {
@@ -1027,11 +1091,13 @@ static int spislave_periph_interrupt(int irq, void *context, void *arg)
 
   /* Clear the trans_done interrupt flag */
 
-  setbits(SPI_TRANS_DONE_INT_CLR_M, SPI_DMA_INT_CLR_REG(priv->config->id));
+  setbits(int_clear, SPI_DMA_INT_CLR_REG(priv->config->id));
 
   /* Trigger the start of user-defined transaction */
 
+#ifndef CONFIG_ESP32S3_SPI_IO_QIO
   setbits(SPI_USR_M, SPI_CMD_REG(priv->config->id));
+#endif
 
   return 0;
 }
@@ -1050,7 +1116,7 @@ static int spislave_periph_interrupt(int irq, void *context, void *arg)
  *
  ****************************************************************************/
 
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
 void spislave_dma_init(struct spislave_priv_s *priv)
 {
   /* Enable GDMA clock for the SPI peripheral */
@@ -1087,10 +1153,10 @@ void spislave_dma_init(struct spislave_priv_s *priv)
 #endif
 
 /****************************************************************************
- * Name: spislave_gpio_initialize
+ * Name: spislave_initializ_iomux
  *
  * Description:
- *   Initialize ESP32-S3 SPI Slave GPIO
+ *   Initialize ESP32-S3 SPI Slave GPIO by IO MUX.
  *
  * Input Parameters:
  *   priv - Private SPI Slave controller structure
@@ -1100,56 +1166,120 @@ void spislave_dma_init(struct spislave_priv_s *priv)
  *
  ****************************************************************************/
 
-static void spislave_gpio_initialize(struct spislave_priv_s *priv)
+#if SPI_VIA_IOMUX != 0
+static void spislave_initializ_iomux(struct spislave_priv_s *priv)
 {
+  uint32_t attr = INPUT_FUNCTION_5 | DRIVE_0;
   const struct spislave_config_s *config = priv->config;
 
-  esp32s3_gpiowrite(config->cs_pin, 1);
-  esp32s3_gpiowrite(config->mosi_pin, 1);
-  esp32s3_gpiowrite(config->miso_pin, 1);
-  esp32s3_gpiowrite(config->clk_pin, 1);
+  esp32s3_configgpio(config->cs_pin,  attr);
+  esp32s3_configgpio(config->clk_pin, attr);
 
-#if SPI_VIA_IOMUX != 0
-  if (priv->config->id == 0)
-    {
-      esp32s3_configgpio(config->cs_pin, INPUT_FUNCTION_5 | PULLUP);
-      esp32s3_gpio_matrix_out(config->cs_pin, SIG_GPIO_OUT_IDX, 0, 0);
+  esp32s3_gpio_matrix_out(config->cs_pin,   SIG_GPIO_OUT_IDX, 0, 0);
+  esp32s3_gpio_matrix_out(config->clk_pin,  SIG_GPIO_OUT_IDX, 0, 0);
+  esp32s3_gpio_matrix_out(config->mosi_pin, SIG_GPIO_OUT_IDX, 0, 0);
+  esp32s3_gpio_matrix_out(config->miso_pin, SIG_GPIO_OUT_IDX, 0, 0);
 
-      esp32s3_configgpio(config->mosi_pin, INPUT_FUNCTION_5 | PULLUP);
-      esp32s3_gpio_matrix_out(config->mosi_pin, SIG_GPIO_OUT_IDX, 0, 0);
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+  attr |= OUTPUT;
 
-      esp32s3_configgpio(config->miso_pin, OUTPUT_FUNCTION_5 | PULLUP);
-      esp32s3_gpio_matrix_out(config->miso_pin, SIG_GPIO_OUT_IDX, 0, 0);
+  esp32s3_configgpio(config->mosi_pin, attr);
+  esp32s3_configgpio(config->miso_pin, attr);
+  esp32s3_configgpio(config->io2_pin,  attr);
+  esp32s3_configgpio(config->io3_pin,  attr);
 
-      esp32s3_configgpio(config->clk_pin, INPUT_FUNCTION_5 | PULLUP);
-      esp32s3_gpio_matrix_out(config->clk_pin, SIG_GPIO_OUT_IDX, 0, 0);
-    }
-  else
-    {
-      esp32s3_configgpio(config->cs_pin, INPUT_FUNCTION_2 | PULLUP);
-      esp32s3_gpio_matrix_in(config->cs_pin, config->cs_insig, 0);
+  esp32s3_gpio_matrix_out(config->io2_pin, SIG_GPIO_OUT_IDX, 0, 0);
+  esp32s3_gpio_matrix_out(config->io3_pin, SIG_GPIO_OUT_IDX, 0, 0);
+#else
+  esp32s3_configgpio(config->mosi_pin, attr);
+  esp32s3_configgpio(config->miso_pin, OUTPUT_FUNCTION_5);
+#endif
+}
+#endif
 
-      esp32s3_configgpio(config->mosi_pin, INPUT_FUNCTION_2 | PULLUP);
-      esp32s3_gpio_matrix_in(config->mosi_pin, config->mosi_insig, 0);
+/****************************************************************************
+ * Name: spislave_initializ_iomatrix
+ *
+ * Description:
+ *   Initialize ESP32-S3 SPI Slave GPIO by IO matrix.
+ *
+ * Input Parameters:
+ *   priv - Private SPI Slave controller structure
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
 
-      esp32s3_configgpio(config->miso_pin, OUTPUT_FUNCTION_2 | PULLUP);
-      esp32s3_gpio_matrix_out(config->miso_pin, config->miso_outsig, 0, 0);
+#if SPI_VIA_IOMUX == 0 || defined(CONFIG_ESP32S3_SPI3)
+static void spislave_initializ_iomatrix(struct spislave_priv_s *priv)
+{
+  uint32_t attr = INPUT | DRIVE_0;
+  const struct spislave_config_s *config = priv->config;
 
-      esp32s3_configgpio(config->clk_pin, INPUT_FUNCTION_2 | PULLUP);
-      esp32s3_gpio_matrix_in(config->clk_pin, config->clk_insig, 0);
-    }
-#else
-  esp32s3_configgpio(config->cs_pin, INPUT_FUNCTION_2 | PULLUP);
+  esp32s3_configgpio(config->cs_pin, attr);
   esp32s3_gpio_matrix_in(config->cs_pin, config->cs_insig, 0);
 
-  esp32s3_configgpio(config->mosi_pin, INPUT_FUNCTION_2 | PULLUP);
+  esp32s3_configgpio(config->clk_pin, attr);
+  esp32s3_gpio_matrix_in(config->clk_pin, config->clk_insig, 0);
+
+#  ifdef CONFIG_ESP32S3_SPI_IO_QIO
+  attr |= OUTPUT;
+
+  esp32s3_configgpio(config->mosi_pin, attr);
   esp32s3_gpio_matrix_in(config->mosi_pin, config->mosi_insig, 0);
+  esp32s3_gpio_matrix_out(config->mosi_pin, config->mosi_outsig, 0, 0);
 
-  esp32s3_configgpio(config->miso_pin, OUTPUT_FUNCTION_2 | PULLUP);
+  esp32s3_configgpio(config->miso_pin, attr);
+  esp32s3_gpio_matrix_in(config->miso_pin, config->miso_insig, 0);
   esp32s3_gpio_matrix_out(config->miso_pin, config->miso_outsig, 0, 0);
 
-  esp32s3_configgpio(config->clk_pin, INPUT_FUNCTION_2 | PULLUP);
-  esp32s3_gpio_matrix_in(config->clk_pin, config->clk_insig, 0);
+  esp32s3_configgpio(config->io2_pin, attr);
+  esp32s3_gpio_matrix_in(config->io2_pin, config->io2_insig, 0);
+  esp32s3_gpio_matrix_out(config->io2_pin, config->io2_outsig, 0, 0);
+
+  esp32s3_configgpio(config->io3_pin, attr);
+  esp32s3_gpio_matrix_in(config->io3_pin, config->io3_insig, 0);
+  esp32s3_gpio_matrix_out(config->io3_pin, config->io3_outsig, 0, 0);
+#  else
+  esp32s3_configgpio(config->mosi_pin, attr);
+  esp32s3_gpio_matrix_in(config->mosi_pin, config->mosi_insig, 0);
+
+  esp32s3_configgpio(config->miso_pin, OUTPUT);
+  esp32s3_gpio_matrix_out(config->miso_pin, config->miso_outsig, 0, 0);
+#  endif
+}
+#endif
+
+/****************************************************************************
+ * Name: spislave_gpio_initialize
+ *
+ * Description:
+ *   Initialize ESP32-S3 SPI Slave GPIO
+ *
+ * Input Parameters:
+ *   priv - Private SPI Slave controller structure
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void spislave_gpio_initialize(struct spislave_priv_s *priv)
+{
+#if SPI_VIA_IOMUX != 0
+  if (priv->config->id == 2)
+    {
+      spislave_initializ_iomux(priv);
+    }
+#  ifdef CONFIG_ESP32S3_SPI3
+  else
+    {
+      spislave_initializ_iomatrix(priv);
+    }
+#  endif
+#else
+  spislave_initializ_iomatrix(priv);
 #endif
 }
 
@@ -1169,6 +1299,7 @@ static void spislave_gpio_initialize(struct spislave_priv_s *priv)
 
 static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr)
 {
+  uint32_t regval;
   struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
   const struct spislave_config_s *config = priv->config;
 
@@ -1183,11 +1314,23 @@ static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr)
 
   putreg32(0, SPI_CLOCK_REG(priv->config->id));
 
-  putreg32(SPI_DOUTDIN_M, SPI_USER_REG(priv->config->id));
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+  regval = 0;
+#else
+  regval = SPI_DOUTDIN_M;
+#endif
+  putreg32(regval, SPI_USER_REG(priv->config->id));
 
   putreg32(0, SPI_CTRL_REG(priv->config->id));
 
-  putreg32(SPI_SLAVE_MODE_M, SPI_SLAVE_REG(priv->config->id));
+  regval = SPI_SLAVE_MODE_M;
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  regval |= SPI_SLV_WRDMA_BITLEN_EN_M | SPI_SLV_RDDMA_BITLEN_EN_M;
+#else
+  regval |= SPI_SLV_WRBUF_BITLEN_EN_M | SPI_SLV_RDBUF_BITLEN_EN_M;
+#endif
+
+  putreg32(regval, SPI_SLAVE_REG(priv->config->id));
 
   spislave_peripheral_reset(priv);
 
@@ -1200,11 +1343,8 @@ static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr)
 
   resetbits(SPI_INT_MASK, SPI_DMA_INT_ENA_REG(priv->config->id));
 
-#ifdef ESP32S3_SPI_DMA
-  if (priv->config->dma_used)
-    {
-      spislave_dma_init(priv);
-    }
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  spislave_dma_init(priv);
 #endif
 
   esp32s3_gpioirqenable(ESP32S3_PIN2IRQ(config->cs_pin), GPIO_INTR_POSEDGE);
@@ -1216,8 +1356,13 @@ static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr)
    * queued.
    */
 
-  setbits(SPI_TRANS_DONE_INT_RAW_M, SPI_DMA_INT_RAW_REG(priv->config->id));
-  setbits(SPI_TRANS_DONE_INT_ENA_M, SPI_DMA_INT_ENA_REG(priv->config->id));
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+  regval = SPI_SLV_INT_EN;
+#else
+  regval = SPI_TRANS_DONE_INT_ENA_M;
+#endif
+  setbits(regval, SPI_DMA_INT_RAW_REG(priv->config->id));
+  setbits(regval, SPI_DMA_INT_ENA_REG(priv->config->id));
 }
 
 /****************************************************************************
@@ -1244,12 +1389,8 @@ static void spislave_deinitialize(struct spi_slave_ctrlr_s *ctrlr)
 
   resetbits(SPI_TRANS_DONE_INT_ENA_M, SPI_DMA_INT_ENA_REG(priv->config->id));
 
-#ifdef ESP32S3_SPI_DMA
-  if (priv->config->dma_used)
-    {
-      resetbits(priv->config->dma_clk_bit, SYSTEM_PERIP_CLK_EN0_REG);
-    }
-
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  resetbits(priv->config->dma_clk_bit, SYSTEM_PERIP_CLK_EN0_REG);
   priv->rx_dma_offset = 0;
 #endif
 
@@ -1315,7 +1456,7 @@ static void spislave_bind(struct spi_slave_ctrlr_s *ctrlr,
 
   SPIS_DEV_CMDDATA(dev, false);
 
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
   priv->rx_dma_offset = 0;
 #endif
 
@@ -1337,6 +1478,10 @@ static void spislave_bind(struct spi_slave_ctrlr_s *ctrlr,
       priv->tx_length += num_bytes;
     }
 
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  spislave_prepare_next_rx(priv);
+#endif
+
   /* Enable the CPU interrupt that is linked to the SPI Slave controller */
 
   up_enable_irq(priv->config->irq);
@@ -1380,11 +1525,8 @@ static void spislave_unbind(struct spi_slave_ctrlr_s *ctrlr)
 
   resetbits(SPI_TRANS_DONE_INT_ENA_M, SPI_DMA_INT_ENA_REG(priv->config->id));
 
-#ifdef ESP32S3_SPI_DMA
-  if (priv->config->dma_used)
-    {
-      resetbits(priv->config->dma_clk_bit, SYSTEM_PERIP_CLK_EN0_REG);
-    }
+#ifdef CONFIG_ESP32S3_SPI_DMA
+  resetbits(priv->config->dma_clk_bit, SYSTEM_PERIP_CLK_EN0_REG);
 #endif
 
   resetbits(priv->config->clk_bit, SYSTEM_PERIP_CLK_EN0_REG);