| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- /*
- * Copyright (C) 2008-2009 by egnite GmbH
- * Copyright (C) 2006 by egnite Software 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/nvmem_at45d.c
- * \brief Non-volatile memory support using Adesto/Atmel AT45 serial
- * DataFlash memory chips.
- *
- * \verbatim
- * $Id: nvmem_at45d.c 5227 2013-07-19 08:48:47Z u_bonnes $
- * \endverbatim
- */
- #include <cfg/eeprom.h>
- #include <cfg/memory.h>
- #include <dev/board.h>
- #include <dev/spi_at45d.h>
- #include <sys/nutdebug.h>
- #include <stdlib.h>
- #include <string.h>
- #include <memdebug.h>
- #include <dev/nvmem_at45d.h>
- static NUTDEVICE *devSysConf;
- /*!
- * \brief Mimic initialization without actually registering the device.
- *
- * This is a little bit tricky. If we want to use the existing DataFlash
- * routines for accessing the system configuration, they must be
- * properly initialized. This is normally done by calling NutRegister...
- * in the application. However, the system configuration must be know
- * before entering any application code.
- *
- */
- static int SpiAt45dConfigDevice(void)
- {
- #if !defined(DEV_SPIBUS)
- return -1;
- #else /* DEV_SPIBUS */
- if (devSysConf == NULL) {
- NUTSPINODE *node;
- NUTDEVICE *dev;
- #if NUT_CONFIG_AT45D == 0
- dev = &devSpiAt45d0;
- #elif NUT_CONFIG_AT45D == 1
- dev = &devSpiAt45d1;
- #elif NUT_CONFIG_AT45D == 2
- dev = &devSpiAt45d2;
- #elif NUT_CONFIG_AT45D == 3
- dev = &devSpiAt45d3;
- #else
- return -1;
- #endif
- node = (NUTSPINODE *) dev->dev_icb;
- NUTASSERT(node != NULL);
- if (node->node_bus == NULL) {
- NUTSPIBUS *bus;
- bus = &DEV_SPIBUS;
- node->node_bus = bus;
- }
- #ifdef NUT_CONFIG_AT45D_CS
- node->node_cs = NUT_CONFIG_AT45D_CS;
- #endif
- NUTASSERT(node->node_bus->bus_initnode != NULL);
- if ((*node->node_bus->bus_initnode) (node)) {
- return -1;
- }
- NutEventPost(&node->node_bus->bus_mutex);
- if (SpiAt45dInit(dev)) {
- return -1;
- }
- devSysConf = dev;
- }
- return 0;
- #endif /* DEV_SPIBUS */
- }
- static uint32_t SpiAt45dConfigPage(void)
- {
- #ifdef NUT_CONFIG_AT45D_PAGE
- return NUT_CONFIG_AT45D_PAGE;
- #else
- return SpiAt45dPages(devSysConf) - 1;
- #endif
- }
- /*!
- * \brief Get size of configuration area.
- *
- * A part of the DataFlash may be used to store configuration parameters,
- * like the network interface MAC address, the local hostname etc. The
- * size of this area may be configured by defining \ref NUT_CONFIG_AT45D_SIZE.
- * Otherwise one full page is used.
- *
- * \return The number of bytes available for configuration data. In case of
- * an error, 0 is returned.
- */
- size_t SpiAt45dConfigSize(void)
- {
- size_t rc = 0;
- if (SpiAt45dConfigDevice() == 0) {
- #ifdef NUT_CONFIG_AT45D_SIZE
- rc = NUT_CONFIG_AT45D_SIZE;
- #else
- rc = (size_t) SpiAt45dPageSize(devSysConf);
- #endif
- }
- return rc;
- }
- /*!
- * \brief Load configuration parameters from flash memory.
- *
- * \param pos Start location within configuration sector.
- * \param data Points to a buffer that receives the contents.
- * \param len Number of bytes to read.
- *
- * \return 0 on success or -1 in case of an error.
- */
- int SpiAt45dConfigRead(size_t pos, void *data, size_t len)
- {
- int rc = -1;
- uint8_t *buff;
- int csize = SpiAt45dConfigSize();
- /* Load the complete configuration area. */
- if (csize >= pos + len && (buff = malloc(csize)) != NULL) {
- uint32_t cpage = SpiAt45dConfigPage();
- if (SpiAt45dPageRead(devSysConf, cpage, buff, csize) == csize) {
- /* Copy requested contents to caller's buffer. */
- memcpy(data, buff + pos, len);
- rc = 0;
- }
- free(buff);
- }
- return rc;
- }
- /*!
- * \brief Store configuration parameters in flash memory.
- *
- * \param pos Start location within configuration sector.
- * \param data Points to a buffer that contains the bytes to store.
- * \param len Number of bytes to store.
- *
- * \return 0 on success or -1 in case of an error.
- */
- int SpiAt45dConfigWrite(size_t pos, const void *data, size_t len)
- {
- int rc = -1;
- uint8_t *pbuff;
- uint8_t *data_buff = (uint8_t*) data;
- int csize = SpiAt45dConfigSize();
- int psize = SpiAt45dPageSize(devSysConf);
- int page = SpiAt45dConfigPage();
- int offset;
- int wsize;
- int remaining = len;
- if ((len > 0) && (csize >= pos + len) && (len > 0) && ((pbuff = malloc(psize)) != NULL)) {
- page += pos / psize;
- offset = pos % psize;
- wsize = (offset + len > psize) ? psize - offset : psize;
- if (remaining < wsize) {
- wsize = remaining;
- }
- while (remaining > 0) {
- /* Load one full page */
- if (SpiAt45dPageRead(devSysConf, page, pbuff, psize) == psize) {
- /* Compare old with new contents. */
- if (memcmp(pbuff + offset, data_buff, wsize)) {
- /* New contents differs. Copy it into the sector buffer. */
- memcpy(pbuff + offset, data_buff, wsize);
- /* Erase sector and write new data. */
- if (SpiAt45dPageWrite(devSysConf, page, pbuff, psize) == psize) {
- rc = 0;
- } else {
- rc = -1;
- break;
- }
- } else {
- rc = 0;
- }
- } else {
- rc = -1;
- break;
- }
- data_buff += wsize;
- remaining -= wsize;
- offset = 0;
- page ++;
- wsize = (remaining > psize) ? psize : remaining;
- }
- free(pbuff);
- }
- return rc;
- }
|