| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 |
- /*
- * Copyright (C) 2008-2011 by egnite GmbH
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS 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.
- *
- * For additional information see http://www.ethernut.de/
- */
- /*!
- * \file dev/spi_node_at45d.c
- * \brief Low level routines for Adesto/Atmel AT45D SPI Flash.
- *
- * \verbatim
- * $Id$
- * \endverbatim
- */
- #include <cfg/memory.h>
- #include <dev/blockdev.h>
- #include <sys/nutdebug.h>
- #include <sys/timer.h>
- #include <stdlib.h>
- #include <string.h>
- #include <dev/spi_node_at45d.h>
- /*!
- * \addtogroup xgSpiNodeAt45d
- */
- /*@{*/
- typedef struct _AT45D_DCB {
- HANDLE dcb_lock;
- } AT45D_DCB;
- static AT45D_DCB dcbAt45d0 = {
- SIGNALED
- };
- static AT45D_DCB dcbAt45d1 = {
- SIGNALED
- };
- static AT45D_DCB dcbAt45d2 = {
- SIGNALED
- };
- static AT45D_DCB dcbAt45d3 = {
- SIGNALED
- };
- int At45dNodeLock(NUTSPINODE * node)
- {
- AT45D_DCB *dcb = (AT45D_DCB *) node->node_dcb;
- return NutEventWait(&dcb->dcb_lock, NUT_WAIT_INFINITE);
- }
- void At45dNodeUnlock(NUTSPINODE * node)
- {
- AT45D_DCB *dcb = (AT45D_DCB *) node->node_dcb;
- NutEventPost(&dcb->dcb_lock);
- }
- /*!
- * \brief Transmit DataFlash command.
- *
- * \param node Specifies the SPI node.
- * \param op Command code.
- * \param parm Command parameter.
- * \param oplen Command length.
- *
- * \return 0 on success, -1 on errors.
- */
- static int At45dNodeTransmitCmd(NUTSPINODE * node, uint8_t op, uint32_t parm, uint_fast8_t oplen)
- {
- uint8_t cmd[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
- NUTASSERT(oplen <= sizeof(cmd));
- cmd[0] = op;
- if (parm) {
- cmd[1] = (uint8_t) (parm >> 16);
- cmd[2] = (uint8_t) (parm >> 8);
- cmd[3] = (uint8_t) parm;
- }
- return (*((NUTSPIBUS *) node->node_bus)->bus_transfer) (node, cmd, NULL, oplen);
- }
- /*!
- * \brief Execute DataFlash command with data transfer.
- *
- * \param node Specifies the SPI node.
- * \param op Command code.
- * \param parm Command parameter.
- * \param oplen Command length.
- * \param txbuf Pointer to the transmit data buffer, may be set to NULL.
- * \param rxbuf Pointer to the receive data buffer, may be set to NULL.
- * \param xlen Number of byte to receive and/or transmit.
- *
- * \return 0 on success, -1 on errors.
- */
- int At45dNodeTransfer(NUTSPINODE * node, uint8_t op, uint32_t parm, uint_fast8_t oplen,
- const void *txbuf, void *rxbuf, int xlen)
- {
- int rc;
- NUTSPIBUS *bus;
- /* Sanity checks. */
- NUTASSERT(node != NULL);
- bus = (NUTSPIBUS *) node->node_bus;
- NUTASSERT(bus != NULL);
- NUTASSERT(bus->bus_alloc != NULL);
- NUTASSERT(bus->bus_transfer != NULL);
- NUTASSERT(bus->bus_release != NULL);
- rc = (*bus->bus_alloc) (node, 0);
- if (rc == 0) {
- rc = At45dNodeTransmitCmd(node, op, parm, oplen);
- if (rc == 0 && xlen) {
- rc = (*bus->bus_transfer) (node, txbuf, rxbuf, xlen);
- }
- (*bus->bus_release) (node);
- }
- return rc;
- }
- /*!
- * \brief Execute DataFlash command without data.
- *
- * \param node Specifies the SPI node.
- * \param op Command operation code.
- * \param parm Optional command parameter.
- * \param oplen Command length.
- *
- * \return 0 on success, -1 on errors.
- */
- int At45dNodeCommand(NUTSPINODE * node, uint8_t op, uint32_t parm, uint_fast8_t oplen)
- {
- return At45dNodeTransfer(node, op, parm, oplen, NULL, NULL, 0);
- }
- /*!
- * \brief Query the status of the serial flash.
- *
- * \param node Specifies the SPI node.
- *
- * \return 0 on success or -1 in case of an error.
- */
- uint8_t At45dNodeStatus(NUTSPINODE * node)
- {
- int rc;
- uint8_t cmd[2] = { DFCMD_READ_STATUS, 0xFF };
- NUTSPIBUS *bus;
- /* Sanity checks. */
- NUTASSERT(node != NULL);
- NUTASSERT(node->node_bus != NULL);
- bus = (NUTSPIBUS *) node->node_bus;
- NUTASSERT(bus->bus_alloc != NULL);
- NUTASSERT(bus->bus_transfer != NULL);
- NUTASSERT(bus->bus_wait != NULL);
- NUTASSERT(bus->bus_release != NULL);
- rc = (*bus->bus_alloc) (node, 0);
- if (rc == 0) {
- rc = (*bus->bus_transfer) (node, cmd, cmd, 2);
- if (rc == 0) {
- (*bus->bus_wait) (node, NUT_WAIT_INFINITE);
- rc = cmd[1];
- }
- (*bus->bus_release) (node);
- }
- return (uint8_t) rc;
- }
- /*!
- * \brief Wait until DataFlash memory cycle finished.
- *
- * \param node Specifies the SPI node.
- * \param tmo Number of loops (or milliseconds) to wait at max.
- * \param poll If 0, the current thread will be suspended for
- * 1 millisecond between each retry. Otherwise the
- * polling loop will not sleep, but may be still suspended
- * by the lower level SPI bus driver.
- *
- * \return 0 on success or -1 in case of an error.
- */
- int At45dNodeWaitReady(NUTSPINODE * node, uint32_t tmo, int poll)
- {
- uint8_t sr;
- while (((sr = At45dNodeStatus(node)) & 0x80) == 0) {
- if (!poll) {
- NutSleep(1);
- }
- if (tmo-- == 0) {
- return -1;
- }
- }
- return 0;
- }
- /*!
- * \brief Determine the DataFlash type.
- *
- * If the board contains a known DataFlash chip, but couldn't be
- * determined by this routine, then most probably the chip select
- * configuration is wrong.
- *
- * \param node Specifies the SPI node.
- *
- * \return Pointer to a \ref AT45D_INFO structure, which contains
- * the relevant DataFlash parameters. If no known DataFlash
- * is available, then NULL is returned.
- */
- AT45D_INFO *At45dNodeProbe(NUTSPINODE * node)
- {
- int_fast8_t i;
- uint8_t sr;
- if (At45dNodeWaitReady(node, 10, 1) == 0) {
- sr = At45dNodeStatus(node);
- if (sr != 0xff) {
- sr &= AT45D_STATUS_DENSITY | AT45D_STATUS_PAGE_SIZE;
- for (i = at45d_known_types; --i >= 0;) {
- if (sr == at45d_info[i].at45d_srval) {
- return &at45d_info[i];
- }
- }
- }
- }
- return NULL;
- }
- #ifndef SPI_RATE_AT45D0
- #define SPI_RATE_AT45D0 33000000
- #endif
- #ifndef SPI_MODE_AT45D0
- #ifdef SPI_CSHIGH_AT45D0
- #define SPI_MODE_AT45D0 (SPI_MODE_3 | SPI_MODE_CSHIGH)
- #else
- #define SPI_MODE_AT45D0 SPI_MODE_3
- #endif
- #elif defined(SPI_CSHIGH_AT45D0)
- /* This is a tricky problem. Originally we didn't provide mode settings
- ** in the Configurator, but used mode 3 only. After experiencing problems
- ** with mode switching on the EIR, we need to set mode 0 for that board,
- ** which spoils our chip select polarity setting. */
- #if SPI_MODE_AT45D0 == SPI_MODE_0
- #undef SPI_MODE_AT45D0
- #define SPI_MODE_AT45D0 (SPI_MODE_0 | SPI_MODE_CSHIGH)
- #elif SPI_MODE_AT45D0 == SPI_MODE_3
- #undef SPI_MODE_AT45D0
- #define SPI_MODE_AT45D0 (SPI_MODE_3 | SPI_MODE_CSHIGH)
- #endif
- #endif /* SPI_MODE_AT45D0 */
- /*!
- * \brief First AT45D DataFlash SPI node implementation structure.
- */
- NUTSPINODE nodeAt45d0 = {
- NULL, /*!< \brief Pointer to the bus controller driver, node_bus. */
- NULL, /*!< \brief Pointer to the bus device driver specific settings, node_stat. */
- SPI_RATE_AT45D0, /*!< \brief Initial clock rate, node_rate. */
- SPI_MODE_AT45D0, /*!< \brief Initial mode, node_mode. */
- 8, /*!< \brief Initial data bits, node_bits. */
- 0, /*!< \brief Chip select, node_cs. */
- &dcbAt45d0 /*!< \brief Pointer to our private device control block, node_dcb. */
- };
- #ifndef SPI_RATE_AT45D1
- #define SPI_RATE_AT45D1 33000000
- #endif
- #ifndef SPI_MODE_AT45D1
- #ifdef SPI_CSHIGH_AT45D1
- #define SPI_MODE_AT45D1 (SPI_MODE_3 | SPI_MODE_CSHIGH)
- #else
- #define SPI_MODE_AT45D1 SPI_MODE_3
- #endif
- #elif defined(SPI_CSHIGH_AT45D1)
- /* Same problem problem as above. */
- #if SPI_MODE_AT45D1 == SPI_MODE_0
- #undef SPI_MODE_AT45D1
- #define SPI_MODE_AT45D1 (SPI_MODE_0 | SPI_MODE_CSHIGH)
- #elif SPI_MODE_AT45D1 == SPI_MODE_3
- #undef SPI_MODE_AT45D1
- #define SPI_MODE_AT45D1 (SPI_MODE_3 | SPI_MODE_CSHIGH)
- #endif
- #endif /* SPI_MODE_AT45D1 */
- /*!
- * \brief Second AT45D DataFlash SPI node implementation structure.
- */
- NUTSPINODE nodeAt45d1 = {
- NULL, /*!< \brief Pointer to the bus controller driver, node_bus. */
- NULL, /*!< \brief Pointer to the bus device driver specific settings, node_stat. */
- SPI_RATE_AT45D1, /*!< \brief Initial clock rate, node_rate. */
- SPI_MODE_AT45D1, /*!< \brief Initial mode, node_mode. */
- 8, /*!< \brief Initial data bits, node_bits. */
- 0, /*!< \brief Chip select, node_cs. */
- &dcbAt45d1 /*!< \brief Pointer to our private device control block, node_dcb. */
- };
- #ifndef SPI_RATE_AT45D2
- #define SPI_RATE_AT45D2 33000000
- #endif
- #ifndef SPI_MODE_AT45D2
- #ifdef SPI_CSHIGH_AT45D2
- #define SPI_MODE_AT45D2 (SPI_MODE_3 | SPI_MODE_CSHIGH)
- #else
- #define SPI_MODE_AT45D2 SPI_MODE_3
- #endif
- #elif defined(SPI_CSHIGH_AT45D2)
- /* Same problem problem as above. */
- #if SPI_MODE_AT45D2 == SPI_MODE_0
- #undef SPI_MODE_AT45D2
- #define SPI_MODE_AT45D2 (SPI_MODE_0 | SPI_MODE_CSHIGH)
- #elif SPI_MODE_AT45D2 == SPI_MODE_3
- #undef SPI_MODE_AT45D2
- #define SPI_MODE_AT45D2 (SPI_MODE_3 | SPI_MODE_CSHIGH)
- #endif
- #endif /* SPI_MODE_AT45D2 */
- /*!
- * \brief Third AT45D DataFlash SPI node implementation structure.
- */
- NUTSPINODE nodeAt45d2 = {
- NULL, /*!< \brief Pointer to the bus controller driver, node_bus. */
- NULL, /*!< \brief Pointer to the bus device driver specific settings, node_stat. */
- SPI_RATE_AT45D2, /*!< \brief Initial clock rate, node_rate. */
- SPI_MODE_AT45D2, /*!< \brief Initial mode, node_mode. */
- 8, /*!< \brief Initial data bits, node_bits. */
- 0, /*!< \brief Chip select, node_cs. */
- &dcbAt45d2 /*!< \brief Pointer to our private device control block, node_dcb. */
- };
- #ifndef SPI_RATE_AT45D3
- #define SPI_RATE_AT45D3 33000000
- #endif
- #ifndef SPI_MODE_AT45D3
- #ifdef SPI_CSHIGH_AT45D3
- #define SPI_MODE_AT45D3 (SPI_MODE_3 | SPI_MODE_CSHIGH)
- #else
- #define SPI_MODE_AT45D3 SPI_MODE_3
- #endif
- #elif defined(SPI_CSHIGH_AT45D3)
- /* Same problem problem as above. */
- #if SPI_MODE_AT45D3 == SPI_MODE_0
- #undef SPI_MODE_AT45D3
- #define SPI_MODE_AT45D3 (SPI_MODE_0 | SPI_MODE_CSHIGH)
- #elif SPI_MODE_AT45D3 == SPI_MODE_3
- #undef SPI_MODE_AT45D3
- #define SPI_MODE_AT45D3 (SPI_MODE_3 | SPI_MODE_CSHIGH)
- #endif
- #endif /* SPI_MODE_AT45D3 */
- /*!
- * \brief Forth AT45D DataFlash SPI node implementation structure.
- */
- NUTSPINODE nodeAt45d3 = {
- NULL, /*!< \brief Pointer to the bus controller driver, node_bus. */
- NULL, /*!< \brief Pointer to the bus device driver specific settings, node_stat. */
- SPI_RATE_AT45D3, /*!< \brief Initial clock rate, node_rate. */
- SPI_MODE_AT45D3, /*!< \brief Initial mode, node_mode. */
- 8, /*!< \brief Initial data bits, node_bits. */
- 0, /*!< \brief Chip select, node_cs. */
- &dcbAt45d3 /*!< \brief Pointer to our private device control block, node_dcb. */
- };
- /*@}*/
|