blob: faa852826c7b0e46956e5684026aeda2c9115a7c [file] [log] [blame]
/******************************************************************************
*
* Copyright (C) 2010 - 2016 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
* XILINX 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
* @addtogroup iicps_v3_5
* @{
*
* Handles master mode transfers.
*
* <pre> 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.
* 3.0 sk 12/06/14 Implemented Repeated start feature.
* 01/31/15 Modified the code according to MISRAC 2012 Compliant.
* 02/18/15 Implemented larger data transfer using repeated start
* in Zynq UltraScale MP.
* 3.3 kvn 05/05/16 Modified latest code for MISRA-C:2012 Compliance.
* 3.6 ask 09/03/18 In XIicPs_MasterRecvPolled, set transfer size register
* before slave address. Fix for CR996440.
* </pre>
*
******************************************************************************/
/***************************** 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;
u32 Platform = XGetPlatform_Info();
/*
* 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);
XIicPs_EnableInterrupts(BaseAddr,
(u32)XIICPS_IXR_NACK_MASK | (u32)XIICPS_IXR_COMP_MASK |
(u32)XIICPS_IXR_ARB_LOST_MASK);
/*
* Do the address transfer to notify the slave.
*/
XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, (u32)SlaveAddr);
/* Clear the Hold bit in ZYNQ if receive byte count is less than
* the FIFO depth to get the completion interrupt properly.
*/
if ((ByteCount < XIICPS_FIFO_DEPTH) && (Platform == (u32)XPLAT_ZYNQ))
{
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) &
(u32)(~XIICPS_CR_HOLD_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->SendBufferPtr = NULL;
InstancePtr->IsSend = 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);
/*
* Setup the transfer size register so the slave knows how much
* to send to us.
*/
if (ByteCount > (s32)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 {
InstancePtr->CurrByteCount = ByteCount;
XIicPs_WriteReg(BaseAddr, (u32)(XIICPS_TRANS_SIZE_OFFSET),
(u32)ByteCount);
InstancePtr->UpdateTxSize = 0;
}
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);
/*
* Do the address transfer to signal the slave.
*/
XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, (u32)SlaveAddr);
}
/*****************************************************************************/
/**
* 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;
_Bool Value;
/*
* Assert validates the input arguments.
*/
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(MsgPtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
Xil_AssertNonvoid((u16)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 != FALSE) {
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 Result;
s32 IsHold;
s32 UpdateTxSize = 0;
s32 ByteCountVar = ByteCount;
u32 Platform;
/*
* 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;
Platform = XGetPlatform_Info();
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;
} else {
IsHold = 0;
}
(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);
/*
* Set up the transfer size register so the slave knows how much
* to send to us.
*/
if (ByteCountVar > (s32)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);
}
XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr);
/*
* 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) &&
(UpdateTxSize == 0)) {
IsHold = 0;
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr,
XIICPS_CR_OFFSET) &
(~XIICPS_CR_HOLD_MASK));
}
XIicPs_RecvByte(InstancePtr);
ByteCountVar --;
if (Platform == (u32)XPLAT_ZYNQ) {
if ((UpdateTxSize != 0) &&
(ByteCountVar == (XIICPS_FIFO_DEPTH + 1))) {
break;
}
}
StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
}
if (Platform == (u32)XPLAT_ZYNQ) {
if ((UpdateTxSize != 0) &&
(ByteCountVar == (XIICPS_FIFO_DEPTH + 1))) {
/* wait while fifo is full */
while (XIicPs_ReadReg(BaseAddr,
XIICPS_TRANS_SIZE_OFFSET) !=
(u32)(ByteCountVar - XIICPS_FIFO_DEPTH)) { ;
}
if ((InstancePtr->RecvByteCount - XIICPS_FIFO_DEPTH) >
(s32)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;
}
}
} else {
if ((InstancePtr->RecvByteCount > 0) && (ByteCountVar == 0)) {
/*
* 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);
if ((InstancePtr->RecvByteCount) >
(s32)XIICPS_MAX_TRANSFER_SIZE) {
XIicPs_WriteReg(BaseAddr,
XIICPS_TRANS_SIZE_OFFSET,
XIICPS_MAX_TRANSFER_SIZE);
ByteCountVar = (s32)XIICPS_MAX_TRANSFER_SIZE;
} else {
XIicPs_WriteReg(BaseAddr,
XIICPS_TRANS_SIZE_OFFSET,
InstancePtr->RecvByteCount);
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));
/*
* wait for slv monitor control bit to be clear
*/
while (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.
*
* <pre>
* 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.
*
* </pre>
*
* @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;
u16 SlaveAddr;
s32 ByteCnt;
s32 IsHold;
u32 Platform;
/*
* Assert validates the input arguments.
*/
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
BaseAddr = InstancePtr->Config.BaseAddress;
Platform = XGetPlatform_Info();
/*
* 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) &&
(InstancePtr->UpdateTxSize == 0)) {
IsHold = 0;
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr,
XIICPS_CR_OFFSET) &
(~XIICPS_CR_HOLD_MASK));
}
XIicPs_RecvByte(InstancePtr);
ByteCnt--;
if (Platform == (u32)XPLAT_ZYNQ) {
if ((InstancePtr->UpdateTxSize != 0) &&
(ByteCnt == (XIICPS_FIFO_DEPTH + 1))) {
break;
}
}
}
if (Platform == (u32)XPLAT_ZYNQ) {
if ((InstancePtr->UpdateTxSize != 0) &&
(ByteCnt == (XIICPS_FIFO_DEPTH + 1))) {
/* wait while fifo is full */
while (XIicPs_ReadReg(BaseAddr,
XIICPS_TRANS_SIZE_OFFSET) !=
(u32)(ByteCnt - XIICPS_FIFO_DEPTH)) {
}
if ((InstancePtr->RecvByteCount - XIICPS_FIFO_DEPTH) >
(s32)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;
}
}
} else {
if ((InstancePtr->RecvByteCount > 0) && (ByteCnt == 0)) {
/*
* Clear the interrupt status register before use it to
* monitor.
*/
IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);
XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg);
SlaveAddr = (u16)XIicPs_ReadReg(BaseAddr, (u32)XIICPS_ADDR_OFFSET);
XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr);
if ((InstancePtr->RecvByteCount) >
(s32)XIICPS_MAX_TRANSFER_SIZE) {
XIicPs_WriteReg(BaseAddr,
XIICPS_TRANS_SIZE_OFFSET,
XIICPS_MAX_TRANSFER_SIZE);
ByteCnt = (s32)XIICPS_MAX_TRANSFER_SIZE;
} else {
XIicPs_WriteReg(BaseAddr,
XIICPS_TRANS_SIZE_OFFSET,
InstancePtr->RecvByteCount);
InstancePtr->UpdateTxSize = 0;
ByteCnt = InstancePtr->RecvByteCount;
}
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);
}
}
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;
}
/*
* Arbitration lost interrupt
*/
if (0U != (IntrStatusReg & XIICPS_IXR_ARB_LOST_MASK)) {
StatusEvent |= XIICPS_EVENT_ARB_LOST;
}
/*
* All other interrupts are treated as error.
*/
if (0U != (IntrStatusReg & (XIICPS_IXR_NACK_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;
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;
}else {
ControlReg &= (u32)(~XIICPS_CR_RD_WR_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;
}
/** @} */