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