qspi_core.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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. * 2018-11-16 zylx first version.
  9. */
  10. #include <drivers/spi.h>
  11. rt_err_t rt_qspi_configure(struct rt_qspi_device *device, struct rt_qspi_configuration *cfg)
  12. {
  13. RT_ASSERT(device != RT_NULL);
  14. RT_ASSERT(cfg != RT_NULL);
  15. /* reset the CS pin */
  16. if (device->parent.cs_pin != PIN_NONE)
  17. {
  18. if (cfg->parent.mode & RT_SPI_CS_HIGH)
  19. rt_pin_write(device->parent.cs_pin, PIN_LOW);
  20. else
  21. rt_pin_write(device->parent.cs_pin, PIN_HIGH);
  22. }
  23. /* If the configurations are the same, we don't need to set again. */
  24. if (device->config.medium_size == cfg->medium_size &&
  25. device->config.ddr_mode == cfg->ddr_mode &&
  26. device->config.qspi_dl_width == cfg->qspi_dl_width &&
  27. device->config.parent.data_width == cfg->parent.data_width &&
  28. device->config.parent.mode == (cfg->parent.mode & RT_SPI_MODE_MASK) &&
  29. device->config.parent.max_hz == cfg->parent.max_hz)
  30. {
  31. return RT_EOK;
  32. }
  33. /* copy configuration items */
  34. device->config.parent.mode = cfg->parent.mode;
  35. device->config.parent.max_hz = cfg->parent.max_hz;
  36. device->config.parent.data_width = cfg->parent.data_width;
  37. device->config.parent.reserved = cfg->parent.reserved;
  38. device->config.medium_size = cfg->medium_size;
  39. device->config.ddr_mode = cfg->ddr_mode;
  40. device->config.qspi_dl_width = cfg->qspi_dl_width;
  41. return rt_spi_bus_configure(&device->parent);
  42. }
  43. rt_err_t rt_qspi_bus_register(struct rt_spi_bus *bus, const char *name, const struct rt_spi_ops *ops)
  44. {
  45. rt_err_t result = RT_EOK;
  46. result = rt_spi_bus_register(bus, name, ops);
  47. if(result == RT_EOK)
  48. {
  49. /* set SPI bus to qspi modes */
  50. bus->mode = RT_SPI_BUS_MODE_QSPI;
  51. }
  52. return result;
  53. }
  54. rt_size_t rt_qspi_transfer_message(struct rt_qspi_device *device, struct rt_qspi_message *message)
  55. {
  56. rt_err_t result;
  57. RT_ASSERT(device != RT_NULL);
  58. RT_ASSERT(message != RT_NULL);
  59. result = rt_mutex_take(&(device->parent.bus->lock), RT_WAITING_FOREVER);
  60. if (result != RT_EOK)
  61. {
  62. rt_set_errno(-RT_EBUSY);
  63. return 0;
  64. }
  65. /* reset errno */
  66. rt_set_errno(RT_EOK);
  67. /* configure SPI bus */
  68. if (device->parent.bus->owner != &device->parent)
  69. {
  70. /* not the same owner as current, re-configure SPI bus */
  71. result = device->parent.bus->ops->configure(&device->parent, &device->parent.config);
  72. if (result == RT_EOK)
  73. {
  74. /* set SPI bus owner */
  75. device->parent.bus->owner = &device->parent;
  76. }
  77. else
  78. {
  79. /* configure SPI bus failed */
  80. rt_set_errno(-RT_EIO);
  81. goto __exit;
  82. }
  83. }
  84. /* transmit each SPI message */
  85. result = device->parent.bus->ops->xfer(&device->parent, &message->parent);
  86. if (result == 0)
  87. {
  88. rt_set_errno(-RT_EIO);
  89. }
  90. __exit:
  91. /* release bus lock */
  92. rt_mutex_release(&(device->parent.bus->lock));
  93. return result;
  94. }
  95. rt_err_t rt_qspi_send_then_recv(struct rt_qspi_device *device, const void *send_buf, rt_size_t send_length, void *recv_buf, rt_size_t recv_length)
  96. {
  97. RT_ASSERT(send_buf);
  98. RT_ASSERT(recv_buf);
  99. RT_ASSERT(send_length != 0);
  100. struct rt_qspi_message message;
  101. unsigned char *ptr = (unsigned char *)send_buf;
  102. rt_size_t count = 0;
  103. rt_err_t result = 0;
  104. message.instruction.content = ptr[0];
  105. message.instruction.qspi_lines = 1;
  106. count++;
  107. /* get address */
  108. if (send_length > 1)
  109. {
  110. if (device->config.medium_size > 0x1000000 && send_length >= 5)
  111. {
  112. /* medium size greater than 16Mb, address size is 4 Byte */
  113. message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]);
  114. message.address.size = 32;
  115. count += 4;
  116. }
  117. else if (send_length >= 4)
  118. {
  119. /* address size is 3 Byte */
  120. message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
  121. message.address.size = 24;
  122. count += 3;
  123. }
  124. else
  125. {
  126. return -RT_ERROR;
  127. }
  128. message.address.qspi_lines = 1;
  129. }
  130. else
  131. {
  132. /* no address stage */
  133. message.address.content = 0 ;
  134. message.address.qspi_lines = 0;
  135. message.address.size = 0;
  136. }
  137. message.alternate_bytes.content = 0;
  138. message.alternate_bytes.size = 0;
  139. message.alternate_bytes.qspi_lines = 0;
  140. /* set dummy cycles */
  141. if (count != send_length)
  142. {
  143. message.dummy_cycles = (send_length - count) * 8;
  144. }
  145. else
  146. {
  147. message.dummy_cycles = 0;
  148. }
  149. /* set recv buf and recv size */
  150. message.parent.recv_buf = recv_buf;
  151. message.parent.send_buf = RT_NULL;
  152. message.parent.length = recv_length;
  153. message.parent.cs_take = 1;
  154. message.parent.cs_release = 1;
  155. message.qspi_data_lines = 1;
  156. result = rt_qspi_transfer_message(device, &message);
  157. if (result == 0)
  158. {
  159. result = -RT_EIO;
  160. }
  161. else
  162. {
  163. result = recv_length;
  164. }
  165. return result;
  166. }
  167. rt_err_t rt_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length)
  168. {
  169. RT_ASSERT(send_buf);
  170. RT_ASSERT(length != 0);
  171. struct rt_qspi_message message;
  172. unsigned char *ptr = (unsigned char *)send_buf;
  173. rt_size_t count = 0;
  174. rt_err_t result = 0;
  175. message.instruction.content = ptr[0];
  176. message.instruction.qspi_lines = 1;
  177. count++;
  178. /* get address */
  179. if (length > 1)
  180. {
  181. if (device->config.medium_size > 0x1000000 && length >= 5)
  182. {
  183. /* medium size greater than 16Mb, address size is 4 Byte */
  184. message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]);
  185. message.address.size = 32;
  186. message.address.qspi_lines = 1;
  187. count += 4;
  188. }
  189. else if (length >= 4)
  190. {
  191. /* address size is 3 Byte */
  192. message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
  193. message.address.size = 24;
  194. message.address.qspi_lines = 1;
  195. count += 3;
  196. }
  197. else
  198. {
  199. return -RT_ERROR;
  200. }
  201. }
  202. else
  203. {
  204. /* no address stage */
  205. message.address.content = 0 ;
  206. message.address.qspi_lines = 0;
  207. message.address.size = 0;
  208. }
  209. message.alternate_bytes.content = 0;
  210. message.alternate_bytes.size = 0;
  211. message.alternate_bytes.qspi_lines = 0;
  212. message.dummy_cycles = 0;
  213. /* determine if there is data to send */
  214. if (length - count > 0)
  215. {
  216. message.qspi_data_lines = 1;
  217. }
  218. else
  219. {
  220. message.qspi_data_lines = 0;
  221. }
  222. /* set send buf and send size */
  223. message.parent.send_buf = ptr + count;
  224. message.parent.recv_buf = RT_NULL;
  225. message.parent.length = length - count;
  226. message.parent.cs_take = 1;
  227. message.parent.cs_release = 1;
  228. result = rt_qspi_transfer_message(device, &message);
  229. if (result == 0)
  230. {
  231. result = -RT_EIO;
  232. }
  233. else
  234. {
  235. result = length;
  236. }
  237. return result;
  238. }