/****************************************************************************** * * Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Use of the Software is limited solely to applications: * (a) running on a Xilinx device, or * (b) that interact with a Xilinx device through a bus or interconnect. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Xilinx shall not be used * in advertising or otherwise to promote the sale, use or other dealings in * this Software without prior written authorization from Xilinx. * ******************************************************************************/ /*****************************************************************************/ /** * * @file xiicps_master.c * * Handles master mode transfers. * *
 MODIFICATION HISTORY:
*
* Ver   Who  Date     Changes
* ----- ---  -------- ---------------------------------------------
* 1.00a jz   01/30/10 First release
* 1.00a sdm  09/21/11 Updated the XIicPs_SetupMaster to not check for
*		      Bus Busy condition when the Hold Bit is set.
* 1.01a sg   03/30/12 Fixed an issue in XIicPs_MasterSendPolled where a
*		      check for transfer completion is added, which indicates
*			 the completion of current transfer.
* 2.0   hk   03/07/14 Added check for error status in the while loop that
*                     checks for completion. CR# 762244, 764875.
* 2.1   hk   04/24/14 Fix for CR# 789821 to handle >14 byte transfers.
*                     Fix for CR# 761060 - provision for repeated start.
* 2.2   hk   08/23/14 Slave monitor mode changes - clear FIFO, enable
*                     read mode and clear transfer size register.
*                     Disable NACK to avoid interrupts on each retry.
* 2.3	sk	 10/06/14 Fill transmit fifo before address register when sending.
* 					  Replaced XIICPS_DATA_INTR_DEPTH with XIICPS_FIFO_DEPTH.
* 					  Repeated start feature removed.
*			 12/06/14 Implemented Repeated start feature.
*
* 
* ******************************************************************************/ /***************************** Include Files *********************************/ #include "xiicps.h" /************************** Constant Definitions *****************************/ /**************************** Type Definitions *******************************/ /***************** Macros (Inline Functions) Definitions *********************/ /************************** Function Prototypes ******************************/ s32 TransmitFifoFill(XIicPs *InstancePtr); static s32 XIicPs_SetupMaster(XIicPs *InstancePtr, s32 Role); static void MasterSendData(XIicPs *InstancePtr); /************************* Variable Definitions *****************************/ /*****************************************************************************/ /** * This function initiates an interrupt-driven send in master mode. * * It tries to send the first FIFO-full of data, then lets the interrupt * handler to handle the rest of the data if there is any. * * @param InstancePtr is a pointer to the XIicPs instance. * @param MsgPtr is the pointer to the send buffer. * @param ByteCount is the number of bytes to be sent. * @param SlaveAddr is the address of the slave we are sending to. * * @return None. * * @note This send routine is for interrupt-driven transfer only. * ****************************************************************************/ void XIicPs_MasterSend(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount, u16 SlaveAddr) { u32 BaseAddr; /* * Assert validates the input arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(MsgPtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); Xil_AssertVoid(XIICPS_ADDR_MASK >= SlaveAddr); BaseAddr = InstancePtr->Config.BaseAddress; InstancePtr->SendBufferPtr = MsgPtr; InstancePtr->SendByteCount = ByteCount; InstancePtr->RecvBufferPtr = NULL; InstancePtr->IsSend = 1; /* * Set repeated start if sending more than FIFO of data. */ if (((InstancePtr->IsRepeatedStart) != 0)|| ((ByteCount > XIICPS_FIFO_DEPTH) != 0U)) { XIicPs_WriteReg(BaseAddr, (u32)XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) | (u32)XIICPS_CR_HOLD_MASK); } /* * Setup as a master sending role. */ (void)XIicPs_SetupMaster(InstancePtr, SENDING_ROLE); (void)TransmitFifoFill(InstancePtr); /* * Do the address transfer to notify the slave. */ XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, (u32)SlaveAddr); XIicPs_EnableInterrupts(BaseAddr, (u32)XIICPS_IXR_NACK_MASK | (u32)XIICPS_IXR_COMP_MASK | (u32)XIICPS_IXR_ARB_LOST_MASK); } /*****************************************************************************/ /** * This function initiates an interrupt-driven receive in master mode. * * It sets the transfer size register so the slave can send data to us. * The rest of the work is managed by interrupt handler. * * @param InstancePtr is a pointer to the XIicPs instance. * @param MsgPtr is the pointer to the receive buffer. * @param ByteCount is the number of bytes to be received. * @param SlaveAddr is the address of the slave we are receiving from. * * @return None. * * @note This receive routine is for interrupt-driven transfer only. * ****************************************************************************/ void XIicPs_MasterRecv(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount, u16 SlaveAddr) { u32 BaseAddr; /* * Assert validates the input arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(MsgPtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); Xil_AssertVoid(XIICPS_ADDR_MASK >= SlaveAddr); BaseAddr = InstancePtr->Config.BaseAddress; InstancePtr->RecvBufferPtr = MsgPtr; InstancePtr->RecvByteCount = ByteCount; InstancePtr->CurrByteCount = ByteCount; InstancePtr->SendBufferPtr = NULL; InstancePtr->IsSend = 0; InstancePtr->UpdateTxSize = 0; if ((ByteCount > XIICPS_FIFO_DEPTH) || ((InstancePtr->IsRepeatedStart) !=0)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) | (u32)XIICPS_CR_HOLD_MASK); } /* * Initialize for a master receiving role. */ (void)XIicPs_SetupMaster(InstancePtr, RECVING_ROLE); /* * Do the address transfer to signal the slave. */ XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, (u32)SlaveAddr); /* * Setup the transfer size register so the slave knows how much * to send to us. */ if (ByteCount > XIICPS_MAX_TRANSFER_SIZE) { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, XIICPS_MAX_TRANSFER_SIZE); InstancePtr->CurrByteCount = (s32)XIICPS_MAX_TRANSFER_SIZE; InstancePtr->UpdateTxSize = 1; }else { XIicPs_WriteReg(BaseAddr, (u32)(XIICPS_TRANS_SIZE_OFFSET), (u32)ByteCount); } XIicPs_EnableInterrupts(BaseAddr, (u32)XIICPS_IXR_NACK_MASK | (u32)XIICPS_IXR_DATA_MASK | (u32)XIICPS_IXR_RX_OVR_MASK | (u32)XIICPS_IXR_COMP_MASK | (u32)XIICPS_IXR_ARB_LOST_MASK); } /*****************************************************************************/ /** * This function initiates a polled mode send in master mode. * * It sends data to the FIFO and waits for the slave to pick them up. * If slave fails to remove data from FIFO, the send fails with * time out. * * @param InstancePtr is a pointer to the XIicPs instance. * @param MsgPtr is the pointer to the send buffer. * @param ByteCount is the number of bytes to be sent. * @param SlaveAddr is the address of the slave we are sending to. * * @return * - XST_SUCCESS if everything went well. * - XST_FAILURE if timed out. * * @note This send routine is for polled mode transfer only. * ****************************************************************************/ s32 XIicPs_MasterSendPolled(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount, u16 SlaveAddr) { u32 IntrStatusReg; u32 StatusReg; u32 BaseAddr; u32 Intrs; u32 Value; s32 Status; /* * Assert validates the input arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(MsgPtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(XIICPS_ADDR_MASK >= SlaveAddr); BaseAddr = InstancePtr->Config.BaseAddress; InstancePtr->SendBufferPtr = MsgPtr; InstancePtr->SendByteCount = ByteCount; if (((InstancePtr->IsRepeatedStart) != 0) || ((ByteCount > XIICPS_FIFO_DEPTH) != 0U)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) | (u32)XIICPS_CR_HOLD_MASK); } (void)XIicPs_SetupMaster(InstancePtr, SENDING_ROLE); /* * Intrs keeps all the error-related interrupts. */ Intrs = (u32)XIICPS_IXR_ARB_LOST_MASK | (u32)XIICPS_IXR_TX_OVR_MASK | (u32)XIICPS_IXR_NACK_MASK; /* * Clear the interrupt status register before use it to monitor. */ IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg); /* * Transmit first FIFO full of data. */ (void)TransmitFifoFill(InstancePtr); XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, (u32)SlaveAddr); IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); /* * Continue sending as long as there is more data and * there are no errors. */ Value = ((InstancePtr->SendByteCount > (s32)0) && ((IntrStatusReg & Intrs) == (u32)0U)); while (Value != (u32)0x00U) { StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); /* * Wait until transmit FIFO is empty. */ if ((StatusReg & XIICPS_SR_TXDV_MASK) != 0U) { IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); Value = ((InstancePtr->SendByteCount > (s32)0) && ((IntrStatusReg & Intrs) == (u32)0U)); continue; } /* * Send more data out through transmit FIFO. */ (void)TransmitFifoFill(InstancePtr); Value = ((InstancePtr->SendByteCount > (s32)0) && ((IntrStatusReg & Intrs) == (u32)0U)); } /* * Check for completion of transfer. */ while ((IntrStatusReg & XIICPS_IXR_COMP_MASK) != XIICPS_IXR_COMP_MASK){ IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); /* * If there is an error, tell the caller. */ if ((IntrStatusReg & Intrs) != 0U) { return (s32)XST_FAILURE; } } if ((!(InstancePtr->IsRepeatedStart)) != 0) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr,XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } return (s32)XST_SUCCESS; } /*****************************************************************************/ /** * This function initiates a polled mode receive in master mode. * * It repeatedly sets the transfer size register so the slave can * send data to us. It polls the data register for data to come in. * If slave fails to send us data, it fails with time out. * * @param InstancePtr is a pointer to the XIicPs instance. * @param MsgPtr is the pointer to the receive buffer. * @param ByteCount is the number of bytes to be received. * @param SlaveAddr is the address of the slave we are receiving from. * * @return * - XST_SUCCESS if everything went well. * - XST_FAILURE if timed out. * * @note This receive routine is for polled mode transfer only. * ****************************************************************************/ s32 XIicPs_MasterRecvPolled(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount, u16 SlaveAddr) { u32 IntrStatusReg; u32 Intrs; u32 StatusReg; u32 BaseAddr; s32 BytesToRecv; s32 BytesToRead; s32 TransSize; s32 Tmp = 0; u32 Status_Rcv; u32 Status; s32 Result; s32 IsHold = 0; s32 UpdateTxSize = 0; s32 ByteCountVar = ByteCount; /* * Assert validates the input arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(MsgPtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(XIICPS_ADDR_MASK >= SlaveAddr); BaseAddr = InstancePtr->Config.BaseAddress; InstancePtr->RecvBufferPtr = MsgPtr; InstancePtr->RecvByteCount = ByteCountVar; if((ByteCountVar > XIICPS_FIFO_DEPTH) || ((InstancePtr->IsRepeatedStart) !=0)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) | (u32)XIICPS_CR_HOLD_MASK); IsHold = 1; } (void)XIicPs_SetupMaster(InstancePtr, RECVING_ROLE); /* * Clear the interrupt status register before use it to monitor. */ IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg); XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr); /* * Set up the transfer size register so the slave knows how much * to send to us. */ if (ByteCountVar > XIICPS_MAX_TRANSFER_SIZE) { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, XIICPS_MAX_TRANSFER_SIZE); ByteCountVar = (s32)XIICPS_MAX_TRANSFER_SIZE; UpdateTxSize = 1; }else { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, ByteCountVar); } /* * Intrs keeps all the error-related interrupts. */ Intrs = (u32)XIICPS_IXR_ARB_LOST_MASK | (u32)XIICPS_IXR_RX_OVR_MASK | (u32)XIICPS_IXR_RX_UNF_MASK | (u32)XIICPS_IXR_NACK_MASK; /* * Poll the interrupt status register to find the errors. */ IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); while ((InstancePtr->RecvByteCount > 0) && ((IntrStatusReg & Intrs) == 0U)) { StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); while ((StatusReg & XIICPS_SR_RXDV_MASK) != 0U) { if (((InstancePtr->RecvByteCount < XIICPS_DATA_INTR_DEPTH) != 0U) && (IsHold != 0) && ((!(InstancePtr->IsRepeatedStart)) != 0)) { IsHold = 0; XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } XIicPs_RecvByte(InstancePtr); ByteCountVar --; if ((UpdateTxSize != 0) && ((ByteCountVar == (XIICPS_FIFO_DEPTH + 1)) != 0U)) { break; } StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); } if ((UpdateTxSize != 0) && ((ByteCountVar == (XIICPS_FIFO_DEPTH + 1)) != 0U)) { /* * wait while fifo is full */ while(XIicPs_ReadReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET) != (u32)(ByteCountVar - XIICPS_FIFO_DEPTH)) { ; } if ((InstancePtr->RecvByteCount - XIICPS_FIFO_DEPTH) > XIICPS_MAX_TRANSFER_SIZE) { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, XIICPS_MAX_TRANSFER_SIZE); ByteCountVar = (s32)XIICPS_MAX_TRANSFER_SIZE + XIICPS_FIFO_DEPTH; }else { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, InstancePtr->RecvByteCount - XIICPS_FIFO_DEPTH); UpdateTxSize = 0; ByteCountVar = InstancePtr->RecvByteCount; } } IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); } if ((!(InstancePtr->IsRepeatedStart)) != 0) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr,XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } if ((IntrStatusReg & Intrs) != 0x0U) { Result = (s32)XST_FAILURE; } else { Result = (s32)XST_SUCCESS; } return Result; } /*****************************************************************************/ /** * This function enables the slave monitor mode. * * It enables slave monitor in the control register and enables * slave ready interrupt. It then does an address transfer to slave. * Interrupt handler will signal the caller if slave responds to * the address transfer. * * @param InstancePtr is a pointer to the XIicPs instance. * @param SlaveAddr is the address of the slave we want to contact. * * @return None. * * @note None. * ****************************************************************************/ void XIicPs_EnableSlaveMonitor(XIicPs *InstancePtr, u16 SlaveAddr) { u32 BaseAddr; u32 ConfigReg; Xil_AssertVoid(InstancePtr != NULL); BaseAddr = InstancePtr->Config.BaseAddress; /* Clear transfer size register */ XIicPs_WriteReg(BaseAddr, (u32)XIICPS_TRANS_SIZE_OFFSET, 0x0U); /* * Enable slave monitor mode in control register. */ ConfigReg = XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET); ConfigReg |= (u32)XIICPS_CR_MS_MASK | (u32)XIICPS_CR_NEA_MASK | (u32)XIICPS_CR_CLR_FIFO_MASK | (u32)XIICPS_CR_SLVMON_MASK; ConfigReg &= (u32)(~XIICPS_CR_RD_WR_MASK); XIicPs_WriteReg(BaseAddr, (u32)XIICPS_CR_OFFSET, ConfigReg); /* * Set up interrupt flag for slave monitor interrupt. * Dont enable NACK. */ XIicPs_EnableInterrupts(BaseAddr, (u32)XIICPS_IXR_SLV_RDY_MASK); /* * Initialize the slave monitor register. */ XIicPs_WriteReg(BaseAddr, (u32)XIICPS_SLV_PAUSE_OFFSET, 0xFU); /* * Set the slave address to start the slave address transmission. */ XIicPs_WriteReg(BaseAddr, (u32)XIICPS_ADDR_OFFSET, (u32)SlaveAddr); return; } /*****************************************************************************/ /** * This function disables slave monitor mode. * * @param InstancePtr is a pointer to the XIicPs instance. * * @return None. * * @note None. * ****************************************************************************/ void XIicPs_DisableSlaveMonitor(XIicPs *InstancePtr) { u32 BaseAddr; Xil_AssertVoid(InstancePtr != NULL); BaseAddr = InstancePtr->Config.BaseAddress; /* * Clear slave monitor control bit. */ XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_SLVMON_MASK)); /* * Clear interrupt flag for slave monitor interrupt. */ XIicPs_DisableInterrupts(BaseAddr, XIICPS_IXR_SLV_RDY_MASK); return; } /*****************************************************************************/ /** * The interrupt handler for the master mode. It does the protocol handling for * the interrupt-driven transfers. * * Completion events and errors are signaled to upper layer for proper handling. * *
* The interrupts that are handled are:
* - DATA
*	This case is handled only for master receive data.
*	The master has to request for more data (if there is more data to
*	receive) and read the data from the FIFO .
*
* - COMP
*	If the Master is transmitting data and there is more data to be
*	sent then the data is written to the FIFO. If there is no more data to
*	be transmitted then a completion event is signalled to the upper layer
*	by calling the callback handler.
*
*	If the Master is receiving data then the data is read from the FIFO and
*	the Master has to request for more data (if there is more data to
*	receive). If all the data has been received then a completion event
*	is signalled to the upper layer by calling the callback handler.
*	It is an error if the amount of received data is more than expected.
*
* - NAK and SLAVE_RDY
*	This is signalled to the upper layer by calling the callback handler.
*
* - All Other interrupts
*	These interrupts are marked as error. This is signalled to the upper
*	layer by calling the callback handler.
*
* 
* * @param InstancePtr is a pointer to the XIicPs instance. * * @return None. * * @note None. * ****************************************************************************/ void XIicPs_MasterInterruptHandler(XIicPs *InstancePtr) { u32 IntrStatusReg; u32 StatusEvent = 0U; u32 BaseAddr; s32 ByteCnt; s32 IsHold; /* * Assert validates the input arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); BaseAddr = InstancePtr->Config.BaseAddress; /* * Read the Interrupt status register. */ IntrStatusReg = XIicPs_ReadReg(BaseAddr, (u32)XIICPS_ISR_OFFSET); /* * Write the status back to clear the interrupts so no events are * missed while processing this interrupt. */ XIicPs_WriteReg(BaseAddr, (u32)XIICPS_ISR_OFFSET, IntrStatusReg); /* * Use the Mask register AND with the Interrupt Status register so * disabled interrupts are not processed. */ IntrStatusReg &= ~(XIicPs_ReadReg(BaseAddr, (u32)XIICPS_IMR_OFFSET)); ByteCnt = InstancePtr->CurrByteCount; IsHold = 0; if ((XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) & (u32)XIICPS_CR_HOLD_MASK) != 0U) { IsHold = 1; } /* * Send */ if (((InstancePtr->IsSend) != 0) && ((u32)0U != (IntrStatusReg & (u32)XIICPS_IXR_COMP_MASK))) { if (InstancePtr->SendByteCount > 0) { MasterSendData(InstancePtr); } else { StatusEvent |= XIICPS_EVENT_COMPLETE_SEND; } } /* * Receive */ if (((!(InstancePtr->IsSend))!= 0) && ((0 != (IntrStatusReg & (u32)XIICPS_IXR_DATA_MASK)) || (0 != (IntrStatusReg & (u32)XIICPS_IXR_COMP_MASK)))){ while ((XIicPs_ReadReg(BaseAddr, (u32)XIICPS_SR_OFFSET) & XIICPS_SR_RXDV_MASK) != 0U) { if (((InstancePtr->RecvByteCount < XIICPS_DATA_INTR_DEPTH)!= 0U) && (IsHold != 0) && ((!(InstancePtr->IsRepeatedStart))!= 0)) { IsHold = 0; XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } XIicPs_RecvByte(InstancePtr); ByteCnt--; if ((InstancePtr->UpdateTxSize != 0) && ((ByteCnt == (XIICPS_FIFO_DEPTH + 1))!= 0U)) { break; } } if ((InstancePtr->UpdateTxSize != 0) && ((ByteCnt == (XIICPS_FIFO_DEPTH + 1))!= 0U)) { /* * wait while fifo is full */ while(XIicPs_ReadReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET) != (u32)(ByteCnt - XIICPS_FIFO_DEPTH)) { } if ((InstancePtr->RecvByteCount - XIICPS_FIFO_DEPTH) > XIICPS_MAX_TRANSFER_SIZE) { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, XIICPS_MAX_TRANSFER_SIZE); ByteCnt = (s32)XIICPS_MAX_TRANSFER_SIZE + XIICPS_FIFO_DEPTH; }else { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, InstancePtr->RecvByteCount - XIICPS_FIFO_DEPTH); InstancePtr->UpdateTxSize = 0; ByteCnt = InstancePtr->RecvByteCount; } } InstancePtr->CurrByteCount = ByteCnt; } if (((!(InstancePtr->IsSend)) != 0) && (0U != (IntrStatusReg & XIICPS_IXR_COMP_MASK))) { /* * If all done, tell the application. */ if (InstancePtr->RecvByteCount == 0){ if ((!(InstancePtr->IsRepeatedStart)) != 0) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } StatusEvent |= XIICPS_EVENT_COMPLETE_RECV; } } /* * Slave ready interrupt, it is only meaningful for master mode. */ if (0U != (IntrStatusReg & XIICPS_IXR_SLV_RDY_MASK)) { StatusEvent |= XIICPS_EVENT_SLAVE_RDY; } if (0U != (IntrStatusReg & XIICPS_IXR_NACK_MASK)) { if ((!(InstancePtr->IsRepeatedStart)) != 0 ) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } StatusEvent |= XIICPS_EVENT_NACK; } /* * All other interrupts are treated as error. */ if (0U != (IntrStatusReg & (XIICPS_IXR_NACK_MASK | XIICPS_IXR_ARB_LOST_MASK | XIICPS_IXR_RX_UNF_MASK | XIICPS_IXR_TX_OVR_MASK | XIICPS_IXR_RX_OVR_MASK))) { if ((!(InstancePtr->IsRepeatedStart)) != 0) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } StatusEvent |= XIICPS_EVENT_ERROR; } /* * Signal application if there are any events. */ if (StatusEvent != 0U) { InstancePtr->StatusHandler(InstancePtr->CallBackRef, StatusEvent); } } /*****************************************************************************/ /* * This function prepares a device to transfers as a master. * * @param InstancePtr is a pointer to the XIicPs instance. * * @param Role specifies whether the device is sending or receiving. * * @return * - XST_SUCCESS if everything went well. * - XST_FAILURE if bus is busy. * * @note Interrupts are always disabled, device which needs to use * interrupts needs to setup interrupts after this call. * ****************************************************************************/ static s32 XIicPs_SetupMaster(XIicPs *InstancePtr, s32 Role) { u32 ControlReg; u32 BaseAddr; u32 EnabledIntr = 0x0U; Xil_AssertNonvoid(InstancePtr != NULL); BaseAddr = InstancePtr->Config.BaseAddress; ControlReg = XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET); /* * Only check if bus is busy when repeated start option is not set. */ if ((ControlReg & XIICPS_CR_HOLD_MASK) == 0U) { if (XIicPs_BusIsBusy(InstancePtr) == (s32)1) { return (s32)XST_FAILURE; } } /* * Set up master, AckEn, nea and also clear fifo. */ ControlReg |= (u32)XIICPS_CR_ACKEN_MASK | (u32)XIICPS_CR_CLR_FIFO_MASK | (u32)XIICPS_CR_NEA_MASK | (u32)XIICPS_CR_MS_MASK; if (Role == RECVING_ROLE) { ControlReg |= (u32)XIICPS_CR_RD_WR_MASK; EnabledIntr = (u32)XIICPS_IXR_DATA_MASK |(u32)XIICPS_IXR_RX_OVR_MASK; }else { ControlReg &= (u32)(~XIICPS_CR_RD_WR_MASK); } EnabledIntr |= (u32)XIICPS_IXR_COMP_MASK | (u32)XIICPS_IXR_ARB_LOST_MASK; XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, ControlReg); XIicPs_DisableAllInterrupts(BaseAddr); return (s32)XST_SUCCESS; } /*****************************************************************************/ /* * This function handles continuation of sending data. It is invoked * from interrupt handler. * * @param InstancePtr is a pointer to the XIicPs instance. * * @return None. * * @note None. * ****************************************************************************/ static void MasterSendData(XIicPs *InstancePtr) { (void)TransmitFifoFill(InstancePtr); /* * Clear hold bit if done, so stop can be sent out. */ if (InstancePtr->SendByteCount == 0) { /* * If user has enabled repeated start as an option, * do not disable it. */ if ((!(InstancePtr->IsRepeatedStart)) != 0) { XIicPs_WriteReg(InstancePtr->Config.BaseAddress, (u32)XIICPS_CR_OFFSET, XIicPs_ReadReg(InstancePtr->Config.BaseAddress, (u32)XIICPS_CR_OFFSET) & (u32)(~ XIICPS_CR_HOLD_MASK)); } } return; }