nu_spi.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /**************************************************************************//**
  2. * @file spi.c
  3. * @brief N9H30 SPI driver source file
  4. *
  5. * @note
  6. * SPDX-License-Identifier: Apache-2.0
  7. * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
  8. *****************************************************************************/
  9. /* Header files */
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include "N9H30.h"
  13. #include "nu_sys.h"
  14. #include "nu_spi.h"
  15. /** @addtogroup N9H30_Device_Driver N9H30 Device Driver
  16. @{
  17. */
  18. /** @addtogroup N9H30_SPI_Driver SPI Driver
  19. @{
  20. */
  21. /** @addtogroup N9H30_SPI_EXPORTED_CONSTANTS SPI Exported Constants
  22. @{
  23. */
  24. /// @cond HIDDEN_SYMBOLS
  25. #define spi_out(dev, byte, addr) outpw((dev)->base + addr, byte)
  26. #define spi_in(dev, addr) inpw((dev)->base + addr)
  27. typedef struct
  28. {
  29. uint32_t base; /* spi bus number */
  30. uint8_t openflag;
  31. uint8_t intflag;
  32. } spi_dev;
  33. /// @endcond HIDDEN_SYMBOLS
  34. /*@}*/ /* end of group N9H30_EMAC_EXPORTED_CONSTANTS */
  35. /** @addtogroup N9H30_SPI_EXPORTED_FUNCTIONS SPI Exported Functions
  36. @{
  37. */
  38. /// @cond HIDDEN_SYMBOLS
  39. static spi_dev spi_device[SPI_NUMBER];
  40. #if 0
  41. /**
  42. * @brief SPI-0 Interrupt handler
  43. * @param None
  44. * @return None
  45. */
  46. static void spi0ISR(void)
  47. {
  48. // clear interrupt flag
  49. outpw(REG_SPI0_CNTRL, spi_in((spi_dev *)((uint32_t)&spi_device[0]), CNTRL) | 0x1 << 16);
  50. spi_device[0].intflag = 1;
  51. }
  52. /**
  53. * @brief SPI-1 Interrupt handler
  54. * @param None
  55. * @return None
  56. */
  57. static void spi1ISR(void)
  58. {
  59. // clear interrupt flag
  60. outpw(REG_SPI1_CNTRL, spi_in((spi_dev *)((uint32_t)&spi_device[1]), CNTRL) | 0x1 << 16);
  61. spi_device[1].intflag = 1;
  62. }
  63. #endif
  64. /**
  65. * @brief Set SPI divider
  66. * @param[in] dev pointer to spi interface structure
  67. * @param[in] speed desire spi speed
  68. * @return speed set actually
  69. */
  70. static uint32_t spiSetSpeed(spi_dev *dev, uint32_t speed)
  71. {
  72. uint16_t div = (uint16_t)(SPI_INPUT_CLOCK / (2 * speed)) - 1;
  73. spi_out(dev, div, DIVIDER);
  74. return (SPI_INPUT_CLOCK / (2 * (div + 1)));
  75. }
  76. /// @endcond /* HIDDEN_SYMBOLS */
  77. /**
  78. * @brief Initialize spi interface and install interrupt callback function
  79. * @return always 0.
  80. * @retval 0 Success.
  81. */
  82. int32_t spiInit(int32_t fd)
  83. {
  84. #if 0
  85. if (fd == 0)
  86. {
  87. sysInstallISR(IRQ_LEVEL_1, SPI0_IRQn, (PVOID)spi0ISR);
  88. sysEnableInterrupt(SPI0_IRQn);
  89. memset((void *)&spi_device[0], 0, sizeof(spi_dev));
  90. }
  91. else
  92. {
  93. sysInstallISR(IRQ_LEVEL_1, SPI1_IRQn, (PVOID)spi1ISR);
  94. sysEnableInterrupt(SPI1_IRQn);
  95. memset((void *)&spi_device[1], 0, sizeof(spi_dev));
  96. }
  97. sysSetLocalInterrupt(ENABLE_IRQ);
  98. #endif
  99. return (0);
  100. }
  101. /**
  102. * @brief Support some spi driver commands for application.
  103. * @param[in] fd is interface number.
  104. * @param[in] cmd is command.
  105. * @param[in] arg0 is the first argument of command.
  106. * @param[in] arg1 is the second argument of command.
  107. * @return command status.
  108. * @retval 0 Success otherwise fail. Fail value could be
  109. * - \ref SPI_ERR_NODEV
  110. * - \ref SPI_ERR_IO
  111. * - \ref SPI_ERR_ARG
  112. */
  113. int32_t spiIoctl(int32_t fd, uint32_t cmd, uint32_t arg0, uint32_t arg1)
  114. {
  115. spi_dev *dev;
  116. if (fd != 0 && fd != 1)
  117. return (SPI_ERR_NODEV);
  118. dev = (spi_dev *)((uint32_t)&spi_device[fd]);
  119. if (dev->openflag == 0)
  120. return (SPI_ERR_IO);
  121. switch (cmd)
  122. {
  123. case SPI_IOC_TRIGGER:
  124. dev->intflag = 0;
  125. spi_out(dev, spi_in(dev, CNTRL) | 0x1, CNTRL);
  126. break;
  127. #if 0
  128. case SPI_IOC_SET_INTERRUPT:
  129. if (arg0 == SPI_ENABLE_INTERRUPT)
  130. spi_out(dev, spi_in(dev, CNTRL) | (0x1 << 17), CNTRL);
  131. else
  132. spi_out(dev, spi_in(dev, CNTRL) & ~(0x1 << 17), CNTRL);
  133. break;
  134. #endif
  135. case SPI_IOC_SET_SPEED:
  136. return spiSetSpeed(dev, (uint32_t)arg0);
  137. case SPI_IOC_SET_DUAL_QUAD_MODE:
  138. if (arg0 == SPI_DISABLE_DUAL_QUAD)
  139. {
  140. spi_out(dev, (spi_in(dev, CNTRL) & ~(0x3 << 21)), CNTRL);
  141. break;
  142. }
  143. if (arg0 == SPI_DUAL_MODE)
  144. spi_out(dev, (spi_in(dev, CNTRL) & ~(0x3 << 21)) | (0x1 << 22), CNTRL);
  145. else
  146. spi_out(dev, (spi_in(dev, CNTRL) & ~(0x3 << 21)) | (0x1 << 21), CNTRL);
  147. break;
  148. case SPI_IOC_SET_DUAL_QUAD_DIR:
  149. if (arg0 == SPI_DUAL_QUAD_INPUT)
  150. spi_out(dev, spi_in(dev, CNTRL) & ~(0x1 << 20), CNTRL);
  151. else
  152. spi_out(dev, spi_in(dev, CNTRL) | (0x1 << 20), CNTRL);
  153. break;
  154. case SPI_IOC_SET_LSB_MSB:
  155. if (arg0 == SPI_MSB)
  156. spi_out(dev, spi_in(dev, CNTRL) & ~(0x1 << 10), CNTRL);
  157. else
  158. spi_out(dev, spi_in(dev, CNTRL) | (0x1 << 10), CNTRL);
  159. break;
  160. case SPI_IOC_SET_TX_NUM:
  161. if (arg0 < 4)
  162. spi_out(dev, (spi_in(dev, CNTRL) & ~(0x3 << 8)) | (arg0 << 8), CNTRL);
  163. else
  164. return SPI_ERR_ARG;
  165. break;
  166. case SPI_IOC_SET_TX_BITLEN:
  167. if (arg0 < 32)
  168. spi_out(dev, (spi_in(dev, CNTRL) & ~(0x1f << 3)) | (arg0 << 3), CNTRL);
  169. else
  170. return SPI_ERR_ARG;
  171. break;
  172. case SPI_IOC_SET_MODE:
  173. if (arg0 > SPI_MODE_3)
  174. return SPI_ERR_ARG;
  175. if (arg0 == SPI_MODE_0)
  176. spi_out(dev, (spi_in(dev, CNTRL) & ~((0x3 << 1) | (1UL << 31))) | (1 << 2), CNTRL);
  177. else if (arg0 == SPI_MODE_1)
  178. spi_out(dev, (spi_in(dev, CNTRL) & ~((0x3 << 1) | (1UL << 31))) | (1 << 1), CNTRL);
  179. else if (arg0 == SPI_MODE_2)
  180. spi_out(dev, (spi_in(dev, CNTRL) & ~((0x3 << 1) | (1UL << 31))) | ((1UL << 31) | (1 << 2)), CNTRL);
  181. else
  182. spi_out(dev, (spi_in(dev, CNTRL) & ~((0x3 << 1) | (1UL << 31))) | ((1UL << 31) | (1 << 1)), CNTRL);
  183. break;
  184. case SPI_IOC_ENABLE_SS:
  185. if (arg0 == SPI_SS_SS0)
  186. spi_out(dev, (spi_in(dev, SSR) & ~(0x3)) | 0x1, SSR);
  187. else if (arg0 == SPI_SS_SS1)
  188. spi_out(dev, (spi_in(dev, SSR) & ~(0x3)) | 0x2, SSR);
  189. else if (arg0 == SPI_SS_BOTH)
  190. spi_out(dev, (spi_in(dev, SSR) & ~(0x3)) | 0x3, SSR);
  191. else
  192. return SPI_ERR_ARG;
  193. break;
  194. case SPI_IOC_DISABLE_SS:
  195. if (arg0 == SPI_SS_SS0)
  196. spi_out(dev, (spi_in(dev, SSR) & ~(0x1)), SSR);
  197. else if (arg0 == SPI_SS_SS1)
  198. spi_out(dev, (spi_in(dev, SSR) & ~(0x2)), SSR);
  199. else if (arg0 == SPI_SS_BOTH)
  200. spi_out(dev, (spi_in(dev, SSR) & ~(0x3)), SSR);
  201. else
  202. return SPI_ERR_ARG;
  203. break;
  204. case SPI_IOC_SET_AUTOSS:
  205. if (arg0 == SPI_DISABLE_AUTOSS)
  206. spi_out(dev, spi_in(dev, SSR) & ~(0x1 << 3), SSR);
  207. else
  208. spi_out(dev, spi_in(dev, SSR) | (0x1 << 3), SSR);
  209. break;
  210. case SPI_IOC_SET_SS_ACTIVE_LEVEL:
  211. if (arg0 == SPI_SS_ACTIVE_LOW)
  212. spi_out(dev, spi_in(dev, SSR) & ~(0x1 << 2), SSR);
  213. else
  214. spi_out(dev, spi_in(dev, SSR) | (0x1 << 2), SSR);
  215. default:
  216. break;
  217. }
  218. return 0;
  219. }
  220. /**
  221. * @brief Open spi interface and initialize some variables
  222. * @param[in] fd is interface number.
  223. * @return always 0
  224. * @retval 0 success.
  225. */
  226. int spiOpen(int32_t fd)
  227. {
  228. spi_dev *dev;
  229. if ((uint32_t)fd >= SPI_NUMBER)
  230. return SPI_ERR_NODEV;
  231. dev = (spi_dev *)((uint32_t)&spi_device[fd]);
  232. if (dev->openflag != 0) /* a card slot can open only once */
  233. return (SPI_ERR_BUSY);
  234. memset(dev, 0, sizeof(spi_dev));
  235. dev->base = ((uint32_t)fd) ? SPI1_BA : SPI0_BA;
  236. dev->openflag = 1;
  237. dev->intflag = 0;
  238. return 0;
  239. }
  240. /**
  241. * @brief Get busy status of spi interface
  242. * @param[in] fd is interface number.
  243. * @return busy or not
  244. * @retval 0 not busy.
  245. * @retval 1 busy.
  246. */
  247. uint8_t spiGetBusyStatus(int32_t fd)
  248. {
  249. spi_dev *dev;
  250. dev = (spi_dev *)((uint32_t)&spi_device[fd]);
  251. if (spi_in(dev, CNTRL) & (0x1 << 17))
  252. return (!dev->intflag);
  253. else
  254. return ((spi_in(dev, CNTRL) & 0x1) == 0x1 ? 1 : 0);
  255. }
  256. /**
  257. * @brief Read data form spi interface
  258. * @param[in] fd is interface number.
  259. * @param[in] buff_id is buffer number. If transfer number is 4, application needs read 4 times (buff_id is from 0 to 3) from buffer.
  260. * @return data
  261. */
  262. uint32_t spiRead(int32_t fd, uint8_t buff_id)
  263. {
  264. spi_dev *dev;
  265. dev = (spi_dev *)((uint32_t)&spi_device[fd]);
  266. return spi_in(dev, (RX0 + 4 * buff_id));
  267. }
  268. /**
  269. * @brief Write data to spi interface
  270. * @param[in] fd is interface number.
  271. * @param[in] buff_id is buffer number. If transfer number is 4, application needs write 4 times (buff_id is from 0 to 3) to buffer.
  272. * @param[in] data is data to be written.
  273. * @return none
  274. */
  275. void spiWrite(int32_t fd, uint8_t buff_id, uint32_t data)
  276. {
  277. spi_dev *dev;
  278. dev = (spi_dev *)((uint32_t)&spi_device[fd]);
  279. spi_out(dev, data, (TX0 + 4 * buff_id));
  280. }
  281. /*@}*/ /* end of group N9H30_SPI_EXPORTED_FUNCTIONS */
  282. /*@}*/ /* end of group N9H30_SPI_Driver */
  283. /*@}*/ /* end of group N9H30_Device_Driver */
  284. /*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/