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

xiaoxiang 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 091372069c risc-v/bl808: Add SPI driver
091372069c is described below

commit 091372069c831ed63ddf2ec0ef7a998f9fc9a639
Author: Henry Rovner <[email protected]>
AuthorDate: Sat Jul 6 15:23:51 2024 -0700

    risc-v/bl808: Add SPI driver
    
    This commit implements a driver for SPI0 and SPI1 on the BL808 and 
introduces an accompanying example configuration.
---
 .../platforms/risc-v/bl808/boards/ox64/index.rst   |    7 +
 Documentation/platforms/risc-v/bl808/index.rst     |    2 +-
 arch/risc-v/include/bl808/irq.h                    |    2 +
 arch/risc-v/src/bl808/Kconfig                      |   94 ++
 arch/risc-v/src/bl808/Make.defs                    |    2 +-
 arch/risc-v/src/bl808/bl808_gpio.h                 |   37 +-
 arch/risc-v/src/bl808/bl808_spi.c                  | 1337 ++++++++++++++++++++
 arch/risc-v/src/bl808/bl808_spi.h                  |   72 ++
 arch/risc-v/src/bl808/hardware/bl808_glb.h         |   19 +
 arch/risc-v/src/bl808/hardware/bl808_memorymap.h   |    3 +
 .../bl808/hardware/{bl808_glb.h => bl808_mm_glb.h} |   45 +-
 arch/risc-v/src/bl808/hardware/bl808_spi.h         |  144 +++
 boards/risc-v/bl808/ox64/configs/spi/defconfig     |  100 ++
 boards/risc-v/bl808/ox64/src/bl808_appinit.c       |   13 +
 14 files changed, 1829 insertions(+), 48 deletions(-)

diff --git a/Documentation/platforms/risc-v/bl808/boards/ox64/index.rst 
b/Documentation/platforms/risc-v/bl808/boards/ox64/index.rst
index 9313dd2cbf..85d245ce7d 100644
--- a/Documentation/platforms/risc-v/bl808/boards/ox64/index.rst
+++ b/Documentation/platforms/risc-v/bl808/boards/ox64/index.rst
@@ -143,3 +143,10 @@ adc
 This configuration enables support for the general purpose ADC and the adc 
example app.
 By default, the ADC will scan external channels 3, 4, 6, 7 and 9 (GPIO pins 
11, 6, 12,
 13 and 18). Serial Console is enabled on UART3 at 2 Mbps.
+
+spi
+---
+
+This configuration enables support for SPI0 and spitool.
+By default, GPIO14 is MISO, 13 is MOSI, 15 is SCLK and 12 is SS.
+Serial Console is enabled on UART3 at 2 Mbps.
diff --git a/Documentation/platforms/risc-v/bl808/index.rst 
b/Documentation/platforms/risc-v/bl808/index.rst
index a91742fe22..f8f9d95d44 100644
--- a/Documentation/platforms/risc-v/bl808/index.rst
+++ b/Documentation/platforms/risc-v/bl808/index.rst
@@ -51,7 +51,7 @@ GPIO         Yes
 I2C          No
 I2S          No
 PWM          No
-SPI          No
+SPI          Yes
 Timers       No
 UART         Yes
 USB          No
diff --git a/arch/risc-v/include/bl808/irq.h b/arch/risc-v/include/bl808/irq.h
index 4de1636b05..0b743f1063 100644
--- a/arch/risc-v/include/bl808/irq.h
+++ b/arch/risc-v/include/bl808/irq.h
@@ -52,12 +52,14 @@
 /* D0 IRQs ******************************************************************/
 
 #define BL808_IRQ_UART3 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 4)
+#define BL808_IRQ_SPI1 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 7)
 #define BL808_IRQ_D0_IPC (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 38)
 #define BL808_IRQ_M0IC (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 65)
 
 /* M0 IRQs ******************************************************************/
 
 #define BL808_IRQ_GPADC (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 
BL808_M0_IRQ_OFFSET + 25)
+#define BL808_IRQ_SPI0  (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 
BL808_M0_IRQ_OFFSET + 27)
 #define BL808_IRQ_UART0 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 
BL808_M0_IRQ_OFFSET + 28)
 #define BL808_IRQ_UART1 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 
BL808_M0_IRQ_OFFSET + 29)
 #define BL808_IRQ_UART2 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 
BL808_M0_IRQ_OFFSET + 30)
diff --git a/arch/risc-v/src/bl808/Kconfig b/arch/risc-v/src/bl808/Kconfig
index 0766d0dd5b..0156783813 100644
--- a/arch/risc-v/src/bl808/Kconfig
+++ b/arch/risc-v/src/bl808/Kconfig
@@ -130,4 +130,98 @@ config BL808_UART3
        select UART3_SERIALDRIVER
        select ARCH_HAVE_SERIAL_TERMIOS
 
+menuconfig BL808_SPI0
+       bool "SPI 0"
+       default n
+       select SPI
+
+if BL808_SPI0
+
+config BL808_SPI0_DEG_ENABLE
+       bool "Deglitch enable"
+       default y
+
+config BL808_SPI0_CONT_ENABLE
+       bool "Continuous transfer mode"
+       default y
+
+config BL808_SPI0_BYTE_INV
+       bool "Invert byte transfer order"
+       default n
+
+config BL808_SPI0_BIT_INV
+       bool "Invert bit transfer order"
+       default n
+
+comment "Refer to datasheet for valid pin assignments"
+
+config BL808_SPI0_MISO
+       int "MISO Pin"
+       default 14
+       range 0 45
+
+config BL808_SPI0_MOSI
+       int "MOSI Pin"
+       default 13
+       range 0 45
+
+config BL808_SPI0_SCLK
+       int "SCLK Pin"
+       default 15
+       range 0 45
+
+config BL808_SPI0_SS
+       int "SS Pin"
+       default 12
+       range 0 45
+
+endif
+
+menuconfig BL808_SPI1
+       bool "SPI 1"
+       default n
+       select SPI
+
+if BL808_SPI1
+
+config BL808_SPI1_DEG_ENABLE
+       bool "Deglitch enable"
+       default y
+
+config BL808_SPI1_CONT_ENABLE
+       bool "Continuous transfer mode"
+       default y
+
+config BL808_SPI1_BYTE_INV
+       bool "Invert byte transfer order"
+       default n
+
+config BL808_SPI1_BIT_INV
+       bool "Invert bit transfer order"
+       default n
+
+comment "Refer to datasheet for valid pin assignments"
+
+config BL808_SPI1_MISO
+       int "MISO Pin"
+       default 14
+       range 0 45
+
+config BL808_SPI1_MOSI
+       int "MOSI Pin"
+       default 13
+       range 0 45
+
+config BL808_SPI1_SCLK
+       int "SCLK Pin"
+       default 15
+       range 0 45
+
+config BL808_SPI1_SS
+       int "SS Pin"
+       default 12
+       range 0 45
+
+endif
+
 endmenu
diff --git a/arch/risc-v/src/bl808/Make.defs b/arch/risc-v/src/bl808/Make.defs
index 89e9abe62c..ffb276ace9 100644
--- a/arch/risc-v/src/bl808/Make.defs
+++ b/arch/risc-v/src/bl808/Make.defs
@@ -28,4 +28,4 @@ HEAD_ASRC = bl808_head.S
 CHIP_CSRCS  = bl808_start.c bl808_irq_dispatch.c bl808_irq.c
 CHIP_CSRCS += bl808_timerisr.c bl808_allocateheap.c
 CHIP_CSRCS += bl808_gpio.c bl808_mm_init.c bl808_pgalloc.c bl808_serial.c
-CHIP_CSRCS += bl808_gpadc.c
+CHIP_CSRCS += bl808_gpadc.c bl808_spi.c
diff --git a/arch/risc-v/src/bl808/bl808_gpio.h 
b/arch/risc-v/src/bl808/bl808_gpio.h
index f9b25c88bd..d51bdea699 100644
--- a/arch/risc-v/src/bl808/bl808_gpio.h
+++ b/arch/risc-v/src/bl808/bl808_gpio.h
@@ -43,7 +43,7 @@
  * 1111 1100 0000 0000
  * 5432 1098 7654 3210
  * ---- ---- ---- ----
- * .... ..MU UDDS FFFF
+ * .... .MUU DDSF FFFF
  */
 
 /* Mode:
@@ -51,10 +51,10 @@
  * 1111 1100 0000 0000
  * 5432 1098 7654 3210
  * ---- ---- ---- ----
- * .... ..M. .... ....
+ * .... .M.. .... ....
  */
 
-#define GPIO_MODE_SHIFT  (9)                     /* Bit 9: Port Mode */
+#define GPIO_MODE_SHIFT  (10)                     /* Bit 10: Port Mode */
 #define GPIO_MODE_MASK   (1 << GPIO_MODE_SHIFT)
 #  define GPIO_INPUT     (1 << GPIO_MODE_SHIFT)  /* Input Enable */
 #  define GPIO_OUTPUT    (0 << GPIO_MODE_SHIFT)  /* Output Enable */
@@ -64,10 +64,10 @@
  * 1111 1100 0000 0000
  * 5432 1098 7654 3210
  * ---- ---- ---- ----
- * .... ...U U... ....
+ * .... ..UU .... ....
  */
 
-#define GPIO_PUPD_SHIFT (7) /* Bits 7-8: Pull-up/down */
+#define GPIO_PUPD_SHIFT (8) /* Bits 8-9: Pull-up/down */
 #define GPIO_PUPD_MASK  (3 << GPIO_PUPD_SHIFT)
 #define GPIO_FLOAT      (0 << GPIO_PUPD_SHIFT) /* No pull-up, pull-down */
 #define GPIO_PULLUP     (1 << GPIO_PUPD_SHIFT) /* Pull-up */
@@ -78,10 +78,10 @@
  * 1111 1100 0000 0000
  * 5432 1098 7654 3210
  * ---- ---- ---- ----
- * .... .... .DD. ....
+ * .... .... DD.. ....
  */
 
-#define GPIO_DRV_SHIFT (5) /* Bits 5-6: Drive */
+#define GPIO_DRV_SHIFT (6) /* Bits 6-7: Drive */
 #define GPIO_DRV_MASK  (3 << GPIO_DRV_SHIFT)
 #define GPIO_DRV_0     (0 << GPIO_DRV_SHIFT)
 #define GPIO_DRV_1     (1 << GPIO_DRV_SHIFT)
@@ -93,10 +93,10 @@
  * 1111 1100 0000 0000
  * 5432 1098 7654 3210
  * ---- ---- ---- ----
- * .... .... ...S ....
+ * .... .... ..S. ....
  */
 
-#define GPIO_SMT_SHIFT (4) /* Bit 4: SMT Enable */
+#define GPIO_SMT_SHIFT (5) /* Bit 5: SMT Enable */
 #define GPIO_SMT_MASK  (3 << GPIO_SMT_SHIFT)
 #define GPIO_SMT_DIS   (0 << GPIO_SMT_SHIFT)
 #define GPIO_SMT_EN    (1 << GPIO_SMT_SHIFT)
@@ -106,21 +106,22 @@
  * 1111 1100 0000 0000
  * 5432 1098 7654 3210
  * ---- ---- ---- ----
- * .... .... .... FFFF
+ * .... .... ...F FFFF
  */
 
-#define GPIO_FUNC_SHIFT  (0) /* Bits 0-3: GPIO Type */
-#define GPIO_FUNC_MASK   (15 << GPIO_FUNC_SHIFT)
-#define GPIO_FUNC_SDIO   (1  << GPIO_FUNC_SHIFT)  /* SDIO */
+#define GPIO_FUNC_SHIFT  (0) /* Bits 0-4: GPIO Type */
+#define GPIO_FUNC_MASK   (0x1f << GPIO_FUNC_SHIFT)
+#define GPIO_FUNC_SDH    (0  << GPIO_FUNC_SHIFT)  /* SDH */
+#define GPIO_FUNC_SPI0   (1  << GPIO_FUNC_SHIFT)  /* SPI0 */
 #define GPIO_FUNC_FLASH  (2  << GPIO_FUNC_SHIFT)  /* Flash */
-#define GPIO_FUNC_SPI    (4  << GPIO_FUNC_SHIFT)  /* SPI */
-#define GPIO_FUNC_I2C    (6  << GPIO_FUNC_SHIFT)  /* I2C */
+#define GPIO_FUNC_I2C1   (6  << GPIO_FUNC_SHIFT)  /* I2C1 */
 #define GPIO_FUNC_UART   (7  << GPIO_FUNC_SHIFT)  /* UART */
-#define GPIO_FUNC_PWM    (8  << GPIO_FUNC_SHIFT)  /* PWM */
-#define GPIO_FUNC_EXT_PA (9  << GPIO_FUNC_SHIFT)  /* Analog */
+#define GPIO_FUNC_CAM    (9  << GPIO_FUNC_SHIFT)  /* CSI */
 #define GPIO_FUNC_ANA    (10 << GPIO_FUNC_SHIFT)  /* Analog */
 #define GPIO_FUNC_SWGPIO (11 << GPIO_FUNC_SHIFT)  /* Software GPIO */
-#define GPIO_FUNC_JTAG   (14 << GPIO_FUNC_SHIFT)  /* JTAG */
+#define GPIO_FUNC_PWM0   (16 << GPIO_FUNC_SHIFT)  /* PWM0 */
+#define GPIO_FUNC_SPI1   (18 << GPIO_FUNC_SHIFT)  /* SPI1 */
+#define GPIO_FUNC_JTAG_D0 (27 << GPIO_FUNC_SHIFT) /* JTAG */
 
 /****************************************************************************
  * Public Types
diff --git a/arch/risc-v/src/bl808/bl808_spi.c 
b/arch/risc-v/src/bl808/bl808_spi.c
new file mode 100644
index 0000000000..2e00f32a6a
--- /dev/null
+++ b/arch/risc-v/src/bl808/bl808_spi.c
@@ -0,0 +1,1337 @@
+/****************************************************************************
+ * arch/risc-v/src/bl808/bl808_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>
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/compiler.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/mutex.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/signal.h>
+#include <nuttx/spi/spi.h>
+
+#include <arch/board/board.h>
+
+#include "bl808_gpio.h"
+#include "bl808_spi.h"
+#include "hardware/bl808_glb.h"
+#include "hardware/bl808_mm_glb.h"
+#include "hardware/bl808_spi.h"
+#include "riscv_internal.h"
+
+/* This file is based on bl602/bl602_spi.c */
+
+#if defined(CONFIG_BL808_SPI0) || defined(CONFIG_BL808_SPI1)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define SPI_FREQ_DEFAULT 400000
+#define SPI_CLK_PRE_DIV 160000000
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* SPI frequency cal configuration */
+
+struct prescale_and_count_cal_ctx_s
+{
+  uint64_t desired_ticks;
+  uint64_t count_max;
+  uint64_t error;
+  uint64_t count;
+  uint32_t prescale;
+  uint8_t update;
+};
+
+/* SPI clock configuration */
+
+struct spi_clock_cfg_s
+{
+  uint8_t start_len;       /* Length of start condition */
+  uint8_t stop_len;        /* Length of stop condition */
+  uint8_t data_phase0_len; /* Length of data phase 0,affecting clock */
+  uint8_t data_phase1_len; /* Length of data phase 1,affecting clock */
+  uint8_t interval_len;    /* Length of interval between frame */
+};
+
+/* SPI Device hardware configuration */
+
+struct bl808_spi_config_s
+{
+  uint32_t clk_freq;      /* SPI clock frequency */
+  enum spi_mode_e mode;   /* SPI default mode */
+
+  bool deglitch_enable;   /* Enable or disable de-glitch function */
+  bool continuous_enable; /* Enable or disable master continuous transfer
+                           * mode,enable:SS will stay asserted if next data
+                           * is valid
+                           */
+  bool byte_invert;       /* The byte is sent first in SPI transfer ,0 is send
+                           * 0byte first; 1 is send 3byte first
+                           */
+  bool bit_invert;        /* The bit is sent first in SPI transfer ,0 is each 
byte
+                           * is sent out MSB first; 1 is each byte is sent out 
LSB
+                           * first
+                           */
+};
+
+struct bl808_spi_priv_s
+{
+  /* Externally visible part of the SPI interface */
+
+  struct spi_dev_s spi_dev;
+
+  /* SPI block ID */
+
+  uint8_t idx;
+
+  /* Port configuration */
+
+  const struct bl808_spi_config_s *config;
+
+  int refs; /* Referernce count */
+
+  /* Held while chip is selected for mutual exclusion */
+
+  mutex_t lock;
+
+  uint32_t frequency; /* Requested clock frequency */
+  uint32_t actual;    /* Actual clock frequency */
+
+  enum spi_mode_e mode; /* Actual SPI hardware mode */
+
+  /* Actual SPI send/receive bits once transmission */
+
+  uint8_t nbits;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int bl808_spi_lock(struct spi_dev_s *dev, bool lock);
+
+static void bl808_spi_select(struct spi_dev_s *dev, uint32_t devid,
+                             bool selected);
+
+static uint32_t bl808_spi_setfrequency(struct spi_dev_s *dev,
+                                       uint32_t frequency);
+static void bl808_spi_setmode(struct spi_dev_s *dev,
+                              enum spi_mode_e mode);
+static void bl808_spi_setbits(struct spi_dev_s *dev, int nbits);
+#ifdef CONFIG_SPI_HWFEATURES
+static int bl808_spi_hwfeatures(struct spi_dev_s *dev,
+                                spi_hwfeatures_t features);
+#endif
+static uint8_t bl808_spi_status(struct spi_dev_s *dev,
+                                uint32_t devid);
+#ifdef CONFIG_SPI_CMDDATA
+static int bl808_spi_cmddata(struct spi_dev_s *dev,
+                              uint32_t devid, bool cmd);
+#endif
+static uint32_t bl808_spi_send(struct spi_dev_s *dev, uint32_t wd);
+static void bl808_spi_exchange(struct spi_dev_s *dev,
+                               const void *txbuffer,
+                               void *rxbuffer, size_t nwords);
+#ifndef CONFIG_SPI_EXCHANGE
+static void bl808_spi_sndblock(struct spi_dev_s *dev,
+                               const void *txbuffer, size_t nwords);
+static void bl808_spi_recvblock(struct spi_dev_s *dev,
+                                void *rxbuffer, size_t nwords);
+#endif
+#ifdef CONFIG_SPI_TRIGGER
+static int bl808_spi_trigger(struct spi_dev_s *dev);
+#endif
+static void bl808_spi_init(struct spi_dev_s *dev);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct spi_ops_s bl808_spi_ops =
+{
+    .lock = bl808_spi_lock,
+    .select = bl808_spi_select,
+    .setfrequency = bl808_spi_setfrequency,
+#ifdef CONFIG_SPI_DELAY_CONTROL
+    .setdelay = bl808_spi_setdelay,
+#endif
+    .setmode = bl808_spi_setmode,
+    .setbits = bl808_spi_setbits,
+#ifdef CONFIG_SPI_HWFEATURES
+    .hwfeatures = bl808_spi_hwfeatures,
+#endif
+    .status = bl808_spi_status,
+#ifdef CONFIG_SPI_CMDDATA
+    .cmddata = bl808_spi_cmddata,
+#endif
+    .send = bl808_spi_send,
+#ifdef CONFIG_SPI_EXCHANGE
+    .exchange = bl808_spi_exchange,
+#else
+    .sndblock = bl808_spi_sndblock,
+    .recvblock = bl808_spi_recvblock,
+#endif
+#ifdef CONFIG_SPI_TRIGGER
+    .trigger = bl808_spi_trigger,
+#endif
+    .registercallback = NULL,
+};
+
+#ifdef CONFIG_BL808_SPI0
+static const struct bl808_spi_config_s bl808_spi0_config =
+{
+    .clk_freq = SPI_FREQ_DEFAULT,
+    .mode = SPIDEV_MODE0,
+
+#ifdef CONFIG_BL808_SPI0_DEG_ENABLE
+    .deglitch_enable = 1,
+#else
+    .deglitch_enable = 0,
+#endif
+
+#ifdef CONFIG_BL808_SPI0_CONT_ENABLE
+    .continuous_enable = 1,
+#else
+    .continuous_enable = 0,
+#endif
+
+#ifdef CONFIG_BL808_SPI0_BYTE_INV
+    .byte_invert = 1,
+#else
+    .byte_invert = 0,
+#endif
+
+#ifdef CONFIG_BL808_SPI0_BIT_INV
+    .bit_invert = 1,
+#else
+    .bit_invert = 0,
+#endif
+};
+
+static struct bl808_spi_priv_s bl808_spi0_priv =
+{
+  .spi_dev =
+  {
+    .ops      = &bl808_spi_ops
+  },
+  .idx        = 0,
+  .config     = &bl808_spi0_config,
+  .lock       = NXMUTEX_INITIALIZER,
+};
+
+#endif  /* CONFIG_BL808_SPI0 */
+
+#ifdef CONFIG_BL808_SPI1
+static const struct bl808_spi_config_s bl808_spi1_config =
+{
+    .clk_freq = SPI_FREQ_DEFAULT,
+    .mode = SPIDEV_MODE0,
+
+#ifdef CONFIG_BL808_SPI1_DEG_ENABLE
+    .deglitch_enable = 1,
+#else
+    .deglitch_enable = 0,
+#endif
+
+#ifdef CONFIG_BL808_SPI1_CONT_ENABLE
+    .continuous_enable = 1,
+#else
+    .continuous_enable = 0,
+#endif
+
+#ifdef CONFIG_BL808_SPI1_BYTE_INV
+    .byte_invert = 1,
+#else
+    .byte_invert = 0,
+#endif
+
+#ifdef CONFIG_BL808_SPI1_BIT_INV
+    .bit_invert = 1,
+#else
+    .bit_invert = 0,
+#endif
+};
+
+static struct bl808_spi_priv_s bl808_spi1_priv =
+{
+  .spi_dev =
+  {
+    .ops      = &bl808_spi_ops
+  },
+  .idx        = 1,
+  .config     = &bl808_spi1_config,
+  .lock       = NXMUTEX_INITIALIZER,
+};
+
+#endif  /* CONFIG_BL808_SPI1 */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: bl808_check_with_new_prescale
+ *
+ * Description:
+ *   Check if the option prescale
+ *
+ ****************************************************************************/
+
+static void
+bl808_check_with_new_prescale(struct prescale_and_count_cal_ctx_s *p_ctx,
+                                    uint32_t prescale_new)
+{
+  uint64_t count = p_ctx->desired_ticks / prescale_new;
+  uint64_t error;
+
+  if (count > p_ctx->count_max)
+    {
+      count = p_ctx->count_max;
+    }
+
+  error = p_ctx->desired_ticks - count * prescale_new;
+
+  if (p_ctx->error > error)
+    {
+      p_ctx->error = error;
+      p_ctx->count = count;
+      p_ctx->prescale = prescale_new;
+      p_ctx->update = 1;
+    }
+}
+
+/****************************************************************************
+ * Name: bl808_prescale_and_count_cal
+ *
+ * Description:
+ *   prescale and count cal
+ *
+ ****************************************************************************/
+
+static int
+bl808_prescale_and_count_cal(uint32_t counter_width,
+                            uint32_t prescale_max, size_t ticks,
+                            uint32_t *p_prescale, size_t *p_count)
+{
+  struct prescale_and_count_cal_ctx_s ctx;
+
+  uint32_t prescale_min;
+  uint32_t prescale;
+
+  size_t count_max;
+
+  count_max = ((uint64_t)1ull << counter_width) - 1;
+
+  if (ticks <= count_max)
+    {
+      *p_prescale = 1;
+      *p_count = ticks;
+
+      return 0;
+    }
+
+  prescale_min = ticks / count_max;
+
+  ctx.count_max = count_max;
+  ctx.desired_ticks = ticks;
+  ctx.error = ticks;
+  ctx.count = count_max;
+  ctx.prescale = 1;
+  ctx.update = 0;
+
+  if (prescale_max < prescale_min)
+    {
+      return -1;
+    }
+
+  for (prescale = prescale_min; prescale <= prescale_max; prescale++)
+    {
+      bl808_check_with_new_prescale(&ctx, prescale);
+      if (ctx.error == 0)
+        {
+          break;
+        }
+    }
+
+  if (ctx.update)
+    {
+      *p_prescale = ctx.prescale;
+      *p_count = ctx.count;
+
+      return 0;
+    }
+
+  return -1;
+}
+
+/****************************************************************************
+ * Name: bl808_set_spi_clk
+ *
+ * Description:
+ *   set SPI clock
+ *
+ ****************************************************************************/
+
+static void bl808_set_spi_clk(uint8_t div, uint8_t idx)
+{
+  if (idx == 0)
+    {
+      modifyreg32(BL808_GLB_SPI_CFG0,
+                  SPI_CFG_CLK_DIV_MASK,
+                  (div << SPI_CFG_CLK_DIV_SHIFT));
+    }
+  else
+    {
+      modifyreg32(BL808_MM_GLB_CLK_CTRL_PERI,
+                  CLK_CTRL_PERI_SPI_DIV_MASK,
+                  (div << CLK_CTRL_PERI_SPI_DIV_SHIFT));
+    }
+}
+
+/****************************************************************************
+ * Name: bl808_clockconfig
+ *
+ * Description:
+ *   SPI clock config
+ *
+ ****************************************************************************/
+
+static void bl808_clockconfig(struct spi_clock_cfg_s *clockcfg, uint8_t idx)
+{
+  /* Configure length of data phase1/0 and start/stop condition */
+
+  modifyreg32(BL808_SPI_PRD_0(idx), SPI_PRD_0_CR_S_MASK,
+              (clockcfg->start_len - 1));
+  modifyreg32(BL808_SPI_PRD_0(idx), SPI_PRD_0_CR_P_MASK,
+              (clockcfg->stop_len - 1) << SPI_PRD_0_CR_P_SHIFT);
+  modifyreg32(BL808_SPI_PRD_0(idx), SPI_PRD_0_CR_D_PH_0_MASK,
+              (clockcfg->data_phase0_len - 1) << SPI_PRD_0_CR_D_PH_0_SHIFT);
+  modifyreg32(BL808_SPI_PRD_0(idx), SPI_PRD_0_CR_D_PH_1_MASK,
+              (clockcfg->data_phase1_len - 1) << SPI_PRD_0_CR_D_PH_1_SHIFT);
+
+  /* Configure length of interval between frame */
+
+  modifyreg32(BL808_SPI_PRD_1(idx), SPI_PRD_1_CR_I_MASK,
+              clockcfg->interval_len - 1);
+}
+
+/****************************************************************************
+ * Name: bl808_spi_lock
+ *
+ * Description:
+ *   Lock or unlock the SPI device
+ *
+ * Input Parameters:
+ *   priv   - Private SPI device structure
+ *   lock   - true: Lock spi bus, false: unlock SPI bus
+ *
+ * Returned Value:
+ *   The result of lock or unlock the SPI device
+ *
+ ****************************************************************************/
+
+static int bl808_spi_lock(struct spi_dev_s *dev, bool lock)
+{
+  int ret;
+  struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+
+  if (lock)
+    {
+      ret = nxmutex_lock(&priv->lock);
+    }
+  else
+    {
+      ret = nxmutex_unlock(&priv->lock);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: bl808_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 disable bl808_SPI_SWCS, driver will use hardware CS so that when
+ *   once transmission is started, hardware select the device and when this
+ *   transmission is done, hardware deselect the device automatically. And
+ *   the function will do nothing.
+ *
+ * Input Parameters:
+ *   priv     - Private SPI device structure
+ *   devid    - Identifies the device to select
+ *   selected - true: slave selected, false: slave de-selected
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void bl808_spi_select(struct spi_dev_s *dev, uint32_t devid,
+                             bool selected)
+{
+  /* we used hardware CS */
+
+  spiinfo("devid: %u, CS: %s\n", devid, selected ? "select" : "free");
+
+#ifdef CONFIG_SPI_CMDDATA
+  /* revert MISO from GPIO Pin to SPI Pin */
+
+  struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+  if (!selected)
+    {
+#ifdef CONFIG_BL808_SPI0
+      if (priv->idx == 0)
+        {
+          bl808_configgpio(CONFIG_BL808_SPI0_MISO,
+                           GPIO_INPUT
+                           | GPIO_DRV_1
+                           | GPIO_SMT_EN
+                           | GPIO_PULLUP
+                           | GPIO_FUNC_SPI0);
+        }
+#endif
+
+#ifdef CONFIG_BL808_SPI1
+      if (priv->idx == 1)
+        {
+          bl808_configgpio(CONFIG_BL808_SPI1_MISO,
+                           GPIO_INPUT
+                           | GPIO_DRV_1
+                           | GPIO_SMT_EN
+                           | GPIO_PULLUP
+                           | GPIO_FUNC_SPI0);
+        }
+#endif
+    }
+#endif
+}
+
+/****************************************************************************
+ * Name: bl808_spi_setfrequency
+ *
+ * Description:
+ *   Set the SPI frequency.
+ *
+ * Input Parameters:
+ *   dev -       Device-specific state data
+ *   frequency - The SPI frequency requested
+ *
+ * Returned Value:
+ *   Returns the actual frequency selected
+ *
+ ****************************************************************************/
+
+static uint32_t bl808_spi_setfrequency(struct spi_dev_s *dev,
+                                       uint32_t frequency)
+{
+  struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+  uint8_t idx = priv->idx;
+  struct spi_clock_cfg_s clockcfg;
+  size_t count;
+  uint32_t ticks;
+  uint32_t clk_div;
+
+  if (priv->frequency == frequency)
+    {
+      /* We are already at this frequency. Return the actual. */
+
+      return priv->actual;
+    }
+
+  ticks = SPI_CLK_PRE_DIV / frequency;
+
+  /* Width of SPI1 clk div is 8, vs 5 for SPI0 */
+
+  uint32_t max_div = (idx == 0) ? 32 : 256;
+
+  if (bl808_prescale_and_count_cal(8, max_div, ticks, &clk_div, &count) != 0)
+    {
+      spierr("SPI div clk error\n");
+      DEBUGPANIC();
+
+      return -1;
+    }
+
+  bl808_set_spi_clk(1, clk_div - 1);
+
+  clockcfg.start_len = count;
+  clockcfg.stop_len = count;
+  clockcfg.data_phase0_len = count;
+  clockcfg.data_phase1_len = count;
+  clockcfg.interval_len = count;
+
+  bl808_clockconfig(&clockcfg, idx);
+
+  priv->frequency = frequency;
+
+  spiinfo("frequency=%u, actual=%u\n", priv->frequency, priv->actual);
+
+  return priv->actual;
+}
+
+/****************************************************************************
+ * Name: bl808_spi_setdelay
+ *
+ * Description:
+ *   Set the SPI Delays in nanoseconds. Optional.
+ *
+ * Input Parameters:
+ *   dev        - Device-specific state data
+ *   startdelay - The delay between CS active and first CLK
+ *   stopdelay  - The delay between last CLK and CS inactive
+ *   csdelay    - The delay between CS inactive and CS active again
+ *   ifdelay    - The delay between frames
+ *
+ * Returned Value:
+ *   Returns zero (OK) on success; a negated errno value is return on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_DELAY_CONTROL
+static int bl808_spi_setdelay(struct spi_dev_s *dev, uint32_t startdelay,
+                                uint32_t stopdelay, uint32_t csdelay,
+                                uint32_t ifdelay)
+{
+  spierr("SPI CS delay control not supported\n");
+  DEBUGPANIC();
+
+  return -1;
+}
+#endif
+
+/****************************************************************************
+ * Name: bl808_spi_setmode
+ *
+ * Description:
+ *   Set the SPI mode.
+ *
+ * Input Parameters:
+ *   dev -  Device-specific state data
+ *   mode - The SPI mode requested
+ *
+ * Returned Value:
+ *   none
+ *
+ ****************************************************************************/
+
+static void
+bl808_spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode)
+{
+  struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+  uint8_t idx = priv->idx;
+
+  spiinfo("mode=%d\n", mode);
+
+  /* Has the mode changed? */
+
+  if (mode != priv->mode)
+    {
+      switch (mode)
+        {
+          /* NOTE: CPHA definition in the register is inverted compared
+           * to the standard. See reference manual or bouffalo_sdk.
+           */
+
+        case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */
+          modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_SCLK_POL,
+                      SPI_CFG_CR_SCLK_PH);
+          break;
+
+        case SPIDEV_MODE1: /* CPOL=0; CPHA=1 */
+          modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_SCLK_POL
+                      | SPI_CFG_CR_SCLK_PH, 0);
+          break;
+
+        case SPIDEV_MODE2: /* CPOL=1; CPHA=0 */
+          modifyreg32(BL808_SPI_CFG(idx), 0, SPI_CFG_CR_SCLK_POL
+                      | SPI_CFG_CR_SCLK_PH);
+          break;
+
+        case SPIDEV_MODE3: /* CPOL=1; CPHA=1 */
+          modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_SCLK_PH,
+                      SPI_CFG_CR_SCLK_POL);
+          break;
+
+        default:
+          return;
+        }
+
+      priv->mode = mode;
+    }
+}
+
+/****************************************************************************
+ * Name: bl808_spi_setbits
+ *
+ * Description:
+ *   Set the number if bits per word.
+ *
+ * Input Parameters:
+ *   dev -  Device-specific state data
+ *   nbits - The number of bits in an SPI word.
+ *
+ * Returned Value:
+ *   none
+ *
+ ****************************************************************************/
+
+static void bl808_spi_setbits(struct spi_dev_s *dev, int nbits)
+{
+  struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+  uint8_t idx = priv->idx;
+
+  spiinfo("nbits=%d\n", nbits);
+
+  /* Has the number of bits changed? */
+
+  if (nbits != priv->nbits)
+    {
+      /* Save the selection so that subsequent re-configurations
+       * will be faster.
+       */
+
+    switch (nbits)
+      {
+      case 8:
+
+        /* set valid width for each fifo entry 8 bit */
+
+        modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_FRAME_SIZE_MASK, 0);
+        break;
+
+      case 16:
+        modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_FRAME_SIZE_MASK,
+                    1 << SPI_CFG_CR_FRAME_SIZE_SHIFT);
+        break;
+
+      case 24:
+        modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_FRAME_SIZE_MASK,
+                    2 << SPI_CFG_CR_FRAME_SIZE_SHIFT);
+        break;
+
+      case 32:
+        modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_FRAME_SIZE_MASK,
+                    3 << SPI_CFG_CR_FRAME_SIZE_SHIFT);
+        break;
+
+      default:
+        return;
+      }
+
+      priv->nbits = nbits;
+    }
+}
+
+/****************************************************************************
+ * Name: bl808_spi_status
+ *
+ * Description:
+ *   Get SPI/MMC status.  Optional.
+ *
+ * Input Parameters:
+ *   dev   - Device-specific state data
+ *   devid - Identifies the device to report status on
+ *
+ * Returned Value:
+ *   Returns a bitset of status values (see SPI_STATUS_* defines)
+ *
+ ****************************************************************************/
+
+static uint8_t bl808_spi_status(struct spi_dev_s *dev, uint32_t devid)
+{
+  uint8_t status = 0;
+
+  return status;
+}
+
+/****************************************************************************
+ * Name: bl808_spi_cmddata
+ *
+ * Description:
+ *   Some devices require an additional out-of-band bit to specify if the
+ *   next word sent to the device is a command or data. This is typical, for
+ *   example, in "9-bit" displays where the 9th bit is the CMD/DATA bit.
+ *   This function provides selection of command or data.
+ *
+ *   This "latches" the CMD/DATA state.  It does not have to be called before
+ *   every word is transferred; only when the CMD/DATA state changes.  This
+ *   method is required if CONFIG_SPI_CMDDATA is selected in the NuttX
+ *   configuration
+ *
+ *   This function reconfigures MISO from SPI Pin to GPIO Pin, and sets
+ *   MISO to high (data) or low (command). bl808_spi_select() will revert
+ *   MISO back from GPIO Pin to SPI Pin.  We must revert because the SPI Bus
+ *   may be used by other drivers.
+ *
+ * Input Parameters:
+ *   dev - Device-specific state data
+ *   cmd - TRUE: The following word is a command; FALSE: the following words
+ *         are data.
+ *
+ * Returned Value:
+ *   OK unless an error occurs.  Then a negated errno value is returned
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_CMDDATA
+static int bl808_spi_cmddata(struct spi_dev_s *dev,
+                              uint32_t devid, bool cmd)
+{
+  spiinfo("devid: %" PRIu32 " CMD: %s\n", devid, cmd ? "command" :
+          "data");
+  struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+
+  if (devid == SPIDEV_DISPLAY(0))
+    {
+      gpio_pinset_t gpio;
+      int ret;
+
+      /* reconfigure MISO from SPI Pin to GPIO Pin,
+       * then write 0 for command or 1 for data
+       */
+
+#ifdef CONFIG_BL808_SPI0
+      if (priv->idx == 0)
+        {
+          bl808_configgpio(BL808_SPI0_MISO, GPIO_OUTPUT
+                           | GPIO_PULLUP
+                           | GPIO_FUNC_SWGPIO);
+
+          bl808_gpiowrite(BL808_SPI0_MISO, !cmd);
+        }
+#endif
+
+#ifdef CONFIG_BL808_SPI1
+      if (priv->idx == 1)
+        {
+          bl808_configgpio(BL808_SPI1_MISO, GPIO_OUTPUT
+                           | GPIO_PULLUP
+                           | GPIO_FUNC_SWGPIO);
+
+          bl808_gpiowrite(BL808_SPI1_MISO, !cmd);
+        }
+#endif
+
+      return OK;
+    }
+
+  spierr("SPI cmddata not supported\n");
+  DEBUGPANIC();
+
+  return -ENODEV;
+}
+#endif
+
+/****************************************************************************
+ * Name: bl808_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 bl808_spi_hwfeatures(struct spi_dev_s *dev,
+                                spi_hwfeatures_t features)
+{
+  /* Other H/W features are not supported */
+
+  spierr("SPI hardware specific feature not supported\n");
+  DEBUGPANIC();
+
+  return -1;
+}
+#endif
+
+/****************************************************************************
+ * Name: bl808_spi_poll_send
+ *
+ * Description:
+ *   Exchange 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 bl808_spi_poll_send(struct bl808_spi_priv_s *priv,
+                                    uint32_t wd)
+{
+  uint8_t idx = priv->idx;
+  uint32_t val;
+  uint32_t tmp_val = 0;
+
+  /* spi fifo clear  */
+
+  modifyreg32(BL808_SPI_FIFO_CFG_0(idx), 0,
+              SPI_FIFO_CFG_0_RX_CLR
+              | SPI_FIFO_CFG_0_TX_CLR);
+
+  /* write data to tx fifo */
+
+  putreg32(wd, BL808_SPI_FIFO_WDATA(idx));
+
+  /* spi enable master */
+
+  modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_S_EN, SPI_CFG_CR_M_EN);
+
+  while (0 == tmp_val)
+    {
+      /* get data from rx fifo */
+
+      tmp_val = getreg32(BL808_SPI_FIFO_CFG_1(idx));
+      tmp_val = (tmp_val & SPI_FIFO_CFG_1_RX_CNT_MASK)
+                >> SPI_FIFO_CFG_1_RX_CNT_SHIFT;
+    }
+
+  val = getreg32(BL808_SPI_FIFO_RDATA(idx));
+
+  spiinfo("send=%x and recv=%x\n", wd, val);
+
+  modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_M_EN, 0);
+
+  return val;
+}
+
+/****************************************************************************
+ * Name: bl808_spi_send
+ *
+ * Description:
+ *   Exchange 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 bl808_spi_send(struct spi_dev_s *dev, uint32_t wd)
+{
+  struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+  return bl808_spi_poll_send(priv, wd);
+}
+
+/****************************************************************************
+ * Name: bl808_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 bl808_spi_poll_exchange(struct bl808_spi_priv_s *priv,
+                                    const void *txbuffer,
+                                    void *rxbuffer, size_t nwords)
+{
+  int i;
+  uint32_t w_wd = 0xffff;
+  uint32_t r_wd;
+
+  for (i = 0; i < nwords; i++)
+    {
+      if (txbuffer)
+        {
+          if (priv->nbits == 8)
+            {
+              w_wd = ((uint8_t *)txbuffer)[i];
+            }
+          else
+            {
+              w_wd = ((uint16_t *)txbuffer)[i];
+            }
+        }
+
+      r_wd = bl808_spi_poll_send(priv, w_wd);
+
+      if (rxbuffer)
+        {
+          if (priv->nbits == 8)
+            {
+              ((uint8_t *)rxbuffer)[i] = r_wd;
+            }
+          else
+            {
+              ((uint16_t *)rxbuffer)[i] = r_wd;
+            }
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: bl808_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 bl808_spi_exchange(struct spi_dev_s *dev,
+                               const void *txbuffer, void *rxbuffer,
+                               size_t nwords)
+{
+  struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+  bl808_spi_poll_exchange(priv, txbuffer, rxbuffer, nwords);
+}
+
+#ifndef CONFIG_SPI_EXCHANGE
+
+/****************************************************************************
+ * Name: bl808_spi_sndblock
+ *
+ * Description:
+ *   Send a block of data on SPI.
+ *
+ * Input Parameters:
+ *   dev    - Device-specific state data
+ *   buffer - 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 bl808_spi_sndblock(struct spi_dev_s *dev,
+                               const void *txbuffer, size_t nwords)
+{
+  spiinfo("txbuffer=%p nwords=%d\n", txbuffer, nwords);
+
+  bl808_spi_exchange(dev, txbuffer, NULL, nwords);
+}
+
+/****************************************************************************
+ * Name: bl808_spi_recvblock
+ *
+ * Description:
+ *   Receive a block of data from SPI.
+ *
+ * Input Parameters:
+ *   dev -    Device-specific state data
+ *   buffer - 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 bl808_spi_recvblock(struct spi_dev_s *dev,
+                                void *rxbuffer, size_t nwords)
+{
+  spiinfo("rxbuffer=%p nwords=%d\n", rxbuffer, nwords);
+
+  bl808_spi_exchange(dev, NULL, rxbuffer, nwords);
+}
+#endif
+
+/****************************************************************************
+ * Name: bl808_spi_trigger
+ *
+ * Description:
+ *   Trigger a previously configured DMA transfer.
+ *
+ * Input Parameters:
+ *   dev      - Device-specific state data
+ *
+ * Returned Value:
+ *   OK       - Trigger was fired
+ *   -ENOSYS  - Trigger not fired due to lack of DMA or low level support
+ *   -EIO     - Trigger not fired because not previously primed
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_TRIGGER
+static int bl808_spi_trigger(struct spi_dev_s *dev)
+{
+  spierr("SPI trigger not supported\n");
+  DEBUGPANIC();
+
+  return -ENOSYS;
+}
+#endif
+
+/****************************************************************************
+ * Name: bl808_spi_init
+ *
+ * Description:
+ *   Initialize bl808 SPI hardware interface
+ *
+ * Input Parameters:
+ *   dev      - Device-specific state data
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void bl808_spi_init(struct spi_dev_s *dev)
+{
+  struct bl808_spi_priv_s *priv = (struct bl808_spi_priv_s *)dev;
+  const struct bl808_spi_config_s *config = priv->config;
+  uint8_t idx = priv->idx;
+
+#ifdef CONFIG_BL808_SPI0
+  if (idx == 0)
+    {
+      bl808_configgpio(CONFIG_BL808_SPI0_MISO,
+                       GPIO_INPUT
+                       | GPIO_DRV_1
+                       | GPIO_SMT_EN
+                       | GPIO_PULLUP
+                       | GPIO_FUNC_SPI0);
+
+      bl808_configgpio(CONFIG_BL808_SPI0_MOSI,
+                       GPIO_INPUT
+                       | GPIO_DRV_1
+                       | GPIO_SMT_EN
+                       | GPIO_PULLUP
+                       | GPIO_FUNC_SPI0);
+
+      bl808_configgpio(CONFIG_BL808_SPI0_SCLK,
+                       GPIO_INPUT
+                       | GPIO_DRV_1
+                       | GPIO_SMT_EN
+                       | GPIO_PULLUP
+                       | GPIO_FUNC_SPI0);
+
+      bl808_configgpio(CONFIG_BL808_SPI0_SS,
+                       GPIO_INPUT
+                       | GPIO_DRV_1
+                       | GPIO_SMT_EN
+                       | GPIO_PULLUP
+                       | GPIO_FUNC_SPI0);
+
+      modifyreg32(BL808_GLB_PARM_CFG0, 0,
+                  1 << PARM_SPI_0_MASTER_MODE_SHIFT);
+    }
+#endif
+
+#ifdef CONFIG_BL808_SPI1
+  if (idx == 1)
+    {
+      bl808_configgpio(CONFIG_BL808_SPI1_MISO,
+                       GPIO_INPUT
+                       | GPIO_DRV_1
+                       | GPIO_SMT_EN
+                       | GPIO_PULLUP
+                       | GPIO_FUNC_SPI1);
+
+      bl808_configgpio(CONFIG_BL808_SPI1_MOSI,
+                       GPIO_INPUT
+                       | GPIO_DRV_1
+                       | GPIO_SMT_EN
+                       | GPIO_PULLUP
+                       | GPIO_FUNC_SPI1);
+
+      bl808_configgpio(CONFIG_BL808_SPI1_SCLK,
+                       GPIO_INPUT
+                       | GPIO_DRV_1
+                       | GPIO_SMT_EN
+                       | GPIO_PULLUP
+                       | GPIO_FUNC_SPI1);
+
+      bl808_configgpio(CONFIG_BL808_SPI1_SS,
+                       GPIO_INPUT
+                       | GPIO_DRV_1
+                       | GPIO_SMT_EN
+                       | GPIO_PULLUP
+                       | GPIO_FUNC_SPI1);
+
+      modifyreg32(BL808_GLB_PARM_CFG0, 0,
+                  1 << PARM_MM_SPI_MASTER_MODE_SHIFT);
+    }
+#endif
+
+  /* Disable RX ignore */
+
+  modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_RXD_IGNR_EN, 0);
+
+  /* Set deglitch */
+
+  if (config->deglitch_enable)
+    {
+      modifyreg32(BL808_SPI_CFG(idx), 0, SPI_CFG_CR_DEG_EN);
+    }
+  else
+    {
+      modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_DEG_EN, 0);
+    }
+
+  /* Set continuous transfer */
+
+  if (config->continuous_enable)
+    {
+      modifyreg32(BL808_SPI_CFG(idx), 0, SPI_CFG_CR_M_CONT_EN);
+    }
+  else
+    {
+      modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_M_CONT_EN, 0);
+    }
+
+  /* Set byte inversion */
+
+  if (config->byte_invert)
+    {
+      modifyreg32(BL808_SPI_CFG(idx), 0, SPI_CFG_CR_BYTE_INV);
+    }
+  else
+    {
+      modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_BYTE_INV, 0);
+    }
+
+  /* Set bit inversion */
+
+  if (config->bit_invert)
+    {
+      modifyreg32(BL808_SPI_CFG(idx), 0, SPI_CFG_CR_BIT_INV);
+    }
+  else
+    {
+      modifyreg32(BL808_SPI_CFG(idx), SPI_CFG_CR_BIT_INV, 0);
+    }
+
+  bl808_spi_setfrequency(dev, config->clk_freq);
+  bl808_spi_setbits(dev, 8);
+  bl808_spi_setmode(dev, config->mode);
+
+  /* spi fifo clear */
+
+  modifyreg32(BL808_SPI_FIFO_CFG_0(idx), 0, SPI_FIFO_CFG_0_RX_CLR
+              | SPI_FIFO_CFG_0_TX_CLR);
+}
+
+/****************************************************************************
+ * Name: bl808_spibus_initialize
+ *
+ * Description:
+ *   Initialize and register the configured SPI busses
+ *
+ ****************************************************************************/
+
+struct spi_dev_s *bl808_spibus_initialize(int bus)
+{
+  struct spi_dev_s *spi_dev;
+  struct bl808_spi_priv_s *priv;
+
+#ifdef CONFIG_BL808_SPI0
+  if (bus == 0)
+    {
+      priv = &bl808_spi0_priv;
+    }
+#endif
+
+#ifdef CONFIG_BL808_SPI1
+  if (bus == 1)
+    {
+      priv = &bl808_spi1_priv;
+    }
+#endif
+
+  spi_dev = (struct spi_dev_s *)priv;
+
+  nxmutex_lock(&priv->lock);
+  if (priv->refs == 0)
+    {
+      bl808_spi_init(spi_dev);
+    }
+
+  priv->refs++;
+
+  nxmutex_unlock(&priv->lock);
+
+  return spi_dev;
+}
+
+#endif /* CONFIG_BL808_SPI0 || CONFIG_BL808_SPI1 */
diff --git a/arch/risc-v/src/bl808/bl808_spi.h 
b/arch/risc-v/src/bl808/bl808_spi.h
new file mode 100644
index 0000000000..6bcb3fb043
--- /dev/null
+++ b/arch/risc-v/src/bl808/bl808_spi.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+ * arch/risc-v/src/bl808/bl808_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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_RISCV_SRC_BL808_BL808_SPI_H
+#define __ARCH_RISCV_SRC_BL808_BL808_SPI_H
+
+/* This file is based on bl602/bl602_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
+
+#include <nuttx/spi/spi.h>
+#include <nuttx/spi/spi_transfer.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: bl808_spibus_initialize
+ *
+ * Description:
+ *   Initialize the selected SPI bus
+ *
+ * Input Parameters:
+ *   Port number (for hardware that has multiple SPI interfaces)
+ *
+ * Returned Value:
+ *   Valid SPI device structure reference on success; a NULL on failure
+ *
+ ****************************************************************************/
+
+struct spi_dev_s *bl808_spibus_initialize(int bus);
+
+#ifdef __cplusplus
+}
+#endif
+#undef EXTERN
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_RISCV_SRC_BL808_BL808_SPI_H */
diff --git a/arch/risc-v/src/bl808/hardware/bl808_glb.h 
b/arch/risc-v/src/bl808/hardware/bl808_glb.h
index d5bc359cb1..23f907a065 100644
--- a/arch/risc-v/src/bl808/hardware/bl808_glb.h
+++ b/arch/risc-v/src/bl808/hardware/bl808_glb.h
@@ -36,6 +36,8 @@
 
 #define BL808_GLB_UART_CFG1_OFFSET    0x154
 #define BL808_GLB_UART_CFG2_OFFSET    0x158
+#define BL808_GLB_SPI_CFG0_OFFSET     0x1b0
+#define BL808_GLB_PARM_CFG0_OFFSET    0x510
 
 #define BL808_GPIO_CFG_OFFSET              0x0008c4  /* gpio_cfg0 */
 
@@ -43,15 +45,32 @@
 
 #define BL808_GLB_UART_CFG1 (BL808_GLB_BASE + BL808_GLB_UART_CFG1_OFFSET)
 #define BL808_GLB_UART_CFG2 (BL808_GLB_BASE + BL808_GLB_UART_CFG2_OFFSET)
+#define BL808_GLB_SPI_CFG0 (BL808_GLB_BASE + BL808_GLB_SPI_CFG0_OFFSET)
+#define BL808_GLB_PARM_CFG0 (BL808_GLB_BASE + BL808_GLB_PARM_CFG0_OFFSET)
 
 #define BL808_GPIO_CFG(n)        (BL808_GLB_BASE + BL808_GPIO_CFG_OFFSET + 4*n)
 
 /* Register bit definitions *************************************************/
 
 /* UART_CFG registers *******************************************************/
+
 #define UART_CFG_SIG_SEL_SHIFT(n)  ((n % 8) * 4)
 #define UART_CFG_SIG_SEL_MASK(n)   (0x0f << UART_CFG_SIG_SEL_SHIFT(n))
 
+/* SPI_CFG0 *****************************************************************/
+
+#define SPI_CFG_CLK_DIV_SHIFT 0
+#define SPI_CFG_CLK_DIV_MASK (0x1f << SPI_CFG_CLK_DIV_SHIFT)
+#define SPI_CFG_CLK_EN_SHIFT 8
+#define SPI_CFG_CLK_SEL_SHIFT 9
+#define SPI_CFG_SWAP_SET_SHIFT 16
+#define SPI_CFG_SWAP_SET_MASK (0x0f << SPI_CFG_SWAP_SET_SHIFT);
+
+/* PARM_CFG0 ****************************************************************/
+
+#define PARM_SPI_0_MASTER_MODE_SHIFT 12
+#define PARM_MM_SPI_MASTER_MODE_SHIFT 27
+
 /* GPIO_CFG registers *******************************************************/
 
 /* bit definitions from lupyuen's wip-nuttx, branch gpio2 *******************/
diff --git a/arch/risc-v/src/bl808/hardware/bl808_memorymap.h 
b/arch/risc-v/src/bl808/hardware/bl808_memorymap.h
index bed2b31756..aaff526633 100644
--- a/arch/risc-v/src/bl808/hardware/bl808_memorymap.h
+++ b/arch/risc-v/src/bl808/hardware/bl808_memorymap.h
@@ -33,9 +33,12 @@
 #define BL808_GPADC_BASE   0x20002000ul
 #define BL808_UART0_BASE   0x2000a000ul
 #define BL808_UART1_BASE   0x2000a100ul
+#define BL808_SPI0_BASE    0x2000a200ul
 #define BL808_UART2_BASE   0x2000aa00ul
 #define BL808_AON_BASE     0x2000f000ul
 #define BL808_UART3_BASE   0x30002000ul
+#define BL808_MM_GLB_BASE  0x30007000ul
+#define BL808_SPI1_BASE    0x30008000ul
 #define BL808_PLIC_BASE    0xe0000000ul
 
 #endif /* __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_MEMORYMAP_H */
diff --git a/arch/risc-v/src/bl808/hardware/bl808_glb.h 
b/arch/risc-v/src/bl808/hardware/bl808_mm_glb.h
similarity index 51%
copy from arch/risc-v/src/bl808/hardware/bl808_glb.h
copy to arch/risc-v/src/bl808/hardware/bl808_mm_glb.h
index d5bc359cb1..a23e0001da 100644
--- a/arch/risc-v/src/bl808/hardware/bl808_glb.h
+++ b/arch/risc-v/src/bl808/hardware/bl808_mm_glb.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * arch/risc-v/src/bl808/hardware/bl808_glb.h
+ * arch/risc-v/src/bl808/hardware/bl808_mm_glb.h
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,8 +18,8 @@
  *
  ****************************************************************************/
 
-#ifndef __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_GLB_H
-#define __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_GLB_H
+#ifndef __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_MM_GLB_H
+#define __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_MM_GLB_H
 
 /****************************************************************************
  * Included Files
@@ -34,36 +34,25 @@
 
 /* Register offsets *********************************************************/
 
-#define BL808_GLB_UART_CFG1_OFFSET    0x154
-#define BL808_GLB_UART_CFG2_OFFSET    0x158
-
-#define BL808_GPIO_CFG_OFFSET              0x0008c4  /* gpio_cfg0 */
+#define BL808_MM_GLB_CLK_CTRL_PERI_OFFSET 0x10
 
 /* Register definitions *****************************************************/
 
-#define BL808_GLB_UART_CFG1 (BL808_GLB_BASE + BL808_GLB_UART_CFG1_OFFSET)
-#define BL808_GLB_UART_CFG2 (BL808_GLB_BASE + BL808_GLB_UART_CFG2_OFFSET)
-
-#define BL808_GPIO_CFG(n)        (BL808_GLB_BASE + BL808_GPIO_CFG_OFFSET + 4*n)
+#define BL808_MM_GLB_CLK_CTRL_PERI (BL808_MM_GLB_BASE \
+                                   + BL808_MM_GLB_CLK_CTRL_PERI_OFFSET)
 
 /* Register bit definitions *************************************************/
 
-/* UART_CFG registers *******************************************************/
-#define UART_CFG_SIG_SEL_SHIFT(n)  ((n % 8) * 4)
-#define UART_CFG_SIG_SEL_MASK(n)   (0x0f << UART_CFG_SIG_SEL_SHIFT(n))
-
-/* GPIO_CFG registers *******************************************************/
-
-/* bit definitions from lupyuen's wip-nuttx, branch gpio2 *******************/
+/* CLK_CTRL_PERI ************************************************************/
 
-#define GPIO_CFGCTL0_GPIO_0_FUNC_SEL_SHIFT           (8)
-#define GPIO_CFGCTL0_GPIO_0_FUNC_SEL_MASK            (0x0f << 
GPIO_CFGCTL0_GPIO_0_FUNC_SEL_SHIFT)
-#define GPIO_CFGCTL0_GPIO_0_OE                       (1 << 6)
-#define GPIO_CFGCTL0_GPIO_0_PD                       (1 << 5)
-#define GPIO_CFGCTL0_GPIO_0_PU                       (1 << 4)
-#define GPIO_CFGCTL0_GPIO_0_DRV_SHIFT                (2)
-#define GPIO_CFGCTL0_GPIO_0_DRV_MASK                 (0x03 << 
GPIO_CFGCTL0_GPIO_0_DRV_SHIFT)
-#define GPIO_CFGCTL0_GPIO_0_SMT                      (1 << 1)
-#define GPIO_CFGCTL0_GPIO_0_IE                       (1 << 0)
+#define CLK_CTRL_PERI_I2C0_DIV_SHIFT 0
+#define CLK_CTRL_PERI_I2C0_DIV_MASK (0xff << CLK_CTRL_PERI_I2C0_DIV_SHIFT)
+#define CLK_CTRL_PERI_I2C0_EN_SHIFT 9
+#define CLK_CTRL_PERI_UART_DIV_EN_SHIFT 16
+#define CLK_CTRL_PERI_UART_DIV_SHIFT 17
+#define CLK_CTRL_PERI_UART_DIV_MASK (0x07 << CLK_CTRL_PERI_UART_DIV_SHIFT)
+#define CLK_CTRL_PERI_SPI_DIV_EN_SHIFT 23
+#define CLK_CTRL_PERI_SPI_DIV_SHIFT 24
+#define CLK_CTRL_PERI_SPI_DIV_MASK (0xff << CLK_CTRL_PERI_SPI_DIV_SHIFT)
 
-#endif /* __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_GLB_H */
+#endif /* __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_MM_GLB_H */
diff --git a/arch/risc-v/src/bl808/hardware/bl808_spi.h 
b/arch/risc-v/src/bl808/hardware/bl808_spi.h
new file mode 100644
index 0000000000..6b7343d946
--- /dev/null
+++ b/arch/risc-v/src/bl808/hardware/bl808_spi.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+ * arch/risc-v/src/bl808/hardware/bl808_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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_SPI_H
+#define __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_SPI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include "bl808_memorymap.h"
+
+/* This file is based on bl602/hardware/bl602_spi.h */
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define BL808_SPI_BASE(n) ((n == 0) ? BL808_SPI0_BASE \
+                           : BL808_SPI1_BASE)
+
+/* Register offsets *********************************************************/
+
+#define BL808_SPI_CFG_OFFSET            0x000000  /* spi_config */
+#define BL808_SPI_INT_STS_OFFSET        0x000004  /* spi_int_sts */
+#define BL808_SPI_BUS_BUSY_OFFSET       0x000008  /* spi_bus_busy */
+#define BL808_SPI_PRD_0_OFFSET          0x000010  /* spi_prd_0 */
+#define BL808_SPI_PRD_1_OFFSET          0x000014  /* spi_prd_1 */
+#define BL808_SPI_RXD_IGNR_OFFSET       0x000018  /* spi_rxd_ignr */
+#define BL808_SPI_STO_VALUE_OFFSET      0x00001c  /* spi_sto_value */
+#define BL808_SPI_FIFO_CFG_0_OFFSET     0x000080  /* spi_fifo_config_0 */
+#define BL808_SPI_FIFO_CFG_1_OFFSET     0x000084  /* spi_fifo_config_1 */
+#define BL808_SPI_FIFO_WDATA_OFFSET     0x000088  /* spi_fifo_wdata */
+#define BL808_SPI_FIFO_RDATA_OFFSET     0x00008c  /* spi_fifo_rdata */
+
+/* Register definitions *****************************************************/
+
+#define BL808_SPI_CFG(n)         (BL808_SPI_BASE(n) + BL808_SPI_CFG_OFFSET)
+#define BL808_SPI_INT_STS(n)     (BL808_SPI_BASE(n) + BL808_SPI_INT_STS_OFFSET)
+#define BL808_SPI_BUS_BUSY(n)    (BL808_SPI_BASE(n) + 
BL808_SPI_BUS_BUSY_OFFSET)
+#define BL808_SPI_PRD_0(n)       (BL808_SPI_BASE(n) + BL808_SPI_PRD_0_OFFSET)
+#define BL808_SPI_PRD_1(n)       (BL808_SPI_BASE(n) + BL808_SPI_PRD_1_OFFSET)
+#define BL808_SPI_RXD_IGNR(n)    (BL808_SPI_BASE(n) + 
BL808_SPI_RXD_IGNR_OFFSET)
+#define BL808_SPI_STO_VALUE(n)   (BL808_SPI_BASE(n) + 
BL808_SPI_STO_VALUE_OFFSET)
+#define BL808_SPI_FIFO_CFG_0(n)  (BL808_SPI_BASE(n) + 
BL808_SPI_FIFO_CFG_0_OFFSET)
+#define BL808_SPI_FIFO_CFG_1(n)  (BL808_SPI_BASE(n) + 
BL808_SPI_FIFO_CFG_1_OFFSET)
+#define BL808_SPI_FIFO_WDATA(n)  (BL808_SPI_BASE(n) + 
BL808_SPI_FIFO_WDATA_OFFSET)
+#define BL808_SPI_FIFO_RDATA(n)  (BL808_SPI_BASE(n) + 
BL808_SPI_FIFO_RDATA_OFFSET)
+
+/* Register bit definitions *************************************************/
+
+#define SPI_CFG_CR_DEG_CNT_SHIFT      (12)
+#define SPI_CFG_CR_DEG_CNT_MASK       (0x0f << SPI_CFG_CR_DEG_CNT_SHIFT)
+#define SPI_CFG_CR_DEG_EN             (1 << 11)
+#define SPI_CFG_CR_M_CONT_EN          (1 << 9)
+#define SPI_CFG_CR_RXD_IGNR_EN        (1 << 8)
+#define SPI_CFG_CR_BYTE_INV           (1 << 7)
+#define SPI_CFG_CR_BIT_INV            (1 << 6)
+#define SPI_CFG_CR_SCLK_PH            (1 << 5)
+#define SPI_CFG_CR_SCLK_POL           (1 << 4)
+#define SPI_CFG_CR_FRAME_SIZE_SHIFT   (2)
+#define SPI_CFG_CR_FRAME_SIZE_MASK    (0x03 << SPI_CFG_CR_FRAME_SIZE_SHIFT)
+#define SPI_CFG_CR_S_EN               (1 << 1)
+#define SPI_CFG_CR_M_EN               (1 << 0)
+
+#define SPI_INT_STS_CR_FER_EN         (1 << 29)
+#define SPI_INT_STS_CR_TXU_EN         (1 << 28)
+#define SPI_INT_STS_CR_STO_EN         (1 << 27)
+#define SPI_INT_STS_CR_RXF_EN         (1 << 26)
+#define SPI_INT_STS_CR_TXF_EN         (1 << 25)
+#define SPI_INT_STS_CR_END_EN         (1 << 24)
+#define SPI_INT_STS_RSVD_21           (1 << 21)
+#define SPI_INT_STS_CR_TXU_CLR        (1 << 20)
+#define SPI_INT_STS_CR_STO_CLR        (1 << 19)
+#define SPI_INT_STS_RSVD_18           (1 << 18)
+#define SPI_INT_STS_RSVD_17           (1 << 17)
+#define SPI_INT_STS_CR_END_CLR        (1 << 16)
+#define SPI_INT_STS_CR_FER_MASK       (1 << 13)
+#define SPI_INT_STS_CR_TXU_MASK       (1 << 12)
+#define SPI_INT_STS_CR_STO_MASK       (1 << 11)
+#define SPI_INT_STS_CR_RXF_MASK       (1 << 10)
+#define SPI_INT_STS_CR_TXF_MASK       (1 << 9)
+#define SPI_INT_STS_CR_END_MASK       (1 << 8)
+#define SPI_INT_STS_FER_INT           (1 << 5)
+#define SPI_INT_STS_TXU_INT           (1 << 4)
+#define SPI_INT_STS_STO_INT           (1 << 3)
+#define SPI_INT_STS_RXF_INT           (1 << 2)
+#define SPI_INT_STS_TXF_INT           (1 << 1)
+#define SPI_INT_STS_END_INT           (1 << 0)
+
+#define SPI_BUS_BUSY_STS_BUS_BUSY     (1 << 0)
+
+#define SPI_PRD_0_CR_D_PH_1_SHIFT     (24)
+#define SPI_PRD_0_CR_D_PH_1_MASK      (0xff << SPI_PRD_0_CR_D_PH_1_SHIFT)
+#define SPI_PRD_0_CR_D_PH_0_SHIFT     (16)
+#define SPI_PRD_0_CR_D_PH_0_MASK      (0xff << SPI_PRD_0_CR_D_PH_0_SHIFT)
+#define SPI_PRD_0_CR_P_SHIFT          (8)
+#define SPI_PRD_0_CR_P_MASK           (0xff << SPI_PRD_0_CR_P_SHIFT)
+#define SPI_PRD_0_CR_S_MASK           (0xff)
+
+#define SPI_PRD_1_CR_I_MASK           (0xff)
+
+#define SPI_RXD_IGNR_CR_IGNR_S_SHIFT  (16)
+#define SPI_RXD_IGNR_CR_IGNR_S_MASK   (0x1f << 
SPI_RXD_IGNR_CR_RXD_IGNR_S_SHIFT)
+#define SPI_RXD_IGNR_CR_IGNR_P_MASK   (0x1f)
+
+#define SPI_STO_VALUE_CR_VALUE_MASK   (0xfff)
+
+#define SPI_FIFO_CFG_0_RX_UNDERFLOW   (1 << 7)
+#define SPI_FIFO_CFG_0_RX_OVERFLOW    (1 << 6)
+#define SPI_FIFO_CFG_0_TX_UNDERFLOW   (1 << 5)
+#define SPI_FIFO_CFG_0_TX_OVERFLOW    (1 << 4)
+#define SPI_FIFO_CFG_0_RX_CLR         (1 << 3)
+#define SPI_FIFO_CFG_0_TX_CLR         (1 << 2)
+#define SPI_FIFO_CFG_0_DMA_RX_EN       (1 << 1)
+#define SPI_FIFO_CFG_0_DMA_TX_EN       (1 << 0)
+
+#define SPI_FIFO_CFG_1_RX_TH_SHIFT    (24)
+#define SPI_FIFO_CFG_1_RX_TH_MASK     (0x1f << SPI_FIFO_CFG_1_RX_TH_SHIFT)
+#define SPI_FIFO_CFG_1_TX_TH_SHIFT    (16)
+#define SPI_FIFO_CFG_1_TX_TH_MASK     (0x1f << SPI_FIFO_CFG_1_TX_TH_SHIFT)
+#define SPI_FIFO_CFG_1_RX_CNT_SHIFT   (8)
+#define SPI_FIFO_CFG_1_RX_CNT_MASK    (0x3f << SPI_FIFO_CFG_1_RX_CNT_SHIFT)
+#define SPI_FIFO_CFG_1_TX_CNT_MASK    (0x3f)
+
+#endif /* __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_SPI_H */
diff --git a/boards/risc-v/bl808/ox64/configs/spi/defconfig 
b/boards/risc-v/bl808/ox64/configs/spi/defconfig
new file mode 100644
index 0000000000..3c6a4a7296
--- /dev/null
+++ b/boards/risc-v/bl808/ox64/configs/spi/defconfig
@@ -0,0 +1,100 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed 
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that 
includes your
+# modifications.
+#
+# CONFIG_DISABLE_OS_API is not set
+# CONFIG_NSH_DISABLE_LOSMART is not set
+# CONFIG_STANDARD_SERIAL is not set
+CONFIG_ARCH="risc-v"
+CONFIG_ARCH_ADDRENV=y
+CONFIG_ARCH_BOARD="ox64"
+CONFIG_ARCH_BOARD_BL808_OX64=y
+CONFIG_ARCH_CHIP="bl808"
+CONFIG_ARCH_CHIP_BL808=y
+CONFIG_ARCH_DATA_NPAGES=128
+CONFIG_ARCH_DATA_VBASE=0x80100000
+CONFIG_ARCH_HEAP_NPAGES=128
+CONFIG_ARCH_HEAP_VBASE=0x80200000
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_KERNEL_STACKSIZE=3072
+CONFIG_ARCH_PGPOOL_MAPPING=y
+CONFIG_ARCH_PGPOOL_PBASE=0x50600000
+CONFIG_ARCH_PGPOOL_SIZE=4194304
+CONFIG_ARCH_PGPOOL_VBASE=0x50600000
+CONFIG_ARCH_RISCV=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_TEXT_NPAGES=128
+CONFIG_ARCH_TEXT_VBASE=0x80000000
+CONFIG_ARCH_USE_MMU=y
+CONFIG_ARCH_USE_MPU=y
+CONFIG_ARCH_USE_S_MODE=y
+CONFIG_BL808_SPI0=y
+CONFIG_BL808_UART0=y
+CONFIG_BL808_UART1=y
+CONFIG_BL808_UART2=y
+CONFIG_BL808_UART3=y
+CONFIG_BOARDCTL_ROMDISK=y
+CONFIG_BOARD_LATE_INITIALIZE=y
+CONFIG_BOARD_LOOPSPERMSEC=1120
+CONFIG_BUILD_KERNEL=y
+CONFIG_DEBUG_ASSERTIONS=y
+CONFIG_DEBUG_ASSERTIONS_EXPRESSION=y
+CONFIG_DEBUG_FEATURES=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DEV_ZERO=y
+CONFIG_ELF=y
+CONFIG_EXAMPLES_HELLO=m
+CONFIG_FS_PROCFS=y
+CONFIG_FS_ROMFS=y
+CONFIG_IDLETHREAD_STACKSIZE=3072
+CONFIG_INIT_FILEPATH="/system/bin/init"
+CONFIG_INIT_MOUNT=y
+CONFIG_INIT_MOUNT_FLAGS=0x1
+CONFIG_INIT_MOUNT_TARGET="/system/bin"
+CONFIG_INIT_STACKSIZE=3072
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBC_ENVPATH=y
+CONFIG_LIBC_EXECFUNCS=y
+CONFIG_LIBC_PERROR_STDOUT=y
+CONFIG_LIBC_STRERROR=y
+CONFIG_MEMSET_64BIT=y
+CONFIG_MEMSET_OPTSPEED=y
+CONFIG_MM_PGALLOC=y
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_FILE_APPS=y
+CONFIG_NSH_READLINE=y
+CONFIG_PATH_INITIAL="/system/bin"
+CONFIG_RAM_SIZE=1048576
+CONFIG_RAM_START=0x50200000
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HAVE_PARENT=y
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_STACK_COLORATION=y
+CONFIG_START_MONTH=12
+CONFIG_START_YEAR=2021
+CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_SYSTEM_NSH_PROGNAME="init"
+CONFIG_SYSTEM_SPITOOL=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_UART0_BAUD=2000000
+CONFIG_UART0_BITS=7
+CONFIG_UART1_BAUD=2000000
+CONFIG_UART1_BITS=7
+CONFIG_UART2_BAUD=2000000
+CONFIG_UART2_BITS=7
+CONFIG_UART3_BAUD=2000000
+CONFIG_UART3_BITS=7
+CONFIG_UART3_SERIAL_CONSOLE=y
+CONFIG_USEC_PER_TICK=1000
+CONFIG_USERLED=y
+CONFIG_USERLED_LOWER=y
diff --git a/boards/risc-v/bl808/ox64/src/bl808_appinit.c 
b/boards/risc-v/bl808/ox64/src/bl808_appinit.c
index 0fe3b21c8a..9f0305bcbd 100644
--- a/boards/risc-v/bl808/ox64/src/bl808_appinit.c
+++ b/boards/risc-v/bl808/ox64/src/bl808_appinit.c
@@ -38,6 +38,9 @@
 #ifdef CONFIG_USERLED
 #include <nuttx/leds/userled.h>
 #endif
+#if defined(CONFIG_BL808_SPI0) || defined(CONFIG_BL808_SPI1)
+#include "bl808_spi.h"
+#endif
 #include "bl808_gpadc.h"
 
 /****************************************************************************
@@ -170,6 +173,16 @@ void board_late_initialize(void)
 
 #endif
 
+#ifdef CONFIG_BL808_SPI0
+  struct spi_dev_s *spi0 = bl808_spibus_initialize(0);
+  spi_register(spi0, 0);
+#endif
+
+#ifdef CONFIG_BL808_SPI1
+  struct spi_dev_s *spi1 = bl808_spibus_initialize(1);
+  spi_register(spi1, 1);
+#endif
+
 #ifdef CONFIG_NSH_ARCHINIT
 
   mount(NULL, "/proc", "procfs", 0, NULL);

Reply via email to