embeddedsw/XilinxProcessorIPLib/drivers/iic/src/xiic_intr.c
Kedareswara rao Appana eec760a402 iic: update copy right information
This patch updates the copy right to 2015.

Signed-off-by: Kedareswara rao Appana <appanad@xilinx.com>
2015-04-26 10:30:26 +05:30

443 lines
15 KiB
C
Executable file
Raw Blame History

/******************************************************************************
*
* Copyright (C) 2006 - 2015 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 xiic_intr.c
*
* Contains interrupt functions of the XIic driver. This file is required
* for the driver.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -----------------------------------------------
* 1.01a rfp 10/19/01 release
* 1.01c ecm 12/05/02 new rev
* 1.01c rmm 05/14/03 Fixed diab compiler warnings relating to asserts.
* 1.03a ecm 06/22/06 Added a call to the status handler in the TxErrorHandler
* even if the Rx buffer pointer is not set. This fix is as
* a result of a Sony use model which did not set the Rx
* pointer while in Master mode so it checks if MSMS == 1.
* 1.13a wgr 03/22/07 Converted to new coding style.
* 2.00a sdm 10/22/09 Converted all register accesses to 32 bit access.
* Updated to use the HAL APIs/macros.
* Some of the macros have been renamed to remove _m from
* the name and Some of the macros have been renamed to be
* consistent, see the xiic_l.h file for further information.
* 2.01a ktn 04/09/10 Updated TxErrorhandler to be called for Master Transmitter
* case based on Addressed As Slave (AAS) bit rather than
* MSMS bit(CR 540199).
* 2.06a bss 02/14/13 Modified TxErrorHandler in xiic_intr.c to fix CR #686483
* Modified bitwise OR to logical OR in
* XIic_InterruptHandler API.
* 2.07a adk 18/04/13 Updated the code to avoid unused variable warnings
* when compiling with the -Wextra -Wall flags.
* In the file xiic.c and xiic_i.h. CR:705001
* </pre>
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "xiic.h"
#include "xiic_i.h"
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions ******************/
/************************** Function Prototypes ****************************/
static void StubFunction(XIic *InstancePtr);
static void TxErrorHandler(XIic *InstancePtr);
/************************** Variable Definitions *****************************/
/* The following function pointers are used to help allow finer partitioning
* of the driver such that some parts of it are optional. These pointers are
* setup by functions in the optional parts of the driver.
*/
void (*XIic_AddrAsSlaveFuncPtr) (XIic *InstancePtr) = StubFunction;
void (*XIic_NotAddrAsSlaveFuncPtr) (XIic *InstancePtr) = StubFunction;
void (*XIic_RecvSlaveFuncPtr) (XIic *InstancePtr) = StubFunction;
void (*XIic_SendSlaveFuncPtr) (XIic *InstancePtr) = StubFunction;
void (*XIic_RecvMasterFuncPtr) (XIic *InstancePtr) = StubFunction;
void (*XIic_SendMasterFuncPtr) (XIic *InstancePtr) = StubFunction;
void (*XIic_ArbLostFuncPtr) (XIic *InstancePtr) = StubFunction;
void (*XIic_BusNotBusyFuncPtr) (XIic *InstancePtr) = StubFunction;
/*****************************************************************************/
/**
*
* This function is the interrupt handler for the XIic driver. This function
* should be connected to the interrupt system.
*
* Only one interrupt source is handled for each interrupt allowing
* higher priority system interrupts quicker response time.
*
* @param InstancePtr is a pointer to the XIic instance to be worked on.
*
* @return None.
*
* @internal
*
* The XIIC_INTR_ARB_LOST_MASK and XIIC_INTR_TX_ERROR_MASK interrupts must have
* higher priority than the other device interrupts so that the IIC device does
* not get into a potentially confused state. The remaining interrupts may be
* rearranged with no harm.
*
******************************************************************************/
void XIic_InterruptHandler(void *InstancePtr)
{
u32 Status;
u32 IntrStatus;
u32 IntrPending;
u32 IntrEnable;
XIic *IicPtr = NULL;
u32 Clear = 0;
/*
* Verify that each of the inputs are valid.
*/
Xil_AssertVoid(InstancePtr != NULL);
/*
* Convert the non-typed pointer to an IIC instance pointer
*/
IicPtr = (XIic *) InstancePtr;
/*
* Get the interrupt Status.
*/
IntrPending = XIic_ReadIisr(IicPtr->BaseAddress);
IntrEnable = XIic_ReadIier(IicPtr->BaseAddress);
IntrStatus = IntrPending & IntrEnable;
/*
* Do not processes a devices interrupts if the device has no
* interrupts pending or the global interrupts have been disabled.
*/
if ((IntrStatus == 0) ||
(XIic_IsIntrGlobalEnabled(IicPtr->BaseAddress) == FALSE)) {
return;
}
/*
* Update interrupt stats and get the contents of the status register.
*/
IicPtr->Stats.IicInterrupts++;
Status = XIic_ReadReg(IicPtr->BaseAddress, XIIC_SR_REG_OFFSET);
/*
* Service requesting interrupt.
*/
if (IntrStatus & XIIC_INTR_ARB_LOST_MASK) {
/* Bus Arbritration Lost */
IicPtr->Stats.ArbitrationLost++;
XIic_ArbLostFuncPtr(IicPtr);
Clear = XIIC_INTR_ARB_LOST_MASK;
} else if (IntrStatus & XIIC_INTR_TX_ERROR_MASK) {
/* Transmit errors (no acknowledge) received */
IicPtr->Stats.TxErrors++;
TxErrorHandler(IicPtr);
Clear = XIIC_INTR_TX_ERROR_MASK;
} else if (IntrStatus & XIIC_INTR_NAAS_MASK) {
/* Not Addressed As Slave */
XIic_NotAddrAsSlaveFuncPtr(IicPtr);
Clear = XIIC_INTR_NAAS_MASK;
} else if (IntrStatus & XIIC_INTR_RX_FULL_MASK) {
/* Receive register/FIFO is full */
IicPtr->Stats.RecvInterrupts++;
if (Status & XIIC_SR_ADDR_AS_SLAVE_MASK) {
XIic_RecvSlaveFuncPtr(IicPtr);
} else {
XIic_RecvMasterFuncPtr(IicPtr);
}
Clear = XIIC_INTR_RX_FULL_MASK;
} else if (IntrStatus & XIIC_INTR_AAS_MASK) {
/* Addressed As Slave */
XIic_AddrAsSlaveFuncPtr(IicPtr);
Clear = XIIC_INTR_AAS_MASK;
} else if (IntrStatus & XIIC_INTR_BNB_MASK) {
/* IIC bus has transitioned to not busy */
/* Check if send callback needs to run */
if (IicPtr->BNBOnly == TRUE) {
XIic_BusNotBusyFuncPtr(IicPtr);
IicPtr->BNBOnly = FALSE;
} else {
IicPtr->SendHandler(IicPtr->SendCallBackRef, 0);
}
Clear = XIIC_INTR_BNB_MASK;
/* The bus is not busy, disable BusNotBusy interrupt */
XIic_DisableIntr(IicPtr->BaseAddress, XIIC_INTR_BNB_MASK);
} else if ((IntrStatus & XIIC_INTR_TX_EMPTY_MASK) ||
(IntrStatus & XIIC_INTR_TX_HALF_MASK)) {
/* Transmit register/FIFO is empty or <20> empty */
IicPtr->Stats.SendInterrupts++;
if (Status & XIIC_SR_ADDR_AS_SLAVE_MASK) {
XIic_SendSlaveFuncPtr(IicPtr);
} else {
XIic_SendMasterFuncPtr(IicPtr);
}
IntrStatus = XIic_ReadIisr(IicPtr->BaseAddress);
Clear = IntrStatus & (XIIC_INTR_TX_EMPTY_MASK |
XIIC_INTR_TX_HALF_MASK);
}
/*
* Clear Interrupts.
*/
XIic_WriteIisr(IicPtr->BaseAddress, Clear);
}
/******************************************************************************
*
* This function fills the FIFO using the occupancy register to determine the
* available space to be filled. When the repeated start option is on, the last
* byte is withheld to allow the control register to be properly set on the last
* byte.
*
* @param InstancePtr is a pointer to the XIic instance to be worked on.
*
* @param Role indicates the role of this IIC device, a slave or a master,
* on the IIC bus (XIIC_SLAVE_ROLE or XIIC_MASTER_ROLE).
*
* @return None.
*
* @note None.
*
******************************************************************************/
void XIic_TransmitFifoFill(XIic *InstancePtr, int Role)
{
u8 AvailBytes;
int LoopCnt;
int NumBytesToSend;
/*
* Determine number of bytes to write to FIFO. Number of bytes that
* can be put into the FIFO is (FIFO depth) - (current occupancy + 1)
* When more room in FIFO than msg bytes put all of message in the FIFO.
*/
AvailBytes = IIC_TX_FIFO_DEPTH -
(u8) (XIic_ReadReg(InstancePtr->BaseAddress,
XIIC_TFO_REG_OFFSET) + 1);
if (InstancePtr->SendByteCount > AvailBytes) {
NumBytesToSend = AvailBytes;
} else {
/*
* More space in FIFO than bytes in message.
*/
if ((InstancePtr->Options & XII_REPEATED_START_OPTION) ||
(Role == XIIC_SLAVE_ROLE)) {
NumBytesToSend = InstancePtr->SendByteCount;
} else {
NumBytesToSend = InstancePtr->SendByteCount - 1;
}
}
/*
* Fill FIFO with amount determined above.
*/
for (LoopCnt = 0; LoopCnt < NumBytesToSend; LoopCnt++) {
XIic_WriteSendByte(InstancePtr);
}
}
/*****************************************************************************/
/**
*
* 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.
*
******************************************************************************/
static void TxErrorHandler(XIic *InstancePtr)
{
u32 IntrStatus;
u32 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_FlushTxFifo(InstancePtr);
XIic_DisableIntr(InstancePtr->BaseAddress,
XIIC_TX_RX_INTERRUPTS);
/*
* If operating in Master mode, call status handler to indicate
* NOACK occured.
*/
IntrStatus = XIic_ReadIisr(InstancePtr->BaseAddress);
if ((IntrStatus & XIIC_INTR_AAS_MASK) == 0) {
InstancePtr->StatusHandler(InstancePtr->
StatusCallBackRef,
XII_SLAVE_NO_ACK_EVENT);
} else {
/* Decrement the Tx Error since Tx Error interrupt
* implies transmit complete while sending as Slave
*/
InstancePtr->Stats.TxErrors--;
}
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_ReadIisr(InstancePtr->BaseAddress);
if (IntrStatus & XIIC_INTR_RX_FULL_MASK) {
/* Rx Reg/FIFO has data, Disable Tx error interrupts */
XIic_DisableIntr(InstancePtr->BaseAddress,
XIIC_INTR_TX_ERROR_MASK);
return;
}
XIic_FlushTxFifo(InstancePtr);
/*
* Disable and clear Tx empty, <20> empty, Rx Full or Tx error interrupts.
*/
XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS);
XIic_ClearIntr(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 = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET);
CntlReg &= ~XIIC_CR_MSMS_MASK;
XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, CntlReg);
/*
* Set FIFO occupancy depth = 1 so that the first byte will throttle
* next recieve msg.
*/
XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, 0);
/*
* Call the event callback.
*/
InstancePtr->StatusHandler(InstancePtr->StatusCallBackRef,
XII_SLAVE_NO_ACK_EVENT);
}
/*****************************************************************************/
/**
*
* This function is a stub function that is used for the default function for
* events that are handled optionally only when the appropriate modules are
* linked in. Function pointers are used to handle some events to allow
* some events to be optionally handled.
*
* @param InstancePtr is a pointer to the XIic instance to be worked on.
*
******************************************************************************/
static void StubFunction(XIic *InstancePtr)
{
(void )InstancePtr;
Xil_AssertVoidAlways();
}