summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2011-07-24 10:59:32 +0200
committerHarald Welte <laforge@gnumonks.org>2011-07-24 10:59:32 +0200
commit7268260e100caf8efb12193b12442574c5d4b193 (patch)
treed8315c9f66a8b894dda8ca6c6c590d5cb7e9b50d
parent7dd5963915d405866595439aef4c47b8eee83edf (diff)
import 'memories' part of at91lib from serialflash-example
-rw-r--r--at91lib/memories/spi-flash/at26.c222
-rw-r--r--at91lib/memories/spi-flash/at26.h252
-rw-r--r--at91lib/memories/spi-flash/spid.c215
-rw-r--r--at91lib/memories/spi-flash/spid.h183
4 files changed, 872 insertions, 0 deletions
diff --git a/at91lib/memories/spi-flash/at26.c b/at91lib/memories/spi-flash/at26.c
new file mode 100644
index 0000000..d7934c9
--- /dev/null
+++ b/at91lib/memories/spi-flash/at26.c
@@ -0,0 +1,222 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "at26.h"
+#include <board.h>
+#include <utility/assert.h>
+
+//------------------------------------------------------------------------------
+// Internal definitions
+//------------------------------------------------------------------------------
+
+/// SPI clock frequency used in Hz.
+#define SPCK 1000000
+
+/// SPI chip select configuration value.
+#define CSR (AT91C_SPI_NCPHA | \
+ SPID_CSR_DLYBCT(BOARD_MCK, 100) | \
+ SPID_CSR_DLYBS(BOARD_MCK, 5) | \
+ SPID_CSR_SCBR(BOARD_MCK, SPCK))
+
+/// Number of recognized dataflash.
+#define NUMDATAFLASH (sizeof(at26Devices) / sizeof(At26Desc))
+
+//------------------------------------------------------------------------------
+// Internal variables
+//------------------------------------------------------------------------------
+
+/// Array of recognized serial firmware dataflash chips.
+static const At26Desc at26Devices[] = {
+ // name, Jedec ID, size, page size, block size, block erase command
+ {"AT25DF041A" , 0x0001441F, 1 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"AT25DF161" , 0x0002461F, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"AT26DF081A" , 0x0001451F, 1 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"AT26DF0161" , 0x0000461F, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"AT26DF161A" , 0x0001461F, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"AT26DF321 " , 0x0000471F, 8 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ // Manufacturer: ST
+ {"M25P05" , 0x00102020, 64 * 1024, 256, 32 * 1024, AT26_BLOCK_ERASE_64K},
+ {"M25P10" , 0x00112020, 128 * 1024, 256, 32 * 1024, AT26_BLOCK_ERASE_64K},
+ {"M25P20" , 0x00122020, 256 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"M25P40" , 0x00132020, 512 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"M25P80" , 0x00142020, 1 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"M25P16" , 0x00152020, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"M25P32" , 0x00162020, 4 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"M25P64" , 0x00172020, 8 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ // Manufacturer: Windbond
+ {"W25X10" , 0x001130EF, 128 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"W25X20" , 0x001230EF, 256 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"W25X40" , 0x001330EF, 512 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"W25X80" , 0x001430EF, 1 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ // Manufacturer: Macronix
+ {"MX25L512" , 0x001020C2, 64 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"MX25L3205" , 0x001620C2, 4 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"MX25L6405" , 0x001720C2, 8 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ // Other
+ {"SST25VF512" , 0x000048BF, 64 * 1024, 256, 32 * 1024, AT26_BLOCK_ERASE_32K}
+};
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes an AT26 driver instance with the given SPI driver and chip
+/// select value.
+/// \param pAt26 Pointer to an AT26 driver instance.
+/// \param pSpid Pointer to an SPI driver instance.
+/// \param cs Chip select value to communicate with the serial flash.
+//------------------------------------------------------------------------------
+void AT26_Configure(At26 *pAt26, Spid *pSpid, unsigned char cs)
+{
+ SpidCmd *pCommand;
+
+ SANITY_CHECK(pAt26);
+ SANITY_CHECK(pSpid);
+ SANITY_CHECK(cs < 4);
+
+ // Configure the SPI chip select for the serial flash
+ SPID_ConfigureCS(pSpid, cs, CSR);
+
+ // Initialize the AT26 fields
+ pAt26->pSpid = pSpid;
+ pAt26->pDesc = 0;
+
+ // Initialize the command structure
+ pCommand = &(pAt26->command);
+ pCommand->pCmd = (unsigned char *) pAt26->pCmdBuffer;
+ pCommand->callback = 0;
+ pCommand->pArgument = 0;
+ pCommand->spiCs = cs;
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if the serial flash driver is currently busy executing a command;
+/// otherwise returns 0.
+/// \param pAt26 Pointer to an At26 driver instance.
+//------------------------------------------------------------------------------
+unsigned char AT26_IsBusy(At26 *pAt26)
+{
+ return SPID_IsBusy(pAt26->pSpid);
+}
+
+//------------------------------------------------------------------------------
+/// Sends a command to the serial flash through the SPI. The command is made up
+/// of two parts: the first is used to transmit the command byte and optionally,
+/// address and dummy bytes. The second part is the data to send or receive.
+/// This function does not block: it returns as soon as the transfer has been
+/// started. An optional callback can be invoked to notify the end of transfer.
+/// Return 0 if successful; otherwise, returns AT26_ERROR_BUSY if the AT26
+/// driver is currently executing a command, or AT26_ERROR_SPI if the command
+/// cannot be sent because of a SPI error.
+/// \param pAt26 Pointer to an At26 driver instance.
+/// \param cmd Command byte.
+/// \param cmdSize Size of command (command byte + address bytes + dummy bytes).
+/// \param pData Data buffer.
+/// \param dataSize Number of bytes to send/receive.
+/// \param address Address to transmit.
+/// \param callback Optional user-provided callback to invoke at end of transfer.
+/// \param pArgument Optional argument to the callback function.
+//------------------------------------------------------------------------------
+unsigned char AT26_SendCommand(
+ At26 *pAt26,
+ unsigned char cmd,
+ unsigned char cmdSize,
+ unsigned char *pData,
+ unsigned int dataSize,
+ unsigned int address,
+ SpidCallback callback,
+ void *pArgument)
+
+{
+ SpidCmd *pCommand;
+
+ SANITY_CHECK(pAt26);
+
+ // Check if the SPI driver is available
+ if (AT26_IsBusy(pAt26)) {
+
+ return AT26_ERROR_BUSY;
+ }
+
+ // Store command and address in command buffer
+ pAt26->pCmdBuffer[0] = (cmd & 0x000000FF)
+ | ((address & 0x0000FF) << 24)
+ | ((address & 0x00FF00) << 8)
+ | ((address & 0xFF0000) >> 8);
+
+ // Update the SPI transfer descriptor
+ pCommand = &(pAt26->command);
+ pCommand->cmdSize = cmdSize;
+ pCommand->pData = pData;
+ pCommand->dataSize = dataSize;
+ pCommand->callback = callback;
+ pCommand->pArgument = pArgument;
+
+ // Start the SPI transfer
+ if (SPID_SendCommand(pAt26->pSpid, pCommand)) {
+
+ return AT26_ERROR_SPI;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Tries to detect a serial firmware flash device given its JEDEC identifier.
+/// The JEDEC id can be retrieved by sending the correct command to the device.
+/// Returns the corresponding AT26 descriptor if found; otherwise returns 0.
+/// \param pAt26 Pointer to an AT26 driver instance.
+/// \param jedecId JEDEC identifier of device.
+//------------------------------------------------------------------------------
+const At26Desc * AT26_FindDevice(At26 *pAt26, unsigned int jedecId)
+{
+ unsigned int i = 0;
+
+ SANITY_CHECK(pAt26);
+
+ // Search if device is recognized
+ pAt26->pDesc = 0;
+ while ((i < NUMDATAFLASH) && !(pAt26->pDesc)) {
+
+ if (jedecId == at26Devices[i].jedecId) {
+
+ pAt26->pDesc = &(at26Devices[i]);
+ }
+
+ i++;
+ }
+
+ return pAt26->pDesc;
+}
+
diff --git a/at91lib/memories/spi-flash/at26.h b/at91lib/memories/spi-flash/at26.h
new file mode 100644
index 0000000..4e3aa6d
--- /dev/null
+++ b/at91lib/memories/spi-flash/at26.h
@@ -0,0 +1,252 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// The AT26 serial firmware Dataflash driver is based on top of the
+/// corresponding Spi driver. A Dataflash structure instance has to be
+/// initialized using the DF_Init function. Then basic dataflash
+/// operations can be launched using macros such as DF_continuous_read.
+/// These macros invoke the DF_Command() function which invokes the
+/// DPI low driver using the SPI_SendCommand() function.
+/// Beware to compute the dataflash internal address, the dataflash sector
+/// description must be known (DataflashDesc). Dataflash can be automatically
+/// detected using the DF_Scan() function.
+///
+/// !Usage
+///
+/// -# Initializes an AT26 instance and configures SPI chip select pin
+/// using AT26_Configure().
+/// -# Detect DF and returns DF description corresponding to the device
+/// connected using AT26_FindDevice().This function shall be called by
+/// the application before AT26_SendCommand().
+/// -# Sends a command to the DF through the SPI using AT26_SendCommand().
+/// The command is identified by its command code and the number of
+/// bytes to transfer.
+/// -# Example code for sending command to write a page to DF.
+/// \code
+/// // Program page
+/// error = AT26_SendCommand(pAt26, AT26_BYTE_PAGE_PROGRAM, 4,
+/// pData, writeSize, address, 0, 0);
+/// \endcode
+/// -# Example code for sending command to read a page from DF.
+/// If data needs to be received, then a data buffer must be
+/// provided.
+/// \code
+/// // Start a read operation
+/// error = AT26_SendCommand(pAt26, AT26_READ_ARRAY_LF,
+/// 4, pData, size, address, 0, 0);
+/// \endcode
+/// -# This function does not block; its optional callback will
+/// be invoked when the transfer completes.
+/// -# Check the AT26 driver is ready or not by polling AT26_IsBusy().
+///
+//------------------------------------------------------------------------------
+#ifndef AT26_H
+#define AT26_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "spid.h"
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+#define AT26_Size(pAt26) ((pAt26)->pDesc->size)
+#define AT26_PageSize(pAt26) ((pAt26)->pDesc->pageSize)
+#define AT26_BlockSize(pAt26) ((pAt26)->pDesc->blockSize)
+#define AT26_Name(pAt26) ((pAt26)->pDesc->name)
+#define AT26_PageNumber(pAt26) (AT26_Size(pAt26) / AT26_PageSize(pAt26))
+#define AT26_BlockNumber(pAt26) (AT26_Size(pAt26) / AT26_BlockSize(pAt26))
+#define AT26_PagePerBlock(pAt26) (AT26_BlockSize(pAt26) / AT26_PageSize(pAt26))
+#define AT26_BlockEraseCmd(pAt26) ((pAt26)->pDesc->blockEraseCmd)
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// Device is protected, operation cannot be carried out.
+#define AT26_ERROR_PROTECTED 1
+/// Device is busy executing a command.
+#define AT26_ERROR_BUSY 2
+/// There was a problem while trying to program page data.
+#define AT26_ERROR_PROGRAM 3
+/// There was an SPI communication error.
+#define AT26_ERROR_SPI 4
+
+/// Device ready/busy status bit.
+#define AT26_STATUS_RDYBSY (1 << 0)
+/// Device is ready.
+#define AT26_STATUS_RDYBSY_READY (0 << 0)
+/// Device is busy with internal operations.
+#define AT26_STATUS_RDYBSY_BUSY (1 << 0)
+/// Write enable latch status bit.
+#define AT26_STATUS_WEL (1 << 1)
+/// Device is not write enabled.
+#define AT26_STATUS_WEL_DISABLED (0 << 1)
+/// Device is write enabled.
+#define AT26_STATUS_WEL_ENABLED (1 << 1)
+/// Software protection status bitfield.
+#define AT26_STATUS_SWP (3 << 2)
+/// All sectors are software protected.
+#define AT26_STATUS_SWP_PROTALL (3 << 2)
+/// Some sectors are software protected.
+#define AT26_STATUS_SWP_PROTSOME (1 << 2)
+/// No sector is software protected.
+#define AT26_STATUS_SWP_PROTNONE (0 << 2)
+/// Write protect pin status bit.
+#define AT26_STATUS_WPP (1 << 4)
+/// Write protect signal is not asserted.
+#define AT26_STATUS_WPP_NOTASSERTED (0 << 4)
+/// Write protect signal is asserted.
+#define AT26_STATUS_WPP_ASSERTED (1 << 4)
+/// Erase/program error bit.
+#define AT26_STATUS_EPE (1 << 5)
+/// Erase or program operation was successful.
+#define AT26_STATUS_EPE_SUCCESS (0 << 5)
+/// Erase or program error detected.
+#define AT26_STATUS_EPE_ERROR (1 << 5)
+/// Sector protection registers locked bit.
+#define AT26_STATUS_SPRL (1 << 7)
+/// Sector protection registers are unlocked.
+#define AT26_STATUS_SPRL_UNLOCKED (0 << 7)
+/// Sector protection registers are locked.
+#define AT26_STATUS_SPRL_LOCKED (1 << 7)
+
+/// Read array command code.
+#define AT26_READ_ARRAY 0x0B
+/// Read array (low frequency) command code.
+#define AT26_READ_ARRAY_LF 0x03
+/// Block erase command code (4K block).
+#define AT26_BLOCK_ERASE_4K 0x20
+/// Block erase command code (32K block).
+#define AT26_BLOCK_ERASE_32K 0x52
+/// Block erase command code (64K block).
+#define AT26_BLOCK_ERASE_64K 0xD8
+/// Chip erase command code 1.
+#define AT26_CHIP_ERASE_1 0x60
+/// Chip erase command code 2.
+#define AT26_CHIP_ERASE_2 0xC7
+/// Byte/page program command code.
+#define AT26_BYTE_PAGE_PROGRAM 0x02
+/// Sequential program mode command code 1.
+#define AT26_SEQUENTIAL_PROGRAM_1 0xAD
+/// Sequential program mode command code 2.
+#define AT26_SEQUENTIAL_PROGRAM_2 0xAF
+/// Write enable command code.
+#define AT26_WRITE_ENABLE 0x06
+/// Write disable command code.
+#define AT26_WRITE_DISABLE 0x04
+/// Protect sector command code.
+#define AT26_PROTECT_SECTOR 0x36
+/// Unprotect sector command code.
+#define AT26_UNPROTECT_SECTOR 0x39
+/// Read sector protection registers command code.
+#define AT26_READ_SECTOR_PROT 0x3C
+/// Read status register command code.
+#define AT26_READ_STATUS 0x05
+/// Write status register command code.
+#define AT26_WRITE_STATUS 0x01
+/// Read manufacturer and device ID command code.
+#define AT26_READ_JEDEC_ID 0x9F
+/// Deep power-down command code.
+#define AT26_DEEP_PDOWN 0xB9
+/// Resume from deep power-down command code.
+#define AT26_RES_DEEP_PDOWN 0xAB
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Describes a serial firmware flash device parameters.
+//------------------------------------------------------------------------------
+typedef struct _At26Desc {
+
+ /// Device string name.
+ const char *name;
+ /// JEDEC ID of device.
+ unsigned int jedecId;
+ /// Size of device in bytes.
+ unsigned int size;
+ /// Size of one page in bytes.
+ unsigned int pageSize;
+ /// Block erase size in bytes.
+ unsigned int blockSize;
+ /// Block erase command.
+ unsigned int blockEraseCmd;
+
+} At26Desc;
+
+//------------------------------------------------------------------------------
+/// Serial flash driver structure. Holds the current state of the driver,
+/// including the current command and the descriptor for the underlying device.
+//------------------------------------------------------------------------------
+typedef struct _At26 {
+
+ /// Pointer to the underlying SPI driver.
+ Spid *pSpid;
+ /// Current SPI command sent to the SPI driver.
+ SpidCmd command;
+ /// Pointer to a descriptor for the serial firmware flash device.
+ const At26Desc *pDesc;
+ /// Command buffer.
+ unsigned int pCmdBuffer[2];
+
+} At26;
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void AT26_Configure(At26 *pAt26, Spid *pSpid, unsigned char cs);
+
+extern unsigned char AT26_SendCommand(
+ At26 *pAt26,
+ unsigned char cmd,
+ unsigned char cmdSize,
+ unsigned char *pData,
+ unsigned int dataSize,
+ unsigned int address,
+ SpidCallback callback,
+ void *pArgument);
+
+extern unsigned char AT26_IsBusy(At26 *pAt26);
+
+extern const At26Desc * AT26_FindDevice(
+ At26 *pAt26,
+ unsigned int jedecId);
+
+#endif //#ifndef AT26_H
+
diff --git a/at91lib/memories/spi-flash/spid.c b/at91lib/memories/spi-flash/spid.c
new file mode 100644
index 0000000..3dd0409
--- /dev/null
+++ b/at91lib/memories/spi-flash/spid.c
@@ -0,0 +1,215 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "spid.h"
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+/// Write PMC register
+#define WRITE_PMC(pPmc, regName, value) pPmc->regName = (value)
+
+/// Write SPI register
+#define WRITE_SPI(pSpi, regName, value) pSpi->regName = (value)
+
+/// Read SPI registers
+#define READ_SPI(pSpi, regName) (pSpi->regName)
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes the Spid structure and the corresponding SPI hardware.
+/// Always returns 0.
+/// \param pSpid Pointer to a Spid instance.
+/// \param pSpiHw Associated SPI peripheral.
+/// \param spiId SPI peripheral identifier.
+//------------------------------------------------------------------------------
+unsigned char SPID_Configure(Spid *pSpid, AT91S_SPI *pSpiHw, unsigned char spiId)
+{
+ // Initialize the SPI structure
+ pSpid->pSpiHw = pSpiHw;
+ pSpid->spiId = spiId;
+ pSpid->semaphore = 1;
+ pSpid->pCurrentCommand = 0;
+
+ // Enable the SPI clock
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pSpid->spiId));
+
+ // Execute a software reset of the SPI twice
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST);
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST);
+
+ // Configure SPI in Master Mode with No CS selected !!!
+ WRITE_SPI(pSpiHw, SPI_MR, AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS);
+
+ // Disable the PDC transfer
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
+
+ // Enable the SPI
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIEN);
+
+ // Enable the SPI clock
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pSpid->spiId));
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Configures the parameters for the device corresponding to the cs.
+/// \param pSpid Pointer to a Spid instance.
+/// \param cs number corresponding to the SPI chip select.
+/// \param csr SPI_CSR value to setup.
+//------------------------------------------------------------------------------
+void SPID_ConfigureCS(Spid *pSpid, unsigned char cs, unsigned int csr)
+{
+ AT91S_SPI *pSpiHw = pSpid->pSpiHw;
+ WRITE_SPI(pSpiHw, SPI_CSR[cs], csr);
+}
+
+//------------------------------------------------------------------------------
+/// Starts a SPI master transfer. This is a non blocking function. It will
+/// return as soon as the transfer is started.
+/// Returns 0 if the transfer has been started successfully; otherwise returns
+/// SPID_ERROR_LOCK is the driver is in use, or SPID_ERROR if the command is not
+/// valid.
+/// \param pSpid Pointer to a Spid instance.
+/// \param pCommand Pointer to the SPI command to execute.
+//------------------------------------------------------------------------------
+unsigned char SPID_SendCommand(Spid *pSpid, SpidCmd *pCommand)
+{
+ AT91S_SPI *pSpiHw = pSpid->pSpiHw;
+ unsigned int spiMr;
+
+ // Try to get the dataflash semaphore
+ if (pSpid->semaphore == 0) {
+
+ return SPID_ERROR_LOCK;
+ }
+ pSpid->semaphore--;
+
+ // Enable the SPI clock
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pSpid->spiId));
+
+ // Disable transmitter and receiver
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
+
+ // Write to the MR register
+ spiMr = READ_SPI(pSpiHw, SPI_MR);
+ spiMr |= AT91C_SPI_PCS;
+ spiMr &= ~((1 << pCommand->spiCs) << 16);
+ WRITE_SPI(pSpiHw, SPI_MR, spiMr);
+
+ // Initialize the two SPI PDC buffer
+ WRITE_SPI(pSpiHw, SPI_RPR, (int) pCommand->pCmd);
+ WRITE_SPI(pSpiHw, SPI_RCR, pCommand->cmdSize);
+ WRITE_SPI(pSpiHw, SPI_TPR, (int) pCommand->pCmd);
+ WRITE_SPI(pSpiHw, SPI_TCR, pCommand->cmdSize);
+
+ WRITE_SPI(pSpiHw, SPI_RNPR, (int) pCommand->pData);
+ WRITE_SPI(pSpiHw, SPI_RNCR, pCommand->dataSize);
+ WRITE_SPI(pSpiHw, SPI_TNPR, (int) pCommand->pData);
+ WRITE_SPI(pSpiHw, SPI_TNCR, pCommand->dataSize);
+
+ // Initialize the callback
+ pSpid->pCurrentCommand = pCommand;
+
+ // Enable transmitter and receiver
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTEN | AT91C_PDC_TXTEN);
+
+ // Enable buffer complete interrupt
+ WRITE_SPI(pSpiHw, SPI_IER, AT91C_SPI_RXBUFF);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// The SPI_Handler must be called by the SPI Interrupt Service Routine with the
+/// corresponding Spi instance.
+/// The SPI_Handler will unlock the Spi semaphore and invoke the upper application
+/// callback.
+/// \param pSpid Pointer to a Spid instance.
+//------------------------------------------------------------------------------
+void SPID_Handler(Spid *pSpid)
+{
+ SpidCmd *pSpidCmd = pSpid->pCurrentCommand;
+ AT91S_SPI *pSpiHw = pSpid->pSpiHw;
+ volatile unsigned int spiSr;
+
+ // Read the status register
+ spiSr = READ_SPI(pSpiHw, SPI_SR);
+ if (spiSr & AT91C_SPI_RXBUFF) {
+
+ // Disable transmitter and receiver
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
+
+ // Disable the SPI clock
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pSpid->spiId));
+
+ // Disable buffer complete interrupt
+ WRITE_SPI(pSpiHw, SPI_IDR, AT91C_SPI_RXBUFF);
+
+ // Release the dataflash semaphore
+ pSpid->semaphore++;
+
+ // Invoke the callback associated with the current command
+ if (pSpidCmd && pSpidCmd->callback) {
+
+ pSpidCmd->callback(0, pSpidCmd->pArgument);
+ }
+
+ // Nothing must be done after. A new DF operation may have been started
+ // in the callback function.
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if the SPI driver is currently busy executing a command; otherwise
+/// returns 0.
+/// \param pSpid Pointer to a SPI driver instance.
+//------------------------------------------------------------------------------
+unsigned char SPID_IsBusy(const Spid *pSpid)
+{
+ if (pSpid->semaphore == 0) {
+
+ return 1;
+ }
+ else {
+
+ return 0;
+ }
+}
+
diff --git a/at91lib/memories/spi-flash/spid.h b/at91lib/memories/spi-flash/spid.h
new file mode 100644
index 0000000..5852c1c
--- /dev/null
+++ b/at91lib/memories/spi-flash/spid.h
@@ -0,0 +1,183 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !!!Purpose
+///
+/// The Spi driver is a low level spi driver which performs SPI device Initializes,
+/// spi transfer and receive. It can be used by upper SPI driver such as AT45
+/// driver and AT26 driver.
+///
+/// !!!Usage
+///
+/// -# Initializes a SPI instance and the corresponding SPI hardware,
+/// Configure SPI in Master Mode using SPID_Configure().
+/// -# Configures the SPI characteristics (such as Clock Polarity, Phase,
+/// transfers delay and Baud Rate) for the device corresponding to the
+/// chip select using SPID_ConfigureCS().
+/// -# Starts a SPI master transfer using SPID_SendCommand().
+/// The transfer is performed using the PDC channels.
+/// -# It enable the SPI clock.
+/// -# Set the corresponding peripheral chip select.
+/// -# Initialize the two SPI PDC buffers.
+/// - Initialize SPI_TPR and SPI_TCR with SPI command data and size
+/// to send command data first.
+/// - Initialize SPI_RPR and SPI_RCR with SPI command data and size
+/// as dummy value.
+/// - Initialize SPI_TNPR and SPI_TNCR with rest of the data to be
+/// transfered.(if the data specified in cmd structure)
+/// - Initialize SPI_RNPR and SPI_RNCR with rest of the data to be
+/// received.(if the data specified in cmd structure)
+/// -# Initialize the callback function if specified.
+/// -# Enable transmitter and receiver.
+/// -# Example for sending a command to the dataflash through the SPI.
+/// \code
+/// /// Build command to be sent.
+/// ...
+/// // Send Command and data through the SPI
+/// if (SPID_SendCommand(pAt45->pSpid, pCommand)) {
+/// return AT45_ERROR_SPI;
+/// }
+/// \endcode
+/// -# The SPI_Handler() must be called by the SPI Interrupt Service Routine
+/// with the corresponding Spi instance. It is invokes to check for pending
+/// interrupts.
+/// - Example for initializing SPI interrupt handler in upper application.
+/// \code
+/// AIC_ConfigureIT(AT91C_ID_SPI, 0, SPI_Handler);
+/// \endcode
+//------------------------------------------------------------------------------
+
+#ifndef SPID_H
+#define SPID_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// An unspecified error has occured.
+#define SPID_ERROR 1
+
+/// SPI driver is currently in use.
+#define SPID_ERROR_LOCK 2
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+/// Calculates the value of the SCBR field of the Chip Select Register given
+/// MCK and SPCK.
+#define SPID_CSR_SCBR(mck, spck) ((((mck) / (spck)) << 8) & AT91C_SPI_SCBR)
+
+/// Calculates the value of the DLYBS field of the Chip Select Register given
+/// the delay in ns and MCK.
+#define SPID_CSR_DLYBS(mck, delay) \
+ ((((((delay) * ((mck) / 1000000)) / 1000) + 1) << 16) & AT91C_SPI_DLYBS)
+
+/// Calculates the value of the DLYBCT field of the Chip Select Register given
+/// the delay in ns and MCK.
+#define SPID_CSR_DLYBCT(mck, delay) \
+ ((((((delay) / 32 * ((mck) / 1000000)) / 1000) + 1) << 24) & AT91C_SPI_DLYBCT)
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+/// SPI transfer complete callback.
+typedef void (*SpidCallback )(unsigned char, void *);
+
+//------------------------------------------------------------------------------
+/// Spi Transfer Request prepared by the application upper layer. This structure
+/// is sent to the SPI_SendCommand function to start the transfer. At the end of
+/// the transfer, the callback is invoked by the interrupt handler.
+//------------------------------------------------------------------------------
+typedef struct _SpidCmd {
+
+ /// Pointer to the command data.
+ unsigned char *pCmd;
+ /// Command size in bytes.
+ unsigned char cmdSize;
+ /// Pointer to the data to be sent.
+ unsigned char *pData;
+ /// Data size in bytes.
+ unsigned short dataSize;
+ /// SPI chip select.
+ unsigned char spiCs;
+ /// Callback function invoked at the end of transfer.
+ SpidCallback callback;
+ /// Callback arguments.
+ void *pArgument;
+
+} SpidCmd;
+
+//------------------------------------------------------------------------------
+/// Constant structure associated with SPI port. This structure prevents
+/// client applications to have access in the same time.
+//------------------------------------------------------------------------------
+typedef struct {
+
+ /// Pointer to SPI Hardware registers
+ AT91S_SPI *pSpiHw;
+ /// SPI Id as defined in the product datasheet
+ char spiId;
+ /// Current SpiCommand being processed
+ SpidCmd *pCurrentCommand;
+ /// Mutual exclusion semaphore.
+ volatile char semaphore;
+
+} Spid;
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern unsigned char SPID_Configure(
+ Spid *pSpid,
+ AT91S_SPI *pSpiHw,
+ unsigned char spiId);
+
+extern void SPID_ConfigureCS(Spid *pSpid, unsigned char cs, unsigned int csr);
+
+extern unsigned char SPID_SendCommand(
+ Spid *pSpid,
+ SpidCmd *pCommand);
+
+extern void SPID_Handler(Spid *pSpid);
+
+extern unsigned char SPID_IsBusy(const Spid *pSpid);
+
+#endif // #ifndef SPID_H
+
personal git repositories of Harald Welte. Your mileage may vary