dw_spi.c 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337
  1. /* ------------------------------------------
  2. * Copyright (c) 2017, Synopsys, Inc. All rights reserved.
  3. * Redistribution and use in source and binary forms, with or without modification,
  4. * are permitted provided that the following conditions are met:
  5. * 1) Redistributions of source code must retain the above copyright notice, this
  6. * list of conditions and the following disclaimer.
  7. * 2) Redistributions in binary form must reproduce the above copyright notice,
  8. * this list of conditions and the following disclaimer in the documentation and/or
  9. * other materials provided with the distribution.
  10. * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may
  11. * be used to endorse or promote products derived from this software without
  12. * specific prior written permission.
  13. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  14. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  15. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  16. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  17. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  18. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  19. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  20. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  21. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  22. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. *
  24. * \version 2017.03
  25. * \date 2014-06-25
  26. * \author Huaqi Fang(Huaqi.Fang@synopsys.com)
  27. --------------------------------------------- */
  28. /**
  29. * \defgroup DEVICE_DW_SPI Designware SPI Driver
  30. * \ingroup DEVICE_DW
  31. * \brief Designware SPI Driver Implementation
  32. */
  33. /**
  34. * \file
  35. * \brief DesignWare SPI driver implementation based on device hal layer definition (\ref dev_spi.h)
  36. * \ingroup DEVICE_DW_SPI
  37. */
  38. #include <string.h>
  39. #include "inc/embARC_toolchain.h"
  40. #include "inc/embARC_error.h"
  41. #include "inc/arc/arc_exception.h"
  42. #include "device/designware/spi/dw_spi_hal.h"
  43. #include "device/designware/spi/dw_spi.h"
  44. /**
  45. * \defgroup DEVICE_DW_SPI_DEFINES DesignWare SPI Driver Macros
  46. * \ingroup DEVICE_DW_SPI
  47. * \brief DesignWare SPI driver macros used in spi driver
  48. * @{
  49. */
  50. /** check expressions used in DesignWare SPI driver implementation */
  51. #define DW_SPI_CHECK_EXP(EXPR, ERROR_CODE) CHECK_EXP(EXPR, ercd, ERROR_CODE, error_exit)
  52. /** convert DesignWare frequence to divisor */
  53. #define DW_SPI_FREQ2DV(perifreq, spifreq) ((perifreq) / (spifreq))
  54. #ifndef DISABLE_DEVICE_OBJECT_VALID_CHECK
  55. /** valid check of spi info object */
  56. #define VALID_CHK_SPI_INFO_OBJECT(spiinfo_obj_ptr) { \
  57. DW_SPI_CHECK_EXP((spiinfo_obj_ptr)!=NULL, E_OBJ); \
  58. DW_SPI_CHECK_EXP(((spiinfo_obj_ptr)->spi_ctrl)!=NULL, E_OBJ); \
  59. }
  60. #endif
  61. /**
  62. * \defgroup DEVICE_DW_SPI_DEF_CBR DesignWare SPI Interrupt Callback Routine Select Marcos
  63. * \ingroup DEVICE_DW_SPI_DEFINES
  64. * \brief DesignWare SPI interrupt callback routines select macros definitions
  65. * @{
  66. */
  67. #define DW_SPI_RDY_SND (1U) /*!< ready to send callback */
  68. #define DW_SPI_RDY_RCV (2U) /*!< ready to receive callback */
  69. #define DW_SPI_RDY_XFER (3U) /*!< ready to transfer callback */
  70. /** @} */
  71. /** @} */
  72. /**
  73. * \defgroup DEVICE_DW_SPI_STATIC DesignWare SPI Driver Static Functions
  74. * \ingroup DEVICE_DW_SPI
  75. * \brief Static or inline functions, variables for DesignWare SPI handle spi operations,
  76. * only used in this file.
  77. * @{
  78. */
  79. /** Disable designware spi device */
  80. Inline void dw_spi_disable(DW_SPI_REG *spi_reg_ptr)
  81. {
  82. /** disable spi operations, then program spi control regs is possible */
  83. spi_reg_ptr->SSIENR = DW_SPI_SSI_DISABLE;
  84. }
  85. /** Enable designware spi device */
  86. Inline void dw_spi_enable(DW_SPI_REG *spi_reg_ptr)
  87. {
  88. spi_reg_ptr->SSIENR = DW_SPI_SSI_ENABLE;
  89. }
  90. /** Clear all designware spi interrupt */
  91. Inline void dw_spi_clear_interrupt_all(DW_SPI_REG *spi_reg_ptr)
  92. {
  93. (void)spi_reg_ptr->ICR;
  94. }
  95. /** test whether spi is busy, busy return 1, else 0 */
  96. Inline int32_t dw_spi_busy(DW_SPI_REG *spi_reg_ptr)
  97. {
  98. return ((spi_reg_ptr->SR & DW_SPI_SR_BUSY) != 0);
  99. }
  100. /** test whether spi is ready to send, 1 ready, 0 not ready */
  101. Inline int32_t dw_spi_putready(DW_SPI_REG *spi_reg_ptr)
  102. {
  103. return ((spi_reg_ptr->SR & DW_SPI_SR_TFNF) != 0);
  104. }
  105. /** test whether spi is read to receive, 1 ready, 0 not ready */
  106. Inline int32_t dw_spi_getready(DW_SPI_REG *spi_reg_ptr)
  107. {
  108. return ((spi_reg_ptr->SR & DW_SPI_SR_RFNE) != 0);
  109. }
  110. /** write data to spi send fifo */
  111. Inline void dw_spi_putdata(DW_SPI_REG *spi_reg_ptr, int32_t data)
  112. {
  113. spi_reg_ptr->DATAREG = (uint32_t)data;
  114. }
  115. /** read data from spi receive fifo, return data received */
  116. Inline int32_t dw_spi_getdata(DW_SPI_REG *spi_reg_ptr)
  117. {
  118. return (int32_t)spi_reg_ptr->DATAREG;
  119. }
  120. /**
  121. * \brief send data by spi when available,
  122. * mostly used in interrupt method, non-blocked function
  123. * \param[in] spi_reg_ptr spi register structure pointer
  124. * \param[in] data data to be sent
  125. * \retval E_OK send successfully
  126. * \retval E_OBJ not ready to send data
  127. */
  128. Inline int32_t dw_spi_snd_dat(DW_SPI_REG *spi_reg_ptr, int32_t data)
  129. {
  130. if (dw_spi_putready(spi_reg_ptr)) {
  131. dw_spi_putdata(spi_reg_ptr, data);
  132. return E_OK;
  133. }
  134. return E_OBJ;
  135. }
  136. /**
  137. * \brief receive one char from spi,
  138. * mostly used in interrupt routine, non-blocked function
  139. * \param[in] spi_reg_ptr spi register structure pointer
  140. * \return data received by the spi
  141. */
  142. Inline int32_t dw_spi_rcv_dat(DW_SPI_REG *spi_reg_ptr)
  143. {
  144. return dw_spi_getdata(spi_reg_ptr);
  145. }
  146. /**
  147. * \brief send char by spi in poll method, blocked function
  148. * \param[in] spi_reg_ptr spi register structure pointer
  149. * \param[in] data data to be sent
  150. */
  151. Inline void dw_spi_psnd_dat(DW_SPI_REG *spi_reg_ptr, int32_t data)
  152. {
  153. /** wait until spi is ready to send */
  154. while (!dw_spi_putready(spi_reg_ptr)); /* blocked */
  155. /** send char */
  156. dw_spi_putdata(spi_reg_ptr, data);
  157. }
  158. /**
  159. * \brief receive one char from spi in poll method, blocked function
  160. * \param[in] spi_reg_ptr spi register structure pointer
  161. * \return data received by the spi
  162. */
  163. Inline int32_t dw_spi_prcv_dat(DW_SPI_REG *spi_reg_ptr)
  164. {
  165. /** wait until spi is ready to receive */
  166. while (!dw_spi_getready(spi_reg_ptr)); /* blocked */
  167. /** receive data */
  168. return dw_spi_getdata(spi_reg_ptr);
  169. }
  170. /** Reset designware FIFO by disable spi device, then enable device */
  171. Inline void dw_spi_reset_fifo(DW_SPI_REG *spi_reg_ptr)
  172. {
  173. dw_spi_disable(spi_reg_ptr);
  174. dw_spi_enable(spi_reg_ptr);
  175. }
  176. /** Enable designware spi bit interrupt with mask */
  177. Inline void dw_spi_unmask_interrupt(DW_SPI_REG *spi_reg_ptr, uint32_t mask)
  178. {
  179. spi_reg_ptr->IMR |= mask;
  180. }
  181. /** Disable designware spi bit interrupt with mask */
  182. Inline void dw_spi_mask_interrupt(DW_SPI_REG *spi_reg_ptr, uint32_t mask)
  183. {
  184. spi_reg_ptr->IMR &= ~mask;
  185. }
  186. /** Set designware spi device frequency */
  187. Inline void dw_spi_set_freq(DW_SPI_CTRL *spi_ctrl_ptr, uint32_t freq)
  188. {
  189. uint32_t sck_divisor;
  190. DW_SPI_REG *spi_reg_ptr = spi_ctrl_ptr->dw_spi_regs;
  191. dw_spi_disable(spi_reg_ptr);
  192. sck_divisor = DW_SPI_FREQ2DV(spi_ctrl_ptr->dw_apb_bus_freq, freq);
  193. spi_reg_ptr->BAUDR = sck_divisor;
  194. dw_spi_enable(spi_reg_ptr);
  195. }
  196. /** Set designware spi device data frame size */
  197. static int32_t dw_spi_set_dfs(DW_SPI_REG *spi_reg_ptr, uint32_t dfs)
  198. {
  199. uint32_t ctrl0_reg;
  200. if ((dfs <= 3) || (dfs > 16)) return -1;
  201. dw_spi_disable(spi_reg_ptr);
  202. ctrl0_reg = spi_reg_ptr->CTRLR0;
  203. ctrl0_reg &= ~(DW_SPI_CTRLR0_DFS_MASK);
  204. spi_reg_ptr->CTRLR0 = ctrl0_reg | (dfs-1);
  205. dw_spi_enable(spi_reg_ptr);
  206. return 0;
  207. }
  208. /** Choose proper designware spi clock mode setting value */
  209. Inline uint32_t dw_spi_select_clockmode(uint32_t clk_mode)
  210. {
  211. return (clk_mode << DW_SPI_CTRLR0_SC_OFS);
  212. }
  213. /** Set designware spi clock mode */
  214. Inline int32_t dw_spi_set_clockmode(DW_SPI_REG *spi_reg_ptr, uint32_t clk_mode)
  215. {
  216. if (clk_mode > SPI_CPOL_1_CPHA_1) {
  217. return -1;
  218. }
  219. dw_spi_disable(spi_reg_ptr);
  220. spi_reg_ptr->CTRLR0 &= ~(DW_SPI_CTRLR0_SC_MASK);
  221. spi_reg_ptr->CTRLR0 |= dw_spi_select_clockmode(clk_mode);
  222. dw_spi_enable(spi_reg_ptr);
  223. return 0;
  224. }
  225. /** Select a spi slave with slv_line */
  226. Inline int32_t dw_spi_select_slave(DW_SPI_REG *spi_reg_ptr, uint32_t slv_line)
  227. {
  228. /* check if spi busy */
  229. if (dw_spi_busy(spi_reg_ptr)) return -1;
  230. spi_reg_ptr->SER = 1<<slv_line;
  231. return 0;
  232. }
  233. /** Deselect a spi device */
  234. Inline int32_t dw_spi_deselect_slave(DW_SPI_REG *spi_reg_ptr, uint32_t slv_line)
  235. {
  236. /* check if spi busy */
  237. if (dw_spi_busy(spi_reg_ptr)) return -1;
  238. spi_reg_ptr->SER = 0;
  239. return 0;
  240. }
  241. Inline void dw_spi_flush_tx(DW_SPI_REG *spi_reg_ptr)
  242. {
  243. dw_spi_reset_fifo(spi_reg_ptr);
  244. }
  245. Inline void dw_spi_flush_rx(DW_SPI_REG *spi_reg_ptr)
  246. {
  247. dw_spi_reset_fifo(spi_reg_ptr);
  248. }
  249. /** Get TX FIFO Length.
  250. * calculate spi fifo length using fifo threshold method
  251. * If you attempt to set bits [7:0] of this register to
  252. * a value greater than or equal to the depth of the FIFO,
  253. * this field is not written and retains its current value.
  254. */
  255. static uint32_t dw_spi_get_txfifo_len(DW_SPI_REG *spi_reg_ptr)
  256. {
  257. uint32_t fifo_thr_lev_tmp, left, right, i;
  258. fifo_thr_lev_tmp = spi_reg_ptr->TXFTLR;
  259. if (fifo_thr_lev_tmp != 0) {
  260. left = fifo_thr_lev_tmp;
  261. } else {
  262. left = DW_SPI_MIN_FIFO_LENGTH;
  263. }
  264. right = DW_SPI_MAX_FIFO_LENGTH + 1;
  265. for (i = left; i <= right; i++) {
  266. spi_reg_ptr->TXFTLR = i;
  267. if (spi_reg_ptr->TXFTLR != i) {
  268. break;
  269. }
  270. }
  271. spi_reg_ptr->TXFTLR = fifo_thr_lev_tmp; /* restore old fifo threshold */
  272. return (i);
  273. }
  274. /** Get RX FIFO Length */
  275. static uint32_t dw_spi_get_rxfifo_len(DW_SPI_REG *spi_reg_ptr)
  276. {
  277. uint32_t fifo_thr_lev_tmp, left, right, i;
  278. fifo_thr_lev_tmp = spi_reg_ptr->RXFTLR;
  279. if (fifo_thr_lev_tmp != 0) {
  280. left = fifo_thr_lev_tmp;
  281. } else {
  282. left = DW_SPI_MIN_FIFO_LENGTH;
  283. }
  284. right = DW_SPI_MAX_FIFO_LENGTH + 1;
  285. for (i = left; i <= right; i++) {
  286. spi_reg_ptr->RXFTLR = i;
  287. if (spi_reg_ptr->RXFTLR != i) {
  288. break;
  289. }
  290. }
  291. spi_reg_ptr->RXFTLR = fifo_thr_lev_tmp; /* restore old fifo threshold */
  292. return (i);
  293. }
  294. /** Init Designware SPI Hardware */
  295. static void dw_spi_hw_init(DW_SPI_CTRL *spi_ctrl_ptr, uint32_t clk_mode, uint32_t dfs)
  296. {
  297. uint32_t ctrl0_reg = 0;
  298. DW_SPI_REG *spi_reg_ptr = spi_ctrl_ptr->dw_spi_regs;
  299. dw_spi_disable(spi_reg_ptr);
  300. /* Clear interrupts */
  301. ctrl0_reg = spi_reg_ptr->ICR;
  302. /* Mask all interrupts */
  303. spi_reg_ptr->IMR = 0;
  304. ctrl0_reg = DW_SPI_CTRLR0_FRF_MOTOROLA | DW_SPI_TMOD_TRANSMIT_RECEIVE \
  305. | dw_spi_select_clockmode(clk_mode) | (dfs - 1) | DW_SPI_CTRLR0_SLV_OE_ENABLE;
  306. spi_reg_ptr->CTRLR0 = ctrl0_reg;
  307. spi_reg_ptr->CTRLR1 = 0;
  308. /* deselect slaves */
  309. spi_reg_ptr->SER = 0;
  310. /* Set threshold values for both tx and rx */
  311. spi_reg_ptr->TXFTLR = 0;
  312. spi_reg_ptr->RXFTLR = 0;
  313. dw_spi_enable(spi_reg_ptr);
  314. }
  315. /** enable designware spi */
  316. static void dw_spi_enable_device(DEV_SPI_INFO *spi_info_ptr)
  317. {
  318. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl);
  319. DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs);
  320. if ((spi_info_ptr->status & DEV_ENABLED) == 0) {
  321. dw_spi_enable(spi_reg_ptr);
  322. spi_info_ptr->status |= DEV_ENABLED;
  323. }
  324. }
  325. /** disable designware spi */
  326. static void dw_spi_disable_device(DEV_SPI_INFO *spi_info_ptr)
  327. {
  328. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl);
  329. DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs);
  330. dw_spi_disable(spi_reg_ptr);
  331. spi_info_ptr->status &= ~DEV_ENABLED;
  332. }
  333. /**
  334. * \brief disable designware spi send or receive interrupt
  335. * \param[in] DEV_SPI_INFO *spi_info_ptr
  336. * \param[in] cbrtn control code of callback routine of send or receive
  337. */
  338. static int32_t dw_spi_dis_cbr(DEV_SPI_INFO *spi_info_ptr, uint32_t cbrtn)
  339. {
  340. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl);
  341. int32_t ercd = E_OK;
  342. if ((spi_info_ptr->status & DW_SPI_IN_XFER) != 0) { /* only in transfer need do check */
  343. switch (cbrtn) {
  344. case DW_SPI_RDY_SND:
  345. DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_TX, E_CTX);
  346. spi_info_ptr->status &= ~(DW_SPI_IN_TX);
  347. break;
  348. case DW_SPI_RDY_RCV:
  349. DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_RX, E_CTX);
  350. spi_info_ptr->status &= ~(DW_SPI_IN_RX);
  351. break;
  352. case DW_SPI_RDY_XFER:
  353. DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_XFER, E_CTX);
  354. spi_info_ptr->status &= ~(DW_SPI_IN_XFER);
  355. break;
  356. default:
  357. break;
  358. }
  359. }
  360. dw_spi_mask_interrupt(spi_ctrl_ptr->dw_spi_regs, DW_SPI_IMR_XFER);
  361. if (spi_ctrl_ptr->int_status & DW_SPI_GINT_ENABLE) {
  362. int_disable(spi_ctrl_ptr->intno);
  363. spi_ctrl_ptr->int_status &= ~DW_SPI_GINT_ENABLE;
  364. }
  365. error_exit:
  366. return ercd;
  367. }
  368. /**
  369. * \brief enable DesignWare SPI send or receive interrupt
  370. * \param[in] DEV_SPI_INFO *spi_info_ptr
  371. * \param[in] cbrtn control code of callback routine of send or receive
  372. */
  373. static int32_t dw_spi_ena_cbr(DEV_SPI_INFO *spi_info_ptr, uint32_t cbrtn)
  374. {
  375. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl);
  376. int32_t ercd = E_OK;
  377. DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) == 0, E_CTX);
  378. switch (cbrtn) {
  379. case DW_SPI_RDY_SND:
  380. spi_info_ptr->status |= DW_SPI_IN_TX;
  381. break;
  382. case DW_SPI_RDY_RCV:
  383. spi_info_ptr->status |= DW_SPI_IN_RX;
  384. break;
  385. case DW_SPI_RDY_XFER:
  386. spi_info_ptr->status |= DW_SPI_IN_XFER;
  387. break;
  388. default:
  389. break;
  390. }
  391. dw_spi_unmask_interrupt(spi_ctrl_ptr->dw_spi_regs, DW_SPI_IMR_XFER);
  392. if ((spi_ctrl_ptr->int_status & DW_SPI_GINT_ENABLE) == 0) {
  393. spi_ctrl_ptr->int_status |= DW_SPI_GINT_ENABLE;
  394. int_enable(spi_ctrl_ptr->intno);
  395. }
  396. error_exit:
  397. return ercd;
  398. }
  399. /**
  400. * \brief enable designware spi interrupt
  401. * \param spi_info_ptr spi information structure pointer
  402. */
  403. static void dw_spi_enable_interrupt(DEV_SPI_INFO *spi_info_ptr)
  404. {
  405. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl);
  406. int_handler_install(spi_ctrl_ptr->intno, spi_ctrl_ptr->dw_spi_int_handler);
  407. spi_ctrl_ptr->int_status |= DW_SPI_GINT_ENABLE;
  408. int_enable(spi_ctrl_ptr->intno); /** enable spi interrupt */
  409. }
  410. /**
  411. * \brief disable designware spi interrupt
  412. * \param spi_info_ptr spi information structure pointer
  413. */
  414. static void dw_spi_disable_interrupt(DEV_SPI_INFO *spi_info_ptr)
  415. {
  416. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl);
  417. /** disable spi send&receive interrupt after disable spi interrupt */
  418. dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_SND);
  419. dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_RCV);
  420. dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_XFER);
  421. /* disable spi interrupt */
  422. dw_spi_mask_interrupt(spi_ctrl_ptr->dw_spi_regs, DW_SPI_IMR_XFER);
  423. spi_info_ptr->status &= ~DW_SPI_IN_XFER;
  424. int_disable(spi_ctrl_ptr->intno);
  425. spi_ctrl_ptr->int_status &= ~(DW_SPI_GINT_ENABLE);
  426. }
  427. static void dw_spi_reset_device(DEV_SPI_INFO *spi_info_ptr)
  428. {
  429. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl);
  430. DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs);
  431. dw_spi_disable_device(spi_info_ptr);
  432. dw_spi_disable_interrupt(spi_info_ptr);
  433. dw_spi_clear_interrupt_all(spi_reg_ptr);
  434. dw_spi_enable_device(spi_info_ptr);
  435. }
  436. /** abort current interrupt transmit transfer */
  437. static int32_t dw_spi_abort_tx(DEV_SPI *spi_obj)
  438. {
  439. DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info);
  440. int32_t ercd = E_OK;
  441. DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) != 0, E_OK);
  442. DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_TX, E_CTX);
  443. dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_SND);
  444. spi_info_ptr->status |= DEV_IN_TX_ABRT;
  445. if (spi_info_ptr->spi_cbs.tx_cb != NULL) {
  446. spi_info_ptr->spi_cbs.tx_cb(spi_obj);
  447. }
  448. spi_info_ptr->status &= ~(DEV_IN_TX_ABRT);
  449. error_exit:
  450. return ercd;
  451. }
  452. /** abort current interrupt receive transfer */
  453. static int32_t dw_spi_abort_rx(DEV_SPI *spi_obj)
  454. {
  455. DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info);
  456. int32_t ercd = E_OK;
  457. DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) != 0, E_OK);
  458. DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_RX, E_CTX);
  459. dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_RCV);
  460. spi_info_ptr->status |= DEV_IN_RX_ABRT;
  461. if (spi_info_ptr->spi_cbs.rx_cb != NULL) {
  462. spi_info_ptr->spi_cbs.rx_cb(spi_obj);
  463. }
  464. spi_info_ptr->status &= ~(DEV_IN_RX_ABRT);
  465. error_exit:
  466. return ercd;
  467. }
  468. /** abort current interrupt transfer */
  469. static int32_t dw_spi_abort_xfer(DEV_SPI *spi_obj)
  470. {
  471. DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info);
  472. int32_t ercd = E_OK;
  473. DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) != 0, E_OK);
  474. DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_XFER, E_CTX);
  475. dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_XFER);
  476. spi_info_ptr->status |= DEV_IN_XFER_ABRT;
  477. if (spi_info_ptr->spi_cbs.xfer_cb != NULL) {
  478. spi_info_ptr->spi_cbs.xfer_cb(spi_obj);
  479. }
  480. spi_info_ptr->status &= ~(DEV_IN_XFER_ABRT);
  481. error_exit:
  482. return ercd;
  483. }
  484. /** Get available transmit fifo count */
  485. static int32_t dw_spi_get_txavail(DW_SPI_CTRL *spi_ctrl_ptr)
  486. {
  487. int32_t tx_avail = 0;
  488. DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs);
  489. #if DW_SPI_CALC_FIFO_LEN_ENABLE
  490. if (spi_ctrl_ptr->tx_fifo_len <= 1) {
  491. if (dw_spi_putready(spi_reg_ptr) == 1) {
  492. tx_avail = 1;
  493. } else {
  494. tx_avail = 0;
  495. }
  496. } else
  497. #endif
  498. {
  499. tx_avail = spi_ctrl_ptr->tx_fifo_len - spi_reg_ptr->TXFLR;
  500. }
  501. return tx_avail;
  502. }
  503. /** Get available receive fifo count */
  504. static int32_t dw_spi_get_rxavail(DW_SPI_CTRL *spi_ctrl_ptr)
  505. {
  506. int32_t rx_avail = 0;
  507. DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs);
  508. #if DW_SPI_CALC_FIFO_LEN_ENABLE
  509. if (spi_ctrl_ptr->rx_fifo_len <= 1) {
  510. if (dw_spi_getready(spi_reg_ptr) == 1) {
  511. rx_avail = 1;
  512. } else {
  513. rx_avail = 0;
  514. }
  515. } else
  516. #endif
  517. {
  518. rx_avail = spi_reg_ptr->RXFLR;
  519. }
  520. return rx_avail;
  521. }
  522. static uint32_t dw_spi_tx_max(DW_SPI_CTRL *spi_ctrl_ptr)
  523. {
  524. uint32_t tx_left, tx_room;
  525. DW_SPI_TRANSFER *xfer = &(spi_ctrl_ptr->dw_xfer);
  526. tx_left = (xfer->xfer_len - xfer->tx_idx) / xfer->nbytes;
  527. tx_room = dw_spi_get_txavail(spi_ctrl_ptr);
  528. return (tx_left < tx_room) ? tx_left : tx_room;
  529. }
  530. static uint32_t dw_spi_rx_max(DW_SPI_CTRL *spi_ctrl_ptr)
  531. {
  532. uint32_t rx_left, rx_room;
  533. DW_SPI_TRANSFER *xfer = &(spi_ctrl_ptr->dw_xfer);
  534. rx_left = (xfer->xfer_len - xfer->rx_idx) / xfer->nbytes;
  535. rx_room = dw_spi_get_rxavail(spi_ctrl_ptr);
  536. return (rx_left < rx_room) ? rx_left : rx_room;
  537. }
  538. Inline int32_t dw_spi_rx_end(DW_SPI_CTRL *spi_ctrl_ptr)
  539. {
  540. DW_SPI_TRANSFER *xfer = &(spi_ctrl_ptr->dw_xfer);
  541. return (xfer->rx_idx >= xfer->xfer_len);
  542. }
  543. Inline int32_t dw_spi_tx_end(DW_SPI_CTRL *spi_ctrl_ptr)
  544. {
  545. DW_SPI_TRANSFER *xfer = &(spi_ctrl_ptr->dw_xfer);
  546. return (xfer->tx_idx >= xfer->xfer_len);
  547. }
  548. /** 1 for end, 0 for not end */
  549. Inline int32_t dw_spi_xfer_end(DW_SPI_CTRL *spi_ctrl_ptr)
  550. {
  551. return (dw_spi_tx_end(spi_ctrl_ptr) && dw_spi_rx_end(spi_ctrl_ptr));
  552. }
  553. static int32_t dw_spi_writer(DEV_SPI_INFO *spi_info_ptr)
  554. {
  555. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL_PTR)(spi_info_ptr->spi_ctrl);
  556. DW_SPI_TRANSFER *dw_xfer = &(spi_ctrl_ptr->dw_xfer);
  557. DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs);
  558. uint32_t tx_max = dw_spi_tx_max(spi_ctrl_ptr);
  559. int32_t tx_w;
  560. uint32_t tx_cnt = tx_max;
  561. if (dw_xfer->tx_xfer == NULL) {
  562. return 0;
  563. }
  564. while (tx_max) {
  565. if (dw_xfer->tx_xfer->tx_idx >= dw_xfer->tx_xfer->tot_len) {
  566. dw_xfer->tx_xfer = dw_xfer->tx_xfer->next;
  567. if (dw_xfer->tx_xfer == NULL) {
  568. break;
  569. }
  570. }
  571. if ( (dw_xfer->tx_xfer->tx_idx >= dw_xfer->tx_xfer->tx_ofs) \
  572. && (dw_xfer->tx_xfer->tx_idx < dw_xfer->tx_xfer->tx_totlen)) {
  573. if (dw_xfer->nbytes == 1) {
  574. tx_w = (int32_t)(*(int8_t *)(dw_xfer->tx_xfer->tx_buf));
  575. } else {
  576. tx_w = (int32_t)(*(int16_t *)(dw_xfer->tx_xfer->tx_buf));
  577. }
  578. dw_xfer->tx_xfer->tx_buf += dw_xfer->nbytes;
  579. } else {
  580. tx_w = spi_info_ptr->dummy;
  581. }
  582. dw_spi_putdata(spi_reg_ptr, tx_w);
  583. dw_xfer->tx_xfer->tx_idx += dw_xfer->nbytes;
  584. dw_xfer->tx_idx += dw_xfer->nbytes;
  585. tx_max --;
  586. }
  587. return ((tx_cnt-tx_max) * dw_xfer->nbytes);
  588. }
  589. static int32_t dw_spi_reader(DEV_SPI_INFO *spi_info_ptr)
  590. {
  591. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL_PTR)(spi_info_ptr->spi_ctrl);
  592. DW_SPI_TRANSFER *dw_xfer = &(spi_ctrl_ptr->dw_xfer);
  593. DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs);
  594. uint32_t rx_max = dw_spi_rx_max(spi_ctrl_ptr);
  595. int32_t rx_w;
  596. uint32_t rx_cnt = rx_max;
  597. if (dw_xfer->rx_xfer == NULL) {
  598. return 0;
  599. }
  600. while (rx_max) {
  601. if (dw_xfer->rx_xfer->rx_idx >= dw_xfer->rx_xfer->tot_len) {
  602. dw_xfer->rx_xfer = dw_xfer->rx_xfer->next;
  603. if (dw_xfer->rx_xfer == NULL) {
  604. break;
  605. }
  606. }
  607. rx_w = dw_spi_getdata(spi_reg_ptr);
  608. if ( (dw_xfer->rx_xfer->rx_idx >= dw_xfer->rx_xfer->rx_ofs) \
  609. && (dw_xfer->rx_xfer->rx_idx < dw_xfer->rx_xfer->rx_totlen) ) {
  610. if (dw_xfer->nbytes == 1) {
  611. *(int8_t *)(dw_xfer->rx_xfer->rx_buf) = rx_w;
  612. } else {
  613. *(int16_t *)(dw_xfer->rx_xfer->rx_buf) = rx_w;
  614. }
  615. dw_xfer->rx_xfer->rx_buf += dw_xfer->nbytes;
  616. }
  617. dw_xfer->rx_xfer->rx_idx += dw_xfer->nbytes;
  618. dw_xfer->rx_idx += dw_xfer->nbytes;
  619. rx_max --;
  620. }
  621. return ((rx_cnt-rx_max) * dw_xfer->nbytes);
  622. }
  623. Inline uint32_t dw_spi_nbytes(uint32_t dfs)
  624. {
  625. uint32_t nbytes = 1;
  626. if (dfs > 8) nbytes = 2;
  627. return nbytes;
  628. }
  629. static void dw_spi_init_transfer(DW_SPI_CTRL *spi_ctrl_ptr, DEV_SPI_TRANSFER *xfer, uint32_t dfs)
  630. {
  631. DW_SPI_TRANSFER *dw_xfer= &(spi_ctrl_ptr->dw_xfer);
  632. uint32_t tot_len = 0;
  633. dw_xfer->tx_xfer = xfer;
  634. dw_xfer->rx_xfer = xfer;
  635. dw_xfer->tx_idx = 0;
  636. dw_xfer->rx_idx = 0;
  637. dw_xfer->nbytes = dw_spi_nbytes(dfs);
  638. /** Calculate all transfer length */
  639. while (xfer) {
  640. DEV_SPI_XFER_INIT(xfer);
  641. tot_len += xfer->tot_len;
  642. xfer = xfer->next;
  643. }
  644. dw_xfer->xfer_len = tot_len;
  645. }
  646. /* Check buffer align status, 0 for aligned, -1 for not-aligned */
  647. static int32_t dw_spi_chk_xfer_aligned(DEV_SPI_TRANSFER *xfer, uint32_t dfs)
  648. {
  649. uint32_t align_bytes = 1;
  650. if (xfer == NULL) return -1;
  651. if (dfs > 8) {
  652. align_bytes = 2;
  653. } else {
  654. return 0;
  655. }
  656. while (xfer) {
  657. /* check tx buffer align status */
  658. if (xfer->tx_len != 0) {
  659. if (xfer->tx_len % align_bytes) return -1;
  660. if (xfer->tx_ofs % align_bytes) return -1;
  661. if (!CHECK_ALIGN_BYTES(xfer->tx_buf, align_bytes)) return -1;
  662. }
  663. /* check tx buffer align status */
  664. if (xfer->rx_len != 0) {
  665. if (xfer->rx_len % align_bytes) return -1;
  666. if (xfer->rx_ofs % align_bytes) return -1;
  667. if (!CHECK_ALIGN_BYTES(xfer->rx_buf, align_bytes)) return -1;
  668. }
  669. xfer = xfer->next;
  670. }
  671. return 0;
  672. }
  673. static uint32_t dw_spi_poll_transfer(DEV_SPI_INFO *spi_info_ptr)
  674. {
  675. uint32_t len = 0;
  676. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL_PTR)(spi_info_ptr->spi_ctrl);
  677. spi_info_ptr->status |= DEV_IN_XFER;
  678. while (!dw_spi_xfer_end(spi_ctrl_ptr)) {
  679. len += dw_spi_writer(spi_info_ptr);
  680. len += dw_spi_reader(spi_info_ptr);
  681. }
  682. spi_info_ptr->status &= ~DEV_IN_XFER;
  683. return len>>1;
  684. }
  685. /** @} */
  686. /**
  687. * \brief open a designware spi device
  688. * \param[in] spi_obj spi object pointer
  689. * \param[in] mode spi working mode (master or slave)
  690. * \param[in] param parameter, for master, param is the freq, for slave, param is dfs
  691. * \retval E_OK Open successfully without any issues
  692. * \retval E_OPNED If device was opened before with different parameters,
  693. * then just increase the \ref dev_spi_info::opn_cnt "opn_cnt" and return \ref E_OPNED
  694. * \retval E_OBJ Device object is not valid
  695. * \retval E_SYS Device is opened for different mode before, if you want to open it with different mode, you need to fully close it first.
  696. * \retval E_PAR Parameter is not valid
  697. * \retval E_NOSPT Open settings are not supported
  698. */
  699. int32_t dw_spi_open (DEV_SPI *spi_obj, uint32_t mode, uint32_t param)
  700. {
  701. int32_t ercd = E_OK;
  702. uint32_t param2check;
  703. uint32_t clk_mode, dfs_val;
  704. uint32_t support_modes;
  705. DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info);
  706. /* START ERROR CHECK */
  707. VALID_CHK_SPI_INFO_OBJECT(spi_info_ptr);
  708. DW_SPI_CHECK_EXP((mode==DEV_MASTER_MODE)||(mode==DEV_SLAVE_MODE), E_PAR);
  709. if (mode == DEV_SLAVE_MODE) { /* clock mode should be in the enum structure */
  710. DW_SPI_CHECK_EXP((param>=SPI_CPOL_0_CPHA_0) && (param<=SPI_CPOL_1_CPHA_1), E_PAR);
  711. } else { /* frequence should > 0 */
  712. DW_SPI_CHECK_EXP(param>0, E_PAR);
  713. }
  714. /* END OF ERROR CHECK */
  715. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL_PTR)(spi_info_ptr->spi_ctrl);
  716. /* Check supported modes, master or slave */
  717. support_modes = spi_ctrl_ptr->support_modes;
  718. DW_SPI_CHECK_EXP( (((support_modes)&DW_SPI_MASTER_SUPPORTED)&&(mode == DEV_MASTER_MODE)) || \
  719. (((support_modes)&DW_SPI_SLAVE_SUPPORTED)&&(mode == DEV_SLAVE_MODE)), E_NOSPT);
  720. /** Check opened before use case */
  721. if (spi_info_ptr->opn_cnt > 0) {
  722. if (mode != spi_info_ptr->mode) {
  723. /* current working mode is different from passing mode */
  724. return E_SYS;
  725. }
  726. if (mode == DEV_MASTER_MODE) { /* param is freq when as master */
  727. param2check = spi_info_ptr->freq;
  728. } else { /* param is clk_mode when as slave */
  729. param2check = spi_info_ptr->clk_mode;
  730. }
  731. spi_info_ptr->opn_cnt ++;
  732. if (param != param2check) { /* open with different speed mode */
  733. return E_OPNED;
  734. } else {
  735. return E_OK;
  736. }
  737. }
  738. /* auto increase open count */
  739. spi_info_ptr->opn_cnt ++;
  740. /* Do FIFO Length get before init */
  741. #if DW_SPI_CALC_FIFO_LEN_ENABLE
  742. spi_ctrl_ptr->tx_fifo_len = dw_spi_get_txfifo_len(spi_ctrl_ptr->dw_spi_regs);
  743. spi_ctrl_ptr->rx_fifo_len = dw_spi_get_rxfifo_len(spi_ctrl_ptr->dw_spi_regs);
  744. #endif
  745. /* hardware init */
  746. spi_info_ptr->mode = mode;
  747. clk_mode = SPI_CLK_MODE_DEFAULT;
  748. dfs_val = SPI_DFS_DEFAULT;
  749. if (mode == DEV_SLAVE_MODE) {
  750. clk_mode = param;
  751. }
  752. spi_info_ptr->dfs = dfs_val;
  753. spi_info_ptr->clk_mode = clk_mode;
  754. dw_spi_hw_init(spi_ctrl_ptr, clk_mode, dfs_val);
  755. if (mode == DEV_MASTER_MODE) { /* Deselect all slaves, and set frequence */
  756. dw_spi_deselect_slave(spi_ctrl_ptr->dw_spi_regs, 0);
  757. dw_spi_set_freq(spi_ctrl_ptr, param);
  758. spi_info_ptr->freq = param;
  759. }
  760. spi_info_ptr->status = DEV_ENABLED;
  761. spi_info_ptr->extra = NULL;
  762. spi_info_ptr->slave = SPI_SLAVE_NOT_SELECTED;
  763. spi_info_ptr->dummy = 0xff;
  764. spi_ctrl_ptr->int_status = 0;
  765. dw_spi_init_transfer(spi_ctrl_ptr, NULL, dfs_val);
  766. /** install spi interrupt into system */
  767. dw_spi_disable_interrupt(spi_info_ptr);
  768. int_handler_install(spi_ctrl_ptr->intno, spi_ctrl_ptr->dw_spi_int_handler);
  769. memset(&(spi_info_ptr->xfer), 0, sizeof(DEV_SPI_TRANSFER));
  770. memset(&(spi_info_ptr->spi_cbs), 0, sizeof(DEV_SPI_CBS));
  771. error_exit:
  772. return ercd;
  773. }
  774. /**
  775. * \brief close a DesignWare SPI device
  776. * \param[in] spi_obj spi object pointer
  777. * \retval E_OK Close successfully without any issues(including scenario that device is already closed)
  778. * \retval E_OPNED Device is still opened, the device \ref dev_spi_info::opn_cnt "opn_cnt" decreased by 1
  779. * \retval E_OBJ Device object is not valid
  780. */
  781. int32_t dw_spi_close (DEV_SPI *spi_obj)
  782. {
  783. int32_t ercd = E_OK;
  784. DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info);
  785. /* START ERROR CHECK */
  786. VALID_CHK_SPI_INFO_OBJECT(spi_info_ptr);
  787. DW_SPI_CHECK_EXP(spi_info_ptr->opn_cnt > 0, E_OK);
  788. /* END OF ERROR CHECK */
  789. spi_info_ptr->opn_cnt --;
  790. if (spi_info_ptr->opn_cnt == 0) {
  791. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl);
  792. dw_spi_disable_interrupt(spi_info_ptr);
  793. dw_spi_abort_tx(spi_obj);
  794. dw_spi_abort_rx(spi_obj);
  795. memset(&(spi_info_ptr->xfer), 0, sizeof(DEV_SPI_TRANSFER));
  796. memset(&(spi_info_ptr->spi_cbs), 0, sizeof(DEV_SPI_CBS));
  797. memset(&(spi_ctrl_ptr->dw_xfer), 0, sizeof(DW_SPI_TRANSFER));
  798. dw_spi_disable_device(spi_info_ptr);
  799. spi_info_ptr->status = DEV_DISABLED;
  800. spi_info_ptr->extra = NULL;
  801. } else {
  802. ercd = E_OPNED;
  803. }
  804. error_exit:
  805. return ercd;
  806. }
  807. /**
  808. * \brief control spi by ctrl command
  809. * \param[in] spi_obj spi object pointer
  810. * \param[in] ctrl_cmd control command code to do specific spi work
  811. * \param[in,out] param parameters used to control spi or return something
  812. * \retval E_OK Control device successfully
  813. * \retval E_CLSED Device is not opened
  814. * \retval E_OBJ Device object is not valid or not exists
  815. * \retval E_PAR Parameter is not valid for current control command
  816. * \retval E_SYS Control device failed, due to hardware issues, such as device is disabled
  817. * \retval E_CTX Control device failed, due to different reasons like in transfer state
  818. * \retval E_NOSPT Control command is not supported or not valid
  819. */
  820. int32_t dw_spi_control (DEV_SPI *spi_obj, uint32_t ctrl_cmd, void *param)
  821. {
  822. int32_t ercd = E_OK;
  823. DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info);
  824. /* START ERROR CHECK */
  825. VALID_CHK_SPI_INFO_OBJECT(spi_info_ptr);
  826. DW_SPI_CHECK_EXP(spi_info_ptr->opn_cnt > 0, E_CLSED);
  827. /* END OF ERROR CHECK */
  828. uint32_t val32; /** to receive unsigned int value */
  829. DEV_BUFFER *devbuf;
  830. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl);
  831. DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs);
  832. DEV_SPI_TRANSFER *spi_xfer = &(spi_info_ptr->xfer);
  833. /* check whether current device is disabled */
  834. if ((spi_info_ptr->status & DEV_ENABLED) == 0) {
  835. /** When device is disabled,
  836. * only SPI_CMD_ENA_DEV, SPI_CMD_DIS_DEV, SPI_CMD_GET_STATUS, SPI_CMD_RESET
  837. * are available, other commands will return E_SYS
  838. */
  839. if ((ctrl_cmd != SPI_CMD_ENA_DEV) && \
  840. (ctrl_cmd != SPI_CMD_DIS_DEV) && \
  841. (ctrl_cmd != SPI_CMD_GET_STATUS) && \
  842. (ctrl_cmd != SPI_CMD_RESET) ) {
  843. return E_SYS;
  844. }
  845. }
  846. switch (ctrl_cmd) {
  847. /* Commmon commands for both master and slave mode */
  848. case SPI_CMD_GET_STATUS:
  849. DW_SPI_CHECK_EXP((param!=NULL) && CHECK_ALIGN_4BYTES(param), E_PAR);
  850. *((int32_t *)param) = spi_info_ptr->status;
  851. break;
  852. case SPI_CMD_SET_CLK_MODE:
  853. DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX);
  854. val32 = (uint32_t)param;
  855. DW_SPI_CHECK_EXP((val32>=SPI_CPOL_0_CPHA_0) && (val32<=SPI_CPOL_1_CPHA_1), E_PAR);
  856. if (dw_spi_set_clockmode(spi_reg_ptr, val32) == 0) {
  857. spi_info_ptr->clk_mode = val32;
  858. } else {
  859. ercd = E_SYS;
  860. }
  861. break;
  862. case SPI_CMD_ENA_DEV:
  863. dw_spi_enable_device(spi_info_ptr);
  864. break;
  865. case SPI_CMD_DIS_DEV:
  866. dw_spi_disable_device(spi_info_ptr);
  867. break;
  868. case SPI_CMD_RESET:
  869. dw_spi_reset_device(spi_info_ptr);
  870. break;
  871. case SPI_CMD_FLUSH_TX:
  872. DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX);
  873. dw_spi_flush_tx(spi_reg_ptr);
  874. break;
  875. case SPI_CMD_FLUSH_RX:
  876. DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX);
  877. dw_spi_flush_rx(spi_reg_ptr);
  878. break;
  879. case SPI_CMD_SET_DFS:
  880. DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX);
  881. val32 = (uint32_t)param;
  882. DW_SPI_CHECK_EXP(val32>0, E_PAR);
  883. if (dw_spi_set_dfs(spi_reg_ptr, val32) == 0) {
  884. spi_info_ptr->dfs = val32;
  885. } else {
  886. ercd = E_SYS;
  887. }
  888. break;
  889. case SPI_CMD_SET_DUMMY_DATA:
  890. val32 = (uint32_t)param;
  891. spi_info_ptr->dummy = val32;
  892. break;
  893. case SPI_CMD_GET_RXAVAIL: /* Notice in bytes unit */
  894. DW_SPI_CHECK_EXP((param!=NULL) && CHECK_ALIGN_4BYTES(param), E_PAR);
  895. *((int32_t *)param) = dw_spi_get_rxavail(spi_ctrl_ptr) * dw_spi_nbytes(spi_info_ptr->dfs);
  896. break;
  897. case SPI_CMD_GET_TXAVAIL: /* Notice in bytes unit */
  898. DW_SPI_CHECK_EXP((param!=NULL) && CHECK_ALIGN_4BYTES(param), E_PAR);
  899. *((int32_t *)param) = dw_spi_get_txavail(spi_ctrl_ptr) * dw_spi_nbytes(spi_info_ptr->dfs);
  900. break;
  901. case SPI_CMD_SET_TXCB:
  902. DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR);
  903. spi_info_ptr->spi_cbs.tx_cb = param;
  904. break;
  905. case SPI_CMD_SET_RXCB:
  906. DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR);
  907. spi_info_ptr->spi_cbs.rx_cb = param;
  908. break;
  909. case SPI_CMD_SET_XFERCB:
  910. DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR);
  911. spi_info_ptr->spi_cbs.xfer_cb = param;
  912. break;
  913. case SPI_CMD_SET_ERRCB:
  914. DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR);
  915. spi_info_ptr->spi_cbs.err_cb = param;
  916. break;
  917. case SPI_CMD_ABORT_TX:
  918. ercd = dw_spi_abort_tx(spi_obj);
  919. break;
  920. case SPI_CMD_ABORT_RX:
  921. ercd = dw_spi_abort_rx(spi_obj);
  922. break;
  923. case SPI_CMD_ABORT_XFER:
  924. ercd = dw_spi_abort_xfer(spi_obj);
  925. break;
  926. case SPI_CMD_SET_TXINT:
  927. val32 = (uint32_t)param;
  928. if (val32 == 0) {
  929. ercd = dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_SND);
  930. } else {
  931. ercd = dw_spi_ena_cbr(spi_info_ptr, DW_SPI_RDY_SND);
  932. }
  933. break;
  934. case SPI_CMD_SET_RXINT:
  935. val32 = (uint32_t)param;
  936. if (val32 == 0) {
  937. ercd = dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_RCV);
  938. } else {
  939. ercd = dw_spi_ena_cbr(spi_info_ptr, DW_SPI_RDY_RCV);
  940. }
  941. break;
  942. case SPI_CMD_SET_TXINT_BUF:
  943. DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR);
  944. DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX);
  945. if (param != NULL) {
  946. devbuf = (DEV_BUFFER *)param;
  947. DEV_SPI_XFER_SET_TXBUF(spi_xfer, devbuf->buf, 0, devbuf->len);
  948. DEV_SPI_XFER_SET_RXBUF(spi_xfer, NULL, devbuf->len, 0);
  949. DEV_SPI_XFER_SET_NEXT(spi_xfer, NULL);
  950. DW_SPI_CHECK_EXP(dw_spi_chk_xfer_aligned(spi_xfer, spi_info_ptr->dfs) == 0, E_PAR);
  951. dw_spi_init_transfer(spi_ctrl_ptr, spi_xfer, spi_info_ptr->dfs);
  952. } else {
  953. DEV_SPI_XFER_SET_TXBUF(spi_xfer, NULL, 0, 0);
  954. DEV_SPI_XFER_SET_RXBUF(spi_xfer, NULL, 0, 0);
  955. DEV_SPI_XFER_SET_NEXT(spi_xfer, NULL);
  956. dw_spi_init_transfer(spi_ctrl_ptr, NULL, spi_info_ptr->dfs);
  957. }
  958. break;
  959. case SPI_CMD_SET_RXINT_BUF:
  960. DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR);
  961. DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX);
  962. if (param != NULL) {
  963. devbuf = (DEV_BUFFER *)param;
  964. DEV_SPI_XFER_SET_TXBUF(spi_xfer, NULL, devbuf->len, 0);
  965. DEV_SPI_XFER_SET_RXBUF(spi_xfer, devbuf->buf, 0, devbuf->len);
  966. DEV_SPI_XFER_SET_NEXT(spi_xfer, NULL);
  967. /* Check transfer align */
  968. DW_SPI_CHECK_EXP(dw_spi_chk_xfer_aligned(spi_xfer, spi_info_ptr->dfs) == 0, E_PAR);
  969. dw_spi_init_transfer(spi_ctrl_ptr, spi_xfer, spi_info_ptr->dfs);
  970. } else {
  971. DEV_SPI_XFER_SET_TXBUF(spi_xfer, NULL, 0, 0);
  972. DEV_SPI_XFER_SET_RXBUF(spi_xfer, NULL, 0, 0);
  973. DEV_SPI_XFER_SET_NEXT(spi_xfer, NULL);
  974. dw_spi_init_transfer(spi_ctrl_ptr, NULL, spi_info_ptr->dfs);
  975. }
  976. break;
  977. case SPI_CMD_TRANSFER_POLLING:
  978. DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR);
  979. DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX);
  980. if (param != NULL) {
  981. /* Check transfer align */
  982. DW_SPI_CHECK_EXP(dw_spi_chk_xfer_aligned((DEV_SPI_TRANSFER *)param, spi_info_ptr->dfs) == 0, E_PAR);
  983. *spi_xfer = *((DEV_SPI_TRANSFER *)param);
  984. dw_spi_init_transfer(spi_ctrl_ptr, spi_xfer, spi_info_ptr->dfs);
  985. /* Transfer data by poll */
  986. dw_spi_poll_transfer(spi_info_ptr);
  987. } else {
  988. ercd = E_PAR;
  989. }
  990. break;
  991. case SPI_CMD_TRANSFER_INT:
  992. DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR);
  993. if (param != NULL) {
  994. DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX);
  995. /* Check transfer align */
  996. DW_SPI_CHECK_EXP(dw_spi_chk_xfer_aligned((DEV_SPI_TRANSFER *)param, spi_info_ptr->dfs) == 0, E_PAR);
  997. *spi_xfer = *((DEV_SPI_TRANSFER *)param);
  998. dw_spi_init_transfer(spi_ctrl_ptr, spi_xfer, spi_info_ptr->dfs);
  999. /* Transfer data by interrupt */
  1000. ercd = dw_spi_ena_cbr(spi_info_ptr, DW_SPI_RDY_XFER);
  1001. } else {
  1002. ercd = dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_XFER);
  1003. }
  1004. break;
  1005. /* Master mode only commands */
  1006. case SPI_CMD_MST_SET_FREQ:
  1007. DW_SPI_CHECK_EXP(spi_info_ptr->mode == DEV_MASTER_MODE, E_NOSPT);
  1008. DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX);
  1009. val32 = (uint32_t)param;
  1010. DW_SPI_CHECK_EXP(val32>0, E_PAR);
  1011. dw_spi_set_freq(spi_ctrl_ptr, val32);
  1012. spi_info_ptr->freq = val32;
  1013. break;
  1014. case SPI_CMD_MST_SEL_DEV:
  1015. DW_SPI_CHECK_EXP(spi_info_ptr->mode == DEV_MASTER_MODE, E_NOSPT);
  1016. DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX);
  1017. val32 = (uint32_t)param;
  1018. if (dw_spi_select_slave(spi_reg_ptr, val32) == 0) {
  1019. spi_info_ptr->slave = val32;
  1020. } else {
  1021. ercd = E_SYS;
  1022. }
  1023. break;
  1024. case SPI_CMD_MST_DSEL_DEV:
  1025. DW_SPI_CHECK_EXP(spi_info_ptr->mode == DEV_MASTER_MODE, E_NOSPT);
  1026. DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX);
  1027. val32 = (uint32_t)param;
  1028. if (dw_spi_deselect_slave(spi_reg_ptr, val32) == 0) {
  1029. spi_info_ptr->slave = SPI_SLAVE_NOT_SELECTED;
  1030. } else {
  1031. ercd = E_SYS;
  1032. }
  1033. break;
  1034. /* Slave mode only commands */
  1035. default:
  1036. ercd = E_NOSPT;
  1037. break;
  1038. }
  1039. error_exit:
  1040. return ercd;
  1041. }
  1042. /**
  1043. * \brief send data through DesignWare SPI
  1044. * \param[in] spi_obj spi object pointer
  1045. * \param[in] data pointer to data need to send by spi
  1046. * \param[in] len length of data to be sent
  1047. * \retval >0 Byte count that was successfully sent for poll method
  1048. * \retval E_OBJ Device object is not valid or not exists
  1049. * \retval E_PAR Parameter is not valid
  1050. * \retval E_CTX Device is still in transfer state
  1051. * \retval E_SYS Can't write data to hardware due to hardware issues, such as device is disabled
  1052. */
  1053. int32_t dw_spi_write (DEV_SPI *spi_obj, const void *data, uint32_t len)
  1054. {
  1055. int32_t ercd = E_OK;
  1056. DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info);
  1057. /* START ERROR CHECK */
  1058. VALID_CHK_SPI_INFO_OBJECT(spi_info_ptr);
  1059. DW_SPI_CHECK_EXP(spi_info_ptr->opn_cnt > 0, E_CLSED);
  1060. DW_SPI_CHECK_EXP(spi_info_ptr->status & DEV_ENABLED, E_SYS);
  1061. DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX);
  1062. DW_SPI_CHECK_EXP(data!=NULL, E_PAR);
  1063. DW_SPI_CHECK_EXP(len>0, E_PAR);
  1064. /* END OF ERROR CHECK */
  1065. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL_PTR)(spi_info_ptr->spi_ctrl);
  1066. DEV_SPI_TRANSFER spi_xfer;
  1067. /* Master and Slave transmit */
  1068. DEV_SPI_XFER_SET_TXBUF(&spi_xfer, data, 0, len);
  1069. DEV_SPI_XFER_SET_RXBUF(&spi_xfer, NULL, len, 0);
  1070. DEV_SPI_XFER_SET_NEXT(&spi_xfer, NULL);
  1071. /* Check transfer align */
  1072. DW_SPI_CHECK_EXP(dw_spi_chk_xfer_aligned(&spi_xfer, spi_info_ptr->dfs) == 0, E_PAR);
  1073. dw_spi_init_transfer(spi_ctrl_ptr, &spi_xfer, spi_info_ptr->dfs);
  1074. ercd = dw_spi_poll_transfer(spi_info_ptr);
  1075. error_exit:
  1076. return ercd;
  1077. }
  1078. /**
  1079. * \brief read data through DesignWare SPI
  1080. * \param[in] spi_info_ptr spi information structure pointer
  1081. * \param[out] data data that need to read (data must be char type)
  1082. * \param[in] len data count need to read
  1083. * \retval >=0 data have been read
  1084. * \retval E_PAR arguments passed was wrong
  1085. * \retval E_OBJ spi has something error, nothing can be done
  1086. * \retval E_CLSED spi was closed, not available for control
  1087. * \retval <0 other error code not defined here
  1088. */
  1089. int32_t dw_spi_read (DEV_SPI *spi_obj, void *data, uint32_t len)
  1090. {
  1091. int32_t ercd = E_OK;
  1092. DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info);
  1093. /* START ERROR CHECK */
  1094. VALID_CHK_SPI_INFO_OBJECT(spi_info_ptr);
  1095. DW_SPI_CHECK_EXP(spi_info_ptr->opn_cnt > 0, E_CLSED);
  1096. DW_SPI_CHECK_EXP(spi_info_ptr->status & DEV_ENABLED, E_SYS);
  1097. DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX);
  1098. DW_SPI_CHECK_EXP(data!=NULL, E_PAR);
  1099. DW_SPI_CHECK_EXP(len>0, E_PAR);
  1100. /* END OF ERROR CHECK */
  1101. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL_PTR)(spi_info_ptr->spi_ctrl);
  1102. DEV_SPI_TRANSFER spi_xfer;
  1103. /* Master and Slave transmit */
  1104. DEV_SPI_XFER_SET_TXBUF(&spi_xfer, NULL, len, 0);
  1105. DEV_SPI_XFER_SET_RXBUF(&spi_xfer, data, 0, len);
  1106. DEV_SPI_XFER_SET_NEXT(&spi_xfer, NULL);
  1107. /* Check transfer align */
  1108. DW_SPI_CHECK_EXP(dw_spi_chk_xfer_aligned(&spi_xfer, spi_info_ptr->dfs) == 0, E_PAR);
  1109. dw_spi_init_transfer(spi_ctrl_ptr, &spi_xfer, spi_info_ptr->dfs);
  1110. ercd = dw_spi_poll_transfer(spi_info_ptr);
  1111. error_exit:
  1112. return ercd;
  1113. }
  1114. /**
  1115. * \brief DesignWare SPI interrupt processing routine
  1116. * \param[in] spi_info_ptr DEV_SPI_INFO *spi_info_ptr
  1117. * \param[in] ptr extra information
  1118. */
  1119. void dw_spi_isr(DEV_SPI *spi_obj, void *ptr)
  1120. {
  1121. int32_t ercd = E_OK;
  1122. DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info);
  1123. /* START ERROR CHECK */
  1124. VALID_CHK_SPI_INFO_OBJECT(spi_info_ptr);
  1125. /* END OF ERROR CHECK */
  1126. DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL_PTR)(spi_info_ptr->spi_ctrl);
  1127. DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs);
  1128. uint32_t isr_status;
  1129. isr_status = spi_reg_ptr->ISR;
  1130. if (!isr_status) return;
  1131. if (spi_ctrl_ptr->dw_xfer.xfer_len == 0) {
  1132. dw_spi_disable_interrupt(spi_info_ptr);
  1133. } else {
  1134. if (isr_status & (DW_SPI_IMR_TXOIM|DW_SPI_IMR_RXOIM|DW_SPI_IMR_RXUIM)) {
  1135. dw_spi_clear_interrupt_all(spi_reg_ptr);
  1136. dw_spi_disable_interrupt(spi_info_ptr);
  1137. if (spi_info_ptr->spi_cbs.err_cb) {
  1138. spi_info_ptr->spi_cbs.err_cb(spi_obj);
  1139. }
  1140. memset(&(spi_ctrl_ptr->dw_xfer), 0, sizeof(DW_SPI_TRANSFER));
  1141. }
  1142. dw_spi_reader(spi_info_ptr);
  1143. if (isr_status & DW_SPI_IMR_TXEIM) {
  1144. dw_spi_writer(spi_info_ptr);
  1145. }
  1146. if (dw_spi_xfer_end(spi_ctrl_ptr)) {
  1147. if ((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_TX) {
  1148. dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_SND);
  1149. if (spi_info_ptr->spi_cbs.tx_cb) {
  1150. spi_info_ptr->spi_cbs.tx_cb(spi_obj);
  1151. }
  1152. } else if ((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_RX) {
  1153. dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_RCV);
  1154. if (spi_info_ptr->spi_cbs.rx_cb) {
  1155. spi_info_ptr->spi_cbs.rx_cb(spi_obj);
  1156. }
  1157. } else if ((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_XFER) {
  1158. dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_XFER);
  1159. if (spi_info_ptr->spi_cbs.xfer_cb) {
  1160. spi_info_ptr->spi_cbs.xfer_cb(spi_obj);
  1161. }
  1162. } else {
  1163. dw_spi_disable_interrupt(spi_info_ptr);
  1164. }
  1165. memset(&(spi_ctrl_ptr->dw_xfer), 0, sizeof(DW_SPI_TRANSFER));
  1166. }
  1167. }
  1168. error_exit:
  1169. return;
  1170. }
  1171. /** @} */ /* DEVICE_DW_SPI_IMPLEMENT */
  1172. /** @} */ /* DEVICE_DW_SPI */