nvmem_at45d.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * Copyright (C) 2008-2009 by egnite GmbH
  3. * Copyright (C) 2006 by egnite Software GmbH
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. Neither the name of the copyright holders nor the names of
  17. * contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * For additional information see http://www.ethernut.de/
  34. */
  35. /*!
  36. * \file dev/nvmem_at45d.c
  37. * \brief Non-volatile memory support using Adesto/Atmel AT45 serial
  38. * DataFlash memory chips.
  39. *
  40. * \verbatim
  41. * $Id: nvmem_at45d.c 5227 2013-07-19 08:48:47Z u_bonnes $
  42. * \endverbatim
  43. */
  44. #include <cfg/eeprom.h>
  45. #include <cfg/memory.h>
  46. #include <dev/board.h>
  47. #include <dev/spi_at45d.h>
  48. #include <sys/nutdebug.h>
  49. #include <stdlib.h>
  50. #include <string.h>
  51. #include <memdebug.h>
  52. #include <dev/nvmem_at45d.h>
  53. static NUTDEVICE *devSysConf;
  54. /*!
  55. * \brief Mimic initialization without actually registering the device.
  56. *
  57. * This is a little bit tricky. If we want to use the existing DataFlash
  58. * routines for accessing the system configuration, they must be
  59. * properly initialized. This is normally done by calling NutRegister...
  60. * in the application. However, the system configuration must be know
  61. * before entering any application code.
  62. *
  63. */
  64. static int SpiAt45dConfigDevice(void)
  65. {
  66. #if !defined(DEV_SPIBUS)
  67. return -1;
  68. #else /* DEV_SPIBUS */
  69. if (devSysConf == NULL) {
  70. NUTSPINODE *node;
  71. NUTDEVICE *dev;
  72. #if NUT_CONFIG_AT45D == 0
  73. dev = &devSpiAt45d0;
  74. #elif NUT_CONFIG_AT45D == 1
  75. dev = &devSpiAt45d1;
  76. #elif NUT_CONFIG_AT45D == 2
  77. dev = &devSpiAt45d2;
  78. #elif NUT_CONFIG_AT45D == 3
  79. dev = &devSpiAt45d3;
  80. #else
  81. return -1;
  82. #endif
  83. node = (NUTSPINODE *) dev->dev_icb;
  84. NUTASSERT(node != NULL);
  85. if (node->node_bus == NULL) {
  86. NUTSPIBUS *bus;
  87. bus = &DEV_SPIBUS;
  88. node->node_bus = bus;
  89. }
  90. #ifdef NUT_CONFIG_AT45D_CS
  91. node->node_cs = NUT_CONFIG_AT45D_CS;
  92. #endif
  93. NUTASSERT(node->node_bus->bus_initnode != NULL);
  94. if ((*node->node_bus->bus_initnode) (node)) {
  95. return -1;
  96. }
  97. NutEventPost(&node->node_bus->bus_mutex);
  98. if (SpiAt45dInit(dev)) {
  99. return -1;
  100. }
  101. devSysConf = dev;
  102. }
  103. return 0;
  104. #endif /* DEV_SPIBUS */
  105. }
  106. static uint32_t SpiAt45dConfigPage(void)
  107. {
  108. #ifdef NUT_CONFIG_AT45D_PAGE
  109. return NUT_CONFIG_AT45D_PAGE;
  110. #else
  111. return SpiAt45dPages(devSysConf) - 1;
  112. #endif
  113. }
  114. /*!
  115. * \brief Get size of configuration area.
  116. *
  117. * A part of the DataFlash may be used to store configuration parameters,
  118. * like the network interface MAC address, the local hostname etc. The
  119. * size of this area may be configured by defining \ref NUT_CONFIG_AT45D_SIZE.
  120. * Otherwise one full page is used.
  121. *
  122. * \return The number of bytes available for configuration data. In case of
  123. * an error, 0 is returned.
  124. */
  125. size_t SpiAt45dConfigSize(void)
  126. {
  127. size_t rc = 0;
  128. if (SpiAt45dConfigDevice() == 0) {
  129. #ifdef NUT_CONFIG_AT45D_SIZE
  130. rc = NUT_CONFIG_AT45D_SIZE;
  131. #else
  132. rc = (size_t) SpiAt45dPageSize(devSysConf);
  133. #endif
  134. }
  135. return rc;
  136. }
  137. /*!
  138. * \brief Load configuration parameters from flash memory.
  139. *
  140. * \param pos Start location within configuration sector.
  141. * \param data Points to a buffer that receives the contents.
  142. * \param len Number of bytes to read.
  143. *
  144. * \return 0 on success or -1 in case of an error.
  145. */
  146. int SpiAt45dConfigRead(size_t pos, void *data, size_t len)
  147. {
  148. int rc = -1;
  149. uint8_t *buff;
  150. int csize = SpiAt45dConfigSize();
  151. /* Load the complete configuration area. */
  152. if (csize >= pos + len && (buff = malloc(csize)) != NULL) {
  153. uint32_t cpage = SpiAt45dConfigPage();
  154. if (SpiAt45dPageRead(devSysConf, cpage, buff, csize) == csize) {
  155. /* Copy requested contents to caller's buffer. */
  156. memcpy(data, buff + pos, len);
  157. rc = 0;
  158. }
  159. free(buff);
  160. }
  161. return rc;
  162. }
  163. /*!
  164. * \brief Store configuration parameters in flash memory.
  165. *
  166. * \param pos Start location within configuration sector.
  167. * \param data Points to a buffer that contains the bytes to store.
  168. * \param len Number of bytes to store.
  169. *
  170. * \return 0 on success or -1 in case of an error.
  171. */
  172. int SpiAt45dConfigWrite(size_t pos, const void *data, size_t len)
  173. {
  174. int rc = -1;
  175. uint8_t *pbuff;
  176. uint8_t *data_buff = (uint8_t*) data;
  177. int csize = SpiAt45dConfigSize();
  178. int psize = SpiAt45dPageSize(devSysConf);
  179. int page = SpiAt45dConfigPage();
  180. int offset;
  181. int wsize;
  182. int remaining = len;
  183. if ((len > 0) && (csize >= pos + len) && (len > 0) && ((pbuff = malloc(psize)) != NULL)) {
  184. page += pos / psize;
  185. offset = pos % psize;
  186. wsize = (offset + len > psize) ? psize - offset : psize;
  187. if (remaining < wsize) {
  188. wsize = remaining;
  189. }
  190. while (remaining > 0) {
  191. /* Load one full page */
  192. if (SpiAt45dPageRead(devSysConf, page, pbuff, psize) == psize) {
  193. /* Compare old with new contents. */
  194. if (memcmp(pbuff + offset, data_buff, wsize)) {
  195. /* New contents differs. Copy it into the sector buffer. */
  196. memcpy(pbuff + offset, data_buff, wsize);
  197. /* Erase sector and write new data. */
  198. if (SpiAt45dPageWrite(devSysConf, page, pbuff, psize) == psize) {
  199. rc = 0;
  200. } else {
  201. rc = -1;
  202. break;
  203. }
  204. } else {
  205. rc = 0;
  206. }
  207. } else {
  208. rc = -1;
  209. break;
  210. }
  211. data_buff += wsize;
  212. remaining -= wsize;
  213. offset = 0;
  214. page ++;
  215. wsize = (remaining > psize) ? psize : remaining;
  216. }
  217. free(pbuff);
  218. }
  219. return rc;
  220. }