spibus0at91ssc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /*
  2. * Copyright (C) 2009, 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 arch/arm/dev/atmel/spibus0at91ssc.c
  36. * \brief SSC SPI bus 0 driver.
  37. *
  38. * \verbatim
  39. * $Id$
  40. * \endverbatim
  41. */
  42. #include <cfg/spi.h>
  43. #include <cfg/arch/gpio.h>
  44. #include <dev/gpio.h>
  45. #include <dev/spibus_ssc.h>
  46. #include <sys/event.h>
  47. #include <sys/timer.h>
  48. #include <sys/nutdebug.h>
  49. #include <errno.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52. #ifdef ELEKTOR_IR1
  53. #ifndef SSC0SPI_CS0_PIO_BIT
  54. #define SSC0SPI_CS0_PIO_BIT 15
  55. #endif
  56. #ifndef SSC0SPI_CS0_PIO_ID
  57. #define SSC0SPI_CS0_PIO_ID PIOA_ID
  58. #endif
  59. #endif
  60. #if defined(SSC0SPI_CS0_PIO_BIT) && defined(SSC0SPI_CS0_PIO_ID)
  61. #undef GPIO_ID
  62. #define GPIO_ID SSC0SPI_CS0_PIO_ID
  63. #include <cfg/arch/porttran.h>
  64. static INLINE void SSC0SPI_CS0_LO(void)
  65. {
  66. GPIO_SET_LO(SSC0SPI_CS0_PIO_BIT);
  67. }
  68. static INLINE void SSC0SPI_CS0_HI(void)
  69. {
  70. GPIO_SET_HI(SSC0SPI_CS0_PIO_BIT);
  71. }
  72. static INLINE void SSC0SPI_CS0_SO(void)
  73. {
  74. GPIO_ENABLE(SSC0SPI_CS0_PIO_BIT);
  75. GPIO_OUTPUT(SSC0SPI_CS0_PIO_BIT);
  76. }
  77. #else
  78. #define SSC0SPI_CS0_LO()
  79. #define SSC0SPI_CS0_HI()
  80. #define SSC0SPI_CS0_SO()
  81. #endif
  82. static AT91SSCREG gspi_reg0;
  83. static uint8_t * volatile spi0_txp;
  84. static uint8_t * volatile spi0_rxp;
  85. static volatile size_t spi0_xc;
  86. static uint8_t ssc_pdc_txbuf[512] SECTION_BSS_IRAM;
  87. static uint8_t ssc_pdc_rxbuf[512] SECTION_BSS_IRAM;
  88. /*!
  89. * \brief Set the specified chip select to a given level.
  90. */
  91. static AT91SSCREG *SscSpi0ChipSelect(uint_fast8_t cs, uint_fast8_t hi)
  92. {
  93. if (cs == 0) {
  94. if (hi) {
  95. SSC0SPI_CS0_HI();
  96. } else {
  97. SSC0SPI_CS0_LO();
  98. }
  99. SSC0SPI_CS0_SO();
  100. return &gspi_reg0;
  101. }
  102. return NULL;
  103. }
  104. void SscSpiBus0Interrupt(void *arg)
  105. {
  106. if (spi0_xc) {
  107. if (spi0_rxp) {
  108. *spi0_rxp++ = (uint8_t) inr(SSC_RHR);
  109. }
  110. spi0_xc--;
  111. }
  112. if (spi0_xc) {
  113. if (spi0_txp) {
  114. outr(SSC_THR, *spi0_txp);
  115. spi0_txp++;
  116. } else {
  117. outr(SSC_THR, 0xFFFFFFFF);
  118. }
  119. } else {
  120. NutEventPostFromIrq((void **)arg);
  121. }
  122. }
  123. void SscSpiBus0PdcIrq(void *arg)
  124. {
  125. NutEventPostFromIrq((void **)arg);
  126. }
  127. static void SscSpiBus0Clock(int xlen)
  128. {
  129. while (xlen--) {
  130. outr(SSC_THR, 0xFF);
  131. while ((inr(SSC_SR) & SSC_RXRDY) == 0);
  132. inr(SSC_RHR);
  133. }
  134. }
  135. static void SscSpiBus0Read(uint8_t *rxbuf, int xlen)
  136. {
  137. while (xlen--) {
  138. outr(SSC_THR, 0xFF);
  139. while ((inr(SSC_SR) & SSC_RXRDY) == 0);
  140. *rxbuf++ = (uint8_t) inr(SSC_RHR);
  141. }
  142. }
  143. static void SscSpiBus0Write(const uint8_t *txbuf, int xlen)
  144. {
  145. while (xlen--) {
  146. outr(SSC_THR, *txbuf);
  147. txbuf++;
  148. while ((inr(SSC_SR) & SSC_RXRDY) == 0);
  149. inr(SSC_RHR);
  150. }
  151. }
  152. static void SscSpiBus0WriteRead(const uint8_t *txbuf, uint8_t *rxbuf, int xlen)
  153. {
  154. while (xlen--) {
  155. outr(SSC_THR, *txbuf);
  156. txbuf++;
  157. while ((inr(SSC_SR) & SSC_RXRDY) == 0);
  158. *rxbuf++ = (uint8_t) inr(SSC_RHR);
  159. }
  160. }
  161. /*!
  162. * \brief Transfer data on the SPI bus.
  163. *
  164. * A device must have been selected by calling SscSpi0Select().
  165. *
  166. * \param node Specifies the SPI bus node.
  167. * \param txbuf Pointer to the transmit buffer. If NULL, undetermined
  168. * byte values are transmitted.
  169. * \param rxbuf Pointer to the receive buffer. If NULL, then incoming
  170. * data is discarded.
  171. * \param xlen Number of bytes to transfer.
  172. *
  173. * \return Always 0.
  174. */
  175. static int SscSpiBus0Transfer(NUTSPINODE * node, const void *txbuf, void *rxbuf, int xlen)
  176. {
  177. if (xlen < 32) {
  178. if (txbuf) {
  179. if (rxbuf) {
  180. SscSpiBus0WriteRead((const uint8_t *) txbuf, (uint8_t *) rxbuf, xlen);
  181. } else {
  182. SscSpiBus0Write((const uint8_t *) txbuf, xlen);
  183. }
  184. }
  185. else if (rxbuf) {
  186. SscSpiBus0Read((uint8_t *) rxbuf, xlen);
  187. }
  188. else {
  189. SscSpiBus0Clock(xlen);
  190. }
  191. } else {
  192. #if 0
  193. spi0_txp = (uint8_t *) txbuf;
  194. spi0_rxp = (uint8_t *) rxbuf;
  195. spi0_xc = (size_t) xlen;
  196. /* Enable and kick interrupts. */
  197. if (rxbuf) {
  198. outr(SSC_IER, SSC_RXRDY);
  199. } else {
  200. outr(SSC_IER, SSC_TXRDY);
  201. }
  202. if (txbuf) {
  203. outr(SSC_THR, *spi0_txp);
  204. spi0_txp++;
  205. } else {
  206. outr(SSC_THR, 0xFFFFFFFF);
  207. }
  208. /* Wait until transfer has finished. */
  209. NutEventWait(&node->node_bus->bus_ready, NUT_WAIT_INFINITE);
  210. outr(SSC_IDR, SSC_RXRDY);
  211. #else
  212. if (txbuf) {
  213. memcpy(ssc_pdc_txbuf, txbuf, xlen);
  214. } else {
  215. memset(ssc_pdc_txbuf, 0xFF, xlen);
  216. }
  217. if (rxbuf) {
  218. memset(ssc_pdc_rxbuf, 0xFF, 512);
  219. }
  220. /* Set first transmit pointer and counter. */
  221. outr(SSC_TPR, (unsigned int) ssc_pdc_txbuf);
  222. outr(SSC_TCR, (unsigned int) xlen);
  223. /* Set first receive pointer and counter. */
  224. outr(SSC_RPR, (unsigned int) ssc_pdc_rxbuf);
  225. outr(SSC_RCR, (unsigned int) xlen);
  226. outr(SSC_IER, SSC_RXBUFF);
  227. outr(SSC_PTCR, PDC_TXTEN | PDC_RXTEN);
  228. /* Wait until transfer has finished. */
  229. NutEventWait(&node->node_bus->bus_ready, NUT_WAIT_INFINITE);
  230. outr(SSC_PTCR, PDC_TXTDIS | PDC_RXTDIS);
  231. outr(SSC_IDR, SSC_RXBUFF);
  232. if (rxbuf) {
  233. memcpy(rxbuf, ssc_pdc_rxbuf, xlen);
  234. }
  235. #endif
  236. }
  237. return 0;
  238. }
  239. /*!
  240. * \brief Initialize an SPI bus node.
  241. *
  242. * This routine is called for each SPI node, which is registered via
  243. * NutRegisterSpiDevice().
  244. *
  245. * \param node Specifies the SPI bus node.
  246. *
  247. * \return Always 0.
  248. */
  249. static int SscSpiBus0NodeInit(NUTSPINODE * node)
  250. {
  251. NUTSPIBUS *bus = node->node_bus;
  252. AT91SSCREG *sscreg;
  253. /* Try to deactivate the chip select and retrieve the shadow regs. */
  254. sscreg = SscSpi0ChipSelect(node->node_cs, 1);
  255. if (sscreg == NULL) {
  256. /* Invalid chip select. */
  257. return -1;
  258. }
  259. /* Check if this is the first call. */
  260. if (node->node_stat == NULL) {
  261. /* Bind the shadow register to this node. */
  262. node->node_stat = sscreg;
  263. /* Perform software reset. */
  264. outr(SSC_CR, SSC_SWRST | SSC_TXDIS | SSC_RXDIS);
  265. /* Enable SSC clock. */
  266. outr(PMC_PCER, _BV(SSC_ID));
  267. /* Select SSC peripheral functions. */
  268. outr(PIOA_ASR, _BV(PA16_TK_A) | _BV(PA17_TD_A) | _BV(PA18_RD_A) | _BV(PA19_RK_A));
  269. /* Enable SSC peripheral pins. */
  270. outr(PIOA_PDR, _BV(PA16_TK_A) | _BV(PA17_TD_A) | _BV(PA18_RD_A) | _BV(PA19_RK_A));
  271. /* Update shadow registers. */
  272. SscSpiSetup(node);
  273. /* Set clock divider from shadow register. */
  274. outr(SSC_CMR, sscreg->at91ssc_cmr);
  275. /* Set receive clock mode. */
  276. outr(SSC_RCMR, SSC_CKS_PIN | SSC_CKI | SSC_START_TX);
  277. /* Set transmit clock mode. */
  278. outr(SSC_TCMR, SSC_CKS_DIV | SSC_CKO_TRAN);
  279. /* Set receive and transmit frame mode from shadow register. */
  280. outr(SSC_RFMR, sscreg->at91ssc_fmr);
  281. outr(SSC_TFMR, sscreg->at91ssc_fmr);
  282. /* Enable transmitter. */
  283. outr(SSC_CR, SSC_TXEN | SSC_RXEN);
  284. #if 0
  285. NutRegisterIrqHandler(bus->bus_sig, SscSpiBus0Interrupt, &bus->bus_ready);
  286. #else
  287. NutRegisterIrqHandler(bus->bus_sig, SscSpiBus0PdcIrq, &bus->bus_ready);
  288. #endif
  289. outr(SSC_IDR, (unsigned int) - 1);
  290. NutIrqEnable(bus->bus_sig);
  291. }
  292. return 0;
  293. }
  294. /*! \brief Select a device on the SPI bus.
  295. *
  296. * Locks and activates the bus for the specified node.
  297. *
  298. * \param node Specifies the SPI bus node.
  299. * \param tmo Timeout in milliseconds. To disable timeout, set this
  300. * parameter to NUT_WAIT_INFINITE.
  301. *
  302. * \return 0 on success. In case of an error, -1 is returned and the bus
  303. * is not locked.
  304. */
  305. static int SscSpiBus0Select(NUTSPINODE * node, uint32_t tmo)
  306. {
  307. int rc;
  308. /* Sanity check. */
  309. NUTASSERT(node != NULL);
  310. NUTASSERT(node->node_stat != NULL);
  311. /* Allocate the bus. */
  312. rc = NutEventWait(&node->node_bus->bus_mutex, tmo);
  313. if (rc) {
  314. errno = EIO;
  315. } else {
  316. AT91SSCREG *sscreg = (AT91SSCREG *) node->node_stat;
  317. /* If the mode changed, update our shadow registers. */
  318. if (node->node_mode & SPI_MODE_UPDATE) {
  319. SscSpiSetup(node);
  320. }
  321. /* Set the clock rate for this node. */
  322. outr(SSC_CMR, sscreg->at91ssc_cmr);
  323. /* Set receive and transmit frame mode for this node. */
  324. outr(SSC_RFMR, sscreg->at91ssc_fmr);
  325. outr(SSC_TFMR, sscreg->at91ssc_fmr);
  326. /* Activate the node's chip select. */
  327. SscSpi0ChipSelect(node->node_cs, 0);
  328. }
  329. return rc;
  330. }
  331. /*! \brief Deselect a device on the SPI bus.
  332. *
  333. * Deactivates the chip select and unlocks the bus.
  334. *
  335. * \param node Specifies the SPI bus node.
  336. *
  337. * \return Always 0.
  338. */
  339. static int SscSpiBus0Deselect(NUTSPINODE * node)
  340. {
  341. /* Sanity check. */
  342. NUTASSERT(node != NULL);
  343. NUTASSERT(node->node_bus != NULL);
  344. /* Deactivate the node's chip select. */
  345. SscSpi0ChipSelect(node->node_cs, 1);
  346. /* Release the bus. */
  347. NutEventPost(&node->node_bus->bus_mutex);
  348. return 0;
  349. }
  350. /*!
  351. * \brief AT91 SSC SPI bus driver implementation structure.
  352. */
  353. NUTSPIBUS spiBus0Ssc = {
  354. NULL, /*!< Bus mutex semaphore (bus_mutex). */
  355. NULL, /*!< Bus ready signal (bus_ready). */
  356. 0, /*!< Unused bus base address (bus_base). */
  357. &sig_SSC, /*!< Bus interrupt handler (bus_sig). */
  358. SscSpiBus0NodeInit, /*!< Initialize the bus (bus_initnode). */
  359. SscSpiBus0Select, /*!< Select the specified device (bus_alloc). */
  360. SscSpiBus0Deselect, /*!< Deselect the specified device (bus_release). */
  361. SscSpiBus0Transfer, /*!< Transfer data to and from a specified device (bus_transfer). */
  362. NutSpiBusWait, /*!< Wait for bus transfer ready (bus_wait). */
  363. NutSpiBusSetMode, /*!< Set SPI mode of a specified device (bus_set_mode). */
  364. NutSpiBusSetRate, /*!< Set clock rate of a specified device (bus_set_rate). */
  365. NutSpiBusSetBits /*!< Set number of data bits of a specified device (bus_set_bits). */
  366. };