You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by da...@apache.org on 2020/05/28 12:14:49 UTC

[incubator-nuttx] branch master updated (102c4c2 -> 48c88f2)

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

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


    from 102c4c2  tools/testbuild.sh: Call makefunc with JOPTION directly
     new 8d3c9a8  arch/arm/src/stm32h7/stm32_spi.h: Split long lines
     new e030047  update to SPI slave intefaces
     new b2a9a8c  arch/arm/src/samv7/sam_spi_slave.c: Change for modified spi slave interface
     new 48c88f2  arch/arm/src/stm32h7: Add the spi slave bus control driver

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 arch/arm/src/samv7/sam_spi_slave.c     |   23 +-
 arch/arm/src/stm32h7/Make.defs         |    4 +
 arch/arm/src/stm32h7/stm32_spi.h       |  104 +-
 arch/arm/src/stm32h7/stm32_spi_slave.c | 1806 ++++++++++++++++++++++++++++++++
 include/nuttx/spi/slave.h              |   86 +-
 5 files changed, 1956 insertions(+), 67 deletions(-)
 create mode 100644 arch/arm/src/stm32h7/stm32_spi_slave.c


[incubator-nuttx] 02/04: update to SPI slave intefaces

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit e030047f4598162543accbe8b048415fcb088037
Author: Jukka Laitinen <ju...@intel.com>
AuthorDate: Fri Sep 20 09:17:10 2019 +0300

    update to SPI slave intefaces
    
    Make it possible to enqueue and receive full buffers of data with
    single call, to avoid call overhead when sending / receiving large amounts
    of data.
    
    Also make it possible for the slave device to leave received data in the
    controller receive buffers and retrieve it from there by polling
    
    Signed-off-by: Jukka Laitinen <ju...@intel.com>
---
 include/nuttx/spi/slave.h | 86 ++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 67 insertions(+), 19 deletions(-)

diff --git a/include/nuttx/spi/slave.h b/include/nuttx/spi/slave.h
index a979d22..166e4f9 100644
--- a/include/nuttx/spi/slave.h
+++ b/include/nuttx/spi/slave.h
@@ -49,7 +49,9 @@
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
+
 /* Configuration ************************************************************/
+
 /* CONFIG_SPI_SLAVE - Enable support for SPI slave features
  * CONFIG_SPI_SLAVE_DMA - Enable support for DMA data transfers (not
  *   implemented in initial version).
@@ -109,18 +111,21 @@
  *
  * Input Parameters:
  *   sctrlr - SPI slave controller interface instance
- *   data   - Command/data mode data value to be shifted out.  The width of
- *            the data must be the same as the nbits parameter previously
- *            provided to the bind() methods.
+ *   data   - Pointer to the command/data mode data to be shifted out.
+ *            The data width must be aligned to the nbits parameter which was
+ *            previously provided to the bind() methods.
+ *   len    - Number of units of "nbits" wide to enqueue,
+ *            "nbits" being the data width given in "bind"
  *
  * Returned Value:
- *   Zero if the word was successfully queue; A negated errno valid is
- *   returned on any failure to enqueue the word (such as if the queue is
- *   full).
+ *   Number of data items successfully queued, or a negated errno:
+ *          - "len" if all the data was successfully queued
+ *          - "0..len-1" if queue is full
+ *          - "-errno" in any other error
  *
  ****************************************************************************/
 
-#define SPI_SCTRLR_ENQUEUE(c,v)  ((c)->ops->enqueue(c,v))
+#define SPI_SCTRLR_ENQUEUE(c,v,l)  ((c)->ops->enqueue(c,v,l))
 
 /****************************************************************************
  * Name: SPI_SCTRLR_QFULL
@@ -158,6 +163,43 @@
 #define SPI_SCTRLR_QFLUSH(c)  ((c)->ops->qflush(c))
 
 /****************************************************************************
+ * Name: SPI_SCTRLR_QPOLL
+ *
+ * Description:
+ *   Tell the controller to output all the receive queue data.
+ *
+ *   This will cause 1..n SPI_SDEV_RECEIVE calls back to the slave device,
+ *   offering blocks of data to the device. From each call, the slave device
+ *   driver will return the number of data units it accepted/read out.
+ *
+ *   The poll will return when:
+ *   1. slave device returns that it received less data than what was
+ *      offered to it
+ *   OR
+ *   2. all the buffered data has been offered to the slave device
+ *
+ *   If the slave device wants the poll to return and leave data into the
+ *   controller driver's queue, it shall return any number less than what was
+ *   offered. The controller driver will discard the amount of data that the
+ *   slave device accepted. The data left to the buffers will be offered
+ *   again in the next qpoll.
+ *
+ *   If the slave device wants the poll to return and let the controller
+ *   driver throw away the buffered data it shall just return the same number
+ *   of bytes that was offered to each receive call.
+ *
+ * Input Parameters:
+ *   sctrlr - SPI slave controller interface instance
+ *
+ * Returned Value:
+ *   Number of units of width "nbits" left in the rx queue. If the device
+ *   accepted all the data, the return value will be 0
+ *
+ ****************************************************************************/
+
+#define SPI_SCTRLR_QPOLL(c)  ((c)->ops->qpoll(c))
+
+/****************************************************************************
  * Name: SPI_SDEV_SELECT
  *
  * Description:
@@ -222,9 +264,11 @@
  *
  * Input Parameters:
  *   sdev - SPI device interface instance
+ *   data - Pointer to the data buffer pointer to be shifed out.
+ *          The device will set the data buffer pointer to the actual data
  *
  * Returned Value:
- *   The next data value to be shifted out
+ *   The number of data bytes to be shifted out from the data buffer
  *
  * Assumptions:
  *   May be called from an interrupt handler and the response is usually
@@ -232,7 +276,7 @@
  *
  ****************************************************************************/
 
-#define SPI_SDEV_GETDATA(d)  ((d)->ops->getdata(d))
+#define SPI_SDEV_GETDATA(d,v)  ((d)->ops->getdata(d,v))
 
 /****************************************************************************
  * Name: SPI_SDEV_RECEIVE
@@ -245,10 +289,13 @@
  *
  * Input Parameters:
  *   sdev - SPI device interface instance
- *   data - The last command/data value that was shifted in
+ *   data - Pointer to the new data that has been shifted in
+ *   len  - Length of the new data in units of nbits wide,
+ *          nbits being the data width given in "bind"
  *
  * Returned Value:
- *   None
+ *   Number of units accepted by the device. In other words,
+ *   number of units to be removed from controller's receive queue.
  *
  * Assumptions:
  *   May be called from an interrupt handler and in time-critical
@@ -258,11 +305,12 @@
  *
  ****************************************************************************/
 
-#define SPI_SDEV_RECEIVE(d,v)  ((d)->ops->receive(d,v))
+#define SPI_SDEV_RECEIVE(d,v,l)  ((d)->ops->receive(d,v,l))
 
 /****************************************************************************
  * Public Types
  ****************************************************************************/
+
 /* There are two interfaces defined for the implementation of SPI slave:
  *
  * 1) struct spi_sctrlr_s:   Defines one interface between the SPI
@@ -451,9 +499,11 @@ struct spi_sctrlrops_s
                    FAR struct spi_sdev_s *sdev, enum spi_smode_e mode,
                    int nbits);
   CODE void     (*unbind)(FAR struct spi_sctrlr_s *sctrlr);
-  CODE int      (*enqueue)(FAR struct spi_sctrlr_s *sctrlr, uint16_t data);
+  CODE int      (*enqueue)(FAR struct spi_sctrlr_s *sctrlr,
+                   FAR const void *data, size_t nwords);
   CODE bool     (*qfull)(FAR struct spi_sctrlr_s *sctrlr);
   CODE void     (*qflush)(FAR struct spi_sctrlr_s *sctrlr);
+  CODE size_t   (*qpoll)(FAR struct spi_sctrlr_s *sctrlr);
 };
 
 /* SPI slave controller private data.  This structure only defines the
@@ -475,8 +525,10 @@ struct spi_sdevops_s
 {
   CODE void     (*select)(FAR struct spi_sdev_s *sdev, bool selected);
   CODE void     (*cmddata)(FAR struct spi_sdev_s *sdev, bool data);
-  CODE uint16_t (*getdata)(FAR struct spi_sdev_s *sdev);
-  CODE void     (*receive)(FAR struct spi_sdev_s *sdev, uint16_t cmd);
+  CODE size_t   (*getdata)(FAR struct spi_sdev_s *sdev,
+                           FAR const void **data);
+  CODE size_t   (*receive)(FAR struct spi_sdev_s *sdev,
+                           FAR const void *data, size_t nwords);
 };
 
 /* SPI slave device private data.  This structure only defines the initial
@@ -505,10 +557,6 @@ extern "C"
 #define EXTERN extern
 #endif
 
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
 #undef EXTERN
 #if defined(__cplusplus)
 }


[incubator-nuttx] 01/04: arch/arm/src/stm32h7/stm32_spi.h: Split long lines

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 8d3c9a8773a7da61f40bb83c225e1e6d665a1986
Author: Jukka Laitinen <ju...@intel.com>
AuthorDate: Mon May 25 12:13:54 2020 +0300

    arch/arm/src/stm32h7/stm32_spi.h: Split long lines
    
    Signed-off-by: Jukka Laitinen <ju...@intel.com>
---
 arch/arm/src/stm32h7/stm32_spi.h | 88 ++++++++++++++++++++++------------------
 1 file changed, 48 insertions(+), 40 deletions(-)

diff --git a/arch/arm/src/stm32h7/stm32_spi.h b/arch/arm/src/stm32h7/stm32_spi.h
index 7db865a..3e4228c 100644
--- a/arch/arm/src/stm32h7/stm32_spi.h
+++ b/arch/arm/src/stm32h7/stm32_spi.h
@@ -1,4 +1,4 @@
-/************************************************************************************
+/*****************************************************************************
  * arch/arm/src/stm32h7/stm32_spi.h
  *
  *   Copyright (C) 2018 Gregory Nutt. All rights reserved.
@@ -33,14 +33,14 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 #ifndef __ARCH_ARM_SRC_STM32H7_STM32_SPI_H
 #define __ARCH_ARM_SRC_STM32H7_STM32_SPI_H
 
-/************************************************************************************
+/*****************************************************************************
  * Included Files
- ************************************************************************************/
+ *****************************************************************************/
 
 #include <nuttx/config.h>
 
@@ -49,10 +49,6 @@
 #include "chip.h"
 #include "hardware/stm32_spi.h"
 
-/************************************************************************************
- * Public Functions
- ************************************************************************************/
-
 #ifndef __ASSEMBLY__
 
 #undef EXTERN
@@ -66,7 +62,11 @@ extern "C"
 
 struct spi_dev_s; /* Forward reference */
 
-/************************************************************************************
+/*****************************************************************************
+ * Public Function Prototypes
+ *****************************************************************************/
+
+/*****************************************************************************
  * Name: stm32_spibus_initialize
  *
  * Description:
@@ -78,84 +78,92 @@ struct spi_dev_s; /* Forward reference */
  * Returned Value:
  *   Valid SPI device structure reference on success; a NULL on failure
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 FAR struct spi_dev_s *stm32_spibus_initialize(int bus);
 
-/************************************************************************************
+/*****************************************************************************
  * Name:  stm32_spi1/2/...select and stm32_spi1/2/...status
  *
  * Description:
- *   The external functions, stm32_spi1/2/...select, stm32_spi1/2/...status, and
- *   stm32_spi1/2/...cmddata must be provided by board-specific logic.  These are
- *   implementations of the select, status, and cmddata methods of the SPI interface
- *   defined by struct spi_ops_s (see include/nuttx/spi/spi.h). All other methods
- *   (including stm32_spibus_initialize()) are provided by common STM32 logic.  To use this
- *   common SPI logic on your board:
+ *   The external functions, stm32_spi1/2/...select, stm32_spi1/2/...status,
+ *   and stm32_spi1/2/...cmddata must be provided by board-specific logic.
+ *   These are implementations of the select, status, and cmddata methods of
+ *   the SPI interface defined by struct spi_ops_s (see
+ *   include/nuttx/spi/spi.h).
+ *   All other methods (including stm32_spibus_initialize()) are provided by
+ *   common STM32 logic.  To use this common SPI logic on your board:
  *
  *   1. Provide logic in stm32_boardinitialize() to configure SPI chip select
  *      pins.
- *   2. Provide stm32_spi1/2/...select() and stm32_spi1/2/...status() functions in your
- *      board-specific logic.  These functions will perform chip selection and
- *      status operations using GPIOs in the way your board is configured.
- *   3. If CONFIG_SPI_CMDDATA is defined in your NuttX configuration file, then
- *      provide stm32_spi1/2/...cmddata() functions in your board-specific logic.
- *      These functions will perform cmd/data selection operations using GPIOs in the
- *      way your board is configured.
+ *   2. Provide stm32_spi1/2/...select() and stm32_spi1/2/...status()
+ *      functions in your board-specific logic.  These functions will perform
+ *      chip selection and status operations using GPIOs in the way your board
+ *      is configured.
+ *   3. If CONFIG_SPI_CMDDATA is defined in your NuttX configuration file,
+ *      then provide stm32_spi1/2/...cmddata() functions in your board-
+ *      specific logic. These functions will perform cmd/data selection
+ *      operations using GPIOs in the way your board is configured.
  *   4. Add a calls to stm32_spibus_initialize() in your low level application
  *      initialization logic
- *   5. The handle returned by stm32_spibus_initialize() may then be used to bind the
- *      SPI driver to higher level logic (e.g., calling
+ *   5. The handle returned by stm32_spibus_initialize() may then be used to
+ *      bind the SPI driver to higher level logic (e.g., calling
  *      mmcsd_spislotinitialize(), for example, will bind the SPI driver to
  *      the SPI MMC/SD driver).
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 #ifdef CONFIG_STM32H7_SPI1
-void stm32_spi1select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+void stm32_spi1select(FAR struct spi_dev_s *dev, uint32_t devid,
+                      bool selected);
 uint8_t stm32_spi1status(FAR struct spi_dev_s *dev, uint32_t devid);
 int stm32_spi1cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
 #endif
 
 #ifdef CONFIG_STM32H7_SPI2
-void stm32_spi2select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+void stm32_spi2select(FAR struct spi_dev_s *dev, uint32_t devid,
+                      bool selected);
 uint8_t stm32_spi2status(FAR struct spi_dev_s *dev, uint32_t devid);
 int stm32_spi2cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
 #endif
 
 #ifdef CONFIG_STM32H7_SPI3
-void stm32_spi3select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+void stm32_spi3select(FAR struct spi_dev_s *dev, uint32_t devid,
+                      bool selected);
 uint8_t stm32_spi3status(FAR struct spi_dev_s *dev, uint32_t devid);
 int stm32_spi3cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
 #endif
 
 #ifdef CONFIG_STM32H7_SPI4
-void stm32_spi4select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+  void stm32_spi4select(FAR struct spi_dev_s *dev, uint32_t devid,
+                        bool selected);
 uint8_t stm32_spi4status(FAR struct spi_dev_s *dev, uint32_t devid);
 int stm32_spi4cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
 #endif
 
 #ifdef CONFIG_STM32H7_SPI5
-void stm32_spi5select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+void stm32_spi5select(FAR struct spi_dev_s *dev, uint32_t devid,
+                      bool selected);
 uint8_t stm32_spi5status(FAR struct spi_dev_s *dev, uint32_t devid);
 int stm32_spi5cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
 #endif
 
 #ifdef CONFIG_STM32H7_SPI6
-void stm32_spi6select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+void stm32_spi6select(FAR struct spi_dev_s *dev, uint32_t devid,
+                      bool selected);
 uint8_t stm32_spi6status(FAR struct spi_dev_s *dev, uint32_t devid);
 int stm32_spi6cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
 #endif
 
-/************************************************************************************
+/*****************************************************************************
  * Name: stm32_spi1/2/...register
  *
  * Description:
- *   If the board supports a card detect callback to inform the SPI-based MMC/SD
- *   driver when an SD card is inserted or removed, then CONFIG_SPI_CALLBACK should
- *   be defined and the following function(s) must be implemented.  These functions
- *   implements the registercallback method of the SPI interface (see
- *   include/nuttx/spi/spi.h for details)
+ *   If the board supports a card detect callback to inform the SPI-based
+ *   MMC/SD driver when an SD card is inserted or removed, then
+ *   CONFIG_SPI_CALLBACK should be defined and the following function(s) must
+ *   be implemented.  These functions implements the registercallback method
+ *   of the SPI interface (see include/nuttx/spi/spi.h for details)
  *
  * Input Parameters:
  *   dev -      Device-specific state data
@@ -165,7 +173,7 @@ int stm32_spi6cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
  * Returned Value:
  *   0 on success; negated errno on failure.
  *
- ****************************************************************************/
+ *****************************************************************************/
 
 #ifdef CONFIG_SPI_CALLBACK
 #ifdef CONFIG_STM32H7_SPI1


[incubator-nuttx] 04/04: arch/arm/src/stm32h7: Add the spi slave bus control driver

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 48c88f2af36c235262eb74a3e1810dd1ab75cebe
Author: Jukka Laitinen <ju...@intel.com>
AuthorDate: Thu Sep 12 12:29:11 2019 +0300

    arch/arm/src/stm32h7: Add the spi slave bus control driver
    
    This is a work in progress, and now only serves as
    DMA enabled simplex RX-only mode bus controller
    
    Signed-off-by: Jukka Laitinen <ju...@intel.com>
---
 arch/arm/src/stm32h7/Make.defs         |    4 +
 arch/arm/src/stm32h7/stm32_spi.h       |   16 +
 arch/arm/src/stm32h7/stm32_spi_slave.c | 1806 ++++++++++++++++++++++++++++++++
 3 files changed, 1826 insertions(+)

diff --git a/arch/arm/src/stm32h7/Make.defs b/arch/arm/src/stm32h7/Make.defs
index 44fe8dc..8cbc15b 100644
--- a/arch/arm/src/stm32h7/Make.defs
+++ b/arch/arm/src/stm32h7/Make.defs
@@ -180,6 +180,10 @@ ifeq ($(CONFIG_STM32H7_SPI),y)
 CHIP_CSRCS += stm32_spi.c
 endif
 
+ifeq ($(CONFIG_SPI_SLAVE),y)
+CHIP_CSRCS += stm32_spi_slave.c
+endif
+
 ifeq ($(CONFIG_STM32H7_SDMMC),y)
 CHIP_CSRCS += stm32_sdmmc.c
 endif
diff --git a/arch/arm/src/stm32h7/stm32_spi.h b/arch/arm/src/stm32h7/stm32_spi.h
index 3e4228c..d59a93b 100644
--- a/arch/arm/src/stm32h7/stm32_spi.h
+++ b/arch/arm/src/stm32h7/stm32_spi.h
@@ -83,6 +83,22 @@ struct spi_dev_s; /* Forward reference */
 FAR struct spi_dev_s *stm32_spibus_initialize(int bus);
 
 /*****************************************************************************
+ * Name: stm32_spi_slave_initialize
+ *
+ * Description:
+ *   Initialize the selected SPI bus for slave operation
+ *
+ * Input Parameters:
+ *   bus number
+ *
+ * Returned Value:
+ *   Valid SPI device structure reference on succcess; a NULL on failure
+ *
+ *****************************************************************************/
+
+FAR struct spi_sctrlr_s *stm32_spi_slave_initialize(int bus);
+
+/*****************************************************************************
  * Name:  stm32_spi1/2/...select and stm32_spi1/2/...status
  *
  * Description:
diff --git a/arch/arm/src/stm32h7/stm32_spi_slave.c b/arch/arm/src/stm32h7/stm32_spi_slave.c
new file mode 100644
index 0000000..e2e6025
--- /dev/null
+++ b/arch/arm/src/stm32h7/stm32_spi_slave.c
@@ -0,0 +1,1806 @@
+/*****************************************************************************
+ * arch/arm/src/stm32h7/stm32_spi_slave.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Included Files
+ *****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <debug.h>
+#include <string.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/spi/spi.h>
+#include <nuttx/spi/slave.h>
+#include <nuttx/power/pm.h>
+
+#include <arch/board/board.h>
+
+#include "arm_internal.h"
+#include "arm_arch.h"
+
+#include "chip.h"
+#include "stm32_rcc.h"
+#include "stm32_gpio.h"
+#include "stm32_spi.h"
+#include "stm32_dma.h"
+
+#if defined(CONFIG_STM32H7_SPI1_SLAVE) ||                               \
+  defined(CONFIG_STM32H7_SPI2_SLAVE) ||                                 \
+  defined(CONFIG_STM32H7_SPI3_SLAVE) ||                                 \
+  defined(CONFIG_STM32H7_SPI4_SLAVE) ||                                 \
+  defined(CONFIG_STM32H7_SPI5_SLAVE) ||                                 \
+  defined(CONFIG_STM32H7_SPI6_SLAVE)
+
+/*****************************************************************************
+ * Pre-processor Definitions
+ *****************************************************************************/
+
+/* Configuration *************************************************************/
+
+/* SPI interrupts */
+
+#ifdef CONFIG_STM32H7_SPI_INTERRUPTS
+#  error "Interrupt driven SPI not yet supported"
+#endif
+
+/* Can't have both interrupt driven SPI and SPI DMA */
+
+#if defined(CONFIG_STM32H7_SPI_INTERRUPTS) && defined(CONFIG_STM32H7_SPI_DMA)
+#  error "Cannot enable both interrupt mode and DMA mode for SPI"
+#endif
+
+/* SPI DMA priority */
+
+#ifdef CONFIG_STM32H7_SPI_DMA
+
+#  if defined(CONFIG_SPI_DMAPRIO)
+#    define SPI_DMA_PRIO  CONFIG_SPI_DMAPRIO
+#  elif defined(DMA_SCR_PRIMED)
+#    define SPI_DMA_PRIO  DMA_SCR_PRILO
+#  else
+#    error "Unknown STM32 DMA"
+#  endif
+
+#  if (SPI_DMA_PRIO & ~DMA_SCR_PL_MASK) != 0
+#    error "Illegal value for CONFIG_SPI_DMAPRIO"
+#  endif
+
+/* DMA channel configuration */
+
+#  define SPI_RXDMA16_CONFIG        (SPI_DMA_PRIO | DMA_SCR_MSIZE_16BITS | \
+                                     DMA_SCR_PSIZE_16BITS | DMA_SCR_MINC | \
+                                     DMA_SCR_DIR_P2M | DMA_SCR_CIRC)
+#  define SPI_RXDMA8_CONFIG         (SPI_DMA_PRIO | DMA_SCR_MSIZE_8BITS | \
+                                     DMA_SCR_PSIZE_8BITS | DMA_SCR_MINC| \
+                                     DMA_SCR_DIR_P2M | DMA_SCR_CIRC)
+#  define SPI_TXDMA16_CONFIG        (SPI_DMA_PRIO | DMA_SCR_MSIZE_16BITS| \
+                                     DMA_SCR_PSIZE_16BITS | DMA_SCR_MINC| \
+                                     DMA_SCR_DIR_M2P)
+#  define SPI_TXDMA8_CONFIG         (SPI_DMA_PRIO | DMA_SCR_MSIZE_8BITS|  \
+                                     DMA_SCR_PSIZE_8BITS | DMA_SCR_MINC|DMA_SCR_DIR_M2P)
+#endif
+
+/* Kernel clock configuration
+ * TODO:
+ *  - support for all kernel clock configuration
+ */
+
+#if defined(CONFIG_STM32H7_SPI1_SLAVE) || defined(CONFIG_STM32H7_SPI2_SLAVE) || \
+  defined(CONFIG_STM32H7_SPI3_SLAVE)
+#  if STM32_RCC_D2CCIP1R_SPI123SRC == RCC_D2CCIP1R_SPI123SEL_PLL1
+#    define SPI123_KERNEL_CLOCK_FREQ STM32_PLL1Q_FREQUENCY
+#  else
+#    error Not supported yet
+#  endif
+#  if SPI123_KERNEL_CLOCK_FREQ > 200000000
+#    error Not supported SPI123 frequency
+#  endif
+#endif  /* SPI123 */
+
+#if defined(CONFIG_STM32H7_SPI4_SLAVE) || defined(CONFIG_STM32H7_SPI5_SLAVE)
+#  if STM32_RCC_D2CCIP1R_SPI45SRC == RCC_D2CCIP1R_SPI45SEL_APB
+#    define SPI45_KERNEL_CLOCK_FREQ STM32_PCLK2_FREQUENCY
+#  else
+#    error Not supported yet
+#  endif
+#  if SPI45_KERNEL_CLOCK_FREQ > 100000000
+#    error Not supported SPI45 frequency
+#  endif
+#endif  /* SPI45 */
+
+#if defined(CONFIG_STM32H7_SPI6_SLAVE)
+#  if STM32_RCC_D3CCIPR_SPI6SRC == RCC_D3CCIPR_SPI6SEL_PCLK4
+#    define SPI6_KERNEL_CLOCK_FREQ STM32_PCLK4_FREQUENCY
+#  else
+#    error Not supported yet
+#  endif
+#  if SPI6_KERNEL_CLOCK_FREQ > 100000000
+#    error Not supported SPI6 frequency
+#  endif
+#endif  /* SPI6 */
+
+#if defined (CONFIG_STM32H7_SPI_SLAVE_QSIZE)
+#  if CONFIG_STM32H7_SPI_SLAVE_QSIZE > 65535
+#    error CONFIG_STM32H7_SPI_SLAVE_QSIZE too large
+#  endif
+#endif
+
+/* SPI6 is in D3 domain and is not yet supported. Remove this when the proper
+ * support is in place
+ */
+
+#if defined (CONFIG_STM32H7_SPI6_SLAVE)
+#    error SPI6 slave not supported yet
+#endif
+
+#define DMA_BUFFER_MASK    (ARMV7M_DCACHE_LINESIZE - 1)
+#define DMA_ALIGN_UP(n)    (((n) + DMA_BUFFER_MASK) & ~DMA_BUFFER_MASK)
+#define DMA_ALIGN_DOWN(n)  ((n) & ~DMA_BUFFER_MASK)
+
+/*****************************************************************************
+ * Private Types
+ *****************************************************************************/
+
+enum spi_config_e
+{
+  FULL_DUPLEX = 0,
+  SIMPLEX_TX,
+  SIMPLEX_RX,
+  HALF_DUPLEX
+};
+
+struct stm32_spidev_s
+{
+  struct spi_sctrlr_s sctrlr;    /* Externally visible part of the
+                                  * SPI slave interface */
+  struct spi_sdev_s *sdev;       /* Bound SPI slave device interface */
+  uint32_t         spibase;      /* SPIn base address */
+  uint32_t         spiclock;     /* Clocking for the SPI module */
+  uint8_t          irq;          /* SPI IRQ number */
+  uint32_t         nss_pin;      /* Chip select pin configuration */
+#ifdef CONFIG_STM32H7_SPI_DMA
+  volatile uint8_t rxresult;     /* Result of the RX DMA */
+  volatile uint8_t txresult;     /* Result of the TX DMA */
+  uint32_t         rxch;         /* The RX DMA channel number */
+  uint32_t         txch;         /* The TX DMA channel number */
+  DMA_HANDLE       rxdma;        /* DMA channel handle for RX transfers */
+  DMA_HANDLE       txdma;        /* DMA channel handle for TX transfers */
+  sem_t            rxsem;        /* Wait for RX DMA to complete */
+  sem_t            txsem;        /* Wait for TX DMA to complete */
+  uint32_t         txccr;        /* DMA control register for TX transfers */
+  uint32_t         rxccr;        /* DMA control register for RX transfers */
+  bool             dmarunning;   /* DMA is started */
+#endif
+  bool             initialized;  /* Has SPI interface been initialized */
+  sem_t            exclsem;      /* Held while chip is selected for mutual
+                                  * exclusion */
+  int8_t           nbits;        /* Width of word in bits */
+  uint8_t          mode;         /* Mode 0,1,2,3 */
+  uint8_t          bus;          /* SPI bus number */
+  bool             nss;          /* True: Chip selected */
+#ifdef CONFIG_PM
+  struct pm_callback_s pm_cb;    /* PM callbacks */
+#endif
+  enum spi_config_e config;      /* full/half duplex, simplex rx/tx */
+
+  /* Output queue */
+
+  uint16_t ohead;                 /* Location of next value in out queue */
+  uint16_t otail;                 /* Index of first value in out queue */
+  uint8_t *outq;
+
+  /* Input queue */
+
+  uint16_t ihead;                 /* Location of next unread value */
+#ifndef CONFIG_STM32H7_SPI_DMA
+  uint16_t itail;                 /* Index of next free memory pointer */
+#endif
+  uint8_t *inq;
+};
+
+/*****************************************************************************
+ * Private Function Prototypes
+ *****************************************************************************/
+
+/* Helpers */
+
+static inline uint32_t spi_getreg(FAR struct stm32_spidev_s *priv,
+                                  uint32_t offset);
+static inline void spi_putreg(FAR struct stm32_spidev_s *priv,
+                              uint32_t offset, uint32_t value);
+static inline void spi_modifyreg(FAR struct stm32_spidev_s *priv,
+                                 uint32_t offset, uint32_t clrbits,
+                                 uint32_t setbits);
+static inline uint32_t spi_readword(FAR struct stm32_spidev_s *priv);
+static inline void spi_writeword(FAR struct stm32_spidev_s *priv,
+                                 uint32_t byte);
+static inline bool spi_9to16bitmode(FAR struct stm32_spidev_s *priv);
+#ifdef CONFIG_DEBUG_SPI_INFO
+static inline void spi_dumpregs(FAR struct stm32_spidev_s *priv);
+#endif
+
+/* DMA support */
+
+#ifdef CONFIG_STM32H7_SPI_DMA
+static void        spi_dmarxcallback(DMA_HANDLE handle, uint8_t isr,
+                                     void *arg);
+static void        spi_dmatxcallback(DMA_HANDLE handle, uint8_t isr,
+                                     void *arg);
+static void        spi_dmarxsetup(FAR struct stm32_spidev_s *priv,
+                                  size_t nwords);
+static void        spi_dmatxsetup(FAR struct stm32_spidev_s *priv,
+                                  size_t nwords);
+static inline void spi_dmarxstart(FAR struct stm32_spidev_s *priv);
+static inline void spi_dmatxstart(FAR struct stm32_spidev_s *priv);
+#endif
+
+/* Interrupt handler detecting nss status changes */
+
+static int  spi_nssinterrupt(int irq, void *context, void *arg);
+
+/* SPI slave methods */
+
+static void     spi_bind(struct spi_sctrlr_s *sctrlr,
+                  struct spi_sdev_s *sdev, enum spi_smode_e mode,
+                  int nbits);
+static void     spi_unbind(struct spi_sctrlr_s *sctrlr);
+static int      spi_enqueue(struct spi_sctrlr_s *sctrlr,
+                            FAR const void *data,
+                            size_t len);
+static bool     spi_qfull(struct spi_sctrlr_s *sctrlr);
+static void     spi_qflush(struct spi_sctrlr_s *sctrlr);
+static size_t   spi_qpoll(struct spi_sctrlr_s *sctrlr);
+
+/* Initialization */
+
+static void     spi_slave_initialize(FAR struct stm32_spidev_s *priv);
+
+/* PM interface */
+
+#ifdef CONFIG_PM
+static int         spi_pm_prepare(FAR struct pm_callback_s *cb, int domain,
+                                  enum pm_state_e pmstate);
+#endif
+
+/*****************************************************************************
+ * Private Data
+ *****************************************************************************/
+
+/* SPI slave controller driver operations */
+
+static const struct spi_sctrlrops_s g_sctrlr_ops =
+{
+  .bind              = spi_bind,
+  .unbind            = spi_unbind,
+  .enqueue           = spi_enqueue,
+  .qfull             = spi_qfull,
+  .qflush            = spi_qflush,
+  .qpoll             = spi_qpoll,
+};
+
+#define SPI_SLAVE_OUTQ(x) spi##x##_outq
+#define SPI_SLAVE_INQ(x) spi##x##_inq
+
+#ifdef CONFIG_STM32H7_SPI_DMA
+#define SPI_SLAVE_INIT_DMA(x)                           \
+  .rxch          = DMAMAP_SPI##x##_RX,                  \
+  .txch          = DMAMAP_SPI##x##_TX,                  \
+  .outq	         = SPI_SLAVE_OUTQ(x),                   \
+  .inq	         = SPI_SLAVE_INQ(x),
+#else
+#define SPI_SLAVE_INIT_DMA(x)
+#endif
+
+#ifdef CONFIG_PM
+#define SPI_SLAVE_INIT_PM_PREPARE .pm_cb.prepare = spi_pm_prepare,
+#else
+#define SPI_SLAVE_INIT_PM_PREPARE
+#endif
+
+#define SPI_SLAVE_INIT(x)                               \
+{                                                       \
+  .sctrlr.ops    = &g_sctrlr_ops,                       \
+  .sdev          = NULL,                                \
+  .spibase       = STM32_SPI##x##_BASE,                 \
+  .spiclock      = SPI45_KERNEL_CLOCK_FREQ,             \
+  .irq           = STM32_IRQ_SPI##x,                    \
+  SPI_SLAVE_INIT_DMA(x)                                 \
+  .initialized   = false,                               \
+  SPI_SLAVE_INIT_PM_PREPARE                             \
+  .config        = CONFIG_STM32H7_SPI##x##_COMMTYPE,    \
+}
+
+#ifdef CONFIG_STM32H7_SPI1_SLAVE
+
+static uint8_t SPI_SLAVE_OUTQ(1)[DMA_ALIGN_UP(CONFIG_STM32H7_SPI_SLAVE_QSIZE)]
+__attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+static uint8_t SPI_SLAVE_INQ(1)[DMA_ALIGN_UP(CONFIG_STM32H7_SPI_SLAVE_QSIZE)]
+__attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+static struct stm32_spidev_s g_spi1sctrlr = SPI_SLAVE_INIT(1);
+
+#endif
+
+#ifdef CONFIG_STM32H7_SPI2_SLAVE
+
+static uint8_t SPI_SLAVE_OUTQ(2)[DMA_ALIGN_UP(CONFIG_STM32H7_SPI_SLAVE_QSIZE)]
+__attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+static uint8_t SPI_SLAVE_INQ(2)[DMA_ALIGN_UP(CONFIG_STM32H7_SPI_SLAVE_QSIZE)]
+__attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+static struct stm32_spidev_s g_spi2sctrlr = SPI_SLAVE_INIT(2);
+
+#endif
+
+#ifdef CONFIG_STM32H7_SPI3_SLAVE
+
+static uint8_t SPI_SLAVE_OUTQ(3)[DMA_ALIGN_UP(CONFIG_STM32H7_SPI_SLAVE_QSIZE)]
+__attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+static uint8_t SPI_SLAVE_INQ(3)[DMA_ALIGN_UP(CONFIG_STM32H7_SPI_SLAVE_QSIZE)]
+__attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+static struct stm32_spidev_s g_spi3sctrlr = SPI_SLAVE_INIT(3);
+
+#endif
+
+#ifdef CONFIG_STM32H7_SPI4_SLAVE
+
+static uint8_t SPI_SLAVE_OUTQ(4)[DMA_ALIGN_UP(CONFIG_STM32H7_SPI_SLAVE_QSIZE)]
+__attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+static uint8_t SPI_SLAVE_INQ(4)[DMA_ALIGN_UP(CONFIG_STM32H7_SPI_SLAVE_QSIZE)]
+__attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+static struct stm32_spidev_s g_spi4sctrlr = SPI_SLAVE_INIT(4);
+
+#endif
+
+#ifdef CONFIG_STM32H7_SPI5_SLAVE
+
+static uint8_t SPI_SLAVE_OUTQ(5)[DMA_ALIGN_UP(CONFIG_STM32H7_SPI_SLAVE_QSIZE)]
+__attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+static uint8_t SPI_SLAVE_INQ(5)[DMA_ALIGN_UP(CONFIG_STM32H7_SPI_SLAVE_QSIZE)]
+__attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+static struct stm32_spidev_s g_spi5sctrlr = SPI_SLAVE_INIT(5);
+
+#endif
+
+#ifdef CONFIG_STM32H7_SPI6_SLAVE
+
+/* TODO: these needs to be located in SRAM3 for SPI6 */
+
+static uint8_t SPI_SLAVE_OUTQ(6)[DMA_ALIGN_UP(CONFIG_STM32H7_SPI_SLAVE_QSIZE)]
+__attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+static uint8_t SPI_SLAVE_INQ(6)[DMA_ALIGN_UP(CONFIG_STM32H7_SPI_SLAVE_QSIZE)]
+__attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+static struct stm32_spidev_s g_spi6sctrlr = SPI_SLAVE_INIT(6);
+
+#endif
+
+/*****************************************************************************
+ * Private Functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Name: spi_getreg8
+ *
+ * Description:
+ *   Get the contents of the SPI register at offset
+ *
+ * Input Parameters:
+ *   priv   - private SPI device structure
+ *   offset - offset to the register of interest
+ *
+ * Returned Value:
+ *   The contents of the 8-bit register
+ *
+ *****************************************************************************/
+
+static inline uint8_t spi_getreg8(FAR struct stm32_spidev_s *priv,
+                                  uint32_t offset)
+{
+  return getreg8(priv->spibase + offset);
+}
+
+/*****************************************************************************
+ * Name: spi_putreg8
+ *
+ * Description:
+ *   Write a 8-bit value to the SPI register at offset
+ *
+ * Input Parameters:
+ *   priv   - private SPI device structure
+ *   offset - offset to the register of interest
+ *   value  - the 8-bit value to be written
+ *
+ *****************************************************************************/
+
+static inline void spi_putreg8(FAR struct stm32_spidev_s *priv,
+                               uint32_t offset, uint8_t value)
+{
+  putreg8(value, priv->spibase + offset);
+}
+
+/*****************************************************************************
+ * Name: spi_getreg
+ *
+ * Description:
+ *   Get the contents of the SPI register at offset
+ *
+ * Input Parameters:
+ *   priv   - private SPI device structure
+ *   offset - offset to the register of interest
+ *
+ * Returned Value:
+ *   The contents of the 16-bit register
+ *
+ *****************************************************************************/
+
+static inline uint32_t spi_getreg(FAR struct stm32_spidev_s *priv,
+                                  uint32_t offset)
+{
+  return getreg32(priv->spibase + offset);
+}
+
+/*****************************************************************************
+ * Name: spi_putreg
+ *
+ * Description:
+ *   Write a 16-bit value to the SPI register at offset
+ *
+ * Input Parameters:
+ *   priv   - private SPI device structure
+ *   offset - offset to the register of interest
+ *   value  - the 16-bit value to be written
+ *
+ *****************************************************************************/
+
+static inline void spi_putreg(FAR struct stm32_spidev_s *priv,
+                              uint32_t offset, uint32_t value)
+{
+  putreg32(value, priv->spibase + offset);
+}
+
+/*****************************************************************************
+ * Name: spi_modifyreg
+ *
+ * Description:
+ *   Write a 32-bit value to the SPI register at offset
+ *
+ * Input Parameters:
+ *   priv    - private SPI device structure
+ *   offset  - offset to the register of interest
+ *   clrbits - the bits to clear
+ *   setbits - the bits to set
+ *
+ * Returned Value:
+ *   None
+ *
+ *****************************************************************************/
+
+static inline void spi_modifyreg(FAR struct stm32_spidev_s *priv,
+                                 uint32_t offset, uint32_t clrbits,
+                                 uint32_t setbits)
+{
+  modifyreg32(priv->spibase + offset, clrbits, setbits);
+}
+
+/*****************************************************************************
+ * Name: spi_readword
+ *
+ * Description:
+ *   Read one byte from SPI
+ *
+ * Input Parameters:
+ *   priv - Device-specific state data
+ *
+ * Returned Value:
+ *   Byte as read
+ *
+ *****************************************************************************/
+
+static inline uint32_t spi_readword(FAR struct stm32_spidev_s *priv)
+{
+  /* Can't receive in tx only mode */
+
+  if (priv->config == SIMPLEX_TX)
+    {
+      return 0;
+    }
+
+  /* Wait until the receive buffer is not empty */
+
+  while ((spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_RXP) == 0);
+
+  /* Then return the received byte */
+
+  return spi_getreg(priv, STM32_SPI_RXDR_OFFSET);
+}
+
+/*****************************************************************************
+ * Name: spi_writeword
+ *
+ * Description:
+ *   Write one byte to SPI
+ *
+ * Input Parameters:
+ *   priv - Device-specific state data
+ *   byte - Byte to send
+ *
+ * Returned Value:
+ *   None
+ *
+ *****************************************************************************/
+
+static inline void spi_writeword(FAR struct stm32_spidev_s *priv,
+                                 uint32_t word)
+{
+  /* Can't transmit in rx only mode */
+
+  if (priv->config == SIMPLEX_RX)
+    {
+      return;
+    }
+
+  /* Wait until the transmit buffer is empty */
+
+  while ((spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_TXP) == 0);
+
+  /* Then send the byte */
+
+  spi_putreg(priv, STM32_SPI_TXDR_OFFSET, word);
+}
+
+/*****************************************************************************
+ * Name: spi_readbyte
+ *
+ * Description:
+ *   Read one byte from SPI
+ *
+ * Input Parameters:
+ *   priv - Device-specific state data
+ *
+ * Returned Value:
+ *   Byte as read
+ *
+ *****************************************************************************/
+
+static inline uint8_t spi_readbyte(FAR struct stm32_spidev_s *priv)
+{
+  /* Can't receive in tx only mode */
+
+  if (priv->config == SIMPLEX_TX)
+    {
+      return 0;
+    }
+
+  /* Wait until the receive buffer is not empty */
+
+  while ((spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_RXP) == 0);
+
+  /* Then return the received byte */
+
+  return spi_getreg8(priv, STM32_SPI_RXDR_OFFSET);
+}
+
+/*****************************************************************************
+ * Name: spi_writebyte
+ *
+ * Description:
+ *   Write one 8-bit frame to the SPI FIFO
+ *
+ * Input Parameters:
+ *   priv - Device-specific state data
+ *   byte - Byte to send
+ *
+ * Returned Value:
+ *   None
+ *
+ *****************************************************************************/
+
+static inline void spi_writebyte(FAR struct stm32_spidev_s *priv,
+                                 uint8_t byte)
+{
+  /* Can't transmit in rx only mode */
+
+  if (priv->config == SIMPLEX_RX)
+    {
+      return;
+    }
+
+  /* Wait until the transmit buffer is empty */
+
+  while ((spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_TXP) == 0);
+
+  /* Then send the byte */
+
+  spi_putreg8(priv, STM32_SPI_TXDR_OFFSET, byte);
+}
+
+/*****************************************************************************
+ * Name: spi_dumpregs
+ *****************************************************************************/
+
+#ifdef CONFIG_DEBUG_SPI_INFO
+static void spi_dumpregs(FAR struct stm32_spidev_s *priv)
+{
+  spiinfo("CR1: 0x%08x CFG1: 0x%08x CFG2: 0x%08x\n",
+          spi_getreg(priv, STM32_SPI_CR1_OFFSET),
+          spi_getreg(priv, STM32_SPI_CFG1_OFFSET),
+          spi_getreg(priv, STM32_SPI_CFG2_OFFSET));
+  spiinfo("IER: 0x%08x SR: 0x%08x I2SCFGR: 0x%08x\n",
+          spi_getreg(priv, STM32_SPI_IER_OFFSET),
+          spi_getreg(priv, STM32_SPI_SR_OFFSET),
+          spi_getreg(priv, STM32_SPI_I2SCFGR_OFFSET));
+}
+#endif
+
+/*****************************************************************************
+ * Name: spi_9to16bitmode
+ *
+ * Description:
+ *   Check if the SPI is operating in more then 8 bit mode
+ *
+ * Input Parameters:
+ *   priv     - Device-specific state data
+ *
+ * Returned Value:
+ *   true: >8 bit mode-bit mode, false: <= 8-bit mode
+ *
+ *****************************************************************************/
+
+static inline bool spi_9to16bitmode(FAR struct stm32_spidev_s *priv)
+{
+  uint32_t regval = spi_getreg(priv, STM32_SPI_CFG1_OFFSET);
+
+  return ((regval & SPI_CFG1_CRCSIZE_9BIT) == SPI_CFG1_CRCSIZE_9BIT);
+}
+
+/*****************************************************************************
+ * Name: spi_dmarxcallback
+ *
+ * Description:
+ *   Called when the RX DMA completes
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_STM32H7_SPI_DMA
+static void spi_dmarxcallback(DMA_HANDLE handle, uint8_t isr, void *arg)
+{
+  FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)arg;
+
+  /* Wake-up the SPI driver */
+
+  priv->rxresult = isr | 0x080;  /* OR'ed with 0x80 to assure non-zero */
+}
+#endif
+
+/*****************************************************************************
+ * Name: spi_dmatxcallback
+ *
+ * Description:
+ *   Called when the RX DMA completes
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_STM32H7_SPI_DMA
+static void spi_dmatxcallback(DMA_HANDLE handle, uint8_t isr, void *arg)
+{
+  FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)arg;
+
+  /* Wake-up the SPI driver */
+
+  priv->txresult = isr | 0x080;  /* OR'ed with 0x80 to assure non-zero */
+}
+#endif
+
+/*****************************************************************************
+ * Name: spi_dmarxsetup
+ *
+ * Description:
+ *   Setup to perform RX DMA
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_STM32H7_SPI_DMA
+static void spi_dmarxsetup(FAR struct stm32_spidev_s *priv, size_t nwords)
+{
+  stm32_dmacfg_t dmacfg;
+
+  /* Can't receive in tx only mode */
+
+  if (priv->config == SIMPLEX_TX)
+    {
+      return;
+    }
+
+  /* 8- or 16-bit mode? */
+
+  if (spi_9to16bitmode(priv))
+    {
+      /* 16-bit mode */
+
+      priv->rxccr = SPI_RXDMA16_CONFIG;
+    }
+  else
+    {
+      /* 8-bit mode -- is there a buffer to receive data in? */
+
+      priv->rxccr = SPI_RXDMA8_CONFIG;
+    }
+
+  /* Configure the RX DMA */
+
+  /* This just transfers continuously to circular buffer */
+
+  dmacfg.paddr = priv->spibase + STM32_SPI_RXDR_OFFSET;
+  dmacfg.maddr = (uint32_t)priv->inq;
+  dmacfg.ndata = CONFIG_STM32H7_SPI_SLAVE_QSIZE;
+  dmacfg.cfg1  = priv->rxccr;
+  dmacfg.cfg2  = 0;
+
+  stm32_dmasetup(priv->rxdma, &dmacfg);
+}
+#endif
+
+/*****************************************************************************
+ * Name: spi_dmatxsetup
+ *
+ * Description:
+ *   Setup to perform TX DMA
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_STM32H7_SPI_DMA
+static void spi_dmatxsetup(FAR struct stm32_spidev_s *priv, size_t nwords)
+{
+  /* TODO: set up dma to transfer out the new data from priv->outq,
+   * which is set up in spi_enqueue
+   * When the transfer is complete, update outq indexies accordingly
+   */
+
+#if 0
+  stm32_dmacfg_t dmacfg;
+
+  /* Can't transmit in rx only mode */
+
+  if (priv->config == SIMPLEX_RX)
+    {
+      return;
+    }
+
+  /* 8- or 16-bit mode? */
+
+  if (spi_9to16bitmode(priv))
+    {
+      /* 16-bit mode */
+
+      priv->txccr = SPI_TXDMA16_CONFIG;
+    }
+  else
+    {
+      /* 8-bit mode */
+
+      priv->txccr = SPI_TXDMA8_CONFIG;
+    }
+
+  dmacfg.paddr = priv->spibase + STM32_SPI_TXDR_OFFSET;
+  dmacfg.maddr = (uint32_t)priv->outq[0];
+  dmacfg.ndata = nwords;
+  dmacfg.cfg1  = priv->txccr;
+  dmacfg.cfg2  = 0;
+
+  /* Setup the TX DMA */
+
+  stm32_dmasetup(priv->txdma, &dmacfg);
+
+#endif // 0
+}
+#endif
+
+/*****************************************************************************
+ * Name: spi_dmarxstart
+ *
+ * Description:
+ *   Start RX DMA. NB! This must be called before spi_dmatxstart
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_STM32H7_SPI_DMA
+static void spi_dmarxstart(FAR struct stm32_spidev_s *priv)
+{
+  /* Can't receive in tx only mode */
+
+  if (priv->config == SIMPLEX_TX)
+    {
+      return;
+    }
+
+  priv->rxresult = 0;
+
+  spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, 0, SPI_CFG1_RXDMAEN);
+  stm32_dmastart(priv->rxdma, spi_dmarxcallback, priv, false);
+}
+#endif
+
+/*****************************************************************************
+ * Name: spi_dmatxstart
+ *
+ * Description:
+ *   Start TX DMA. NB! This must be called after spi_dmarxstart
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_STM32H7_SPI_DMA
+static void spi_dmatxstart(FAR struct stm32_spidev_s *priv)
+{
+  /* Can't transmit in rx only mode */
+
+  if (priv->config == SIMPLEX_RX)
+    {
+      return;
+    }
+
+  priv->txresult = 0;
+  stm32_dmastart(priv->txdma, spi_dmatxcallback, priv, false);
+  spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, 0, SPI_CFG1_TXDMAEN);
+}
+#endif
+
+/*****************************************************************************
+ * Name: spi_lock
+ *
+ * Description:
+ *   Take or release the semaphore that enforces mutually exclusive access to
+ *   SPI resources, handling any exceptional conditions
+ *
+ * Input Parameters:
+ *   dev  - Device-specific state data
+ *   lock - true: Lock spi bus, false: unlock SPI bus
+ *
+ * Returned Value:
+ *   None
+ *
+ *****************************************************************************/
+
+static int spi_lock(FAR struct spi_sctrlr_s *sctrlr, bool lock)
+{
+  FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)sctrlr;
+  int ret;
+
+  if (lock)
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      do
+        {
+          ret = nxsem_wait(&priv->exclsem);
+
+          /* The only case that an error should occur here is if the wait
+           * was awakened by a signal.
+           */
+
+          DEBUGASSERT(ret == OK || ret == -EINTR);
+        }
+      while (ret == -EINTR);
+    }
+  else
+    {
+      (void)nxsem_post(&priv->exclsem);
+      ret = OK;
+    }
+
+  return ret;
+}
+
+/*****************************************************************************
+ * Name: spi_enable
+ *
+ * Description:
+ *   Enable/disable the SPI peripheral
+ *
+ * Input Parameters:
+ *   priv  - Device-specific state data
+ *   state - true: enable, false: disable
+ *
+ *****************************************************************************/
+
+static inline void spi_enable(FAR struct stm32_spidev_s *priv, bool state)
+{
+  if (state == true)
+    {
+      /* Enable SPI */
+
+      spi_modifyreg(priv, STM32_SPI_CR1_OFFSET, 0, SPI_CR1_SPE);
+    }
+  else
+    {
+      /* Disable SPI */
+
+      spi_modifyreg(priv, STM32_SPI_CR1_OFFSET, SPI_CR1_SPE, 0);
+    }
+}
+
+/*****************************************************************************
+ * Name: spi_setmode
+ *
+ * Description:
+ *   Set the SPI mode.  see enum spi_mode_e for mode definitions
+ *
+ * Input Parameters:
+ *   dev  - Device-specific state data
+ *   mode - The SPI mode requested
+ *
+ * Returned Value:
+ *   Returns the actual frequency selected
+ *
+ *****************************************************************************/
+
+static void spi_setmode(FAR struct spi_sctrlr_s *sctrlr, enum spi_mode_e mode)
+{
+  FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)sctrlr;
+  uint32_t setbits = 0;
+  uint32_t clrbits = 0;
+
+  spiinfo("mode=%d\n", mode);
+
+  /* Has the mode changed? */
+
+  if (mode != priv->mode)
+    {
+      /* Yes... Set CR1 appropriately */
+
+      switch (mode)
+        {
+        case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */
+          setbits = 0;
+          clrbits = SPI_CFG2_CPOL | SPI_CFG2_CPHA;
+          break;
+
+        case SPIDEV_MODE1: /* CPOL=0; CPHA=1 */
+          setbits = SPI_CFG2_CPHA;
+          clrbits = SPI_CFG2_CPOL;
+          break;
+
+        case SPIDEV_MODE2: /* CPOL=1; CPHA=0 */
+          setbits = SPI_CFG2_CPOL;
+          clrbits = SPI_CFG2_CPHA;
+          break;
+
+        case SPIDEV_MODE3: /* CPOL=1; CPHA=1 */
+          setbits = SPI_CFG2_CPOL | SPI_CFG2_CPHA;
+          clrbits = 0;
+          break;
+
+        default:
+          return;
+        }
+
+      /* Change SPI mode */
+
+      spi_modifyreg(priv, STM32_SPI_CFG2_OFFSET, clrbits, setbits);
+
+      /* Save the mode so that subsequent re-configurations will be faster */
+
+      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 requested
+ *
+ * Returned Value:
+ *   None
+ *
+ *****************************************************************************/
+
+static void spi_setbits(FAR struct spi_sctrlr_s *sctrlr, int nbits)
+{
+  FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)sctrlr;
+  uint32_t setbits = 0;
+  uint32_t clrbits = 0;
+  int savbits = nbits;
+
+  spiinfo("nbits=%d\n", nbits);
+
+  /* Has the number of bits changed? */
+
+  if (nbits != priv->nbits)
+    {
+      /* Yes... Set CFG1 appropriately */
+
+      /* Set the number of bits (valid range 4-32) */
+
+      if (nbits < 4 || nbits > 32)
+        {
+          return;
+        }
+
+      clrbits = SPI_CFG1_DSIZE_MASK;
+      setbits = SPI_CFG1_DSIZE_VAL(nbits);
+
+      /* REVISIT: FIFO threshold level */
+
+      /* If nbits is <=8, then we are in byte mode and FRXTH shall be set
+       * (else, transaction will not complete).
+       */
+
+      if (nbits < 9)
+        {
+          setbits |= SPI_CFG1_FTHLV_1DATA; /* RX FIFO Threshold = 1 byte */
+        }
+      else
+        {
+          setbits |= SPI_CFG1_FTHLV_2DATA; /* RX FIFO Threshold = 2 byte */
+        }
+
+      spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, clrbits, setbits);
+
+      priv->nbits = savbits;
+    }
+}
+
+/*****************************************************************************
+ * Name: spi_bind
+ *
+ * Description:
+ *   Bind the SPI slave device interface to the SPI slave controller
+ *   interface and configure the SPI interface.  Upon return, the SPI
+ *   slave controller driver is fully operational and ready to perform
+ *   transfers.
+ *
+ * Input Parameters:
+ *   sctrlr - SPI slave controller interface instance
+ *   sdev   - SPI slave device interface instance
+ *   mode   - The SPI mode requested
+ *   nbits  - The number of bits requests.
+ *            If value is greater > 0 then it implies MSB first
+ *            If value is below < 0, then it implies LSB first with -nbits
+ *
+ * Returned Value:
+ *   none
+ *
+ *****************************************************************************/
+
+static void spi_bind(struct spi_sctrlr_s *sctrlr,
+                     struct spi_sdev_s *sdev, enum spi_smode_e mode,
+                     int nbits)
+{
+  struct stm32_spidev_s *priv = (struct stm32_spidev_s *)sctrlr;
+  uint32_t nss_gpio;
+
+  spiinfo("sdev=%p mode=%d nbits=%d\n", sdv, mode, nbits);
+
+  DEBUGASSERT(priv != NULL && priv->sdev == NULL && sdev != NULL);
+
+  /* Get exclusive access to the SPI device */
+
+  spi_lock(sctrlr, true);
+
+  /* Make sure the spi is disabled */
+
+  spi_enable(priv, false);
+
+  /* Make sure the dma is disabled */
+
+  spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET,
+                SPI_CFG1_RXDMAEN | SPI_CFG1_TXDMAEN, 0);
+
+  /* invalidate the whole rx buffer */
+
+  up_flush_dcache((uintptr_t)priv->inq,
+                  (uintptr_t)priv->inq + CONFIG_STM32H7_SPI_SLAVE_QSIZE);
+
+  /* Bind the SPI slave device interface instance to the SPI slave
+   * controller interface.
+   */
+
+  priv->sdev = sdev;
+
+  /* Initialize the circular buffer head */
+
+  priv->ihead = 0;
+
+  /* Setup to begin normal SPI operation */
+
+  spi_setmode(sctrlr, mode);
+  spi_setbits(sctrlr, nbits);
+
+  /* First, configure NSS as GPIO EXTI input */
+
+  nss_gpio = priv->nss_pin & (GPIO_PORT_MASK | GPIO_PIN_MASK);
+  nss_gpio |= (GPIO_INPUT | GPIO_FLOAT | GPIO_EXTI);
+  stm32_configgpio(nss_gpio);
+
+  /* Bind to NSS interrupt */
+
+  (void)stm32_gpiosetevent(priv->nss_pin, false, true, false,
+                           spi_nssinterrupt, priv);
+
+#ifdef CONFIG_PM
+  /* Register to receive power management callbacks */
+
+  ret = pm_register(&priv->pm_cb);
+  DEBUGASSERT(ret == OK);
+  UNUSED(ret);
+#endif
+
+  spi_lock(sctrlr, false);
+}
+
+/*****************************************************************************
+ * Name: spi_nssinterrupt
+ *
+ * Description:
+ *   SPI slave NSS interrupt handler
+ *
+ * Input Parameters:
+ *   irq     - not used
+ *   context - not used
+ *   arg     - pointer to controller
+ *
+ * Returned Value:
+ *   OK
+ *
+ *****************************************************************************/
+
+static int spi_nssinterrupt(int irq, void *context, void *arg)
+{
+  FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)arg;
+
+  /* If the pin is low, just enable rising edge interrupt */
+
+  if (!stm32_gpioread(priv->nss_pin))
+    {
+      /* Bind to NSS rising edge interrupt */
+
+      (void)stm32_gpiosetevent(priv->nss_pin, true, false, false,
+                               spi_nssinterrupt, priv);
+      return OK;
+    }
+
+  /* Disable NSS interrupt */
+
+  (void)stm32_gpiosetevent(priv->nss_pin, false, false, false,
+                           NULL, priv);
+
+  /* Re-configure nss pin */
+
+  stm32_configgpio(priv->nss_pin);
+
+  /* Enable spi peripheral */
+
+  spi_enable(priv, true);
+
+  /* Flush SPI read FIFO */
+
+  while ((spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_RXPLVL_MASK) != 0)
+    {
+      spi_getreg(priv, STM32_SPI_RXDR_OFFSET);
+    }
+
+  /* Disable spi before dma setup */
+
+  spi_enable(priv, false);
+
+#ifdef CONFIG_STM32H7_SPI_DMA
+
+  /* Setup DMAs */
+
+  spi_dmarxsetup(priv, 0);
+  spi_dmatxsetup(priv, 0);
+
+  /* Start the DMAs */
+
+  spi_dmarxstart(priv);
+  spi_dmatxstart(priv);
+
+  priv->dmarunning = true;
+#endif
+
+  /* Enable spi peripheral */
+
+  spi_enable(priv, true);
+
+  return OK;
+}
+
+/*****************************************************************************
+ * Name: spi_unbind
+ *
+ * Description:
+ *   Un-bind the SPI slave device interface from the SPI slave controller
+ *   interface.  Reset the SPI interface and restore the SPI slave
+ *   controller driver to its initial state,
+ *
+ * Input Parameters:
+ *   sctrlr - SPI slave controller interface instance
+ *
+ * Returned Value:
+ *   none
+ *
+ *****************************************************************************/
+
+static void spi_unbind(struct spi_sctrlr_s *sctrlr)
+{
+  struct stm32_spidev_s *priv = (struct stm32_spidev_s *)sctrlr;
+
+  DEBUGASSERT(priv != NULL);
+  spiinfo("Unbinding %p\n", priv->sdev);
+
+  DEBUGASSERT(priv->sdev != NULL);
+
+  /* Get exclusive access to the SPI device */
+
+  spi_lock(sctrlr, true);
+
+  /* Unbind the SPI slave interface */
+
+  priv->sdev = NULL;
+
+  /* Disable DMA */
+
+  spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET,
+                SPI_CFG1_RXDMAEN | SPI_CFG1_TXDMAEN, 0);
+
+  /* Disable the SPI peripheral */
+
+  spi_enable(priv, false);
+
+  spi_lock(sctrlr, false);
+}
+
+/*****************************************************************************
+ * Name: spi_enqueue
+ *
+ * Description:
+ *   Enqueue the next value to be shifted out from the interface.  This adds
+ *   the word the controller driver for a subsequent transfer but has no
+ *   effect on anyin-process or currently "committed" transfers
+ *
+ * Input Parameters:
+ *   sctrlr - SPI slave controller interface instance
+ *   data   - Command/data mode data value to be shifted out.  The width of
+ *            the data must be the same as the nbits parameter previously
+ *            provided to the bind() methods.
+ *
+ * Returned Value:
+ *   Zero if the word was successfully queue; A negated errno valid is
+ *   returned on any failure to enqueue the word (such as if the queue is
+ *   full).
+ *
+ *****************************************************************************/
+
+static int spi_enqueue(struct spi_sctrlr_s *sctrlr, FAR const void *data,
+                       size_t len)
+{
+  return 0;
+}
+
+/*****************************************************************************
+ * Name: spi_qfull
+ *
+ * Description:
+ *   Return true if the queue is full or false if there is space to add an
+ *   additional word to the queue.
+ *
+ * Input Parameters:
+ *   sctrlr - SPI slave controller interface instance
+ *
+ * Returned Value:
+ *   true if the output wueue is full
+ *
+ *****************************************************************************/
+
+static bool spi_qfull(struct spi_sctrlr_s *sctrlr)
+{
+  return false;
+}
+
+/*****************************************************************************
+ * Name: spi_qflush
+ *
+ * Description:
+ *   Discard all saved values in the output queue.  On return from this
+ *   function the output queue will be empty.  Any in-progress or otherwise
+ *   "committed" output values may not be flushed.
+ *
+ * Input Parameters:
+ *   sctrlr - SPI slave controller interface instance
+ *
+ * Returned Value:
+ *   None
+ *
+ *****************************************************************************/
+
+static void spi_qflush(struct spi_sctrlr_s *sctrlr)
+{
+  struct stm32_spidev_s *priv = (struct stm32_spidev_s *)sctrlr;
+  irqstate_t flags;
+
+  DEBUGASSERT(priv != NULL && priv->sdev != NULL);
+
+#ifdef CONFIG_STM32H7_SPI_DMA
+  if (!priv->dmarunning)
+    {
+      return;
+    }
+#endif
+
+  /* Get exclusive access to the SPI device */
+
+  spi_lock(sctrlr, true);
+  flags = enter_critical_section();
+
+  /* Flush the input buffers */
+
+#ifdef CONFIG_STM32H7_SPI_DMA
+  priv->ihead =
+    CONFIG_STM32H7_SPI_SLAVE_QSIZE - stm32_dmaresidual(priv->rxdma);
+#else
+  priv->ihead = 0;
+  priv->itail = 0;
+#endif
+
+  /* Flush the output buffers */
+
+  priv->ohead = 0;
+  priv->otail = 0;
+  leave_critical_section(flags);
+  spi_lock(sctrlr, false);
+}
+
+/*****************************************************************************
+ * Name: spi_rx_buffer_free
+ *
+ * Description:
+ *   Handle buffer wrapping around & invalidate the previous buffer cache
+ *
+ * Input Parameters:
+ *   ptr - pointer to the rx buffer
+ *   start - start index of just received data
+ *   end - end index of just received data
+ *
+ * Returned Value:
+ *   new start index; 0 if buffer wrapped around, end otherwise
+ *
+ *****************************************************************************/
+
+static inline int spi_rx_buffer_free(uint8_t *ptr, int start, int end)
+{
+  /* The priv->ihead can only be greater than qsize if the device driver
+   * returns garbage
+   */
+
+  if (end >= CONFIG_STM32H7_SPI_SLAVE_QSIZE)
+    {
+      end = 0;
+      up_invalidate_dcache((uintptr_t)&ptr[start],
+                           (uintptr_t)&ptr[CONFIG_STM32H7_SPI_SLAVE_QSIZE]);
+    }
+  else
+    {
+      up_invalidate_dcache((uintptr_t)&ptr[start],
+                           (uintptr_t)&ptr[end]);
+    }
+
+  return end;
+}
+
+/*****************************************************************************
+ * Name: spi_qpoll
+ *
+ * Description:
+ *   Tell the controller to output all the receive queue data.
+ *
+ * Input Parameters:
+ *   sctrlr - SPI slave controller interface instance
+ *
+ * Returned Value:
+ *   Number of bytes left in the rx queue. If the device accepted all the
+ *
+ *****************************************************************************/
+
+static size_t spi_qpoll(struct spi_sctrlr_s *sctrlr)
+{
+  struct stm32_spidev_s *priv = (struct stm32_spidev_s *)sctrlr;
+  int itail;
+  int ihead;
+  uint16_t bytes_left;
+
+  DEBUGASSERT(priv != NULL && priv->sdev != NULL);
+  DEBUGASSERT(priv->ihead < CONFIG_STM32H7_SPI_SLAVE_QSIZE);
+
+#ifdef CONFIG_STM32H7_SPI_DMA
+  if (!priv->dmarunning)
+    {
+      return 0;
+    }
+#endif
+
+  /* Get exclusive access to the SPI device */
+
+  spi_lock(sctrlr, true);
+
+#ifdef CONFIG_STM32H7_SPI_DMA
+  itail = CONFIG_STM32H7_SPI_SLAVE_QSIZE - stm32_dmaresidual(priv->rxdma);
+#else
+  #error Support only simplex mode rx with dma
+#endif
+
+  /* Receive all data between last read index and the current index */
+
+  ihead = priv->ihead;
+  if (ihead > itail)
+    {
+      /* Receive the end of receive buffer */
+
+      priv->ihead += SPI_SDEV_RECEIVE(priv->sdev,
+                                      (const uint16_t *)&priv->inq[ihead],
+                                      CONFIG_STM32H7_SPI_SLAVE_QSIZE -
+                                        ihead);
+
+      /* Invalidate dcache and wrap around the priv->ihead */
+
+      priv->ihead = spi_rx_buffer_free(priv->inq, ihead, priv->ihead);
+    }
+
+  ihead = priv->ihead;
+  if (ihead < itail)
+    {
+      /* Receive the data between ihead and itail */
+
+      priv->ihead += SPI_SDEV_RECEIVE(priv->sdev,
+                                      (const uint16_t *)&priv->inq[ihead],
+                                      itail - ihead);
+
+      /* Invalidate dcache and wrap around the priv->ihead */
+
+      priv->ihead = spi_rx_buffer_free(priv->inq, ihead, priv->ihead);
+    }
+
+  /* Calculate the number of bytes left in the buffer */
+
+  bytes_left = itail < priv->ihead
+    ? CONFIG_STM32H7_SPI_SLAVE_QSIZE - priv->ihead + itail
+    : itail - priv->ihead;
+
+  spi_lock(sctrlr, false);
+
+  return bytes_left;
+}
+
+/*****************************************************************************
+ * Name: spi_pm_prepare
+ *
+ * Description:
+ *   Request the driver to prepare for a new power state. This is a
+ *   warning that the system is about to enter into a new power state.  The
+ *   driver should begin whatever operations that may be required to enter
+ *   power state.  The driver may abort the state change mode by returning
+ *   a non-zero value from the callback function.
+ *
+ * Input Parameters:
+ *   cb      - Returned to the driver.  The driver version of the callback
+ *             structure may include additional, driver-specific state
+ *             data at the end of the structure.
+ *   domain  - Identifies the activity domain of the state change
+ *   pmstate - Identifies the new PM state
+ *
+ * Returned Value:
+ *   0 (OK) means the event was successfully processed and that the driver
+ *   is prepared for the PM state change.  Non-zero means that the driver
+ *   is not prepared to perform the tasks needed achieve this power setting
+ *   and will cause the state change to be aborted.  NOTE:  The prepare
+ *   method will also be recalled when reverting from lower back to higher
+ *   power consumption modes (say because another driver refused a lower
+ *   power state change).  Drivers are not permitted to return non-zero
+ *   values when reverting back to higher power consumption modes!
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_PM
+static int spi_pm_prepare(FAR struct pm_callback_s *cb, int domain,
+                          enum pm_state_e pmstate)
+{
+  struct stm32_spidev_s *priv =
+      (struct stm32_spidev_s *)((char *)cb -
+                                    offsetof(struct stm32_spidev_s, pm_cb));
+  int sval;
+
+  /* Logic to prepare for a reduced power state goes here. */
+
+  switch (pmstate)
+    {
+    case PM_NORMAL:
+    case PM_IDLE:
+      break;
+
+    case PM_STANDBY:
+    case PM_SLEEP:
+
+      /* Check if exclusive lock for SPI bus is held. */
+
+      if (nxsem_getvalue(&priv->exclsem, &sval) < 0)
+        {
+          DEBUGASSERT(false);
+          return -EINVAL;
+        }
+
+      /* If exclusive lock is held, do not allow entry to deeper PM states */
+
+      if (sval <= 0)
+        {
+          return -EBUSY;
+        }
+
+      break;
+
+    default:
+
+      /* Should not get here */
+
+      break;
+    }
+
+  return OK;
+}
+#endif
+
+/*****************************************************************************
+ * Name: spi_slave_initialize
+ *
+ * Description:
+ *   Initialize the selected SPI bus for slave operations
+ *
+ * Input Parameters:
+ *   priv   - private SPI device structure
+ *
+ * Returned Value:
+ *   None
+ *
+ *****************************************************************************/
+
+static void spi_slave_initialize(struct stm32_spidev_s *priv)
+{
+  uint32_t setbits = 0;
+  uint32_t clrbits = 0;
+#ifdef CONFIG_PM
+  int ret;
+#endif
+
+  /* Configure CR1, CFG1 and CFG2. Default configuration:
+   *   Mode 0:                        CFG2.CPHA=0 and CFG2.CPOL=0
+   *   Master:                        CFG2.MSTR=1
+   *   8-bit:                         CFG1.DSIZE=7
+   *   MSB tranmitted first:          CFG2.LSBFRST=0
+   *   Replace NSS with SSI & SSI=1:  CR1.SSI=1 CFG2.SSM=1 (prevent MODF err)
+   *   Two lines full duplex:         CFG2.COMM=0
+   */
+
+  /* CR1 */
+
+  clrbits = SPI_CR1_SPE;
+  spi_modifyreg(priv, STM32_SPI_CR1_OFFSET, clrbits, setbits);
+
+  /* CFG1 */
+
+  clrbits = SPI_CFG1_DSIZE_MASK;
+  setbits = SPI_CFG1_DSIZE_8BIT | SPI_CFG1_FTHLV_1DATA; /* REVISIT: FTHLV */
+  spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, clrbits, setbits);
+
+  /* CFG2 */
+
+  clrbits = SPI_CFG2_CPHA | SPI_CFG2_CPOL | SPI_CFG2_LSBFRST |
+    SPI_CFG2_COMM_MASK;
+  setbits = SPI_CFG2_SSM;
+
+  switch (priv->config)
+    {
+    default:
+    case FULL_DUPLEX:
+      setbits |= SPI_CFG2_COMM_FULL;
+      break;
+    case SIMPLEX_TX:
+      setbits |= SPI_CFG2_COMM_STX;
+      break;
+    case SIMPLEX_RX:
+      setbits |= SPI_CFG2_COMM_SRX;
+      break;
+    case HALF_DUPLEX:
+      setbits |= SPI_CFG2_COMM_HALF;
+      break;
+    }
+
+  spi_modifyreg(priv, STM32_SPI_CFG2_OFFSET, clrbits, setbits);
+
+  priv->nbits     = 8;
+  priv->mode      = SPIDEV_MODE0;
+
+  /* CRCPOLY configuration */
+
+  spi_putreg(priv, STM32_SPI_CRCPOLY_OFFSET, 7);
+
+  /* Initialize the SPI semaphore that enforces mutually exclusive access. */
+
+  nxsem_init(&priv->exclsem, 0, 1);
+
+#ifdef CONFIG_STM32H7_SPI_DMA
+  /* DMA will be started in the interrupt handler, syncronized to the master
+   * nss
+   */
+
+  priv->dmarunning = false;
+
+  /* Initialize the SPI semaphores that is used to wait for DMA completion.
+   * This semaphore is used for signaling and, hence, should not have
+   * priority inheritance enabled.
+   */
+
+  nxsem_init(&priv->rxsem, 0, 0);
+  nxsem_init(&priv->txsem, 0, 0);
+
+  sem_setprotocol(&priv->rxsem, SEM_PRIO_NONE);
+  sem_setprotocol(&priv->txsem, SEM_PRIO_NONE);
+
+  if (priv->config != SIMPLEX_TX)
+    {
+      priv->rxdma = stm32_dmachannel(priv->rxch);
+      DEBUGASSERT(priv->rxdma);
+    }
+
+  if (priv->config != SIMPLEX_RX)
+    {
+      priv->txdma = stm32_dmachannel(priv->txch);
+      DEBUGASSERT(priv->txdma);
+    }
+
+#endif
+
+#ifdef CONFIG_DEBUG_SPI_INFO
+  /* Dump registers after initialization */
+
+  spi_dumpregs(priv);
+#endif
+}
+
+/*****************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Name: stm32_spi_slave_initialize
+ *
+ * Description:
+ *   Initialize the selected SPI port(bus) to operate as spi slave
+ *
+ * Input Parameters:
+ *   Port number (for hardware that has mutiple SPI interfaces)
+ *
+ * Returned Value:
+ *   Valid SPI device structure reference on succcess; a NULL on failure
+ *
+ *****************************************************************************/
+
+/* Helper macros to avoid duplicating all the code */
+
+#define GPIO_SPI_SCK(x) GPIO_SPI##x##_SCK
+#define GPIO_SPI_MISO(x) GPIO_SPI##x##_MISO
+#define GPIO_SPI_MOSI(x) GPIO_SPI##x##_MOSI
+#define GPIO_SPI_NSS(x) GPIO_SPI##x##_NSS
+
+#define SPI_SLAVE_INIT_BUS(x) \
+  priv = &g_spi##x##sctrlr;                                     \
+                                                                \
+  /* Only configure if the bus is not already configured */     \
+                                                                \
+  if (!priv->initialized)                                       \
+    {                                                           \
+      /* Configure SPI5 pins: SCK, MISO, MOSI and NSS */        \
+                                                                \
+      stm32_configgpio(GPIO_SPI_SCK(x));                        \
+      stm32_configgpio(GPIO_SPI_MISO(x));                       \
+      stm32_configgpio(GPIO_SPI_MOSI(x));                       \
+      priv->nss_pin = GPIO_SPI_NSS(x);                          \
+                                                                \
+      /* Set up default configuration: 8-bit, etc. */           \
+                                                                \
+      spi_slave_initialize(priv);                               \
+      priv->initialized = true;                                 \
+    }
+
+FAR struct spi_sctrlr_s *stm32_spi_slave_initialize(int bus)
+{
+  FAR struct stm32_spidev_s *priv = NULL;
+  irqstate_t flags = enter_critical_section();
+
+#ifdef CONFIG_STM32H7_SPI1_SLAVE
+  if (bus == 1)
+    {
+      SPI_SLAVE_INIT_BUS(1);
+    }
+  else
+#endif
+
+#ifdef CONFIG_STM32H7_SPI2_SLAVE
+  if (bus == 2)
+    {
+      SPI_SLAVE_INIT_BUS(2);
+    }
+  else
+#endif
+
+#ifdef CONFIG_STM32H7_SPI3_SLAVE
+  if (bus == 3)
+    {
+      SPI_SLAVE_INIT_BUS(3);
+    }
+  else
+#endif
+
+#ifdef CONFIG_STM32H7_SPI4_SLAVE
+  if (bus == 4)
+    {
+      SPI_SLAVE_INIT_BUS(4);
+    }
+  else
+#endif
+
+#ifdef CONFIG_STM32H7_SPI5_SLAVE
+  if (bus == 5)
+    {
+      SPI_SLAVE_INIT_BUS(5);
+    }
+  else
+#endif
+
+#ifdef CONFIG_STM32H7_SPI6_SLAVE
+  if (bus == 6)
+    {
+      SPI_SLAVE_INIT_BUS(6);
+    }
+  else
+#endif
+    {
+      spierr("ERROR: Unsupported SPI bus: %d\n", bus);
+      return NULL;
+    }
+
+  /* Initialize the SPI operations */
+
+  priv->sctrlr.ops = &g_sctrlr_ops;
+
+  leave_critical_section(flags);
+  return (FAR struct spi_sctrlr_s *)priv;
+}
+
+#endif /* CONFIG_STM32H7_SPI1..6_SLAVE */


[incubator-nuttx] 03/04: arch/arm/src/samv7/sam_spi_slave.c: Change for modified spi slave interface

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit b2a9a8cf814eae801bd876fdfd01b81ab6d6e29b
Author: Jukka Laitinen <ju...@intel.com>
AuthorDate: Tue May 26 10:42:13 2020 +0300

    arch/arm/src/samv7/sam_spi_slave.c: Change for modified spi slave interface
    
    Signed-off-by: Jukka Laitinen <ju...@intel.com>
---
 arch/arm/src/samv7/sam_spi_slave.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/arch/arm/src/samv7/sam_spi_slave.c b/arch/arm/src/samv7/sam_spi_slave.c
index 9845ce8..9197756 100644
--- a/arch/arm/src/samv7/sam_spi_slave.c
+++ b/arch/arm/src/samv7/sam_spi_slave.c
@@ -149,7 +149,8 @@ static void     spi_bind(struct spi_sctrlr_s *sctrlr,
                   struct spi_sdev_s *sdev, enum spi_smode_e mode,
                   int nbits);
 static void     spi_unbind(struct spi_sctrlr_s *sctrlr);
-static int      spi_enqueue(struct spi_sctrlr_s *sctrlr, uint16_t data);
+static int      spi_enqueue(struct spi_sctrlr_s *sctrlr,
+                  FAR const void *data, size_t nwords);
 static bool     spi_qfull(struct spi_sctrlr_s *sctrlr);
 static void     spi_qflush(struct spi_sctrlr_s *sctrlr);
 
@@ -485,7 +486,8 @@ static int spi_interrupt(int irq, void *context, FAR void *arg)
 
           /* Report the receipt of data to the SPI device driver */
 
-          SPI_SDEV_RECEIVE(priv->sdev, data);
+          SPI_SDEV_RECEIVE(priv->sdev, (const uint16_t *)&data,
+                           sizeof(data));
         }
 
       /* When a transfer starts, the data shifted out is the data present
@@ -615,7 +617,7 @@ static uint16_t spi_dequeue(struct sam_spidev_s *priv)
 
       ret = priv->outval;
 
-      /* Disable further TXDR/OVRE interrupts until spi_enqueue() is called. */
+      /* Disable further TXDR/OVRE interrupts until spi_enqueue() is called */
 
       regval = (SPI_INT_TDRE | SPI_INT_UNDES);
       spi_putreg(priv, regval, SAM_SPI_IDR_OFFSET);
@@ -728,7 +730,9 @@ static void spi_setbits(struct sam_spidev_s *priv, int nbits)
 
       spiinfo("csr0=%08x\n", regval);
 
-      /* Save the selection so the subsequence re-configurations will be faster */
+      /* Save the selection so the subsequence re-configurations will be
+       * faster
+       */
 
       priv->nbits = nbits;
     }
@@ -763,6 +767,7 @@ static void spi_bind(struct spi_sctrlr_s *sctrlr,
   struct sam_spidev_s *priv = (struct sam_spidev_s *)sctrlr;
   uint32_t regval;
   int ret;
+  FAR const void *data;
 
   spiinfo("sdev=%p mode=%d nbits=%d\n", sdv, mode, nbits);
 
@@ -812,7 +817,8 @@ static void spi_bind(struct spi_sctrlr_s *sctrlr,
    * be shifted out the SPI clock is detected.
    */
 
-  priv->outval = SPI_SDEV_GETDATA(sdev);
+  SPI_SDEV_GETDATA(sdev, &data);
+  priv->outval = *(const uint16_t *)data;
   spi_putreg(priv, priv->outval, SAM_SPI_TDR_OFFSET);
 
   /* Setup to begin normal SPI operation */
@@ -924,7 +930,8 @@ static void spi_unbind(struct spi_sctrlr_s *sctrlr)
  *
  ****************************************************************************/
 
-static int spi_enqueue(struct spi_sctrlr_s *sctrlr, uint16_t data)
+static int spi_enqueue(struct spi_sctrlr_s *sctrlr, FAR const void *data,
+                       size_t nwords)
 {
   struct sam_spidev_s *priv = (struct sam_spidev_s *)sctrlr;
   irqstate_t flags;
@@ -932,7 +939,7 @@ static int spi_enqueue(struct spi_sctrlr_s *sctrlr, uint16_t data)
   int next;
   int ret;
 
-  spiinfo("data=%04x\n", data);
+  spiinfo("data=%04x\n", *(const uint16_t *)data);
   DEBUGASSERT(priv != NULL && priv->sdev != NULL);
 
   /* Get exclusive access to the SPI device */
@@ -966,7 +973,7 @@ static int spi_enqueue(struct spi_sctrlr_s *sctrlr, uint16_t data)
        * be overwritten.
        */
 
-      priv->outq[priv->head] = data;
+      priv->outq[priv->head] = *(const uint16_t *)data;
       priv->head = next;
       ret = OK;