spimss.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /**
  2. * @file spimss.c
  3. * @brief This file contains the function implementations for the
  4. * Serial Peripheral Interface (SPIMSS) peripheral module.
  5. */
  6. /* *****************************************************************************
  7. * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a
  10. * copy of this software and associated documentation files (the "Software"),
  11. * to deal in the Software without restriction, including without limitation
  12. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  13. * and/or sell copies of the Software, and to permit persons to whom the
  14. * Software is furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included
  17. * in all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  20. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  22. * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
  23. * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  24. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  25. * OTHER DEALINGS IN THE SOFTWARE.
  26. *
  27. * Except as contained in this notice, the name of Maxim Integrated
  28. * Products, Inc. shall not be used except as stated in the Maxim Integrated
  29. * Products, Inc. Branding Policy.
  30. *
  31. * The mere transfer of this software does not imply any licenses
  32. * of trade secrets, proprietary technology, copyrights, patents,
  33. * trademarks, maskwork rights, or any other form of intellectual
  34. * property whatsoever. Maxim Integrated Products, Inc. retains all
  35. * ownership rights.
  36. *
  37. * $Date: 2019-05-06 14:44:04 -0500 (Mon, 06 May 2019) $
  38. * $Revision: 43157 $
  39. *
  40. **************************************************************************** */
  41. /* **** Includes **** */
  42. #include <string.h>
  43. #include <stdio.h>
  44. #include <stdint.h>
  45. #include "mxc_config.h"
  46. #include "mxc_assert.h"
  47. #include "mxc_sys.h"
  48. #include "spimss.h"
  49. #include "mxc_lock.h"
  50. /**
  51. * @ingroup spimss
  52. * @{
  53. */
  54. /* **** Definitions **** */
  55. /* **** Globals **** */
  56. typedef struct {
  57. spimss_req_t *req;
  58. } spimss_req_state_t;
  59. static spimss_req_state_t states[MXC_SPIMSS_INSTANCES];
  60. /* **** Functions **** */
  61. static int SPIMSS_TransSetup(mxc_spimss_regs_t *spi, spimss_req_t *req, int master);
  62. static uint32_t SPIMSS_MasterTransHandler(mxc_spimss_regs_t *spi, spimss_req_t *req);
  63. static uint32_t SPIMSS_TransHandler(mxc_spimss_regs_t *spi, spimss_req_t *req);
  64. static uint32_t SPIMSS_SlaveTransHandler(mxc_spimss_regs_t *spi, spimss_req_t *req);
  65. /* ************************************************************************** */
  66. int SPIMSS_Init(mxc_spimss_regs_t *spi, unsigned mode, unsigned freq, const sys_cfg_spimss_t* sys_cfg)
  67. {
  68. int spi_num, error;
  69. unsigned int spimss_clk;
  70. unsigned int pol, pha; // Polarity and phase of the clock (SPI mode)
  71. spi_num = MXC_SPIMSS_GET_IDX(spi);
  72. MXC_ASSERT(spi_num >= 0);
  73. if (mode > 3) {
  74. return E_BAD_PARAM;
  75. }
  76. if ((error = SYS_SPIMSS_Init(spi, sys_cfg)) != E_NO_ERROR) {
  77. return error;
  78. }
  79. states[spi_num].req = NULL;
  80. spi->ctrl &= ~(MXC_F_SPIMSS_CTRL_SPIEN); // Keep the SPI Disabled (This is the SPI Start)
  81. // Check if frequency is too high
  82. if (freq > PeripheralClock) {
  83. return E_BAD_PARAM;
  84. }
  85. // Set the bit rate
  86. spimss_clk = PeripheralClock;
  87. spi->brg = (spimss_clk / freq) >> 1;
  88. // Set the mode
  89. pol = mode >> 1; // Get the polarity out of the mode input value
  90. pha = mode & 1; // Get the phase out of the mode input value
  91. spi->ctrl = (spi->ctrl & ~(MXC_F_SPIMSS_CTRL_CLKPOL)) | (pol << MXC_F_SPIMSS_CTRL_CLKPOL_POS); // polarity
  92. spi->ctrl = (spi->ctrl & ~(MXC_F_SPIMSS_CTRL_PHASE)) | (pha << MXC_F_SPIMSS_CTRL_PHASE_POS); // phase
  93. spi->status &= ~(MXC_F_SPIMSS_STATUS_IRQ);
  94. return E_NO_ERROR;
  95. }
  96. /* ************************************************************************* */
  97. int SPIMSS_Shutdown(mxc_spimss_regs_t *spi)
  98. {
  99. int spi_num, err;
  100. spimss_req_t *temp_req;
  101. // Disable and turn off the SPI transaction.
  102. spi->ctrl = 0; // Interrupts, SPI transaction all turned off
  103. spi->status = 0;
  104. spi->mod = 0;
  105. // Reset FIFO counters
  106. spi->dma &= ~(MXC_F_SPIMSS_DMA_RX_FIFO_CNT|MXC_F_SPIMSS_DMA_TX_FIFO_CNT);
  107. // Call all of the pending callbacks for this SPI
  108. spi_num = MXC_SPIMSS_GET_IDX(spi);
  109. if (states[spi_num].req != NULL) {
  110. // Save the request
  111. temp_req = states[spi_num].req;
  112. // Unlock this SPI
  113. mxc_free_lock((uint32_t*)&states[spi_num].req);
  114. // Callback if not NULL
  115. if (temp_req->callback != NULL) {
  116. temp_req->callback(temp_req, E_SHUTDOWN);
  117. }
  118. }
  119. spi->status = 0;
  120. // Clear system level configurations
  121. if ((err = SYS_SPIMSS_Shutdown(spi)) != E_NO_ERROR) {
  122. return err;
  123. }
  124. return E_NO_ERROR;
  125. }
  126. /* ************************************************************************** */
  127. int SPIMSS_TransSetup(mxc_spimss_regs_t *spi, spimss_req_t *req, int master)
  128. {
  129. int spi_num;
  130. spi->ctrl &= ~(MXC_F_SPIMSS_CTRL_SPIEN); // Make sure the Initiation
  131. // of SPI Start is disabled.
  132. spi->mod |= MXC_F_SPIMSS_MOD_TX_LJ; // Making sure data is left
  133. // justified.
  134. if ((req->tx_data == NULL) && (req->rx_data == NULL)) {
  135. return -1;
  136. }
  137. spi_num = MXC_SPIMSS_GET_IDX(spi);
  138. MXC_ASSERT(spi_num >= 0);
  139. if (req->len == 0) {
  140. return 0;
  141. }
  142. req->tx_num = 0;
  143. req->rx_num = 0;
  144. if (mxc_get_lock((uint32_t*)&states[spi_num].req, (uint32_t)req) != E_NO_ERROR) {
  145. return E_BUSY;
  146. }
  147. if (master) { // Enable master mode
  148. spi->ctrl |= MXC_F_SPIMSS_CTRL_MMEN; // SPI configured as master.
  149. spi->mod |= MXC_F_SPIMSS_CTRL_MMEN; // SSEL pin is an output.
  150. } else { // Enable slave mode
  151. spi->ctrl &= ~(MXC_F_SPIMSS_CTRL_MMEN); // SPI configured as slave.
  152. spi->mod &= ~(MXC_F_SPIMSS_CTRL_MMEN); // SSEL pin is an input.
  153. }
  154. // Setup the character size
  155. if (req->bits <16) {
  156. MXC_SETFIELD(spi->mod, MXC_F_SPIMSS_MOD_NUMBITS , req->bits << MXC_F_SPIMSS_MOD_NUMBITS_POS);
  157. } else {
  158. MXC_SETFIELD(spi->mod, MXC_F_SPIMSS_MOD_NUMBITS , 0 << MXC_F_SPIMSS_MOD_NUMBITS_POS);
  159. }
  160. // Setup the slave select
  161. spi->mod |= MXC_F_SPIMSS_MOD_SSV; // Assert a high on Slave Select,
  162. // to get the line ready for active low later
  163. // Clear the TX and RX FIFO
  164. spi->dma |= (MXC_F_SPIMSS_DMA_TX_FIFO_CLEAR | MXC_F_SPIMSS_DMA_RX_FIFO_CLEAR);
  165. return E_NO_ERROR;
  166. }
  167. /* ************************************************************************** */
  168. void SPIMSS_Handler(mxc_spimss_regs_t *spi) // From the IRQ
  169. {
  170. int spi_num;
  171. uint32_t flags;
  172. unsigned int int_enable;
  173. flags = spi->status;
  174. spi->status = flags;
  175. spi->status|= 0x80; // clear interrupt
  176. spi_num = MXC_SPIMSS_GET_IDX(spi);
  177. int_enable = 0;
  178. if (states[spi_num].req != NULL) {
  179. if ((spi->ctrl & MXC_F_SPIMSS_CTRL_MMEN) >> MXC_F_SPIMSS_CTRL_MMEN_POS) {
  180. int_enable = SPIMSS_MasterTransHandler(spi, states[spi_num].req);
  181. } else {
  182. int_enable = SPIMSS_SlaveTransHandler(spi, states[spi_num].req);
  183. }
  184. }
  185. if (int_enable==1) {
  186. spi->ctrl |= (MXC_F_SPIMSS_CTRL_IRQE );
  187. }
  188. }
  189. /* ************************************************************************** */
  190. int SPIMSS_MasterTrans(mxc_spimss_regs_t *spi, spimss_req_t *req)
  191. {
  192. int error;
  193. if ((error = SPIMSS_TransSetup(spi, req, 1)) != E_NO_ERROR) {
  194. return error;
  195. }
  196. req->callback = NULL;
  197. spi->mod &= ~(MXC_F_SPIMSS_MOD_SSV); // This will assert the Slave Select.
  198. spi->ctrl |= MXC_F_SPIMSS_CTRL_SPIEN; // Enable/Start SPI
  199. while (SPIMSS_MasterTransHandler(spi,req)!=0) {
  200. }
  201. spi->mod |= MXC_F_SPIMSS_MOD_SSV;
  202. spi->ctrl &= ~(MXC_F_SPIMSS_CTRL_SPIEN); // Last of the SPIMSS value has been transmitted...
  203. // stop the transmission...
  204. return E_NO_ERROR;
  205. }
  206. /* ************************************************************************** */
  207. int SPIMSS_SlaveTrans(mxc_spimss_regs_t *spi, spimss_req_t *req)
  208. {
  209. int error;
  210. if ((error = SPIMSS_TransSetup(spi, req,0)) != E_NO_ERROR) {
  211. return error;
  212. }
  213. while (SPIMSS_SlaveTransHandler(spi,req)!=0) {
  214. spi->ctrl |= MXC_F_SPIMSS_CTRL_SPIEN; // Enable/Start SPI
  215. while ((spi->status & MXC_F_SPIMSS_STATUS_TXST) == MXC_F_SPIMSS_STATUS_TXST) {}
  216. }
  217. spi->ctrl &= ~(MXC_F_SPIMSS_CTRL_SPIEN); // Last of the SPIMSS value has been transmitted...
  218. // stop the transmission...
  219. return E_NO_ERROR;
  220. }
  221. /* ************************************************************************** */
  222. int SPIMSS_MasterTransAsync(mxc_spimss_regs_t *spi, spimss_req_t *req)
  223. {
  224. int error;
  225. uint8_t int_enable;
  226. if ((error = SPIMSS_TransSetup(spi, req, 1) )!= E_NO_ERROR) {
  227. return error;
  228. }
  229. int_enable = SPIMSS_MasterTransHandler(spi,req);
  230. spi->mod ^= MXC_F_SPIMSS_MOD_SSV; // This will assert the Slave Select.
  231. spi->ctrl |= MXC_F_SPIMSS_CTRL_SPIEN; // Enable/Start SPI
  232. if (int_enable==1) {
  233. spi->ctrl |= (MXC_F_SPIMSS_CTRL_IRQE | MXC_F_SPIMSS_CTRL_STR);
  234. }
  235. return E_NO_ERROR;
  236. }
  237. /* ************************************************************************** */
  238. int SPIMSS_SlaveTransAsync(mxc_spimss_regs_t *spi, spimss_req_t *req)
  239. {
  240. int error;
  241. uint8_t int_enable;
  242. if ((error = SPIMSS_TransSetup(spi, req, 0)) != E_NO_ERROR) {
  243. return error;
  244. }
  245. int_enable = SPIMSS_SlaveTransHandler(spi,req);
  246. spi->ctrl |= MXC_F_SPIMSS_CTRL_SPIEN; // Enable/Start SPI
  247. if (int_enable==1) { // Trigger a SPI Interrupt
  248. spi->ctrl |= (MXC_F_SPIMSS_CTRL_IRQE );
  249. }
  250. return E_NO_ERROR;
  251. }
  252. /* ************************************************************************** */
  253. uint32_t SPIMSS_MasterTransHandler(mxc_spimss_regs_t *spi, spimss_req_t *req)
  254. {
  255. unsigned start_set = 0;
  256. uint32_t retval;
  257. if (!start_set) {
  258. start_set = 1;
  259. retval = SPIMSS_TransHandler(spi,req);
  260. }
  261. return retval;
  262. }
  263. /* ************************************************************************** */
  264. uint32_t SPIMSS_SlaveTransHandler(mxc_spimss_regs_t *spi, spimss_req_t *req)
  265. {
  266. return SPIMSS_TransHandler(spi,req);
  267. }
  268. /* ************************************************************************** */
  269. uint32_t SPIMSS_TransHandler(mxc_spimss_regs_t *spi, spimss_req_t *req)
  270. {
  271. unsigned tx_avail, rx_avail;
  272. int remain, spi_num;
  273. uint32_t int_en =0;
  274. uint32_t length =req->len;
  275. spi_num = MXC_SPIMSS_GET_IDX(spi);
  276. // Read the RX FIFO
  277. if (req->rx_data != NULL) {
  278. // Wait for there to be data in the RX FIFO
  279. rx_avail = ((spi->dma & MXC_F_SPIMSS_DMA_RX_FIFO_CNT) >> MXC_F_SPIMSS_DMA_RX_FIFO_CNT_POS);
  280. if ((length - req->rx_num) < rx_avail) {
  281. rx_avail = (length - req->rx_num);
  282. }
  283. // Read from the FIFO
  284. while (rx_avail) {
  285. // Don't read less than 2 bytes if we are using greater than 8 bit characters
  286. if (req->bits>8) {
  287. ((uint16_t*)req->rx_data)[req->rx_num++] = spi->data16;
  288. rx_avail -= 1;
  289. } else {
  290. ((uint8_t*)req->rx_data)[req->rx_num++] = spi->data8[0];
  291. rx_avail -= 1;
  292. }
  293. rx_avail = ((spi->dma & MXC_F_SPIMSS_DMA_RX_FIFO_CNT) >> MXC_F_SPIMSS_DMA_RX_FIFO_CNT_POS);
  294. if ((length - req->rx_num) < rx_avail) {
  295. rx_avail = (length - req->rx_num);
  296. }
  297. }
  298. remain = length - req->rx_num;
  299. if (remain) {
  300. if (remain > MXC_SPIMSS_FIFO_DEPTH) {
  301. spi->dma = ((spi->dma & ~MXC_F_SPIMSS_DMA_RX_FIFO_CNT) | ((2) << MXC_F_SPIMSS_DMA_RX_FIFO_CNT_POS));
  302. } else {
  303. spi->dma = ((spi->dma & ~MXC_F_SPIMSS_DMA_RX_FIFO_CNT) | ((remain-1) << MXC_F_SPIMSS_DMA_RX_FIFO_CNT_POS));
  304. }
  305. int_en = 1;
  306. }
  307. // Break out if we've received all the bytes and we're not transmitting
  308. if ((req->tx_data == NULL) && (req->rx_num == length)) {
  309. spi->ctrl &= ~(MXC_F_SPIMSS_CTRL_IRQE | MXC_F_SPIMSS_CTRL_STR);
  310. int_en = 0;
  311. mxc_free_lock((uint32_t*)&states[spi_num].req);
  312. // Callback if not NULL
  313. if (req->callback != NULL) {
  314. req->callback(req, E_NO_ERROR);
  315. }
  316. }
  317. }
  318. // Note:- spi->dma shows the FIFO TX count and FIFO RX count in
  319. // Words, while the calculation below is in bytes.
  320. if (req->tx_data != NULL) {
  321. if (req->tx_num < length) {
  322. // Calculate how many bytes we can write to the FIFO (tx_avail holds that value)
  323. tx_avail = MXC_SPIMSS_FIFO_DEPTH - (((spi->dma & MXC_F_SPIMSS_DMA_TX_FIFO_CNT) >> MXC_F_SPIMSS_DMA_TX_FIFO_CNT_POS)); // in bytes
  324. if ((length - req->tx_num) < tx_avail) {
  325. tx_avail = (length - req->tx_num); // This is for the last spin
  326. }
  327. if (req->bits > 8) {
  328. tx_avail &= ~(unsigned)0x1;
  329. }
  330. // Write the FIFO
  331. while (tx_avail) {
  332. if (req->bits >8) {
  333. spi->data16 = ((uint16_t*)req->tx_data)[req->tx_num++];
  334. tx_avail -= 1;
  335. } else {
  336. spi->data8[0] = ((uint8_t*)req->tx_data)[req->tx_num++];
  337. tx_avail -=1;
  338. }
  339. }
  340. }
  341. remain = length - req->tx_num;
  342. // If there are values remaining to be transmitted, this portion will get
  343. // executed and int_en set, to indicate that this must spin and come back again...
  344. if (remain) {
  345. if (remain > MXC_SPIMSS_FIFO_DEPTH) { // more tx rounds will happen... Transfer the maximum,
  346. spi->dma = ((spi->dma & ~MXC_F_SPIMSS_DMA_TX_FIFO_CNT) | ((MXC_SPIMSS_FIFO_DEPTH) << MXC_F_SPIMSS_DMA_TX_FIFO_CNT_POS));
  347. } else { // only one more tx round will be done... Transfer whatever remains,
  348. spi->dma = ((spi->dma & ~MXC_F_SPIMSS_DMA_TX_FIFO_CNT) | ((remain) << MXC_F_SPIMSS_DMA_TX_FIFO_CNT_POS));
  349. }
  350. int_en = 1; // This will act as a trigger for the next round...
  351. }
  352. // Break out if we've transmitted all the bytes and not receiving
  353. if ((req->rx_data == NULL) && (req->tx_num == length)) {
  354. spi->ctrl &= ~(MXC_F_SPIMSS_CTRL_IRQE | MXC_F_SPIMSS_CTRL_STR);
  355. int_en = 0;
  356. mxc_free_lock((uint32_t*)&states[spi_num].req);
  357. // Callback if not NULL
  358. if (req->callback != NULL) {
  359. req->callback(req, E_NO_ERROR);
  360. }
  361. }
  362. }
  363. // Break out once we've transmitted and received all of the data
  364. if ((req->rx_num == length) && (req->tx_num == length)) {
  365. spi->ctrl &= ~(MXC_F_SPIMSS_CTRL_IRQE | MXC_F_SPIMSS_CTRL_STR);
  366. int_en = 0;
  367. mxc_free_lock((uint32_t*)&states[spi_num].req);
  368. // Callback if not NULL
  369. if (req->callback != NULL) {
  370. req->callback(req, E_NO_ERROR);
  371. }
  372. }
  373. return int_en;
  374. }
  375. /* ************************************************************************* */
  376. int SPIMSS_AbortAsync(spimss_req_t *req)
  377. {
  378. int spi_num;
  379. mxc_spimss_regs_t *spi;
  380. // Check the input parameters
  381. if (req == NULL) {
  382. return E_BAD_PARAM;
  383. }
  384. // Find the request, set to NULL
  385. for (spi_num = 0; spi_num < MXC_SPIMSS_INSTANCES; spi_num++) {
  386. if (req == states[spi_num].req) {
  387. spi = MXC_SPIMSS_GET_SPI(spi_num);
  388. // Disable interrupts, clear the flags
  389. spi->ctrl &= ~(MXC_F_SPIMSS_CTRL_IRQE | MXC_F_SPIMSS_CTRL_STR);
  390. // Disable and turn off the SPI transaction.
  391. spi->ctrl &= ~(MXC_F_SPIMSS_CTRL_SPIEN);
  392. // Unlock this SPI
  393. mxc_free_lock((uint32_t*)&states[spi_num].req);
  394. // Callback if not NULL
  395. if (req->callback != NULL) {
  396. req->callback(req, E_ABORT);
  397. }
  398. return E_NO_ERROR;
  399. }
  400. }
  401. return E_BAD_PARAM;
  402. }
  403. /**@} end of group spimss */