drv_spi.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /*
  2. * Copyright (c) 2006-2024, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024-03-28 qiujingbao first version
  9. * 2024/06/08 flyingcys fix transmission failure
  10. */
  11. #include <rtthread.h>
  12. #include <rthw.h>
  13. #include <rtdevice.h>
  14. #include "board.h"
  15. #include "drv_spi.h"
  16. #include "drv_pinmux.h"
  17. #include "drv_ioremap.h"
  18. #define DBG_LEVEL DBG_LOG
  19. #include <rtdbg.h>
  20. #define LOG_TAG "drv.spi"
  21. struct _device_spi
  22. {
  23. struct rt_spi_bus spi_bus;
  24. struct dw_spi dws;
  25. char *device_name;
  26. };
  27. static struct _device_spi _spi_obj[] =
  28. {
  29. #ifdef BSP_USING_SPI0
  30. {
  31. .dws.regs = (void *)DW_SPI0_BASE,
  32. .dws.irq = DW_SPI0_IRQn,
  33. .dws.index = 0,
  34. .device_name = "spi0",
  35. },
  36. #endif /* BSP_USING_SPI0 */
  37. #ifdef BSP_USING_SPI1
  38. {
  39. .dws.regs = (void *)DW_SPI1_BASE,
  40. .dws.irq = DW_SPI1_IRQn,
  41. .dws.index = 0,
  42. .device_name = "spi1",
  43. },
  44. #endif /* BSP_USING_SPI1 */
  45. #ifdef BSP_USING_SPI2
  46. {
  47. .dws.regs = (void *)DW_SPI2_BASE,
  48. .dws.irq = DW_SPI2_IRQn,
  49. .dws.index = 0,
  50. .device_name = "spi2",
  51. },
  52. #endif /* BSP_USING_SPI2 */
  53. #ifdef BSP_USING_SPI3
  54. {
  55. .dws.regs = (void *)DW_SPI3_BASE,
  56. .dws.irq = DW_SPI3_IRQn,
  57. .dws.index = 0,
  58. .device_name = "spi3",
  59. },
  60. #endif /* BSP_USING_SPI3 */
  61. };
  62. static rt_err_t spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *cfg)
  63. {
  64. RT_ASSERT(device != RT_NULL);
  65. RT_ASSERT(device->bus != RT_NULL);
  66. RT_ASSERT(device->bus->parent.user_data != RT_NULL);
  67. RT_ASSERT(cfg != RT_NULL);
  68. struct _device_spi *spi = (struct _device_spi *)device->bus->parent.user_data;
  69. struct dw_spi *dws = &spi->dws;
  70. rt_uint8_t mode;
  71. LOG_D("spi_configure input");
  72. /* set cs low when spi idle */
  73. writel(0, (void *)0x030001d0);
  74. if (cfg->mode & RT_SPI_SLAVE)
  75. {
  76. LOG_E("invalid mode: %d", cfg->mode);
  77. return -RT_EINVAL;
  78. }
  79. spi_reset_chip(dws);
  80. spi_hw_init(dws);
  81. spi_enable_chip(dws, 0);
  82. LOG_D("cfg->max_hz: %d", cfg->max_hz);
  83. dw_spi_set_clock(dws, SPI_REF_CLK, cfg->max_hz);
  84. LOG_D("cfg->data_width: %d", cfg->data_width);
  85. if (dw_spi_set_data_frame_len(dws, (uint32_t)cfg->data_width) < 0)
  86. {
  87. LOG_E("dw_spi_set_data_frame_len failed...\n");
  88. return -RT_ERROR;
  89. }
  90. LOG_D("cfg->mode: %08x", cfg->mode);
  91. switch (cfg->mode & RT_SPI_MODE_3)
  92. {
  93. case RT_SPI_MODE_0:
  94. mode = SPI_FORMAT_CPOL0_CPHA0;
  95. break;
  96. case RT_SPI_MODE_1:
  97. mode = SPI_FORMAT_CPOL0_CPHA1;
  98. break;
  99. case RT_SPI_MODE_2:
  100. mode = SPI_FORMAT_CPOL1_CPHA0;
  101. break;
  102. case RT_SPI_MODE_3:
  103. mode = SPI_FORMAT_CPOL1_CPHA1;
  104. break;
  105. default:
  106. LOG_E("spi configure mode error %x\n", cfg->mode);
  107. break;
  108. }
  109. dw_spi_set_polarity_and_phase(dws, mode);
  110. dw_spi_set_cs(dws, 1, 0);
  111. spi_enable_chip(dws, 1);
  112. return RT_EOK;
  113. }
  114. static rt_err_t dw_spi_transfer_one(struct dw_spi *dws, const void *tx_buf, void *rx_buf, uint32_t len, enum transfer_type tran_type)
  115. {
  116. dws->tx = NULL;
  117. dws->tx_end = NULL;
  118. dws->rx = NULL;
  119. dws->rx_end = NULL;
  120. if (tx_buf != NULL) {
  121. dws->tx = tx_buf;
  122. dws->tx_end = dws->tx + len;
  123. }
  124. if (rx_buf != NULL) {
  125. dws->rx = rx_buf;
  126. dws->rx_end = dws->rx + len;
  127. }
  128. dws->rx_len = len / dws->n_bytes;
  129. dws->tx_len = len / dws->n_bytes;
  130. spi_enable_chip(dws, 0);
  131. /* For poll mode just disable all interrupts */
  132. spi_mask_intr(dws, 0xff);
  133. /* set tran mode */
  134. set_tran_mode(dws);
  135. /* cs0 */
  136. dw_spi_set_cs(dws, true, 0);
  137. /* enable spi */
  138. spi_enable_chip(dws, 1);
  139. rt_hw_us_delay(10);
  140. if (tran_type == POLL_TRAN)
  141. {
  142. if (poll_transfer(dws) < 0)
  143. return -RT_ERROR;
  144. }
  145. else
  146. {
  147. return -RT_ENOSYS;
  148. }
  149. return RT_EOK;
  150. }
  151. static rt_ssize_t spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
  152. {
  153. RT_ASSERT(device != RT_NULL);
  154. RT_ASSERT(device->bus != RT_NULL);
  155. RT_ASSERT(device->bus->parent.user_data != RT_NULL);
  156. RT_ASSERT(message != RT_NULL);
  157. struct _device_spi *spi = (struct _device_spi *)device->bus->parent.user_data;
  158. struct dw_spi *dws = &spi->dws;
  159. int32_t ret = RT_EOK;
  160. if (message->send_buf && message->recv_buf)
  161. {
  162. ret = dw_spi_transfer_one(dws, message->send_buf, message->recv_buf, message->length, POLL_TRAN);
  163. }
  164. else if (message->send_buf)
  165. {
  166. ret = dw_spi_transfer_one(dws, message->send_buf, RT_NULL, message->length, POLL_TRAN);
  167. }
  168. else if (message->recv_buf)
  169. {
  170. ret = dw_spi_transfer_one(dws, RT_NULL, message->recv_buf, message->length, POLL_TRAN);
  171. } else {
  172. return 0;
  173. }
  174. if (ret != RT_EOK)
  175. {
  176. LOG_E("spi transfer error : %d", ret);
  177. return 0;
  178. }
  179. return message->length;
  180. }
  181. static const struct rt_spi_ops _spi_ops =
  182. {
  183. .configure = spi_configure,
  184. .xfer = spi_xfer,
  185. };
  186. #if defined(BOARD_TYPE_MILKV_DUO) || defined(BOARD_TYPE_MILKV_DUO256M)
  187. // For Duo / Duo 256m, only SPI2 are exported on board.
  188. #ifdef BSP_USING_SPI0
  189. static const char *pinname_whitelist_spi0_sck[] = {
  190. NULL,
  191. };
  192. static const char *pinname_whitelist_spi0_sdo[] = {
  193. NULL,
  194. };
  195. static const char *pinname_whitelist_spi0_sdi[] = {
  196. NULL,
  197. };
  198. static const char *pinname_whitelist_spi0_cs[] = {
  199. NULL,
  200. };
  201. #endif
  202. #ifdef BSP_USING_SPI1
  203. static const char *pinname_whitelist_spi1_sck[] = {
  204. NULL,
  205. };
  206. static const char *pinname_whitelist_spi1_sdo[] = {
  207. NULL,
  208. };
  209. static const char *pinname_whitelist_spi1_sdi[] = {
  210. NULL,
  211. };
  212. static const char *pinname_whitelist_spi1_cs[] = {
  213. NULL,
  214. };
  215. #endif
  216. #ifdef BSP_USING_SPI2
  217. static const char *pinname_whitelist_spi2_sck[] = {
  218. "SD1_CLK",
  219. NULL,
  220. };
  221. static const char *pinname_whitelist_spi2_sdo[] = {
  222. "SD1_CMD",
  223. NULL,
  224. };
  225. static const char *pinname_whitelist_spi2_sdi[] = {
  226. "SD1_D0",
  227. NULL,
  228. };
  229. static const char *pinname_whitelist_spi2_cs[] = {
  230. "SD1_D3",
  231. NULL,
  232. };
  233. #endif
  234. #ifdef BSP_USING_SPI3
  235. static const char *pinname_whitelist_spi3_sck[] = {
  236. NULL,
  237. };
  238. static const char *pinname_whitelist_spi3_sdo[] = {
  239. NULL,
  240. };
  241. static const char *pinname_whitelist_spi3_sdi[] = {
  242. NULL,
  243. };
  244. static const char *pinname_whitelist_spi3_cs[] = {
  245. NULL,
  246. };
  247. #endif
  248. #else
  249. #error "Unsupported board type!"
  250. #endif
  251. static void rt_hw_spi_pinmux_config()
  252. {
  253. #ifdef BSP_USING_SPI0
  254. pinmux_config(BSP_SPI0_SCK_PINNAME, SPI0_SCK, pinname_whitelist_spi0_sck);
  255. pinmux_config(BSP_SPI0_SDO_PINNAME, SPI0_SDO, pinname_whitelist_spi0_sdo);
  256. pinmux_config(BSP_SPI0_SDI_PINNAME, SPI0_SDI, pinname_whitelist_spi0_sdi);
  257. pinmux_config(BSP_SPI0_CS_PINNAME, SPI0_CS_X, pinname_whitelist_spi0_cs);
  258. #endif /* BSP_USING_SPI0 */
  259. #ifdef BSP_USING_SPI1
  260. pinmux_config(BSP_SPI1_SCK_PINNAME, SPI1_SCK, pinname_whitelist_spi1_sck);
  261. pinmux_config(BSP_SPI1_SDO_PINNAME, SPI1_SDO, pinname_whitelist_spi1_sdo);
  262. pinmux_config(BSP_SPI1_SDI_PINNAME, SPI1_SDI, pinname_whitelist_spi1_sdi);
  263. pinmux_config(BSP_SPI1_CS_PINNAME, SPI1_CS_X, pinname_whitelist_spi1_cs);
  264. #endif /* BSP_USING_SPI1 */
  265. #ifdef BSP_USING_SPI2
  266. pinmux_config(BSP_SPI2_SCK_PINNAME, SPI2_SCK, pinname_whitelist_spi2_sck);
  267. pinmux_config(BSP_SPI2_SDO_PINNAME, SPI2_SDO, pinname_whitelist_spi2_sdo);
  268. pinmux_config(BSP_SPI2_SDI_PINNAME, SPI2_SDI, pinname_whitelist_spi2_sdi);
  269. pinmux_config(BSP_SPI2_CS_PINNAME, SPI2_CS_X, pinname_whitelist_spi2_cs);
  270. #endif /* BSP_USING_SPI2 */
  271. #ifdef BSP_USING_SPI3
  272. pinmux_config(BSP_SPI3_SCK_PINNAME, SPI3_SCK, pinname_whitelist_spi3_sck);
  273. pinmux_config(BSP_SPI3_SDO_PINNAME, SPI3_SDO, pinname_whitelist_spi3_sdo);
  274. pinmux_config(BSP_SPI3_SDI_PINNAME, SPI3_SDI, pinname_whitelist_spi3_sdi);
  275. pinmux_config(BSP_SPI3_CS_PINNAME, SPI3_CS_X, pinname_whitelist_spi3_cs);
  276. #endif /* BSP_USING_SPI3 */
  277. }
  278. int rt_hw_spi_init(void)
  279. {
  280. rt_err_t ret = RT_EOK;
  281. rt_hw_spi_pinmux_config();
  282. for (rt_size_t i = 0; i < sizeof(_spi_obj) / sizeof(struct _device_spi); i++)
  283. {
  284. _spi_obj[i].dws.regs = (void *)DRV_IOREMAP((void *)_spi_obj[i].dws.regs, 0x1000);
  285. _spi_obj[i].spi_bus.parent.user_data = (void *)&_spi_obj[i];
  286. ret = rt_spi_bus_register(&_spi_obj[i].spi_bus, _spi_obj[i].device_name, &_spi_ops);
  287. }
  288. RT_ASSERT(ret == RT_EOK);
  289. return ret;
  290. }
  291. INIT_DEVICE_EXPORT(rt_hw_spi_init);