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

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


The following commit(s) were added to refs/heads/master by this push:
     new 3feb9985a5 bcm2711/spi: Create interrupt-based SPI driver.
3feb9985a5 is described below

commit 3feb9985a50dfc1b1a0faee4ad6a336e87bedda2
Author: Matteo Golin <matteo.go...@gmail.com>
AuthorDate: Mon May 19 17:50:43 2025 -0400

    bcm2711/spi: Create interrupt-based SPI driver.
    
    This implements an interrupt-based SPI driver for the BCM2711 SPI
    interfaces (excluding auxiliary SPI interfaces). Only tested on SPI0
    since proprietary firmware does not initialize any other SPI interfaces,
    and doing so will require reverse engineering.
---
 .../arm64/bcm2711/boards/raspberrypi-4b/index.rst  |   29 +-
 Documentation/platforms/arm64/bcm2711/index.rst    |   30 +-
 arch/arm64/include/bcm2711/irq.h                   |    8 +-
 arch/arm64/src/bcm2711/Kconfig                     |   79 +-
 arch/arm64/src/bcm2711/bcm2711_gpio.c              |   11 +-
 arch/arm64/src/bcm2711/bcm2711_spi.c               | 1003 ++++++++++++++++++--
 arch/arm64/src/bcm2711/hardware/bcm2711_irq.h      |  127 +--
 arch/arm64/src/bcm2711/hardware/bcm2711_memmap.h   |    4 +
 arch/arm64/src/bcm2711/hardware/bcm2711_spi.h      |   44 +-
 9 files changed, 1119 insertions(+), 216 deletions(-)

diff --git 
a/Documentation/platforms/arm64/bcm2711/boards/raspberrypi-4b/index.rst 
b/Documentation/platforms/arm64/bcm2711/boards/raspberrypi-4b/index.rst
index 4337e067a6..3db438e527 100644
--- a/Documentation/platforms/arm64/bcm2711/boards/raspberrypi-4b/index.rst
+++ b/Documentation/platforms/arm64/bcm2711/boards/raspberrypi-4b/index.rst
@@ -4,6 +4,26 @@ Raspberry Pi 4B
 
 .. tags:: chip:bcm2711, experimental
 
+.. warning::
+
+   The board support for this device is experimental. Not all features are
+   implemented and they have not been extensively tested by many users.
+
+   Help is wanted if you are interested in supporting a feature or if you've
+   found an issue with any of the implementation! See :doc:`the contributing
+   guidelines </contributing/index>`.
+
+.. warning::
+
+   The SPI driver implemented for the :doc:`BCM2711 <../../index>` has only 
been
+   tested on SPI0. It appears that even using the special `overlays
+   
<https://github.com/raspberrypi/linux/blob/stable/arch/arm/boot/dts/overlays/README>`_
+   for the device tree passed to the proprietary firmware does not properly
+   initialize the remaining SPI interfaces, and thus they have not been working
+   properly. More effort is required to reverse engineer the magic incantations
+   required to initialize these interfaces, at which point it is assumed that
+   the driver implementation should extend to SPI3-6.
+
 The `Raspberry Pi 4B 
<https://www.raspberrypi.com/products/raspberry-pi-4-model-b/specifications/>`_ 
is an ARM64
 hobbyist board created by Raspberry Pi.
 
@@ -139,17 +159,14 @@ Board Peripheral Support
 
 SMP is currently unsupported.
 
+To see support for general chip peripherals (I2C, SPI, UART, etc), see the
+:doc:`BCM2711 page <../../index>`
+
 NuttX for the Raspberry Pi 4 supports these on-board peripherals:
 
 ======================== =======
 Peripheral               Support
 ======================== =======
-I2C                      Partial (able to read, that's it)
-UART                     Mini UART yes, PL011 no
-GPIO                     Partial
-PWM                      No
-SPI                      No
-PCM                      No
 AV port                  No
 HDMI                     No
 WiFi                     No
diff --git a/Documentation/platforms/arm64/bcm2711/index.rst 
b/Documentation/platforms/arm64/bcm2711/index.rst
index fd8f44a93d..35791210e4 100644
--- a/Documentation/platforms/arm64/bcm2711/index.rst
+++ b/Documentation/platforms/arm64/bcm2711/index.rst
@@ -2,12 +2,38 @@
 BCM2711
 =======
 
-The `BCM2711 
<https://www.raspberrypi.com/documentation/computers/processors.html#bcm2711>`_ 
is a Broadcom SoC used for
-the Raspberry Pi 4B board.
+.. tags:: chip:bcm2711, experimental
+
+.. warning::
+
+   The support for this chip is experimental. Not all features are
+   implemented and they have not been extensively tested by many users.
+
+   Help is wanted if you are interested in supporting a feature or if you've
+   found an issue with any of the implementation! See :doc:`the contributing
+   guidelines </contributing/index>`.
+
+The `BCM2711
+<https://www.raspberrypi.com/documentation/computers/processors.html#bcm2711>`_
+is a Broadcom SoC used for the Raspberry Pi 4B board.
 
 - **CPU:** Quad-core ARM Cortex-A72
 - **Interrupt Controller:** GIC400
 
+Supported Peripherals
+=====================
+
+======================== =======
+Peripheral               Support
+======================== =======
+I2C                      Partial (able to read, that's it)
+UART                     Mini UART yes, PL011 no
+GPIO                     Partial
+PWM                      No
+SPI                      Interrupt-based driver (no DMA) for all SPI except 1 
& 2 (auxiliary)
+PCM                      No
+======================== =======
+
 Supported Boards
 ================
 
diff --git a/arch/arm64/include/bcm2711/irq.h b/arch/arm64/include/bcm2711/irq.h
index 1275fda79e..287022d4a6 100644
--- a/arch/arm64/include/bcm2711/irq.h
+++ b/arch/arm64/include/bcm2711/irq.h
@@ -20,8 +20,8 @@
  *
  ****************************************************************************/
 
-#ifndef __ARCH_ARM64_SRC_BCM2711_IRQ_H
-#define __ARCH_ARM64_SRC_BCM2711_IRQ_H
+#ifndef __ARCH_ARM64_INCLUDE_BCM2711_IRQ_H
+#define __ARCH_ARM64_INCLUDE_BCM2711_IRQ_H
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -122,8 +122,6 @@
 #define BCM_IRQ_VC_EMMC BCM_IRQ_VC(62)
 #define BCM_IRQ_VC_ETHPCIESEC BCM_IRQ_VC(63)
 
-/* TODO: what about PACTL_CS address section 6.2.4? */
-
 /* ETH_PCIe interrupts */
 
 #define BCM_IRQ_ETH_BASE 160
@@ -143,4 +141,4 @@
 #define BCM_IRQ_ARMLOCAL_IRQ_SOURCEN_MAILBOX_CORE3_IRQ (1 << 4)
 #define BCM_IRQ_ARMLOCAL_IRQ_SOURCEN_CNT_V_IRQ (1 << 3)
 
-#endif // __ARCH_ARM64_SRC_BCM2711_IRQ_H
+#endif // __ARCH_ARM64_INCLUDE_BCM2711_IRQ_H
diff --git a/arch/arm64/src/bcm2711/Kconfig b/arch/arm64/src/bcm2711/Kconfig
index 70fbfeed9d..31236464e8 100644
--- a/arch/arm64/src/bcm2711/Kconfig
+++ b/arch/arm64/src/bcm2711/Kconfig
@@ -103,17 +103,92 @@ config BCM2711_SPI
 
 if BCM2711_SPI
 
+config BCM2711_SPI0
+       bool "SPI0"
+       depends on BCM2711_SPI
+       default n
+       ---help---
+               Enable the SPI0 interface.
+
+if BCM2711_SPI0
+
+config BCM2711_SPI0_CE0
+       int "CE0 GPIO"
+       depends on BCM2711_SPI0
+       default 8
+       ---help---
+               The GPIO pin for the chip enable 0 signal (8, 36, 43)
+
+config BCM2711_SPI0_CE1
+       int "CE1 GPIO"
+       depends on BCM2711_SPI0
+       default 7
+       ---help---
+               The GPIO pin for the chip enable 1 signal (7, 35, 44)
+
+config BCM2711_SPI0_MISO
+       int "MISO GPIO"
+       depends on BCM2711_SPI0
+       default 9
+       ---help---
+               The GPIO pin for the MISO signal (9, 37, 40)
+
+config BCM2711_SPI0_MOSI
+       int "MOSI GPIO"
+       depends on BCM2711_SPI0
+       default 10
+       ---help---
+               The GPIO pin for the MOSI signal (10, 38, 41)
+
+config BCM2711_SPI0_SCLK
+       int "SCLK GPIO"
+       depends on BCM2711_SPI0
+       default 11
+       ---help---
+               The GPIO pin for the SCLK signal (11, 39, 42)
+
+endif
+
 config BCM2711_SPI1
        bool "SPI1"
+       depends on BCM2711_SPI
        default n
        ---help---
-               Enable the SPI1 interface.
+               Enable the SPI1 interface (auxiliary).
 
 config BCM2711_SPI2
        bool "SPI2"
        default n
        ---help---
-               Enable the SPI2 interface.
+               Enable the SPI2 interface (auxiliary).
+
+config BCM2711_SPI3
+       bool "SPI3"
+       depends on BCM2711_SPI
+       default n
+       ---help---
+               Enable the SPI3 interface.
+
+config BCM2711_SPI4
+       bool "SPI4"
+       depends on BCM2711_SPI
+       default n
+       ---help---
+               Enable the SPI4 interface.
+
+config BCM2711_SPI5
+       bool "SPI5"
+       depends on BCM2711_SPI
+       default n
+       ---help---
+               Enable the SPI5 interface.
+
+config BCM2711_SPI6
+       bool "SPI6"
+       depends on BCM2711_SPI
+       default n
+       ---help---
+               Enable the SPI6 interface.
 
 endif # BCM2711_SPI
 
diff --git a/arch/arm64/src/bcm2711/bcm2711_gpio.c 
b/arch/arm64/src/bcm2711/bcm2711_gpio.c
index f3c2e4d5e9..f155e58a66 100644
--- a/arch/arm64/src/bcm2711/bcm2711_gpio.c
+++ b/arch/arm64/src/bcm2711/bcm2711_gpio.c
@@ -327,22 +327,25 @@ void bcm2711_gpio_set_pulls(uint32_t gpio, bool up, bool 
down)
   if (gpio <= 15)
     {
       value = (direction << (gpio * 2));
-      modreg32(value, value, BCM_GPIO_PUP_PDN_CNTRL_REG0);
+      modreg32(value, (0x3 << (gpio * 2)), BCM_GPIO_PUP_PDN_CNTRL_REG0);
     }
   else if (gpio <= 31 && gpio > 15)
     {
       value = (direction << ((gpio - 16) * 2));
-      modreg32(value, value, BCM_GPIO_PUP_PDN_CNTRL_REG1);
+      modreg32(value, (0x3 << ((gpio - 16) * 2)),
+               BCM_GPIO_PUP_PDN_CNTRL_REG1);
     }
   else if (gpio <= 47 && gpio > 31)
     {
       value = (direction << ((gpio - 32) * 2));
-      modreg32(value, value, BCM_GPIO_PUP_PDN_CNTRL_REG2);
+      modreg32(value, (0x3 << ((gpio - 32) * 2)),
+               BCM_GPIO_PUP_PDN_CNTRL_REG2);
     }
   else if (gpio <= 57 && gpio > 47)
     {
       value = (direction << ((gpio - 48) * 2));
-      modreg32(value, value, BCM_GPIO_PUP_PDN_CNTRL_REG3);
+      modreg32(value, (0x3 << ((gpio - 48) * 2)),
+               BCM_GPIO_PUP_PDN_CNTRL_REG3);
     }
 }
 
diff --git a/arch/arm64/src/bcm2711/bcm2711_spi.c 
b/arch/arm64/src/bcm2711/bcm2711_spi.c
index c09067739e..585c63215b 100644
--- a/arch/arm64/src/bcm2711/bcm2711_spi.c
+++ b/arch/arm64/src/bcm2711/bcm2711_spi.c
@@ -27,19 +27,25 @@
 #include <nuttx/config.h>
 
 #include <assert.h>
+#include <debug.h>
 #include <errno.h>
+#include <stdbool.h>
 #include <stdint.h>
 
 #include <arch/board/board.h>
 #include <nuttx/arch.h>
 #include <nuttx/irq.h>
 #include <nuttx/mutex.h>
+#include <nuttx/semaphore.h>
 #include <nuttx/spi/spi.h>
 
 #include "arm64_arch.h"
 #include "arm64_gic.h"
+#include "bcm2711_gpio.h"
 #include "chip.h"
 #include "hardware/bcm2711_aux.h"
+#include "hardware/bcm2711_irq.h"
+#include "hardware/bcm2711_spi.h"
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -49,16 +55,116 @@
 
 #define CORE_CLOCK_FREQUENCY 150000000
 
-/* Calculate the value required in the speed register for the correct
+/* Calculate the value required in the CDIV register for the correct
  * frequency.
  */
 
-#define SPI_SPEED_FIELD(spiclk) ((CORE_CLOCK_FREQUENCY / (2 * (spiclk))) - 1)
+#define SPI_CDIV(freq) (CORE_CLOCK_FREQUENCY / (freq))
 
 /* Calculate the actual frequency based on the speed field. */
 
-#define SPI_ACTUAL_FREQ(speedfield)                                            
\
-  (CORE_CLOCK_FREQUENCY / (2 * ((speedfield) + 1)))
+#define SPI_ACTUAL_FREQ(cdiv) (CORE_CLOCK_FREQUENCY / (cdiv))
+
+/* SPI interface pins (GPIO pins) */
+
+/* SPI0 (has alternate pin options, except CE2) */
+
+#ifdef CONFIG_BCM2711_SPI0
+#if CONFIG_BCM2711_SPI0_CE0 == 8
+#define SPI0_CE0_ALT BCM_GPIO_FUNC0
+#elif CONFIG_BCM2711_SPI0_CE0 == 36
+#define SPI0_CE0_ALT BCM_GPIO_FUNC0
+#elif CONFIG_BCM2711_SPI0_CE0 == 43
+#define SPI0_CE0_ALT BCM_GPIO_FUNC4
+#else
+#error "Invalid GPIO number for SPI0 CE0"
+#endif
+
+#if CONFIG_BCM2711_SPI0_CE1 == 7
+#define SPI0_CE1_ALT BCM_GPIO_FUNC0
+#elif CONFIG_BCM2711_SPI0_CE1 == 35
+#define SPI0_CE1_ALT BCM_GPIO_FUNC0
+#elif CONFIG_BCM2711_SPI0_CE1 == 44
+#define SPI0_CE1_ALT BCM_GPIO_FUNC4
+#else
+#error "Invalid GPIO number for SPI0 CE1"
+#endif
+
+#if CONFIG_BCM2711_SPI0_MISO == 9
+#define SPI0_MISO_ALT BCM_GPIO_FUNC0
+#elif CONFIG_BCM2711_SPI0_MISO == 37
+#define SPI0_MISO_ALT BCM_GPIO_FUNC0
+#elif CONFIG_BCM2711_SPI0_MISO == 40
+#define SPI0_MISO_ALT BCM_GPIO_FUNC4
+#else
+#error "Invalid GPIO number for SPI0 MISO"
+#endif
+
+#if CONFIG_BCM2711_SPI0_MOSI == 10
+#define SPI0_MOSI_ALT BCM_GPIO_FUNC0
+#elif CONFIG_BCM2711_SPI0_MOSI == 38
+#define SPI0_MOSI_ALT BCM_GPIO_FUNC0
+#elif CONFIG_BCM2711_SPI0_MOSI == 41
+#define SPI0_MOSI_ALT BCM_GPIO_FUNC4
+#else
+#error "Invalid GPIO number for SPI0 MOSI"
+#endif
+
+#if CONFIG_BCM2711_SPI0_SCLK == 11
+#define SPI0_SCLK_ALT BCM_GPIO_FUNC0
+#elif CONFIG_BCM2711_SPI0_SCLK == 39
+#define SPI0_SCLK_ALT BCM_GPIO_FUNC0
+#elif CONFIG_BCM2711_SPI0_SCLK == 42
+#define SPI0_SCLK_ALT BCM_GPIO_FUNC4
+#else
+#error "Invalid GPIO number for SPI0 SCLK"
+#endif
+
+#define SPI0_CE2 45
+#endif
+
+/* SPI1 */
+
+#define SPI1_MISO 19
+#define SPI1_MOSI 20
+#define SPI1_SCLK 21
+#define SPI1_CE0 18
+#define SPI1_CE1 17
+#define SPI1_CE2 16
+
+/* SPI2 (datasheet does not mention this interface's available pins) */
+
+/* SPI3 (no CE2) */
+
+#define SPI3_MISO 1
+#define SPI3_MOSI 2
+#define SPI3_SCLK 3
+#define SPI3_CE0 0
+#define SPI3_CE1 24
+
+/* SPI4 (no CE2) */
+
+#define SPI4_MISO 5
+#define SPI4_MOSI 6
+#define SPI4_SCLK 7
+#define SPI4_CE0 4
+#define SPI4_CE1 25
+
+/* SPI5 (no CE2) */
+
+#define SPI5_MISO 13
+#define SPI5_MOSI 14
+#define SPI5_SCLK 15
+#define SPI5_CE0 12
+#define SPI5_CE1 26
+
+/* SPI6 (no CE2) */
+
+#define SPI6_MISO 19
+#define SPI6_MOSI 20
+#define SPI6_SCLK 21
+#define SPI6_CE0 18
+#define SPI6_CE1 27
 
 /****************************************************************************
  * Private Types
@@ -71,11 +177,16 @@ struct bcm2711_spidev_s
   struct spi_dev_s spidev; /* Externally visible */
   uint32_t base;           /* Base address of SPI interface register */
   mutex_t lock;            /* Mutual exclusion during chip select */
+  sem_t wait;              /* Where to wait for transfer completion */
   uint32_t freq;           /* Request clock frequency */
   uint32_t actualfreq;     /* Actual clock frequency */
   uint8_t nbits;           /* Word bit-width */
   uint8_t mode;            /* 0, 1, 2 or 3 */
-  uint8_t port;            /* 1 or 2 */
+  uint8_t port;            /* SPI 0-6 */
+  bool initialized;        /* Already initialized */
+  uint8_t *txbuffer;       /* Transmit buffer for current transfer */
+  uint8_t *rxbuffer;       /* Receive buffer for current transfer */
+  size_t nwords;           /* Number of words in exchange */
 };
 
 /****************************************************************************
@@ -84,19 +195,20 @@ struct bcm2711_spidev_s
 
 /* SPI methods */
 
-static int spi_lock(struct spi_dev_s *dev, bool lock);
-static uint32_t spi_setfrequency(struct spi_dev_s *dev, uint32_t frequency);
-static void spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode);
-static void spi_setbits(struct spi_dev_s *dev, int nbits);
-static uint32_t spi_send(struct spi_dev_s *dev, uint32_t wd);
-static void unused_code spi_exchange(struct spi_dev_s *dev,
-                                     const void *txbuffer, void *rxbuffer,
-                                     size_t nwords);
-
+static int spi_lock(FAR struct spi_dev_s *dev, bool lock);
+static uint32_t spi_setfrequency(FAR struct spi_dev_s *dev,
+                                 uint32_t frequency);
+static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode);
+static void spi_setbits(FAR struct spi_dev_s *dev, int nbits);
+static uint32_t spi_send(FAR struct spi_dev_s *dev, uint32_t wd);
+static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
+                         void *rxbuffer, size_t nwords);
+static void spi_select(FAR struct spi_dev_s *dev, uint32_t devid,
+                       bool selected);
 #ifndef CONFIG_SPI_EXCHANGE
-static void spi_sndblock(struct spi_dev_s *dev, const void *buffer,
+static void spi_sndblock(FAR struct spi_dev_s *dev, const void *buffer,
                          size_t nwords);
-static void spi_recvblock(struct spi_dev_s *dev, void *buffer,
+static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer,
                           size_t nwords);
 #endif /* CONFIG_SPI_EXCHANGE */
 
@@ -104,69 +216,375 @@ static void spi_recvblock(struct spi_dev_s *dev, void 
*buffer,
  * Private Data
  ****************************************************************************/
 
-/* Operations for SPI interfaces */
+/* Operations for non-auxiliary SPI interfaces */
 
 static const struct spi_ops_s g_spiops =
 {
-  .lock = spi_lock,
-  .setfrequency = spi_setfrequency,
-  .setmode = spi_setmode,
-  .setbits = spi_setbits,
-  .send = spi_send,
+    .lock = spi_lock,
+    .setfrequency = spi_setfrequency,
+    .setmode = spi_setmode,
+    .setbits = spi_setbits,
+    .send = spi_send,
+    .select = spi_select,
 #ifdef CONFIG_SPI_EXCHANGE
-  .exchange = spi_exchange,
+    .exchange = spi_exchange,
 #else
-  .sndblock = spi_sndblock,
-  .recvblock = spi_recvblock,
+    .sndblock = spi_sndblock,
+    .recvblock = spi_recvblock,
 #endif /* CONFIG_SPI_EXCHANGE */
 #ifdef CONFIG_SPI_HWFEATURES
-  .hwfeatures = NULL,
+    .hwfeatures = NULL,
 #endif /* CONFIG_SPI_HWFEATURES */
 #ifdef CONFIG_SPI_CALLBACK
-  .registercallback = /* TODO */, /* Provided externally */
+    .registercallback = NULL,
+    /* TODO when needed */, /* Provided externally */
 #else
-  .registercallback = 0, /* Not implemented */
+    .registercallback = NULL, /* Not implemented */
 #endif
 };
 
-#define CONFIG_BCM2711_SPI1 // TODO remove
-#if defined(CONFIG_BCM2711_SPI1)
+/* True if the interrupt handler for SPI is attached, false otherwise */
+
+static bool g_interrupts = false;
 
-static struct bcm2711_spidev_s g_spi1dev =
+#if defined(CONFIG_BCM2711_SPI0)
+static struct bcm2711_spidev_s g_spi0dev =
 {
-  .spidev =
-      {
-          .ops = &g_spiops,
-      },
-  .base = BCM_AUX_SPI1_BASEADDR,
-  .frequency = 0,
-  .port = 1,
-  .lock = NXMUTEX_INITIALIZER,
+    .spidev =
+        {
+            .ops = &g_spiops,
+        },
+    .base = BCM_SPI0_BASEADDR,
+    .freq = 0,
+    .port = 0,
+    .lock = NXMUTEX_INITIALIZER,
+    .wait = NXSEM_INITIALIZER(0, 0),
+    .txbuffer = NULL,
+    .rxbuffer = NULL,
+    .nwords = 0,
 };
+#endif
 
-#endif /* defined(CONFIG_BCM2711_SPI1) */
+#if defined(CONFIG_BCM2711_SPI3)
+static struct bcm2711_spidev_s g_spi3dev =
+{
+    .spidev =
+        {
+            .ops = &g_spiops,
+        },
+    .base = BCM_SPI3_BASEADDR,
+    .freq = 0,
+    .port = 3,
+    .lock = NXMUTEX_INITIALIZER,
+    .wait = NXSEM_INITIALIZER(0, 0),
+    .txbuffer = NULL,
+    .rxbuffer = NULL,
+    .nwords = 0,
+};
+#endif
 
-#define CONFIG_BCM2711_SPI2 // TODO remove
-#if defined(CONFIG_BCM2711_SPI2)
+#if defined(CONFIG_BCM2711_SPI4)
+static struct bcm2711_spidev_s g_spi4dev =
+{
+    .spidev =
+        {
+            .ops = &g_spiops,
+        },
+    .base = BCM_SPI4_BASEADDR,
+    .freq = 0,
+    .port = 4,
+    .lock = NXMUTEX_INITIALIZER,
+    .wait = NXSEM_INITIALIZER(0, 0),
+    .txbuffer = NULL,
+    .rxbuffer = NULL,
+    .nwords = 0,
+};
+#endif
 
-static struct bcm2711_spidev_s g_spi2dev =
+#if defined(CONFIG_BCM2711_SPI5)
+static struct bcm2711_spidev_s g_spi5dev =
 {
-  .spidev =
-      {
-          .ops = &g_spiops,
-      },
-  .base = BCM_AUX_SPI2_BASEADDR,
-  .frequency = 0,
-  .port = 2,
-  .lock = NXMUTEX_INITIALIZER,
+    .spidev =
+        {
+            .ops = &g_spiops,
+        },
+    .base = BCM_SPI5_BASEADDR,
+    .freq = 0,
+    .port = 5,
+    .lock = NXMUTEX_INITIALIZER,
+    .wait = NXSEM_INITIALIZER(0, 0),
+    .txbuffer = NULL,
+    .rxbuffer = NULL,
+    .nwords = 0,
 };
+#endif
 
-#endif /* defined(CONFIG_BCM2711_SPI2) */
+#if defined(CONFIG_BCM2711_SPI6)
+static struct bcm2711_spidev_s g_spi6dev =
+{
+    .spidev =
+        {
+            .ops = &g_spiops,
+        },
+    .base = BCM_SPI6_BASEADDR,
+    .freq = 0,
+    .port = 6,
+    .lock = NXMUTEX_INITIALIZER,
+    .wait = NXSEM_INITIALIZER(0, 0),
+    .txbuffer = NULL,
+    .rxbuffer = NULL,
+    .nwords = 0,
+};
+#endif
 
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: spi_interrupt_en
+ *
+ * Description:
+ *   Enable/disable interrupts for the SPI interfaces.
+ *
+ * Input Parameters:
+ *   priv - Device-specific state data
+ *   en   - true: enable interrupts, false: disable interrupts
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void spi_interrupt_en(struct bcm2711_spidev_s *priv, bool en)
+{
+  uint32_t regval;
+
+  DEBUGASSERT(priv);
+
+  if (en)
+    {
+      regval = (BCM_SPI_CS_INTR | BCM_SPI_CS_INTD);
+    }
+  else
+    {
+      regval = 0;
+    }
+
+  modreg32(regval, (BCM_SPI_CS_INTR | BCM_SPI_CS_INTD),
+           BCM_SPI_CS(priv->base));
+}
+
+/****************************************************************************
+ * Name: spi_fill_txfifo
+ *
+ * Description:
+ *   Write as much data to the TX FIFO as possible without overflowing it. TX
+ *   will also stop if RX is 3/4 full. This function will not do anything if
+ *   the SPI device has no data waiting to be written.
+ *
+ * Input Parameters:
+ *   dev - The SPI device to write to.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void spi_fill_txfifo(struct bcm2711_spidev_s *dev)
+{
+  uint32_t data;
+  while ((getreg32(BCM_SPI_CS(dev->base)) & BCM_SPI_CS_TXD) &&
+        !(getreg32(BCM_SPI_CS(dev->base)) & BCM_SPI_CS_RXR) &&
+        dev->nwords)
+    {
+      if (dev->txbuffer)
+        {
+          data = (uint32_t)*dev->txbuffer++;
+        }
+
+      putreg32(dev->txbuffer ? data : 0xff, BCM_SPI_FIFO(dev->base));
+
+      dev->nwords--;
+    }
+}
+
+/****************************************************************************
+ * Name: spi_drain_rxfifo
+ *
+ * Description:
+ *   Read as much data from the RX FIFO as possible. Will not do anything if
+ *   there is no data to be read.
+ *
+ * Input Parameters:
+ *   dev - The SPI device to write to.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void spi_drain_rxfifo(struct bcm2711_spidev_s *dev)
+{
+  uint32_t data;
+
+  while (getreg32(BCM_SPI_CS(dev->base)) & BCM_SPI_CS_RXD)
+    {
+      data = getreg32(BCM_SPI_FIFO(dev->base));
+      if (dev->rxbuffer)
+        {
+          *dev->rxbuffer++ = (uint8_t)data;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: spi_interrupt_handler
+ *
+ * Description:
+ *   The interrupt service routine for a given SPI interface.
+ *
+ * Input Parameters:
+ *   dev - The SPI device to be serviced.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static int spi_service_interrupt(struct bcm2711_spidev_s *dev)
+{
+  int err = 0;
+
+  /* From peripheral data sheet:
+   *
+   * If DONE is set and data to write (this means it is the first interrupt),
+   * write up to 64 bytes to SPI_FIFO. If DONE is set and no more data, set
+   * TA = 0. Read trailing data from SPI_FIFO until RXD is 0.
+   *
+   * If RXR is set read 48 bytes data from SPI_FIFO and if more data to
+   * write, write up to 48 bytes to SPI_FIFO
+   */
+
+  if (getreg32(BCM_SPI_CS(dev->base)) & BCM_SPI_CS_DONE)
+    {
+      if (dev->nwords > 0)
+        {
+          /* While there is space to write and stuff to write, write it to
+           * the FIFO. Check here if the RX FIFO needs reading so we don't
+           * overflow it either.
+           */
+
+          spi_fill_txfifo(dev);
+        }
+      else
+        {
+          /* Mark transfer as over, there is nothing left to write */
+
+          modreg32(0, BCM_SPI_CS_TA, BCM_SPI_CS(dev->base));
+
+          /* Drain the remaining data to be read */
+
+          spi_drain_rxfifo(dev);
+
+          /* Clean buffers. */
+
+          dev->txbuffer = NULL;
+          dev->rxbuffer = NULL;
+
+          /* Post the semaphore to let the caller know the transfer is over */
+
+          nxsem_post(&dev->wait);
+        }
+    }
+
+  /* If the RX FIFO needs to be read */
+
+  if (getreg32(BCM_SPI_CS(dev->base)) & BCM_SPI_CS_RXR)
+    {
+      /* Read RX FIFO into buffer (if provided) until empty */
+
+      spi_drain_rxfifo(dev);
+
+      /* If more information can be written now, then write it */
+
+      spi_fill_txfifo(dev);
+    }
+
+  return err;
+}
+
+/****************************************************************************
+ * Name: spi_interrupt_handler
+ *
+ * Description:
+ *   The interrupt handler for SPI interrupts.
+ *
+ * Input Parameters:
+ *   irq - The IRQ number
+ *   context - The interrupt context
+ *   arg - NULL in this case, all data is grabbed from the SPI device global
+ *         definitions
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static int spi_interrupt_handler(int irq, FAR void *context, FAR void *arg)
+{
+  uint32_t pactl;
+
+  /* Check which SPI interfaces need to be serviced and service them */
+
+  pactl = getreg32(BCM_PACTL_CS);
+
+  if (pactl & BCM_PACTL_CS_SPI0)
+    {
+#if defined(CONFIG_BCM2711_SPI0)
+      spi_service_interrupt(&g_spi0dev);
+#endif
+    }
+  else if (pactl & BCM_PACTL_CS_SPI1)
+    {
+#if defined(CONFIG_BCM2711_SPI1)
+#error "SPI1 interrupt not implemented"
+#endif
+    }
+  else if (pactl & BCM_PACTL_CS_SPI2)
+    {
+#if defined(CONFIG_BCM2711_SPI2)
+#error "SPI1 interrupt not implemented"
+#endif
+    }
+  else if (pactl & BCM_PACTL_CS_SPI3)
+    {
+#if defined(CONFIG_BCM2711_SPI3)
+      spi_service_interrupt(&g_spi3dev);
+#endif
+    }
+  else if (pactl & BCM_PACTL_CS_SPI4)
+    {
+#if defined(CONFIG_BCM2711_SPI4)
+      spi_service_interrupt(&g_spi4dev);
+#endif
+    }
+  else if (pactl & BCM_PACTL_CS_SPI5)
+    {
+#if defined(CONFIG_BCM2711_SPI5)
+      spi_service_interrupt(&g_spi5dev);
+#endif
+    }
+  else if (pactl & BCM_PACTL_CS_SPI6)
+    {
+#if defined(CONFIG_BCM2711_SPI6)
+      spi_service_interrupt(&g_spi6dev);
+#endif
+    }
+
+  return 0;
+}
+
 /****************************************************************************
  * Name: spi_lock
  *
@@ -184,7 +602,7 @@ static struct bcm2711_spidev_s g_spi2dev =
  *   lock - true: Lock spi bus, false: unlock SPI bus
  *
  * Returned Value:
- *   None
+ *   Result of locking the mutex, 0 on success.
  *
  ****************************************************************************/
 
@@ -221,24 +639,296 @@ static uint32_t spi_setfrequency(struct spi_dev_s *dev, 
uint32_t frequency)
 {
   struct bcm2711_spidev_s *priv = (struct bcm2711_spidev_s *)dev;
 
-  /* Calculate the speed field value needed */
+  DEBUGASSERT(priv);
+
+  /* Calculate the clock divisor needed (must be a multiple of 2) */
 
-  uint32_t speed = SPI_SPEED_FIELD(frequency);
+  uint32_t cdiv = SPI_CDIV(frequency);
+  cdiv &= ~0x1; /* Clear last bit to guarantee multiple of 2 rounded down */
+  DEBUGASSERT(cdiv < 0xffff);
 
-  /* Save the speed field to take effect */
+  /* Save the clock divisor to take effect */
 
-  modreg32(BCM_SPI_CNTL0_SPEED, speed << 20, BCM_SPI_CNTL0_REG(priv->base));
+  putreg32(cdiv, BCM_SPI_CLK(priv->base));
 
   /* Calculate the new actual and save settings */
 
   priv->freq = frequency;
-  priv->actualfreq = SPI_ACTUAL_FREQ(speed);
+  priv->actualfreq = SPI_ACTUAL_FREQ(cdiv);
 
-  spiinfo("Frequency %" PRId32 "->%" PRId32 "\n",
-          frequency, priv->actualfreq);
+  spiinfo("Frequency %" PRId32 "->%" PRId32 "\n", frequency,
+          priv->actualfreq);
   return priv->actualfreq;
 }
 
+/****************************************************************************
+ * Name: spi_setmode
+ *
+ * Description:
+ *   Set the SPI mode.
+ *
+ * Input Parameters:
+ *   dev -       Device-specific state data
+ *   frequency - The SPI mode requested
+ *
+ * Returned Value: None
+ *
+ ****************************************************************************/
+
+static void spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode)
+{
+  struct bcm2711_spidev_s *priv = (struct bcm2711_spidev_s *)dev;
+  uint32_t regval;
+
+  DEBUGASSERT(priv);
+
+  /* No change to SPI mode */
+
+  if (mode == priv->mode)
+    {
+      return;
+    }
+
+  switch (mode)
+    {
+    case SPIDEV_MODE0: /* CPOL=0, CPHA=0 */
+      regval = 0;
+      break;
+    case SPIDEV_MODE1: /* CPOL=0, CPHA=1 */
+      regval = BCM_SPI_CS_CPHA;
+      break;
+    case SPIDEV_MODE2: /* CPOL=1, CPHA=0 */
+      regval = BCM_SPI_CS_CPOL;
+      break;
+    case SPIDEV_MODE3: /* CPOL=1, CPHA=1 */
+      regval = BCM_SPI_CS_CPOL | BCM_SPI_CS_CPHA;
+      break;
+    default:
+      spierr("Bad SPI mode: %d\n", mode);
+      DEBUGASSERT(false);
+      return;
+    }
+
+  spiinfo("SPI set mode: %d", mode);
+  modreg32(regval, (BCM_SPI_CS_CPOL | BCM_SPI_CS_CPHA),
+           BCM_SPI_CS(priv->base));
+  priv->mode = mode;
+}
+
+/****************************************************************************
+ * Name: spi_setbits
+ *
+ * Description:
+ *   Set the number of bits per word.
+ *
+ * Input Parameters:
+ *   dev -  Device-specific state data
+ *   nbits - The number of bits requests
+ *
+ * Returned Value:
+ *   none
+ *
+ ****************************************************************************/
+
+static void spi_setbits(struct spi_dev_s *dev, int nbits)
+{
+  struct bcm2711_spidev_s *priv = (struct bcm2711_spidev_s *)dev;
+
+  DEBUGASSERT(priv);
+
+  /* As far as I'm aware, the BCM2711 only supports 8 bits per word? */
+
+  DEBUGASSERT(nbits == 8);
+}
+
+/****************************************************************************
+ * Name: 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:
+ *   response
+ *
+ ****************************************************************************/
+
+static uint32_t spi_send(struct spi_dev_s *dev, uint32_t wd)
+{
+  struct bcm2711_spidev_s *priv = (struct bcm2711_spidev_s *)dev;
+  uint32_t regval;
+
+  /* Wait until the TX FIFO can accept data */
+
+  while (!(getreg32(BCM_SPI_CS(priv->base)) & BCM_SPI_CS_TXD))
+    ;
+
+  /* Make sure TA (transfer active) bit is set */
+
+  modreg32(BCM_SPI_CS_TA, BCM_SPI_CS_TA, BCM_SPI_CS(priv->base));
+
+  /* Write the byte to the TX FIFO */
+
+  putreg32(wd, BCM_SPI_FIFO(priv->base));
+
+  /* Wait for the RX FIFO not empty */
+
+  while (!(getreg32(BCM_SPI_CS(priv->base)) & BCM_SPI_CS_RXD))
+    ;
+
+  /* Get the value from the RX FIFO */
+
+  regval = getreg32(BCM_SPI_FIFO(priv->base));
+  spiinfo("%04" PRIx32 "->%04" PRIx32 "\n", wd, regval);
+
+  /* Wait for done signal */
+
+  while (!(getreg32(BCM_SPI_CS(priv->base)) & BCM_SPI_CS_DONE))
+    ;
+
+  /* End the transfer */
+
+  modreg32(0, BCM_SPI_CS_TA, BCM_SPI_CS(priv->base));
+
+  return regval;
+}
+
+/****************************************************************************
+ * Name: spi_exchange
+ *
+ * Description:
+ *   Wrapper function to 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 spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
+                         void *rxbuffer, size_t nwords)
+{
+  struct bcm2711_spidev_s *priv = (struct bcm2711_spidev_s *)dev;
+
+  /* Set the buffers up */
+
+  priv->txbuffer = (void *)txbuffer;
+  priv->rxbuffer = rxbuffer;
+  priv->nwords = nwords;
+
+  /* Start the transfer */
+
+  modreg32(BCM_SPI_CS_TA, BCM_SPI_CS_TA, BCM_SPI_CS(priv->base));
+
+  /* Block on semaphore until transfers are all done */
+
+  nxsem_wait_uninterruptible(&priv->wait);
+}
+
+/****************************************************************************
+ * Name: 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
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_SPI_EXCHANGE
+static void spi_sndblock(struct spi_dev_s *dev, const void *buffer,
+                         size_t nwords)
+{
+  return spi_exchange(dev, buffer, NULL, nwords);
+}
+
+/****************************************************************************
+ * Name: spi_recvblock
+ *
+ * Description:
+ *   Revice 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 spi_recvblock(struct spi_dev_s *dev, void *buffer, size_t nwords)
+{
+  return spi_exchange(dev, NULL, buffer, nwords);
+}
+#endif /* !CONFIG_SPI_EXCHANGE */
+
+/****************************************************************************
+ * Name: spi_select
+ *
+ * Description:
+ *   Enables/disables the chosen chip select ping for the BCM2711 SPI
+ *   interface. Some SPI interfaces have up to 3 chip select options. The CS
+ *   pin is automatically asserted and de-asserted during transfers, so this
+ *   function will only choose which CS interface is active at any time.
+ *
+ ****************************************************************************/
+
+static void spi_select(FAR struct spi_dev_s *dev, uint32_t devid,
+                       bool selected)
+{
+  struct bcm2711_spidev_s *priv = (struct bcm2711_spidev_s *)dev;
+  spiinfo("Select devid %u", devid);
+
+  /* Get the last bits of the device ID, indicating index (TODO: is this
+   * appropriate?)
+   */
+
+  devid = devid & 0xffff;
+  DEBUGASSERT(priv);
+  DEBUGASSERT(devid < 2);
+  spiinfo("Using chip enable %u", devid);
+
+  /* Do nothing if not actively selecting a peripheral device */
+
+  if (!selected)
+    {
+      return;
+    }
+
+  /* Set chip select pin to be the active pin */
+
+  modreg32(devid & 0x3, BCM_SPI_CS_CS, BCM_SPI_CS(priv->base));
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -259,5 +949,196 @@ static uint32_t spi_setfrequency(struct spi_dev_s *dev, 
uint32_t frequency)
 
 struct spi_dev_s *bcm2711_spibus_initialize(int port)
 {
-  return NULL;
+  int err;
+  struct bcm2711_spidev_s *priv = NULL;
+
+  switch (port)
+    {
+#if defined(CONFIG_BCM2711_SPI0)
+    case 0:
+      priv = &g_spi0dev;
+      break;
+#endif
+#if defined(CONFIG_BCM2711_SPI1)
+    case 1:
+#error "SPI1 is not implemented"
+      break;
+#endif
+#if defined(CONFIG_BCM2711_SPI2)
+    case 2:
+#error "SPI2 is not implemented"
+      break;
+#endif
+#if defined(CONFIG_BCM2711_SPI3)
+    case 3:
+      priv = &g_spi3dev;
+      break;
+#endif
+#if defined(CONFIG_BCM2711_SPI4)
+    case 4:
+      priv = &g_spi4dev;
+      break;
+#endif
+#if defined(CONFIG_BCM2711_SPI5)
+    case 5:
+      priv = &g_spi5dev;
+      break;
+#endif
+#if defined(CONFIG_BCM2711_SPI6)
+    case 6:
+      priv = &g_spi6dev;
+      break;
+#endif
+    default:
+      return NULL;
+    }
+
+  if (priv->initialized)
+    {
+      return &priv->spidev;
+    }
+
+  /* Perform initialization */
+
+  priv->nbits = 8;
+  priv->freq = 0;
+  priv->mode = SPIDEV_MODE0;
+  priv->txbuffer = NULL;
+  priv->rxbuffer = NULL;
+  priv->nwords = 0;
+
+  /* If the main SPI interrupt handler is not attached yet, attach it */
+
+  if (!g_interrupts)
+    {
+      err = irq_attach(BCM_IRQ_VC_SPI, spi_interrupt_handler, NULL);
+
+      if (err)
+        {
+          spierr("Could not attach SPI interrupt handler: %d\n", err);
+          irqerr("Could not attach SPI interrupt handler: %d\n", err);
+          return NULL;
+        }
+
+      arm64_gic_irq_set_priority(BCM_IRQ_VC_SPI, 0, IRQ_TYPE_LEVEL);
+      up_enable_irq(BCM_IRQ_VC_SPI);
+      g_interrupts = true;
+
+      irqinfo("SPI interrupt handler attached.");
+      spiinfo("SPI interrupt handler attached.");
+    }
+
+  /* Enable SPI interface interrupts for non-auxiliary SPI devices */
+
+  if (port != 1 && port != 2)
+    {
+      spiinfo("Enabled interrupts for SPI%d\n", port);
+      spi_interrupt_en(priv, true);
+    }
+
+  /* Set up GPIO pins for the interface */
+
+  switch (port)
+    {
+#if defined(CONFIG_BCM2711_SPI0)
+    case 0:
+      bcm2711_gpio_set_pulls(CONFIG_BCM2711_SPI0_CE0, true, false);
+      bcm2711_gpio_set_pulls(CONFIG_BCM2711_SPI0_CE1, true, false);
+      bcm2711_gpio_set_pulls(CONFIG_BCM2711_SPI0_MOSI, false, true);
+      bcm2711_gpio_set_pulls(CONFIG_BCM2711_SPI0_MISO, false, true);
+      bcm2711_gpio_set_pulls(CONFIG_BCM2711_SPI0_SCLK, false, true);
+
+      bcm2711_gpio_set_func(CONFIG_BCM2711_SPI0_CE0, SPI0_CE0_ALT);
+      bcm2711_gpio_set_func(CONFIG_BCM2711_SPI0_CE1, SPI0_CE1_ALT);
+      bcm2711_gpio_set_func(CONFIG_BCM2711_SPI0_MOSI, SPI0_MOSI_ALT);
+      bcm2711_gpio_set_func(CONFIG_BCM2711_SPI0_MISO, SPI0_MISO_ALT);
+      bcm2711_gpio_set_func(CONFIG_BCM2711_SPI0_SCLK, SPI0_SCLK_ALT);
+      break;
+#endif
+#if defined(CONFIG_BCM2711_SPI1)
+    case 1:
+      bcm2711_gpio_set_pulls(SPI1_CE0, true, false);
+      bcm2711_gpio_set_pulls(SPI1_CE1, true, false);
+      bcm2711_gpio_set_pulls(SPI2_CE1, true, false);
+      bcm2711_gpio_set_pulls(SPI1_MOSI, false, true);
+      bcm2711_gpio_set_pulls(SPI1_MISO, false, true);
+      bcm2711_gpio_set_pulls(SPI1_SCLK, false, true);
+
+      bcm2711_gpio_set_func(SPI1_CE0, BCM_GPIO_FUNC4);
+      bcm2711_gpio_set_func(SPI1_CE1, BCM_GPIO_FUNC4);
+      bcm2711_gpio_set_func(SPI1_CE2, BCM_GPIO_FUNC4);
+      bcm2711_gpio_set_func(SPI1_MOSI, BCM_GPIO_FUNC4);
+      bcm2711_gpio_set_func(SPI1_MISO, BCM_GPIO_FUNC4);
+      bcm2711_gpio_set_func(SPI1_SCLK, BCM_GPIO_FUNC4);
+      break;
+#endif
+#if defined(CONFIG_BCM2711_SPI2)
+    case 2:
+#error "SPI2 is not implemented"
+      break;
+#endif
+#if defined(CONFIG_BCM2711_SPI3)
+    case 3:
+      bcm2711_gpio_set_pulls(SPI3_CE0, true, false);
+      bcm2711_gpio_set_pulls(SPI3_CE1, true, false);
+      bcm2711_gpio_set_pulls(SPI3_MOSI, false, true);
+      bcm2711_gpio_set_pulls(SPI3_MISO, false, true);
+      bcm2711_gpio_set_pulls(SPI3_SCLK, false, true);
+
+      bcm2711_gpio_set_func(SPI3_CE0, BCM_GPIO_FUNC3);
+      bcm2711_gpio_set_func(SPI3_CE1, BCM_GPIO_FUNC5);
+      bcm2711_gpio_set_func(SPI3_MOSI, BCM_GPIO_FUNC3);
+      bcm2711_gpio_set_func(SPI3_MISO, BCM_GPIO_FUNC3);
+      bcm2711_gpio_set_func(SPI3_SCLK, BCM_GPIO_FUNC3);
+      break;
+#endif
+#if defined(CONFIG_BCM2711_SPI4)
+    case 4:
+      bcm2711_gpio_set_pulls(SPI4_CE0, true, false);
+      bcm2711_gpio_set_pulls(SPI4_CE1, true, false);
+      bcm2711_gpio_set_pulls(SPI4_MOSI, false, true);
+      bcm2711_gpio_set_pulls(SPI4_MISO, false, true);
+      bcm2711_gpio_set_pulls(SPI4_SCLK, false, true);
+
+      bcm2711_gpio_set_func(SPI4_CE0, BCM_GPIO_FUNC3);
+      bcm2711_gpio_set_func(SPI4_CE1, BCM_GPIO_FUNC5);
+      bcm2711_gpio_set_func(SPI4_MOSI, BCM_GPIO_FUNC3);
+      bcm2711_gpio_set_func(SPI4_MISO, BCM_GPIO_FUNC3);
+      bcm2711_gpio_set_func(SPI4_SCLK, BCM_GPIO_FUNC3);
+      break;
+#endif
+#if defined(CONFIG_BCM2711_SPI5)
+    case 5:
+      bcm2711_gpio_set_pulls(SPI5_CE0, true, false);
+      bcm2711_gpio_set_pulls(SPI5_CE1, true, false);
+      bcm2711_gpio_set_pulls(SPI5_MOSI, false, true);
+      bcm2711_gpio_set_pulls(SPI5_MISO, false, true);
+      bcm2711_gpio_set_pulls(SPI5_SCLK, false, true);
+
+      bcm2711_gpio_set_func(SPI5_CE0, BCM_GPIO_FUNC3);
+      bcm2711_gpio_set_func(SPI5_CE1, BCM_GPIO_FUNC5);
+      bcm2711_gpio_set_func(SPI5_MOSI, BCM_GPIO_FUNC3);
+      bcm2711_gpio_set_func(SPI5_MISO, BCM_GPIO_FUNC3);
+      bcm2711_gpio_set_func(SPI5_SCLK, BCM_GPIO_FUNC3);
+      break;
+#endif
+#if defined(CONFIG_BCM2711_SPI6)
+    case 6:
+      bcm2711_gpio_set_pulls(SPI6_CE0, true, false);
+      bcm2711_gpio_set_pulls(SPI6_CE1, true, false);
+      bcm2711_gpio_set_pulls(SPI6_MOSI, false, true);
+      bcm2711_gpio_set_pulls(SPI6_MISO, false, true);
+      bcm2711_gpio_set_pulls(SPI6_SCLK, false, true);
+
+      bcm2711_gpio_set_func(SPI6_CE0, BCM_GPIO_FUNC3);
+      bcm2711_gpio_set_func(SPI6_CE1, BCM_GPIO_FUNC5);
+      bcm2711_gpio_set_func(SPI6_MOSI, BCM_GPIO_FUNC3);
+      bcm2711_gpio_set_func(SPI6_MISO, BCM_GPIO_FUNC3);
+      bcm2711_gpio_set_func(SPI6_SCLK, BCM_GPIO_FUNC3);
+      break;
+#endif
+    }
+
+  priv->initialized = true;
+  return &priv->spidev;
 }
diff --git a/arch/arm64/src/bcm2711/hardware/bcm2711_irq.h 
b/arch/arm64/src/bcm2711/hardware/bcm2711_irq.h
index 70315a498a..e57df74f43 100644
--- a/arch/arm64/src/bcm2711/hardware/bcm2711_irq.h
+++ b/arch/arm64/src/bcm2711/hardware/bcm2711_irq.h
@@ -33,108 +33,6 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
-/* ARM_LOCAL interrupts */
-
-/* ARMC interrupts */
-
-#define BCM_IRQ_ARMC_TIMER 0      /* Timer */
-#define BCM_IRQ_ARMC_MAILBOX 1    /* Mailbox */
-#define BCM_IRQ_ARMC_DOORBELL0 2  /* Doorbell 0 */
-#define BCM_IRQ_ARMC_DOORBELL1 3  /* Doorbell 1 */
-#define BCM_IRQ_ARMC_VPU0HALT 4   /* VPU 0 halted */
-#define BCM_IRQ_ARMC_VPU1HALT 5   /* VPU 1 halted */
-#define BCM_IRQ_ARMC_ARMADDRERR 6 /* ARM address error */
-#define BCM_IRQ_ARMC_ARMAXIERR 7  /* ARM AXI error */
-#define BCM_IRQ_ARMC_SWI0 8       /* Software interrupt 0 */
-#define BCM_IRQ_ARMC_SWI1 9       /* Software interrupt 1 */
-#define BCM_IRQ_ARMC_SWI2 10      /* Software interrupt 2 */
-#define BCM_IRQ_ARMC_SWI3 11      /* Software interrupt 3 */
-#define BCM_IRQ_ARMC_SWI4 12      /* Software interrupt 4 */
-#define BCM_IRQ_ARMC_SWI5 13      /* Software interrupt 5 */
-#define BCM_IRQ_ARMC_SWI6 14      /* Software interrupt 6 */
-#define BCM_IRQ_ARMC_SWI7 15      /* Software interrupt 7 */
-
-/* VideoCore interrupts */
-
-#define BCM_IRQ_VC_TIMER0 0
-#define BCM_IRQ_VC_TIMER1 1
-#define BCM_IRQ_VC_TIMER2 2
-#define BCM_IRQ_VC_TIMER3 3
-#define BCM_IRQ_VC_H2640 4
-#define BCM_IRQ_VC_H2641 5
-#define BCM_IRQ_VC_H2642 6
-#define BCM_IRQ_VC_JPEG 7
-#define BCM_IRQ_VC_ISP 8
-#define BCM_IRQ_VC_USB 9
-#define BCM_IRQ_VC_V3D 10
-#define BCM_IRQ_VC_TRANSPOSE 11
-#define BCM_IRQ_VC_MCSYNC0 12
-#define BCM_IRQ_VC_MCSYNC1 13
-#define BCM_IRQ_VC_MCSYNC2 14
-#define BCM_IRQ_VC_MCSYNC3 15
-#define BCM_IRQ_VC_DMA0 16
-#define BCM_IRQ_VC_DMA1 17
-#define BCM_IRQ_VC_DMA2 18
-#define BCM_IRQ_VC_DMA3 19
-#define BCM_IRQ_VC_DMA4 20
-#define BCM_IRQ_VC_DMA5 21
-#define BCM_IRQ_VC_DMA6 22
-#define BCM_IRQ_VC_DMA7N8 23
-#define BCM_IRQ_VC_DMA9N10 24
-#define BCM_IRQ_VC_DMA11 25
-#define BCM_IRQ_VC_DMA12 26
-#define BCM_IRQ_VC_DMA13 27
-#define BCM_IRQ_VC_DMA14 28
-#define BCM_IRQ_VC_AUX 29
-#define BCM_IRQ_VC_ARM 30
-#define BCM_IRQ_VC_DMA15 31
-#define BCM_IRQ_VC_HDMICEC 32
-#define BCM_IRQ_VC_HVS 33
-#define BCM_IRQ_VC_RPIVID 34
-#define BCM_IRQ_VC_SDC 35
-#define BCM_IRQ_VC_DSI0 36
-#define BCM_IRQ_VC_PIXVLV2 37
-#define BCM_IRQ_VC_CAM0 38
-#define BCM_IRQ_VC_CAM1 39
-#define BCM_IRQ_VC_HDMI0 40
-#define BCM_IRQ_VC_HDMI1 41
-#define BCM_IRQ_VC_PIXVLV3 42
-#define BCM_IRQ_VC_SPIBSCSLV 43
-#define BCM_IRQ_VC_DSI1 44
-#define BCM_IRQ_VC_PXLVLV0 45
-#define BCM_IRQ_VC_PXLVLV1N4 46
-#define BCM_IRQ_VC_CPR 47
-#define BCM_IRQ_VC_SMI 48
-#define BCM_IRQ_VC_GPIO0 49
-#define BCM_IRQ_VC_GPIO1 50
-#define BCM_IRQ_VC_GPIO2 51
-#define BCM_IRQ_VC_GPIO3 52
-#define BCM_IRQ_VC_I2C 53
-#define BCM_IRQ_VC_SPI 54
-#define BCM_IRQ_VC_PCMI2S 55
-#define BCM_IRQ_VC_SDHOST 56
-#define BCM_IRQ_VC_PL011UART 57
-#define BCM_IRQ_VC_ETHPCIE 58
-#define BCM_IRQ_VC_VEC 59
-#define BCM_IRQ_VC_CPG 60
-#define BCM_IRQ_VC_RNG 61
-#define BCM_IRQ_VC_EMMC 62
-#define BCM_IRQ_VC_ETHPCIESEC 63
-
-/* TODO: what about PACTL_CS address section 6.2.4? */
-
-/* ETH_PCIe interrupts */
-
-#define BCM_IRQ_ETH_AVS 9
-#define BCM_IRQ_ETH_PCIE0_INTA 15
-#define BCM_IRQ_ETH_PCIE0_INTB 16
-#define BCM_IRQ_ETH_PCIE0_INTC 17
-#define BCM_IRQ_ETH_PCIE0_INTD 18
-#define BCM_IRQ_ETH_PCIE0_MSI 20
-#define BCM_IRQ_ETH_GENET0_A 29
-#define BCM_IRQ_ETH_GENET0_B 30
-#define BCM_IRQ_ETH_USB0_XHCI0 48
-
 /* ARM_LOCAL interrupt register offsets */
 
 #define BCM_IRQ_ARMLOCAL_ARM_CONTROL_OFFSET 0x00
@@ -605,4 +503,29 @@
 #define BCM_IRQ_ARMC_SWIRQ_SET_SW_INT (0xff)
 #define BCM_IRQ_ARMC_SWIRQ_CLEAR_SW_INT (0xff)
 
+/* PACTL_CS register bit definitions */
+
+#define BCM_PACTL_CS_SPI0 (1 << 0)
+#define BCM_PACTL_CS_SPI1 (1 << 1)
+#define BCM_PACTL_CS_SPI2 (1 << 2)
+#define BCM_PACTL_CS_SPI3 (1 << 3)
+#define BCM_PACTL_CS_SPI4 (1 << 4)
+#define BCM_PACTL_CS_SPI5 (1 << 5)
+#define BCM_PACTL_CS_SPI6 (1 << 6)
+
+#define BCM_PACTL_CS_I2C0 (1 << 8)
+#define BCM_PACTL_CS_I2C1 (1 << 9)
+#define BCM_PACTL_CS_I2C2 (1 << 10)
+#define BCM_PACTL_CS_I2C3 (1 << 11)
+#define BCM_PACTL_CS_I2C4 (1 << 12)
+#define BCM_PACTL_CS_I2C5 (1 << 13)
+#define BCM_PACTL_CS_I2C6 (1 << 14)
+#define BCM_PACTL_CS_I2C7 (1 << 15)
+
+#define BCM_PACTL_CS_UART5 (1 << 16)
+#define BCM_PACTL_CS_UART4 (1 << 17)
+#define BCM_PACTL_CS_UART3 (1 << 18)
+#define BCM_PACTL_CS_UART2 (1 << 19)
+#define BCM_PACTL_CS_UART0 (1 << 20)
+
 #endif /* __ARCH_ARM64_SRC_BCM2711_IRQ_H */
diff --git a/arch/arm64/src/bcm2711/hardware/bcm2711_memmap.h 
b/arch/arm64/src/bcm2711/hardware/bcm2711_memmap.h
index 0ee903a609..d1b48e2665 100644
--- a/arch/arm64/src/bcm2711/hardware/bcm2711_memmap.h
+++ b/arch/arm64/src/bcm2711/hardware/bcm2711_memmap.h
@@ -103,6 +103,10 @@
 #define BCM_DMA15_BASE                                                       \
   (BCM_PERIPHERAL_BASEADDR + 0x000e05000) /* DMA Channel 15 */
 
+/* PACTL register address */
+
+#define BCM_PACTL_CS (BCM_PERIPHERAL_BASEADDR + 0x204e00)
+
 /* ARM_LOCAL base address */
 
 #if defined(CONFIG_BCM2711_LOW_PERIPHERAL)
diff --git a/arch/arm64/src/bcm2711/hardware/bcm2711_spi.h 
b/arch/arm64/src/bcm2711/hardware/bcm2711_spi.h
index 6131d1653b..58ac2341cc 100644
--- a/arch/arm64/src/bcm2711/hardware/bcm2711_spi.h
+++ b/arch/arm64/src/bcm2711/hardware/bcm2711_spi.h
@@ -44,40 +44,12 @@
 
 /* SPI register addresses */
 
-#define BCM_SPI0_CS (BCM_SPI0_BASEADDR + BCM_SPI_CS_OFFSET)
-#define BCM_SPI0_FIFO (BCM_SPI0_BASEADDR + BCM_SPI_FIFO_OFFSET)
-#define BCM_SPI0_CLK (BCM_SPI0_BASEADDR + BCM_SPI_CLK_OFFSET)
-#define BCM_SPI0_DLEN (BCM_SPI0_BASEADDR + BCM_SPI_DLEN_OFFSET)
-#define BCM_SPI0_LTOH (BCM_SPI0_BASEADDR + BCM_SPI_LTOH_OFFSET)
-#define BCM_SPI0_DC (BCM_SPI0_BASEADDR + BCM_SPI_DC_OFFSET)
-
-#define BCM_SPI3_CS (BCM_SPI3_BASEADDR + BCM_SPI_CS_OFFSET)
-#define BCM_SPI3_FIFO (BCM_SPI3_BASEADDR + BCM_SPI_FIFO_OFFSET)
-#define BCM_SPI3_CLK (BCM_SPI3_BASEADDR + BCM_SPI_CLK_OFFSET)
-#define BCM_SPI3_DLEN (BCM_SPI3_BASEADDR + BCM_SPI_DLEN_OFFSET)
-#define BCM_SPI3_LTOH (BCM_SPI3_BASEADDR + BCM_SPI_LTOH_OFFSET)
-#define BCM_SPI3_DC (BCM_SPI3_BASEADDR + BCM_SPI_DC_OFFSET)
-
-#define BCM_SPI4_CS (BCM_SPI4_BASEADDR + BCM_SPI_CS_OFFSET)
-#define BCM_SPI4_FIFO (BCM_SPI4_BASEADDR + BCM_SPI_FIFO_OFFSET)
-#define BCM_SPI4_CLK (BCM_SPI4_BASEADDR + BCM_SPI_CLK_OFFSET)
-#define BCM_SPI4_DLEN (BCM_SPI4_BASEADDR + BCM_SPI_DLEN_OFFSET)
-#define BCM_SPI4_LTOH (BCM_SPI4_BASEADDR + BCM_SPI_LTOH_OFFSET)
-#define BCM_SPI4_DC (BCM_SPI4_BASEADDR + BCM_SPI_DC_OFFSET)
-
-#define BCM_SPI5_CS (BCM_SPI5_BASEADDR + BCM_SPI_CS_OFFSET)
-#define BCM_SPI5_FIFO (BCM_SPI5_BASEADDR + BCM_SPI_FIFO_OFFSET)
-#define BCM_SPI5_CLK (BCM_SPI5_BASEADDR + BCM_SPI_CLK_OFFSET)
-#define BCM_SPI5_DLEN (BCM_SPI5_BASEADDR + BCM_SPI_DLEN_OFFSET)
-#define BCM_SPI5_LTOH (BCM_SPI5_BASEADDR + BCM_SPI_LTOH_OFFSET)
-#define BCM_SPI5_DC (BCM_SPI5_BASEADDR + BCM_SPI_DC_OFFSET)
-
-#define BCM_SPI6_CS (BCM_SPI6_BASEADDR + BCM_SPI_CS_OFFSET)
-#define BCM_SPI6_FIFO (BCM_SPI6_BASEADDR + BCM_SPI_FIFO_OFFSET)
-#define BCM_SPI6_CLK (BCM_SPI6_BASEADDR + BCM_SPI_CLK_OFFSET)
-#define BCM_SPI6_DLEN (BCM_SPI6_BASEADDR + BCM_SPI_DLEN_OFFSET)
-#define BCM_SPI6_LTOH (BCM_SPI6_BASEADDR + BCM_SPI_LTOH_OFFSET)
-#define BCM_SPI6_DC (BCM_SPI6_BASEADDR + BCM_SPI_DC_OFFSET)
+#define BCM_SPI_CS(base)   ((base) + BCM_SPI_CS_OFFSET)
+#define BCM_SPI_FIFO(base) ((base) + BCM_SPI_FIFO_OFFSET)
+#define BCM_SPI_CLK(base)  ((base) + BCM_SPI_CLK_OFFSET)
+#define BCM_SPI_DLEN(base) ((base) + BCM_SPI_DLEN_OFFSET)
+#define BCM_SPI_LTOH(base) ((base) + BCM_SPI_LTOH_OFFSET)
+#define BCM_SPI_DC(base)   ((base) + BCM_SPI_DC_OFFSET)
 
 /* SPI register bit definitions */
 
@@ -123,4 +95,8 @@
 #define BCM_SPI_DC_TPANIC (0xff << 8)
 #define BCM_SPI_DC_TDREQ (0xff << 0)
 
+/* Informational constants */
+
+#define BCM_SPI_FIFO_DEPTH 16
+
 #endif /* __ARCH_ARM64_SRC_BCM2711_SPI_H */

Reply via email to