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