You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2024/06/13 01:53:25 UTC

(nuttx) branch master updated: esp32[c3|c6|h2]: Add SPI Slave support

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 0cf7676aca esp32[c3|c6|h2]: Add SPI Slave support
0cf7676aca is described below

commit 0cf7676acaecc0076eacdb2eedd9e926362d68c8
Author: Eren Terzioglu <er...@espressif.com>
AuthorDate: Tue Apr 23 10:40:29 2024 +0300

    esp32[c3|c6|h2]: Add SPI Slave support
---
 arch/risc-v/src/common/espressif/Kconfig           |  15 +
 arch/risc-v/src/common/espressif/Make.defs         |   3 +
 arch/risc-v/src/common/espressif/esp_spi.h         |  33 +
 arch/risc-v/src/common/espressif/esp_spi_slave.c   | 940 +++++++++++++++++++++
 arch/risc-v/src/esp32c3/hal_esp32c3.mk             |   2 +
 arch/risc-v/src/esp32c6/hal_esp32c6.mk             |   2 +
 arch/risc-v/src/esp32h2/hal_esp32h2.mk             |   2 +
 .../esp32c3/common/include/esp_board_spislavedev.h |  74 ++
 boards/risc-v/esp32c3/common/src/Make.defs         |   4 +
 .../esp32c3/common/src/esp_board_spislavedev.c     |  82 ++
 .../esp32c3/esp32c3-generic/src/esp32c3_bringup.c  |  14 +
 .../esp32c6/common/include/esp_board_spislavedev.h |  74 ++
 boards/risc-v/esp32c6/common/src/Make.defs         |   4 +
 .../esp32c6/common/src/esp_board_spislavedev.c     |  82 ++
 .../esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c  |  14 +
 .../esp32c6/esp32c6-devkitm/src/esp32c6_bringup.c  |  14 +
 .../esp32h2/common/include/esp_board_spislavedev.h |  74 ++
 boards/risc-v/esp32h2/common/src/Make.defs         |   4 +
 .../esp32h2/common/src/esp_board_spislavedev.c     |  82 ++
 .../esp32h2/esp32h2-devkit/src/esp32h2_bringup.c   |  14 +
 20 files changed, 1533 insertions(+)

diff --git a/arch/risc-v/src/common/espressif/Kconfig b/arch/risc-v/src/common/espressif/Kconfig
index bb6ffc2225..5e10163143 100644
--- a/arch/risc-v/src/common/espressif/Kconfig
+++ b/arch/risc-v/src/common/espressif/Kconfig
@@ -869,6 +869,21 @@ config ESPRESSIF_SPI_UDCS
 
 if ESPRESSIF_SPI2
 
+config ESPRESSIF_SPI2_SLAVE
+	bool "SPI2 Slave mode"
+	default n
+	depends on SPI_SLAVE
+	select ESPRESSIF_GPIO_IRQ
+	---help---
+		Configure SPI2 to operate in Slave mode.
+
+config ESPRESSIF_SPI2_SLAVE_BUFSIZE
+	int "SPI2 Slave buffer size"
+	default 2048
+	depends on ESPRESSIF_SPI2_SLAVE
+	---help---
+		Configure the size of SPI2 Slave controller's internal buffers.
+
 config ESPRESSIF_SPI2_CSPIN
 	int "SPI2 CS Pin"
 	default 10
diff --git a/arch/risc-v/src/common/espressif/Make.defs b/arch/risc-v/src/common/espressif/Make.defs
index 1c1b418a50..9daf4e270e 100644
--- a/arch/risc-v/src/common/espressif/Make.defs
+++ b/arch/risc-v/src/common/espressif/Make.defs
@@ -86,6 +86,9 @@ endif
 
 ifeq ($(CONFIG_ESPRESSIF_SPI),y)
 	CHIP_CSRCS += esp_spi.c
+	ifeq ($(CONFIG_SPI_SLAVE),y)
+		CHIP_CSRCS += esp_spi_slave.c
+	endif
 endif
 
 ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y)
diff --git a/arch/risc-v/src/common/espressif/esp_spi.h b/arch/risc-v/src/common/espressif/esp_spi.h
index d565141518..5979f7e2dc 100644
--- a/arch/risc-v/src/common/espressif/esp_spi.h
+++ b/arch/risc-v/src/common/espressif/esp_spi.h
@@ -126,6 +126,39 @@ int esp_spi2_cmddata(struct spi_dev_s *dev,
 
 int esp_spibus_uninitialize(struct spi_dev_s *dev);
 
+/****************************************************************************
+ * Name: esp_spislave_ctrlr_initialize
+ *
+ * Description:
+ *   Initialize the selected SPI Slave bus.
+ *
+ * Input Parameters:
+ *   port - Port number (for hardware that has multiple SPI Slave interfaces)
+ *
+ * Returned Value:
+ *   Valid SPI Slave controller structure reference on success;
+ *   NULL on failure.
+ *
+ ****************************************************************************/
+
+struct spi_slave_ctrlr_s *esp_spislave_ctrlr_initialize(int port);
+
+/****************************************************************************
+ * Name: esp_spislave_ctrlr_uninitialize
+ *
+ * Description:
+ *   Uninitialize an SPI Slave bus.
+ *
+ * Input Parameters:
+ *   ctrlr - SPI Slave controller interface instance
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success. Otherwise -1 (ERROR).
+ *
+ ****************************************************************************/
+
+int esp_spislave_ctrlr_uninitialize(struct spi_slave_ctrlr_s *ctrlr);
+
 #endif /* CONFIG_ESPRESSIF_SPI */
 
 #ifdef __cplusplus
diff --git a/arch/risc-v/src/common/espressif/esp_spi_slave.c b/arch/risc-v/src/common/espressif/esp_spi_slave.c
new file mode 100644
index 0000000000..645993e090
--- /dev/null
+++ b/arch/risc-v/src/common/espressif/esp_spi_slave.c
@@ -0,0 +1,940 @@
+/****************************************************************************
+ * arch/risc-v/src/common/espressif/esp_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_ESPRESSIF_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/spi/spi.h>
+#include <nuttx/spi/slave.h>
+
+#include <arch/board/board.h>
+
+#include "esp_spi.h"
+#include "esp_irq.h"
+#include "esp_gpio.h"
+#include "hal/spi_ll.h"
+#include "hal/spi_hal.h"
+#include "hal/spi_slave_hal.h"
+#include "periph_ctrl.h"
+
+#include "riscv_internal.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#define SPI_SLAVE_BUFSIZE (CONFIG_ESPRESSIF_SPI2_SLAVE_BUFSIZE)
+
+/* Verify whether SPI has been assigned IOMUX pins.
+ * Otherwise, SPI signals will be routed via GPIO Matrix.
+ */
+
+#define SPI_IS_CS_IOMUX   (CONFIG_ESPRESSIF_SPI2_CSPIN == SPI2_IOMUX_CSPIN)
+#define SPI_IS_CLK_IOMUX  (CONFIG_ESPRESSIF_SPI2_CLKPIN == SPI2_IOMUX_CLKPIN)
+#define SPI_IS_MOSI_IOMUX (CONFIG_ESPRESSIF_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN)
+#define SPI_IS_MISO_IOMUX (CONFIG_ESPRESSIF_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)
+
+/* SPI Slave default width */
+
+#define SPI_SLAVE_DEFAULT_WIDTH (8)
+
+/* SPI Slave default mode */
+
+#define SPI_SLAVE_DEFAULT_MODE  (SPISLAVE_MODE0)
+
+#define WORDS2BYTES(_priv, _wn)   ((_wn) * ((_priv)->nbits / 8))
+#define BYTES2WORDS(_priv, _bn)   ((_bn) / ((_priv)->nbits / 8))
+
+/* 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 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 */
+  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 cpuint;                   /* SPI interrupt ID */
+  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;
+  int module;                   /* Peripheral module */
+  spi_slave_hal_context_t ctx;  /* Context struct of the common layer */
+  spi_slave_hal_config_t cfg;   /* Configuration struct of the common layer */
+};
+
+/****************************************************************************
+ * 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_evict_sent_data(struct spislave_priv_s *priv,
+                                     uint32_t sent_bytes);
+static void spislave_initialize(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
+ ****************************************************************************/
+
+#ifdef CONFIG_ESPRESSIF_SPI2
+static const struct spislave_config_s esp_spi2slave_config =
+{
+  .width        = SPI_SLAVE_DEFAULT_WIDTH,
+  .mode         = SPI_SLAVE_DEFAULT_MODE,
+  .cs_pin       = CONFIG_ESPRESSIF_SPI2_CSPIN,
+  .mosi_pin     = CONFIG_ESPRESSIF_SPI2_MOSIPIN,
+  .miso_pin     = CONFIG_ESPRESSIF_SPI2_MISOPIN,
+  .clk_pin      = CONFIG_ESPRESSIF_SPI2_CLKPIN,
+  .periph       = ETS_SPI2_INTR_SOURCE,
+  .irq          = ESP_IRQ_SPI2,
+  .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 esp_spi2slave_ops =
+{
+  .bind     = spislave_bind,
+  .unbind   = spislave_unbind,
+  .enqueue  = spislave_enqueue,
+  .qfull    = spislave_qfull,
+  .qflush   = spislave_qflush,
+  .qpoll    = spislave_qpoll
+};
+
+static struct spislave_priv_s esp_spi2slave_priv =
+{
+  .ctrlr         =
+                  {
+                    .ops = &esp_spi2slave_ops
+                  },
+  .dev           = NULL,
+  .config        = &esp_spi2slave_config,
+  .refs          = 0,
+  .cpuint        = -ENOMEM,
+  .mode          = SPISLAVE_MODE0,
+  .nbits         = 0,
+  .tx_length     = 0,
+  .tx_buffer     =
+                  {
+                    0
+                  },
+  .rx_length     = 0,
+  .rx_buffer     =
+                  {
+                    0
+                  },
+  .is_processing = false,
+  .is_tx_enabled = false,
+  .module = PERIPH_SPI2_MODULE,
+  .ctx =
+          {
+            0
+          },
+  .cfg =
+          {
+            .host_id = SPI2_HOST,
+          }
+};
+#endif /* CONFIG_ESPRESSIF_SPI2 */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * 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:
+ *   hw - Beginning address of the peripheral register
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline void spislave_cpu_tx_fifo_reset(spi_dev_t *hw)
+{
+  spi_ll_cpu_tx_fifo_reset(hw);
+}
+
+/****************************************************************************
+ * 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_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_prepare_next_tx
+ *
+ * Description:
+ *   Prepare the SPI Slave controller for transmitting data on the next
+ *   transaction.
+ *
+ * Input Parameters:
+ *   priv - Private SPI Slave controller structure
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void spislave_prepare_next_tx(struct spislave_priv_s *priv)
+{
+  if (priv->tx_length != 0)
+    {
+      spi_slave_hal_prepare_data(&priv->ctx);
+      priv->is_tx_enabled = true;
+    }
+  else
+    {
+      spiwarn("TX buffer empty! Disabling TX for next transaction\n");
+
+      spislave_cpu_tx_fifo_reset(priv->ctx.hw);
+
+      priv->is_tx_enabled = false;
+    }
+}
+
+/****************************************************************************
+ * Name: spislave_periph_interrupt
+ *
+ * Description:
+ *   Handler for the SPI Slave controller interrupt which is triggered when a
+ *   transfer is finished.
+ *
+ * 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_periph_interrupt(int irq, void *context, void *arg)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)arg;
+
+  uint32_t transfer_size = spi_slave_hal_get_rcv_bitlen(&priv->ctx) / 8;
+
+  if (!priv->is_processing)
+    {
+      SPIS_DEV_SELECT(priv->dev, true);
+      priv->is_processing = true;
+    }
+
+  /* RX process */
+
+  if (transfer_size > 0)
+    {
+      spi_slave_hal_store_result(&priv->ctx);
+      priv->rx_length += transfer_size;
+    }
+
+  /* TX process */
+
+  if (transfer_size > 0 && priv->is_tx_enabled)
+    {
+      spislave_evict_sent_data(priv, transfer_size);
+    }
+
+  priv->ctx.bitlen = priv->tx_length;
+  priv->ctx.rx_buffer = priv->rx_buffer;
+  priv->ctx.tx_buffer = priv->tx_buffer;
+  spislave_prepare_next_tx(priv);
+
+  if (priv->is_processing && esp_gpioread(priv->config->cs_pin))
+    {
+      priv->is_processing = false;
+      SPIS_DEV_SELECT(priv->dev, false);
+    }
+
+  /* Clear the trans_done interrupt flag */
+
+  /* Trigger the start of user-defined transaction */
+
+  spi_slave_hal_user_start(&priv->ctx);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: spislave_initialize
+ *
+ * Description:
+ *   Initialize SPI Slave hardware interface.
+ *
+ * Input Parameters:
+ *   ctrlr - SPI Slave controller interface instance
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
+  const struct spislave_config_s *config = priv->config;
+
+  spiinfo("ctrlr=%p\n", ctrlr);
+
+  esp_gpiowrite(config->cs_pin, 1);
+  esp_gpiowrite(config->mosi_pin, 1);
+  esp_gpiowrite(config->miso_pin, 1);
+  esp_gpiowrite(config->clk_pin, 1);
+
+#if SPI_VIA_IOMUX
+  esp_configgpio(config->cs_pin, INPUT_FUNCTION_3 | PULLUP);
+  esp_gpio_matrix_out(config->cs_pin, SIG_GPIO_OUT_IDX, 0, 0);
+
+  esp_configgpio(config->mosi_pin, INPUT_FUNCTION_3 | PULLUP);
+  esp_gpio_matrix_out(config->mosi_pin, SIG_GPIO_OUT_IDX, 0, 0);
+
+  esp_configgpio(config->miso_pin, OUTPUT_FUNCTION_3);
+  esp_gpio_matrix_out(config->miso_pin, SIG_GPIO_OUT_IDX, 0, 0);
+
+  esp_configgpio(config->clk_pin, INPUT_FUNCTION_3 | PULLUP);
+  esp_gpio_matrix_out(config->clk_pin, SIG_GPIO_OUT_IDX, 0, 0);
+#else
+  esp_configgpio(config->cs_pin, INPUT_FUNCTION_2 | PULLUP);
+  esp_gpio_matrix_in(config->cs_pin, config->cs_insig, 0);
+
+  esp_configgpio(config->mosi_pin, INPUT_FUNCTION_2 | PULLUP);
+  esp_gpio_matrix_in(config->mosi_pin, config->mosi_insig, 0);
+
+  esp_configgpio(config->miso_pin, OUTPUT_FUNCTION_2);
+  esp_gpio_matrix_out(config->miso_pin, config->miso_outsig, 0, 0);
+
+  esp_configgpio(config->clk_pin, INPUT_FUNCTION_2 | PULLUP);
+  esp_gpio_matrix_in(config->clk_pin, config->clk_insig, 0);
+#endif
+
+  esp_gpioirqenable(ESP_PIN2IRQ(config->cs_pin), RISING);
+
+  priv->ctx.rx_lsbfirst = 0;
+  priv->ctx.tx_lsbfirst = 0;
+
+  priv->ctx.dmadesc_n = 0;
+  priv->ctx.use_dma = 0;
+}
+
+/****************************************************************************
+ * Name: spislave_bind
+ *
+ * Description:
+ *   Bind the SPI Slave device interface to the SPI Slave controller
+ *   interface and configure the SPI interface. Upon return, the SPI
+ *   slave controller driver is fully operational and ready to perform
+ *   transfers.
+ *
+ * Input Parameters:
+ *   ctrlr - SPI Slave controller interface instance
+ *   dev   - SPI Slave device interface instance
+ *   mode  - The SPI mode requested
+ *   nbits - The number of bits requests.
+ *            If value is greater than 0, then it implies MSB first
+ *            If value is less than 0, then it implies LSB first with -nbits
+ *
+ * Returned Value:
+ *   None.
+ *
+ * Assumptions:
+ *   This implementation currently supports only positive "nbits" values,
+ *   i.e., it always configures the SPI Slave controller driver as MSB first.
+ *
+ ****************************************************************************/
+
+static void spislave_bind(struct spi_slave_ctrlr_s *ctrlr,
+                          struct spi_slave_dev_s *dev,
+                          enum spi_slave_mode_e mode,
+                          int nbits)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
+  const void *data = NULL;
+  irqstate_t flags;
+  size_t num_words;
+
+  spiinfo("ctrlr=%p dev=%p mode=%d nbits=%d\n", ctrlr, dev, mode, nbits);
+
+  DEBUGASSERT(priv != NULL);
+  DEBUGASSERT(priv->dev == NULL);
+  DEBUGASSERT(dev != NULL);
+  DEBUGASSERT(nbits > 0);
+
+  flags = enter_critical_section();
+
+  priv->dev = dev;
+
+  SPIS_DEV_SELECT(dev, false);
+
+  SPIS_DEV_CMDDATA(dev, false);
+
+  priv->rx_length = 0;
+  priv->tx_length = 0;
+  priv->is_tx_enabled = false;
+  priv->nbits = nbits;
+  priv->ctx.mode = mode;
+
+  /* Configure SPI Slave peripheral */
+
+  spislave_initialize(ctrlr);
+  periph_module_enable(priv->module);
+  spi_slave_hal_init(&priv->ctx, &priv->cfg);
+  spi_slave_hal_setup_device(&priv->ctx);
+
+  num_words = SPIS_DEV_GETDATA(dev, &data);
+
+  if (data != NULL && num_words > 0)
+    {
+      size_t num_bytes = WORDS2BYTES(priv, num_words);
+      memcpy(priv->tx_buffer, data, num_bytes);
+      priv->tx_length += num_bytes;
+    }
+
+  /* Enable the CPU interrupt that is linked to the SPI Slave controller */
+
+  up_enable_irq(priv->config->irq);
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: spislave_unbind
+ *
+ * Description:
+ *   Un-bind the SPI Slave device interface from the SPI Slave controller
+ *   interface. Reset the SPI interface and restore the SPI Slave
+ *   controller driver to its initial state.
+ *
+ * Input Parameters:
+ *   ctrlr - SPI Slave controller interface instance
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void spislave_unbind(struct spi_slave_ctrlr_s *ctrlr)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
+  irqstate_t flags;
+
+  DEBUGASSERT(priv != NULL);
+  DEBUGASSERT(priv->dev != NULL);
+
+  spiinfo("Unbinding %p\n", priv->dev);
+
+  flags = enter_critical_section();
+
+  up_disable_irq(priv->config->irq);
+
+  esp_gpioirqdisable(ESP_PIN2IRQ(priv->config->cs_pin));
+
+  /* Disable the trans_done interrupt */
+
+  periph_module_disable(priv->module);
+
+  priv->dev = NULL;
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: spislave_enqueue
+ *
+ * Description:
+ *   Enqueue the next value to be shifted out from the interface. This adds
+ *   the word to the controller driver for a subsequent transfer but has no
+ *   effect on any in-process or currently "committed" transfers.
+ *
+ * Input Parameters:
+ *   ctrlr - SPI Slave controller interface instance
+ *   data  - Pointer to the command/data mode data to be shifted out.
+ *           The data width must be aligned to the nbits parameter which was
+ *           previously provided to the bind() method.
+ *   len   - Number of units of "nbits" wide to enqueue,
+ *           "nbits" being the data width previously provided to the bind()
+ *           method.
+ *
+ * Returned Value:
+ *   Number of data items successfully queued, or a negated errno:
+ *         - "len" if all the data was successfully queued
+ *         - "0..len-1" if queue is full
+ *         - "-errno" in any other error
+ *
+ ****************************************************************************/
+
+static int spislave_enqueue(struct spi_slave_ctrlr_s *ctrlr,
+                            const void *data,
+                            size_t len)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
+  size_t num_bytes = WORDS2BYTES(priv, len);
+  size_t bufsize;
+  irqstate_t flags;
+  int enqueued_words;
+
+  spiinfo("ctrlr=%p, data=%p, num_bytes=%zu\n", ctrlr, data, num_bytes);
+
+  DEBUGASSERT(priv != NULL);
+  DEBUGASSERT(priv->dev != NULL);
+
+  flags = enter_critical_section();
+
+  bufsize = SPI_SLAVE_BUFSIZE - priv->tx_length;
+  if (bufsize == 0)
+    {
+      leave_critical_section(flags);
+      return -ENOSPC;
+    }
+
+  num_bytes = MIN(num_bytes, bufsize);
+  memcpy(priv->tx_buffer + priv->tx_length, data, num_bytes);
+  priv->tx_length += num_bytes;
+
+  enqueued_words = BYTES2WORDS(priv, num_bytes);
+
+  if (!priv->is_processing)
+    {
+      spislave_prepare_next_tx(priv);
+    }
+
+  leave_critical_section(flags);
+
+  return enqueued_words;
+}
+
+/****************************************************************************
+ * Name: spislave_qfull
+ *
+ * Description:
+ *   Return true if the queue is full or false if there is space to add an
+ *   additional word to the queue.
+ *
+ * Input Parameters:
+ *   ctrlr - SPI Slave controller interface instance
+ *
+ * Returned Value:
+ *   true if the output queue is full, false otherwise.
+ *
+ ****************************************************************************/
+
+static bool spislave_qfull(struct spi_slave_ctrlr_s *ctrlr)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
+  irqstate_t flags;
+  bool is_full = false;
+
+  DEBUGASSERT(priv != NULL);
+  DEBUGASSERT(priv->dev != NULL);
+
+  spiinfo("ctrlr=%p\n", ctrlr);
+
+  flags = enter_critical_section();
+  is_full = priv->tx_length == SPI_SLAVE_BUFSIZE;
+  leave_critical_section(flags);
+
+  return is_full;
+}
+
+/****************************************************************************
+ * Name: spislave_qflush
+ *
+ * Description:
+ *   Discard all saved values in the output queue. On return from this
+ *   function the output queue will be empty. Any in-progress or otherwise
+ *   "committed" output values may not be flushed.
+ *
+ * Input Parameters:
+ *   ctrlr - SPI Slave controller interface instance
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void spislave_qflush(struct spi_slave_ctrlr_s *ctrlr)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
+  irqstate_t flags;
+
+  DEBUGASSERT(priv != NULL);
+  DEBUGASSERT(priv->dev != NULL);
+
+  spiinfo("ctrlr=%p\n", ctrlr);
+
+  flags = enter_critical_section();
+  priv->tx_length = 0;
+  priv->is_tx_enabled = false;
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: spislave_qpoll
+ *
+ * Description:
+ *   Tell the controller to output all the receive queue data.
+ *
+ * Input Parameters:
+ *   ctrlr - SPI Slave controller interface instance
+ *
+ * Returned Value:
+ *   Number of units of width "nbits" left in the RX queue. If the device
+ *   accepted all the data, the return value will be 0.
+ *
+ ****************************************************************************/
+
+static size_t spislave_qpoll(struct spi_slave_ctrlr_s *ctrlr)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
+  irqstate_t flags;
+  uint32_t tmp;
+  uint32_t recv_n;
+  size_t remaining_words;
+
+  DEBUGASSERT(priv != NULL);
+  DEBUGASSERT(priv->dev != NULL);
+
+  spiinfo("ctrlr=%p\n", ctrlr);
+
+  flags = enter_critical_section();
+
+  tmp = SPIS_DEV_RECEIVE(priv->dev, priv->rx_buffer,
+                         BYTES2WORDS(priv, priv->rx_length));
+  recv_n = WORDS2BYTES(priv, tmp);
+  if (recv_n < priv->rx_length)
+    {
+      /* If the upper layer does not receive all of the data from the receive
+       * buffer, move the remaining data to the head of the buffer.
+       */
+
+      priv->rx_length -= recv_n;
+      memmove(priv->rx_buffer, priv->rx_buffer + recv_n, priv->rx_length);
+    }
+  else
+    {
+      priv->rx_length = 0;
+    }
+
+  remaining_words = BYTES2WORDS(priv, priv->rx_length);
+
+  leave_critical_section(flags);
+
+  return remaining_words;
+}
+
+/****************************************************************************
+ * Name: esp_spislave_ctrlr_initialize
+ *
+ * Description:
+ *   Initialize the selected SPI Slave bus.
+ *
+ * Input Parameters:
+ *   port - Port number (for hardware that has multiple SPI Slave interfaces)
+ *
+ * Returned Value:
+ *   Valid SPI Slave controller structure reference on success;
+ *   NULL on failure.
+ *
+ ****************************************************************************/
+
+struct spi_slave_ctrlr_s *esp_spislave_ctrlr_initialize(int port)
+{
+  struct spi_slave_ctrlr_s *spislave_dev;
+  struct spislave_priv_s *priv;
+  irqstate_t flags;
+
+  switch (port)
+    {
+#ifdef CONFIG_ESPRESSIF_SPI2
+      case ESPRESSIF_SPI2:
+        priv = &esp_spi2slave_priv;
+        break;
+#endif
+      default:
+        return NULL;
+    }
+
+  spislave_dev = (struct spi_slave_ctrlr_s *)priv;
+
+  flags = enter_critical_section();
+
+  if ((volatile int)priv->refs != 0)
+    {
+      leave_critical_section(flags);
+
+      return spislave_dev;
+    }
+
+  /* Attach IRQ for CS pin interrupt */
+
+  DEBUGVERIFY(irq_attach(ESP_PIN2IRQ(priv->config->cs_pin),
+                         spislave_cs_interrupt,
+                         priv));
+
+  if (priv->cpuint != -ENOMEM)
+    {
+      /* Disable the provided CPU Interrupt to configure it. */
+
+      up_disable_irq(priv->config->irq);
+    }
+
+  priv->cpuint = esp_setup_irq(priv->config->periph,
+                               ESP_IRQ_PRIORITY_DEFAULT,
+                               ESP_IRQ_TRIGGER_LEVEL);
+  if (priv->cpuint < 0)
+    {
+      /* Failed to allocate a CPU interrupt of this type. */
+
+      leave_critical_section(flags);
+
+      return NULL;
+    }
+
+  if (irq_attach(priv->config->irq, spislave_periph_interrupt, priv) != OK)
+    {
+      /* Failed to attach IRQ, so CPU interrupt must be freed. */
+
+      esp_teardown_irq(priv->config->periph, priv->cpuint);
+      priv->cpuint = -ENOMEM;
+      leave_critical_section(flags);
+
+      return NULL;
+    }
+
+  priv->refs++;
+
+  leave_critical_section(flags);
+
+  return spislave_dev;
+}
+
+/****************************************************************************
+ * Name: esp_spislave_ctrlr_uninitialize
+ *
+ * Description:
+ *   Uninitialize an SPI Slave bus.
+ *
+ * Input Parameters:
+ *   ctrlr - SPI Slave controller interface instance
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success. Otherwise -1 (ERROR).
+ *
+ ****************************************************************************/
+
+int esp_spislave_ctrlr_uninitialize(struct spi_slave_ctrlr_s *ctrlr)
+{
+  struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
+  irqstate_t flags;
+
+  DEBUGASSERT(ctrlr != NULL);
+
+  if (priv->refs == 0)
+    {
+      return ERROR;
+    }
+
+  flags = enter_critical_section();
+
+  if (--priv->refs)
+    {
+      leave_critical_section(flags);
+      return OK;
+    }
+
+  up_disable_irq(priv->config->irq);
+  esp_teardown_irq(priv->config->periph, priv->cpuint);
+  priv->cpuint = -ENOMEM;
+
+  esp_gpioirqdisable(ESP_PIN2IRQ(priv->config->cs_pin));
+  periph_module_disable(priv->module);
+
+  priv->cpuint = -ENOMEM;
+  priv->mode = SPISLAVE_MODE0;
+  priv->nbits = 0;
+  priv->tx_length = 0;
+  priv->rx_length = 0;
+  priv->is_processing = false;
+  priv->is_tx_enabled = false;
+
+  leave_critical_section(flags);
+
+  return OK;
+}
+
+#endif /* defined(CONFIG_ESPRESSIF_SPI) && defined (CONFIG_SPI_SLAVE) */
diff --git a/arch/risc-v/src/esp32c3/hal_esp32c3.mk b/arch/risc-v/src/esp32c3/hal_esp32c3.mk
index 68ea1ebcb0..e12dc422ac 100644
--- a/arch/risc-v/src/esp32c3/hal_esp32c3.mk
+++ b/arch/risc-v/src/esp32c3/hal_esp32c3.mk
@@ -132,6 +132,8 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)uart_hal.c
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)uart_hal_iram.c
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)wdt_hal_iram.c
+CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_slave_hal_iram.c
+CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_slave_hal.c
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)xt_wdt_hal.c
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)$(CHIP_SERIES)$(DELIM)clk_tree_hal.c
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)$(CHIP_SERIES)$(DELIM)efuse_hal.c
diff --git a/arch/risc-v/src/esp32c6/hal_esp32c6.mk b/arch/risc-v/src/esp32c6/hal_esp32c6.mk
index 915faf55e4..0ff90470b3 100644
--- a/arch/risc-v/src/esp32c6/hal_esp32c6.mk
+++ b/arch/risc-v/src/esp32c6/hal_esp32c6.mk
@@ -137,6 +137,8 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)uart_hal.c
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)uart_hal_iram.c
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)wdt_hal_iram.c
+CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_slave_hal_iram.c
+CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_slave_hal.c
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)$(CHIP_SERIES)$(DELIM)clk_tree_hal.c
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)$(CHIP_SERIES)$(DELIM)efuse_hal.c
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)$(CHIP_SERIES)$(DELIM)modem_clock_hal.c
diff --git a/arch/risc-v/src/esp32h2/hal_esp32h2.mk b/arch/risc-v/src/esp32h2/hal_esp32h2.mk
index d46ccba76a..f9fb63a08a 100644
--- a/arch/risc-v/src/esp32h2/hal_esp32h2.mk
+++ b/arch/risc-v/src/esp32h2/hal_esp32h2.mk
@@ -120,6 +120,8 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)uart_hal.c
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)uart_hal_iram.c
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)wdt_hal_iram.c
+CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_slave_hal_iram.c
+CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_slave_hal.c
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)$(CHIP_SERIES)$(DELIM)clk_tree_hal.c
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)$(CHIP_SERIES)$(DELIM)efuse_hal.c
 CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)$(CHIP_SERIES)$(DELIM)modem_clock_hal.c
diff --git a/boards/risc-v/esp32c3/common/include/esp_board_spislavedev.h b/boards/risc-v/esp32c3/common/include/esp_board_spislavedev.h
new file mode 100644
index 0000000000..f87f905d17
--- /dev/null
+++ b/boards/risc-v/esp32c3/common/include/esp_board_spislavedev.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+ * boards/risc-v/esp32c3/common/include/esp_board_spislavedev.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __BOARDS_RISCV_ESP32C3_COMMON_INCLUDE_ESP_BOARD_SPISLAVEDEV_H
+#define __BOARDS_RISCV_ESP32C3_COMMON_INCLUDE_ESP_BOARD_SPISLAVEDEV_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_spislavedev_initialize
+ *
+ * Description:
+ *   Initialize SPI Slave driver and register the /dev/spislv device.
+ *
+ * Input Parameters:
+ *   bus - The SPI bus number, used to build the device path as /dev/spislvN
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned
+ *   to indicate the nature of any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_SLAVE
+int board_spislavedev_initialize(int bus);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __BOARDS_RISCV_ESP32C3_COMMON_INCLUDE_ESP_BOARD_SPISLAVEDEV_H */
diff --git a/boards/risc-v/esp32c3/common/src/Make.defs b/boards/risc-v/esp32c3/common/src/Make.defs
index 67892bf2ba..bf7869e3b8 100644
--- a/boards/risc-v/esp32c3/common/src/Make.defs
+++ b/boards/risc-v/esp32c3/common/src/Make.defs
@@ -36,6 +36,10 @@ ifeq ($(CONFIG_SPI_DRIVER),y)
   CSRCS += esp_board_spidev.c
 endif
 
+ifeq ($(CONFIG_SPI_SLAVE_DRIVER),y)
+  CSRCS += esp_board_spislavedev.c
+endif
+
 ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y)
   CSRCS += esp_board_spiflash.c
 endif
diff --git a/boards/risc-v/esp32c3/common/src/esp_board_spislavedev.c b/boards/risc-v/esp32c3/common/src/esp_board_spislavedev.c
new file mode 100644
index 0000000000..1b9d3bacc4
--- /dev/null
+++ b/boards/risc-v/esp32c3/common/src/esp_board_spislavedev.c
@@ -0,0 +1,82 @@
+/****************************************************************************
+ * boards/risc-v/esp32c3/common/src/esp_board_spislavedev.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>
+
+#include <stdio.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/spi/slave.h>
+
+#include "espressif/esp_spi.h"
+
+#include "esp_board_spislavedev.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_spislavedev_initialize
+ *
+ * Description:
+ *   Initialize SPI Slave driver and register the /dev/spislv device.
+ *
+ * Input Parameters:
+ *   bus - The SPI bus number, used to build the device path as /dev/spislvN
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned
+ *   to indicate the nature of any failure.
+ *
+ ****************************************************************************/
+
+int board_spislavedev_initialize(int bus)
+{
+  int ret;
+
+  struct spi_slave_ctrlr_s *ctrlr;
+
+  spiinfo("Initializing /dev/spislv%d...\n", bus);
+
+  /* Initialize SPI Slave controller device */
+
+  ctrlr = esp_spislave_ctrlr_initialize(bus);
+  if (ctrlr == NULL)
+    {
+      spierr("Failed to initialize SPI%d as slave.\n", bus);
+      return -ENODEV;
+    }
+
+  ret = spi_slave_register(ctrlr, bus);
+  if (ret < 0)
+    {
+      spierr("Failed to register /dev/spislv%d: %d\n", bus, ret);
+
+      esp_spislave_ctrlr_uninitialize(ctrlr);
+    }
+
+  return ret;
+}
diff --git a/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_bringup.c b/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_bringup.c
index 420476536e..41151e4a01 100644
--- a/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_bringup.c
+++ b/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_bringup.c
@@ -78,6 +78,11 @@
 #  include "esp_board_wlan.h"
 #endif
 
+#ifdef CONFIG_SPI_SLAVE_DRIVER
+#  include "espressif/esp_spi.h"
+#  include "esp_board_spislavedev.h"
+#endif
+
 #include "esp32c3-generic.h"
 
 /****************************************************************************
@@ -211,6 +216,15 @@ int esp_bringup(void)
     }
 #endif
 
+#if defined(CONFIG_SPI_SLAVE_DRIVER) && defined(CONFIG_ESPRESSIF_SPI2)
+  ret = board_spislavedev_initialize(ESPRESSIF_SPI2);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "Failed to initialize SPI%d Slave driver: %d\n",
+             ESPRESSIF_SPI2, ret);
+    }
+#endif
+
 #ifdef CONFIG_ONESHOT
   ret = esp_oneshot_initialize();
   if (ret < 0)
diff --git a/boards/risc-v/esp32c6/common/include/esp_board_spislavedev.h b/boards/risc-v/esp32c6/common/include/esp_board_spislavedev.h
new file mode 100644
index 0000000000..10ccd55ede
--- /dev/null
+++ b/boards/risc-v/esp32c6/common/include/esp_board_spislavedev.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+ * boards/risc-v/esp32c6/common/include/esp_board_spislavedev.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __BOARDS_RISCV_ESP32C6_COMMON_INCLUDE_ESP_BOARD_SPISLAVEDEV_H
+#define __BOARDS_RISCV_ESP32C6_COMMON_INCLUDE_ESP_BOARD_SPISLAVEDEV_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_spislavedev_initialize
+ *
+ * Description:
+ *   Initialize SPI Slave driver and register the /dev/spislv device.
+ *
+ * Input Parameters:
+ *   bus - The SPI bus number, used to build the device path as /dev/spislvN
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned
+ *   to indicate the nature of any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_SLAVE
+int board_spislavedev_initialize(int bus);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __BOARDS_RISCV_ESP32C6_COMMON_INCLUDE_ESP_BOARD_SPISLAVEDEV_H */
diff --git a/boards/risc-v/esp32c6/common/src/Make.defs b/boards/risc-v/esp32c6/common/src/Make.defs
index d3240f9ad5..177181975b 100644
--- a/boards/risc-v/esp32c6/common/src/Make.defs
+++ b/boards/risc-v/esp32c6/common/src/Make.defs
@@ -36,6 +36,10 @@ ifeq ($(CONFIG_SPI_DRIVER),y)
   CSRCS += esp_board_spidev.c
 endif
 
+ifeq ($(CONFIG_SPI_SLAVE_DRIVER),y)
+  CSRCS += esp_board_spislavedev.c
+endif
+
 ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y)
   CSRCS += esp_board_spiflash.c
 endif
diff --git a/boards/risc-v/esp32c6/common/src/esp_board_spislavedev.c b/boards/risc-v/esp32c6/common/src/esp_board_spislavedev.c
new file mode 100644
index 0000000000..f81799bb91
--- /dev/null
+++ b/boards/risc-v/esp32c6/common/src/esp_board_spislavedev.c
@@ -0,0 +1,82 @@
+/****************************************************************************
+ * boards/risc-v/esp32c6/common/src/esp_board_spislavedev.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>
+
+#include <stdio.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/spi/slave.h>
+
+#include "espressif/esp_spi.h"
+
+#include "esp_board_spislavedev.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_spislavedev_initialize
+ *
+ * Description:
+ *   Initialize SPI Slave driver and register the /dev/spislv device.
+ *
+ * Input Parameters:
+ *   bus - The SPI bus number, used to build the device path as /dev/spislvN
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned
+ *   to indicate the nature of any failure.
+ *
+ ****************************************************************************/
+
+int board_spislavedev_initialize(int bus)
+{
+  int ret;
+
+  struct spi_slave_ctrlr_s *ctrlr;
+
+  spiinfo("Initializing /dev/spislv%d...\n", bus);
+
+  /* Initialize SPI Slave controller device */
+
+  ctrlr = esp_spislave_ctrlr_initialize(bus);
+  if (ctrlr == NULL)
+    {
+      spierr("Failed to initialize SPI%d as slave.\n", bus);
+      return -ENODEV;
+    }
+
+  ret = spi_slave_register(ctrlr, bus);
+  if (ret < 0)
+    {
+      spierr("Failed to register /dev/spislv%d: %d\n", bus, ret);
+
+      esp_spislave_ctrlr_uninitialize(ctrlr);
+    }
+
+  return ret;
+}
diff --git a/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c b/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c
index 9b115fbd8f..d2af1a6352 100644
--- a/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c
+++ b/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c
@@ -78,6 +78,11 @@
 #  include "esp_board_wlan.h"
 #endif
 
+#ifdef CONFIG_SPI_SLAVE_DRIVER
+#  include "espressif/esp_spi.h"
+#  include "esp_board_spislavedev.h"
+#endif
+
 #include "esp32c6-devkitc.h"
 
 /****************************************************************************
@@ -257,6 +262,15 @@ int esp_bringup(void)
     }
 #endif
 
+#if defined(CONFIG_SPI_SLAVE_DRIVER) && defined(CONFIG_ESPRESSIF_SPI2)
+  ret = board_spislavedev_initialize(ESPRESSIF_SPI2);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "Failed to initialize SPI%d Slave driver: %d\n",
+             ESPRESSIF_SPI2, ret);
+    }
+#endif
+
 #ifdef CONFIG_DEV_GPIO
   ret = esp_gpio_init();
   if (ret < 0)
diff --git a/boards/risc-v/esp32c6/esp32c6-devkitm/src/esp32c6_bringup.c b/boards/risc-v/esp32c6/esp32c6-devkitm/src/esp32c6_bringup.c
index 2ffccd2ccb..d4cf38dc98 100644
--- a/boards/risc-v/esp32c6/esp32c6-devkitm/src/esp32c6_bringup.c
+++ b/boards/risc-v/esp32c6/esp32c6-devkitm/src/esp32c6_bringup.c
@@ -78,6 +78,11 @@
 #  include "esp_board_wlan.h"
 #endif
 
+#ifdef CONFIG_SPI_SLAVE_DRIVER
+#  include "espressif/esp_spi.h"
+#  include "esp_board_spislavedev.h"
+#endif
+
 #include "esp32c6-devkitm.h"
 
 /****************************************************************************
@@ -257,6 +262,15 @@ int esp_bringup(void)
     }
 #endif
 
+#if defined(CONFIG_SPI_SLAVE_DRIVER) && defined(CONFIG_ESPRESSIF_SPI2)
+  ret = board_spislavedev_initialize(ESPRESSIF_SPI2);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "Failed to initialize SPI%d Slave driver: %d\n",
+             ESPRESSIF_SPI2, ret);
+    }
+#endif
+
 #ifdef CONFIG_DEV_GPIO
   ret = esp_gpio_init();
   if (ret < 0)
diff --git a/boards/risc-v/esp32h2/common/include/esp_board_spislavedev.h b/boards/risc-v/esp32h2/common/include/esp_board_spislavedev.h
new file mode 100644
index 0000000000..8b4e4aeda5
--- /dev/null
+++ b/boards/risc-v/esp32h2/common/include/esp_board_spislavedev.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+ * boards/risc-v/esp32h2/common/include/esp_board_spislavedev.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __BOARDS_RISCV_ESP32H2_COMMON_INCLUDE_ESP_BOARD_SPISLAVEDEV_H
+#define __BOARDS_RISCV_ESP32H2_COMMON_INCLUDE_ESP_BOARD_SPISLAVEDEV_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_spislavedev_initialize
+ *
+ * Description:
+ *   Initialize SPI Slave driver and register the /dev/spislv device.
+ *
+ * Input Parameters:
+ *   bus - The SPI bus number, used to build the device path as /dev/spislvN
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned
+ *   to indicate the nature of any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_SLAVE
+int board_spislavedev_initialize(int bus);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __BOARDS_RISCV_ESP32H2_COMMON_INCLUDE_ESP_BOARD_SPISLAVEDEV_H */
diff --git a/boards/risc-v/esp32h2/common/src/Make.defs b/boards/risc-v/esp32h2/common/src/Make.defs
index a8a80f2998..66daeb3213 100644
--- a/boards/risc-v/esp32h2/common/src/Make.defs
+++ b/boards/risc-v/esp32h2/common/src/Make.defs
@@ -36,6 +36,10 @@ ifeq ($(CONFIG_SPI_DRIVER),y)
   CSRCS += esp_board_spidev.c
 endif
 
+ifeq ($(CONFIG_SPI_SLAVE_DRIVER),y)
+  CSRCS += esp_board_spislavedev.c
+endif
+
 ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y)
   CSRCS += esp_board_spiflash.c
 endif
diff --git a/boards/risc-v/esp32h2/common/src/esp_board_spislavedev.c b/boards/risc-v/esp32h2/common/src/esp_board_spislavedev.c
new file mode 100644
index 0000000000..66319f4b09
--- /dev/null
+++ b/boards/risc-v/esp32h2/common/src/esp_board_spislavedev.c
@@ -0,0 +1,82 @@
+/****************************************************************************
+ * boards/risc-v/esp32h2/common/src/esp_board_spislavedev.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>
+
+#include <stdio.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/spi/slave.h>
+
+#include "espressif/esp_spi.h"
+
+#include "esp_board_spislavedev.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_spislavedev_initialize
+ *
+ * Description:
+ *   Initialize SPI Slave driver and register the /dev/spislv device.
+ *
+ * Input Parameters:
+ *   bus - The SPI bus number, used to build the device path as /dev/spislvN
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned
+ *   to indicate the nature of any failure.
+ *
+ ****************************************************************************/
+
+int board_spislavedev_initialize(int bus)
+{
+  int ret;
+
+  struct spi_slave_ctrlr_s *ctrlr;
+
+  spiinfo("Initializing /dev/spislv%d...\n", bus);
+
+  /* Initialize SPI Slave controller device */
+
+  ctrlr = esp_spislave_ctrlr_initialize(bus);
+  if (ctrlr == NULL)
+    {
+      spierr("Failed to initialize SPI%d as slave.\n", bus);
+      return -ENODEV;
+    }
+
+  ret = spi_slave_register(ctrlr, bus);
+  if (ret < 0)
+    {
+      spierr("Failed to register /dev/spislv%d: %d\n", bus, ret);
+
+      esp_spislave_ctrlr_uninitialize(ctrlr);
+    }
+
+  return ret;
+}
diff --git a/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c b/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c
index 0213f5ef4f..8af13b13f3 100644
--- a/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c
+++ b/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c
@@ -70,6 +70,11 @@
 #  include "esp_board_spidev.h"
 #endif
 
+#ifdef CONFIG_SPI_SLAVE_DRIVER
+#  include "espressif/esp_spi.h"
+#  include "esp_board_spislavedev.h"
+#endif
+
 #include "esp32h2-devkit.h"
 
 /****************************************************************************
@@ -224,6 +229,15 @@ int esp_bringup(void)
     }
 #endif
 
+#if defined(CONFIG_SPI_SLAVE_DRIVER) && defined(CONFIG_ESPRESSIF_SPI2)
+  ret = board_spislavedev_initialize(ESPRESSIF_SPI2);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "Failed to initialize SPI%d Slave driver: %d\n",
+             ESPRESSIF_SPI2, ret);
+    }
+#endif
+
 #ifdef CONFIG_DEV_GPIO
   ret = esp_gpio_init();
   if (ret < 0)