pkarashchenko commented on code in PR #11138:
URL: https://github.com/apache/nuttx/pull/11138#discussion_r1384543539


##########
arch/xtensa/src/esp32s2/esp32s2_spi_slave.c:
##########
@@ -0,0 +1,1734 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_spi_slave.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>
+
+#if defined(CONFIG_ESP32S2_SPI) && defined(CONFIG_SPI_SLAVE)
+
+#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 <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/spi/spi.h>
+#include <nuttx/spi/slave.h>
+
+#include <arch/board/board.h>
+
+#include "esp32s2_spi.h"
+#include "esp32s2_irq.h"
+#include "esp32s2_gpio.h"
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+#include "esp32s2_dma.h"
+#endif
+
+#include "xtensa.h"
+#include "hardware/esp32s2_gpio_sigmap.h"
+#include "hardware/esp32s2_pinmap.h"
+#include "hardware/esp32s2_spi.h"
+#include "hardware/esp32s2_soc.h"
+#include "hardware/esp32s2_system.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#define SPI_SLAVE_BUFSIZE (CONFIG_ESP32S2_SPI_SLAVE_BUFSIZE)
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+/* SPI DMA RX/TX number of descriptors */
+
+#  if (SPI_SLAVE_BUFSIZE % ESP32S2_DMA_BUFLEN_MAX) > 0
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_DMA_BUFLEN_MAX + 1)
+#  else
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_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_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_ESP32S2_SPI_DMA */
+
+/* Verify whether SPI has been assigned IOMUX pins.
+ * Otherwise, SPI signals will be routed via GPIO Matrix.
+ */
+
+#ifdef CONFIG_ESP32S2_SPI2
+#  define SPI_IS_CS_IOMUX   (CONFIG_ESP32S2_SPI2_CSPIN == SPI2_IOMUX_CSPIN)
+#  define SPI_IS_CLK_IOMUX  (CONFIG_ESP32S2_SPI2_CLKPIN == SPI2_IOMUX_CLKPIN)
+#  define SPI_IS_MOSI_IOMUX (CONFIG_ESP32S2_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN)
+#  define SPI_IS_MISO_IOMUX (CONFIG_ESP32S2_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))
+#else
+#  define SPI_VIA_IOMUX     0
+#endif
+
+/* SPI Slave interrupt mask */
+
+#define SPI_INT_MASK      (SPI_IN_DONE_INT_ENA_M |      \
+                           SPI_OUT_DONE_INT_ENA_M |     \
+                           SPI_SLV_WR_DMA_DONE_M | \
+                           SPI_SLV_RD_DMA_DONE_M | \

Review Comment:
   please fix style here



##########
arch/xtensa/src/esp32s2/esp32s2_spi_slave.c:
##########
@@ -0,0 +1,1734 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_spi_slave.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>
+
+#if defined(CONFIG_ESP32S2_SPI) && defined(CONFIG_SPI_SLAVE)
+
+#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 <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/spi/spi.h>
+#include <nuttx/spi/slave.h>
+
+#include <arch/board/board.h>
+
+#include "esp32s2_spi.h"
+#include "esp32s2_irq.h"
+#include "esp32s2_gpio.h"
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+#include "esp32s2_dma.h"
+#endif
+
+#include "xtensa.h"
+#include "hardware/esp32s2_gpio_sigmap.h"
+#include "hardware/esp32s2_pinmap.h"
+#include "hardware/esp32s2_spi.h"
+#include "hardware/esp32s2_soc.h"
+#include "hardware/esp32s2_system.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#define SPI_SLAVE_BUFSIZE (CONFIG_ESP32S2_SPI_SLAVE_BUFSIZE)
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+/* SPI DMA RX/TX number of descriptors */
+
+#  if (SPI_SLAVE_BUFSIZE % ESP32S2_DMA_BUFLEN_MAX) > 0
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_DMA_BUFLEN_MAX + 1)
+#  else
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_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_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_ESP32S2_SPI_DMA */
+
+/* Verify whether SPI has been assigned IOMUX pins.
+ * Otherwise, SPI signals will be routed via GPIO Matrix.
+ */
+
+#ifdef CONFIG_ESP32S2_SPI2
+#  define SPI_IS_CS_IOMUX   (CONFIG_ESP32S2_SPI2_CSPIN == SPI2_IOMUX_CSPIN)
+#  define SPI_IS_CLK_IOMUX  (CONFIG_ESP32S2_SPI2_CLKPIN == SPI2_IOMUX_CLKPIN)
+#  define SPI_IS_MOSI_IOMUX (CONFIG_ESP32S2_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN)
+#  define SPI_IS_MISO_IOMUX (CONFIG_ESP32S2_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))
+#else
+#  define SPI_VIA_IOMUX     0
+#endif
+
+/* SPI Slave interrupt mask */
+
+#define SPI_INT_MASK      (SPI_IN_DONE_INT_ENA_M |      \
+                           SPI_OUT_DONE_INT_ENA_M |     \
+                           SPI_SLV_WR_DMA_DONE_M | \
+                           SPI_SLV_RD_DMA_DONE_M | \
+                           SPI_SLV_WR_BUF_DONE_M | \
+                           SPI_SLV_RD_BUF_DONE_M)
+
+/* SPI Slave default width */
+
+#define SPI_SLAVE_DEFAULT_WIDTH (8)
+
+/* SPI Slave default mode */
+
+#define SPI_SLAVE_DEFAULT_MODE  (SPISLAVE_MODE0)
+
+/* SPI Slave maximum buffer size in bytes */
+
+#define SPI_SLAVE_HW_BUF_SIZE   (64)
+
+#define WORDS2BYTES(_priv, _wn)   ((_wn) * ((_priv)->nbits / 8))
+#define BYTES2WORDS(_priv, _bn)   ((_bn) / ((_priv)->nbits / 8))
+
+#define setbits(bs, a)     modifyreg32(a, 0, bs)
+#define resetbits(bs, a)   modifyreg32(a, bs, 0)
+
+/* SPI Slave controller hardware configuration */
+
+struct spislave_config_s
+{
+  int32_t width;              /* SPI Slave default width */
+  enum spi_slave_mode_e mode; /* SPI Slave default mode */
+
+  uint8_t id;                 /* SPI 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 periph;             /* Peripheral ID */
+  uint8_t irq;                /* Interrupt ID */
+  uint32_t clk_bit;           /* Clock enable bit */
+  uint32_t rst_bit;           /* SPI reset bit */
+#ifdef CONFIG_ESP32S2_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 */
+#endif
+  uint32_t cs_insig;          /* SPI CS input signal index */
+  uint32_t cs_outsig;         /* SPI CS output signal index */
+  uint32_t mosi_insig;        /* SPI MOSI input signal index */
+  uint32_t mosi_outsig;       /* SPI MOSI output signal index */
+  uint32_t miso_insig;        /* SPI MISO input signal index */
+  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 */
+};
+
+struct spislave_priv_s
+{
+  /* Externally visible part of the SPI Slave controller interface */
+
+  struct spi_slave_ctrlr_s ctrlr;
+
+  /* Reference to SPI Slave device interface */
+
+  struct spi_slave_dev_s *dev;
+
+  /* Port configuration */
+
+  const struct spislave_config_s *config;
+  int refs;                   /* Reference count */
+  int cpu;                    /* CPU ID */
+  int cpuint;                 /* SPI interrupt ID */
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  int32_t dma_channel;        /* Channel assigned by the GDMA driver */
+
+  /* DMA RX/TX description */
+
+  struct esp32s2_dmadesc_s *dma_rxdesc;
+  struct esp32s2_dmadesc_s *dma_txdesc;
+
+  uint32_t rx_dma_offset;     /* Offset of DMA RX buffer */
+#endif
+  enum spi_slave_mode_e mode; /* Current SPI Slave hardware mode */
+  uint8_t nbits;              /* Current configured bit width */
+  uint32_t tx_length;         /* Location of next TX value */
+
+  /* SPI Slave TX queue buffer */
+
+  uint8_t tx_buffer[SPI_SLAVE_BUFSIZE];
+  uint32_t rx_length;         /* Location of next RX value */
+
+  /* SPI Slave RX queue buffer */
+
+  uint8_t rx_buffer[SPI_SLAVE_BUFSIZE];
+
+  /* Flag that indicates whether SPI Slave is currently processing */
+
+  bool is_processing;
+
+  /* Flag that indicates whether SPI Slave TX is currently enabled */
+
+  bool is_tx_enabled;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* SPI Slave controller interrupt handlers */
+
+static int spislave_cs_interrupt(int irq, void *context, void *arg);
+static int spislave_periph_interrupt(int irq, void *context, void *arg);
+
+/* SPI Slave controller internal functions */
+
+static void spislave_setmode(struct spi_slave_ctrlr_s *ctrlr,
+                             enum spi_slave_mode_e mode);
+static void spislave_setbits(struct spi_slave_ctrlr_s *ctrlr, int nbits);
+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 CONFIG_ESP32S2_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);
+static void spislave_prepare_next_tx(struct spislave_priv_s *priv);
+#else
+static void spislave_write_tx_buffer(struct spislave_priv_s *priv);
+#endif
+static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_deinitialize(struct spi_slave_ctrlr_s *ctrlr);
+
+/* SPI Slave controller operations */
+
+static void spislave_bind(struct spi_slave_ctrlr_s *ctrlr,
+                          struct spi_slave_dev_s *dev,
+                          enum spi_slave_mode_e mode,
+                          int nbits);
+static void spislave_unbind(struct spi_slave_ctrlr_s *ctrlr);
+static int spislave_enqueue(struct spi_slave_ctrlr_s *ctrlr,
+                            const void *data,
+                            size_t nwords);
+static bool spislave_qfull(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_qflush(struct spi_slave_ctrlr_s *ctrlr);
+static size_t spislave_qpoll(struct spi_slave_ctrlr_s *ctrlr);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/*  SPI2 private data */
+
+#ifdef CONFIG_ESP32S2_SPI2
+static const struct spislave_config_s esp32s2_spi2slave_config =
+{
+  .width        = SPI_SLAVE_DEFAULT_WIDTH,
+  .mode         = SPI_SLAVE_DEFAULT_MODE,
+  .id           = 2,
+  .cs_pin       = CONFIG_ESP32S2_SPI2_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S2_SPI2_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S2_SPI2_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S2_SPI2_CLKPIN,
+  .periph       = ESP32S2_PERIPH_SPI2,
+  .irq          = ESP32S2_IRQ_SPI2,
+  .clk_bit      = SYSTEM_SPI2_CLK_EN,
+  .rst_bit      = SYSTEM_SPI2_RST,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_clk_bit  = SYSTEM_SPI2_DMA_CLK_EN,
+  .dma_rst_bit  = SYSTEM_SPI2_DMA_RST,
+  .dma_periph   = ESP32S2_DMA_PERIPH_SPI2,
+#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,
+};
+
+static const struct spi_slave_ctrlrops_s esp32s2_spi2slave_ops =
+{
+  .bind     = spislave_bind,
+  .unbind   = spislave_unbind,
+  .enqueue  = spislave_enqueue,
+  .qfull    = spislave_qfull,
+  .qflush   = spislave_qflush,
+  .qpoll    = spislave_qpoll
+};
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+
+/* SPI DMA RX/TX description buffer */
+
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_rxdesc[SPI_DMA_DESC_NUM];
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_txdesc[SPI_DMA_DESC_NUM];
+#endif
+
+static struct spislave_priv_s esp32s2_spi2slave_priv =
+{
+  .ctrlr         =
+                  {
+                    .ops = &esp32s2_spi2slave_ops
+                  },

Review Comment:
   ```suggestion
     .ctrlr         =
       {
         .ops = &esp32s2_spi2slave_ops
       },
   ```



##########
arch/xtensa/src/esp32s2/esp32s2_spi_slave.c:
##########
@@ -0,0 +1,1734 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_spi_slave.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>
+
+#if defined(CONFIG_ESP32S2_SPI) && defined(CONFIG_SPI_SLAVE)
+
+#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 <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/spi/spi.h>
+#include <nuttx/spi/slave.h>
+
+#include <arch/board/board.h>
+
+#include "esp32s2_spi.h"
+#include "esp32s2_irq.h"
+#include "esp32s2_gpio.h"
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+#include "esp32s2_dma.h"
+#endif
+
+#include "xtensa.h"
+#include "hardware/esp32s2_gpio_sigmap.h"
+#include "hardware/esp32s2_pinmap.h"
+#include "hardware/esp32s2_spi.h"
+#include "hardware/esp32s2_soc.h"
+#include "hardware/esp32s2_system.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#define SPI_SLAVE_BUFSIZE (CONFIG_ESP32S2_SPI_SLAVE_BUFSIZE)
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+/* SPI DMA RX/TX number of descriptors */
+
+#  if (SPI_SLAVE_BUFSIZE % ESP32S2_DMA_BUFLEN_MAX) > 0
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_DMA_BUFLEN_MAX + 1)
+#  else
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_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_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_ESP32S2_SPI_DMA */
+
+/* Verify whether SPI has been assigned IOMUX pins.
+ * Otherwise, SPI signals will be routed via GPIO Matrix.
+ */
+
+#ifdef CONFIG_ESP32S2_SPI2
+#  define SPI_IS_CS_IOMUX   (CONFIG_ESP32S2_SPI2_CSPIN == SPI2_IOMUX_CSPIN)
+#  define SPI_IS_CLK_IOMUX  (CONFIG_ESP32S2_SPI2_CLKPIN == SPI2_IOMUX_CLKPIN)
+#  define SPI_IS_MOSI_IOMUX (CONFIG_ESP32S2_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN)
+#  define SPI_IS_MISO_IOMUX (CONFIG_ESP32S2_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))
+#else
+#  define SPI_VIA_IOMUX     0
+#endif
+
+/* SPI Slave interrupt mask */
+
+#define SPI_INT_MASK      (SPI_IN_DONE_INT_ENA_M |      \
+                           SPI_OUT_DONE_INT_ENA_M |     \
+                           SPI_SLV_WR_DMA_DONE_M | \
+                           SPI_SLV_RD_DMA_DONE_M | \
+                           SPI_SLV_WR_BUF_DONE_M | \
+                           SPI_SLV_RD_BUF_DONE_M)
+
+/* SPI Slave default width */
+
+#define SPI_SLAVE_DEFAULT_WIDTH (8)
+
+/* SPI Slave default mode */
+
+#define SPI_SLAVE_DEFAULT_MODE  (SPISLAVE_MODE0)
+
+/* SPI Slave maximum buffer size in bytes */
+
+#define SPI_SLAVE_HW_BUF_SIZE   (64)
+
+#define WORDS2BYTES(_priv, _wn)   ((_wn) * ((_priv)->nbits / 8))
+#define BYTES2WORDS(_priv, _bn)   ((_bn) / ((_priv)->nbits / 8))
+
+#define setbits(bs, a)     modifyreg32(a, 0, bs)
+#define resetbits(bs, a)   modifyreg32(a, bs, 0)
+
+/* SPI Slave controller hardware configuration */
+
+struct spislave_config_s
+{
+  int32_t width;              /* SPI Slave default width */
+  enum spi_slave_mode_e mode; /* SPI Slave default mode */
+
+  uint8_t id;                 /* SPI 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 periph;             /* Peripheral ID */
+  uint8_t irq;                /* Interrupt ID */
+  uint32_t clk_bit;           /* Clock enable bit */
+  uint32_t rst_bit;           /* SPI reset bit */
+#ifdef CONFIG_ESP32S2_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 */
+#endif
+  uint32_t cs_insig;          /* SPI CS input signal index */
+  uint32_t cs_outsig;         /* SPI CS output signal index */
+  uint32_t mosi_insig;        /* SPI MOSI input signal index */
+  uint32_t mosi_outsig;       /* SPI MOSI output signal index */
+  uint32_t miso_insig;        /* SPI MISO input signal index */
+  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 */
+};
+
+struct spislave_priv_s
+{
+  /* Externally visible part of the SPI Slave controller interface */
+
+  struct spi_slave_ctrlr_s ctrlr;
+
+  /* Reference to SPI Slave device interface */
+
+  struct spi_slave_dev_s *dev;
+
+  /* Port configuration */
+
+  const struct spislave_config_s *config;
+  int refs;                   /* Reference count */
+  int cpu;                    /* CPU ID */
+  int cpuint;                 /* SPI interrupt ID */
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  int32_t dma_channel;        /* Channel assigned by the GDMA driver */
+
+  /* DMA RX/TX description */
+
+  struct esp32s2_dmadesc_s *dma_rxdesc;
+  struct esp32s2_dmadesc_s *dma_txdesc;
+
+  uint32_t rx_dma_offset;     /* Offset of DMA RX buffer */
+#endif
+  enum spi_slave_mode_e mode; /* Current SPI Slave hardware mode */
+  uint8_t nbits;              /* Current configured bit width */
+  uint32_t tx_length;         /* Location of next TX value */
+
+  /* SPI Slave TX queue buffer */
+
+  uint8_t tx_buffer[SPI_SLAVE_BUFSIZE];
+  uint32_t rx_length;         /* Location of next RX value */
+
+  /* SPI Slave RX queue buffer */
+
+  uint8_t rx_buffer[SPI_SLAVE_BUFSIZE];
+
+  /* Flag that indicates whether SPI Slave is currently processing */
+
+  bool is_processing;
+
+  /* Flag that indicates whether SPI Slave TX is currently enabled */
+
+  bool is_tx_enabled;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* SPI Slave controller interrupt handlers */
+
+static int spislave_cs_interrupt(int irq, void *context, void *arg);
+static int spislave_periph_interrupt(int irq, void *context, void *arg);
+
+/* SPI Slave controller internal functions */
+
+static void spislave_setmode(struct spi_slave_ctrlr_s *ctrlr,
+                             enum spi_slave_mode_e mode);
+static void spislave_setbits(struct spi_slave_ctrlr_s *ctrlr, int nbits);
+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 CONFIG_ESP32S2_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);
+static void spislave_prepare_next_tx(struct spislave_priv_s *priv);
+#else
+static void spislave_write_tx_buffer(struct spislave_priv_s *priv);
+#endif
+static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_deinitialize(struct spi_slave_ctrlr_s *ctrlr);
+
+/* SPI Slave controller operations */
+
+static void spislave_bind(struct spi_slave_ctrlr_s *ctrlr,
+                          struct spi_slave_dev_s *dev,
+                          enum spi_slave_mode_e mode,
+                          int nbits);
+static void spislave_unbind(struct spi_slave_ctrlr_s *ctrlr);
+static int spislave_enqueue(struct spi_slave_ctrlr_s *ctrlr,
+                            const void *data,
+                            size_t nwords);
+static bool spislave_qfull(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_qflush(struct spi_slave_ctrlr_s *ctrlr);
+static size_t spislave_qpoll(struct spi_slave_ctrlr_s *ctrlr);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/*  SPI2 private data */
+
+#ifdef CONFIG_ESP32S2_SPI2
+static const struct spislave_config_s esp32s2_spi2slave_config =
+{
+  .width        = SPI_SLAVE_DEFAULT_WIDTH,
+  .mode         = SPI_SLAVE_DEFAULT_MODE,
+  .id           = 2,
+  .cs_pin       = CONFIG_ESP32S2_SPI2_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S2_SPI2_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S2_SPI2_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S2_SPI2_CLKPIN,
+  .periph       = ESP32S2_PERIPH_SPI2,
+  .irq          = ESP32S2_IRQ_SPI2,
+  .clk_bit      = SYSTEM_SPI2_CLK_EN,
+  .rst_bit      = SYSTEM_SPI2_RST,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_clk_bit  = SYSTEM_SPI2_DMA_CLK_EN,
+  .dma_rst_bit  = SYSTEM_SPI2_DMA_RST,
+  .dma_periph   = ESP32S2_DMA_PERIPH_SPI2,
+#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,
+};
+
+static const struct spi_slave_ctrlrops_s esp32s2_spi2slave_ops =
+{
+  .bind     = spislave_bind,
+  .unbind   = spislave_unbind,
+  .enqueue  = spislave_enqueue,
+  .qfull    = spislave_qfull,
+  .qflush   = spislave_qflush,
+  .qpoll    = spislave_qpoll
+};
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+
+/* SPI DMA RX/TX description buffer */
+
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_rxdesc[SPI_DMA_DESC_NUM];
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_txdesc[SPI_DMA_DESC_NUM];
+#endif
+
+static struct spislave_priv_s esp32s2_spi2slave_priv =
+{
+  .ctrlr         =
+                  {
+                    .ops = &esp32s2_spi2slave_ops
+                  },
+  .dev           = NULL,
+  .config        = &esp32s2_spi2slave_config,
+  .refs          = 0,
+  .cpu           = -1,
+  .cpuint        = -ENOMEM,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_channel   = -ENOMEM,
+  .dma_rxdesc    = esp32s2_spi2_dma_rxdesc,
+  .dma_txdesc    = esp32s2_spi2_dma_txdesc,
+  .rx_dma_offset = 0,
+#endif
+  .mode          = SPISLAVE_MODE0,
+  .nbits         = 0,
+  .tx_length     = 0,
+  .tx_buffer     =
+                  {
+                    0
+                  },
+  .rx_length     = 0,
+  .rx_buffer     =
+                  {
+                    0
+                  },
+  .is_processing = false,
+  .is_tx_enabled = false
+};
+#endif /* CONFIG_ESP32S2_SPI2 */
+
+#ifdef CONFIG_ESP32S2_SPI3
+static const struct spislave_config_s esp32s2_spi3slave_config =
+{
+  .width        = SPI_SLAVE_DEFAULT_WIDTH,
+  .mode         = SPI_SLAVE_DEFAULT_MODE,
+  .id           = 3,
+  .cs_pin       = CONFIG_ESP32S2_SPI3_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S2_SPI3_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S2_SPI3_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S2_SPI3_CLKPIN,
+  .periph       = ESP32S2_PERIPH_SPI3,
+  .irq          = ESP32S2_IRQ_SPI3,
+  .clk_bit      = SYSTEM_SPI3_CLK_EN,
+  .rst_bit      = SYSTEM_SPI3_RST,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_clk_bit  = SYSTEM_SPI3_DMA_CLK_EN,
+  .dma_rst_bit  = SYSTEM_SPI3_DMA_RST,
+  .dma_periph   = ESP32S2_DMA_PERIPH_SPI3,
+#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_MUX_IDX,
+};
+
+static const struct spi_slave_ctrlrops_s esp32s2_spi3slave_ops =
+{
+  .bind     = spislave_bind,
+  .unbind   = spislave_unbind,
+  .enqueue  = spislave_enqueue,
+  .qfull    = spislave_qfull,
+  .qflush   = spislave_qflush,
+  .qpoll    = spislave_qpoll
+};
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+
+/* SPI DMA RX/TX description buffer */
+
+static struct esp32s2_dmadesc_s esp32s2_spi3_dma_rxdesc[SPI_DMA_DESC_NUM];
+static struct esp32s2_dmadesc_s esp32s2_spi3_dma_txdesc[SPI_DMA_DESC_NUM];
+#endif
+
+static struct spislave_priv_s esp32s2_spi3slave_priv =
+{
+  .ctrlr         =
+                  {
+                    .ops = &esp32s2_spi3slave_ops
+                  },
+  .dev           = NULL,
+  .config        = &esp32s2_spi3slave_config,
+  .refs          = 0,
+  .cpu           = -1,
+  .cpuint        = -ENOMEM,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_channel   = -ENOMEM,
+  .dma_rxdesc    = esp32s2_spi3_dma_rxdesc,
+  .dma_txdesc    = esp32s2_spi3_dma_txdesc,
+  .rx_dma_offset = 0,
+#endif
+  .mode          = SPISLAVE_MODE0,
+  .nbits         = 0,
+  .tx_length     = 0,
+  .tx_buffer     =
+                  {
+                    0
+                  },
+  .rx_length     = 0,
+  .rx_buffer     =
+                  {
+                    0
+                  },
+  .is_processing = false,
+  .is_tx_enabled = false
+};
+#endif /* CONFIG_ESP32S2_SPI3 */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: spislave_peripheral_reset
+ *
+ * Description:
+ *   Reset the SPI Slave peripheral before next transaction.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline void spislave_peripheral_reset(struct spislave_priv_s *priv)
+{
+  setbits(SPI_SOFT_RESET_M, SPI_SLAVE_REG(priv->config->id));
+  resetbits(SPI_SOFT_RESET_M, SPI_SLAVE_REG(priv->config->id));
+}
+
+/****************************************************************************
+ * Name: spislave_cpu_tx_fifo_reset
+ *
+ * Description:
+ *   Reset the BUF TX AFIFO, which is used to send data out in SPI Slave
+ *   CPU-controlled mode transfer.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline void spislave_cpu_tx_fifo_reset(struct spislave_priv_s *priv)
+{
+  setbits(SPI_AHBM_FIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
+  resetbits(SPI_AHBM_FIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
+}
+
+/****************************************************************************
+ * Name: spislave_dma_tx_fifo_reset
+ *
+ * Description:
+ *   Reset the DMA TX AFIFO, which is used to send data out in SPI Slave
+ *   DMA-controlled mode transfer.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_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));
+  resetbits(SPI_DMA_AFIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
+}
+#endif
+
+/****************************************************************************
+ * Name: spislave_dma_rx_fifo_reset
+ *
+ * Description:
+ *   Reset the RX AFIFO, which is used to receive data in SPI Slave mode
+ *   transfer.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_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));
+  resetbits(SPI_RX_AFIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
+}
+#endif
+
+/****************************************************************************
+ * Name: spislave_setmode
+ *
+ * Description:
+ *   Set the SPI Slave mode.
+ *
+ * Input Parameters:
+ *   ctrlr - SPI Slave controller interface instance
+ *   mode  - Requested SPI Slave mode
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void spislave_setmode(struct spi_slave_ctrlr_s *ctrlr,
+                             enum spi_slave_mode_e mode)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
+
+  spiinfo("mode=%d\n", mode);
+
+  /* Has the mode changed? */
+
+  if (mode != priv->mode)
+    {
+      uint32_t ck_idle_edge;
+      uint32_t rsck_i_edge;
+      uint32_t tsck_i_edge;
+      uint32_t clk_mode_13;
+
+      switch (mode)
+        {
+          case SPISLAVE_MODE0: /* CPOL=0; CPHA=0 */
+            ck_idle_edge = 0;
+            rsck_i_edge = 0;
+            tsck_i_edge = 0;
+            clk_mode_13 = 0;
+            break;
+
+          case SPISLAVE_MODE1: /* CPOL=0; CPHA=1 */
+            ck_idle_edge = 0;
+            rsck_i_edge = 1;
+            tsck_i_edge = 1;
+            clk_mode_13 = 1;
+            break;
+
+          case SPISLAVE_MODE2: /* CPOL=1; CPHA=0 */
+            ck_idle_edge = 1;
+            rsck_i_edge = 1;
+            tsck_i_edge = 1;
+            clk_mode_13 = 0;
+            break;
+
+          case SPISLAVE_MODE3: /* CPOL=1; CPHA=1 */
+            ck_idle_edge = 1;
+            rsck_i_edge = 0;
+            tsck_i_edge = 0;
+            clk_mode_13 = 1;
+            break;
+
+          default:
+            spierr("Invalid mode: %d\n", mode);
+            DEBUGPANIC();
+            return;
+        }
+
+      modifyreg32(SPI_MISC_REG(priv->config->id),
+                  SPI_CK_IDLE_EDGE_M,
+                  VALUE_TO_FIELD(ck_idle_edge, SPI_CK_IDLE_EDGE));
+
+      modifyreg32(SPI_USER_REG(priv->config->id),
+                  SPI_RSCK_I_EDGE_M | SPI_TSCK_I_EDGE_M,
+                  VALUE_TO_FIELD(rsck_i_edge, SPI_RSCK_I_EDGE) |
+                  VALUE_TO_FIELD(tsck_i_edge, SPI_TSCK_I_EDGE));
+
+      modifyreg32(SPI_SLAVE_REG(priv->config->id),
+                  SPI_CLK_MODE_13_M | SPI_RSCK_DATA_OUT_M,
+                  VALUE_TO_FIELD(clk_mode_13, SPI_CLK_MODE_13));
+
+      priv->mode = mode;
+    }
+}
+
+/****************************************************************************
+ * Name: spislave_setbits
+ *
+ * Description:
+ *   Set the number of bits per word.
+ *
+ * Input Parameters:
+ *   ctrlr - SPI Slave controller interface instance
+ *   nbits - The number of bits in an SPI word
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void spislave_setbits(struct spi_slave_ctrlr_s *ctrlr, int nbits)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
+
+  spiinfo("nbits=%d\n", nbits);
+
+  priv->nbits = nbits;
+}
+
+/****************************************************************************
+ * Name: spislave_cs_interrupt
+ *
+ * Description:
+ *   Handler for the GPIO interrupt which is triggered when the chip select
+ *   has toggled to inactive state (active high).
+ *
+ * Input Parameters:
+ *   irq     - Number of the IRQ that generated the interrupt
+ *   context - Interrupt register state save info
+ *   arg     - SPI Slave controller private data
+ *
+ * Returned Value:
+ *   Standard interrupt return value.
+ *
+ ****************************************************************************/
+
+static int spislave_cs_interrupt(int irq, void *context, void *arg)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)arg;
+
+  if (priv->is_processing)
+    {
+      priv->is_processing = false;
+      SPIS_DEV_SELECT(priv->dev, false);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: spislave_store_result
+ *
+ * Description:
+ *   Fetch data from the SPI hardware data buffer and record the length.
+ *   This is a post transaction operation.
+ *
+ * Input Parameters:
+ *   priv       - Private SPI Slave controller structure
+ *   recv_bytes - Number of received bytes
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void spislave_store_result(struct spislave_priv_s *priv,
+                                  uint32_t recv_bytes)
+{
+  uint32_t remaining_space = SPI_SLAVE_BUFSIZE - priv->rx_length;
+  uint32_t bytes_to_copy = recv_bytes;
+
+  if (bytes_to_copy > remaining_space)
+    {
+      spiwarn("RX buffer full! Discarded %" PRIu32 " received bytes\n",
+              bytes_to_copy - remaining_space);
+
+      bytes_to_copy = remaining_space;
+    }
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  if (bytes_to_copy)
+    {
+      if ((priv->rx_dma_offset != priv->rx_length))
+        {
+          memmove(priv->rx_buffer + priv->rx_length,
+                  priv->rx_buffer + priv->rx_dma_offset,
+                  bytes_to_copy);
+
+          priv->rx_dma_offset = priv->rx_length;
+        }
+
+      priv->rx_length += bytes_to_copy;
+    }
+#else
+  /* If DMA is not enabled, software should copy incoming data from data
+   * buffer registers to receive buffer.
+   */
+
+  if (bytes_to_copy)
+    {
+      /* Set data_buf_reg with the address of the first data buffer
+       * register (W0).
+       */
+
+      uintptr_t data_buf_reg = SPI_W0_REG(priv->config->id);
+
+      /* Read received data words from SPI hardware data buffer. */
+
+      for (int i = 0; i < bytes_to_copy; i += sizeof(uint32_t))
+        {
+          uint32_t rbytes = MIN(bytes_to_copy - i, sizeof(uintptr_t));

Review Comment:
   maybe better to use `uint32_t` here, the same as in `i += sizeof(uint32_t)`?



##########
arch/xtensa/src/esp32s2/esp32s2_spi_slave.c:
##########
@@ -0,0 +1,1734 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_spi_slave.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>
+
+#if defined(CONFIG_ESP32S2_SPI) && defined(CONFIG_SPI_SLAVE)
+
+#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 <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/spi/spi.h>
+#include <nuttx/spi/slave.h>
+
+#include <arch/board/board.h>
+
+#include "esp32s2_spi.h"
+#include "esp32s2_irq.h"
+#include "esp32s2_gpio.h"
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+#include "esp32s2_dma.h"
+#endif
+
+#include "xtensa.h"
+#include "hardware/esp32s2_gpio_sigmap.h"
+#include "hardware/esp32s2_pinmap.h"
+#include "hardware/esp32s2_spi.h"
+#include "hardware/esp32s2_soc.h"
+#include "hardware/esp32s2_system.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#define SPI_SLAVE_BUFSIZE (CONFIG_ESP32S2_SPI_SLAVE_BUFSIZE)
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+/* SPI DMA RX/TX number of descriptors */
+
+#  if (SPI_SLAVE_BUFSIZE % ESP32S2_DMA_BUFLEN_MAX) > 0
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_DMA_BUFLEN_MAX + 1)
+#  else
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_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_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_ESP32S2_SPI_DMA */
+
+/* Verify whether SPI has been assigned IOMUX pins.
+ * Otherwise, SPI signals will be routed via GPIO Matrix.
+ */
+
+#ifdef CONFIG_ESP32S2_SPI2
+#  define SPI_IS_CS_IOMUX   (CONFIG_ESP32S2_SPI2_CSPIN == SPI2_IOMUX_CSPIN)
+#  define SPI_IS_CLK_IOMUX  (CONFIG_ESP32S2_SPI2_CLKPIN == SPI2_IOMUX_CLKPIN)
+#  define SPI_IS_MOSI_IOMUX (CONFIG_ESP32S2_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN)
+#  define SPI_IS_MISO_IOMUX (CONFIG_ESP32S2_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))
+#else
+#  define SPI_VIA_IOMUX     0
+#endif
+
+/* SPI Slave interrupt mask */
+
+#define SPI_INT_MASK      (SPI_IN_DONE_INT_ENA_M |      \
+                           SPI_OUT_DONE_INT_ENA_M |     \
+                           SPI_SLV_WR_DMA_DONE_M | \
+                           SPI_SLV_RD_DMA_DONE_M | \
+                           SPI_SLV_WR_BUF_DONE_M | \
+                           SPI_SLV_RD_BUF_DONE_M)
+
+/* SPI Slave default width */
+
+#define SPI_SLAVE_DEFAULT_WIDTH (8)
+
+/* SPI Slave default mode */
+
+#define SPI_SLAVE_DEFAULT_MODE  (SPISLAVE_MODE0)
+
+/* SPI Slave maximum buffer size in bytes */
+
+#define SPI_SLAVE_HW_BUF_SIZE   (64)
+
+#define WORDS2BYTES(_priv, _wn)   ((_wn) * ((_priv)->nbits / 8))
+#define BYTES2WORDS(_priv, _bn)   ((_bn) / ((_priv)->nbits / 8))
+
+#define setbits(bs, a)     modifyreg32(a, 0, bs)
+#define resetbits(bs, a)   modifyreg32(a, bs, 0)
+
+/* SPI Slave controller hardware configuration */
+
+struct spislave_config_s
+{
+  int32_t width;              /* SPI Slave default width */
+  enum spi_slave_mode_e mode; /* SPI Slave default mode */
+
+  uint8_t id;                 /* SPI 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 periph;             /* Peripheral ID */
+  uint8_t irq;                /* Interrupt ID */
+  uint32_t clk_bit;           /* Clock enable bit */
+  uint32_t rst_bit;           /* SPI reset bit */
+#ifdef CONFIG_ESP32S2_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 */
+#endif
+  uint32_t cs_insig;          /* SPI CS input signal index */
+  uint32_t cs_outsig;         /* SPI CS output signal index */
+  uint32_t mosi_insig;        /* SPI MOSI input signal index */
+  uint32_t mosi_outsig;       /* SPI MOSI output signal index */
+  uint32_t miso_insig;        /* SPI MISO input signal index */
+  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 */
+};
+
+struct spislave_priv_s
+{
+  /* Externally visible part of the SPI Slave controller interface */
+
+  struct spi_slave_ctrlr_s ctrlr;
+
+  /* Reference to SPI Slave device interface */
+
+  struct spi_slave_dev_s *dev;
+
+  /* Port configuration */
+
+  const struct spislave_config_s *config;
+  int refs;                   /* Reference count */
+  int cpu;                    /* CPU ID */
+  int cpuint;                 /* SPI interrupt ID */
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  int32_t dma_channel;        /* Channel assigned by the GDMA driver */
+
+  /* DMA RX/TX description */
+
+  struct esp32s2_dmadesc_s *dma_rxdesc;
+  struct esp32s2_dmadesc_s *dma_txdesc;
+
+  uint32_t rx_dma_offset;     /* Offset of DMA RX buffer */
+#endif
+  enum spi_slave_mode_e mode; /* Current SPI Slave hardware mode */
+  uint8_t nbits;              /* Current configured bit width */
+  uint32_t tx_length;         /* Location of next TX value */
+
+  /* SPI Slave TX queue buffer */
+
+  uint8_t tx_buffer[SPI_SLAVE_BUFSIZE];
+  uint32_t rx_length;         /* Location of next RX value */
+
+  /* SPI Slave RX queue buffer */
+
+  uint8_t rx_buffer[SPI_SLAVE_BUFSIZE];
+
+  /* Flag that indicates whether SPI Slave is currently processing */
+
+  bool is_processing;
+
+  /* Flag that indicates whether SPI Slave TX is currently enabled */
+
+  bool is_tx_enabled;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* SPI Slave controller interrupt handlers */
+
+static int spislave_cs_interrupt(int irq, void *context, void *arg);
+static int spislave_periph_interrupt(int irq, void *context, void *arg);
+
+/* SPI Slave controller internal functions */
+
+static void spislave_setmode(struct spi_slave_ctrlr_s *ctrlr,
+                             enum spi_slave_mode_e mode);
+static void spislave_setbits(struct spi_slave_ctrlr_s *ctrlr, int nbits);
+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 CONFIG_ESP32S2_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);
+static void spislave_prepare_next_tx(struct spislave_priv_s *priv);
+#else
+static void spislave_write_tx_buffer(struct spislave_priv_s *priv);
+#endif
+static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_deinitialize(struct spi_slave_ctrlr_s *ctrlr);
+
+/* SPI Slave controller operations */
+
+static void spislave_bind(struct spi_slave_ctrlr_s *ctrlr,
+                          struct spi_slave_dev_s *dev,
+                          enum spi_slave_mode_e mode,
+                          int nbits);
+static void spislave_unbind(struct spi_slave_ctrlr_s *ctrlr);
+static int spislave_enqueue(struct spi_slave_ctrlr_s *ctrlr,
+                            const void *data,
+                            size_t nwords);
+static bool spislave_qfull(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_qflush(struct spi_slave_ctrlr_s *ctrlr);
+static size_t spislave_qpoll(struct spi_slave_ctrlr_s *ctrlr);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/*  SPI2 private data */
+
+#ifdef CONFIG_ESP32S2_SPI2
+static const struct spislave_config_s esp32s2_spi2slave_config =
+{
+  .width        = SPI_SLAVE_DEFAULT_WIDTH,
+  .mode         = SPI_SLAVE_DEFAULT_MODE,
+  .id           = 2,
+  .cs_pin       = CONFIG_ESP32S2_SPI2_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S2_SPI2_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S2_SPI2_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S2_SPI2_CLKPIN,
+  .periph       = ESP32S2_PERIPH_SPI2,
+  .irq          = ESP32S2_IRQ_SPI2,
+  .clk_bit      = SYSTEM_SPI2_CLK_EN,
+  .rst_bit      = SYSTEM_SPI2_RST,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_clk_bit  = SYSTEM_SPI2_DMA_CLK_EN,
+  .dma_rst_bit  = SYSTEM_SPI2_DMA_RST,
+  .dma_periph   = ESP32S2_DMA_PERIPH_SPI2,
+#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,
+};
+
+static const struct spi_slave_ctrlrops_s esp32s2_spi2slave_ops =
+{
+  .bind     = spislave_bind,
+  .unbind   = spislave_unbind,
+  .enqueue  = spislave_enqueue,
+  .qfull    = spislave_qfull,
+  .qflush   = spislave_qflush,
+  .qpoll    = spislave_qpoll
+};
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+
+/* SPI DMA RX/TX description buffer */
+
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_rxdesc[SPI_DMA_DESC_NUM];
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_txdesc[SPI_DMA_DESC_NUM];
+#endif
+
+static struct spislave_priv_s esp32s2_spi2slave_priv =
+{
+  .ctrlr         =
+                  {
+                    .ops = &esp32s2_spi2slave_ops
+                  },
+  .dev           = NULL,
+  .config        = &esp32s2_spi2slave_config,
+  .refs          = 0,
+  .cpu           = -1,
+  .cpuint        = -ENOMEM,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_channel   = -ENOMEM,
+  .dma_rxdesc    = esp32s2_spi2_dma_rxdesc,
+  .dma_txdesc    = esp32s2_spi2_dma_txdesc,
+  .rx_dma_offset = 0,
+#endif
+  .mode          = SPISLAVE_MODE0,
+  .nbits         = 0,
+  .tx_length     = 0,
+  .tx_buffer     =
+                  {
+                    0
+                  },
+  .rx_length     = 0,
+  .rx_buffer     =
+                  {
+                    0
+                  },
+  .is_processing = false,
+  .is_tx_enabled = false
+};
+#endif /* CONFIG_ESP32S2_SPI2 */
+
+#ifdef CONFIG_ESP32S2_SPI3
+static const struct spislave_config_s esp32s2_spi3slave_config =
+{
+  .width        = SPI_SLAVE_DEFAULT_WIDTH,
+  .mode         = SPI_SLAVE_DEFAULT_MODE,
+  .id           = 3,
+  .cs_pin       = CONFIG_ESP32S2_SPI3_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S2_SPI3_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S2_SPI3_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S2_SPI3_CLKPIN,
+  .periph       = ESP32S2_PERIPH_SPI3,
+  .irq          = ESP32S2_IRQ_SPI3,
+  .clk_bit      = SYSTEM_SPI3_CLK_EN,
+  .rst_bit      = SYSTEM_SPI3_RST,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_clk_bit  = SYSTEM_SPI3_DMA_CLK_EN,
+  .dma_rst_bit  = SYSTEM_SPI3_DMA_RST,
+  .dma_periph   = ESP32S2_DMA_PERIPH_SPI3,
+#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_MUX_IDX,
+};
+
+static const struct spi_slave_ctrlrops_s esp32s2_spi3slave_ops =
+{
+  .bind     = spislave_bind,
+  .unbind   = spislave_unbind,
+  .enqueue  = spislave_enqueue,
+  .qfull    = spislave_qfull,
+  .qflush   = spislave_qflush,
+  .qpoll    = spislave_qpoll
+};
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+
+/* SPI DMA RX/TX description buffer */
+
+static struct esp32s2_dmadesc_s esp32s2_spi3_dma_rxdesc[SPI_DMA_DESC_NUM];
+static struct esp32s2_dmadesc_s esp32s2_spi3_dma_txdesc[SPI_DMA_DESC_NUM];
+#endif
+
+static struct spislave_priv_s esp32s2_spi3slave_priv =
+{
+  .ctrlr         =
+                  {
+                    .ops = &esp32s2_spi3slave_ops
+                  },
+  .dev           = NULL,
+  .config        = &esp32s2_spi3slave_config,
+  .refs          = 0,
+  .cpu           = -1,
+  .cpuint        = -ENOMEM,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_channel   = -ENOMEM,
+  .dma_rxdesc    = esp32s2_spi3_dma_rxdesc,
+  .dma_txdesc    = esp32s2_spi3_dma_txdesc,
+  .rx_dma_offset = 0,
+#endif
+  .mode          = SPISLAVE_MODE0,
+  .nbits         = 0,
+  .tx_length     = 0,
+  .tx_buffer     =
+                  {
+                    0
+                  },
+  .rx_length     = 0,
+  .rx_buffer     =
+                  {
+                    0
+                  },
+  .is_processing = false,
+  .is_tx_enabled = false
+};
+#endif /* CONFIG_ESP32S2_SPI3 */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: spislave_peripheral_reset
+ *
+ * Description:
+ *   Reset the SPI Slave peripheral before next transaction.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline void spislave_peripheral_reset(struct spislave_priv_s *priv)
+{
+  setbits(SPI_SOFT_RESET_M, SPI_SLAVE_REG(priv->config->id));
+  resetbits(SPI_SOFT_RESET_M, SPI_SLAVE_REG(priv->config->id));
+}
+
+/****************************************************************************
+ * Name: spislave_cpu_tx_fifo_reset
+ *
+ * Description:
+ *   Reset the BUF TX AFIFO, which is used to send data out in SPI Slave
+ *   CPU-controlled mode transfer.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline void spislave_cpu_tx_fifo_reset(struct spislave_priv_s *priv)
+{
+  setbits(SPI_AHBM_FIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
+  resetbits(SPI_AHBM_FIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
+}
+
+/****************************************************************************
+ * Name: spislave_dma_tx_fifo_reset
+ *
+ * Description:
+ *   Reset the DMA TX AFIFO, which is used to send data out in SPI Slave
+ *   DMA-controlled mode transfer.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_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));
+  resetbits(SPI_DMA_AFIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
+}
+#endif
+
+/****************************************************************************
+ * Name: spislave_dma_rx_fifo_reset
+ *
+ * Description:
+ *   Reset the RX AFIFO, which is used to receive data in SPI Slave mode
+ *   transfer.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_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));
+  resetbits(SPI_RX_AFIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
+}
+#endif
+
+/****************************************************************************
+ * Name: spislave_setmode
+ *
+ * Description:
+ *   Set the SPI Slave mode.
+ *
+ * Input Parameters:
+ *   ctrlr - SPI Slave controller interface instance
+ *   mode  - Requested SPI Slave mode
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void spislave_setmode(struct spi_slave_ctrlr_s *ctrlr,
+                             enum spi_slave_mode_e mode)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
+
+  spiinfo("mode=%d\n", mode);
+
+  /* Has the mode changed? */
+
+  if (mode != priv->mode)
+    {
+      uint32_t ck_idle_edge;
+      uint32_t rsck_i_edge;
+      uint32_t tsck_i_edge;
+      uint32_t clk_mode_13;
+
+      switch (mode)
+        {
+          case SPISLAVE_MODE0: /* CPOL=0; CPHA=0 */
+            ck_idle_edge = 0;
+            rsck_i_edge = 0;
+            tsck_i_edge = 0;
+            clk_mode_13 = 0;
+            break;
+
+          case SPISLAVE_MODE1: /* CPOL=0; CPHA=1 */
+            ck_idle_edge = 0;
+            rsck_i_edge = 1;
+            tsck_i_edge = 1;
+            clk_mode_13 = 1;
+            break;
+
+          case SPISLAVE_MODE2: /* CPOL=1; CPHA=0 */
+            ck_idle_edge = 1;
+            rsck_i_edge = 1;
+            tsck_i_edge = 1;
+            clk_mode_13 = 0;
+            break;
+
+          case SPISLAVE_MODE3: /* CPOL=1; CPHA=1 */
+            ck_idle_edge = 1;
+            rsck_i_edge = 0;
+            tsck_i_edge = 0;
+            clk_mode_13 = 1;
+            break;
+
+          default:
+            spierr("Invalid mode: %d\n", mode);
+            DEBUGPANIC();
+            return;
+        }
+
+      modifyreg32(SPI_MISC_REG(priv->config->id),
+                  SPI_CK_IDLE_EDGE_M,
+                  VALUE_TO_FIELD(ck_idle_edge, SPI_CK_IDLE_EDGE));
+
+      modifyreg32(SPI_USER_REG(priv->config->id),
+                  SPI_RSCK_I_EDGE_M | SPI_TSCK_I_EDGE_M,
+                  VALUE_TO_FIELD(rsck_i_edge, SPI_RSCK_I_EDGE) |
+                  VALUE_TO_FIELD(tsck_i_edge, SPI_TSCK_I_EDGE));
+
+      modifyreg32(SPI_SLAVE_REG(priv->config->id),
+                  SPI_CLK_MODE_13_M | SPI_RSCK_DATA_OUT_M,
+                  VALUE_TO_FIELD(clk_mode_13, SPI_CLK_MODE_13));
+
+      priv->mode = mode;
+    }
+}
+
+/****************************************************************************
+ * Name: spislave_setbits
+ *
+ * Description:
+ *   Set the number of bits per word.
+ *
+ * Input Parameters:
+ *   ctrlr - SPI Slave controller interface instance
+ *   nbits - The number of bits in an SPI word
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void spislave_setbits(struct spi_slave_ctrlr_s *ctrlr, int nbits)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
+
+  spiinfo("nbits=%d\n", nbits);
+
+  priv->nbits = nbits;
+}
+
+/****************************************************************************
+ * Name: spislave_cs_interrupt
+ *
+ * Description:
+ *   Handler for the GPIO interrupt which is triggered when the chip select
+ *   has toggled to inactive state (active high).
+ *
+ * Input Parameters:
+ *   irq     - Number of the IRQ that generated the interrupt
+ *   context - Interrupt register state save info
+ *   arg     - SPI Slave controller private data
+ *
+ * Returned Value:
+ *   Standard interrupt return value.
+ *
+ ****************************************************************************/
+
+static int spislave_cs_interrupt(int irq, void *context, void *arg)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)arg;
+
+  if (priv->is_processing)
+    {
+      priv->is_processing = false;
+      SPIS_DEV_SELECT(priv->dev, false);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: spislave_store_result
+ *
+ * Description:
+ *   Fetch data from the SPI hardware data buffer and record the length.
+ *   This is a post transaction operation.
+ *
+ * Input Parameters:
+ *   priv       - Private SPI Slave controller structure
+ *   recv_bytes - Number of received bytes
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void spislave_store_result(struct spislave_priv_s *priv,
+                                  uint32_t recv_bytes)
+{
+  uint32_t remaining_space = SPI_SLAVE_BUFSIZE - priv->rx_length;
+  uint32_t bytes_to_copy = recv_bytes;
+
+  if (bytes_to_copy > remaining_space)
+    {
+      spiwarn("RX buffer full! Discarded %" PRIu32 " received bytes\n",
+              bytes_to_copy - remaining_space);
+
+      bytes_to_copy = remaining_space;
+    }
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  if (bytes_to_copy)
+    {
+      if ((priv->rx_dma_offset != priv->rx_length))
+        {
+          memmove(priv->rx_buffer + priv->rx_length,
+                  priv->rx_buffer + priv->rx_dma_offset,
+                  bytes_to_copy);
+
+          priv->rx_dma_offset = priv->rx_length;
+        }
+
+      priv->rx_length += bytes_to_copy;
+    }
+#else
+  /* If DMA is not enabled, software should copy incoming data from data
+   * buffer registers to receive buffer.
+   */
+
+  if (bytes_to_copy)
+    {
+      /* Set data_buf_reg with the address of the first data buffer
+       * register (W0).
+       */
+
+      uintptr_t data_buf_reg = SPI_W0_REG(priv->config->id);
+
+      /* Read received data words from SPI hardware data buffer. */
+
+      for (int i = 0; i < bytes_to_copy; i += sizeof(uint32_t))
+        {
+          uint32_t rbytes = MIN(bytes_to_copy - i, sizeof(uintptr_t));
+          uint32_t r_wd = getreg32(data_buf_reg);
+
+          memcpy(priv->rx_buffer + priv->rx_length + i, &r_wd, rbytes);
+
+          /* Update data_buf_reg to point to the next data buffer register. */
+
+          data_buf_reg += sizeof(uintptr_t);
+        }
+
+      priv->rx_length += bytes_to_copy;
+    }
+#endif
+}
+
+/****************************************************************************
+ * Name: spislave_prepare_next_rx
+ *
+ * Description:
+ *   Prepare the SPI Slave controller for receiving data on the next
+ *   transaction.
+ *
+ * Input Parameters:
+ *   priv   - Private SPI Slave controller structure
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+static void spislave_prepare_next_rx(struct spislave_priv_s *priv)
+{
+  if (priv->rx_length < SPI_SLAVE_BUFSIZE)
+    {
+      spislave_setup_rx_dma(priv);
+    }
+}
+#endif
+
+/****************************************************************************
+ * Name: spislave_evict_sent_data
+ *
+ * Description:
+ *   Evict from the TX buffer data sent on the latest transaction and update
+ *   the length. This is a post transaction operation.
+ *
+ * Input Parameters:
+ *   priv       - Private SPI Slave controller structure
+ *   sent_bytes - Number of transmitted bytes
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void spislave_evict_sent_data(struct spislave_priv_s *priv,
+                                     uint32_t sent_bytes)
+{
+  if (sent_bytes < priv->tx_length)
+    {
+      priv->tx_length -= sent_bytes;
+
+      memmove(priv->tx_buffer, priv->tx_buffer + sent_bytes,
+              priv->tx_length);
+
+      memset(priv->tx_buffer + priv->tx_length, 0, sent_bytes);
+    }
+  else
+    {
+      priv->tx_length = 0;
+    }
+}
+
+/****************************************************************************
+ * Name: spislave_write_tx_buffer
+ *
+ * Description:
+ *   Write to SPI Slave peripheral hardware data buffer.
+ *
+ * Input Parameters:
+ *   priv   - Private SPI Slave controller structure
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_ESP32S2_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
+   * register (W0).
+   */
+
+  uintptr_t data_buf_reg = SPI_W0_REG(priv->config->id);
+
+  uint32_t transfer_size = MIN(SPI_SLAVE_HW_BUF_SIZE, priv->tx_length);
+
+  /* Write data words to hardware data buffer.
+   * SPI peripheral contains 16 registers (W0 - W15).
+   */
+
+  for (int i = 0; i < transfer_size; i += sizeof(uint32_t))
+    {
+      uint32_t w_wd = UINT32_MAX;
+
+      memcpy(&w_wd, priv->tx_buffer + i, sizeof(uint32_t));
+
+      putreg32(w_wd, data_buf_reg);
+
+      /* Update data_buf_reg to point to the next data buffer register. */
+
+      data_buf_reg += sizeof(uintptr_t);

Review Comment:
   maybe better to use `uint32_t` here, the same as in `i += sizeof(uint32_t)`?



##########
arch/xtensa/src/esp32s2/esp32s2_spi_slave.c:
##########
@@ -0,0 +1,1734 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_spi_slave.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>
+
+#if defined(CONFIG_ESP32S2_SPI) && defined(CONFIG_SPI_SLAVE)
+
+#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 <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/spi/spi.h>
+#include <nuttx/spi/slave.h>
+
+#include <arch/board/board.h>
+
+#include "esp32s2_spi.h"
+#include "esp32s2_irq.h"
+#include "esp32s2_gpio.h"
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+#include "esp32s2_dma.h"
+#endif
+
+#include "xtensa.h"
+#include "hardware/esp32s2_gpio_sigmap.h"
+#include "hardware/esp32s2_pinmap.h"
+#include "hardware/esp32s2_spi.h"
+#include "hardware/esp32s2_soc.h"
+#include "hardware/esp32s2_system.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#define SPI_SLAVE_BUFSIZE (CONFIG_ESP32S2_SPI_SLAVE_BUFSIZE)
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+/* SPI DMA RX/TX number of descriptors */
+
+#  if (SPI_SLAVE_BUFSIZE % ESP32S2_DMA_BUFLEN_MAX) > 0
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_DMA_BUFLEN_MAX + 1)
+#  else
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_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_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_ESP32S2_SPI_DMA */
+
+/* Verify whether SPI has been assigned IOMUX pins.
+ * Otherwise, SPI signals will be routed via GPIO Matrix.
+ */
+
+#ifdef CONFIG_ESP32S2_SPI2
+#  define SPI_IS_CS_IOMUX   (CONFIG_ESP32S2_SPI2_CSPIN == SPI2_IOMUX_CSPIN)
+#  define SPI_IS_CLK_IOMUX  (CONFIG_ESP32S2_SPI2_CLKPIN == SPI2_IOMUX_CLKPIN)
+#  define SPI_IS_MOSI_IOMUX (CONFIG_ESP32S2_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN)
+#  define SPI_IS_MISO_IOMUX (CONFIG_ESP32S2_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))
+#else
+#  define SPI_VIA_IOMUX     0
+#endif
+
+/* SPI Slave interrupt mask */
+
+#define SPI_INT_MASK      (SPI_IN_DONE_INT_ENA_M |      \
+                           SPI_OUT_DONE_INT_ENA_M |     \
+                           SPI_SLV_WR_DMA_DONE_M | \
+                           SPI_SLV_RD_DMA_DONE_M | \
+                           SPI_SLV_WR_BUF_DONE_M | \
+                           SPI_SLV_RD_BUF_DONE_M)
+
+/* SPI Slave default width */
+
+#define SPI_SLAVE_DEFAULT_WIDTH (8)
+
+/* SPI Slave default mode */
+
+#define SPI_SLAVE_DEFAULT_MODE  (SPISLAVE_MODE0)
+
+/* SPI Slave maximum buffer size in bytes */
+
+#define SPI_SLAVE_HW_BUF_SIZE   (64)
+
+#define WORDS2BYTES(_priv, _wn)   ((_wn) * ((_priv)->nbits / 8))
+#define BYTES2WORDS(_priv, _bn)   ((_bn) / ((_priv)->nbits / 8))
+
+#define setbits(bs, a)     modifyreg32(a, 0, bs)
+#define resetbits(bs, a)   modifyreg32(a, bs, 0)
+
+/* SPI Slave controller hardware configuration */
+
+struct spislave_config_s
+{
+  int32_t width;              /* SPI Slave default width */
+  enum spi_slave_mode_e mode; /* SPI Slave default mode */
+
+  uint8_t id;                 /* SPI 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 periph;             /* Peripheral ID */
+  uint8_t irq;                /* Interrupt ID */
+  uint32_t clk_bit;           /* Clock enable bit */
+  uint32_t rst_bit;           /* SPI reset bit */
+#ifdef CONFIG_ESP32S2_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 */
+#endif
+  uint32_t cs_insig;          /* SPI CS input signal index */
+  uint32_t cs_outsig;         /* SPI CS output signal index */
+  uint32_t mosi_insig;        /* SPI MOSI input signal index */
+  uint32_t mosi_outsig;       /* SPI MOSI output signal index */
+  uint32_t miso_insig;        /* SPI MISO input signal index */
+  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 */
+};
+
+struct spislave_priv_s
+{
+  /* Externally visible part of the SPI Slave controller interface */
+
+  struct spi_slave_ctrlr_s ctrlr;
+
+  /* Reference to SPI Slave device interface */
+
+  struct spi_slave_dev_s *dev;
+
+  /* Port configuration */
+
+  const struct spislave_config_s *config;
+  int refs;                   /* Reference count */
+  int cpu;                    /* CPU ID */
+  int cpuint;                 /* SPI interrupt ID */
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  int32_t dma_channel;        /* Channel assigned by the GDMA driver */
+
+  /* DMA RX/TX description */
+
+  struct esp32s2_dmadesc_s *dma_rxdesc;
+  struct esp32s2_dmadesc_s *dma_txdesc;
+
+  uint32_t rx_dma_offset;     /* Offset of DMA RX buffer */
+#endif
+  enum spi_slave_mode_e mode; /* Current SPI Slave hardware mode */
+  uint8_t nbits;              /* Current configured bit width */
+  uint32_t tx_length;         /* Location of next TX value */
+
+  /* SPI Slave TX queue buffer */
+
+  uint8_t tx_buffer[SPI_SLAVE_BUFSIZE];
+  uint32_t rx_length;         /* Location of next RX value */
+
+  /* SPI Slave RX queue buffer */
+
+  uint8_t rx_buffer[SPI_SLAVE_BUFSIZE];
+
+  /* Flag that indicates whether SPI Slave is currently processing */
+
+  bool is_processing;
+
+  /* Flag that indicates whether SPI Slave TX is currently enabled */
+
+  bool is_tx_enabled;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* SPI Slave controller interrupt handlers */
+
+static int spislave_cs_interrupt(int irq, void *context, void *arg);
+static int spislave_periph_interrupt(int irq, void *context, void *arg);
+
+/* SPI Slave controller internal functions */
+
+static void spislave_setmode(struct spi_slave_ctrlr_s *ctrlr,
+                             enum spi_slave_mode_e mode);
+static void spislave_setbits(struct spi_slave_ctrlr_s *ctrlr, int nbits);
+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 CONFIG_ESP32S2_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);
+static void spislave_prepare_next_tx(struct spislave_priv_s *priv);
+#else
+static void spislave_write_tx_buffer(struct spislave_priv_s *priv);
+#endif
+static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_deinitialize(struct spi_slave_ctrlr_s *ctrlr);
+
+/* SPI Slave controller operations */
+
+static void spislave_bind(struct spi_slave_ctrlr_s *ctrlr,
+                          struct spi_slave_dev_s *dev,
+                          enum spi_slave_mode_e mode,
+                          int nbits);
+static void spislave_unbind(struct spi_slave_ctrlr_s *ctrlr);
+static int spislave_enqueue(struct spi_slave_ctrlr_s *ctrlr,
+                            const void *data,
+                            size_t nwords);
+static bool spislave_qfull(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_qflush(struct spi_slave_ctrlr_s *ctrlr);
+static size_t spislave_qpoll(struct spi_slave_ctrlr_s *ctrlr);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/*  SPI2 private data */
+
+#ifdef CONFIG_ESP32S2_SPI2
+static const struct spislave_config_s esp32s2_spi2slave_config =
+{
+  .width        = SPI_SLAVE_DEFAULT_WIDTH,
+  .mode         = SPI_SLAVE_DEFAULT_MODE,
+  .id           = 2,
+  .cs_pin       = CONFIG_ESP32S2_SPI2_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S2_SPI2_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S2_SPI2_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S2_SPI2_CLKPIN,
+  .periph       = ESP32S2_PERIPH_SPI2,
+  .irq          = ESP32S2_IRQ_SPI2,
+  .clk_bit      = SYSTEM_SPI2_CLK_EN,
+  .rst_bit      = SYSTEM_SPI2_RST,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_clk_bit  = SYSTEM_SPI2_DMA_CLK_EN,
+  .dma_rst_bit  = SYSTEM_SPI2_DMA_RST,
+  .dma_periph   = ESP32S2_DMA_PERIPH_SPI2,
+#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,
+};
+
+static const struct spi_slave_ctrlrops_s esp32s2_spi2slave_ops =
+{
+  .bind     = spislave_bind,
+  .unbind   = spislave_unbind,
+  .enqueue  = spislave_enqueue,
+  .qfull    = spislave_qfull,
+  .qflush   = spislave_qflush,
+  .qpoll    = spislave_qpoll
+};
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+
+/* SPI DMA RX/TX description buffer */
+
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_rxdesc[SPI_DMA_DESC_NUM];
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_txdesc[SPI_DMA_DESC_NUM];
+#endif
+
+static struct spislave_priv_s esp32s2_spi2slave_priv =
+{
+  .ctrlr         =
+                  {
+                    .ops = &esp32s2_spi2slave_ops
+                  },
+  .dev           = NULL,
+  .config        = &esp32s2_spi2slave_config,
+  .refs          = 0,
+  .cpu           = -1,
+  .cpuint        = -ENOMEM,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_channel   = -ENOMEM,
+  .dma_rxdesc    = esp32s2_spi2_dma_rxdesc,
+  .dma_txdesc    = esp32s2_spi2_dma_txdesc,
+  .rx_dma_offset = 0,
+#endif
+  .mode          = SPISLAVE_MODE0,
+  .nbits         = 0,
+  .tx_length     = 0,
+  .tx_buffer     =
+                  {
+                    0
+                  },

Review Comment:
   actually zero init to fields is not needed as those will be zero inialized 
at boot



##########
arch/xtensa/src/esp32s2/esp32s2_spi_slave.c:
##########
@@ -0,0 +1,1734 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_spi_slave.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>
+
+#if defined(CONFIG_ESP32S2_SPI) && defined(CONFIG_SPI_SLAVE)
+
+#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 <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/spi/spi.h>
+#include <nuttx/spi/slave.h>
+
+#include <arch/board/board.h>
+
+#include "esp32s2_spi.h"
+#include "esp32s2_irq.h"
+#include "esp32s2_gpio.h"
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+#include "esp32s2_dma.h"
+#endif
+
+#include "xtensa.h"
+#include "hardware/esp32s2_gpio_sigmap.h"
+#include "hardware/esp32s2_pinmap.h"
+#include "hardware/esp32s2_spi.h"
+#include "hardware/esp32s2_soc.h"
+#include "hardware/esp32s2_system.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#define SPI_SLAVE_BUFSIZE (CONFIG_ESP32S2_SPI_SLAVE_BUFSIZE)
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+/* SPI DMA RX/TX number of descriptors */
+
+#  if (SPI_SLAVE_BUFSIZE % ESP32S2_DMA_BUFLEN_MAX) > 0
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_DMA_BUFLEN_MAX + 1)
+#  else
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_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_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_ESP32S2_SPI_DMA */
+
+/* Verify whether SPI has been assigned IOMUX pins.
+ * Otherwise, SPI signals will be routed via GPIO Matrix.
+ */
+
+#ifdef CONFIG_ESP32S2_SPI2
+#  define SPI_IS_CS_IOMUX   (CONFIG_ESP32S2_SPI2_CSPIN == SPI2_IOMUX_CSPIN)
+#  define SPI_IS_CLK_IOMUX  (CONFIG_ESP32S2_SPI2_CLKPIN == SPI2_IOMUX_CLKPIN)
+#  define SPI_IS_MOSI_IOMUX (CONFIG_ESP32S2_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN)
+#  define SPI_IS_MISO_IOMUX (CONFIG_ESP32S2_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))
+#else
+#  define SPI_VIA_IOMUX     0
+#endif
+
+/* SPI Slave interrupt mask */
+
+#define SPI_INT_MASK      (SPI_IN_DONE_INT_ENA_M |      \
+                           SPI_OUT_DONE_INT_ENA_M |     \
+                           SPI_SLV_WR_DMA_DONE_M | \
+                           SPI_SLV_RD_DMA_DONE_M | \
+                           SPI_SLV_WR_BUF_DONE_M | \
+                           SPI_SLV_RD_BUF_DONE_M)
+
+/* SPI Slave default width */
+
+#define SPI_SLAVE_DEFAULT_WIDTH (8)
+
+/* SPI Slave default mode */
+
+#define SPI_SLAVE_DEFAULT_MODE  (SPISLAVE_MODE0)
+
+/* SPI Slave maximum buffer size in bytes */
+
+#define SPI_SLAVE_HW_BUF_SIZE   (64)
+
+#define WORDS2BYTES(_priv, _wn)   ((_wn) * ((_priv)->nbits / 8))
+#define BYTES2WORDS(_priv, _bn)   ((_bn) / ((_priv)->nbits / 8))
+
+#define setbits(bs, a)     modifyreg32(a, 0, bs)
+#define resetbits(bs, a)   modifyreg32(a, bs, 0)
+
+/* SPI Slave controller hardware configuration */
+
+struct spislave_config_s
+{
+  int32_t width;              /* SPI Slave default width */
+  enum spi_slave_mode_e mode; /* SPI Slave default mode */
+
+  uint8_t id;                 /* SPI 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 periph;             /* Peripheral ID */
+  uint8_t irq;                /* Interrupt ID */
+  uint32_t clk_bit;           /* Clock enable bit */
+  uint32_t rst_bit;           /* SPI reset bit */
+#ifdef CONFIG_ESP32S2_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 */
+#endif
+  uint32_t cs_insig;          /* SPI CS input signal index */
+  uint32_t cs_outsig;         /* SPI CS output signal index */
+  uint32_t mosi_insig;        /* SPI MOSI input signal index */
+  uint32_t mosi_outsig;       /* SPI MOSI output signal index */
+  uint32_t miso_insig;        /* SPI MISO input signal index */
+  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 */
+};
+
+struct spislave_priv_s
+{
+  /* Externally visible part of the SPI Slave controller interface */
+
+  struct spi_slave_ctrlr_s ctrlr;
+
+  /* Reference to SPI Slave device interface */
+
+  struct spi_slave_dev_s *dev;
+
+  /* Port configuration */
+
+  const struct spislave_config_s *config;
+  int refs;                   /* Reference count */
+  int cpu;                    /* CPU ID */
+  int cpuint;                 /* SPI interrupt ID */
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  int32_t dma_channel;        /* Channel assigned by the GDMA driver */
+
+  /* DMA RX/TX description */
+
+  struct esp32s2_dmadesc_s *dma_rxdesc;
+  struct esp32s2_dmadesc_s *dma_txdesc;
+
+  uint32_t rx_dma_offset;     /* Offset of DMA RX buffer */
+#endif
+  enum spi_slave_mode_e mode; /* Current SPI Slave hardware mode */
+  uint8_t nbits;              /* Current configured bit width */
+  uint32_t tx_length;         /* Location of next TX value */
+
+  /* SPI Slave TX queue buffer */
+
+  uint8_t tx_buffer[SPI_SLAVE_BUFSIZE];
+  uint32_t rx_length;         /* Location of next RX value */
+
+  /* SPI Slave RX queue buffer */
+
+  uint8_t rx_buffer[SPI_SLAVE_BUFSIZE];
+
+  /* Flag that indicates whether SPI Slave is currently processing */
+
+  bool is_processing;
+
+  /* Flag that indicates whether SPI Slave TX is currently enabled */
+
+  bool is_tx_enabled;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* SPI Slave controller interrupt handlers */
+
+static int spislave_cs_interrupt(int irq, void *context, void *arg);
+static int spislave_periph_interrupt(int irq, void *context, void *arg);
+
+/* SPI Slave controller internal functions */
+
+static void spislave_setmode(struct spi_slave_ctrlr_s *ctrlr,
+                             enum spi_slave_mode_e mode);
+static void spislave_setbits(struct spi_slave_ctrlr_s *ctrlr, int nbits);
+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 CONFIG_ESP32S2_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);
+static void spislave_prepare_next_tx(struct spislave_priv_s *priv);
+#else
+static void spislave_write_tx_buffer(struct spislave_priv_s *priv);
+#endif
+static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_deinitialize(struct spi_slave_ctrlr_s *ctrlr);
+
+/* SPI Slave controller operations */
+
+static void spislave_bind(struct spi_slave_ctrlr_s *ctrlr,
+                          struct spi_slave_dev_s *dev,
+                          enum spi_slave_mode_e mode,
+                          int nbits);
+static void spislave_unbind(struct spi_slave_ctrlr_s *ctrlr);
+static int spislave_enqueue(struct spi_slave_ctrlr_s *ctrlr,
+                            const void *data,
+                            size_t nwords);
+static bool spislave_qfull(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_qflush(struct spi_slave_ctrlr_s *ctrlr);
+static size_t spislave_qpoll(struct spi_slave_ctrlr_s *ctrlr);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/*  SPI2 private data */
+
+#ifdef CONFIG_ESP32S2_SPI2
+static const struct spislave_config_s esp32s2_spi2slave_config =
+{
+  .width        = SPI_SLAVE_DEFAULT_WIDTH,
+  .mode         = SPI_SLAVE_DEFAULT_MODE,
+  .id           = 2,
+  .cs_pin       = CONFIG_ESP32S2_SPI2_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S2_SPI2_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S2_SPI2_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S2_SPI2_CLKPIN,
+  .periph       = ESP32S2_PERIPH_SPI2,
+  .irq          = ESP32S2_IRQ_SPI2,
+  .clk_bit      = SYSTEM_SPI2_CLK_EN,
+  .rst_bit      = SYSTEM_SPI2_RST,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_clk_bit  = SYSTEM_SPI2_DMA_CLK_EN,
+  .dma_rst_bit  = SYSTEM_SPI2_DMA_RST,
+  .dma_periph   = ESP32S2_DMA_PERIPH_SPI2,
+#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,
+};
+
+static const struct spi_slave_ctrlrops_s esp32s2_spi2slave_ops =
+{
+  .bind     = spislave_bind,
+  .unbind   = spislave_unbind,
+  .enqueue  = spislave_enqueue,
+  .qfull    = spislave_qfull,
+  .qflush   = spislave_qflush,
+  .qpoll    = spislave_qpoll
+};
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+
+/* SPI DMA RX/TX description buffer */
+
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_rxdesc[SPI_DMA_DESC_NUM];
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_txdesc[SPI_DMA_DESC_NUM];
+#endif
+
+static struct spislave_priv_s esp32s2_spi2slave_priv =
+{
+  .ctrlr         =
+                  {
+                    .ops = &esp32s2_spi2slave_ops
+                  },
+  .dev           = NULL,
+  .config        = &esp32s2_spi2slave_config,
+  .refs          = 0,
+  .cpu           = -1,
+  .cpuint        = -ENOMEM,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_channel   = -ENOMEM,
+  .dma_rxdesc    = esp32s2_spi2_dma_rxdesc,
+  .dma_txdesc    = esp32s2_spi2_dma_txdesc,
+  .rx_dma_offset = 0,
+#endif
+  .mode          = SPISLAVE_MODE0,
+  .nbits         = 0,
+  .tx_length     = 0,
+  .tx_buffer     =
+                  {
+                    0
+                  },
+  .rx_length     = 0,
+  .rx_buffer     =
+                  {
+                    0
+                  },
+  .is_processing = false,
+  .is_tx_enabled = false
+};
+#endif /* CONFIG_ESP32S2_SPI2 */
+
+#ifdef CONFIG_ESP32S2_SPI3
+static const struct spislave_config_s esp32s2_spi3slave_config =
+{
+  .width        = SPI_SLAVE_DEFAULT_WIDTH,
+  .mode         = SPI_SLAVE_DEFAULT_MODE,
+  .id           = 3,
+  .cs_pin       = CONFIG_ESP32S2_SPI3_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S2_SPI3_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S2_SPI3_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S2_SPI3_CLKPIN,
+  .periph       = ESP32S2_PERIPH_SPI3,
+  .irq          = ESP32S2_IRQ_SPI3,
+  .clk_bit      = SYSTEM_SPI3_CLK_EN,
+  .rst_bit      = SYSTEM_SPI3_RST,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_clk_bit  = SYSTEM_SPI3_DMA_CLK_EN,
+  .dma_rst_bit  = SYSTEM_SPI3_DMA_RST,
+  .dma_periph   = ESP32S2_DMA_PERIPH_SPI3,
+#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_MUX_IDX,
+};
+
+static const struct spi_slave_ctrlrops_s esp32s2_spi3slave_ops =
+{
+  .bind     = spislave_bind,
+  .unbind   = spislave_unbind,
+  .enqueue  = spislave_enqueue,
+  .qfull    = spislave_qfull,
+  .qflush   = spislave_qflush,
+  .qpoll    = spislave_qpoll
+};
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+
+/* SPI DMA RX/TX description buffer */
+
+static struct esp32s2_dmadesc_s esp32s2_spi3_dma_rxdesc[SPI_DMA_DESC_NUM];
+static struct esp32s2_dmadesc_s esp32s2_spi3_dma_txdesc[SPI_DMA_DESC_NUM];
+#endif
+
+static struct spislave_priv_s esp32s2_spi3slave_priv =
+{
+  .ctrlr         =
+                  {
+                    .ops = &esp32s2_spi3slave_ops
+                  },

Review Comment:
   same



##########
arch/xtensa/src/esp32s2/esp32s2_spi_slave.c:
##########
@@ -0,0 +1,1734 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_spi_slave.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>
+
+#if defined(CONFIG_ESP32S2_SPI) && defined(CONFIG_SPI_SLAVE)
+
+#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 <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/spi/spi.h>
+#include <nuttx/spi/slave.h>
+
+#include <arch/board/board.h>
+
+#include "esp32s2_spi.h"
+#include "esp32s2_irq.h"
+#include "esp32s2_gpio.h"
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+#include "esp32s2_dma.h"
+#endif
+
+#include "xtensa.h"
+#include "hardware/esp32s2_gpio_sigmap.h"
+#include "hardware/esp32s2_pinmap.h"
+#include "hardware/esp32s2_spi.h"
+#include "hardware/esp32s2_soc.h"
+#include "hardware/esp32s2_system.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#define SPI_SLAVE_BUFSIZE (CONFIG_ESP32S2_SPI_SLAVE_BUFSIZE)
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+/* SPI DMA RX/TX number of descriptors */
+
+#  if (SPI_SLAVE_BUFSIZE % ESP32S2_DMA_BUFLEN_MAX) > 0
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_DMA_BUFLEN_MAX + 1)
+#  else
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_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_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_ESP32S2_SPI_DMA */
+
+/* Verify whether SPI has been assigned IOMUX pins.
+ * Otherwise, SPI signals will be routed via GPIO Matrix.
+ */
+
+#ifdef CONFIG_ESP32S2_SPI2
+#  define SPI_IS_CS_IOMUX   (CONFIG_ESP32S2_SPI2_CSPIN == SPI2_IOMUX_CSPIN)
+#  define SPI_IS_CLK_IOMUX  (CONFIG_ESP32S2_SPI2_CLKPIN == SPI2_IOMUX_CLKPIN)
+#  define SPI_IS_MOSI_IOMUX (CONFIG_ESP32S2_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN)
+#  define SPI_IS_MISO_IOMUX (CONFIG_ESP32S2_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))
+#else
+#  define SPI_VIA_IOMUX     0
+#endif
+
+/* SPI Slave interrupt mask */
+
+#define SPI_INT_MASK      (SPI_IN_DONE_INT_ENA_M |      \
+                           SPI_OUT_DONE_INT_ENA_M |     \
+                           SPI_SLV_WR_DMA_DONE_M | \
+                           SPI_SLV_RD_DMA_DONE_M | \
+                           SPI_SLV_WR_BUF_DONE_M | \
+                           SPI_SLV_RD_BUF_DONE_M)
+
+/* SPI Slave default width */
+
+#define SPI_SLAVE_DEFAULT_WIDTH (8)
+
+/* SPI Slave default mode */
+
+#define SPI_SLAVE_DEFAULT_MODE  (SPISLAVE_MODE0)
+
+/* SPI Slave maximum buffer size in bytes */
+
+#define SPI_SLAVE_HW_BUF_SIZE   (64)
+
+#define WORDS2BYTES(_priv, _wn)   ((_wn) * ((_priv)->nbits / 8))
+#define BYTES2WORDS(_priv, _bn)   ((_bn) / ((_priv)->nbits / 8))
+
+#define setbits(bs, a)     modifyreg32(a, 0, bs)
+#define resetbits(bs, a)   modifyreg32(a, bs, 0)
+
+/* SPI Slave controller hardware configuration */
+
+struct spislave_config_s
+{
+  int32_t width;              /* SPI Slave default width */
+  enum spi_slave_mode_e mode; /* SPI Slave default mode */
+
+  uint8_t id;                 /* SPI 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 periph;             /* Peripheral ID */
+  uint8_t irq;                /* Interrupt ID */
+  uint32_t clk_bit;           /* Clock enable bit */
+  uint32_t rst_bit;           /* SPI reset bit */
+#ifdef CONFIG_ESP32S2_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 */
+#endif
+  uint32_t cs_insig;          /* SPI CS input signal index */
+  uint32_t cs_outsig;         /* SPI CS output signal index */
+  uint32_t mosi_insig;        /* SPI MOSI input signal index */
+  uint32_t mosi_outsig;       /* SPI MOSI output signal index */
+  uint32_t miso_insig;        /* SPI MISO input signal index */
+  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 */
+};
+
+struct spislave_priv_s
+{
+  /* Externally visible part of the SPI Slave controller interface */
+
+  struct spi_slave_ctrlr_s ctrlr;
+
+  /* Reference to SPI Slave device interface */
+
+  struct spi_slave_dev_s *dev;
+
+  /* Port configuration */
+
+  const struct spislave_config_s *config;
+  int refs;                   /* Reference count */
+  int cpu;                    /* CPU ID */
+  int cpuint;                 /* SPI interrupt ID */
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  int32_t dma_channel;        /* Channel assigned by the GDMA driver */
+
+  /* DMA RX/TX description */
+
+  struct esp32s2_dmadesc_s *dma_rxdesc;
+  struct esp32s2_dmadesc_s *dma_txdesc;
+
+  uint32_t rx_dma_offset;     /* Offset of DMA RX buffer */
+#endif
+  enum spi_slave_mode_e mode; /* Current SPI Slave hardware mode */
+  uint8_t nbits;              /* Current configured bit width */
+  uint32_t tx_length;         /* Location of next TX value */
+
+  /* SPI Slave TX queue buffer */
+
+  uint8_t tx_buffer[SPI_SLAVE_BUFSIZE];
+  uint32_t rx_length;         /* Location of next RX value */
+
+  /* SPI Slave RX queue buffer */
+
+  uint8_t rx_buffer[SPI_SLAVE_BUFSIZE];
+
+  /* Flag that indicates whether SPI Slave is currently processing */
+
+  bool is_processing;
+
+  /* Flag that indicates whether SPI Slave TX is currently enabled */
+
+  bool is_tx_enabled;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* SPI Slave controller interrupt handlers */
+
+static int spislave_cs_interrupt(int irq, void *context, void *arg);
+static int spislave_periph_interrupt(int irq, void *context, void *arg);
+
+/* SPI Slave controller internal functions */
+
+static void spislave_setmode(struct spi_slave_ctrlr_s *ctrlr,
+                             enum spi_slave_mode_e mode);
+static void spislave_setbits(struct spi_slave_ctrlr_s *ctrlr, int nbits);
+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 CONFIG_ESP32S2_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);
+static void spislave_prepare_next_tx(struct spislave_priv_s *priv);
+#else
+static void spislave_write_tx_buffer(struct spislave_priv_s *priv);
+#endif
+static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_deinitialize(struct spi_slave_ctrlr_s *ctrlr);
+
+/* SPI Slave controller operations */
+
+static void spislave_bind(struct spi_slave_ctrlr_s *ctrlr,
+                          struct spi_slave_dev_s *dev,
+                          enum spi_slave_mode_e mode,
+                          int nbits);
+static void spislave_unbind(struct spi_slave_ctrlr_s *ctrlr);
+static int spislave_enqueue(struct spi_slave_ctrlr_s *ctrlr,
+                            const void *data,
+                            size_t nwords);
+static bool spislave_qfull(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_qflush(struct spi_slave_ctrlr_s *ctrlr);
+static size_t spislave_qpoll(struct spi_slave_ctrlr_s *ctrlr);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/*  SPI2 private data */
+
+#ifdef CONFIG_ESP32S2_SPI2
+static const struct spislave_config_s esp32s2_spi2slave_config =
+{
+  .width        = SPI_SLAVE_DEFAULT_WIDTH,
+  .mode         = SPI_SLAVE_DEFAULT_MODE,
+  .id           = 2,
+  .cs_pin       = CONFIG_ESP32S2_SPI2_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S2_SPI2_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S2_SPI2_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S2_SPI2_CLKPIN,
+  .periph       = ESP32S2_PERIPH_SPI2,
+  .irq          = ESP32S2_IRQ_SPI2,
+  .clk_bit      = SYSTEM_SPI2_CLK_EN,
+  .rst_bit      = SYSTEM_SPI2_RST,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_clk_bit  = SYSTEM_SPI2_DMA_CLK_EN,
+  .dma_rst_bit  = SYSTEM_SPI2_DMA_RST,
+  .dma_periph   = ESP32S2_DMA_PERIPH_SPI2,
+#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,
+};
+
+static const struct spi_slave_ctrlrops_s esp32s2_spi2slave_ops =
+{
+  .bind     = spislave_bind,
+  .unbind   = spislave_unbind,
+  .enqueue  = spislave_enqueue,
+  .qfull    = spislave_qfull,
+  .qflush   = spislave_qflush,
+  .qpoll    = spislave_qpoll
+};
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+
+/* SPI DMA RX/TX description buffer */
+
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_rxdesc[SPI_DMA_DESC_NUM];
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_txdesc[SPI_DMA_DESC_NUM];
+#endif
+
+static struct spislave_priv_s esp32s2_spi2slave_priv =
+{
+  .ctrlr         =
+                  {
+                    .ops = &esp32s2_spi2slave_ops
+                  },
+  .dev           = NULL,
+  .config        = &esp32s2_spi2slave_config,
+  .refs          = 0,
+  .cpu           = -1,
+  .cpuint        = -ENOMEM,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_channel   = -ENOMEM,
+  .dma_rxdesc    = esp32s2_spi2_dma_rxdesc,
+  .dma_txdesc    = esp32s2_spi2_dma_txdesc,
+  .rx_dma_offset = 0,
+#endif
+  .mode          = SPISLAVE_MODE0,
+  .nbits         = 0,
+  .tx_length     = 0,
+  .tx_buffer     =
+                  {
+                    0
+                  },

Review Comment:
   same



##########
arch/xtensa/src/esp32s2/esp32s2_spi_slave.c:
##########
@@ -0,0 +1,1734 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_spi_slave.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>
+
+#if defined(CONFIG_ESP32S2_SPI) && defined(CONFIG_SPI_SLAVE)
+
+#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 <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/spi/spi.h>
+#include <nuttx/spi/slave.h>
+
+#include <arch/board/board.h>
+
+#include "esp32s2_spi.h"
+#include "esp32s2_irq.h"
+#include "esp32s2_gpio.h"
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+#include "esp32s2_dma.h"
+#endif
+
+#include "xtensa.h"
+#include "hardware/esp32s2_gpio_sigmap.h"
+#include "hardware/esp32s2_pinmap.h"
+#include "hardware/esp32s2_spi.h"
+#include "hardware/esp32s2_soc.h"
+#include "hardware/esp32s2_system.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#define SPI_SLAVE_BUFSIZE (CONFIG_ESP32S2_SPI_SLAVE_BUFSIZE)
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+/* SPI DMA RX/TX number of descriptors */
+
+#  if (SPI_SLAVE_BUFSIZE % ESP32S2_DMA_BUFLEN_MAX) > 0
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_DMA_BUFLEN_MAX + 1)
+#  else
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_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_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_ESP32S2_SPI_DMA */
+
+/* Verify whether SPI has been assigned IOMUX pins.
+ * Otherwise, SPI signals will be routed via GPIO Matrix.
+ */
+
+#ifdef CONFIG_ESP32S2_SPI2
+#  define SPI_IS_CS_IOMUX   (CONFIG_ESP32S2_SPI2_CSPIN == SPI2_IOMUX_CSPIN)
+#  define SPI_IS_CLK_IOMUX  (CONFIG_ESP32S2_SPI2_CLKPIN == SPI2_IOMUX_CLKPIN)
+#  define SPI_IS_MOSI_IOMUX (CONFIG_ESP32S2_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN)
+#  define SPI_IS_MISO_IOMUX (CONFIG_ESP32S2_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))
+#else
+#  define SPI_VIA_IOMUX     0
+#endif
+
+/* SPI Slave interrupt mask */
+
+#define SPI_INT_MASK      (SPI_IN_DONE_INT_ENA_M |      \
+                           SPI_OUT_DONE_INT_ENA_M |     \
+                           SPI_SLV_WR_DMA_DONE_M | \
+                           SPI_SLV_RD_DMA_DONE_M | \
+                           SPI_SLV_WR_BUF_DONE_M | \
+                           SPI_SLV_RD_BUF_DONE_M)
+
+/* SPI Slave default width */
+
+#define SPI_SLAVE_DEFAULT_WIDTH (8)
+
+/* SPI Slave default mode */
+
+#define SPI_SLAVE_DEFAULT_MODE  (SPISLAVE_MODE0)
+
+/* SPI Slave maximum buffer size in bytes */
+
+#define SPI_SLAVE_HW_BUF_SIZE   (64)
+
+#define WORDS2BYTES(_priv, _wn)   ((_wn) * ((_priv)->nbits / 8))
+#define BYTES2WORDS(_priv, _bn)   ((_bn) / ((_priv)->nbits / 8))
+
+#define setbits(bs, a)     modifyreg32(a, 0, bs)
+#define resetbits(bs, a)   modifyreg32(a, bs, 0)
+
+/* SPI Slave controller hardware configuration */
+
+struct spislave_config_s
+{
+  int32_t width;              /* SPI Slave default width */
+  enum spi_slave_mode_e mode; /* SPI Slave default mode */
+
+  uint8_t id;                 /* SPI 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 periph;             /* Peripheral ID */
+  uint8_t irq;                /* Interrupt ID */
+  uint32_t clk_bit;           /* Clock enable bit */
+  uint32_t rst_bit;           /* SPI reset bit */
+#ifdef CONFIG_ESP32S2_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 */
+#endif
+  uint32_t cs_insig;          /* SPI CS input signal index */
+  uint32_t cs_outsig;         /* SPI CS output signal index */
+  uint32_t mosi_insig;        /* SPI MOSI input signal index */
+  uint32_t mosi_outsig;       /* SPI MOSI output signal index */
+  uint32_t miso_insig;        /* SPI MISO input signal index */
+  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 */
+};
+
+struct spislave_priv_s
+{
+  /* Externally visible part of the SPI Slave controller interface */
+
+  struct spi_slave_ctrlr_s ctrlr;
+
+  /* Reference to SPI Slave device interface */
+
+  struct spi_slave_dev_s *dev;
+
+  /* Port configuration */
+
+  const struct spislave_config_s *config;
+  int refs;                   /* Reference count */
+  int cpu;                    /* CPU ID */
+  int cpuint;                 /* SPI interrupt ID */
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  int32_t dma_channel;        /* Channel assigned by the GDMA driver */
+
+  /* DMA RX/TX description */
+
+  struct esp32s2_dmadesc_s *dma_rxdesc;
+  struct esp32s2_dmadesc_s *dma_txdesc;
+
+  uint32_t rx_dma_offset;     /* Offset of DMA RX buffer */
+#endif
+  enum spi_slave_mode_e mode; /* Current SPI Slave hardware mode */
+  uint8_t nbits;              /* Current configured bit width */
+  uint32_t tx_length;         /* Location of next TX value */
+
+  /* SPI Slave TX queue buffer */
+
+  uint8_t tx_buffer[SPI_SLAVE_BUFSIZE];
+  uint32_t rx_length;         /* Location of next RX value */
+
+  /* SPI Slave RX queue buffer */
+
+  uint8_t rx_buffer[SPI_SLAVE_BUFSIZE];
+
+  /* Flag that indicates whether SPI Slave is currently processing */
+
+  bool is_processing;
+
+  /* Flag that indicates whether SPI Slave TX is currently enabled */
+
+  bool is_tx_enabled;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* SPI Slave controller interrupt handlers */
+
+static int spislave_cs_interrupt(int irq, void *context, void *arg);
+static int spislave_periph_interrupt(int irq, void *context, void *arg);
+
+/* SPI Slave controller internal functions */
+
+static void spislave_setmode(struct spi_slave_ctrlr_s *ctrlr,
+                             enum spi_slave_mode_e mode);
+static void spislave_setbits(struct spi_slave_ctrlr_s *ctrlr, int nbits);
+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 CONFIG_ESP32S2_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);
+static void spislave_prepare_next_tx(struct spislave_priv_s *priv);
+#else
+static void spislave_write_tx_buffer(struct spislave_priv_s *priv);
+#endif
+static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_deinitialize(struct spi_slave_ctrlr_s *ctrlr);
+
+/* SPI Slave controller operations */
+
+static void spislave_bind(struct spi_slave_ctrlr_s *ctrlr,
+                          struct spi_slave_dev_s *dev,
+                          enum spi_slave_mode_e mode,
+                          int nbits);
+static void spislave_unbind(struct spi_slave_ctrlr_s *ctrlr);
+static int spislave_enqueue(struct spi_slave_ctrlr_s *ctrlr,
+                            const void *data,
+                            size_t nwords);
+static bool spislave_qfull(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_qflush(struct spi_slave_ctrlr_s *ctrlr);
+static size_t spislave_qpoll(struct spi_slave_ctrlr_s *ctrlr);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/*  SPI2 private data */
+
+#ifdef CONFIG_ESP32S2_SPI2
+static const struct spislave_config_s esp32s2_spi2slave_config =
+{
+  .width        = SPI_SLAVE_DEFAULT_WIDTH,
+  .mode         = SPI_SLAVE_DEFAULT_MODE,
+  .id           = 2,
+  .cs_pin       = CONFIG_ESP32S2_SPI2_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S2_SPI2_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S2_SPI2_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S2_SPI2_CLKPIN,
+  .periph       = ESP32S2_PERIPH_SPI2,
+  .irq          = ESP32S2_IRQ_SPI2,
+  .clk_bit      = SYSTEM_SPI2_CLK_EN,
+  .rst_bit      = SYSTEM_SPI2_RST,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_clk_bit  = SYSTEM_SPI2_DMA_CLK_EN,
+  .dma_rst_bit  = SYSTEM_SPI2_DMA_RST,
+  .dma_periph   = ESP32S2_DMA_PERIPH_SPI2,
+#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,
+};
+
+static const struct spi_slave_ctrlrops_s esp32s2_spi2slave_ops =
+{
+  .bind     = spislave_bind,
+  .unbind   = spislave_unbind,
+  .enqueue  = spislave_enqueue,
+  .qfull    = spislave_qfull,
+  .qflush   = spislave_qflush,
+  .qpoll    = spislave_qpoll
+};
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+
+/* SPI DMA RX/TX description buffer */
+
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_rxdesc[SPI_DMA_DESC_NUM];
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_txdesc[SPI_DMA_DESC_NUM];
+#endif
+
+static struct spislave_priv_s esp32s2_spi2slave_priv =
+{
+  .ctrlr         =
+                  {
+                    .ops = &esp32s2_spi2slave_ops
+                  },
+  .dev           = NULL,
+  .config        = &esp32s2_spi2slave_config,
+  .refs          = 0,
+  .cpu           = -1,
+  .cpuint        = -ENOMEM,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_channel   = -ENOMEM,
+  .dma_rxdesc    = esp32s2_spi2_dma_rxdesc,
+  .dma_txdesc    = esp32s2_spi2_dma_txdesc,
+  .rx_dma_offset = 0,
+#endif
+  .mode          = SPISLAVE_MODE0,
+  .nbits         = 0,
+  .tx_length     = 0,
+  .tx_buffer     =
+                  {
+                    0
+                  },
+  .rx_length     = 0,
+  .rx_buffer     =
+                  {
+                    0
+                  },

Review Comment:
   same



##########
arch/xtensa/src/esp32s2/esp32s2_spi_slave.c:
##########
@@ -0,0 +1,1734 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_spi_slave.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>
+
+#if defined(CONFIG_ESP32S2_SPI) && defined(CONFIG_SPI_SLAVE)
+
+#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 <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/spi/spi.h>
+#include <nuttx/spi/slave.h>
+
+#include <arch/board/board.h>
+
+#include "esp32s2_spi.h"
+#include "esp32s2_irq.h"
+#include "esp32s2_gpio.h"
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+#include "esp32s2_dma.h"
+#endif
+
+#include "xtensa.h"
+#include "hardware/esp32s2_gpio_sigmap.h"
+#include "hardware/esp32s2_pinmap.h"
+#include "hardware/esp32s2_spi.h"
+#include "hardware/esp32s2_soc.h"
+#include "hardware/esp32s2_system.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#define SPI_SLAVE_BUFSIZE (CONFIG_ESP32S2_SPI_SLAVE_BUFSIZE)
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+/* SPI DMA RX/TX number of descriptors */
+
+#  if (SPI_SLAVE_BUFSIZE % ESP32S2_DMA_BUFLEN_MAX) > 0
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_DMA_BUFLEN_MAX + 1)
+#  else
+#    define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_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_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_ESP32S2_SPI_DMA */
+
+/* Verify whether SPI has been assigned IOMUX pins.
+ * Otherwise, SPI signals will be routed via GPIO Matrix.
+ */
+
+#ifdef CONFIG_ESP32S2_SPI2
+#  define SPI_IS_CS_IOMUX   (CONFIG_ESP32S2_SPI2_CSPIN == SPI2_IOMUX_CSPIN)
+#  define SPI_IS_CLK_IOMUX  (CONFIG_ESP32S2_SPI2_CLKPIN == SPI2_IOMUX_CLKPIN)
+#  define SPI_IS_MOSI_IOMUX (CONFIG_ESP32S2_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN)
+#  define SPI_IS_MISO_IOMUX (CONFIG_ESP32S2_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))
+#else
+#  define SPI_VIA_IOMUX     0
+#endif
+
+/* SPI Slave interrupt mask */
+
+#define SPI_INT_MASK      (SPI_IN_DONE_INT_ENA_M |      \
+                           SPI_OUT_DONE_INT_ENA_M |     \
+                           SPI_SLV_WR_DMA_DONE_M | \
+                           SPI_SLV_RD_DMA_DONE_M | \
+                           SPI_SLV_WR_BUF_DONE_M | \
+                           SPI_SLV_RD_BUF_DONE_M)
+
+/* SPI Slave default width */
+
+#define SPI_SLAVE_DEFAULT_WIDTH (8)
+
+/* SPI Slave default mode */
+
+#define SPI_SLAVE_DEFAULT_MODE  (SPISLAVE_MODE0)
+
+/* SPI Slave maximum buffer size in bytes */
+
+#define SPI_SLAVE_HW_BUF_SIZE   (64)
+
+#define WORDS2BYTES(_priv, _wn)   ((_wn) * ((_priv)->nbits / 8))
+#define BYTES2WORDS(_priv, _bn)   ((_bn) / ((_priv)->nbits / 8))
+
+#define setbits(bs, a)     modifyreg32(a, 0, bs)
+#define resetbits(bs, a)   modifyreg32(a, bs, 0)
+
+/* SPI Slave controller hardware configuration */
+
+struct spislave_config_s
+{
+  int32_t width;              /* SPI Slave default width */
+  enum spi_slave_mode_e mode; /* SPI Slave default mode */
+
+  uint8_t id;                 /* SPI 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 periph;             /* Peripheral ID */
+  uint8_t irq;                /* Interrupt ID */
+  uint32_t clk_bit;           /* Clock enable bit */
+  uint32_t rst_bit;           /* SPI reset bit */
+#ifdef CONFIG_ESP32S2_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 */
+#endif
+  uint32_t cs_insig;          /* SPI CS input signal index */
+  uint32_t cs_outsig;         /* SPI CS output signal index */
+  uint32_t mosi_insig;        /* SPI MOSI input signal index */
+  uint32_t mosi_outsig;       /* SPI MOSI output signal index */
+  uint32_t miso_insig;        /* SPI MISO input signal index */
+  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 */
+};
+
+struct spislave_priv_s
+{
+  /* Externally visible part of the SPI Slave controller interface */
+
+  struct spi_slave_ctrlr_s ctrlr;
+
+  /* Reference to SPI Slave device interface */
+
+  struct spi_slave_dev_s *dev;
+
+  /* Port configuration */
+
+  const struct spislave_config_s *config;
+  int refs;                   /* Reference count */
+  int cpu;                    /* CPU ID */
+  int cpuint;                 /* SPI interrupt ID */
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  int32_t dma_channel;        /* Channel assigned by the GDMA driver */
+
+  /* DMA RX/TX description */
+
+  struct esp32s2_dmadesc_s *dma_rxdesc;
+  struct esp32s2_dmadesc_s *dma_txdesc;
+
+  uint32_t rx_dma_offset;     /* Offset of DMA RX buffer */
+#endif
+  enum spi_slave_mode_e mode; /* Current SPI Slave hardware mode */
+  uint8_t nbits;              /* Current configured bit width */
+  uint32_t tx_length;         /* Location of next TX value */
+
+  /* SPI Slave TX queue buffer */
+
+  uint8_t tx_buffer[SPI_SLAVE_BUFSIZE];
+  uint32_t rx_length;         /* Location of next RX value */
+
+  /* SPI Slave RX queue buffer */
+
+  uint8_t rx_buffer[SPI_SLAVE_BUFSIZE];
+
+  /* Flag that indicates whether SPI Slave is currently processing */
+
+  bool is_processing;
+
+  /* Flag that indicates whether SPI Slave TX is currently enabled */
+
+  bool is_tx_enabled;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* SPI Slave controller interrupt handlers */
+
+static int spislave_cs_interrupt(int irq, void *context, void *arg);
+static int spislave_periph_interrupt(int irq, void *context, void *arg);
+
+/* SPI Slave controller internal functions */
+
+static void spislave_setmode(struct spi_slave_ctrlr_s *ctrlr,
+                             enum spi_slave_mode_e mode);
+static void spislave_setbits(struct spi_slave_ctrlr_s *ctrlr, int nbits);
+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 CONFIG_ESP32S2_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);
+static void spislave_prepare_next_tx(struct spislave_priv_s *priv);
+#else
+static void spislave_write_tx_buffer(struct spislave_priv_s *priv);
+#endif
+static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_deinitialize(struct spi_slave_ctrlr_s *ctrlr);
+
+/* SPI Slave controller operations */
+
+static void spislave_bind(struct spi_slave_ctrlr_s *ctrlr,
+                          struct spi_slave_dev_s *dev,
+                          enum spi_slave_mode_e mode,
+                          int nbits);
+static void spislave_unbind(struct spi_slave_ctrlr_s *ctrlr);
+static int spislave_enqueue(struct spi_slave_ctrlr_s *ctrlr,
+                            const void *data,
+                            size_t nwords);
+static bool spislave_qfull(struct spi_slave_ctrlr_s *ctrlr);
+static void spislave_qflush(struct spi_slave_ctrlr_s *ctrlr);
+static size_t spislave_qpoll(struct spi_slave_ctrlr_s *ctrlr);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/*  SPI2 private data */
+
+#ifdef CONFIG_ESP32S2_SPI2
+static const struct spislave_config_s esp32s2_spi2slave_config =
+{
+  .width        = SPI_SLAVE_DEFAULT_WIDTH,
+  .mode         = SPI_SLAVE_DEFAULT_MODE,
+  .id           = 2,
+  .cs_pin       = CONFIG_ESP32S2_SPI2_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S2_SPI2_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S2_SPI2_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S2_SPI2_CLKPIN,
+  .periph       = ESP32S2_PERIPH_SPI2,
+  .irq          = ESP32S2_IRQ_SPI2,
+  .clk_bit      = SYSTEM_SPI2_CLK_EN,
+  .rst_bit      = SYSTEM_SPI2_RST,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_clk_bit  = SYSTEM_SPI2_DMA_CLK_EN,
+  .dma_rst_bit  = SYSTEM_SPI2_DMA_RST,
+  .dma_periph   = ESP32S2_DMA_PERIPH_SPI2,
+#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,
+};
+
+static const struct spi_slave_ctrlrops_s esp32s2_spi2slave_ops =
+{
+  .bind     = spislave_bind,
+  .unbind   = spislave_unbind,
+  .enqueue  = spislave_enqueue,
+  .qfull    = spislave_qfull,
+  .qflush   = spislave_qflush,
+  .qpoll    = spislave_qpoll
+};
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+
+/* SPI DMA RX/TX description buffer */
+
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_rxdesc[SPI_DMA_DESC_NUM];
+static struct esp32s2_dmadesc_s esp32s2_spi2_dma_txdesc[SPI_DMA_DESC_NUM];
+#endif
+
+static struct spislave_priv_s esp32s2_spi2slave_priv =
+{
+  .ctrlr         =
+                  {
+                    .ops = &esp32s2_spi2slave_ops
+                  },
+  .dev           = NULL,
+  .config        = &esp32s2_spi2slave_config,
+  .refs          = 0,
+  .cpu           = -1,
+  .cpuint        = -ENOMEM,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_channel   = -ENOMEM,
+  .dma_rxdesc    = esp32s2_spi2_dma_rxdesc,
+  .dma_txdesc    = esp32s2_spi2_dma_txdesc,
+  .rx_dma_offset = 0,
+#endif
+  .mode          = SPISLAVE_MODE0,
+  .nbits         = 0,
+  .tx_length     = 0,
+  .tx_buffer     =
+                  {
+                    0
+                  },
+  .rx_length     = 0,
+  .rx_buffer     =
+                  {
+                    0
+                  },
+  .is_processing = false,
+  .is_tx_enabled = false
+};
+#endif /* CONFIG_ESP32S2_SPI2 */
+
+#ifdef CONFIG_ESP32S2_SPI3
+static const struct spislave_config_s esp32s2_spi3slave_config =
+{
+  .width        = SPI_SLAVE_DEFAULT_WIDTH,
+  .mode         = SPI_SLAVE_DEFAULT_MODE,
+  .id           = 3,
+  .cs_pin       = CONFIG_ESP32S2_SPI3_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S2_SPI3_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S2_SPI3_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S2_SPI3_CLKPIN,
+  .periph       = ESP32S2_PERIPH_SPI3,
+  .irq          = ESP32S2_IRQ_SPI3,
+  .clk_bit      = SYSTEM_SPI3_CLK_EN,
+  .rst_bit      = SYSTEM_SPI3_RST,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_clk_bit  = SYSTEM_SPI3_DMA_CLK_EN,
+  .dma_rst_bit  = SYSTEM_SPI3_DMA_RST,
+  .dma_periph   = ESP32S2_DMA_PERIPH_SPI3,
+#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_MUX_IDX,
+};
+
+static const struct spi_slave_ctrlrops_s esp32s2_spi3slave_ops =
+{
+  .bind     = spislave_bind,
+  .unbind   = spislave_unbind,
+  .enqueue  = spislave_enqueue,
+  .qfull    = spislave_qfull,
+  .qflush   = spislave_qflush,
+  .qpoll    = spislave_qpoll
+};
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+
+/* SPI DMA RX/TX description buffer */
+
+static struct esp32s2_dmadesc_s esp32s2_spi3_dma_rxdesc[SPI_DMA_DESC_NUM];
+static struct esp32s2_dmadesc_s esp32s2_spi3_dma_txdesc[SPI_DMA_DESC_NUM];
+#endif
+
+static struct spislave_priv_s esp32s2_spi3slave_priv =
+{
+  .ctrlr         =
+                  {
+                    .ops = &esp32s2_spi3slave_ops
+                  },
+  .dev           = NULL,
+  .config        = &esp32s2_spi3slave_config,
+  .refs          = 0,
+  .cpu           = -1,
+  .cpuint        = -ENOMEM,
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  .dma_channel   = -ENOMEM,
+  .dma_rxdesc    = esp32s2_spi3_dma_rxdesc,
+  .dma_txdesc    = esp32s2_spi3_dma_txdesc,
+  .rx_dma_offset = 0,
+#endif
+  .mode          = SPISLAVE_MODE0,
+  .nbits         = 0,
+  .tx_length     = 0,
+  .tx_buffer     =
+                  {
+                    0
+                  },
+  .rx_length     = 0,
+  .rx_buffer     =
+                  {
+                    0
+                  },
+  .is_processing = false,
+  .is_tx_enabled = false
+};
+#endif /* CONFIG_ESP32S2_SPI3 */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: spislave_peripheral_reset
+ *
+ * Description:
+ *   Reset the SPI Slave peripheral before next transaction.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline void spislave_peripheral_reset(struct spislave_priv_s *priv)
+{
+  setbits(SPI_SOFT_RESET_M, SPI_SLAVE_REG(priv->config->id));
+  resetbits(SPI_SOFT_RESET_M, SPI_SLAVE_REG(priv->config->id));
+}
+
+/****************************************************************************
+ * Name: spislave_cpu_tx_fifo_reset
+ *
+ * Description:
+ *   Reset the BUF TX AFIFO, which is used to send data out in SPI Slave
+ *   CPU-controlled mode transfer.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline void spislave_cpu_tx_fifo_reset(struct spislave_priv_s *priv)
+{
+  setbits(SPI_AHBM_FIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
+  resetbits(SPI_AHBM_FIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
+}
+
+/****************************************************************************
+ * Name: spislave_dma_tx_fifo_reset
+ *
+ * Description:
+ *   Reset the DMA TX AFIFO, which is used to send data out in SPI Slave
+ *   DMA-controlled mode transfer.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_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));
+  resetbits(SPI_DMA_AFIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
+}
+#endif
+
+/****************************************************************************
+ * Name: spislave_dma_rx_fifo_reset
+ *
+ * Description:
+ *   Reset the RX AFIFO, which is used to receive data in SPI Slave mode
+ *   transfer.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_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));
+  resetbits(SPI_RX_AFIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
+}
+#endif
+
+/****************************************************************************
+ * Name: spislave_setmode
+ *
+ * Description:
+ *   Set the SPI Slave mode.
+ *
+ * Input Parameters:
+ *   ctrlr - SPI Slave controller interface instance
+ *   mode  - Requested SPI Slave mode
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void spislave_setmode(struct spi_slave_ctrlr_s *ctrlr,
+                             enum spi_slave_mode_e mode)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
+
+  spiinfo("mode=%d\n", mode);
+
+  /* Has the mode changed? */
+
+  if (mode != priv->mode)
+    {
+      uint32_t ck_idle_edge;
+      uint32_t rsck_i_edge;
+      uint32_t tsck_i_edge;
+      uint32_t clk_mode_13;
+
+      switch (mode)
+        {
+          case SPISLAVE_MODE0: /* CPOL=0; CPHA=0 */
+            ck_idle_edge = 0;
+            rsck_i_edge = 0;
+            tsck_i_edge = 0;
+            clk_mode_13 = 0;
+            break;
+
+          case SPISLAVE_MODE1: /* CPOL=0; CPHA=1 */
+            ck_idle_edge = 0;
+            rsck_i_edge = 1;
+            tsck_i_edge = 1;
+            clk_mode_13 = 1;
+            break;
+
+          case SPISLAVE_MODE2: /* CPOL=1; CPHA=0 */
+            ck_idle_edge = 1;
+            rsck_i_edge = 1;
+            tsck_i_edge = 1;
+            clk_mode_13 = 0;
+            break;
+
+          case SPISLAVE_MODE3: /* CPOL=1; CPHA=1 */
+            ck_idle_edge = 1;
+            rsck_i_edge = 0;
+            tsck_i_edge = 0;
+            clk_mode_13 = 1;
+            break;
+
+          default:
+            spierr("Invalid mode: %d\n", mode);
+            DEBUGPANIC();
+            return;
+        }
+
+      modifyreg32(SPI_MISC_REG(priv->config->id),
+                  SPI_CK_IDLE_EDGE_M,
+                  VALUE_TO_FIELD(ck_idle_edge, SPI_CK_IDLE_EDGE));
+
+      modifyreg32(SPI_USER_REG(priv->config->id),
+                  SPI_RSCK_I_EDGE_M | SPI_TSCK_I_EDGE_M,
+                  VALUE_TO_FIELD(rsck_i_edge, SPI_RSCK_I_EDGE) |
+                  VALUE_TO_FIELD(tsck_i_edge, SPI_TSCK_I_EDGE));
+
+      modifyreg32(SPI_SLAVE_REG(priv->config->id),
+                  SPI_CLK_MODE_13_M | SPI_RSCK_DATA_OUT_M,
+                  VALUE_TO_FIELD(clk_mode_13, SPI_CLK_MODE_13));
+
+      priv->mode = mode;
+    }
+}
+
+/****************************************************************************
+ * Name: spislave_setbits
+ *
+ * Description:
+ *   Set the number of bits per word.
+ *
+ * Input Parameters:
+ *   ctrlr - SPI Slave controller interface instance
+ *   nbits - The number of bits in an SPI word
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void spislave_setbits(struct spi_slave_ctrlr_s *ctrlr, int nbits)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
+
+  spiinfo("nbits=%d\n", nbits);
+
+  priv->nbits = nbits;
+}
+
+/****************************************************************************
+ * Name: spislave_cs_interrupt
+ *
+ * Description:
+ *   Handler for the GPIO interrupt which is triggered when the chip select
+ *   has toggled to inactive state (active high).
+ *
+ * Input Parameters:
+ *   irq     - Number of the IRQ that generated the interrupt
+ *   context - Interrupt register state save info
+ *   arg     - SPI Slave controller private data
+ *
+ * Returned Value:
+ *   Standard interrupt return value.
+ *
+ ****************************************************************************/
+
+static int spislave_cs_interrupt(int irq, void *context, void *arg)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)arg;
+
+  if (priv->is_processing)
+    {
+      priv->is_processing = false;
+      SPIS_DEV_SELECT(priv->dev, false);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: spislave_store_result
+ *
+ * Description:
+ *   Fetch data from the SPI hardware data buffer and record the length.
+ *   This is a post transaction operation.
+ *
+ * Input Parameters:
+ *   priv       - Private SPI Slave controller structure
+ *   recv_bytes - Number of received bytes
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void spislave_store_result(struct spislave_priv_s *priv,
+                                  uint32_t recv_bytes)
+{
+  uint32_t remaining_space = SPI_SLAVE_BUFSIZE - priv->rx_length;
+  uint32_t bytes_to_copy = recv_bytes;
+
+  if (bytes_to_copy > remaining_space)
+    {
+      spiwarn("RX buffer full! Discarded %" PRIu32 " received bytes\n",
+              bytes_to_copy - remaining_space);
+
+      bytes_to_copy = remaining_space;
+    }
+
+#ifdef CONFIG_ESP32S2_SPI_DMA
+  if (bytes_to_copy)
+    {
+      if ((priv->rx_dma_offset != priv->rx_length))
+        {
+          memmove(priv->rx_buffer + priv->rx_length,
+                  priv->rx_buffer + priv->rx_dma_offset,
+                  bytes_to_copy);
+
+          priv->rx_dma_offset = priv->rx_length;
+        }
+
+      priv->rx_length += bytes_to_copy;
+    }
+#else
+  /* If DMA is not enabled, software should copy incoming data from data
+   * buffer registers to receive buffer.
+   */
+
+  if (bytes_to_copy)
+    {
+      /* Set data_buf_reg with the address of the first data buffer
+       * register (W0).
+       */
+
+      uintptr_t data_buf_reg = SPI_W0_REG(priv->config->id);
+
+      /* Read received data words from SPI hardware data buffer. */
+
+      for (int i = 0; i < bytes_to_copy; i += sizeof(uint32_t))
+        {
+          uint32_t rbytes = MIN(bytes_to_copy - i, sizeof(uintptr_t));
+          uint32_t r_wd = getreg32(data_buf_reg);
+
+          memcpy(priv->rx_buffer + priv->rx_length + i, &r_wd, rbytes);
+
+          /* Update data_buf_reg to point to the next data buffer register. */
+
+          data_buf_reg += sizeof(uintptr_t);

Review Comment:
   maybe better to use `uint32_t` here, the same as in `i += sizeof(uint32_t)`?



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

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

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


Reply via email to