changeset 3197:e9c334bea7c0

New package -- Smartfusion Cortex-M3 SPI driver package. [Bugzilla 1001291]
author vae
date Mon, 12 Mar 2012 20:56:32 +0000
parents b24822708a6c
children 70cc85a5623a
files packages/devs/spi/cortexm/a2fxxx/current/ChangeLog packages/devs/spi/cortexm/a2fxxx/current/cdl/spi_a2fxxx.cdl packages/devs/spi/cortexm/a2fxxx/current/include/spi_a2fxxx.h packages/devs/spi/cortexm/a2fxxx/current/src/spi_a2fxxx.c
diffstat 4 files changed, 1037 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/devs/spi/cortexm/a2fxxx/current/ChangeLog
@@ -0,0 +1,31 @@
+2011-04-13  Christophe Coutand  <ecos@hotmail.co.uk>
+
+    * cdl/spi_a2fxxx.cdl:
+    * include/spi_a2fxxx.h:
+    * src/spi_a2fxxx.c:
+    New package -- Smartfusion Cortex-M3 SPI driver package.
+    [Bugzilla 1001291]
+
+//===========================================================================
+// ####GPLCOPYRIGHTBEGIN####                                                
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2011 Free Software Foundation, Inc.                        
+//
+// This program is free software; you can redistribute it and/or modify     
+// it under the terms of the GNU General Public License as published by     
+// the Free Software Foundation; either version 2 or (at your option) any   
+// later version.                                                           
+//
+// This program is distributed in the hope that it will be useful, but      
+// WITHOUT ANY WARRANTY; without even the implied warranty of               
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        
+// General Public License for more details.                                 
+//
+// You should have received a copy of the GNU General Public License        
+// along with this program; if not, write to the                            
+// Free Software Foundation, Inc., 51 Franklin Street,                      
+// Fifth Floor, Boston, MA  02110-1301, USA.                                
+// -------------------------------------------                              
+// ####GPLCOPYRIGHTEND####                                                  
+//===========================================================================
new file mode 100644
--- /dev/null
+++ b/packages/devs/spi/cortexm/a2fxxx/current/cdl/spi_a2fxxx.cdl
@@ -0,0 +1,175 @@
+##=============================================================================
+##
+##      spi_a2fxxx.cdl
+##
+##      Smartfusion Cortex-M3 SPI driver configuration options.
+##
+##=============================================================================
+## ####ECOSGPLCOPYRIGHTBEGIN####                                            
+## -------------------------------------------                              
+## This file is part of eCos, the Embedded Configurable Operating System.   
+## Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc.
+##
+## eCos is free software; you can redistribute it and/or modify it under    
+## the terms of the GNU General Public License as published by the Free     
+## Software Foundation; either version 2 or (at your option) any later      
+## version.                                                                 
+##
+## eCos is distributed in the hope that it will be useful, but WITHOUT      
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+## FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+## for more details.                                                        
+##
+## You should have received a copy of the GNU General Public License        
+## along with eCos; if not, write to the Free Software Foundation, Inc.,    
+## 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+##
+## As a special exception, if other files instantiate templates or use      
+## macros or inline functions from this file, or you compile this file      
+## and link it with other works to produce a work based on this file,       
+## this file does not by itself cause the resulting work to be covered by   
+## the GNU General Public License. However the source code for this file    
+## must still be made available in accordance with section (3) of the GNU   
+## General Public License v2.                                               
+##
+## This exception does not invalidate any other reasons why a work based    
+## on this file might be covered by the GNU General Public License.         
+## -------------------------------------------                              
+## ####ECOSGPLCOPYRIGHTEND####                                              
+##=============================================================================
+#######DESCRIPTIONBEGIN####
+##
+## Author(s):   ccoutand, updated for Smartfusion Cortex-M3
+## Original(s): Chris Holgate
+## Date:        2011-04-25
+## Purpose:     Configure Smartfusion Cortex-M3 SPI driver.
+##
+######DESCRIPTIONEND####
+##
+##=============================================================================
+
+cdl_package CYGPKG_DEVS_SPI_CORTEXM_A2FXXX {
+    display       "Actel Smartfusion SPI driver"
+    description   "
+        This package provides SPI driver support for the Smartfusion Cortex-M3
+        series of microcontrollers.
+    "
+    parent        CYGPKG_IO_SPI
+    active_if     CYGPKG_IO_SPI
+    requires      CYGPKG_HAL_CORTEXM_A2FXXX
+    hardware
+    include_dir   cyg/io
+    compile       -library=libextras.a spi_a2fxxx.c
+
+    cdl_option CYGDBG_DEVS_SPI_CORTEXM_A2FXXX_TRACE {
+        display       "Display status messages during SPI operations"
+        flavor        bool
+        default_value 0
+        description   "
+           Selecting this option will cause the SPI driver to print status
+           messages as various SPI operations are undertaken."
+    }
+
+    cdl_component CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS1 {
+        display       "Actel Smartfusion SPI bus 1"
+        description   "
+            Enable SPI bus 1 on the A2FXXX device.
+            "
+        flavor        bool
+        default_value false
+
+        cdl_option CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS1_TX_DMA {
+            display       "Transmit DMA channel number"
+            flavor        data
+            default_value 0
+        }
+
+        cdl_option CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS1_RX_DMA {
+            display       "Receive DMA channel number"
+            flavor        data
+            default_value 1
+        }
+
+        cdl_option CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS1_TX_DMA_PRI {
+            display       "Transmit DMA channel priority"
+            legal_values  { "HIGH" "LOW" }
+            flavor        data
+            default_value { "HIGH" }
+        }
+
+        cdl_option CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS1_RX_DMA_PRI {
+            display       "Receive DMA channel priority"
+            legal_values  { "HIGH" "LOW" }
+            flavor        data
+            default_value { "HIGH" }
+        }
+    }
+
+    cdl_component CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS2 {
+        display       "Actel Smartfusion SPI bus 2"
+        description   "
+            Enable SPI bus 2 on the A2FXXX device.
+        "
+        flavor        bool
+        default_value false
+
+        cdl_option CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS2_TX_DMA {
+            display       "Transmit DMA channel number"
+            flavor        data
+            default_value 2
+        }
+
+        cdl_option CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS2_RX_DMA {
+            display       "Receive DMA channel number"
+            flavor        data
+            default_value 3
+        }
+
+        cdl_option CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS2_TX_DMA_PRI {
+            display       "Transmit DMA channel priority"
+            legal_values  { "HIGH" "LOW" }
+            flavor        data
+            default_value { "HIGH" }
+        }
+
+        cdl_option CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS2_RX_DMA_PRI {
+            display       "Receive DMA channel priority"
+            legal_values  { "HIGH" "LOW" }
+            flavor        data
+            default_value { "HIGH" }
+        }
+    }
+
+    cdl_component CYGPKG_DEVS_SPI_CORTEXM_A2FXXX_OPTIONS {
+        display "Actel Smartfusion SPI driver build options"
+        flavor  none
+        description   "
+        Package specific build options including control over
+        compiler flags used only in building this package,
+        and details of which tests are built."
+
+        cdl_option CYGPKG_DEVS_SPI_CORTEXM_A2FXXX_CFLAGS_ADD {
+            display "Additional compiler flags"
+            flavor  data
+            no_define
+            default_value { "" }
+            description   "
+                This option modifies the set of compiler flags for
+                building the A2FXXX SPI driver. These flags are used in addition
+                to the set of global flags."
+        }
+
+        cdl_option CYGPKG_DEVS_SPI_CORTEXM_A2FXXX_CFLAGS_REMOVE {
+            display "Suppressed compiler flags"
+            flavor  data
+            no_define
+            default_value { "" }
+            description   "
+                This option modifies the set of compiler flags for
+                building the A2FXXX SPI driver. These flags are removed from
+                the set of global flags if present."
+        }
+    }
+
+}
+# EOF spi_a2fxxx.cdl
new file mode 100644
--- /dev/null
+++ b/packages/devs/spi/cortexm/a2fxxx/current/include/spi_a2fxxx.h
@@ -0,0 +1,195 @@
+#ifndef CYGONCE_DEVS_SPI_CORTEXM_STM32_H
+# define CYGONCE_DEVS_SPI_CORTEXM_STM32_H
+//=============================================================================
+//
+//      spi_a2fxxx.h
+//
+//      Header definitions for Smartfusion Cortex-M3 SPI driver.
+//
+//=============================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//=============================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):   ccoutand, updated for Smartfusion Cortex-M3
+// Original(s): Chris Holgate
+// Date:        2011-04-25
+// Purpose:     Smartfusion Cortex-M3 SPI driver definitions.
+// Description:
+// Usage:       #include <cyg/io/spi_a2fxxx.h>
+//
+//####DESCRIPTIONEND####
+//
+//=============================================================================
+
+# include <pkgconf/hal.h>
+# include <pkgconf/io_spi.h>
+# include <pkgconf/devs_spi_cortexm_a2fxxx.h>
+
+# include <cyg/infra/cyg_type.h>
+# include <cyg/hal/drv_api.h>
+# include <cyg/io/spi.h>
+
+__externC cyg_uint32 a2fxxx_dma_ch_attach(cyg_uint8, cyg_ISR_t *, cyg_DSR_t *,
+                                          cyg_addrword_t);
+
+typedef enum a2fxxx_spi_mode {
+    A2FXXX_SPI_MOTOROLA       = 0x00,
+    A2FXXX_SPI_TI_SYNC_SERIAL = 0x01,
+    A2FXXX_SPI_NS_MICROWIRE   = 0x02
+} a2fxxx_spi_mode;
+
+//-----------------------------------------------------------------------------
+// Macro for defining a SPI device and attaching it to the appropriate bus.
+//
+// _name_     is the name of the SPI device.  This will be used to reference a
+//            data structure of type cyg_spi_device which can be passed to the
+//            SPI driver API without needing a cast.
+// _bus_      is the bus number to which this device is attached (1, 2 or 3).
+// _csnum_    when _csgpio_ is set to false : is the chip select line used for
+//            this device, numbered from 0.
+//            when _csgpio_ is set to true : is the GPIO number used to drive the
+//            device chip select line.
+// _csgpio_   when set to false, the device chip select line is controlled by the
+//            SPI controller.
+//            when set to true, the device chip select line is a GPIO of the processor
+//            control by the SPI driver.
+// _proto_    is the SPI bus protocol:
+//              0 -> Motorola SPI Protocol (_clpol_ and _clpha_ are valid in this mode)
+//              1 -> National Semiconductor MICROWIRE Protocol
+//              2 -> Texas Instruments (TI) Synchronous Serial Protocol
+// _clpol_    is the SPI bus clock polarity used by the device.  This must be
+//            set to 1 if a clock line pullup resistor is used and 0 if a
+//            clock line pulldown resistor is used.
+// _clpha_    is the SPI bus clock phase used by the device.
+// _brate_    is the SPI bus clock baud rate used by the device, measured in Hz.
+// _csup_dly_ is the minimum delay between chip select assert and transfer
+//            start, measured in microseconds.
+// _csdw_dly_ is the minimum delay between transfer end and chip select deassert,
+//            measured in microseconds.
+// _trbt_dly_ is the minimum delay between consecutive transfers.
+
+# define CYG_DEVS_SPI_CORTEXM_A2FXXX_DEVICE( \
+  _name_, _bus_, _csnum_, _csgpio_, _proto_, _clpol_, _clpha_, _brate_, _csup_dly_, _csdw_dly_, _trbt_dly_\
+) \
+cyg_spi_cortexm_a2fxxx_device_t _name_ ##_a2fxxx CYG_SPI_DEVICE_ON_BUS(_bus_) = { \
+{ .spi_bus    = (cyg_spi_bus*) &cyg_spi_a2fxxx_bus## _bus_ }, \
+  .dev_num    = _csnum_,     \
+  .cs_gpio    = _csgpio_,    \
+  .cs_gpio_n  = _csnum_,     \
+  .proto      = _proto_,     \
+  .cl_pol     = _clpol_,     \
+  .cl_pha     = _clpha_,     \
+  .cl_brate   = _brate_,     \
+  .cs_up_udly = _csup_dly_,  \
+  .cs_dw_udly = _csdw_dly_,  \
+  .tr_bt_udly = _trbt_dly_,  \
+  .spi_cr_val = 0,           \
+}; \
+extern cyg_spi_device _name_ __attribute__((alias ( #_name_ "_a2fxxx" )));
+
+//-----------------------------------------------------------------------------
+// A2FXXX SPI bus configuration and state.
+
+typedef struct cyg_spi_cortexm_a2fxxx_bus_setup_s {
+    cyg_uint32      apb_freq;          // Peripheral bus frequency (fp).
+    cyg_haladdress  spi_reg_base;      // Base address of SPI register block.
+    cyg_haladdress  dma_reg_base;      // Base address of DMA register block.
+    cyg_uint8       dma_tx_channel;    // TX DMA channel for this bus.
+    cyg_uint8       dma_rx_channel;    // RX DMA channel for this bus.
+    cyg_uint8       cs_gpio_num;       // Number of chip selects for this bus.
+    const cyg_uint8 *cs_gpio_list;     // List of GPIOs used as chip selects.
+    const cyg_uint8 *spi_gpio_list;    // List of GPIOs used by the SPI interface.
+    cyg_bool        dma_tx_pri;        // Priority for DMA transmit.
+    cyg_bool        dma_rx_pri;        // Priority for DMA receive.
+    cyg_haladdress  *rx_dma_null;
+    cyg_haladdress  *tx_dma_null;
+} cyg_spi_cortexm_a2fxxx_bus_setup_t;
+
+typedef struct cyg_spi_cortexm_a2fxxx_bus_s {
+    // ---- Upper layer data ----
+    cyg_spi_bus     spi_bus;           // Upper layer SPI bus data.
+
+    // ---- Bus configuration constants ----
+    const cyg_spi_cortexm_a2fxxx_bus_setup_t *setup;
+
+    // ---- Driver state (private) ----
+    cyg_interrupt   tx_intr_data;      // DMA interrupt data (TX).
+    cyg_interrupt   rx_intr_data;      // DMA interrupt data (RX).
+    cyg_handle_t    tx_intr_handle;    // DMA interrupt handle (TX).
+    cyg_handle_t    rx_intr_handle;    // DMA interrupt handle (RX).
+    cyg_drv_mutex_t mutex;             // Transfer mutex.
+    cyg_drv_cond_t  condvar;           // Transfer condition variable.
+    cyg_bool        tx_dma_done;       // Flags used to signal completion.
+    cyg_bool        rx_dma_done;       // Flags used to signal completion.
+    cyg_bool        cs_up;             // Chip select asserted flag.
+
+} cyg_spi_cortexm_a2fxxx_bus_t;
+
+//-----------------------------------------------------------------------------
+// A2FXXX SPI device.
+
+typedef struct cyg_spi_cortexm_a2fxxx_device_s {
+    // ---- Upper layer data ----
+    cyg_spi_device  spi_device;        // Upper layer SPI device data.
+
+    // ---- Device setup (user configurable) ----
+    cyg_uint8       dev_num;           // Device number.
+    a2fxxx_spi_mode proto;             // Protocol
+    cyg_bool        cs_gpio;           // True = use GPIO to control CS line
+    cyg_uint32      cs_gpio_n;         // GPIO #
+    cyg_uint8       cl_pol;            // Clock polarity (0 or 1).
+    cyg_uint8       cl_pha;            // Clock phase    (0 or 1).
+    cyg_uint32      cl_brate;          // Clock baud rate.
+    cyg_uint16      cs_up_udly;        // Minimum delay in us between CS up and transfer start.
+    cyg_uint16      cs_dw_udly;        // Minimum delay in us between transfer end and CS down.
+    cyg_uint16      tr_bt_udly;        // Minimum delay in us between two transfers.
+
+    // ---- Device state (private) ----
+    cyg_uint32      spi_cr_val;        // SPI configuration register (initialised to 0).
+
+} cyg_spi_cortexm_a2fxxx_device_t;
+
+//-----------------------------------------------------------------------------
+// Exported bus data structures.
+
+# ifdef CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS1
+externC cyg_spi_cortexm_a2fxxx_bus_t cyg_spi_a2fxxx_bus1;
+# endif
+
+# ifdef CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS2
+externC cyg_spi_cortexm_a2fxxx_bus_t cyg_spi_a2fxxx_bus2;
+# endif
+
+//=============================================================================
+#endif // CYGONCE_DEVS_SPI_CORTEXM_A2FXXX_H
new file mode 100644
--- /dev/null
+++ b/packages/devs/spi/cortexm/a2fxxx/current/src/spi_a2fxxx.c
@@ -0,0 +1,636 @@
+//=============================================================================
+//
+//      spi_a2fxxx.c
+//
+//      SPI driver implementation for Smartfusion Cortex-M3
+//
+//=============================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//=============================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):   ccoutand, updated for Smartfusion Cortex-M3
+// Original(s): Chris Holgate
+// Date:        2011-04-25
+// Purpose:     Smartfusion Cortex-M3 SPI driver implementation
+//
+//####DESCRIPTIONEND####
+//
+//=============================================================================
+
+#include <cyg/hal/hal_io.h>
+#include <cyg/hal/hal_if.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/hal/drv_api.h>
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/diag.h>
+
+#include <cyg/io/spi.h>
+#include <cyg/io/spi_a2fxxx.h>
+
+#include <pkgconf/devs_spi_cortexm_a2fxxx.h>
+
+#include <string.h>
+
+#if defined(CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS1) || \
+      defined(CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS2)
+
+#ifdef CYGDBG_DEVS_SPI_CORTEXM_A2FXXX_TRACE
+# define SPI_TRACE(args...) diag_printf(args)
+#else
+# define SPI_TRACE(args...)
+#endif
+
+//-----------------------------------------------------------------------------
+// API function call forward references.
+
+static void a2fxxx_transaction_begin    (cyg_spi_device*);
+static void a2fxxx_transaction_transfer (cyg_spi_device*, cyg_bool, cyg_uint32, const cyg_uint8*, cyg_uint8*, cyg_bool);
+static void a2fxxx_transaction_tick     (cyg_spi_device*, cyg_bool, cyg_uint32);
+static void a2fxxx_transaction_end      (cyg_spi_device*);
+static int  a2fxxx_get_config           (cyg_spi_device*, cyg_uint32, void*, cyg_uint32*);
+static int  a2fxxx_set_config           (cyg_spi_device*, cyg_uint32, const void*, cyg_uint32*);
+
+//-----------------------------------------------------------------------------
+// Instantiate the bus state data structures.
+
+#ifdef CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS1
+
+static cyg_haladdress rx1_dma_null = 0x0;
+static cyg_haladdress tx1_dma_null = 0x0;
+
+static const cyg_spi_cortexm_a2fxxx_bus_setup_t bus1_setup = {
+    .spi_reg_base                     = CYGHWR_HAL_A2FXXX_SPI0,
+    .dma_reg_base                     = CYGHWR_HAL_A2FXXX_DMA,
+    .dma_tx_channel                   = CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS1_TX_DMA,
+    .dma_rx_channel                   = CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS1_RX_DMA,
+#ifdef CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS1_TX_DMA_PRI_HIGH
+    .dma_tx_pri                       = true,
+#else
+    .dma_tx_pri                       = false,
+#endif
+#ifdef CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS1_RX_DMA_PRI_HIGH
+    .dma_rx_pri                       = true,
+#else
+    .dma_rx_pri                       = false,
+#endif
+    .rx_dma_null                      = &rx1_dma_null,
+    .tx_dma_null                      = &tx1_dma_null,
+};
+
+cyg_spi_cortexm_a2fxxx_bus_t cyg_spi_a2fxxx_bus1 = {
+    .spi_bus.spi_transaction_begin    = a2fxxx_transaction_begin,
+    .spi_bus.spi_transaction_transfer = a2fxxx_transaction_transfer,
+    .spi_bus.spi_transaction_tick     = a2fxxx_transaction_tick,
+    .spi_bus.spi_transaction_end      = a2fxxx_transaction_end,
+    .spi_bus.spi_get_config           = a2fxxx_get_config,
+    .spi_bus.spi_set_config           = a2fxxx_set_config,
+    .setup                            = &bus1_setup,
+    .cs_up                            = false
+};
+#endif
+
+#ifdef CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS2
+
+static cyg_haladdress rx2_dma_null = 0x0;
+static cyg_haladdress tx2_dma_null = 0x0;
+
+static const cyg_spi_cortexm_a2fxxx_bus_setup_t bus2_setup = {
+    .spi_reg_base                     = CYGHWR_HAL_A2FXXX_SPI1,
+    .dma_reg_base                     = CYGHWR_HAL_A2FXXX_DMA,
+    .dma_tx_channel                   = CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS2_TX_DMA,
+    .dma_rx_channel                   = CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS2_RX_DMA,
+#ifdef CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS2_TX_DMA_PRI_HIGH
+    .dma_tx_pri                       = true,
+#else
+    .dma_tx_pri                       = false,
+#endif
+#ifdef CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS2_RX_DMA_PRI_HIGH
+    .dma_rx_pri                       = true,
+#else
+    .dma_rx_pri                       = false,
+#endif
+    .rx_dma_null                      = &rx2_dma_null,
+    .tx_dma_null                      = &tx2_dma_null,
+};
+
+cyg_spi_cortexm_a2fxxx_bus_t cyg_spi_a2fxxx_bus2 = {
+    .spi_bus.spi_transaction_begin    = a2fxxx_transaction_begin,
+    .spi_bus.spi_transaction_transfer = a2fxxx_transaction_transfer,
+    .spi_bus.spi_transaction_tick     = a2fxxx_transaction_tick,
+    .spi_bus.spi_transaction_end      = a2fxxx_transaction_end,
+    .spi_bus.spi_get_config           = a2fxxx_get_config,
+    .spi_bus.spi_set_config           = a2fxxx_set_config,
+    .setup                            = &bus2_setup,
+    .cs_up                            = false
+};
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Implement DMA ISRs.  These clear the DMA channel interrupts and
+// schedule their respective DSRs.
+
+static cyg_uint32 a2fxxx_tx_ISR
+  (cyg_vector_t vector, cyg_addrword_t data)
+{
+    cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus =
+                                  (cyg_spi_cortexm_a2fxxx_bus_t*) data;
+    cyg_uint8 chan = a2fxxx_bus->setup->dma_tx_channel;
+    SPI_TRACE("SPI : Handle TX ISR\n");
+    a2fxxx_dma_clear_interrupt ( chan );
+    return (CYG_ISR_CALL_DSR | CYG_ISR_HANDLED);
+}
+
+static cyg_uint32 a2fxxx_rx_ISR
+  (cyg_vector_t vector, cyg_addrword_t data)
+{
+    cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus =
+                                  (cyg_spi_cortexm_a2fxxx_bus_t*) data;
+    cyg_uint8 chan = a2fxxx_bus->setup->dma_rx_channel;
+    SPI_TRACE("SPI : Handle RX ISR\n");
+    a2fxxx_dma_clear_interrupt ( chan );
+    return (CYG_ISR_CALL_DSR | CYG_ISR_HANDLED);
+}
+
+//-----------------------------------------------------------------------------
+// Implement DMA DSRs.  These clear down the interrupt conditions and assert
+// their respective 'transaction complete' flags.
+
+static void a2fxxx_tx_DSR
+  (cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+    cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus =
+                                  (cyg_spi_cortexm_a2fxxx_bus_t*) data;
+    SPI_TRACE("SPI : Handle TX DSR\n");
+    cyg_drv_dsr_lock ();
+    a2fxxx_bus->tx_dma_done = true;
+    cyg_drv_cond_signal (&a2fxxx_bus->condvar);
+    cyg_drv_dsr_unlock ();
+}
+
+static void a2fxxx_rx_DSR
+  (cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+    cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus =
+                                  (cyg_spi_cortexm_a2fxxx_bus_t*) data;
+    SPI_TRACE("SPI : Handle RX DSR\n");
+    cyg_drv_dsr_lock ();
+    a2fxxx_bus->rx_dma_done = true;
+    cyg_drv_cond_signal (&a2fxxx_bus->condvar);
+    cyg_drv_dsr_unlock ();
+}
+
+//-----------------------------------------------------------------------------
+// Set up a new SPI bus on initialization.
+
+static void a2fxxx_spi_bus_setup
+  (cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus)
+{
+    cyg_uint8 dma_tx_type, dma_rx_type;
+
+    if( a2fxxx_bus->setup->spi_reg_base == CYGHWR_HAL_A2FXXX_SPI1 ){
+        CYGHWR_HAL_A2FXXX_GPIO_SET( CYGHWR_HAL_A2FXXX_SPI1_DO );
+        CYGHWR_HAL_A2FXXX_GPIO_SET( CYGHWR_HAL_A2FXXX_SPI1_DI );
+        CYGHWR_HAL_A2FXXX_GPIO_SET( CYGHWR_HAL_A2FXXX_SPI1_CLK );
+        dma_tx_type = CYGHWR_HAL_A2FXXX_DMA_XFER(TO_SPI1);
+        dma_rx_type = CYGHWR_HAL_A2FXXX_DMA_XFER(FROM_SPI1);
+    }
+    else {
+        CYGHWR_HAL_A2FXXX_GPIO_SET( CYGHWR_HAL_A2FXXX_SPI0_DO );
+        CYGHWR_HAL_A2FXXX_GPIO_SET( CYGHWR_HAL_A2FXXX_SPI0_DI );
+        CYGHWR_HAL_A2FXXX_GPIO_SET( CYGHWR_HAL_A2FXXX_SPI0_CLK );
+        dma_tx_type = CYGHWR_HAL_A2FXXX_DMA_XFER(TO_SPI0);
+        dma_rx_type = CYGHWR_HAL_A2FXXX_DMA_XFER(FROM_SPI0);
+    }
+
+    // Initialize the synchronization primitives.
+    cyg_drv_mutex_init (&a2fxxx_bus->mutex);
+    cyg_drv_cond_init (&a2fxxx_bus->condvar, &a2fxxx_bus->mutex);
+
+    // Setup DMA channel
+    a2fxxx_dma_ch_setup(a2fxxx_bus->setup->dma_tx_channel, dma_tx_type,
+             CYGHWR_HAL_A2FXXX_DMA_OUTBOUND, sizeof(cyg_uint8), 0,
+             a2fxxx_bus->setup->dma_tx_pri, 9);
+    a2fxxx_dma_ch_setup(a2fxxx_bus->setup->dma_rx_channel, dma_rx_type,
+             CYGHWR_HAL_A2FXXX_DMA_INBOUND, 0, sizeof(cyg_uint8),
+             a2fxxx_bus->setup->dma_rx_pri, 9);
+
+    // Register ISR /DSR
+    a2fxxx_dma_ch_attach(a2fxxx_bus->setup->dma_tx_channel,
+              a2fxxx_tx_ISR, a2fxxx_tx_DSR, (cyg_addrword_t) a2fxxx_bus);
+
+    a2fxxx_dma_ch_attach(a2fxxx_bus->setup->dma_rx_channel,
+              a2fxxx_rx_ISR, a2fxxx_rx_DSR, (cyg_addrword_t) a2fxxx_bus);
+
+    // Call upper layer bus init.
+    CYG_SPI_BUS_COMMON_INIT(&a2fxxx_bus->spi_bus);
+}
+
+//-----------------------------------------------------------------------------
+// Drive a GPIO pin as a SPI chip select line.
+
+static inline void a2fxxx_spi_chip_select
+  (cyg_spi_device* device, cyg_bool assert)
+{
+    cyg_spi_cortexm_a2fxxx_device_t* a2fxxx_device =
+                  (cyg_spi_cortexm_a2fxxx_device_t*) device;
+    cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus =
+                  (cyg_spi_cortexm_a2fxxx_bus_t*) device->spi_bus;
+
+    // CS is driven from GPIO
+    if( a2fxxx_device->cs_gpio == true) {
+        if (assert == true)
+            CYGHWR_HAL_A2FXXX_GPIO_OUT( a2fxxx_device->cs_gpio_n, 0 );
+        else
+            CYGHWR_HAL_A2FXXX_GPIO_OUT( a2fxxx_device->cs_gpio_n, 1 );
+    }
+    // CS is driven from controller
+    else {
+        cyg_uint32 reg_addr = a2fxxx_bus->setup->spi_reg_base +
+                                        CYGHWR_HAL_A2FXXX_SPI_SLAVE_SEL;
+        cyg_uint32 reg_data;
+        HAL_READ_UINT32 (reg_addr, reg_data);
+        if (assert == true)
+            reg_data |= CYGHWR_HAL_A2FXXX_SPI_CS_SEL(a2fxxx_device->dev_num);
+        else
+            reg_data &= ~CYGHWR_HAL_A2FXXX_SPI_CS_SEL(a2fxxx_device->dev_num);
+        HAL_WRITE_UINT32 (reg_addr, reg_data);
+    }
+}
+
+//-----------------------------------------------------------------------------
+// Configure build-in SPI chip select line
+
+static inline void a2fxxx_spi_set_ss
+  (cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus, cyg_uint8 ss_num)
+{
+    cyg_uint32 ss;
+
+    if( a2fxxx_bus->setup->spi_reg_base == CYGHWR_HAL_A2FXXX_SPI0 ){
+        if ( ss_num == 0 ) {
+            ss = CYGHWR_HAL_A2FXXX_SPI0_SS0;
+        } else if( ss_num == 1 ) {
+            ss = CYGHWR_HAL_A2FXXX_SPI0_SS1;
+        } else if( ss_num == 2 ) {
+            ss = CYGHWR_HAL_A2FXXX_SPI0_SS2;
+        } else if( ss_num == 3 ) {
+            ss = CYGHWR_HAL_A2FXXX_SPI0_SS3;
+        } else {
+            CYG_ASSERT (ss < 4, "SPI : SPI0 SS out of range.");
+        }
+    }
+    else {
+        if ( ss_num == 0 ) {
+            ss = CYGHWR_HAL_A2FXXX_SPI1_SS0;
+        } else if( ss_num == 1 ) {
+            ss = CYGHWR_HAL_A2FXXX_SPI1_SS1;
+        } else if( ss_num == 2 ) {
+            ss = CYGHWR_HAL_A2FXXX_SPI1_SS2;
+        } else if( ss_num == 3 ) {
+            ss = CYGHWR_HAL_A2FXXX_SPI1_SS3;
+        } else if( ss_num == 4 ) {
+            ss = CYGHWR_HAL_A2FXXX_SPI1_SS4;
+        } else if( ss_num == 5 ) {
+            ss = CYGHWR_HAL_A2FXXX_SPI1_SS5;
+        } else if( ss_num == 6 ) {
+            ss = CYGHWR_HAL_A2FXXX_SPI1_SS6;
+        } else if( ss_num == 7 ) {
+            ss = CYGHWR_HAL_A2FXXX_SPI1_SS7;
+        } else {
+            CYG_ASSERT (ss < 8, "SPI : SPI1 SS out of range.");
+        }
+    }
+
+    CYGHWR_HAL_A2FXXX_GPIO_SET( ss );
+}
+
+//-----------------------------------------------------------------------------
+// Initiate a DMA transfer over the SPI interface.
+
+static void spi_transaction_dma
+  (cyg_spi_device* device, cyg_bool tick_only, cyg_bool polled, cyg_uint32 count,
+  const cyg_uint8* tx_data, cyg_uint8* rx_data, cyg_bool drop_cs)
+{
+    cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus =
+                (cyg_spi_cortexm_a2fxxx_bus_t*) device->spi_bus;
+    cyg_spi_cortexm_a2fxxx_device_t* a2fxxx_device =
+                (cyg_spi_cortexm_a2fxxx_device_t*) device;
+    cyg_haladdress reg_addr;
+    cyg_uint32 spi_cr_val = a2fxxx_device->spi_cr_val;
+    cyg_haladdress spi_reg_base = a2fxxx_bus->setup->spi_reg_base;
+
+    SPI_TRACE("SPI : Transfer start\n");
+
+    // Drive chip select low, either from GPIO or build in SS signal
+    if( !a2fxxx_bus->cs_up && !tick_only ){
+        SPI_TRACE("SPI : Setup CS\n");
+        CYGACC_CALL_IF_DELAY_US (a2fxxx_device->tr_bt_udly);
+        a2fxxx_spi_chip_select (device, true);
+        CYGACC_CALL_IF_DELAY_US (a2fxxx_device->cs_up_udly);
+        a2fxxx_bus->cs_up = true;
+    }
+
+    // Disable the SPI controller.
+    reg_addr = spi_reg_base + CYGHWR_HAL_A2FXXX_SPI_CTRL;
+    HAL_WRITE_UINT32 (reg_addr, a2fxxx_device->spi_cr_val);
+
+    // Write down transfer count
+    spi_cr_val |= CYGHWR_HAL_A2FXXX_SPI_CTRL_COUNT( count );
+    reg_addr = spi_reg_base + CYGHWR_HAL_A2FXXX_SPI_CTRL;
+    HAL_WRITE_UINT32 (reg_addr, spi_cr_val);
+
+    //
+    // Setup DMA channels
+    // For null source or destination pointer, replace the buffer with the SPI driver
+    // dummy buffer and set the DMA address increment to 0
+    //
+    if(tx_data == NULL)
+        a2fxxx_dma_update_incr(a2fxxx_bus->setup->dma_tx_channel, false, 0);
+    else
+        a2fxxx_dma_update_incr(a2fxxx_bus->setup->dma_tx_channel, false,
+                                                          sizeof(cyg_uint8));
+
+    if(rx_data == NULL)
+        a2fxxx_dma_update_incr(a2fxxx_bus->setup->dma_rx_channel, true, 0);
+    else
+        a2fxxx_dma_update_incr(a2fxxx_bus->setup->dma_rx_channel, true,
+                                                          sizeof(cyg_uint8));
+
+    a2fxxx_bus->tx_dma_done = false;
+    a2fxxx_dma_xfer (a2fxxx_bus->setup->dma_tx_channel, polled, count,
+         ((tx_data == NULL) ? (cyg_uint8*) a2fxxx_bus->setup->tx_dma_null :
+          (cyg_uint8*) tx_data),
+          (cyg_uint8*)(a2fxxx_bus->setup->spi_reg_base + CYGHWR_HAL_A2FXXX_SPI_TX));
+
+    a2fxxx_bus->rx_dma_done = false;
+    a2fxxx_dma_xfer (a2fxxx_bus->setup->dma_rx_channel, polled, count,
+          (cyg_uint8*)(a2fxxx_bus->setup->spi_reg_base + CYGHWR_HAL_A2FXXX_SPI_RX),
+         ((rx_data == NULL) ? (cyg_uint8*) a2fxxx_bus->setup->rx_dma_null :
+          (cyg_uint8*) rx_data));
+
+    //
+    // Run the DMA (polling for completion).
+    //
+    if (polled)
+    {
+        // Enable the SPI controller.
+        SPI_TRACE("SPI : Control Register 0x%x, 0x%x, %d\n", reg_addr,
+                   spi_cr_val, count);
+        HAL_WRITE_UINT32 (reg_addr, spi_cr_val | CYGHWR_HAL_A2FXXX_SPI_CTRL_EN);
+
+        // Wait transfer completed.
+        do {
+            if(a2fxxx_dma_get_comp_flag(a2fxxx_bus->setup->dma_rx_channel))
+                a2fxxx_bus->rx_dma_done = true;
+            if(a2fxxx_dma_get_comp_flag(a2fxxx_bus->setup->dma_tx_channel))
+                a2fxxx_bus->tx_dma_done = true;
+        } while ( !(a2fxxx_bus->tx_dma_done && a2fxxx_bus->rx_dma_done) );
+
+        // Acknowledge transfer
+        a2fxxx_dma_clear_interrupt (a2fxxx_bus->setup->dma_rx_channel);
+        a2fxxx_dma_clear_interrupt (a2fxxx_bus->setup->dma_tx_channel);
+
+    } else {
+        cyg_drv_mutex_lock (&a2fxxx_bus->mutex);
+        cyg_drv_dsr_lock ();
+
+        // Enable the SPI controller.
+        SPI_TRACE("SPI : Control Register 0x%x, 0x%x, %d\n", reg_addr,
+                   spi_cr_val, count);
+        HAL_WRITE_UINT32 (reg_addr, spi_cr_val | CYGHWR_HAL_A2FXXX_SPI_CTRL_EN);
+
+        // Sit back and wait for the ISR/DSRs to signal completion.
+        do {
+            cyg_drv_cond_wait (&a2fxxx_bus->condvar);
+        } while (!(a2fxxx_bus->tx_dma_done && a2fxxx_bus->rx_dma_done));
+
+        cyg_drv_dsr_unlock ();
+        cyg_drv_mutex_unlock (&a2fxxx_bus->mutex);
+    }
+
+    SPI_TRACE("SPI : Transfer completed\n");
+
+    if (drop_cs && !tick_only) {
+        SPI_TRACE("SPI : Release chip select\n");
+        CYGACC_CALL_IF_DELAY_US (a2fxxx_device->cs_dw_udly);
+        a2fxxx_spi_chip_select (device, false);
+        a2fxxx_bus->cs_up = false;
+    }
+}
+
+//-----------------------------------------------------------------------------
+// Initialize SPI interfaces on startup.
+
+static void CYGBLD_ATTRIB_C_INIT_PRI(CYG_INIT_BUS_SPI)
+a2fxxx_spi_init(void)
+{
+    hal_dma_init();
+
+#ifdef CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS1
+    CYGHWR_HAL_A2FXXX_PERIPH_RELEASE( CYGHWR_HAL_A2FXXX_PERIPH_SOFTRST(SPI0) );
+    a2fxxx_spi_bus_setup (&cyg_spi_a2fxxx_bus1);
+#endif
+
+#ifdef CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS2
+    CYGHWR_HAL_A2FXXX_PERIPH_RELEASE( CYGHWR_HAL_A2FXXX_PERIPH_SOFTRST(SPI1) );
+    a2fxxx_spi_bus_setup (&cyg_spi_a2fxxx_bus2);
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Start a SPI transaction.
+
+static void a2fxxx_transaction_begin
+  (cyg_spi_device* device)
+{
+    cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus =
+                  (cyg_spi_cortexm_a2fxxx_bus_t*) device->spi_bus;
+    cyg_spi_cortexm_a2fxxx_device_t* a2fxxx_device =
+                  (cyg_spi_cortexm_a2fxxx_device_t*) device;
+
+    cyg_haladdress reg_addr;
+    cyg_uint32 reg_data, divided_clk, br, cs_gpio_n;
+
+    SPI_TRACE("SPI : Transfer begin\n");
+    SPI_TRACE("SPI : Device baud rate = %d\n",      a2fxxx_device->cl_brate);
+    SPI_TRACE("SPI : Device clock polarity = %d\n", a2fxxx_device->cl_pol);
+    SPI_TRACE("SPI : Device clock phase = %d\n",    a2fxxx_device->cl_pha);
+
+    // On the first transaction, generate the values to be programmed into the
+    // SPI configuration registers for this device and cache them.  This avoids
+    // having to recalculate the values for every transaction.
+    if (!a2fxxx_device->spi_cr_val) {
+
+        // SPI bus protocol
+        switch( a2fxxx_device->proto ) {
+        case A2FXXX_SPI_TI_SYNC_SERIAL:
+            reg_data = CYGHWR_HAL_A2FXXX_SPI_CTRL_PROTO_TI;
+            break;
+        case A2FXXX_SPI_NS_MICROWIRE:
+            reg_data = CYGHWR_HAL_A2FXXX_SPI_CTRL_PROTO_NS;
+            break;
+        default:
+            reg_data = CYGHWR_HAL_A2FXXX_SPI_CTRL_PROTO_MOTOROLA;
+            break;
+        }
+
+        // Bus polarity
+        if (a2fxxx_device->cl_pol)
+            reg_data |= CYGHWR_HAL_A2FXXX_SPI_CTRL_SPO;
+        if (a2fxxx_device->cl_pha)
+            reg_data |= CYGHWR_HAL_A2FXXX_SPI_CTRL_SPH;
+
+        // Master mode
+        reg_data |= CYGHWR_HAL_A2FXXX_SPI_CTRL_MASTER;
+
+        // Calculate the maximum viable bus speed.
+        divided_clk = hal_a2fxxx_spi_clock(a2fxxx_bus->setup->spi_reg_base) >> 1;
+        for (br = 0; (br < 7) && (divided_clk > a2fxxx_device->cl_brate); br++)
+            divided_clk >>= 1;
+
+        CYG_ASSERT (divided_clk <= a2fxxx_device->cl_brate,
+            "A2FXXX SPI : Cannot run bus slowly enough for peripheral.");
+
+        SPI_TRACE("SPI : Clock divider = %d\n", divided_clk);
+
+        reg_addr = a2fxxx_bus->setup->spi_reg_base +
+                   CYGHWR_HAL_A2FXXX_SPI_CLK_GEN;
+        HAL_WRITE_UINT32 (reg_addr, br);
+
+        // Set transfer size (byte mode)
+        reg_addr = a2fxxx_bus->setup->spi_reg_base +
+                   CYGHWR_HAL_A2FXXX_SPI_TXRXDF_SIZE;
+        HAL_WRITE_UINT32 (reg_addr, 8);
+
+        // Cache the configuration register settings.
+        a2fxxx_device->spi_cr_val = reg_data;
+
+        // Configure GPIO as chip select
+        if(a2fxxx_device->cs_gpio == true) {
+            cs_gpio_n = a2fxxx_device->cs_gpio_n;
+            SPI_TRACE("SPI : Setup GPIO for CS => %d\n", cs_gpio_n);
+            a2fxxx_device->cs_gpio_n =
+                CYGHWR_HAL_A2FXXX_CS_GPIO( cs_gpio_n,  OUT, cs_gpio_n, DISABLE );
+            CYGHWR_HAL_A2FXXX_GPIO_SET( a2fxxx_device->cs_gpio_n );
+            CYGHWR_HAL_A2FXXX_GPIO_OUT( a2fxxx_device->cs_gpio_n, 1);
+        }
+        // Configure build-in SPI chip select line
+        else {
+           SPI_TRACE("SPI : Setup SPI SS => %d\n", a2fxxx_device->dev_num);
+           a2fxxx_spi_set_ss(a2fxxx_bus, a2fxxx_device->dev_num);
+        }
+    }
+
+    // Set up the SPI controller.
+    reg_addr = a2fxxx_bus->setup->spi_reg_base + CYGHWR_HAL_A2FXXX_SPI_CTRL;
+    HAL_WRITE_UINT32 (reg_addr, a2fxxx_device->spi_cr_val);
+}
+
+//-----------------------------------------------------------------------------
+// Run a transaction transfer.
+
+static void a2fxxx_transaction_transfer
+  (cyg_spi_device* device, cyg_bool polled, cyg_uint32 count,
+  const cyg_uint8* tx_data, cyg_uint8* rx_data, cyg_bool drop_cs)
+{
+    // Check for unsupported transactions.
+    CYG_ASSERT (count > 0, "A2FXXX SPI : Null transfer requested.");
+
+    // Perform transfer
+    spi_transaction_dma (device, false, polled, count, tx_data, rx_data, drop_cs);
+}
+
+//-----------------------------------------------------------------------------
+// Carry out a bus tick operation - this just pushes the required number of
+// zeros onto the bus, leaving the chip select in its current state.
+
+static void a2fxxx_transaction_tick
+  (cyg_spi_device* device, cyg_bool polled, cyg_uint32 count)
+{
+    // Check for unsupported transactions.
+    CYG_ASSERT (count > 0, "A2FXXX SPI : Null transfer requested.");
+
+    SPI_TRACE("SPI : Transfer tick\n");
+
+    // Perform null transfer.
+    spi_transaction_dma (device, true, polled, count, NULL, NULL, false);
+}
+
+//-----------------------------------------------------------------------------
+// Terminate a SPI transaction, disabling the SPI controller.
+
+static void a2fxxx_transaction_end
+  (cyg_spi_device* device)
+{
+    cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus =
+                             (cyg_spi_cortexm_a2fxxx_bus_t*) device->spi_bus;
+    cyg_spi_cortexm_a2fxxx_device_t* a2fxxx_device =
+                                   (cyg_spi_cortexm_a2fxxx_device_t*) device;
+    cyg_haladdress reg_addr;
+
+    SPI_TRACE("SPI : Transfer end\n");
+
+    // De-assert chip select
+    if( a2fxxx_bus->cs_up == true ){
+        SPI_TRACE("SPI : Release chip select\n");
+        CYGACC_CALL_IF_DELAY_US (a2fxxx_device->cs_dw_udly);
+        a2fxxx_spi_chip_select (device, false);
+        a2fxxx_bus->cs_up = false;
+    }
+
+    // Disable controller
+    reg_addr = a2fxxx_bus->setup->spi_reg_base + CYGHWR_HAL_A2FXXX_SPI_CTRL;
+    HAL_WRITE_UINT32 (reg_addr, a2fxxx_device->spi_cr_val);
+}
+
+//-----------------------------------------------------------------------------
+// Note that no dynamic configuration options are currently defined.
+
+static int a2fxxx_get_config
+  (cyg_spi_device* dev, cyg_uint32 key, void* buf, cyg_uint32* len)
+{
+    return -1;
+}
+
+static int a2fxxx_set_config
+  (cyg_spi_device* dev, cyg_uint32 key, const void* buf, cyg_uint32* len)
+{
+    return -1;
+}
+
+#endif
+
+//=============================================================================