You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by pk...@apache.org on 2022/08/11 12:50:00 UTC

[incubator-nuttx] branch master updated: xtensa/esp32s2: Add basic support to SPI

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 0b4ef1406d xtensa/esp32s2: Add basic support to SPI
0b4ef1406d is described below

commit 0b4ef1406d6182e9acaade94862e1f01a5ed955f
Author: Alan Carvalho de Assis <ac...@gmail.com>
AuthorDate: Thu Aug 4 15:16:13 2022 -0300

    xtensa/esp32s2: Add basic support to SPI
---
 arch/xtensa/src/esp32s2/Kconfig                   |   79 ++
 arch/xtensa/src/esp32s2/Make.defs                 |    4 +
 arch/xtensa/src/esp32s2/esp32s2_spi.c             | 1215 +++++++++++++++++++++
 arch/xtensa/src/esp32s2/esp32s2_spi.h             |  150 +++
 arch/xtensa/src/esp32s2/hardware/esp32s2_pinmap.h |   54 +
 arch/xtensa/src/esp32s2/hardware/esp32s2_soc.h    |    2 +
 arch/xtensa/src/esp32s2/hardware/esp32s2_spi.h    |  136 +--
 7 files changed, 1572 insertions(+), 68 deletions(-)

diff --git a/arch/xtensa/src/esp32s2/Kconfig b/arch/xtensa/src/esp32s2/Kconfig
index 01c68a72b4..ff5a671adf 100644
--- a/arch/xtensa/src/esp32s2/Kconfig
+++ b/arch/xtensa/src/esp32s2/Kconfig
@@ -237,6 +237,10 @@ config ESP32S2_I2C
 	bool
 	default n
 
+config ESP32S2_SPI
+	bool
+	default n
+
 config ESP32S2_TIMER
 	bool
 	default n
@@ -252,6 +256,18 @@ config ESP32S2_RNG
 	---help---
 		ESP32-S2 supports a RNG that passed on Dieharder test suite.
 
+config ESP32S2_SPI2
+	bool "SPI 2"
+	default n
+	select ESP32S2_SPI
+	select SPI
+
+config ESP32S2_SPI3
+	bool "SPI 3"
+	default n
+	select ESP32S2_SPI
+	select SPI
+
 config ESP32S2_SPIFLASH
 	bool "SPI Flash"
 	default n
@@ -361,6 +377,69 @@ config ESP32S2_GPIO_IRQ
 	---help---
 		Enable support for interrupting GPIO pins.
 
+menu "SPI configuration"
+	depends on ESP32S2_SPI
+
+config ESP32S2_SPI_SWCS
+	bool "SPI software CS"
+	default n
+	---help---
+		Use SPI software CS.
+
+config ESP32S2_SPI_UDCS
+	bool "User defined CS"
+	default n
+	depends on ESP32S2_SPI_SWCS
+	---help---
+		Use user-defined CS.
+
+if ESP32S2_SPI2
+config ESP32S2_SPI2_CSPIN
+	int "SPI2 CS Pin"
+	default 10
+	range 0 48
+
+config ESP32S2_SPI2_CLKPIN
+	int "SPI2 CLK Pin"
+	default 12
+	range 0 48
+
+config ESP32S2_SPI2_MOSIPIN
+	int "SPI2 MOSI Pin"
+	default 11
+	range 0 48
+
+config ESP32S2_SPI2_MISOPIN
+	int "SPI2 MISO Pin"
+	default 13
+	range 0 48
+
+endif # ESP32S2_SPI2
+
+if ESP32S2_SPI3
+config ESP32S2_SPI3_CSPIN
+	int "SPI3 CS Pin"
+	default 10
+	range 0 48
+
+config ESP32S2_SPI3_CLKPIN
+	int "SPI3 CLK Pin"
+	default 12
+	range 0 48
+
+config ESP32S2_SPI3_MOSIPIN
+	int "SPI3 MOSI Pin"
+	default 11
+	range 0 48
+
+config ESP32S2_SPI3_MISOPIN
+	int "SPI3 MISO Pin"
+	default 13
+	range 0 48
+
+endif # ESP32S2_SPI3
+endmenu
+
 menu "UART Configuration"
 	depends on ESP32S2_UART
 
diff --git a/arch/xtensa/src/esp32s2/Make.defs b/arch/xtensa/src/esp32s2/Make.defs
index db87863817..6d79385633 100644
--- a/arch/xtensa/src/esp32s2/Make.defs
+++ b/arch/xtensa/src/esp32s2/Make.defs
@@ -49,6 +49,10 @@ ifeq ($(CONFIG_ESP32S2_I2C),y)
 CHIP_CSRCS += esp32s2_i2c.c
 endif
 
+ifeq ($(CONFIG_ESP32S2_SPI),y)
+CHIP_CSRCS += esp32s2_spi.c
+endif
+
 ifeq ($(CONFIG_ESP32S2_TIMER),y)
 CHIP_CSRCS += esp32s2_tim.c
 ifeq ($(CONFIG_TIMER),y)
diff --git a/arch/xtensa/src/esp32s2/esp32s2_spi.c b/arch/xtensa/src/esp32s2/esp32s2_spi.c
new file mode 100644
index 0000000000..d86f418846
--- /dev/null
+++ b/arch/xtensa/src/esp32s2/esp32s2_spi.c
@@ -0,0 +1,1215 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_spi.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifdef CONFIG_ESP32S2_SPI
+
+#include <assert.h>
+#include <debug.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/spi/spi.h>
+
+#include <arch/board/board.h>
+
+#include "esp32s2_spi.h"
+#include "esp32s2_irq.h"
+#include "esp32s2_gpio.h"
+
+#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"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Check if Chip-Select pin will be controlled via software */
+
+#ifdef CONFIG_ESP32S2_SPI_SWCS
+#  define SPI_HAVE_SWCS 1
+#else
+#  define SPI_HAVE_SWCS 0
+#endif
+
+/* SPI default frequency (limited by clock divider) */
+
+#define SPI_DEFAULT_FREQ  (400000)
+
+/* SPI default width */
+
+#define SPI_DEFAULT_WIDTH (8)
+
+/* SPI default mode */
+
+#define SPI_DEFAULT_MODE  (SPIDEV_MODE0)
+
+/* SPI Maximum buffer size in bytes */
+
+#define SPI_MAX_BUF_SIZE (64)
+
+#ifndef MIN
+#  define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* SPI Device hardware configuration */
+
+struct esp32s2_spi_config_s
+{
+  uint32_t clk_freq;          /* SPI default clock frequency */
+  uint32_t width;             /* SPI default width */
+  enum spi_mode_e mode;       /* SPI default mode */
+
+  uint8_t id;                 /* ESP32-S2 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 */
+  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 esp32s2_spi_priv_s
+{
+  /* Externally visible part of the SPI interface */
+
+  struct spi_dev_s spi_dev;
+
+  /* Port configuration */
+
+  const struct esp32s2_spi_config_s *config;
+  int refs;             /* Reference count */
+  sem_t exclsem;        /* Held while chip is selected for mutual exclusion */
+  uint32_t frequency;   /* Requested clock frequency */
+  uint32_t actual;      /* Actual clock frequency */
+  enum spi_mode_e mode; /* Actual SPI hardware mode */
+  uint8_t nbits;        /* Actual SPI send/receive bits once transmission */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int esp32s2_spi_lock(struct spi_dev_s *dev, bool lock);
+#ifndef CONFIG_ESP32S2_SPI_UDCS
+static void esp32s2_spi_select(struct spi_dev_s *dev,
+                               uint32_t devid, bool selected);
+#endif
+static uint32_t esp32s2_spi_setfrequency(struct spi_dev_s *dev,
+                                         uint32_t frequency);
+static void esp32s2_spi_setmode(struct spi_dev_s *dev,
+                                enum spi_mode_e mode);
+static void esp32s2_spi_setbits(struct spi_dev_s *dev, int nbits);
+#ifdef CONFIG_SPI_HWFEATURES
+static int esp32s2_spi_hwfeatures(struct spi_dev_s *dev,
+                                  spi_hwfeatures_t features);
+#endif
+static uint32_t esp32s2_spi_send(struct spi_dev_s *dev, uint32_t wd);
+static void esp32s2_spi_exchange(struct spi_dev_s *dev,
+                                 const void *txbuffer,
+                                 void *rxbuffer, size_t nwords);
+static void esp32s2_spi_poll_exchange(struct esp32s2_spi_priv_s *priv,
+                                      const void *txbuffer,
+                                      void *rxbuffer,
+                                      size_t nwords);
+#ifndef CONFIG_SPI_EXCHANGE
+static void esp32s2_spi_sndblock(struct spi_dev_s *dev,
+                                 const void *txbuffer,
+                                 size_t nwords);
+static void esp32s2_spi_recvblock(struct spi_dev_s *dev,
+                                  void *rxbuffer,
+                                  size_t nwords);
+#endif
+#ifdef CONFIG_SPI_TRIGGER
+static int esp32s2_spi_trigger(struct spi_dev_s *dev);
+#endif
+static void esp32s2_spi_init(struct spi_dev_s *dev);
+static void esp32s2_spi_deinit(struct spi_dev_s *dev);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_SPI2
+static const struct esp32s2_spi_config_s esp32s2_spi2_config =
+{
+  .clk_freq     = SPI_DEFAULT_FREQ,
+  .width        = SPI_DEFAULT_WIDTH,
+  .id           = 2,
+  .mode         = SPI_DEFAULT_MODE,
+  .cs_pin       = CONFIG_ESP32S2_SPI2_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S2_SPI2_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S2_SPI2_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S2_SPI2_CLKPIN,
+  .clk_bit      = SYSTEM_SPI2_CLK_EN,
+  .rst_bit      = SYSTEM_SPI2_RST,
+  .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_ops_s esp32s2_spi2_ops =
+{
+#ifdef CONFIG_ESP32S2_SPI_UDCS
+  .select            = esp32s2_spi2_select,
+#else
+  .select            = esp32s2_spi_select,
+#endif
+  .setfrequency      = esp32s2_spi_setfrequency,
+  .setmode           = esp32s2_spi_setmode,
+  .setbits           = esp32s2_spi_setbits,
+#ifdef CONFIG_SPI_HWFEATURES
+  .hwfeatures        = esp32s2_spi_hwfeatures,
+#endif
+  .status            = esp32s2_spi2_status,
+#ifdef CONFIG_SPI_CMDDATA
+  .cmddata           = esp32s2_spi2_cmddata,
+#endif
+  .send              = esp32s2_spi_send,
+#ifdef CONFIG_SPI_EXCHANGE
+  .exchange          = esp32s2_spi_exchange,
+#else
+  .sndblock          = esp32s2_spi_sndblock,
+  .recvblock         = esp32s2_spi_recvblock,
+#endif
+#ifdef CONFIG_SPI_TRIGGER
+  .trigger           = esp32s2_spi_trigger,
+#endif
+  .registercallback  = NULL,
+};
+
+static struct esp32s2_spi_priv_s esp32s2_spi2_priv =
+{
+  .spi_dev     =
+    {
+      .ops = &esp32s2_spi2_ops
+    },
+  .config      = &esp32s2_spi2_config,
+  .refs        = 0,
+  .exclsem     = SEM_INITIALIZER(0),
+  .frequency   = 0,
+  .actual      = 0,
+  .mode        = 0,
+  .nbits       = 0
+};
+#endif /* CONFIG_ESP32S2_SPI2 */
+
+#ifdef CONFIG_ESP32S2_SPI3
+static const struct esp32s2_spi_config_s esp32s2_spi3_config =
+{
+  .clk_freq     = SPI_DEFAULT_FREQ,
+  .width        = SPI_DEFAULT_WIDTH,
+  .id           = 3,
+  .mode         = SPI_DEFAULT_MODE,
+  .cs_pin       = CONFIG_ESP32S2_SPI3_CSPIN,
+  .mosi_pin     = CONFIG_ESP32S2_SPI3_MOSIPIN,
+  .miso_pin     = CONFIG_ESP32S2_SPI3_MISOPIN,
+  .clk_pin      = CONFIG_ESP32S2_SPI3_CLKPIN,
+  .clk_bit      = SYSTEM_SPI3_CLK_EN,
+  .rst_bit      = SYSTEM_SPI3_RST,
+  .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_ops_s esp32s2_spi3_ops =
+{
+#ifdef CONFIG_ESP32S2_SPI_UDCS
+  .select            = esp32s2_spi3_select,
+#else
+  .select            = esp32s2_spi_select,
+#endif
+  .setfrequency      = esp32s2_spi_setfrequency,
+  .setmode           = esp32s2_spi_setmode,
+  .setbits           = esp32s2_spi_setbits,
+#ifdef CONFIG_SPI_HWFEATURES
+  .hwfeatures        = esp32s2_spi_hwfeatures,
+#endif
+  .status            = esp32s2_spi3_status,
+#ifdef CONFIG_SPI_CMDDATA
+  .cmddata           = esp32s2_spi3_cmddata,
+#endif
+  .send              = esp32s2_spi_send,
+#ifdef CONFIG_SPI_EXCHANGE
+  .exchange          = esp32s2_spi_exchange,
+#else
+  .sndblock          = esp32s2_spi_sndblock,
+  .recvblock         = esp32s2_spi_recvblock,
+#endif
+#ifdef CONFIG_SPI_TRIGGER
+  .trigger           = esp32s2_spi_trigger,
+#endif
+  .registercallback  = NULL,
+};
+
+static struct esp32s2_spi_priv_s esp32s2_spi3_priv =
+{
+  .spi_dev     =
+    {
+      .ops = &esp32s2_spi3_ops
+    },
+  .config      = &esp32s2_spi3_config,
+  .refs        = 0,
+  .exclsem     = SEM_INITIALIZER(0),
+  .frequency   = 0,
+  .actual      = 0,
+  .mode        = 0,
+  .nbits       = 0
+};
+#endif /* CONFIG_ESP32S2_SPI3 */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s2_spi_set_regbits
+ *
+ * Description:
+ *   Set the bits of the SPI register.
+ *
+ * Input Parameters:
+ *   addr   - Address of the register of interest
+ *   bits   - Bits to be set
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline void esp32s2_spi_set_regbits(uint32_t addr, uint32_t bits)
+{
+  uint32_t tmp = getreg32(addr);
+
+  putreg32(tmp | bits, addr);
+}
+
+/****************************************************************************
+ * Name: esp32s2_spi_clr_regbits
+ *
+ * Description:
+ *   Clear the bits of the SPI register.
+ *
+ * Input Parameters:
+ *   addr   - Address of the register of interest
+ *   bits   - Bits to be cleared
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline void esp32s2_spi_clr_regbits(uint32_t addr, uint32_t bits)
+{
+  uint32_t tmp = getreg32(addr);
+
+  putreg32(tmp & ~bits, addr);
+}
+
+/****************************************************************************
+ * Name: esp32s2_spi_iomux
+ *
+ * Description:
+ *   Check if the option SPI GPIO pins can use IOMUX directly
+ *
+ * Input Parameters:
+ *   priv   - Private SPI device structure
+ *
+ * Returned Value:
+ *   True if can use IOMUX or false if can't.
+ *
+ ****************************************************************************/
+
+static inline bool esp32s2_spi_iomux(struct esp32s2_spi_priv_s *priv)
+{
+  bool mapped = false;
+  const struct esp32s2_spi_config_s *cfg = priv->config;
+
+  /* We only need to check SPI2, SPI3 doesn't support IOMUX */
+
+  if (cfg->id == 2)
+    {
+      if (cfg->mosi_pin == SPI2_IOMUX_MOSIPIN &&
+#ifndef CONFIG_ESP32S2_SPI_SWCS
+          cfg->cs_pin == SPI2_IOMUX_CSPIN &&
+#endif
+          cfg->miso_pin == SPI2_IOMUX_MISOPIN &&
+          cfg->clk_pin == SPI2_IOMUX_CLKPIN)
+        {
+          mapped = true;
+        }
+    }
+
+  return mapped;
+}
+
+/****************************************************************************
+ * Name: esp32s2_spi_lock
+ *
+ * Description:
+ *   Lock or unlock the SPI device.
+ *
+ * Input Parameters:
+ *   dev    - Device-specific state data
+ *   lock   - true: Lock SPI bus, false: unlock SPI bus
+ *
+ * Returned Value:
+ *   The result of lock or unlock the SPI device.
+ *
+ ****************************************************************************/
+
+static int esp32s2_spi_lock(struct spi_dev_s *dev, bool lock)
+{
+  int ret;
+  struct esp32s2_spi_priv_s *priv = (struct esp32s2_spi_priv_s *)dev;
+
+  if (lock)
+    {
+      ret = nxsem_wait_uninterruptible(&priv->exclsem);
+    }
+  else
+    {
+      ret = nxsem_post(&priv->exclsem);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp32s2_spi_select
+ *
+ * Description:
+ *   Enable/disable the SPI chip select. The implementation of this method
+ *   must include handshaking: If a device is selected, it must hold off
+ *   all other attempts to select the device until the device is deselected.
+ *
+ *   If ESP32S2_SPI_SWCS is disabled, the driver will use hardware CS so that
+ *   once transmission is started the hardware selects the device and when
+ *   this transmission is done hardware deselects the device automatically.
+ *   So, this function will do nothing.
+ *
+ * Input Parameters:
+ *   dev      - Device-specific state data
+ *   devid    - Identifies the device to select
+ *   selected - true: slave selected, false: slave de-selected
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_ESP32S2_SPI_UDCS
+static void esp32s2_spi_select(struct spi_dev_s *dev,
+                               uint32_t devid, bool selected)
+{
+#if SPI_HAVE_SWCS
+  struct esp32s2_spi_priv_s *priv = (struct esp32s2_spi_priv_s *)dev;
+
+  esp32s2_gpiowrite(priv->config->cs_pin, !selected);
+#endif
+
+  spiinfo("devid: %08" PRIx32 " CS: %s\n",
+          devid, selected ? "select" : "free");
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s2_spi_setfrequency
+ *
+ * Description:
+ *   Set the SPI frequency.
+ *
+ * Input Parameters:
+ *   dev       - Device-specific state data
+ *   frequency - The requested SPI frequency
+ *
+ * Returned Value:
+ *   Returns the current selected frequency.
+ *
+ ****************************************************************************/
+
+static uint32_t esp32s2_spi_setfrequency(struct spi_dev_s *dev,
+                                         uint32_t frequency)
+{
+  uint32_t reg_val;
+  struct esp32s2_spi_priv_s *priv = (struct esp32s2_spi_priv_s *)dev;
+  const uint32_t duty_cycle = 128;
+
+  if (priv->frequency == frequency)
+    {
+      /* Requested frequency is the same as the current frequency. */
+
+      return priv->actual;
+    }
+
+  /* In HW, n, h and l fields range from 1 to 64, pre ranges from 1 to 8K.
+   * The value written to register is one lower than the used value.
+   */
+
+  if (frequency > ((APB_CLK_FREQ / 4) * 3))
+    {
+      /* Using APB frequency directly will give us the best result here. */
+
+      reg_val = SPI_CLK_EQU_SYSCLK_M;
+      priv->actual = APB_CLK_FREQ;
+    }
+  else
+    {
+      /* For best duty cycle resolution, we want n to be as close to 32 as
+       * possible, but we also need a pre/n combo that gets us as close as
+       * possible to the intended frequency. To do this, we bruteforce n and
+       * calculate the best pre to go along with that. If there's a choice
+       * between pre/n combos that give the same result, use the one with the
+       * higher n.
+       */
+
+      int32_t pre;
+      int32_t n;
+      int32_t h;
+      int32_t l;
+      int32_t bestn = -1;
+      int32_t bestpre = -1;
+      int32_t besterr = 0;
+      int32_t errval;
+
+      /* Start at n = 2. We need to be able to set h/l so we have at least
+       * one high and one low pulse.
+       */
+
+      for (n = 2; n <= 64; n++)
+        {
+          /* Effectively, this does:
+           *   pre = round((APB_CLK_FREQ / n) / frequency)
+           */
+
+          pre = ((APB_CLK_FREQ / n) + (frequency / 2)) / frequency;
+
+          if (pre <= 0)
+            {
+              pre = 1;
+            }
+
+          if (pre > 16)
+            {
+              pre = 16;
+            }
+
+          errval = abs(APB_CLK_FREQ / (pre * n) - frequency);
+          if (bestn == -1 || errval <= besterr)
+            {
+              besterr = errval;
+              bestn = n;
+              bestpre = pre;
+            }
+        }
+
+      n = bestn;
+      pre = bestpre;
+      l = n;
+
+      /* Effectively, this does:
+       *   h = round((duty_cycle * n) / 256)
+       */
+
+      h = (duty_cycle * n + 127) / 256;
+      if (h <= 0)
+        {
+          h = 1;
+        }
+
+      reg_val = ((l - 1) << SPI_CLKCNT_L_S) |
+                ((h - 1) << SPI_CLKCNT_H_S) |
+                ((n - 1) << SPI_CLKCNT_N_S) |
+                ((pre - 1) << SPI_CLKDIV_PRE_S);
+
+      priv->actual = APB_CLK_FREQ / (n * pre);
+    }
+
+  priv->frequency = frequency;
+
+  putreg32(reg_val, SPI_CLOCK_REG(priv->config->id));
+
+  spiinfo("frequency=%" PRIu32 ", actual=%" PRIu32 "\n",
+          priv->frequency, priv->actual);
+
+  return priv->actual;
+}
+
+/****************************************************************************
+ * Name: esp32s2_spi_setmode
+ *
+ * Description:
+ *   Set the SPI mode.
+ *
+ * Input Parameters:
+ *   dev  - Device-specific state data
+ *   mode - The requested SPI mode
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void esp32s2_spi_setmode(struct spi_dev_s *dev,
+                                enum spi_mode_e mode)
+{
+  struct esp32s2_spi_priv_s *priv = (struct esp32s2_spi_priv_s *)dev;
+
+  spiinfo("mode=%d\n", mode);
+
+  /* Has the mode changed? */
+
+  if (mode != priv->mode)
+    {
+      uint32_t ck_idle_edge;
+      uint32_t ck_out_edge;
+
+      switch (mode)
+        {
+          case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */
+            ck_idle_edge = 0;
+            ck_out_edge = 0;
+            break;
+
+          case SPIDEV_MODE1: /* CPOL=0; CPHA=1 */
+            ck_idle_edge = 0;
+            ck_out_edge = 1;
+            break;
+
+          case SPIDEV_MODE2: /* CPOL=1; CPHA=0 */
+            ck_idle_edge = 1;
+            ck_out_edge = 1;
+            break;
+
+          case SPIDEV_MODE3: /* CPOL=1; CPHA=1 */
+            ck_idle_edge = 1;
+            ck_out_edge = 0;
+            break;
+
+          default:
+            spierr("Invalid mode: %d\n", mode);
+            DEBUGPANIC();
+            return;
+        }
+
+      esp32s2_spi_clr_regbits(SPI_MISC_REG(priv->config->id),
+                              SPI_CK_IDLE_EDGE_M);
+      esp32s2_spi_set_regbits(SPI_MISC_REG(priv->config->id),
+                              VALUE_TO_FIELD(ck_idle_edge,
+                                             SPI_CK_IDLE_EDGE));
+
+      esp32s2_spi_clr_regbits(SPI_USER_REG(priv->config->id),
+                              SPI_CK_OUT_EDGE_M);
+      esp32s2_spi_set_regbits(SPI_USER_REG(priv->config->id),
+                              VALUE_TO_FIELD(ck_out_edge, SPI_CK_OUT_EDGE));
+
+      priv->mode = mode;
+    }
+}
+
+/****************************************************************************
+ * Name: esp32s2_spi_setbits
+ *
+ * Description:
+ *   Set the number of bits per word.
+ *
+ * Input Parameters:
+ *   dev   - Device-specific state data
+ *   nbits - The number of bits in an SPI word.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void esp32s2_spi_setbits(struct spi_dev_s *dev, int nbits)
+{
+  struct esp32s2_spi_priv_s *priv = (struct esp32s2_spi_priv_s *)dev;
+
+  spiinfo("nbits=%d\n", nbits);
+
+  priv->nbits = nbits;
+}
+
+/****************************************************************************
+ * Name: esp32s2_spi_hwfeatures
+ *
+ * Description:
+ *   Set hardware-specific feature flags.
+ *
+ * Input Parameters:
+ *   dev      - Device-specific state data
+ *   features - H/W feature flags
+ *
+ * Returned Value:
+ *   Zero (OK) if the selected H/W features are enabled; A negated errno
+ *   value if any H/W feature is not supportable.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_HWFEATURES
+static int esp32s2_spi_hwfeatures(struct spi_dev_s *dev,
+                                  spi_hwfeatures_t features)
+{
+  /* Other H/W features are not supported */
+
+  return (features == 0) ? OK : -ENOSYS;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s2_spi_poll_send
+ *
+ * Description:
+ *   Send one word on SPI by polling mode.
+ *
+ * Input Parameters:
+ *   priv - SPI private state data
+ *   wd   - The word to send. The size of the data is determined by the
+ *          number of bits selected for the SPI interface.
+ *
+ * Returned Value:
+ *   Received value.
+ *
+ ****************************************************************************/
+
+static uint32_t esp32s2_spi_poll_send(struct esp32s2_spi_priv_s *priv,
+                                      uint32_t wd)
+{
+  uint32_t val;
+
+  const uintptr_t spi_miso_dlen_reg = SPI_MISO_DLEN_REG(priv->config->id);
+  const uintptr_t spi_mosi_dlen_reg = SPI_MOSI_DLEN_REG(priv->config->id);
+  const uintptr_t spi_w0_reg = SPI_W0_REG(priv->config->id);
+  const uintptr_t spi_cmd_reg = SPI_CMD_REG(priv->config->id);
+
+  putreg32((priv->nbits - 1), spi_miso_dlen_reg);
+  putreg32((priv->nbits - 1), spi_mosi_dlen_reg);
+
+  putreg32(wd, spi_w0_reg);
+
+  esp32s2_spi_set_regbits(spi_cmd_reg, SPI_USR_M);
+
+  while ((getreg32(spi_cmd_reg) & SPI_USR_M) != 0)
+    {
+      ;
+    }
+
+  val = getreg32(spi_w0_reg);
+
+  spiinfo("send=0x%" PRIx32 " and recv=0x%" PRIx32 "\n", wd, val);
+
+  return val;
+}
+
+/****************************************************************************
+ * Name: esp32s2_spi_send
+ *
+ * Description:
+ *   Send one word on SPI.
+ *
+ * Input Parameters:
+ *   dev - Device-specific state data
+ *   wd  - The word to send. The size of the data is determined by the
+ *         number of bits selected for the SPI interface.
+ *
+ * Returned Value:
+ *   Received value.
+ *
+ ****************************************************************************/
+
+static uint32_t esp32s2_spi_send(struct spi_dev_s *dev, uint32_t wd)
+{
+  struct esp32s2_spi_priv_s *priv = (struct esp32s2_spi_priv_s *)dev;
+
+  return esp32s2_spi_poll_send(priv, wd);
+}
+
+/****************************************************************************
+ * Name: esp32s2_spi_poll_exchange
+ *
+ * Description:
+ *   Exchange a block of data from SPI.
+ *
+ * Input Parameters:
+ *   priv     - SPI private state data
+ *   txbuffer - A pointer to the buffer of data to be sent
+ *   rxbuffer - A pointer to the buffer in which to receive data
+ *   nwords   - The length of data that to be exchanged in units of words.
+ *              The wordsize is determined by the number of bits-per-word
+ *              selected for the SPI interface. If nbits <= 8, the data is
+ *              packed into uint8_t's; if nbits >8, the data is packed into
+ *              uint16_t's
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void esp32s2_spi_poll_exchange(struct esp32s2_spi_priv_s *priv,
+                                      const void *txbuffer,
+                                      void *rxbuffer,
+                                      size_t nwords)
+{
+  const uint32_t total_bytes = nwords * (priv->nbits / 8);
+  uintptr_t bytes_remaining = total_bytes;
+  const uint8_t *tp = (const uint8_t *)txbuffer;
+  uint8_t *rp = (uint8_t *)rxbuffer;
+
+  while (bytes_remaining != 0)
+    {
+      /* 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_MAX_BUF_SIZE, bytes_remaining);
+
+      /* Write data words to data buffer registers.
+       * SPI peripheral contains 16 registers (W0 - W15).
+       */
+
+      for (int i = 0 ; i < transfer_size; i += sizeof(uintptr_t))
+        {
+          uintptr_t w_wd = UINT32_MAX;
+
+          if (tp != NULL)
+            {
+              memcpy(&w_wd, tp, sizeof(uintptr_t));
+
+              tp += sizeof(uintptr_t);
+            }
+
+          putreg32(w_wd, data_buf_reg);
+
+          spiinfo("send=0x%" PRIx32 " data_reg=0x%" PRIxPTR "\n",
+                  w_wd, data_buf_reg);
+
+          /* Update data_buf_reg to point to the next data buffer register. */
+
+          data_buf_reg += sizeof(uintptr_t);
+        }
+
+      esp32s2_spi_set_regbits(SPI_USER_REG(priv->config->id),
+                              SPI_USR_MOSI_M);
+
+      if (rp == NULL)
+        {
+          esp32s2_spi_clr_regbits(SPI_USER_REG(priv->config->id),
+                                  SPI_USR_MISO_M);
+        }
+      else
+        {
+          esp32s2_spi_set_regbits(SPI_USER_REG(priv->config->id),
+                                  SPI_USR_MISO_M);
+        }
+
+      putreg32((transfer_size * 8) - 1,
+               SPI_MOSI_DLEN_REG(priv->config->id));
+
+      putreg32((transfer_size * 8) - 1,
+               SPI_MISO_DLEN_REG(priv->config->id));
+
+      /* Trigger start of user-defined transaction for master. */
+
+      esp32s2_spi_set_regbits(SPI_CMD_REG(priv->config->id), SPI_USR_M);
+
+      /* Wait for the user-defined transaction to finish. */
+
+      while ((getreg32(SPI_CMD_REG(priv->config->id)) & SPI_USR_M) != 0)
+        {
+          ;
+        }
+
+      if (rp != NULL)
+        {
+          /* Set data_buf_reg with the address of the first data buffer
+           * register (W0).
+           */
+
+          data_buf_reg = SPI_W0_REG(priv->config->id);
+
+          /* Read received data words from SPI data buffer registers. */
+
+          for (int i = 0 ; i < transfer_size; i += sizeof(uintptr_t))
+            {
+              uintptr_t r_wd = getreg32(data_buf_reg);
+
+              spiinfo("recv=0x%" PRIx32 " data_reg=0x%" PRIxPTR "\n",
+                      r_wd, data_buf_reg);
+
+              memcpy(rp, &r_wd, sizeof(uintptr_t));
+
+              rp += sizeof(uintptr_t);
+
+              /* Update data_buf_reg to point to the next data buffer
+               * register.
+               */
+
+              data_buf_reg += sizeof(uintptr_t);
+            }
+        }
+
+      bytes_remaining -= transfer_size;
+    }
+}
+
+/****************************************************************************
+ * Name: esp32s2_spi_exchange
+ *
+ * Description:
+ *   Exchange a block of data from SPI.
+ *
+ * Input Parameters:
+ *   dev      - Device-specific state data
+ *   txbuffer - A pointer to the buffer of data to be sent
+ *   rxbuffer - A pointer to the buffer in which to receive data
+ *   nwords   - The length of data that to be exchanged in units of words.
+ *              The wordsize is determined by the number of bits-per-word
+ *              selected for the SPI interface. If nbits <= 8, the data is
+ *              packed into uint8_t's; if nbits >8, the data is packed into
+ *              uint16_t's
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void esp32s2_spi_exchange(struct spi_dev_s *dev,
+                                 const void *txbuffer,
+                                 void *rxbuffer,
+                                 size_t nwords)
+{
+  struct esp32s2_spi_priv_s *priv = (struct esp32s2_spi_priv_s *)dev;
+
+  esp32s2_spi_poll_exchange(priv, txbuffer, rxbuffer, nwords);
+}
+
+#ifndef CONFIG_SPI_EXCHANGE
+
+/****************************************************************************
+ * Name: esp32s2_spi_sndblock
+ *
+ * Description:
+ *   Send a block of data on SPI.
+ *
+ * Input Parameters:
+ *   dev      - Device-specific state data
+ *   txbuffer - A pointer to the buffer of data to be sent
+ *   nwords   - The length of data to send from the buffer in number of
+ *              words. The wordsize is determined by the number of
+ *              bits-per-word selected for the SPI interface. If nbits <= 8,
+ *              the data is packed into uint8_t's; if nbits >8, the data is
+ *              packed into uint16_t's
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void esp32s2_spi_sndblock(struct spi_dev_s *dev,
+                                 const void *txbuffer,
+                                 size_t nwords)
+{
+  spiinfo("txbuffer=%p nwords=%d\n", txbuffer, nwords);
+
+  esp32s2_spi_exchange(dev, txbuffer, NULL, nwords);
+}
+
+/****************************************************************************
+ * Name: esp32s2_spi_recvblock
+ *
+ * Description:
+ *   Receive a block of data from SPI.
+ *
+ * Input Parameters:
+ *   dev      - Device-specific state data
+ *   rxbuffer - A pointer to the buffer in which to receive data
+ *   nwords   - The length of data that can be received in the buffer in
+ *              number of words. The wordsize is determined by the number of
+ *              bits-per-word selected for the SPI interface. If nbits <= 8,
+ *              the data is packed into uint8_t's; if nbits >8, the data is
+ *              packed into uint16_t's
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void esp32s2_spi_recvblock(struct spi_dev_s *dev,
+                                  void *rxbuffer,
+                                  size_t nwords)
+{
+  spiinfo("rxbuffer=%p nwords=%d\n", rxbuffer, nwords);
+
+  esp32s2_spi_exchange(dev, NULL, rxbuffer, nwords);
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s2_spi_init
+ *
+ * Description:
+ *   Initialize ESP32-S2 SPI hardware interface.
+ *
+ * Input Parameters:
+ *   dev      - Device-specific state data
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void esp32s2_spi_init(struct spi_dev_s *dev)
+{
+  struct esp32s2_spi_priv_s *priv = (struct esp32s2_spi_priv_s *)dev;
+  const struct esp32s2_spi_config_s *config = priv->config;
+  uint32_t regval;
+
+  /* Initialize the SPI semaphore that enforces mutually exclusive access */
+
+  nxsem_init(&priv->exclsem, 0, 1);
+
+  esp32s2_gpiowrite(config->cs_pin, true);
+  esp32s2_gpiowrite(config->mosi_pin, true);
+  esp32s2_gpiowrite(config->miso_pin, true);
+  esp32s2_gpiowrite(config->clk_pin, true);
+
+#if SPI_HAVE_SWCS
+  esp32s2_configgpio(config->cs_pin, OUTPUT_FUNCTION_1);
+  esp32s2_gpio_matrix_out(config->cs_pin, SIG_GPIO_OUT_IDX, 0, 0);
+#endif
+
+  /* SPI3 doesn't have IOMUX, if SPI3 is enabled use GPIO Matrix for both */
+
+  if (esp32s2_spi_iomux(priv))
+    {
+#if !SPI_HAVE_SWCS
+      esp32s2_configgpio(config->cs_pin, OUTPUT_FUNCTION_5);
+      esp32s2_gpio_matrix_out(config->cs_pin, SIG_GPIO_OUT_IDX, 0, 0);
+#endif
+      esp32s2_configgpio(config->mosi_pin, OUTPUT_FUNCTION_5);
+      esp32s2_gpio_matrix_out(config->mosi_pin, SIG_GPIO_OUT_IDX, 0, 0);
+
+      esp32s2_configgpio(config->miso_pin, INPUT_FUNCTION_5 | PULLUP);
+      esp32s2_gpio_matrix_out(config->miso_pin, SIG_GPIO_OUT_IDX, 0, 0);
+
+      esp32s2_configgpio(config->clk_pin, OUTPUT_FUNCTION_5);
+      esp32s2_gpio_matrix_out(config->clk_pin, SIG_GPIO_OUT_IDX, 0, 0);
+    }
+  else
+    {
+#if !SPI_HAVE_SWCS
+      esp32s2_configgpio(config->cs_pin, OUTPUT);
+      esp32s2_gpio_matrix_out(config->cs_pin, config->cs_outsig, 0, 0);
+#endif
+      esp32s2_configgpio(config->mosi_pin, OUTPUT);
+      esp32s2_gpio_matrix_out(config->mosi_pin, config->mosi_outsig, 0, 0);
+
+      esp32s2_configgpio(config->miso_pin, INPUT | PULLUP);
+      esp32s2_gpio_matrix_in(config->miso_pin, config->miso_insig, 0);
+
+      esp32s2_configgpio(config->clk_pin, OUTPUT);
+      esp32s2_gpio_matrix_out(config->clk_pin, config->clk_outsig, 0, 0);
+    }
+
+  modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, 0, config->clk_bit);
+  modifyreg32(SYSTEM_PERIP_RST_EN0_REG, config->rst_bit, 0);
+
+  regval = SPI_DOUTDIN_M | SPI_USR_MISO_M | SPI_USR_MOSI_M | SPI_CS_HOLD_M;
+  putreg32(regval, SPI_USER_REG(priv->config->id));
+  putreg32(0, SPI_USER1_REG(priv->config->id));
+  putreg32(0, SPI_SLAVE_REG(priv->config->id));
+  putreg32(SPI_CS1_DIS_M | SPI_CS2_DIS_M,
+           SPI_MISC_REG(priv->config->id));
+
+#if SPI_HAVE_SWCS
+  esp32s2_spi_set_regbits(SPI_MISC_REG(priv->config->id), SPI_CS0_DIS_M);
+#endif
+
+  putreg32(0, SPI_CTRL_REG(priv->config->id));
+  putreg32(VALUE_TO_FIELD(0, SPI_CS_HOLD_TIME),
+           SPI_USER1_REG(priv->config->id));
+
+  esp32s2_spi_setfrequency(dev, config->clk_freq);
+  esp32s2_spi_setbits(dev, config->width);
+  esp32s2_spi_setmode(dev, config->mode);
+}
+
+/****************************************************************************
+ * Name: esp32s2_spi_deinit
+ *
+ * Description:
+ *   Deinitialize ESP32-S2 SPI hardware interface.
+ *
+ * Input Parameters:
+ *   dev      - Device-specific state data
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void esp32s2_spi_deinit(struct spi_dev_s *dev)
+{
+  struct esp32s2_spi_priv_s *priv = (struct esp32s2_spi_priv_s *)dev;
+
+  modifyreg32(SYSTEM_PERIP_RST_EN0_REG, 0, priv->config->rst_bit);
+  modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, priv->config->clk_bit, 0);
+
+  priv->frequency = 0;
+  priv->actual    = 0;
+  priv->mode      = SPIDEV_MODE0;
+  priv->nbits     = 0;
+}
+
+/****************************************************************************
+ * Name: esp32s2_spibus_initialize
+ *
+ * Description:
+ *   Initialize the selected SPI bus.
+ *
+ * Input Parameters:
+ *   port     - Port number (for hardware that has multiple SPI interfaces)
+ *
+ * Returned Value:
+ *   Valid SPI device structure reference on success; NULL on failure.
+ *
+ ****************************************************************************/
+
+struct spi_dev_s *esp32s2_spibus_initialize(int port)
+{
+  struct spi_dev_s *spi_dev;
+  struct esp32s2_spi_priv_s *priv;
+  irqstate_t flags;
+
+  switch (port)
+    {
+#ifdef CONFIG_ESP32S2_SPI2
+      case ESP32S2_SPI2:
+        priv = &esp32s2_spi2_priv;
+        break;
+#endif
+#ifdef CONFIG_ESP32S2_SPI3
+      case ESP32S2_SPI3:
+        priv = &esp32s2_spi3_priv;
+        break;
+#endif
+      default:
+        return NULL;
+    }
+
+  spi_dev = (struct spi_dev_s *)priv;
+
+  flags = enter_critical_section();
+
+  esp32s2_spi_init(spi_dev);
+
+  priv->refs++;
+
+  leave_critical_section(flags);
+
+  return spi_dev;
+}
+
+/****************************************************************************
+ * Name: esp32s2_spibus_uninitialize
+ *
+ * Description:
+ *   Uninitialize an SPI bus.
+ *
+ * Input Parameters:
+ *   dev      - Device-specific state data
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success. Otherwise -1 (ERROR).
+ *
+ ****************************************************************************/
+
+int esp32s2_spibus_uninitialize(struct spi_dev_s *dev)
+{
+  irqstate_t flags;
+  struct esp32s2_spi_priv_s *priv = (struct esp32s2_spi_priv_s *)dev;
+
+  DEBUGASSERT(dev);
+
+  if (priv->refs == 0)
+    {
+      return ERROR;
+    }
+
+  flags = enter_critical_section();
+
+  if (--priv->refs != 0)
+    {
+      leave_critical_section(flags);
+      return OK;
+    }
+
+  leave_critical_section(flags);
+
+  esp32s2_spi_deinit(dev);
+
+  nxsem_destroy(&priv->exclsem);
+
+  return OK;
+}
+
+#endif /* CONFIG_ESP32S2_SPI */
diff --git a/arch/xtensa/src/esp32s2/esp32s2_spi.h b/arch/xtensa/src/esp32s2/esp32s2_spi.h
new file mode 100644
index 0000000000..3f569b73c8
--- /dev/null
+++ b/arch/xtensa/src/esp32s2/esp32s2_spi.h
@@ -0,0 +1,150 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_spi.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#ifndef __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_SPI_H
+#define __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_SPI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+#ifdef CONFIG_ESP32S2_SPI
+
+#include <nuttx/spi/spi.h>
+
+#ifdef CONFIG_ESP32S2_SPI2
+#  define ESP32S2_SPI2 2
+#endif
+
+#ifdef CONFIG_ESP32S2_SPI3
+#  define ESP32S2_SPI3 3
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s2_spibus_initialize
+ *
+ * Description:
+ *   Initialize the selected SPI bus.
+ *
+ * Input Parameters:
+ *   port     - Port number (for hardware that has multiple SPI interfaces)
+ *
+ * Returned Value:
+ *   Valid SPI device structure reference on success; NULL on failure
+ *
+ ****************************************************************************/
+
+struct spi_dev_s *esp32s2_spibus_initialize(int port);
+
+/****************************************************************************
+ * Name:  esp32s2_spi[2|3]_select and esp32s2_spi[2|3]_status
+ *
+ * Description:
+ *   The external functions, esp32s2_spi[2|3]_select,
+ *   esp32s2_spi[2|3]_status, and esp32s2_spi[2|3]_cmddata must be provided
+ *   by board-specific logic.
+ *   These are implementations of the select, status, and cmddata methods of
+ *   the SPI interface defined by struct spi_ops_s (include/nuttx/spi/spi.h).
+ *   All other methods (including esp32s2_spibus_initialize()) are provided
+ *   by common ESP32-S2 logic. To use this common SPI logic on your board:
+ *
+ *   1. Provide logic in esp32s2_board_initialize() to configure SPI chip
+ *      select pins.
+ *   2. Provide esp32s2_spi[2|3]_select() and esp32s2_spi[2|3]_status()
+ *      functions in your board-specific logic. These functions will perform
+ *      chip selection and status operations using GPIOs in the way your
+ *      board is configured.
+ *   3. If CONFIG_SPI_CMDDATA is defined in your NuttX configuration file,
+ *      then provide esp32s2_spi[2|3]_cmddata() functions in your
+ *      board-specific logic. These functions will perform cmd/data selection
+ *      operations using GPIOs in the way your board is configured.
+ *   4. Add a call to esp32s2_spibus_initialize() in your low level
+ *      application initialization logic.
+ *   5. The handle returned by esp32s2_spibus_initialize() may then be used
+ *      to bind the SPI driver to higher level logic (e.g., calling
+ *      mmcsd_spislotinitialize(), for example, will bind the SPI driver to
+ *      the SPI MMC/SD driver).
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_SPI2
+void esp32s2_spi2_select(struct spi_dev_s *dev, uint32_t devid,
+                         bool selected);
+uint8_t esp32s2_spi2_status(struct spi_dev_s *dev, uint32_t devid);
+int esp32s2_spi2_cmddata(struct spi_dev_s *dev,
+                         uint32_t devid,
+                         bool cmd);
+#endif
+
+#ifdef CONFIG_ESP32S2_SPI3
+void esp32s2_spi3_select(struct spi_dev_s *dev, uint32_t devid,
+                         bool selected);
+uint8_t esp32s2_spi3_status(struct spi_dev_s *dev, uint32_t devid);
+int esp32s2_spi3_cmddata(struct spi_dev_s *dev,
+                         uint32_t devid,
+                         bool cmd);
+#endif
+
+/****************************************************************************
+ * Name: esp32s2_spibus_uninitialize
+ *
+ * Description:
+ *   Uninitialize an SPI bus.
+ *
+ * Input Parameters:
+ *   dev      - Device-specific state data
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success.  Otherwise -1 (ERROR).
+ *
+ ****************************************************************************/
+
+int esp32s2_spibus_uninitialize(struct spi_dev_s *dev);
+
+#endif /* CONFIG_ESP32S2_SPI */
+
+#ifdef __cplusplus
+}
+#endif
+#undef EXTERN
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_SPI_H */
diff --git a/arch/xtensa/src/esp32s2/hardware/esp32s2_pinmap.h b/arch/xtensa/src/esp32s2/hardware/esp32s2_pinmap.h
new file mode 100644
index 0000000000..4b7ecf609b
--- /dev/null
+++ b/arch/xtensa/src/esp32s2/hardware/esp32s2_pinmap.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/hardware/esp32s2_pinmap.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#ifndef __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_ESP32S2_PINMAP_H
+#define __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_ESP32S2_PINMAP_H
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/**
+ * Peripheral' fixed mapped pins by IOMUX, these GPIO pins can have better
+ * speed performance.
+ */
+
+/* UART0 */
+
+/* UART1 */
+
+/* SPI2 */
+
+#define SPI2_IOMUX_MISOPIN      (13)
+#define SPI2_IOMUX_MOSIPIN      (11)
+#define SPI2_IOMUX_CLKPIN       (12)
+#define SPI2_IOMUX_CSPIN        (10)
+#define SPI2_IOMUX_WPPIN        (14)
+#define SPI2_IOMUX_HDPIN        (9)
+
+/* SPI3 */
+
+/* SPI3 have no iomux pins */
+
+#endif /* __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_ESP32S2_PINMAP_H */
diff --git a/arch/xtensa/src/esp32s2/hardware/esp32s2_soc.h b/arch/xtensa/src/esp32s2/hardware/esp32s2_soc.h
index 9276d98d7a..8d7b945421 100644
--- a/arch/xtensa/src/esp32s2/hardware/esp32s2_soc.h
+++ b/arch/xtensa/src/esp32s2/hardware/esp32s2_soc.h
@@ -274,6 +274,8 @@
 #define REG_SPI_MEM_BASE(i)      (DR_REG_SPI0_BASE - (i) * 0x1000)
 #define REG_I2C_BASE(i)          (DR_REG_I2C_EXT_BASE + (i) * 0x14000 )
 
+#define REG_SPI_BASE(i)          (DR_REG_SPI2_BASE + (((i) > 3) ? ((((i) - 2) * 0x1000) + 0x10000) : (((i) - 2) * 0x1000)))
+
 /* Registers Operation */
 
 #define REG_UART_BASE( i )  (DR_REG_UART_BASE + (i) * 0x10000 )
diff --git a/arch/xtensa/src/esp32s2/hardware/esp32s2_spi.h b/arch/xtensa/src/esp32s2/hardware/esp32s2_spi.h
index 1fa5538c47..5abb83e03b 100644
--- a/arch/xtensa/src/esp32s2/hardware/esp32s2_spi.h
+++ b/arch/xtensa/src/esp32s2/hardware/esp32s2_spi.h
@@ -33,7 +33,7 @@
 
 /* SPI_CMD_REG register */
 
-#define SPI_CMD_REG (DR_REG_SPI_BASE + 0x0)
+#define SPI_CMD_REG(i) (REG_SPI_BASE(i) + 0x0)
 
 /* SPI_USR : R/W; bitpos: [24]; default: 0;
  * User define command enable.  An operation will be triggered when the bit
@@ -57,7 +57,7 @@
 
 /* SPI_ADDR_REG register */
 
-#define SPI_ADDR_REG (DR_REG_SPI_BASE + 0x4)
+#define SPI_ADDR_REG(i)    (REG_SPI_BASE(i) + 0x4)
 
 /* SPI_USR_ADDR_VALUE : R/W; bitpos: [31:0]; default: 0;
  * [31:8]:address to slave, [7:0]:Reserved.
@@ -70,7 +70,7 @@
 
 /* SPI_CTRL_REG register */
 
-#define SPI_CTRL_REG (DR_REG_SPI_BASE + 0x8)
+#define SPI_CTRL_REG(i)       (REG_SPI_BASE(i) + 0x8)
 
 /* SPI_WR_BIT_ORDER : R/W; bitpos: [26]; default: 0;
  * In command address write-data (MOSI) phases 1: LSB firs 0: MSB first
@@ -225,7 +225,7 @@
 
 /* SPI_CTRL1_REG register */
 
-#define SPI_CTRL1_REG (DR_REG_SPI_BASE + 0xc)
+#define SPI_CTRL1_REG(i)     (REG_SPI_BASE(i) + 0xc)
 
 /* SPI_CS_HOLD_DELAY : R/W; bitpos: [19:14]; default: 1;
  * SPI cs signal is delayed by spi clock cycles.
@@ -280,7 +280,7 @@
 
 /* SPI_CTRL2_REG register */
 
-#define SPI_CTRL2_REG (DR_REG_SPI_BASE + 0x10)
+#define SPI_CTRL2_REG(i)    (REG_SPI_BASE(i) + 0x10)
 
 /* SPI_CS_DELAY_NUM : R/W; bitpos: [30:29]; default: 0;
  * spi_cs signal is delayed by system clock cycles
@@ -325,7 +325,7 @@
 
 /* SPI_CLOCK_REG register */
 
-#define SPI_CLOCK_REG (DR_REG_SPI_BASE + 0x14)
+#define SPI_CLOCK_REG(i)      (REG_SPI_BASE(i) + 0x14)
 
 /* SPI_CLK_EQU_SYSCLK : R/W; bitpos: [31]; default: 1;
  * In the master mode 1: spi_clk is eqaul to system 0: spi_clk is divided
@@ -378,7 +378,7 @@
 
 /* SPI_USER_REG register */
 
-#define SPI_USER_REG (DR_REG_SPI_BASE + 0x18)
+#define SPI_USER_REG(i)    (REG_SPI_BASE(i) + 0x18)
 
 /* SPI_USR_COMMAND : R/W; bitpos: [31]; default: 1;
  * This bit enable the command phase of an operation.
@@ -649,7 +649,7 @@
 
 /* SPI_USER1_REG register */
 
-#define SPI_USER1_REG (DR_REG_SPI_BASE + 0x1c)
+#define SPI_USER1_REG(i)       (REG_SPI_BASE(i) + 0x1c)
 
 /* SPI_USR_ADDR_BITLEN : R/W; bitpos: [31:27]; default: 23;
  * The length in bits of address phase. The register value shall be
@@ -673,7 +673,7 @@
 
 /* SPI_USER2_REG register */
 
-#define SPI_USER2_REG (DR_REG_SPI_BASE + 0x20)
+#define SPI_USER2_REG(i)          (REG_SPI_BASE(i) + 0x20)
 
 /* SPI_USR_COMMAND_BITLEN : R/W; bitpos: [31:28]; default: 7;
  * The length in bits of command phase. The register value shall be
@@ -696,7 +696,7 @@
 
 /* SPI_MOSI_DLEN_REG register */
 
-#define SPI_MOSI_DLEN_REG (DR_REG_SPI_BASE + 0x24)
+#define SPI_MOSI_DLEN_REG(i)     (REG_SPI_BASE(i) + 0x24)
 
 /* SPI_USR_MOSI_DBITLEN : R/W; bitpos: [22:0]; default: 0;
  * The length in bits of write-data. The register value shall be (bit_num-1).
@@ -709,7 +709,7 @@
 
 /* SPI_MISO_DLEN_REG register */
 
-#define SPI_MISO_DLEN_REG (DR_REG_SPI_BASE + 0x28)
+#define SPI_MISO_DLEN_REG(i)    (REG_SPI_BASE(i) + 0x28)
 
 /* SPI_USR_MISO_DBITLEN : R/W; bitpos: [22:0]; default: 0;
  * The length in bits of  read-data. The register value shall be (bit_num-1).
@@ -722,7 +722,7 @@
 
 /* SPI_SLV_WR_STATUS_REG register */
 
-#define SPI_SLV_WR_STATUS_REG (DR_REG_SPI_BASE + 0x2c)
+#define SPI_SLV_WR_STATUS_REG(i) (REG_SPI_BASE(i) + 0x2c)
 
 /* SPI_OPI_MODE : R/W; bitpos: [1]; default: 0;
  * Just for master mode. 1: spi controller is in OPI mode (all in 8-b-m). 0:
@@ -746,7 +746,7 @@
 
 /* SPI_MISC_REG register */
 
-#define SPI_MISC_REG (DR_REG_SPI_BASE + 0x30)
+#define SPI_MISC_REG(i)          (REG_SPI_BASE(i) + 0x30)
 
 /* SPI_QUAD_DIN_PIN_SWAP : R/W; bitpos: [31]; default: 0;
  * 1:  spi quad input swap enable  0:  spi quad input swap disable
@@ -917,7 +917,7 @@
 
 /* SPI_SLAVE_REG register */
 
-#define SPI_SLAVE_REG (DR_REG_SPI_BASE + 0x34)
+#define SPI_SLAVE_REG(i)  (REG_SPI_BASE(i) + 0x34)
 
 /* SPI_SOFT_RESET : R/W; bitpos: [31]; default: 0;
  * Software reset enable, reset the spi clock line cs line and data lines.
@@ -1031,7 +1031,7 @@
 
 /* SPI_SLAVE1_REG register */
 
-#define SPI_SLAVE1_REG (DR_REG_SPI_BASE + 0x38)
+#define SPI_SLAVE1_REG(i)    (REG_SPI_BASE(i) + 0x38)
 
 /* SPI_SLV_LAST_ADDR : R/W; bitpos: [31:24]; default: 0;
  * In the slave mode it is the value of address.
@@ -1083,7 +1083,7 @@
 
 /* SPI_SLAVE2_REG register */
 
-#define SPI_SLAVE2_REG (DR_REG_SPI_BASE + 0x3c)
+#define SPI_SLAVE2_REG(i)      (REG_SPI_BASE(i) + 0x3c)
 
 /* SPI_SLV_RD_DMA_DONE : R/W; bitpos: [8]; default: 0;
  * The interrupt raw bit for the completion of Rd-DMA operation in the slave
@@ -1097,7 +1097,7 @@
 
 /* SPI_SLV_WRBUF_DLEN_REG register */
 
-#define SPI_SLV_WRBUF_DLEN_REG (DR_REG_SPI_BASE + 0x40)
+#define SPI_SLV_WRBUF_DLEN_REG(i)  (REG_SPI_BASE(i) + 0x40)
 
 /* SPI_CONF_BASE_BITLEN : R/W; bitpos: [31:25]; default: 108;
  * The basic spi_clk cycles of CONF state. The real cycle length of CONF
@@ -1122,7 +1122,7 @@
 
 /* SPI_SLV_RDBUF_DLEN_REG register */
 
-#define SPI_SLV_RDBUF_DLEN_REG (DR_REG_SPI_BASE + 0x44)
+#define SPI_SLV_RDBUF_DLEN_REG(i)  (REG_SPI_BASE(i) + 0x44)
 
 /* SPI_SEG_MAGIC_ERR : R/W; bitpos: [25]; default: 0;
  * 1: The recent magic value in CONF buffer is not right in master DMA
@@ -1156,7 +1156,7 @@
 
 /* SPI_SLV_RD_BYTE_REG register */
 
-#define SPI_SLV_RD_BYTE_REG (DR_REG_SPI_BASE + 0x48)
+#define SPI_SLV_RD_BYTE_REG(i)    (REG_SPI_BASE(i) + 0x48)
 
 /* SPI_USR_CONF : R/W; bitpos: [31]; default: 0;
  * 1: Enable the DMA CONF phase of current seg-trans operation, which means
@@ -1230,7 +1230,7 @@
 
 /* SPI_FSM_REG register */
 
-#define SPI_FSM_REG (DR_REG_SPI_BASE + 0x50)
+#define SPI_FSM_REG(i)          (REG_SPI_BASE(i) + 0x50)
 
 /* SPI_MST_DMA_RD_BYTELEN : R/W; bitpos: [31:12]; default: 0;
  * Define the master DMA read byte length in non seg-trans or seg-trans
@@ -1255,7 +1255,7 @@
 
 /* SPI_HOLD_REG register */
 
-#define SPI_HOLD_REG (DR_REG_SPI_BASE + 0x54)
+#define SPI_HOLD_REG(i)           (REG_SPI_BASE(i) + 0x54)
 
 /* SPI_DMA_SEG_TRANS_DONE : R/W; bitpos: [7]; default: 0;
  * 1:  spi master DMA full-duplex/half-duplex seg-trans ends or slave
@@ -1311,7 +1311,7 @@
 
 /* SPI_DMA_CONF_REG register */
 
-#define SPI_DMA_CONF_REG (DR_REG_SPI_BASE + 0x58)
+#define SPI_DMA_CONF_REG(i)    (REG_SPI_BASE(i) + 0x58)
 
 /* SPI_EXT_MEM_BK_SIZE : R/W; bitpos: [27:26]; default: 0;
  * Select the external memory block size.
@@ -1552,7 +1552,7 @@
 
 /* SPI_DMA_OUT_LINK_REG register */
 
-#define SPI_DMA_OUT_LINK_REG (DR_REG_SPI_BASE + 0x5c)
+#define SPI_DMA_OUT_LINK_REG(i)  (REG_SPI_BASE(i) + 0x5c)
 
 /* SPI_DMA_TX_ENA : R/W; bitpos: [31]; default: 0;
  * spi dma write data status bit.
@@ -1601,7 +1601,7 @@
 
 /* SPI_DMA_IN_LINK_REG register */
 
-#define SPI_DMA_IN_LINK_REG (DR_REG_SPI_BASE + 0x60)
+#define SPI_DMA_IN_LINK_REG(i)   (REG_SPI_BASE(i) + 0x60)
 
 /* SPI_DMA_RX_ENA : R/W; bitpos: [31]; default: 0;
  * spi dma read data status bit.
@@ -1660,7 +1660,7 @@
 
 /* SPI_DMA_INT_ENA_REG register */
 
-#define SPI_DMA_INT_ENA_REG (DR_REG_SPI_BASE + 0x64)
+#define SPI_DMA_INT_ENA_REG(i)       (REG_SPI_BASE(i) + 0x64)
 
 /* SPI_OUT_TOTAL_EOF_INT_ENA : R/W; bitpos: [8]; default: 0;
  * The enable bit for sending all the packets to host done.
@@ -1745,7 +1745,7 @@
 
 /* SPI_DMA_INT_RAW_REG register */
 
-#define SPI_DMA_INT_RAW_REG (DR_REG_SPI_BASE + 0x68)
+#define SPI_DMA_INT_RAW_REG(i)       (REG_SPI_BASE(i) + 0x68)
 
 /* SPI_OUT_TOTAL_EOF_INT_RAW : RO; bitpos: [8]; default: 0;
  * The raw bit for sending all the packets to host done.
@@ -1830,7 +1830,7 @@
 
 /* SPI_DMA_INT_ST_REG register */
 
-#define SPI_DMA_INT_ST_REG (DR_REG_SPI_BASE + 0x6c)
+#define SPI_DMA_INT_ST_REG(i)       (REG_SPI_BASE(i) + 0x6c)
 
 /* SPI_OUT_TOTAL_EOF_INT_ST : RO; bitpos: [8]; default: 0;
  * The status bit for sending all the packets to host done.
@@ -1915,7 +1915,7 @@
 
 /* SPI_DMA_INT_CLR_REG register */
 
-#define SPI_DMA_INT_CLR_REG (DR_REG_SPI_BASE + 0x70)
+#define SPI_DMA_INT_CLR_REG(i)       (REG_SPI_BASE(i) + 0x70)
 
 /* SPI_OUT_TOTAL_EOF_INT_CLR : R/W; bitpos: [8]; default: 0;
  * The clear bit for sending all the packets to host done.
@@ -2000,7 +2000,7 @@
 
 /* SPI_IN_ERR_EOF_DES_ADDR_REG register */
 
-#define SPI_IN_ERR_EOF_DES_ADDR_REG (DR_REG_SPI_BASE + 0x74)
+#define SPI_IN_ERR_EOF_DES_ADDR_REG(i)   (REG_SPI_BASE(i) + 0x74)
 
 /* SPI_DMA_IN_ERR_EOF_DES_ADDR : RO; bitpos: [31:0]; default: 0;
  * The inlink descriptor address when spi dma produce receiving error.
@@ -2013,7 +2013,7 @@
 
 /* SPI_IN_SUC_EOF_DES_ADDR_REG register */
 
-#define SPI_IN_SUC_EOF_DES_ADDR_REG (DR_REG_SPI_BASE + 0x78)
+#define SPI_IN_SUC_EOF_DES_ADDR_REG(i) (REG_SPI_BASE(i) + 0x78)
 
 /* SPI_DMA_IN_SUC_EOF_DES_ADDR : RO; bitpos: [31:0]; default: 0;
  * The last inlink descriptor address when spi dma produce from_suc_eof.
@@ -2026,7 +2026,7 @@
 
 /* SPI_INLINK_DSCR_REG register */
 
-#define SPI_INLINK_DSCR_REG (DR_REG_SPI_BASE + 0x7c)
+#define SPI_INLINK_DSCR_REG(i)         (REG_SPI_BASE(i) + 0x7c)
 
 /* SPI_DMA_INLINK_DSCR : RO; bitpos: [31:0]; default: 0;
  * The content of current in descriptor pointer.
@@ -2039,7 +2039,7 @@
 
 /* SPI_INLINK_DSCR_BF0_REG register */
 
-#define SPI_INLINK_DSCR_BF0_REG (DR_REG_SPI_BASE + 0x80)
+#define SPI_INLINK_DSCR_BF0_REG(i)       (REG_SPI_BASE(i) + 0x80)
 
 /* SPI_DMA_INLINK_DSCR_BF0 : RO; bitpos: [31:0]; default: 0;
  * The content of next in descriptor pointer.
@@ -2052,7 +2052,7 @@
 
 /* SPI_INLINK_DSCR_BF1_REG register */
 
-#define SPI_INLINK_DSCR_BF1_REG (DR_REG_SPI_BASE + 0x84)
+#define SPI_INLINK_DSCR_BF1_REG(i)       (REG_SPI_BASE(i) + 0x84)
 
 /* SPI_DMA_INLINK_DSCR_BF1 : RO; bitpos: [31:0]; default: 0;
  * The content of current in descriptor data buffer pointer.
@@ -2065,7 +2065,7 @@
 
 /* SPI_OUT_EOF_BFR_DES_ADDR_REG register */
 
-#define SPI_OUT_EOF_BFR_DES_ADDR_REG (DR_REG_SPI_BASE + 0x88)
+#define SPI_OUT_EOF_BFR_DES_ADDR_REG(i)    (REG_SPI_BASE(i) + 0x88)
 
 /* SPI_DMA_OUT_EOF_BFR_DES_ADDR : RO; bitpos: [31:0]; default: 0;
  * The address of buffer relative to the outlink descriptor that produce eof.
@@ -2078,7 +2078,7 @@
 
 /* SPI_OUT_EOF_DES_ADDR_REG register */
 
-#define SPI_OUT_EOF_DES_ADDR_REG (DR_REG_SPI_BASE + 0x8c)
+#define SPI_OUT_EOF_DES_ADDR_REG(i)     (REG_SPI_BASE(i) + 0x8c)
 
 /* SPI_DMA_OUT_EOF_DES_ADDR : RO; bitpos: [31:0]; default: 0;
  * The last outlink descriptor address when spi dma produce to_eof.
@@ -2091,7 +2091,7 @@
 
 /* SPI_OUTLINK_DSCR_REG register */
 
-#define SPI_OUTLINK_DSCR_REG (DR_REG_SPI_BASE + 0x90)
+#define SPI_OUTLINK_DSCR_REG(i)     (REG_SPI_BASE(i) + 0x90)
 
 /* SPI_DMA_OUTLINK_DSCR : RO; bitpos: [31:0]; default: 0;
  * The content of current out descriptor pointer.
@@ -2104,7 +2104,7 @@
 
 /* SPI_OUTLINK_DSCR_BF0_REG register */
 
-#define SPI_OUTLINK_DSCR_BF0_REG (DR_REG_SPI_BASE + 0x94)
+#define SPI_OUTLINK_DSCR_BF0_REG(i)       (REG_SPI_BASE(i) + 0x94)
 
 /* SPI_DMA_OUTLINK_DSCR_BF0 : RO; bitpos: [31:0]; default: 0;
  * The content of next out descriptor pointer.
@@ -2117,7 +2117,7 @@
 
 /* SPI_OUTLINK_DSCR_BF1_REG register */
 
-#define SPI_OUTLINK_DSCR_BF1_REG (DR_REG_SPI_BASE + 0x98)
+#define SPI_OUTLINK_DSCR_BF1_REG(i)       (REG_SPI_BASE(i) + 0x98)
 
 /* SPI_DMA_OUTLINK_DSCR_BF1 : RO; bitpos: [31:0]; default: 0;
  * The content of current out descriptor data buffer pointer.
@@ -2130,7 +2130,7 @@
 
 /* SPI_DMA_OUTSTATUS_REG register */
 
-#define SPI_DMA_OUTSTATUS_REG (DR_REG_SPI_BASE + 0x9c)
+#define SPI_DMA_OUTSTATUS_REG(i)       (REG_SPI_BASE(i) + 0x9c)
 
 /* SPI_DMA_OUTFIFO_EMPTY : RO; bitpos: [31]; default: 1;
  * SPI dma outfifo is empty.
@@ -2188,7 +2188,7 @@
 
 /* SPI_DMA_INSTATUS_REG register */
 
-#define SPI_DMA_INSTATUS_REG (DR_REG_SPI_BASE + 0xa0)
+#define SPI_DMA_INSTATUS_REG(i)       (REG_SPI_BASE(i) + 0xa0)
 
 /* SPI_DMA_INFIFO_EMPTY : RO; bitpos: [31]; default: 1;
  * SPI dma infifo is empty.
@@ -2246,7 +2246,7 @@
 
 /* SPI_W0_REG register */
 
-#define SPI_W0_REG (DR_REG_SPI_BASE + 0xa4)
+#define SPI_W0_REG(i)      (REG_SPI_BASE(i) + 0xa4)
 
 /* SPI_BUF0 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2259,7 +2259,7 @@
 
 /* SPI_W1_REG register */
 
-#define SPI_W1_REG (DR_REG_SPI_BASE + 0xa8)
+#define SPI_W1_REG(i)      (REG_SPI_BASE(i) + 0xa8)
 
 /* SPI_BUF1 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2272,7 +2272,7 @@
 
 /* SPI_W2_REG register */
 
-#define SPI_W2_REG (DR_REG_SPI_BASE + 0xac)
+#define SPI_W2_REG(i)      (REG_SPI_BASE(i) + 0xac)
 
 /* SPI_BUF2 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2285,7 +2285,7 @@
 
 /* SPI_W3_REG register */
 
-#define SPI_W3_REG (DR_REG_SPI_BASE + 0xb0)
+#define SPI_W3_REG(i)      (REG_SPI_BASE(i) + 0xb0)
 
 /* SPI_BUF3 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2298,7 +2298,7 @@
 
 /* SPI_W4_REG register */
 
-#define SPI_W4_REG (DR_REG_SPI_BASE + 0xb4)
+#define SPI_W4_REG(i)      (REG_SPI_BASE(i) + 0xb4)
 
 /* SPI_BUF4 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2311,7 +2311,7 @@
 
 /* SPI_W5_REG register */
 
-#define SPI_W5_REG (DR_REG_SPI_BASE + 0xb8)
+#define SPI_W5_REG(i)      (REG_SPI_BASE(i) + 0xb8)
 
 /* SPI_BUF5 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2324,7 +2324,7 @@
 
 /* SPI_W6_REG register */
 
-#define SPI_W6_REG (DR_REG_SPI_BASE + 0xbc)
+#define SPI_W6_REG(i)      (REG_SPI_BASE(i) + 0xbc)
 
 /* SPI_BUF6 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2337,7 +2337,7 @@
 
 /* SPI_W7_REG register */
 
-#define SPI_W7_REG (DR_REG_SPI_BASE + 0xc0)
+#define SPI_W7_REG(i)      (REG_SPI_BASE(i) + 0xc0)
 
 /* SPI_BUF7 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2350,7 +2350,7 @@
 
 /* SPI_W8_REG register */
 
-#define SPI_W8_REG (DR_REG_SPI_BASE + 0xc4)
+#define SPI_W8_REG(i)      (REG_SPI_BASE(i) + 0xc4)
 
 /* SPI_BUF8 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2363,7 +2363,7 @@
 
 /* SPI_W9_REG register */
 
-#define SPI_W9_REG (DR_REG_SPI_BASE + 0xc8)
+#define SPI_W9_REG(i)      (REG_SPI_BASE(i) + 0xc8)
 
 /* SPI_BUF9 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2376,7 +2376,7 @@
 
 /* SPI_W10_REG register */
 
-#define SPI_W10_REG (DR_REG_SPI_BASE + 0xcc)
+#define SPI_W10_REG(i)      (REG_SPI_BASE(i) + 0xcc)
 
 /* SPI_BUF10 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2389,7 +2389,7 @@
 
 /* SPI_W11_REG register */
 
-#define SPI_W11_REG (DR_REG_SPI_BASE + 0xd0)
+#define SPI_W11_REG(i)      (REG_SPI_BASE(i) + 0xd0)
 
 /* SPI_BUF11 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2402,7 +2402,7 @@
 
 /* SPI_W12_REG register */
 
-#define SPI_W12_REG (DR_REG_SPI_BASE + 0xd4)
+#define SPI_W12_REG(i)      (REG_SPI_BASE(i) + 0xd4)
 
 /* SPI_BUF12 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2415,7 +2415,7 @@
 
 /* SPI_W13_REG register */
 
-#define SPI_W13_REG (DR_REG_SPI_BASE + 0xd8)
+#define SPI_W13_REG(i)      (REG_SPI_BASE(i) + 0xd8)
 
 /* SPI_BUF13 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2428,7 +2428,7 @@
 
 /* SPI_W14_REG register */
 
-#define SPI_W14_REG (DR_REG_SPI_BASE + 0xdc)
+#define SPI_W14_REG(i)      (REG_SPI_BASE(i) + 0xdc)
 
 /* SPI_BUF14 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2441,7 +2441,7 @@
 
 /* SPI_W15_REG register */
 
-#define SPI_W15_REG (DR_REG_SPI_BASE + 0xe0)
+#define SPI_W15_REG(i)      (REG_SPI_BASE(i) + 0xe0)
 
 /* SPI_BUF15 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2454,7 +2454,7 @@
 
 /* SPI_W16_REG register */
 
-#define SPI_W16_REG (DR_REG_SPI_BASE + 0xe4)
+#define SPI_W16_REG(i)      (REG_SPI_BASE(i) + 0xe4)
 
 /* SPI_BUF16 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2467,7 +2467,7 @@
 
 /* SPI_W17_REG register */
 
-#define SPI_W17_REG (DR_REG_SPI_BASE + 0xe8)
+#define SPI_W17_REG(i)      (REG_SPI_BASE(i) + 0xe8)
 
 /* SPI_BUF17 : R/W; bitpos: [31:0]; default: 0;
  * data buffer
@@ -2480,7 +2480,7 @@
 
 /* SPI_DIN_MODE_REG register */
 
-#define SPI_DIN_MODE_REG (DR_REG_SPI_BASE + 0xec)
+#define SPI_DIN_MODE_REG(i)          (REG_SPI_BASE(i) + 0xec)
 
 /* SPI_TIMING_CLK_ENA : R/W; bitpos: [24]; default: 0;
  * 1:enable hclk in spi_timing.v.  0: disable it.
@@ -2597,7 +2597,7 @@
 
 /* SPI_DIN_NUM_REG register */
 
-#define SPI_DIN_NUM_REG (DR_REG_SPI_BASE + 0xf0)
+#define SPI_DIN_NUM_REG(i)     (REG_SPI_BASE(i) + 0xf0)
 
 /* SPI_DIN7_NUM : R/W; bitpos: [15:14]; default: 0;
  * the input signals are delayed by system clock cycles, 0: delayed by 1
@@ -2681,7 +2681,7 @@
 
 /* SPI_DOUT_MODE_REG register */
 
-#define SPI_DOUT_MODE_REG (DR_REG_SPI_BASE + 0xf4)
+#define SPI_DOUT_MODE_REG(i)     (REG_SPI_BASE(i) + 0xf4)
 
 /* SPI_DOUT7_MODE : R/W; bitpos: [23:21]; default: 0;
  * Configure the output signal delay mode. 0: without delayed, 1: with the
@@ -2789,7 +2789,7 @@
 
 /* SPI_DOUT_NUM_REG register */
 
-#define SPI_DOUT_NUM_REG (DR_REG_SPI_BASE + 0xf8)
+#define SPI_DOUT_NUM_REG(i)     (REG_SPI_BASE(i) + 0xf8)
 
 /* SPI_DOUT7_NUM : R/W; bitpos: [15:14]; default: 0;
  * the output signals are delayed by system clock cycles, 0: delayed by 1
@@ -2873,7 +2873,7 @@
 
 /* SPI_LCD_CTRL_REG register */
 
-#define SPI_LCD_CTRL_REG (DR_REG_SPI_BASE + 0xfc)
+#define SPI_LCD_CTRL_REG(i)     (REG_SPI_BASE(i) + 0xfc)
 
 /* SPI_LCD_SRGB_MODE_EN : R/W; bitpos: [31]; default: 0;
  * 1: Enable LCD mode output vsync, hsync, de. 0: Disable.
@@ -2913,7 +2913,7 @@
 
 /* SPI_LCD_CTRL1_REG register */
 
-#define SPI_LCD_CTRL1_REG (DR_REG_SPI_BASE + 0x100)
+#define SPI_LCD_CTRL1_REG(i)       (REG_SPI_BASE(i) + 0x100)
 
 /* SPI_LCD_HT_WIDTH : R/W; bitpos: [31:20]; default: 0;
  * It is the horizontal total width of a frame.
@@ -2944,7 +2944,7 @@
 
 /* SPI_LCD_CTRL2_REG register */
 
-#define SPI_LCD_CTRL2_REG (DR_REG_SPI_BASE + 0x104)
+#define SPI_LCD_CTRL2_REG(i)      (REG_SPI_BASE(i) + 0x104)
 
 /* SPI_LCD_HSYNC_POSITION : R/W; bitpos: [31:24]; default: 0;
  * It is the position of spi_hsync_out active pulse in a line.
@@ -3002,7 +3002,7 @@
 
 /* SPI_LCD_D_MODE_REG register */
 
-#define SPI_LCD_D_MODE_REG (DR_REG_SPI_BASE + 0x108)
+#define SPI_LCD_D_MODE_REG(i)      (REG_SPI_BASE(i) + 0x108)
 
 /* SPI_D_VSYNC_MODE : R/W; bitpos: [14:12]; default: 0;
  * Configure the output  spi_vsync delay mode. 0: without delayed, 1: with
@@ -3071,7 +3071,7 @@
 
 /* SPI_LCD_D_NUM_REG register */
 
-#define SPI_LCD_D_NUM_REG (DR_REG_SPI_BASE + 0x10c)
+#define SPI_LCD_D_NUM_REG(i)      (REG_SPI_BASE(i) + 0x10c)
 
 /* SPI_D_VSYNC_NUM : R/W; bitpos: [9:8]; default: 0;
  * the output spi_vsync is delayed by system clock cycles, 0: delayed by 1
@@ -3125,7 +3125,7 @@
 
 /* SPI_REG_DATE_REG register */
 
-#define SPI_REG_DATE_REG (DR_REG_SPI_BASE + 0x3fc)
+#define SPI_REG_DATE_REG(i) (REG_SPI_BASE(i) + 0x3fc)
 
 /* SPI_DATE : RW; bitpos: [27:0]; default: 26222993;
  * SPI register version.