spi_node_at45d.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /*
  2. * Copyright (C) 2008-2011 by egnite GmbH
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of the copyright holders nor the names of
  16. * contributors may be used to endorse or promote products derived
  17. * from this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  22. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  23. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  25. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  26. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  27. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  28. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  29. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. *
  32. * For additional information see http://www.ethernut.de/
  33. */
  34. /*!
  35. * \file dev/spi_node_at45d.c
  36. * \brief Low level routines for Adesto/Atmel AT45D SPI Flash.
  37. *
  38. * \verbatim
  39. * $Id$
  40. * \endverbatim
  41. */
  42. #include <cfg/memory.h>
  43. #include <dev/blockdev.h>
  44. #include <sys/nutdebug.h>
  45. #include <sys/timer.h>
  46. #include <stdlib.h>
  47. #include <string.h>
  48. #include <dev/spi_node_at45d.h>
  49. /*!
  50. * \addtogroup xgSpiNodeAt45d
  51. */
  52. /*@{*/
  53. typedef struct _AT45D_DCB {
  54. HANDLE dcb_lock;
  55. } AT45D_DCB;
  56. static AT45D_DCB dcbAt45d0 = {
  57. SIGNALED
  58. };
  59. static AT45D_DCB dcbAt45d1 = {
  60. SIGNALED
  61. };
  62. static AT45D_DCB dcbAt45d2 = {
  63. SIGNALED
  64. };
  65. static AT45D_DCB dcbAt45d3 = {
  66. SIGNALED
  67. };
  68. int At45dNodeLock(NUTSPINODE * node)
  69. {
  70. AT45D_DCB *dcb = (AT45D_DCB *) node->node_dcb;
  71. return NutEventWait(&dcb->dcb_lock, NUT_WAIT_INFINITE);
  72. }
  73. void At45dNodeUnlock(NUTSPINODE * node)
  74. {
  75. AT45D_DCB *dcb = (AT45D_DCB *) node->node_dcb;
  76. NutEventPost(&dcb->dcb_lock);
  77. }
  78. /*!
  79. * \brief Transmit DataFlash command.
  80. *
  81. * \param node Specifies the SPI node.
  82. * \param op Command code.
  83. * \param parm Command parameter.
  84. * \param oplen Command length.
  85. *
  86. * \return 0 on success, -1 on errors.
  87. */
  88. static int At45dNodeTransmitCmd(NUTSPINODE * node, uint8_t op, uint32_t parm, uint_fast8_t oplen)
  89. {
  90. uint8_t cmd[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  91. NUTASSERT(oplen <= sizeof(cmd));
  92. cmd[0] = op;
  93. if (parm) {
  94. cmd[1] = (uint8_t) (parm >> 16);
  95. cmd[2] = (uint8_t) (parm >> 8);
  96. cmd[3] = (uint8_t) parm;
  97. }
  98. return (*((NUTSPIBUS *) node->node_bus)->bus_transfer) (node, cmd, NULL, oplen);
  99. }
  100. /*!
  101. * \brief Execute DataFlash command with data transfer.
  102. *
  103. * \param node Specifies the SPI node.
  104. * \param op Command code.
  105. * \param parm Command parameter.
  106. * \param oplen Command length.
  107. * \param txbuf Pointer to the transmit data buffer, may be set to NULL.
  108. * \param rxbuf Pointer to the receive data buffer, may be set to NULL.
  109. * \param xlen Number of byte to receive and/or transmit.
  110. *
  111. * \return 0 on success, -1 on errors.
  112. */
  113. int At45dNodeTransfer(NUTSPINODE * node, uint8_t op, uint32_t parm, uint_fast8_t oplen,
  114. const void *txbuf, void *rxbuf, int xlen)
  115. {
  116. int rc;
  117. NUTSPIBUS *bus;
  118. /* Sanity checks. */
  119. NUTASSERT(node != NULL);
  120. bus = (NUTSPIBUS *) node->node_bus;
  121. NUTASSERT(bus != NULL);
  122. NUTASSERT(bus->bus_alloc != NULL);
  123. NUTASSERT(bus->bus_transfer != NULL);
  124. NUTASSERT(bus->bus_release != NULL);
  125. rc = (*bus->bus_alloc) (node, 0);
  126. if (rc == 0) {
  127. rc = At45dNodeTransmitCmd(node, op, parm, oplen);
  128. if (rc == 0 && xlen) {
  129. rc = (*bus->bus_transfer) (node, txbuf, rxbuf, xlen);
  130. }
  131. (*bus->bus_release) (node);
  132. }
  133. return rc;
  134. }
  135. /*!
  136. * \brief Execute DataFlash command without data.
  137. *
  138. * \param node Specifies the SPI node.
  139. * \param op Command operation code.
  140. * \param parm Optional command parameter.
  141. * \param oplen Command length.
  142. *
  143. * \return 0 on success, -1 on errors.
  144. */
  145. int At45dNodeCommand(NUTSPINODE * node, uint8_t op, uint32_t parm, uint_fast8_t oplen)
  146. {
  147. return At45dNodeTransfer(node, op, parm, oplen, NULL, NULL, 0);
  148. }
  149. /*!
  150. * \brief Query the status of the serial flash.
  151. *
  152. * \param node Specifies the SPI node.
  153. *
  154. * \return 0 on success or -1 in case of an error.
  155. */
  156. uint8_t At45dNodeStatus(NUTSPINODE * node)
  157. {
  158. int rc;
  159. uint8_t cmd[2] = { DFCMD_READ_STATUS, 0xFF };
  160. NUTSPIBUS *bus;
  161. /* Sanity checks. */
  162. NUTASSERT(node != NULL);
  163. NUTASSERT(node->node_bus != NULL);
  164. bus = (NUTSPIBUS *) node->node_bus;
  165. NUTASSERT(bus->bus_alloc != NULL);
  166. NUTASSERT(bus->bus_transfer != NULL);
  167. NUTASSERT(bus->bus_wait != NULL);
  168. NUTASSERT(bus->bus_release != NULL);
  169. rc = (*bus->bus_alloc) (node, 0);
  170. if (rc == 0) {
  171. rc = (*bus->bus_transfer) (node, cmd, cmd, 2);
  172. if (rc == 0) {
  173. (*bus->bus_wait) (node, NUT_WAIT_INFINITE);
  174. rc = cmd[1];
  175. }
  176. (*bus->bus_release) (node);
  177. }
  178. return (uint8_t) rc;
  179. }
  180. /*!
  181. * \brief Wait until DataFlash memory cycle finished.
  182. *
  183. * \param node Specifies the SPI node.
  184. * \param tmo Number of loops (or milliseconds) to wait at max.
  185. * \param poll If 0, the current thread will be suspended for
  186. * 1 millisecond between each retry. Otherwise the
  187. * polling loop will not sleep, but may be still suspended
  188. * by the lower level SPI bus driver.
  189. *
  190. * \return 0 on success or -1 in case of an error.
  191. */
  192. int At45dNodeWaitReady(NUTSPINODE * node, uint32_t tmo, int poll)
  193. {
  194. uint8_t sr;
  195. while (((sr = At45dNodeStatus(node)) & 0x80) == 0) {
  196. if (!poll) {
  197. NutSleep(1);
  198. }
  199. if (tmo-- == 0) {
  200. return -1;
  201. }
  202. }
  203. return 0;
  204. }
  205. /*!
  206. * \brief Determine the DataFlash type.
  207. *
  208. * If the board contains a known DataFlash chip, but couldn't be
  209. * determined by this routine, then most probably the chip select
  210. * configuration is wrong.
  211. *
  212. * \param node Specifies the SPI node.
  213. *
  214. * \return Pointer to a \ref AT45D_INFO structure, which contains
  215. * the relevant DataFlash parameters. If no known DataFlash
  216. * is available, then NULL is returned.
  217. */
  218. AT45D_INFO *At45dNodeProbe(NUTSPINODE * node)
  219. {
  220. int_fast8_t i;
  221. uint8_t sr;
  222. if (At45dNodeWaitReady(node, 10, 1) == 0) {
  223. sr = At45dNodeStatus(node);
  224. if (sr != 0xff) {
  225. sr &= AT45D_STATUS_DENSITY | AT45D_STATUS_PAGE_SIZE;
  226. for (i = at45d_known_types; --i >= 0;) {
  227. if (sr == at45d_info[i].at45d_srval) {
  228. return &at45d_info[i];
  229. }
  230. }
  231. }
  232. }
  233. return NULL;
  234. }
  235. #ifndef SPI_RATE_AT45D0
  236. #define SPI_RATE_AT45D0 33000000
  237. #endif
  238. #ifndef SPI_MODE_AT45D0
  239. #ifdef SPI_CSHIGH_AT45D0
  240. #define SPI_MODE_AT45D0 (SPI_MODE_3 | SPI_MODE_CSHIGH)
  241. #else
  242. #define SPI_MODE_AT45D0 SPI_MODE_3
  243. #endif
  244. #elif defined(SPI_CSHIGH_AT45D0)
  245. /* This is a tricky problem. Originally we didn't provide mode settings
  246. ** in the Configurator, but used mode 3 only. After experiencing problems
  247. ** with mode switching on the EIR, we need to set mode 0 for that board,
  248. ** which spoils our chip select polarity setting. */
  249. #if SPI_MODE_AT45D0 == SPI_MODE_0
  250. #undef SPI_MODE_AT45D0
  251. #define SPI_MODE_AT45D0 (SPI_MODE_0 | SPI_MODE_CSHIGH)
  252. #elif SPI_MODE_AT45D0 == SPI_MODE_3
  253. #undef SPI_MODE_AT45D0
  254. #define SPI_MODE_AT45D0 (SPI_MODE_3 | SPI_MODE_CSHIGH)
  255. #endif
  256. #endif /* SPI_MODE_AT45D0 */
  257. /*!
  258. * \brief First AT45D DataFlash SPI node implementation structure.
  259. */
  260. NUTSPINODE nodeAt45d0 = {
  261. NULL, /*!< \brief Pointer to the bus controller driver, node_bus. */
  262. NULL, /*!< \brief Pointer to the bus device driver specific settings, node_stat. */
  263. SPI_RATE_AT45D0, /*!< \brief Initial clock rate, node_rate. */
  264. SPI_MODE_AT45D0, /*!< \brief Initial mode, node_mode. */
  265. 8, /*!< \brief Initial data bits, node_bits. */
  266. 0, /*!< \brief Chip select, node_cs. */
  267. &dcbAt45d0 /*!< \brief Pointer to our private device control block, node_dcb. */
  268. };
  269. #ifndef SPI_RATE_AT45D1
  270. #define SPI_RATE_AT45D1 33000000
  271. #endif
  272. #ifndef SPI_MODE_AT45D1
  273. #ifdef SPI_CSHIGH_AT45D1
  274. #define SPI_MODE_AT45D1 (SPI_MODE_3 | SPI_MODE_CSHIGH)
  275. #else
  276. #define SPI_MODE_AT45D1 SPI_MODE_3
  277. #endif
  278. #elif defined(SPI_CSHIGH_AT45D1)
  279. /* Same problem problem as above. */
  280. #if SPI_MODE_AT45D1 == SPI_MODE_0
  281. #undef SPI_MODE_AT45D1
  282. #define SPI_MODE_AT45D1 (SPI_MODE_0 | SPI_MODE_CSHIGH)
  283. #elif SPI_MODE_AT45D1 == SPI_MODE_3
  284. #undef SPI_MODE_AT45D1
  285. #define SPI_MODE_AT45D1 (SPI_MODE_3 | SPI_MODE_CSHIGH)
  286. #endif
  287. #endif /* SPI_MODE_AT45D1 */
  288. /*!
  289. * \brief Second AT45D DataFlash SPI node implementation structure.
  290. */
  291. NUTSPINODE nodeAt45d1 = {
  292. NULL, /*!< \brief Pointer to the bus controller driver, node_bus. */
  293. NULL, /*!< \brief Pointer to the bus device driver specific settings, node_stat. */
  294. SPI_RATE_AT45D1, /*!< \brief Initial clock rate, node_rate. */
  295. SPI_MODE_AT45D1, /*!< \brief Initial mode, node_mode. */
  296. 8, /*!< \brief Initial data bits, node_bits. */
  297. 0, /*!< \brief Chip select, node_cs. */
  298. &dcbAt45d1 /*!< \brief Pointer to our private device control block, node_dcb. */
  299. };
  300. #ifndef SPI_RATE_AT45D2
  301. #define SPI_RATE_AT45D2 33000000
  302. #endif
  303. #ifndef SPI_MODE_AT45D2
  304. #ifdef SPI_CSHIGH_AT45D2
  305. #define SPI_MODE_AT45D2 (SPI_MODE_3 | SPI_MODE_CSHIGH)
  306. #else
  307. #define SPI_MODE_AT45D2 SPI_MODE_3
  308. #endif
  309. #elif defined(SPI_CSHIGH_AT45D2)
  310. /* Same problem problem as above. */
  311. #if SPI_MODE_AT45D2 == SPI_MODE_0
  312. #undef SPI_MODE_AT45D2
  313. #define SPI_MODE_AT45D2 (SPI_MODE_0 | SPI_MODE_CSHIGH)
  314. #elif SPI_MODE_AT45D2 == SPI_MODE_3
  315. #undef SPI_MODE_AT45D2
  316. #define SPI_MODE_AT45D2 (SPI_MODE_3 | SPI_MODE_CSHIGH)
  317. #endif
  318. #endif /* SPI_MODE_AT45D2 */
  319. /*!
  320. * \brief Third AT45D DataFlash SPI node implementation structure.
  321. */
  322. NUTSPINODE nodeAt45d2 = {
  323. NULL, /*!< \brief Pointer to the bus controller driver, node_bus. */
  324. NULL, /*!< \brief Pointer to the bus device driver specific settings, node_stat. */
  325. SPI_RATE_AT45D2, /*!< \brief Initial clock rate, node_rate. */
  326. SPI_MODE_AT45D2, /*!< \brief Initial mode, node_mode. */
  327. 8, /*!< \brief Initial data bits, node_bits. */
  328. 0, /*!< \brief Chip select, node_cs. */
  329. &dcbAt45d2 /*!< \brief Pointer to our private device control block, node_dcb. */
  330. };
  331. #ifndef SPI_RATE_AT45D3
  332. #define SPI_RATE_AT45D3 33000000
  333. #endif
  334. #ifndef SPI_MODE_AT45D3
  335. #ifdef SPI_CSHIGH_AT45D3
  336. #define SPI_MODE_AT45D3 (SPI_MODE_3 | SPI_MODE_CSHIGH)
  337. #else
  338. #define SPI_MODE_AT45D3 SPI_MODE_3
  339. #endif
  340. #elif defined(SPI_CSHIGH_AT45D3)
  341. /* Same problem problem as above. */
  342. #if SPI_MODE_AT45D3 == SPI_MODE_0
  343. #undef SPI_MODE_AT45D3
  344. #define SPI_MODE_AT45D3 (SPI_MODE_0 | SPI_MODE_CSHIGH)
  345. #elif SPI_MODE_AT45D3 == SPI_MODE_3
  346. #undef SPI_MODE_AT45D3
  347. #define SPI_MODE_AT45D3 (SPI_MODE_3 | SPI_MODE_CSHIGH)
  348. #endif
  349. #endif /* SPI_MODE_AT45D3 */
  350. /*!
  351. * \brief Forth AT45D DataFlash SPI node implementation structure.
  352. */
  353. NUTSPINODE nodeAt45d3 = {
  354. NULL, /*!< \brief Pointer to the bus controller driver, node_bus. */
  355. NULL, /*!< \brief Pointer to the bus device driver specific settings, node_stat. */
  356. SPI_RATE_AT45D3, /*!< \brief Initial clock rate, node_rate. */
  357. SPI_MODE_AT45D3, /*!< \brief Initial mode, node_mode. */
  358. 8, /*!< \brief Initial data bits, node_bits. */
  359. 0, /*!< \brief Chip select, node_cs. */
  360. &dcbAt45d3 /*!< \brief Pointer to our private device control block, node_dcb. */
  361. };
  362. /*@}*/