1 /*
2  * @brief LPC15xx SPI driver
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2014
6  * All rights reserved.
7  *
8  * @par
9  * Software that is described herein is for illustrative purposes only
10  * which provides customers with programming information regarding the
11  * LPC products.  This software is supplied "AS IS" without any warranties of
12  * any kind, and NXP Semiconductors and its licensor disclaim any and
13  * all warranties, express or implied, including all implied warranties of
14  * merchantability, fitness for a particular purpose and non-infringement of
15  * intellectual property rights.  NXP Semiconductors assumes no responsibility
16  * or liability for the use of the software, conveys no license or rights under any
17  * patent, copyright, mask work right, or any other intellectual property rights in
18  * or to any products. NXP Semiconductors reserves the right to make changes
19  * in the software without notification. NXP Semiconductors also makes no
20  * representation or warranty that such application will be suitable for the
21  * specified use without further testing or modification.
22  *
23  * @par
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation is hereby granted, under NXP Semiconductors' and its
26  * licensor's relevant copyrights in the software, without fee, provided that it
27  * is used in conjunction with NXP Semiconductors microcontrollers.  This
28  * copyright, permission, and disclaimer notice must appear in all copies of
29  * this code.
30  */
31 
32 #include "chip.h"
33 
34 /*****************************************************************************
35  * Private types/enumerations/variables
36  ****************************************************************************/
37 
38 /*****************************************************************************
39  * Public types/enumerations/variables
40  ****************************************************************************/
41 
42 /*****************************************************************************
43  * Private functions
44  ****************************************************************************/
45 
SPI_Send_Data_RxIgnore(LPC_SPI_T * pSPI,SPI_DATA_SETUP_T * pXfSetup)46 STATIC void SPI_Send_Data_RxIgnore(LPC_SPI_T *pSPI,
47 								   SPI_DATA_SETUP_T *pXfSetup)
48 {
49 	if (pXfSetup->TxCnt == (pXfSetup->Length - 1)) {
50 		Chip_SPI_SendLastFrame_RxIgnore(pSPI, pXfSetup->pTx[pXfSetup->TxCnt], pXfSetup->DataSize, pXfSetup->ssel);
51 	}
52 	else {
53 		Chip_SPI_SendMidFrame(pSPI, pXfSetup->pTx[pXfSetup->TxCnt]);
54 	}
55 
56 	pXfSetup->TxCnt++;
57 }
58 
SPI_Send_Data(LPC_SPI_T * pSPI,SPI_DATA_SETUP_T * pXfSetup)59 STATIC void SPI_Send_Data(LPC_SPI_T *pSPI,
60 						  SPI_DATA_SETUP_T *pXfSetup)
61 {
62 	if (pXfSetup->TxCnt == (pXfSetup->Length - 1)) {
63 		Chip_SPI_SendLastFrame(pSPI, pXfSetup->pTx[pXfSetup->TxCnt], pXfSetup->DataSize, pXfSetup->ssel);
64 	}
65 	else {
66 		Chip_SPI_SendMidFrame(pSPI, pXfSetup->pTx[pXfSetup->TxCnt]);
67 	}
68 
69 	pXfSetup->TxCnt++;
70 }
71 
SPI_Send_Dummy(LPC_SPI_T * pSPI,SPI_DATA_SETUP_T * pXfSetup)72 STATIC void SPI_Send_Dummy(LPC_SPI_T *pSPI,
73 						   SPI_DATA_SETUP_T *pXfSetup)
74 {
75 	if (pXfSetup->RxCnt == (pXfSetup->Length - 1)) {
76 		Chip_SPI_SendLastFrame(pSPI, 0x55, pXfSetup->DataSize, pXfSetup->ssel);
77 	}
78 	else {
79 		Chip_SPI_SendMidFrame(pSPI, 0x55);
80 	}
81 }
82 
SPI_Receive_Data(LPC_SPI_T * pSPI,SPI_DATA_SETUP_T * pXfSetup)83 STATIC void SPI_Receive_Data(LPC_SPI_T *pSPI,
84 							 SPI_DATA_SETUP_T *pXfSetup)
85 {
86 	pXfSetup->pRx[pXfSetup->RxCnt] = Chip_SPI_ReceiveFrame(pSPI);
87 	pXfSetup->RxCnt++;
88 }
89 
90 /*****************************************************************************
91  * Public functions
92  ****************************************************************************/
93 
94 /* Calculate the Clock Rate Divider for SPI Peripheral */
Chip_SPI_CalClkRateDivider(LPC_SPI_T * pSPI,uint32_t bitRate)95 uint32_t Chip_SPI_CalClkRateDivider(LPC_SPI_T *pSPI, uint32_t bitRate)
96 {
97 	uint32_t SPIClk;
98 	uint32_t DivVal;
99 
100 	/* Get SPI clock rate */
101 	SPIClk = Chip_Clock_GetSystemClockRate();	/*The peripheral clock for both SPIs is the system clock*/
102 
103 	DivVal = SPIClk / bitRate;
104 
105 	return DivVal - 1;
106 }
107 
108 /* Set SPI Config register */
Chip_SPI_SetConfig(LPC_SPI_T * pSPI,SPI_CFG_T * pConfig)109 void Chip_SPI_SetConfig(LPC_SPI_T *pSPI, SPI_CFG_T *pConfig)
110 {
111 	uint32_t EnStat = pSPI->CFG & SPI_CFG_SPI_EN;
112 
113 	/* Disable before update CFG register */
114 	if (EnStat) {
115 		Chip_SPI_Disable(pSPI);
116 	}
117 
118 	/* SPI Configure */
119 	pSPI->CFG = ((uint32_t) pConfig->ClockMode) | ((uint32_t) pConfig->DataOrder) | ((uint32_t) pConfig->Mode) |
120 				((uint32_t) pConfig->SSELPol);
121 
122 	/* Rate Divider setting */
123 	pSPI->DIV = SPI_DIV_VAL(pConfig->ClkDiv);
124 
125 	/* Clear status flag*/
126 	Chip_SPI_ClearStatus(
127 		pSPI,
128 		SPI_STAT_CLR_RXOV | SPI_STAT_CLR_TXUR | SPI_STAT_CLR_SSA | SPI_STAT_CLR_SSD |
129 		SPI_STAT_FORCE_EOT);
130 
131 	/* Return the previous state */
132 	if (EnStat) {
133 		Chip_SPI_Enable(pSPI);
134 	}
135 }
136 
Chip_SPI_Init(LPC_SPI_T * pSPI)137 void Chip_SPI_Init(LPC_SPI_T *pSPI)
138 {
139 	if (pSPI == LPC_SPI1) {
140 		Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SPI1);
141 		Chip_SYSCTL_PeriphReset(RESET_SPI1);
142 	}
143 	else {
144 		Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SPI0);
145 		Chip_SYSCTL_PeriphReset(RESET_SPI0);
146 	}
147 }
148 
149 /* De-initializes the SPI peripheral */
Chip_SPI_DeInit(LPC_SPI_T * pSPI)150 void Chip_SPI_DeInit(LPC_SPI_T *pSPI)
151 {
152 	Chip_SPI_Disable(pSPI);
153 
154 	Chip_Clock_DisablePeriphClock((pSPI == LPC_SPI1) ? SYSCTL_CLOCK_SPI1 : SYSCTL_CLOCK_SPI0);
155 }
156 
157 /* Configure SPI Delay parameters */
Chip_SPI_DelayConfig(LPC_SPI_T * pSPI,SPI_DELAY_CONFIG_T * pConfig)158 void Chip_SPI_DelayConfig(LPC_SPI_T *pSPI, SPI_DELAY_CONFIG_T *pConfig)
159 {
160 	pSPI->DLY = SPI_DLY_PRE_DELAY(pConfig->PreDelay);
161 	pSPI->DLY |= SPI_DLY_POST_DELAY(pConfig->PostDelay);
162 	pSPI->DLY |= SPI_DLY_FRAME_DELAY(pConfig->FrameDelay);
163 	if (pConfig->TransferDelay) {
164 		pSPI->DLY |= SPI_DLY_TRANSFER_DELAY(pConfig->TransferDelay - 1);
165 	}
166 }
167 
168 /* Disable/Enable Interrupt */
Chip_SPI_Int_Cmd(LPC_SPI_T * pSPI,uint32_t IntMask,FunctionalState NewState)169 void Chip_SPI_Int_Cmd(LPC_SPI_T *pSPI, uint32_t IntMask, FunctionalState NewState)
170 {
171 	if (NewState ==  ENABLE) {
172 		pSPI->INTENSET |= (IntMask & SPI_INTENSET_BITMASK);
173 	}
174 	else {
175 		pSPI->INTENCLR = (IntMask & SPI_INTENCLR_BITMASK);
176 	}
177 }
178 
179 /*Send and Receive SPI Data  */
Chip_SPI_RWFrames_Blocking(LPC_SPI_T * pSPI,SPI_DATA_SETUP_T * pXfSetup)180 uint32_t Chip_SPI_RWFrames_Blocking(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *pXfSetup)
181 {
182 	uint32_t Status;
183 	/* Clear status */
184 	Chip_SPI_ClearStatus(
185 		pSPI,
186 		SPI_STAT_CLR_RXOV | SPI_STAT_CLR_TXUR | SPI_STAT_CLR_SSA | SPI_STAT_CLR_SSD |
187 		SPI_STAT_FORCE_EOT);
188 	Chip_SPI_SetControlInfo(pSPI, pXfSetup->DataSize, pXfSetup->ssel | SPI_TXCTL_EOF);
189 	pXfSetup->TxCnt = pXfSetup->RxCnt = 0;
190 	while ((pXfSetup->TxCnt < pXfSetup->Length) ||
191 		   (pXfSetup->RxCnt < pXfSetup->Length)) {
192 		Status = Chip_SPI_GetStatus(pSPI);
193 
194 		/* In case of TxReady */
195 		if ((Status & SPI_STAT_TXRDY) && (pXfSetup->TxCnt < pXfSetup->Length)) {
196 			SPI_Send_Data(pSPI, pXfSetup);
197 		}
198 
199 		/*In case of Rx ready */
200 		if ((Status & SPI_STAT_RXRDY) && (pXfSetup->RxCnt < pXfSetup->Length)) {
201 			SPI_Receive_Data(pSPI, pXfSetup);
202 		}
203 	}
204 	/* Check error */
205 	if (Chip_SPI_GetStatus(pSPI) & (SPI_STAT_RXOV | SPI_STAT_TXUR)) {
206 		return 0;
207 	}
208 	return pXfSetup->TxCnt;
209 }
210 
Chip_SPI_WriteFrames_Blocking(LPC_SPI_T * pSPI,SPI_DATA_SETUP_T * pXfSetup)211 uint32_t Chip_SPI_WriteFrames_Blocking(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *pXfSetup)
212 {
213 	/* Clear status */
214 	Chip_SPI_ClearStatus(
215 		pSPI,
216 		SPI_STAT_CLR_RXOV | SPI_STAT_CLR_TXUR | SPI_STAT_CLR_SSA | SPI_STAT_CLR_SSD |
217 		SPI_STAT_FORCE_EOT);
218 	Chip_SPI_SetControlInfo(pSPI, pXfSetup->DataSize, pXfSetup->ssel | SPI_TXCTL_EOF | SPI_TXCTL_RXIGNORE);
219 	pXfSetup->TxCnt = pXfSetup->RxCnt = 0;
220 	while (pXfSetup->TxCnt < pXfSetup->Length) {
221 		/* Wait for TxReady */
222 		while (!(Chip_SPI_GetStatus(pSPI) & SPI_STAT_TXRDY)) {}
223 
224 		SPI_Send_Data_RxIgnore(pSPI, pXfSetup);
225 
226 	}
227 
228 	/* Make sure the last frame sent completely*/
229 	while (!(Chip_SPI_GetStatus(pSPI) & SPI_STAT_SSD)) {}
230 	Chip_SPI_ClearStatus(pSPI, SPI_STAT_CLR_SSD);
231 
232 	/* Check overrun error */
233 	if (Chip_SPI_GetStatus(pSPI) & SPI_STAT_TXUR) {
234 		return 0;
235 	}
236 	return pXfSetup->TxCnt;
237 }
238 
Chip_SPI_ReadFrames_Blocking(LPC_SPI_T * pSPI,SPI_DATA_SETUP_T * pXfSetup)239 uint32_t Chip_SPI_ReadFrames_Blocking(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *pXfSetup)
240 {
241 	/* Clear status */
242 	Chip_SPI_ClearStatus(
243 		pSPI,
244 		SPI_STAT_CLR_RXOV | SPI_STAT_CLR_TXUR | SPI_STAT_CLR_SSA | SPI_STAT_CLR_SSD |
245 		SPI_STAT_FORCE_EOT);
246 	Chip_SPI_SetControlInfo(pSPI, pXfSetup->DataSize, pXfSetup->ssel | SPI_TXCTL_EOF);
247 	pXfSetup->TxCnt = pXfSetup->RxCnt = 0;
248 	while (pXfSetup->RxCnt < pXfSetup->Length) {
249 		/* Wait for TxReady */
250 		while (!(Chip_SPI_GetStatus(pSPI) & SPI_STAT_TXRDY)) {}
251 
252 		SPI_Send_Dummy(pSPI, pXfSetup);
253 
254 		/* Wait for receive data */
255 		while (!(Chip_SPI_GetStatus(pSPI) & SPI_STAT_RXRDY)) {}
256 
257 		SPI_Receive_Data(pSPI, pXfSetup);
258 
259 	}
260 	/* Check overrun error */
261 	if (Chip_SPI_GetStatus(pSPI) & (SPI_STAT_RXOV | SPI_STAT_TXUR)) {
262 		return 0;
263 	}
264 	return pXfSetup->RxCnt;
265 }
266 
267 /* SPI Interrupt Read/Write with 8-bit frame width */
Chip_SPI_Int_RWFrames(LPC_SPI_T * pSPI,SPI_DATA_SETUP_T * pXfSetup)268 Status Chip_SPI_Int_RWFrames(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *pXfSetup)
269 {
270 	uint32_t Status;
271 
272 	Status = Chip_SPI_GetStatus(pSPI);
273 	/* Check  error in STAT register */
274 	if (Status & (SPI_STAT_RXOV | SPI_STAT_TXUR)) {
275 		/* Clear errors */
276 		Chip_SPI_ClearStatus(pSPI, SPI_STAT_CLR_RXOV | SPI_STAT_CLR_TXUR);
277 		return ERROR;
278 	}
279 
280 	if (pXfSetup->TxCnt == 0) {
281 		if (pXfSetup->pRx == NULL) {
282 			Chip_SPI_SetControlInfo(pSPI, pXfSetup->DataSize, pXfSetup->ssel | SPI_TXCTL_EOF | SPI_TXCTL_RXIGNORE);
283 		}
284 		else {
285 			Chip_SPI_SetControlInfo(pSPI, pXfSetup->DataSize, pXfSetup->ssel | SPI_TXCTL_EOF);
286 		}
287 	}
288 
289 	if (pXfSetup->pRx == NULL) {
290 		if ((Status & SPI_STAT_TXRDY) && (pXfSetup->TxCnt < pXfSetup->Length)) {
291 			SPI_Send_Data_RxIgnore(pSPI, pXfSetup);
292 		}
293 	}
294 	else {
295 		/* check if Tx ready */
296 		if ((Status & SPI_STAT_TXRDY) && (pXfSetup->TxCnt < pXfSetup->Length)) {
297 			SPI_Send_Data(pSPI, pXfSetup);
298 		}
299 
300 		/* check if RX FIFO contains data */
301 		if ((Status & SPI_STAT_RXRDY) && (pXfSetup->RxCnt < pXfSetup->Length)) {
302 			SPI_Receive_Data(pSPI, pXfSetup);
303 		}
304 	}
305 
306 	return SUCCESS;
307 }
308