/**
*
* When multiple IIC devices attempt to use the bus simultaneously, only
* a single device will be able to keep control as a master. Those devices
* that didn't retain control over the bus are said to have lost arbitration.
* When arbitration is lost, this interrupt occurs sigaling the user that
* the message did not get sent as expected.
*
* This function, at arbitration lost:
*   - Disables tx empty, ½ empty and Tx error interrupts
*   - Clears any tx empty, ½ empty Rx Full or tx error interrupts
*   - Clears Arbitration lost interrupt,
*   - Flush Tx FIFO
*   - Call StatusHandler callback with the value: XII_ARB_LOST_EVENT
*
* @param    InstancePtr is a pointer to the XIic instance to be worked on.
*
* @return
*
* None.
*
* @note
*
* None.
*
******************************************************************************/
static void ArbitrationLostHandler(XIic * InstancePtr)
{
	/* Disable tx empty and ½ empty and Tx error interrupts before clearing them
	 * so they won't occur again
	 */
	XIic_mDisableIntr(InstancePtr->BaseAddress, XIIC_TX_INTERRUPTS);

	/* Clear any tx empty, ½ empty Rx Full or tx error interrupts
	 */
	XIic_mClearIntr(InstancePtr->BaseAddress, XIIC_TX_INTERRUPTS);

	XIic_mFlushTxFifo(InstancePtr);

	/* Update Status via StatusHandler callback
	 */
	InstancePtr->StatusHandler(InstancePtr->StatusCallBackRef,
				   XII_ARB_LOST_EVENT);
}
/**
*
* This interrupt occurs four different ways: Two as master and two as slave.
* Master:
* <pre>
*  (1) Transmitter (IMPLIES AN ERROR)
*      The slave receiver did not acknowledge properly.
*  (2) Receiver (Implies tx complete)
*      Interrupt caused by setting TxAck high in the IIC to indicate to the
*      the last byte has been transmitted.
* </pre>
*
* Slave:
* <pre>
*  (3) Transmitter (Implies tx complete)
*      Interrupt caused by master device indicating last byte of the message
*      has been transmitted.
*  (4) Receiver (IMPLIES AN ERROR)
*      Interrupt caused by setting TxAck high in the IIC to indicate Rx
*      IIC had a problem - set by this device and condition already known
*      and interrupt is not enabled.
* </pre>
*
* This interrupt is enabled during Master send and receive and disabled
* when this device knows it is going to send a negative acknowledge (Ack = No).
*
* Signals user of Tx error via status callback sending: XII_TX_ERROR_EVENT
*
* When MasterRecv has no message to send and only receives one byte of data
* from the salve device, the TxError must be enabled to catch addressing
* errors, yet there is not opportunity to disable TxError when there is no
* data to send allowing disabling on last byte. When the slave sends the
* only byte the NOAck causes a Tx Error. To disregard this as no real error,
* when there is data in the Receive FIFO/register then the error was not
* a device address write error, but a NOACK read error - to be ignored.
* To work with or without FIFO's, the Rx Data interrupt is used to indicate
* data is in the rx register.
*
* @param    InstancePtr is a pointer to the XIic instance to be worked on.
*
* @return
*
* None.
*
* @note
*
* No action is required to clear this interrupt in the device as it is a
* pulse. The interrupt need only be cleared in the IpIf interface.
*
******************************************************************************/
static void TxErrorHandler(XIic * InstancePtr)
{
	u32 IntrStatus;
	u8 CntlReg;

	/* When Sending as a slave, Tx error signals end of msg. Not Addressed As
	 * Slave will handle the callbacks. this is used to only flush the Tx fifo.
	 * The addressed as slave bit is gone as soon as the bus has been released
	 * such that the buffer pointers are used to determine the direction of
	 * transfer (send or receive).
	 */
	if (InstancePtr->RecvBufferPtr == NULL) {
		/* Master Receiver finished reading message. Flush Tx fifo to remove an
		 * 0xFF that was written to prevent bus throttling, and disable all
		 * transmit and receive interrupts
		 */
		XIic_mFlushTxFifo(InstancePtr);
		XIic_mDisableIntr(InstancePtr->BaseAddress,
				  XIIC_TX_RX_INTERRUPTS);


		/* If operating in Master mode, call status handler to indicate
		 * NOACK occured
		 */
		CntlReg =
			XIo_In8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET);
		if ((CntlReg & XIIC_CR_MSMS_MASK) != 0) {
			InstancePtr->StatusHandler(InstancePtr->
						   StatusCallBackRef,
						   XII_SLAVE_NO_ACK_EVENT);
		}
		return;
	}

	/* Data in the receive register from either master or slave receive
	 * When:slave, indicates master sent last byte, message completed.
	 * When:master, indicates a master Receive with one byte received. When a
	 * byte is in Rx reg then the Tx error indicates the Rx data was recovered
	 * normally Tx errors are not enabled such that this should not occur.
	 */
	IntrStatus = XIIC_READ_IISR(InstancePtr->BaseAddress);
	if (IntrStatus & XIIC_INTR_RX_FULL_MASK) {
		/* Rx Reg/FIFO has data,  Disable tx error interrupts */

		XIic_mDisableIntr(InstancePtr->BaseAddress,
				  XIIC_INTR_TX_ERROR_MASK);
		return;
	}

	XIic_mFlushTxFifo(InstancePtr);

	/* Disable and clear tx empty, ½ empty, Rx Full or tx error interrupts
	 */
	XIic_mDisableIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS);
	XIic_mClearIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS);

	/* Clear MSMS as on TX error when Rxing, the bus will be
	 * stopped but MSMS bit is still set. Reset to proper state
	 */
	CntlReg = XIo_In8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET);
	CntlReg &= ~XIIC_CR_MSMS_MASK;
	XIo_Out8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET, CntlReg);


	/* set FIFO occupancy depth = 1 so that the first byte will throttle
	 * next recieve msg
	 */
	XIo_Out8(InstancePtr->BaseAddress + XIIC_RFD_REG_OFFSET, 0);

	/* make event callback */

	InstancePtr->StatusHandler(InstancePtr->StatusCallBackRef,
				   XII_SLAVE_NO_ACK_EVENT);
}
Example #3
0
/**
*
* This function is called when the receive register is full. The number
* of bytes received to cause the interrupt is adjustable using the Receive FIFO
* Depth register. The number of bytes in the register is read in the Receive
* FIFO occupancy register. Both these registers are zero based values (0-15)
* such that a value of zero indicates 1 byte.
*
* For a Master Receiver to properly signal the end of a message, the data must
* be read in up to the message length - 1, where control register bits will be
* set for bus controls to occur on reading of the last byte.
*
* @param    InstancePtr is a pointer to the XIic instance to be worked on.
*
* @return
*
* None.
*
* @note
*
* None.
*
******************************************************************************/
static void RecvMasterData(XIic * InstancePtr)
{
	u8 LoopCnt;
	int BytesInFifo;
	int BytesToRead;
	u8 CntlReg;

	/* Device is a master receiving, get the contents of the control register
	 * and determine the number of bytes in fifo to be read out
	 */
	CntlReg = XIo_In8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET);
	BytesInFifo = XIo_In8(InstancePtr->BaseAddress + XIIC_RFO_REG_OFFSET)
	    + 1;

	/* If data in FIFO holds all data to be retrieved - 1, set NOACK and
	 * disable the tx error
	 */
	if ((InstancePtr->RecvByteCount - BytesInFifo) == 1) {
		/* Disable tx error interrupt to prevent interrupt
		 * as this device will cause it when it set NO ACK next
		 */
		XIic_mDisableIntr(InstancePtr->BaseAddress,
				  XIIC_INTR_TX_ERROR_MASK);
		XIic_mClearIntr(InstancePtr->BaseAddress,
				XIIC_INTR_TX_ERROR_MASK);

		/* Write control reg with NO ACK allowing last byte to
		 * have the No ack set to indicate to slave last byte read.
		 */
		XIo_Out8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET,
			 (CntlReg | XIIC_CR_NO_ACK_MASK));

		/* Read one byte to clear a place for the last byte to be read
		 * which will set the NO ACK
		 */
		XIic_mReadRecvByte(InstancePtr);
	}

	/* If data in FIFO is all the data to be received then get the data
	 * and also leave the device in a good state for the next transaction
	 */
	else if ((InstancePtr->RecvByteCount - BytesInFifo) == 0) {
		/* If repeated start option is off then the master should stop
		 * using the bus, otherwise hold the bus, setting repeated start
		 * stops the slave from transmitting data when the FIFO is read
		 */
		if ((InstancePtr->Options & XII_REPEATED_START_OPTION) == 0) {
			CntlReg &= ~XIIC_CR_MSMS_MASK;
		} else {
			CntlReg |= XIIC_CR_REPEATED_START_MASK;
		}
		XIo_Out8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET,
			 CntlReg);

		/* Read data from the FIFO then set zero based FIFO read depth for a byte
		 */
		for (LoopCnt = 0; LoopCnt < BytesInFifo; LoopCnt++) {
			XIic_mReadRecvByte(InstancePtr);
		}
		XIo_Out8(InstancePtr->BaseAddress + XIIC_RFD_REG_OFFSET, 0);

		/* Disable Rx full interrupt and write the control reg with ACK allowing
		 * next byte sent to be acknowledged automatically
		 */
		XIic_mDisableIntr(InstancePtr->BaseAddress,
				  XIIC_INTR_RX_FULL_MASK);

		XIo_Out8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET,
			 (CntlReg & ~XIIC_CR_NO_ACK_MASK));

		/* Send notification of msg Rx complete in RecvHandler callback
		 */
		InstancePtr->RecvHandler(InstancePtr->RecvCallBackRef, 0);
	} else {
		/* Fifo data not at n-1, read all but the last byte of data from the
		 * slave, if more than a FIFO full yet to receive read a FIFO full
		 */
		BytesToRead = InstancePtr->RecvByteCount - BytesInFifo - 1;
		if (BytesToRead > IIC_RX_FIFO_DEPTH) {
			BytesToRead = IIC_RX_FIFO_DEPTH;
		}

		/* Read in data from the FIFO */

		for (LoopCnt = 0; LoopCnt < BytesToRead; LoopCnt++) {
			XIic_mReadRecvByte(InstancePtr);
		}
	}
}