]> git.sur5r.net Git - freertos/blob
074b5ea2e0ced8b0a7af9dcc2fbd23ec064e488d
[freertos] /
1 /******************************************************************************
2 *
3 * Copyright (C) 2010 - 2015 Xilinx, Inc.  All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
30 *
31 ******************************************************************************/
32 /*****************************************************************************/
33 /**
34 * @file xiicps_slave.c
35 * @addtogroup iicps_v3_0
36 * @{
37 *
38 * Handles slave transfers
39 *
40 * <pre> MODIFICATION HISTORY:
41 *
42 * Ver   Who Date     Changes
43 * ----- --  -------- ---------------------------------------------
44 * 1.00a jz  01/30/10 First release
45 * 1.04a kpc 08/30/13 Avoid buffer overwrite in SlaveRecvData function
46 * 3.00  sk      01/31/15 Modified the code according to MISRAC 2012 Compliant.
47 *
48 * </pre>
49 *
50 ******************************************************************************/
51
52 /***************************** Include Files *********************************/
53 #include "xiicps.h"
54
55 /************************** Constant Definitions *****************************/
56
57 /**************************** Type Definitions *******************************/
58
59 /***************** Macros (Inline Functions) Definitions *********************/
60
61 /************************** Function Prototypes ******************************/
62 extern s32 TransmitFifoFill(XIicPs *InstancePtr);
63
64 static s32 SlaveRecvData(XIicPs *InstancePtr);
65
66 /************************* Variable Definitions *****************************/
67
68 /*****************************************************************************/
69 /**
70 * This function sets up the device to be a slave.
71 *
72 * @param        InstancePtr is a pointer to the XIicPs instance.
73 * @param        SlaveAddr is the address of the slave we are receiving from.
74 *
75 * @return       None.
76 *
77 * @note
78 *       Interrupt is always enabled no matter the tranfer is interrupt-
79 *       driven or polled mode. Whether device will be interrupted or not
80 *       depends on whether the device is connected to an interrupt
81 *       controller and interrupt for the device is enabled.
82 *
83 ****************************************************************************/
84 void XIicPs_SetupSlave(XIicPs *InstancePtr, u16 SlaveAddr)
85 {
86         u32 ControlReg;
87         u32 BaseAddr;
88
89         Xil_AssertVoid(InstancePtr != NULL);
90         Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
91         Xil_AssertVoid(XIICPS_ADDR_MASK >= SlaveAddr);
92
93         BaseAddr = InstancePtr->Config.BaseAddress;
94
95         ControlReg = XIicPs_In32(BaseAddr + XIICPS_CR_OFFSET);
96
97         /*
98          * Set up master, AckEn, nea and also clear fifo.
99          */
100         ControlReg |= (u32)XIICPS_CR_ACKEN_MASK | (u32)XIICPS_CR_CLR_FIFO_MASK;
101         ControlReg |= (u32)XIICPS_CR_NEA_MASK;
102         ControlReg &= (u32)(~XIICPS_CR_MS_MASK);
103
104         XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
105                           ControlReg);
106
107         XIicPs_DisableAllInterrupts(BaseAddr);
108
109         XIicPs_WriteReg(InstancePtr->Config.BaseAddress,
110                           XIICPS_ADDR_OFFSET, (u32)SlaveAddr);
111
112         return;
113 }
114
115 /*****************************************************************************/
116 /**
117 * This function setup a slave interrupt-driven send. It set the repeated
118 * start for the device is the tranfer size is larger than FIFO depth.
119 * Data processing for the send is initiated by the interrupt handler.
120 *
121 * @param        InstancePtr is a pointer to the XIicPs instance.
122 * @param        MsgPtr is the pointer to the send buffer.
123 * @param        ByteCount is the number of bytes to be sent.
124 *
125 * @return       None.
126 *
127 * @note         This send routine is for interrupt-driven transfer only.
128 *
129 ****************************************************************************/
130 void XIicPs_SlaveSend(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount)
131 {
132         u32 BaseAddr;
133
134         /*
135          * Assert validates the input arguments
136          */
137         Xil_AssertVoid(InstancePtr != NULL);
138         Xil_AssertVoid(MsgPtr != NULL);
139         Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
140
141
142         BaseAddr = InstancePtr->Config.BaseAddress;
143         InstancePtr->SendBufferPtr = MsgPtr;
144         InstancePtr->SendByteCount = ByteCount;
145         InstancePtr->RecvBufferPtr = NULL;
146
147         XIicPs_EnableInterrupts(BaseAddr,
148                         (u32)XIICPS_IXR_DATA_MASK | (u32)XIICPS_IXR_COMP_MASK |
149                         (u32)XIICPS_IXR_TO_MASK | (u32)XIICPS_IXR_NACK_MASK |
150                         (u32)XIICPS_IXR_TX_OVR_MASK);
151 }
152
153 /*****************************************************************************/
154 /**
155 * This function setup a slave interrupt-driven receive.
156 * Data processing for the receive is handled by the interrupt handler.
157 *
158 * @param        InstancePtr is a pointer to the XIicPs instance.
159 * @param        MsgPtr is the pointer to the receive buffer.
160 * @param        ByteCount is the number of bytes to be received.
161 *
162 * @return       None.
163 *
164 * @note         This routine is for interrupt-driven transfer only.
165 *
166 ****************************************************************************/
167 void XIicPs_SlaveRecv(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount)
168 {
169         /*
170          * Assert validates the input arguments.
171          */
172         Xil_AssertVoid(InstancePtr != NULL);
173         Xil_AssertVoid(MsgPtr != NULL);
174         Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
175
176
177         InstancePtr->RecvBufferPtr = MsgPtr;
178         InstancePtr->RecvByteCount = ByteCount;
179         InstancePtr->SendBufferPtr = NULL;
180
181         XIicPs_EnableInterrupts(InstancePtr->Config.BaseAddress,
182                 (u32)XIICPS_IXR_DATA_MASK | (u32)XIICPS_IXR_COMP_MASK |
183                 (u32)XIICPS_IXR_NACK_MASK | (u32)XIICPS_IXR_TO_MASK |
184                 (u32)XIICPS_IXR_RX_OVR_MASK | (u32)XIICPS_IXR_RX_UNF_MASK);
185
186 }
187
188 /*****************************************************************************/
189 /**
190 * This function sends  a buffer in polled mode as a slave.
191 *
192 * @param        InstancePtr is a pointer to the XIicPs instance.
193 * @param        MsgPtr is the pointer to the send buffer.
194 * @param        ByteCount is the number of bytes to be sent.
195 *
196 * @return
197 *               - XST_SUCCESS if everything went well.
198 *               - XST_FAILURE if master sends us data or master terminates the
199 *               transfer before all data has sent out.
200 *
201 * @note         This send routine is for polled mode transfer only.
202 *
203 ****************************************************************************/
204 s32 XIicPs_SlaveSendPolled(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount)
205 {
206         u32 IntrStatusReg;
207         u32 StatusReg;
208         u32 BaseAddr;
209         s32 Tmp;
210         s32 BytesToSend;
211         s32 Error = 0;
212         s32 Status = (s32)XST_SUCCESS;
213         u32 Value;
214
215         /*
216          * Assert validates the input arguments.
217          */
218         Xil_AssertNonvoid(InstancePtr != NULL);
219         Xil_AssertNonvoid(MsgPtr != NULL);
220         Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
221
222         BaseAddr = InstancePtr->Config.BaseAddress;
223         InstancePtr->SendBufferPtr = MsgPtr;
224         InstancePtr->SendByteCount = ByteCount;
225
226         /*
227          * Use RXRW bit in status register to wait master to start a read.
228          */
229         StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
230         while (((StatusReg & XIICPS_SR_RXRW_MASK) == 0U) &&
231                                 ((!Error) != 0)) {
232
233                 /*
234                  * If master tries to send us data, it is an error.
235                  */
236                 if ((StatusReg & XIICPS_SR_RXDV_MASK) != 0x0U) {
237                         Error = 1;
238                 }
239
240                 StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
241         }
242
243         if (Error != 0) {
244                 Status = (s32)XST_FAILURE;
245         } else {
246
247                 /*
248                  * Clear the interrupt status register.
249                  */
250                 IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);
251                 XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg);
252
253                 /*
254                  * Send data as long as there is more data to send and
255                  * there are no errors.
256                  */
257                 Value = (InstancePtr->SendByteCount > (s32)0) &&
258                                                 ((!Error) != 0);
259                 while (Value != (u32)0x00U) {
260
261                         /*
262                          * Find out how many can be sent.
263                          */
264                         BytesToSend = InstancePtr->SendByteCount;
265                         if (BytesToSend > (s32)(XIICPS_FIFO_DEPTH)) {
266                                 BytesToSend = (s32)(XIICPS_FIFO_DEPTH);
267                         }
268
269                         for(Tmp = 0; Tmp < BytesToSend; Tmp ++) {
270                                 XIicPs_SendByte(InstancePtr);
271                         }
272
273                         StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
274
275                         /*
276                          * Wait for master to read the data out of fifo.
277                          */
278                         while (((StatusReg & XIICPS_SR_TXDV_MASK) != (u32)0x00U) &&
279                                                         ((!Error) != 0)) {
280
281                                 /*
282                                  * If master terminates the transfer before all data is
283                                  * sent, it is an error.
284                                  */
285                                 IntrStatusReg = XIicPs_ReadReg(BaseAddr,
286                                 XIICPS_ISR_OFFSET);
287                                 if ((IntrStatusReg & XIICPS_IXR_NACK_MASK) != 0x0U) {
288                                         Error = 1;
289                                 }
290
291                                 /* Clear ISR.
292                                  */
293                                 XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET,
294                                                         IntrStatusReg);
295
296                                 StatusReg = XIicPs_ReadReg(BaseAddr,
297                                                 XIICPS_SR_OFFSET);
298                         }
299                         Value = (InstancePtr->SendByteCount > (s32)0U) &&
300                                                         ((!Error) != 0);
301                 }
302         }
303         if (Error != 0) {
304         Status = (s32)XST_FAILURE;
305         }
306
307         return Status;
308 }
309 /*****************************************************************************/
310 /**
311 * This function receives a buffer in polled mode as a slave.
312 *
313 * @param        InstancePtr is a pointer to the XIicPs instance.
314 * @param        MsgPtr is the pointer to the receive buffer.
315 * @param        ByteCount is the number of bytes to be received.
316 *
317 * @return
318 *               - XST_SUCCESS if everything went well.
319 *               - XST_FAILURE if timed out.
320 *
321 * @note         This receive routine is for polled mode transfer only.
322 *
323 ****************************************************************************/
324 s32 XIicPs_SlaveRecvPolled(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount)
325 {
326         u32 IntrStatusReg;
327         u32 StatusReg;
328         u32 BaseAddr;
329         s32 Count;
330
331         /*
332          * Assert validates the input arguments.
333          */
334         Xil_AssertNonvoid(InstancePtr != NULL);
335         Xil_AssertNonvoid(MsgPtr != NULL);
336         Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
337
338         BaseAddr = InstancePtr->Config.BaseAddress;
339         InstancePtr->RecvBufferPtr = MsgPtr;
340         InstancePtr->RecvByteCount = ByteCount;
341
342         StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
343
344         /*
345          * Clear the interrupt status register.
346          */
347         IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);
348         XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg);
349
350         /*
351          * Clear the status register.
352          */
353         StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
354         XIicPs_WriteReg(BaseAddr, XIICPS_SR_OFFSET, StatusReg);
355
356         StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
357         Count = InstancePtr->RecvByteCount;
358         while (Count > (s32)0) {
359
360                 /* Wait for master to put data */
361                 while ((StatusReg & XIICPS_SR_RXDV_MASK) == 0U) {
362                     StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
363
364                         /*
365                          * If master terminates the transfer before we get all
366                          * the data or the master tries to read from us,
367                          * it is an error.
368                          */
369                         IntrStatusReg = XIicPs_ReadReg(BaseAddr,
370                                                 XIICPS_ISR_OFFSET);
371                         if (((IntrStatusReg & (XIICPS_IXR_DATA_MASK |
372                                         XIICPS_IXR_COMP_MASK))!=0x0U) &&
373                                 ((StatusReg & XIICPS_SR_RXDV_MASK) == 0U) &&
374                                 ((InstancePtr->RecvByteCount > 0) != 0x0U)) {
375
376                                 return (s32)XST_FAILURE;
377                         }
378
379                         /*
380                          * Clear the interrupt status register.
381                          */
382                         XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET,
383                         IntrStatusReg);
384                 }
385
386                 /*
387                  * Read all data from FIFO.
388                  */
389                 while (((StatusReg & XIICPS_SR_RXDV_MASK)!=0x0U) &&
390                          ((InstancePtr->RecvByteCount > 0) != 0x0U)){
391
392                         XIicPs_RecvByte(InstancePtr);
393
394                         StatusReg = XIicPs_ReadReg(BaseAddr,
395                                 XIICPS_SR_OFFSET);
396                 }
397                 Count = InstancePtr->RecvByteCount;
398         }
399
400         return (s32)XST_SUCCESS;
401 }
402
403 /*****************************************************************************/
404 /**
405 * The interrupt handler for slave mode. It does the protocol handling for
406 * the interrupt-driven transfers.
407 *
408 * Completion events and errors are signaled to upper layer for proper
409 * handling.
410 *
411 * <pre>
412 *
413 * The interrupts that are handled are:
414 * - DATA
415 *       If the instance is sending, it means that the master wants to read more
416 *       data from us. Send more data, and check whether we are done with this
417 *       send.
418 *
419 *       If the instance is receiving, it means that the master has writen
420 *       more data to us. Receive more data, and check whether we are done with
421 *       with this receive.
422 *
423 * - COMP
424 *       This marks that stop sequence has been sent from the master, transfer
425 *       is about to terminate. However, for receiving, the master may have
426 *       written us some data, so receive that first.
427 *
428 *       It is an error if the amount of transfered data is less than expected.
429 *
430 * - NAK
431 *       This marks that master does not want our data. It is for send only.
432 *
433 * - Other interrupts
434 *       These interrupts are marked as error.
435 *
436 * </pre>
437 *
438 * @param        InstancePtr is a pointer to the XIicPs instance.
439 *
440 * @return       None.
441 *
442 * @note         None.
443 *
444 ****************************************************************************/
445 void XIicPs_SlaveInterruptHandler(XIicPs *InstancePtr)
446 {
447         u32 IntrStatusReg;
448         u32 IsSend = 0U;
449         u32 StatusEvent = 0U;
450         s32 LeftOver;
451         u32 BaseAddr;
452
453         /*
454          * Assert validates the input arguments.
455          */
456         Xil_AssertVoid(InstancePtr != NULL);
457         Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
458
459         BaseAddr = InstancePtr->Config.BaseAddress;
460
461         /*
462          * Read the Interrupt status register.
463          */
464         IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);
465
466         /*
467          * Write the status back to clear the interrupts so no events are missed
468          * while processing this interrupt.
469          */
470         XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg);
471
472         /*
473          * Use the Mask register AND with the Interrupt Status register so
474          * disabled interrupts are not processed.
475          */
476         IntrStatusReg &= ~(XIicPs_ReadReg(BaseAddr, XIICPS_IMR_OFFSET));
477
478         /*
479          * Determine whether the device is sending.
480          */
481         if (InstancePtr->RecvBufferPtr == NULL) {
482                 IsSend = 1U;
483         }
484
485         /* Data interrupt
486          *
487          * This means master wants to do more data transfers.
488          * Also check for completion of transfer, signal upper layer if done.
489          */
490         if ((u32)0U != (IntrStatusReg & XIICPS_IXR_DATA_MASK)) {
491                 if (IsSend != 0x0U) {
492                         LeftOver = TransmitFifoFill(InstancePtr);
493                                 /*
494                                  * We may finish send here
495                                  */
496                                 if (LeftOver == 0) {
497                                         StatusEvent |=
498                                                 XIICPS_EVENT_COMPLETE_SEND;
499                                 }
500                 } else {
501                         LeftOver = SlaveRecvData(InstancePtr);
502
503                         /* We may finish the receive here */
504                         if (LeftOver == 0) {
505                                 StatusEvent |= XIICPS_EVENT_COMPLETE_RECV;
506                         }
507                 }
508         }
509
510         /*
511          * Complete interrupt.
512          *
513          * In slave mode, it means the master has done with this transfer, so
514          * we signal the application using completion event.
515          */
516         if (0U != (IntrStatusReg & XIICPS_IXR_COMP_MASK)) {
517                 if (IsSend != 0x0U) {
518                         if (InstancePtr->SendByteCount > 0) {
519                                 StatusEvent |= XIICPS_EVENT_ERROR;
520                         }else {
521                                 StatusEvent |= XIICPS_EVENT_COMPLETE_SEND;
522                         }
523                 } else {
524                         LeftOver = SlaveRecvData(InstancePtr);
525                         if (LeftOver > 0) {
526                                 StatusEvent |= XIICPS_EVENT_ERROR;
527                         } else {
528                                 StatusEvent |= XIICPS_EVENT_COMPLETE_RECV;
529                         }
530                 }
531         }
532
533         /*
534          * Nack interrupt, pass this information to application.
535          */
536         if (0U != (IntrStatusReg & XIICPS_IXR_NACK_MASK)) {
537                 StatusEvent |= XIICPS_EVENT_NACK;
538         }
539
540         /*
541          * All other interrupts are treated as error.
542          */
543         if (0U != (IntrStatusReg & (XIICPS_IXR_TO_MASK |
544                                 XIICPS_IXR_RX_UNF_MASK |
545                                 XIICPS_IXR_TX_OVR_MASK |
546                                 XIICPS_IXR_RX_OVR_MASK))){
547
548                 StatusEvent |= XIICPS_EVENT_ERROR;
549         }
550
551         /*
552          * Signal application if there are any events.
553          */
554         if (0U != StatusEvent) {
555                 InstancePtr->StatusHandler(InstancePtr->CallBackRef,
556                                            StatusEvent);
557         }
558 }
559
560 /*****************************************************************************/
561 /*
562 *
563 * This function handles continuation of receiving data. It is invoked
564 * from interrupt handler.
565 *
566 * @param        InstancePtr is a pointer to the XIicPs instance.
567 *
568 * @return       Number of bytes still expected by the instance.
569 *
570 * @note         None.
571 *
572 ****************************************************************************/
573 static s32 SlaveRecvData(XIicPs *InstancePtr)
574 {
575         u32 StatusReg;
576         u32 BaseAddr;
577
578         BaseAddr = InstancePtr->Config.BaseAddress;
579
580         StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
581
582         while (((StatusReg & XIICPS_SR_RXDV_MASK)!=0x0U) &&
583                         ((InstancePtr->RecvByteCount > 0) != 0x0U)) {
584                 XIicPs_RecvByte(InstancePtr);
585                 StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
586         }
587
588         return InstancePtr->RecvByteCount;
589 }
590 /** @} */