Mercurial > nand-ecoscentric
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 + +//=============================================================================
