drv_spi.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * Copyright (c) 2006-2023, 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. */
  10. #include "drv_spi.h"
  11. #ifdef RT_USING_SPI
  12. #define DBG_TAG "drv.spi"
  13. #define DBG_LVL DBG_INFO
  14. #include <rtdbg.h>
  15. static struct cv1800_spi cv1800_spi_obj[] =
  16. {
  17. #ifdef BSP_USING_SPI
  18. {
  19. .spi_id = SPI2,
  20. .device_name = "spi2",
  21. .fifo_len = SPI_TXFTLR,
  22. },
  23. #endif
  24. };
  25. static struct spi_regs *get_spi_base(uint8_t spi_id)
  26. {
  27. struct spi_regs *spi_base = NULL;
  28. switch (spi_id)
  29. {
  30. case SPI0:
  31. spi_base = (struct spi_regs *)SPI0_BASE;
  32. break;
  33. case SPI1:
  34. spi_base = (struct spi_regs *)SPI1_BASE;
  35. break;
  36. case SPI2:
  37. spi_base = (struct spi_regs *)SPI2_BASE;
  38. break;
  39. case SPI3:
  40. spi_base = (struct spi_regs *)SPI3_BASE;
  41. break;
  42. }
  43. return spi_base;
  44. }
  45. static rt_err_t drv_spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration)
  46. {
  47. rt_err_t ret = RT_EOK;
  48. struct cv1800_spi *spi_dev = RT_NULL;
  49. uint32_t mode;
  50. spi_dev = (struct cv1800_spi *)(device->bus->parent.user_data);
  51. spi_dev->data_width = configuration->data_width;
  52. /* disable spi */
  53. spi_enable(spi_dev->reg, 0);
  54. /* clear irq */
  55. spi_clear_irq(spi_dev->reg, SPI_IRQ_MSAK);
  56. /* set clk */
  57. ret = spi_set_frequency(spi_dev->reg, configuration->max_hz);
  58. if (ret)
  59. return ret;
  60. /* set mode */
  61. ret = gen_spi_mode(configuration, &mode);
  62. if (ret)
  63. return ret;
  64. spi_set_mode(spi_dev->reg, mode);
  65. /* set cs */
  66. spi_enable_cs(spi_dev->reg, 0x1);
  67. spi_enable(spi_dev->reg, 0x1);
  68. mode = mmio_read_32((uintptr_t)&spi_dev->reg->spi_ctrl0);
  69. LOG_D("mode: %x", mode);
  70. mode = mmio_read_32((uintptr_t)&spi_dev->reg->spi_baudr);
  71. LOG_D("spi_baudr: %x", mode);
  72. return ret;
  73. }
  74. int hw_spi_recv(struct cv1800_spi *dev) {
  75. uint32_t rever;
  76. uint32_t tem;
  77. int ret;
  78. rever = mmio_read_32((uintptr_t)&dev->reg->spi_rxflr);
  79. ret = (int)rever;
  80. while (rever)
  81. {
  82. tem = mmio_read_32((uintptr_t)&dev->reg->spi_dr);
  83. if (dev->recv_buf < dev->recv_end)
  84. {
  85. if (dev->data_width == 8)
  86. *(uint8_t *)(dev->recv_buf) = tem;
  87. else
  88. *(uint16_t *)(dev->recv_buf) = tem;
  89. }
  90. else
  91. {
  92. return 0;
  93. }
  94. rever--;
  95. dev->recv_buf += dev->data_width >> 3;
  96. }
  97. return ret;
  98. }
  99. int hw_spi_send(struct cv1800_spi *dev) {
  100. uint32_t txflr;
  101. uint32_t max;
  102. uint16_t value;
  103. txflr = mmio_read_32((uintptr_t)&dev->reg->spi_txflr);
  104. max = dev->fifo_len - txflr;
  105. while (max)
  106. {
  107. if (dev->send_end - dev->send_buf)
  108. {
  109. if (dev->data_width == 8)
  110. value = *(uint8_t *)(dev->send_buf);
  111. else
  112. value = *(uint16_t *)(dev->send_buf);
  113. }
  114. else
  115. {
  116. return 0;
  117. }
  118. mmio_write_32((uintptr_t)&dev->reg->spi_dr, value);
  119. dev->send_buf += dev->data_width >> 3;
  120. max--;
  121. }
  122. return 0;
  123. }
  124. static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message) {
  125. int ret = 0;
  126. struct cv1800_spi *spi_dev;
  127. RT_ASSERT(device != RT_NULL);
  128. RT_ASSERT(device->bus != RT_NULL);
  129. RT_ASSERT(message != RT_NULL);
  130. spi_dev = (struct cv1800_spi *)(device->bus->parent.user_data);
  131. if (message->send_buf != RT_NULL)
  132. {
  133. spi_dev->send_buf = message->send_buf;
  134. spi_dev->send_end = (void *)((uint8_t *)spi_dev->send_buf + message->length);
  135. }
  136. if (message->recv_buf != RT_NULL)
  137. {
  138. spi_dev->recv_buf = message->recv_buf;
  139. spi_dev->recv_end = (void *)((uint8_t *)spi_dev->recv_buf + message->length);
  140. }
  141. /* if user use their cs */
  142. if (message->cs_take && device->cs_pin != PIN_NONE)
  143. rt_pin_write(device->cs_pin, PIN_LOW);
  144. if (message->send_buf)
  145. {
  146. while (spi_dev->send_buf != spi_dev->send_end)
  147. {
  148. hw_spi_send(spi_dev);
  149. }
  150. /* wait for complete */
  151. while (mmio_read_32((uintptr_t)&spi_dev->reg->spi_txflr)) {}
  152. ret = message->length;
  153. }
  154. if (message->recv_buf)
  155. {
  156. while (spi_dev->recv_buf != spi_dev->recv_end)
  157. {
  158. hw_spi_recv(spi_dev);
  159. }
  160. ret = message->length;
  161. }
  162. if (message->cs_release && device->cs_pin != PIN_NONE)
  163. rt_pin_write(device->cs_pin, PIN_HIGH);
  164. return ret;
  165. }
  166. const static struct rt_spi_ops drv_spi_ops =
  167. {
  168. drv_spi_configure,
  169. spixfer,
  170. };
  171. int rt_hw_spi_init(void)
  172. {
  173. rt_err_t ret = RT_EOK;
  174. struct spi_regs *reg = NULL;
  175. for (rt_size_t i = 0; i < sizeof(cv1800_spi_obj) / sizeof(struct cv1800_spi); i++) {
  176. /* set reg base addr */
  177. reg = get_spi_base(cv1800_spi_obj[i].spi_id);
  178. if (!reg)
  179. return -RT_ERROR;
  180. cv1800_spi_obj[i].reg = reg;
  181. cv1800_spi_obj[i].spi_bus.parent.user_data = &cv1800_spi_obj[i];
  182. /* register spix bus */
  183. ret = rt_spi_bus_register(&cv1800_spi_obj[i].spi_bus, cv1800_spi_obj[i].device_name, &drv_spi_ops);
  184. }
  185. return ret;
  186. }
  187. INIT_BOARD_EXPORT(rt_hw_spi_init);
  188. #endif /* RT_USING_SPI */