ls1c_spi.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /*
  2. * Copyright (c) 2006-2018, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2017-10-23 勤为本 first version
  9. */
  10. // 硬件spi接口源文件
  11. #include <string.h>
  12. #include "ls1c_public.h"
  13. #include "ls1c_regs.h"
  14. #include "ls1c_clock.h"
  15. #include "ls1c_spi.h"
  16. /*
  17. * 获取指定SPI模块的基地址
  18. * @SPIx SPI模块的编号
  19. */
  20. void *ls1c_spi_get_base(unsigned char SPIx)
  21. {
  22. void *base = NULL;
  23. switch (SPIx)
  24. {
  25. case LS1C_SPI_0:
  26. base = (void *)LS1C_SPI0_BASE;
  27. break;
  28. case LS1C_SPI_1:
  29. base = (void *)LS1C_SPI1_BASE;
  30. break;
  31. default:
  32. base = NULL;
  33. break;
  34. }
  35. return base;
  36. }
  37. /*
  38. * 打印指定SPI模块的所有寄存器的值
  39. * @spi_base 基地址
  40. */
  41. void ls1c_spi_print_all_regs_info(void *spi_base)
  42. {
  43. printf("[%s] SPCR=0x%x, SPSR=0x%x, SPER=0x%x, SFC_PARAM=0x%x, SFC_SOFTCS=0x%x, SFC_TIMING=0x%x\r\n",
  44. __FUNCTION__,
  45. reg_read_8(spi_base + LS1C_SPI_SPCR_OFFSET),
  46. reg_read_8(spi_base + LS1C_SPI_SPSR_OFFSET),
  47. reg_read_8(spi_base + LS1C_SPI_SPER_OFFSET),
  48. reg_read_8(spi_base + LS1C_SPI_SFC_PARAM_OFFSET),
  49. reg_read_8(spi_base + LS1C_SPI_SFC_SOFTCS_OFFSET),
  50. reg_read_8(spi_base + LS1C_SPI_SFC_TIMING_OFFSET));
  51. return ;
  52. }
  53. /*
  54. * 根据SPI时钟频率计算分频系数
  55. * @max_speed_hz SPI最大通信速度
  56. * @ret 分频系数
  57. */
  58. unsigned int ls1c_spi_get_div(unsigned int max_speed_hz)
  59. {
  60. unsigned long clk = 0;
  61. unsigned int div = 0;
  62. unsigned int div_tmp = 0;
  63. unsigned int bit = 0;
  64. clk = clk_get_apb_rate();
  65. div = DIV_ROUND_UP(clk, max_speed_hz);
  66. if (div < 2)
  67. div = 2;
  68. if (div > 4096)
  69. div = 4096;
  70. bit = ls1c_fls(div) - 1;
  71. switch (1 << bit)
  72. {
  73. case 16:
  74. div_tmp = 2;
  75. if (div > (1 << bit))
  76. {
  77. div_tmp++;
  78. }
  79. break;
  80. case 32:
  81. div_tmp = 3;
  82. if (div > (1 << bit))
  83. {
  84. div_tmp += 2;
  85. }
  86. break;
  87. case 8:
  88. div_tmp = 4;
  89. if (div > (1 << bit))
  90. {
  91. div_tmp -= 2;
  92. }
  93. break;
  94. default:
  95. div_tmp = bit - 1;
  96. if (div > (1 << bit))
  97. {
  98. div_tmp++;
  99. }
  100. break;
  101. }
  102. /*
  103. printf("[%s] clk=%ld, max_speed_hz=%d, div_tmp=%d, bit=%d\r\n",
  104. __FUNCTION__, clk, max_speed_hz, div_tmp, bit);
  105. */
  106. return div_tmp;
  107. }
  108. /*
  109. * 设置时钟
  110. * @spi_base 基地址
  111. * @max_hz 最大频率,单位hz
  112. */
  113. void ls1c_spi_set_clock(void *spi_base, unsigned long max_hz)
  114. {
  115. unsigned int div = 0;
  116. unsigned char val = 0;
  117. // 获取分频系数
  118. div = ls1c_spi_get_div(max_hz);
  119. // 设置spr
  120. val = reg_read_8(spi_base + LS1C_SPI_SPCR_OFFSET);
  121. val &= (~LS1C_SPI_SPCR_SPR_MASK); // spr清零
  122. val |= (div & LS1C_SPI_SPCR_SPR_MASK); // 设置新的spr
  123. reg_write_8(val, spi_base + LS1C_SPI_SPCR_OFFSET);
  124. // 设置spre
  125. val = reg_read_8(spi_base + LS1C_SPI_SPER_OFFSET);
  126. val &= (~LS1C_SPI_SPER_SPRE_MASK); // spre清零
  127. val |= ((div >> 2) & LS1C_SPI_SPER_SPRE_MASK); // 设置新的spre
  128. reg_write_8(val, spi_base + LS1C_SPI_SPER_OFFSET);
  129. return ;
  130. }
  131. /*
  132. * 设置通信模式(时钟极性和相位)
  133. * @spi_base 基地址
  134. * @cpol 时钟极性
  135. * @cpha 时钟相位
  136. */
  137. void ls1c_spi_set_mode(void *spi_base, unsigned char cpol, unsigned char cpha)
  138. {
  139. unsigned char val = 0;
  140. val = reg_read_8(spi_base + LS1C_SPI_SPCR_OFFSET);
  141. // 设置时钟极性--cpol
  142. val &= (~LS1C_SPI_SPCR_CPOL_MASK); // cpol清0
  143. val |= (cpol << LS1C_SPI_SPCR_CPOL_BIT); // 写入新的cpol
  144. // 设置时钟相位--cpha
  145. val &= (~LS1C_SPI_SPCR_CPHA_MASK); // cpha清0
  146. val |= (cpha << LS1C_SPI_SPCR_CPHA_BIT); // 写入新的cpha
  147. reg_write_8(val, spi_base + LS1C_SPI_SPCR_OFFSET);
  148. return ;
  149. }
  150. /*
  151. * 设置指定片选为指定状态
  152. * @spi_base 基地址
  153. * @cs 片选
  154. * @new_status 片选引脚的新状态,取值为0或1,即高电平或低电平
  155. */
  156. void ls1c_spi_set_cs(void *spi_base, unsigned char cs, int new_status)
  157. {
  158. unsigned char val = 0;
  159. val = reg_read_8(spi_base + LS1C_SPI_SFC_SOFTCS_OFFSET);
  160. val |= 0x01 << cs ; //对应的csen=1
  161. if (new_status) // cs = 1
  162. {
  163. val |= (0x10 << cs); // 指定csn=1
  164. }
  165. else // cs = 0
  166. {
  167. val &= ~(0x10 << cs); // 指定csn=0
  168. }
  169. reg_write_8(val, spi_base + LS1C_SPI_SFC_SOFTCS_OFFSET);
  170. return ;
  171. }
  172. /*
  173. * 等待收发完成
  174. * @spi_base 基地址
  175. */
  176. void ls1c_spi_wait_txrx_done(void *spi_base)
  177. {
  178. int timeout = LS1C_SPI_TX_TIMEOUT;
  179. while (timeout--)
  180. {
  181. if (LS1C_SPI_SPSR_SPIF_MASK & reg_read_8(spi_base + LS1C_SPI_SPSR_OFFSET))
  182. break;
  183. }
  184. return ;
  185. }
  186. /*
  187. * 清中断和标志位
  188. * @spi_base 基地址
  189. */
  190. void ls1c_spi_clear(void *spi_base)
  191. {
  192. unsigned char val = 0;
  193. // 清中断
  194. val = reg_read_8(spi_base + LS1C_SPI_SPSR_OFFSET);
  195. val |= LS1C_SPI_SPSR_SPIF_MASK;
  196. reg_write_8(val, spi_base + LS1C_SPI_SPSR_OFFSET);
  197. // 清溢出标志位(Write-Collision Clear)
  198. val = reg_read_8(spi_base + LS1C_SPI_SPSR_OFFSET);
  199. if (LS1C_SPI_SPSR_WCOL_MASK & val)
  200. {
  201. printf("[%s] clear register SPSR's wcol!\r\n"); // 手册和linux源码中不一样,加个打印看看
  202. reg_write_8(val & ~LS1C_SPI_SPSR_WCOL_MASK, spi_base + LS1C_SPI_SPSR_OFFSET); // 写0,linux源码中是写0
  203. // reg_write_8(val | LS1C_SPI_SPSR_WCOL_MASK, spi_base + LS1C_SPI_SPSR_OFFSET); // 写1,按照1c手册,应该写1
  204. }
  205. return ;
  206. }
  207. /*
  208. * 通过指定SPI发送接收一个字节
  209. * 注意,在多任务的系统中,此函数需要互斥。
  210. * 即保证在和某个从设备收发某个字节的过程中,不能被切换到其它任务同时与另外的在同一个SPI总线上的从设备通信
  211. * 因为龙芯1c的每路SPI上可能接有不同的从设备,通信频率、模式等可能不同
  212. * @spi_base 基地址
  213. * @tx_ch 待发送的数据
  214. * @ret 收到的数据
  215. */
  216. unsigned char ls1c_spi_txrx_byte(void *spi_base, unsigned char tx_ch)
  217. {
  218. unsigned char rx_ch = 0;
  219. // 收发数据
  220. reg_write_8(tx_ch, spi_base + LS1C_SPI_TxFIFO_OFFSET); // 开始发送
  221. ls1c_spi_wait_txrx_done(spi_base); // 等待收发完成
  222. rx_ch = reg_read_8(spi_base + LS1C_SPI_RxFIFO_OFFSET); // 读取收到的数据
  223. ls1c_spi_clear(spi_base); // 清中断和标志位
  224. return rx_ch;
  225. }