/******************************************************************************
* Copyright (C) 2001 - 2022 Xilinx, Inc.  All rights reserved.
* Copyright (c) 2022 - 2024 Advanced Micro Devices, Inc. All Rights Reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/

/*****************************************************************************/
/**
*
* @file xspi.c
* @addtogroup spi Overview
* @{
*
* Contains required functions of the XSpi driver component.  See xspi.h for
* a detailed description of the device and driver.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver   Who  Date     Changes
* ----- ---- -------- -----------------------------------------------
* 1.00a rpm  10/11/01 First release
* 1.00b jhl  03/14/02 Repartitioned driver for smaller files.
* 1.00b rpm  04/25/02 Collapsed IPIF and reg base addresses into one
* 1.00b rmm  05/14/03 Fixed diab compiler warnings relating to asserts
* 1.01a jvb  12/13/05 Changed Initialize() into CfgInitialize(), and made
*                     CfgInitialize() take a pointer to a config structure
*                     instead of a device id. Moved Initialize() into
*                     xspi_sinit.c, and had Initialize() call CfgInitialize()
*                     after it retrieved the config structure using the device
*                     id. Removed include of xparameters.h along with any
*                     dependencies on xparameters.h and the _g.c config table.
* 1.11a wgr  03/22/07 Converted to new coding style.
* 1.11a rpm  01/22/08 Updated comment on Transfer regarding needing interrupts.
* 1.12a sdm  03/27/08 Updated the code to support 16/32 bit transfer width and
*                     polled mode of operation. Even for the polled mode of
*                     operation the Interrupt Logic in the core should be
*                     included. The driver can be put in polled mode of
*                     operation by disabling the Global Interrupt after the
*                     Spi Initialization is completed.
* 2.00a sdm  07/30/08 Updated the code to support 16/32 bit transfer width and
*                     polled mode of operation. Even for the polled mode of
*                     operation the Interrupt Logic in the core should be
*                     included. The driver can be put in polled mode of
*                     operation by disabling the Global Interrupt after the
*                     Spi Initialization is completed.
* 2.01b sdm  04/08/09 Fixed an issue in the XSpi_Transfer function where the
*                     Global Interrupt is being enabled in polled mode when a
*                     slave is not selected.
* 3.00a ktn  10/28/09 Updated all the register accesses as 32 bit access.
*		      Updated to use the HAL APIs/macros.
*		      Removed the macro XSpi_mReset, XSpi_Reset API should be
*		      used in its place.
*		      The macros have been renamed to remove _m from the name.
*		      Removed an unnecessary read to the core register in the
*		      XSpi_GetSlaveSelect API.
* 3.01a sdm  04/23/10 Updated the driver to handle new slave mode interrupts
*		      and the DTR Half Empty interrupt.
* 3.04a bss  03/21/12 Updated XSpi_CfgInitialize to support XIP Mode
* 3.05a adk  18/04/13 Updated the code to avoid unused variable 
*	              warnings when compiling with the -Wextra -Wall flags
*		      In the file xspi.c. CR:705005.
* 3.06a adk  07/08/13 Added a dummy read in the CfgInitialize(), if startup
*		      block is used in the h/w design (CR 721229).
* 3.07a adk 11/10/13  In the xspi_transfer function moved the assert slave chip
* 		      select after the configuration of the Data Transmit 
*		      register inorder to work with CPOL and CPHA High Options.
* 		      As per spec (Dual/Quad SPI Transaction instrunction 7,8,9)
* 		      CR:732962
* 4.1	bss 08/07/14  Modified XSpi_Transfer to check for Interrupt Status
*		      register Tx Empty bit instead of Status register
*		      CR#810294.
* 4.2   sk   11/10/15 Used UINTPTR instead of u32 for Baseaddress CR# 867425.
*                     Changed the prototype of XSpi_CfgInitialize API.
* 4.4	tjs  11/28/17 When receive fifo exists, we need to check for status
*                     register rx fifo empty flag. If clear we can proceed for
*                     read. Otherwise we will hit exception. CR# 989938
* 4.5	akm  05/29/19 Removed master inhibit dependency while writing DTR
*		      in between multiple transfers.
* 4.7	akm  10/22/20 Removed dependency of Tx_Full flag while writing DTR
*		      in between multiple transfers.
* 4.8   akm  01/19/21 Fix multiple byte transfer hang issue, when FIFOs are
*                     disabled.
* 4.10  akm  02/21/23 Avoid data loss in interrupt mode with TX HALF EMPTY
*                     Interrupt enabled.
* 4.13  ap   08/20/24 Added logic to wait for FIFO reset to complete.
* 4.14  sb   12/03/24 Fixed GCC warnings.
* </pre>
*
******************************************************************************/

/***************************** Include Files *********************************/

#include "xspi.h"
#include "xspi_i.h"

/************************** Constant Definitions *****************************/


/**************************** Type Definitions *******************************/


/***************** Macros (Inline Functions) Definitions *********************/


/************************** Function Prototypes ******************************/

static void StubStatusHandler(void *CallBackRef, u32 StatusEvent,
				unsigned int ByteCount);

void XSpi_Abort(XSpi *InstancePtr);

/************************** Variable Definitions *****************************/


/*****************************************************************************/
/**
*
* Initializes a specific XSpi instance such that the driver is ready to use.
*
* The state of the device after initialization is:
*	- Device is disabled
*	- Slave mode
*	- Active high clock polarity
*	- Clock phase 0
*
* @param	InstancePtr is a pointer to the XSpi instance to be worked on.
* @param	Config is a reference to a structure containing information
*		about a specific SPI device. This function initializes an
*		InstancePtr object for a specific device specified by the
*		contents of Config. This function can initialize multiple
*		instance objects with the use of multiple calls giving
		different Config information on each call.
* @param	EffectiveAddr is the device base address in the virtual memory
*		address space. The caller is responsible for keeping the
*		address mapping from EffectiveAddr to the device physical base
*		address unchanged once this function is invoked. Unexpected
*		errors may occur if the address mapping changes after this
*		function is called. If address translation is not used, use
*		Config->BaseAddress for this parameters, passing the physical
*		address instead.
*
* @return
*		- XST_SUCCESS if successful.
*		- XST_DEVICE_IS_STARTED if the device is started. It must be
*		  stopped to re-initialize.
*
* @note		None.
*
******************************************************************************/
int XSpi_CfgInitialize(XSpi *InstancePtr, XSpi_Config *Config,
			UINTPTR EffectiveAddr)
{
	u8  Buffer[3];
	u32 ControlReg;
	u32 StatusReg;
	u32 Status;
	u32 Timeout = 1000U;
	
	Xil_AssertNonvoid(InstancePtr != NULL);

	/*
	 * If the device is started, disallow the initialize and return a status
	 * indicating it is started.  This allows the user to stop the device
	 * and reinitialize, but prevents a user from inadvertently
	 * initializing.
	 */
	if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) {
		return XST_DEVICE_IS_STARTED;
	}

	/*
	 * Set some default values.
	 */
	InstancePtr->IsStarted = 0;
	InstancePtr->IsBusy = FALSE;

	InstancePtr->StatusHandler = StubStatusHandler;

	InstancePtr->SendBufferPtr = NULL;
	InstancePtr->RecvBufferPtr = NULL;
	InstancePtr->RequestedBytes = 0;
	InstancePtr->RemainingBytes = 0;
	InstancePtr->BaseAddr = EffectiveAddr;
	InstancePtr->HasFifos = Config->HasFifos;
	InstancePtr->FifosDepth = Config->FifosDepth;
	InstancePtr->SlaveOnly = Config->SlaveOnly;
	InstancePtr->NumSlaveBits = Config->NumSlaveBits;
	if (Config->DataWidth == 0) {
		InstancePtr->DataWidth = XSP_DATAWIDTH_BYTE;
	} else {
		InstancePtr->DataWidth = Config->DataWidth;
	}

	InstancePtr->SpiMode = Config->SpiMode;

	InstancePtr->FlashBaseAddr = Config->AxiFullBaseAddress;
	InstancePtr->XipMode = Config->XipMode;

	InstancePtr->IsReady = XIL_COMPONENT_IS_READY;

	/*
	 * Create a slave select mask based on the number of bits that can
	 * be used to deselect all slaves, initialize the value to put into
	 * the slave select register to this value.
	 */
	InstancePtr->SlaveSelectMask = (1 << InstancePtr->NumSlaveBits) - 1;
	InstancePtr->SlaveSelectReg = InstancePtr->SlaveSelectMask;

	/*
	 * Clear the statistics for this driver.
	 */
	InstancePtr->Stats.ModeFaults = 0;
	InstancePtr->Stats.XmitUnderruns = 0;
	InstancePtr->Stats.RecvOverruns = 0;
	InstancePtr->Stats.SlaveModeFaults = 0;
	InstancePtr->Stats.BytesTransferred = 0;
	InstancePtr->Stats.NumInterrupts = 0;
	
        if(Config->Use_Startup == 1) {
		/*  
		 * Perform a dummy read this is used when startup block is
		 * enabled in the hardware to fix CR #721229.
		 */
		ControlReg = XSpi_GetControlReg(InstancePtr);
		ControlReg |= XSP_CR_TXFIFO_RESET_MASK | XSP_CR_RXFIFO_RESET_MASK |
				XSP_CR_ENABLE_MASK | XSP_CR_MASTER_MODE_MASK ;
		XSpi_SetControlReg(InstancePtr, ControlReg);
		
		/* Wait for Tx and Rx FIFO reset to complete */
		Status = Xil_WaitForEvent(InstancePtr->BaseAddr + XSP_CR_OFFSET,
				XSP_CR_TXFIFO_RESET_MASK | XSP_CR_RXFIFO_RESET_MASK,
				XSP_CR_RESET_DONE_MASK, Timeout);
		if (Status != XST_SUCCESS) {
			return XST_FAILURE;
		}

		/* 
		 * Initiate Read command to get the ID. This Read command is for
		 * Numonyx flash.
		 *
		 * NOTE: If user interfaces different flash to the SPI controller 
		 * this command need to be changed according to target flash Read
		 * command.
		 */
		Buffer[0] = 0x9F;
		Buffer[1] = 0x00;
		Buffer[2] = 0x00;
	
		/* Write dummy ReadId to the DTR register */
		XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Buffer[0]);
		XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Buffer[1]);
		XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Buffer[2]);
	
		/* Master Inhibit enable in the CR */
		ControlReg = XSpi_GetControlReg(InstancePtr);
		ControlReg &= ~XSP_CR_TRANS_INHIBIT_MASK;
		XSpi_SetControlReg(InstancePtr, ControlReg);
	
		/* Master Inhibit disable in the CR */
		ControlReg = XSpi_GetControlReg(InstancePtr);
		ControlReg |= XSP_CR_TRANS_INHIBIT_MASK;
		XSpi_SetControlReg(InstancePtr, ControlReg);
		
		/* Read the Rx Data Register */
		StatusReg = XSpi_GetStatusReg(InstancePtr);
		if ((StatusReg & XSP_SR_RX_EMPTY_MASK) == 0) {
			XSpi_ReadReg(InstancePtr->BaseAddr, XSP_DRR_OFFSET);
		}
		StatusReg = XSpi_GetStatusReg(InstancePtr);
		if ((StatusReg & XSP_SR_RX_EMPTY_MASK) == 0) {
			XSpi_ReadReg(InstancePtr->BaseAddr, XSP_DRR_OFFSET);
		}
	}
	
	/*
	 * Reset the SPI device to get it into its initial state. It is expected
	 * that device configuration will take place after this initialization
	 * is done, but before the device is started.
	 */
	XSpi_Reset(InstancePtr);

	return XST_SUCCESS;
}

/*****************************************************************************/
/**
*
* This function enables interrupts for the SPI device. If the Spi driver is used
* in interrupt mode, it is up to the user to connect the SPI interrupt handler
* to the interrupt controller before this function is called. If the Spi driver
* is used in polled mode the user has to disable the Global Interrupts after
* this function is called. If the device is configured with FIFOs, the FIFOs are
* reset at this time.
*
* @param	InstancePtr is a pointer to the XSpi instance to be worked on.
*
* @return
*		- XST_SUCCESS if the device is successfully started
*		- XST_DEVICE_IS_STARTED if the device was already started.
*
* @note		None.
*
******************************************************************************/
int XSpi_Start(XSpi *InstancePtr)
{
	u32 ControlReg;
	u32 Status;
	u32 Timeout = 1000U;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	/*
	 * If it is already started, return a status indicating so.
	 */
	if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) {
		return XST_DEVICE_IS_STARTED;
	}

	/*
	 * Enable the interrupts.
	 */
	XSpi_IntrEnable(InstancePtr, XSP_INTR_DFT_MASK);

	/*
	 * Indicate that the device is started before we enable the transmitter
	 * or receiver or interrupts.
	 */
	InstancePtr->IsStarted = XIL_COMPONENT_IS_STARTED;

	/*
	 * Reset the transmit and receive FIFOs if present. There is a critical
	 * section here since this register is also modified during interrupt
	 * context. So we wait until after the r/m/w of the control register to
	 * enable the Global Interrupt Enable.
	 */
	ControlReg = XSpi_GetControlReg(InstancePtr);
	ControlReg |= XSP_CR_TXFIFO_RESET_MASK | XSP_CR_RXFIFO_RESET_MASK |
			XSP_CR_ENABLE_MASK;
	XSpi_SetControlReg(InstancePtr, ControlReg);

	/* Wait for Tx and Rx FIFO reset to complete */
	Status = Xil_WaitForEvent(InstancePtr->BaseAddr + XSP_CR_OFFSET,
			XSP_CR_TXFIFO_RESET_MASK | XSP_CR_RXFIFO_RESET_MASK,
			XSP_CR_RESET_DONE_MASK, Timeout);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Enable the Global Interrupt Enable just after we start.
	 */
	XSpi_IntrGlobalEnable(InstancePtr);

	return XST_SUCCESS;
}

/*****************************************************************************/
/**
*
* This function stops the SPI device by disabling interrupts and disabling the
* device itself. Interrupts are disabled only within the device itself. If
* desired, the caller is responsible for disabling interrupts in the interrupt
* controller and disconnecting the interrupt handler from the interrupt
* controller.
*
* In interrupt mode, if the device is in progress of transferring data on the
* SPI bus, this function returns a status indicating the device is busy. The
* user will be notified via the status handler when the transfer is complete,
* and at that time can again try to stop the device. As a master, we do not
* allow the device to be stopped while a transfer is in progress because the
* slave may be left in a bad state. As a slave, we do not allow the device to be
* stopped while a transfer is in progress because the master is not done with
* its transfer yet.
*
* @param	InstancePtr is a pointer to the XSpi instance to be worked on.
*
* @return
* 		- XST_SUCCESS if the device is successfully started.
*		- XST_DEVICE_BUSY if a transfer is in progress and cannot be
*		  stopped.
*
* @note
*
* This function makes use of internal resources that are shared between the
* XSpi_Stop() and XSpi_SetOptions() functions. So if one task might be setting
* device options while another is trying to stop the device, the user is
* is required to provide protection of this shared data (typically using a
* semaphore).
*
******************************************************************************/
int XSpi_Stop(XSpi *InstancePtr)
{
	u32 ControlReg;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	/*
	 * Do not allow the user to stop the device while a transfer is in
	 * progress.
	 */
	if (InstancePtr->IsBusy) {
		return XST_DEVICE_BUSY;
	}

	/*
	 * Disable the device. First disable the interrupts since there is
	 * a critical section here because this register is also modified during
	 * interrupt context. The device is likely disabled already since there
	 * is no transfer in progress, but we do it again just to be sure.
	 */
	XSpi_IntrGlobalDisable(InstancePtr);

	ControlReg = XSpi_GetControlReg(InstancePtr);
	XSpi_SetControlReg(InstancePtr, ControlReg & ~XSP_CR_ENABLE_MASK);

	InstancePtr->IsStarted = 0;

	return XST_SUCCESS;
}

/*****************************************************************************/
/**
*
* Resets the SPI device by writing to the Software Reset register. Reset must
* only be called after the driver has been initialized. The configuration of the
* device after reset is the same as its configuration after initialization.
* Refer to the XSpi_Initialize function for more details. This is a hard reset
* of the device. Any data transfer that is in progress is aborted.
*
* The upper layer software is responsible for re-configuring (if necessary)
* and restarting the SPI device after the reset.
*
* @param	InstancePtr is a pointer to the XSpi instance to be worked on.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
void XSpi_Reset(XSpi *InstancePtr)
{
	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	/*
	 * Abort any transfer that is in progress.
	 */
	XSpi_Abort(InstancePtr);

	/*
	 * Reset any values that are not reset by the hardware reset such that
	 * the software state matches the hardware device.
	 */
	InstancePtr->IsStarted = 0;
	InstancePtr->SlaveSelectReg = InstancePtr->SlaveSelectMask;

	/*
	 * Reset the device.
	 */
	XSpi_WriteReg(InstancePtr->BaseAddr, XSP_SRR_OFFSET,
			XSP_SRR_RESET_MASK);
}

/*****************************************************************************/
/**
*
* Transfers the specified data on the SPI bus. If the SPI device is configured
* to be a master, this function initiates bus communication and sends/receives
* the data to/from the selected SPI slave. If the SPI device is configured to
* be a slave, this function prepares the data to be sent/received when selected
* by a master. For every byte sent, a byte is received.
*
* This function/driver operates in interrupt mode and polled mode.
*  - In interrupt mode this function is non-blocking and the transfer is
*    initiated by this function and completed by the interrupt service routine.
*  - In polled mode this function is blocking and the control exits this
*    function only after all the requested data is transferred.
*
* The caller has the option of providing two different buffers for send and
* receive, or one buffer for both send and receive, or no buffer for receive.
* The receive buffer must be at least as big as the send buffer to prevent
* unwanted memory writes. This implies that the byte count passed in as an
* argument must be the smaller of the two buffers if they differ in size.
* Here are some sample usages:
*
* <pre>
*	XSpi_Transfer(InstancePtr, SendBuf, RecvBuf, ByteCount)
*	The caller wishes to send and receive, and provides two different
*	buffers for send and receive.
*
*	XSpi_Transfer(InstancePtr, SendBuf, NULL, ByteCount)
*	The caller wishes only to send and does not care about the received
*	data. The driver ignores the received data in this case.
*
*	XSpi_Transfer(InstancePtr, SendBuf, SendBuf, ByteCount)
*	The caller wishes to send and receive, but provides the same buffer
*	for doing both. The driver sends the data and overwrites the send
*	buffer with received data as it transfers the data.
*
*	XSpi_Transfer(InstancePtr, RecvBuf, RecvBuf, ByteCount)
*	The caller wishes to only receive and does not care about sending
*	data.  In this case, the caller must still provide a send buffer, but
*	it can be the same as the receive buffer if the caller does not care
*	what it sends. The device must send N bytes of data if it wishes to
*	receive N bytes of data.
* </pre>
*
* In interrupt mode, though this function takes a buffer as an argument, the
* driver can only transfer a limited number of bytes at time. It transfers only
* one byte at a time if there are no FIFOs, or it can transfer the number of
* bytes up to the size of the FIFO if FIFOs exist.
*  - In interrupt mode a call to this function only starts the transfer, the
*    subsequent transfer of the data is performed by the interrupt service
*    routine until the entire buffer has been transferred.The status callback
*    function is called when the entire buffer has been sent/received.
*  - In polled mode this function is blocking and the control exits this
*    function only after all the requested data is transferred.
*
* As a master, the SetSlaveSelect function must be called prior to this
* function.
*
* @param	InstancePtr is a pointer to the XSpi instance to be worked on.
* @param	SendBufPtr is a pointer to a buffer of data which is to be sent.
*		This buffer must not be NULL.
* @param	RecvBufPtr is a pointer to a buffer which will be filled with
*		received data. This argument can be NULL if the caller does not
*		wish to receive data.
* @param	ByteCount contains the number of bytes to send/receive. The
*		number of bytes received always equals the number of bytes sent.
*
* @return
*		-XST_SUCCESS if the buffers are successfully handed off to the
*		driver for transfer. Otherwise, returns:
*		- XST_DEVICE_IS_STOPPED if the device must be started before
*		transferring data.
*		- XST_DEVICE_BUSY indicates that a data transfer is already in
*		progress. This is determined by the driver.
*		- XST_SPI_NO_SLAVE indicates the device is configured as a
*		master and a slave has not yet been selected.
*
* @note
*
* This function is not thread-safe.  The higher layer software must ensure that
* no two threads are transferring data on the SPI bus at the same time.
*
******************************************************************************/
int XSpi_Transfer(XSpi *InstancePtr, u8 *SendBufPtr,
		  u8 *RecvBufPtr, unsigned int ByteCount)
{
	u32 ControlReg;
	u32 GlobalIntrReg;
	u32 StatusReg;
	u32 Data = 0;
	u8  DataWidth;
	u32 DataLen;
	u32 Index;

	/*
	 * The RecvBufPtr argument can be NULL.
	 */
	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(SendBufPtr != NULL);
	Xil_AssertNonvoid(ByteCount > 0);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	if (InstancePtr->IsStarted != XIL_COMPONENT_IS_STARTED) {
		return XST_DEVICE_IS_STOPPED;
	}

	/*
	 * Make sure there is not a transfer already in progress. No need to
	 * worry about a critical section here. Even if the Isr changes the bus
	 * flag just after we read it, a busy error is returned and the caller
	 * can retry when it gets the status handler callback indicating the
	 * transfer is done.
	 */
	if (InstancePtr->IsBusy) {
		return XST_DEVICE_BUSY;
	}

	/*
	 * Save the Global Interrupt Enable Register.
	 */
	GlobalIntrReg = XSpi_IsIntrGlobalEnabled(InstancePtr);

	/*
	 * Enter a critical section from here to the end of the function since
	 * state is modified, an interrupt is enabled, and the control register
	 * is modified (r/m/w).
	 */
	XSpi_IntrGlobalDisable(InstancePtr);

	ControlReg = XSpi_GetControlReg(InstancePtr);

	/*
	 * If configured as a master, be sure there is a slave select bit set
	 * in the slave select register. If no slaves have been selected, the
	 * value of the register will equal the mask.  When the device is in
	 * loopback mode, however, no slave selects need be set.
	 */
	if (ControlReg & XSP_CR_MASTER_MODE_MASK) {
		if ((ControlReg & XSP_CR_LOOPBACK_MASK) == 0) {
			if (InstancePtr->SlaveSelectReg ==
				InstancePtr->SlaveSelectMask) {
				if (GlobalIntrReg == TRUE) {
					/* Interrupt Mode of operation */
					XSpi_IntrGlobalEnable(InstancePtr);
				}
				return XST_SPI_NO_SLAVE;
			}
		}
	}

	/*
	 * Set the busy flag, which will be cleared when the transfer
	 * is completely done.
	 */
	InstancePtr->IsBusy = TRUE;

	/*
	 * Set up buffer pointers.
	 */
	InstancePtr->SendBufferPtr = SendBufPtr;
	InstancePtr->RecvBufferPtr = RecvBufPtr;

	InstancePtr->RequestedBytes = ByteCount;
	InstancePtr->RemainingBytes = ByteCount;

	DataWidth = InstancePtr->DataWidth;

	/* Inhibit the transmitter while the transmit register/FIFO is
	 * being filled.
	 */
	ControlReg = XSpi_GetControlReg(InstancePtr);
	XSpi_SetControlReg(InstancePtr, ControlReg |
			   XSP_CR_TRANS_INHIBIT_MASK);
	/*
	 * Fill the DTR/FIFO with as many bytes as it will take (or as many as
	 * we have to send). We use the tx full status bit to know if the device
	 * can take more data. By doing this, the driver does not need to know
	 * the size of the FIFO or that there even is a FIFO. The downside is
	 * that the status register must be read each loop iteration.
	 */
	StatusReg = XSpi_GetStatusReg(InstancePtr);

	while (((StatusReg & XSP_SR_TX_FULL_MASK) == 0) &&
		(InstancePtr->RemainingBytes > 0)) {
		if (DataWidth == XSP_DATAWIDTH_BYTE) {
			/*
			 * Data Transfer Width is Byte (8 bit).
			 */
			Data = *InstancePtr->SendBufferPtr;
		} else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) {
			/*
			 * Data Transfer Width is Half Word (16 bit).
			 */
			Data = *(u16 *)InstancePtr->SendBufferPtr;
		} else if (DataWidth == XSP_DATAWIDTH_WORD){
			/*
			 * Data Transfer Width is Word (32 bit).
			 */
			Data = *(u32 *)InstancePtr->SendBufferPtr;
		}

		XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Data);
		InstancePtr->SendBufferPtr += (DataWidth >> 3);
		InstancePtr->RemainingBytes -= (DataWidth >> 3);
		StatusReg = XSpi_GetStatusReg(InstancePtr);
	}

	
	/*
	 * Set the slave select register to select the device on the SPI before
	 * starting the transfer of data.
	 */
	XSpi_SetSlaveSelectReg(InstancePtr,
				InstancePtr->SlaveSelectReg);
				
	/*
	 * If the interrupts are enabled as indicated by Global Interrupt
	 * Enable Register, then enable the transmit empty interrupt to operate
	 * in Interrupt mode of operation.
	 */
	if (GlobalIntrReg == TRUE) { /* Interrupt Mode of operation */

		/*
		 * Enable the transmit empty interrupt, which we use to
		 * determine progress on the transmission.
		 */
		XSpi_IntrEnable(InstancePtr, XSP_INTR_TX_EMPTY_MASK);

		/*
		 * End critical section.
		 */
		XSpi_IntrGlobalEnable(InstancePtr);
	}

	/*
	 * Start the transfer by no longer inhibiting the transmitter and
	 * enabling the device. For a master, this will in fact start the
	 * transfer, but for a slave it only prepares the device for a transfer
	 * that must be initiated by a master.
	 */
	ControlReg = XSpi_GetControlReg(InstancePtr);
	ControlReg &= ~XSP_CR_TRANS_INHIBIT_MASK;
	XSpi_SetControlReg(InstancePtr, ControlReg);

	/*
	 * If the interrupts are enabled as indicated by Global Interrupt
	 * Enable Register, then enable the transmit empty interrupt to operate
	 * in Interrupt mode of operation.
	 */
	if (GlobalIntrReg != TRUE) { /* Poll Mode of operation */

		/*
		 * If interrupts are not enabled, poll the status register to
		 * Transmit/Receive SPI data.
		 */
		while(ByteCount > 0) {

			/*
			 * Wait for the transfer to be done by polling the
			 * Transmit empty status bit
			 */
			do {
				StatusReg = XSpi_IntrGetStatus(InstancePtr);
			} while ((StatusReg & XSP_INTR_TX_EMPTY_MASK) == 0);

			XSpi_IntrClear(InstancePtr,XSP_INTR_TX_EMPTY_MASK);


			/*
			 * First get the data received as a result of the
			 * transmit that just completed. We get all the data
			 * available by reading the status register to determine
			 * when the Receive register/FIFO is empty. Always get
			 * the received data, but only fill the receive
			 * buffer if it points to something (the upper layer
			 * software may not care to receive data).
			 */
			StatusReg = XSpi_GetStatusReg(InstancePtr);

			while ((StatusReg & XSP_SR_RX_EMPTY_MASK) == 0) {

				Data = XSpi_ReadReg(InstancePtr->BaseAddr,
								XSP_DRR_OFFSET);
				if (DataWidth == XSP_DATAWIDTH_BYTE) {
					/*
					 * Data Transfer Width is Byte (8 bit).
					 */
					if(InstancePtr->RecvBufferPtr != NULL) {
						*InstancePtr->RecvBufferPtr++ =
							(u8)Data;
					}
				} else if (DataWidth ==
						XSP_DATAWIDTH_HALF_WORD) {
					/*
					 * Data Transfer Width is Half Word
					 * (16 bit).
					 */
					if (InstancePtr->RecvBufferPtr != NULL){
					    *(u16 *)InstancePtr->RecvBufferPtr =
							(u16)Data;
						InstancePtr->RecvBufferPtr += 2;
					}
				} else if (DataWidth == XSP_DATAWIDTH_WORD) {
					/*
					 * Data Transfer Width is Word (32 bit).
					 */
					if (InstancePtr->RecvBufferPtr != NULL){
					    *(u32 *)InstancePtr->RecvBufferPtr =
							Data;
						InstancePtr->RecvBufferPtr += 4;
					}
				}
				InstancePtr->Stats.BytesTransferred +=
						(DataWidth >> 3);
				ByteCount -= (DataWidth >> 3);
				StatusReg = XSpi_GetStatusReg(InstancePtr);
			}

			if (InstancePtr->RemainingBytes > 0) {

				/*
				 * As master transaction inhibit is not set while filling
				 * the DTR/FIFO, as soon as the data is written to the
				 * DTR/FIFO, it gets pushed out on to the lines and the
				 * TX_FULL never gets set. If we depend on TX_FULL flag
				 * for filling the DTR/FIFO, this will lead to RXFIFO
				 * overrun error. So, fill the DTR/FIFO with TXFIFO_DEPTH
				 * length or remaining length of data, whichever is less.
				 */
				if ((InstancePtr->RemainingBytes > InstancePtr->FifosDepth) &&
				    (InstancePtr->FifosDepth != 0)) {
					DataLen = InstancePtr->FifosDepth;
				} else {
					DataLen =InstancePtr->RemainingBytes;
				}

				for(Index = 0; Index < DataLen; Index += (DataWidth / 8)) {
					if (DataWidth == XSP_DATAWIDTH_BYTE) {
						/*
						 * Data Transfer Width is Byte
						 * (8 bit).
						 */
						Data = *InstancePtr->
								SendBufferPtr;

					} else if (DataWidth ==
						XSP_DATAWIDTH_HALF_WORD) {

						/*
						 * Data Transfer Width is Half
						 * Word (16 bit).
			 			 */
						Data = *(u16 *)InstancePtr->
								SendBufferPtr;
					} else if (DataWidth ==
							XSP_DATAWIDTH_WORD) {
						/*
						 * Data Transfer Width is Word
						 * (32 bit).
			 			 */
						Data = *(u32 *)InstancePtr->
								SendBufferPtr;
					}
					XSpi_WriteReg(InstancePtr->BaseAddr,
							XSP_DTR_OFFSET, Data);
					InstancePtr->SendBufferPtr +=
							(DataWidth >> 3);
				}
				InstancePtr->RemainingBytes -= DataLen;

			}
		}

		/*
		 * Stop the transfer (hold off automatic sending) by inhibiting
		 * the transmitter.
		 */
		ControlReg = XSpi_GetControlReg(InstancePtr);
		XSpi_SetControlReg(InstancePtr,
				    ControlReg | XSP_CR_TRANS_INHIBIT_MASK);

		/*
		 * Select the slave on the SPI bus when the transfer is
		 * complete, this is necessary for some SPI devices,
		 * such as serial EEPROMs work correctly as chip enable
		 * may be connected to slave select
		 */
		XSpi_SetSlaveSelectReg(InstancePtr,
					InstancePtr->SlaveSelectMask);
		InstancePtr->IsBusy = FALSE;
	}

	return XST_SUCCESS;
}

/*****************************************************************************/
/**
*
* Selects or deselect the slave with which the master communicates. Each slave
* that can be selected is represented in the slave select register by a bit.
* The argument passed to this function is the bit mask with a 1 in the bit
* position of the slave being selected. Only one slave can be selected.
*
* The user is not allowed to deselect the slave while a transfer is in progress.
* If no transfer is in progress, the user can select a new slave, which
* implicitly deselects the current slave. In order to explicitly deselect the
* current slave, a zero can be passed in as the argument to the function.
*
* @param	InstancePtr is a pointer to the XSpi instance to be worked on.
* @param	SlaveMask is a 32-bit mask with a 1 in the bit position of the
*		slave being selected. Only one slave can be selected. The
*		SlaveMask can be zero if the slave is being deselected.
*
* @return
* 		- XST_SUCCESS if the slave is selected or deselected
*		successfully.
*		- XST_DEVICE_BUSY if a transfer is in progress, slave cannot be
*		changed
*		- XST_SPI_TOO_MANY_SLAVES if more than one slave is being
*		selected.
*
* @note
*
* This function only sets the slave which will be selected when a transfer
* occurs. The slave is not selected when the SPI is idle. The slave select
* has no affect when the device is configured as a slave.
*
******************************************************************************/
int XSpi_SetSlaveSelect(XSpi *InstancePtr, u32 SlaveMask)
{
	int NumAsserted;
	int Index;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	/*
	 * Do not allow the slave select to change while a transfer is in
	 * progress.
	 * No need to worry about a critical section here since even if the Isr
	 * changes the busy flag just after we read it, the function will return
	 * busy and the caller can retry when notified that their current
	 * transfer is done.
	 */
	if (InstancePtr->IsBusy) {
		return XST_DEVICE_BUSY;
	}

	/*
	 * Verify that only one bit in the incoming slave mask is set.
	 */
	NumAsserted = 0;
	for (Index = (InstancePtr->NumSlaveBits - 1); Index >= 0; Index--) {
		if ((SlaveMask >> Index) & 0x1) {
			/* this bit is asserted */
			NumAsserted++;
		}
	}

	/*
	 * Return an error if more than one slave is selected.
	 */
	if (NumAsserted > 1) {
		return XST_SPI_TOO_MANY_SLAVES;
	}

	/*
	 * A single slave is either being selected or the incoming SlaveMask is
	 * zero, which means the slave is being deselected. Setup the value to
	 * be  written to the slave select register as the inverse of the slave
	 * mask.
	 */
	InstancePtr->SlaveSelectReg = ~SlaveMask;

	return XST_SUCCESS;
}

/*****************************************************************************/
/**
*
* Gets the current slave select bit mask for the SPI device.
*
* @param	InstancePtr is a pointer to the XSpi instance to be worked on.
*
* @return	The value returned is a 32-bit mask with a 1 in the bit position
*		of the slave currently selected. The value may be zero if no
*		slaves are selected.
*
* @note		This API is used to get the current slave select bit mask
*		that was set using the XSpi_SetSlaveSelect API.
*		This API deos not read the register from the core and returns
*		the slave select register stored in the instance pointer.
*
******************************************************************************/
u32 XSpi_GetSlaveSelect(XSpi *InstancePtr)
{
	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	/*
	 * Return the inverse of the value contained in
	 * InstancePtr->SlaveSelectReg. This value is set using the API
	 * XSpi_SetSlaveSelect.
	 */
	return ~InstancePtr->SlaveSelectReg;
}

/*****************************************************************************/
/**
*
* Sets the status callback function, the status handler, which the driver calls
* when it encounters conditions that should be reported to the higher layer
* software. The handler executes in an interrupt context, so it must minimize
* the amount of processing performed such as transferring data to a thread
* context. One of the following status events is passed to the status handler.
* <pre>
*   XST_SPI_MODE_FAULT		A mode fault error occurred, meaning another
*				master tried to select this device as a slave
*				when this device was configured to be a master.
*				Any transfer in progress is aborted.
*
*   XST_SPI_TRANSFER_DONE	The requested data transfer is done
*
*   XST_SPI_TRANSMIT_UNDERRUN	As a slave device, the master clocked
*				data but there were none available in the
*				transmit register/FIFO. This typically means the
*				slave application did not issue a transfer
*				request fast enough, or the processor/driver
*				could not fill the transmit register/FIFO fast
*				enough.
*
*   XST_SPI_RECEIVE_OVERRUN	The SPI device lost data. Data was received
*				but the receive data register/FIFO was full.
*				This indicates that the device is receiving data
*				faster than the processor/driver can consume it.
*
*   XST_SPI_SLAVE_MODE_FAULT	A slave SPI device was selected as a slave while
*				it was disabled.  This indicates the master is
*				already transferring data (which is being
*				dropped until the slave application issues a
*				transfer).
* </pre>
*
* @param	InstancePtr is a pointer to the XSpi instance to be worked on.
* @param	CallBackRef is the upper layer callback reference passed back
*		when the callback function is invoked.
* @param	FuncPtr is the pointer to the callback function.
*
* @return	None.
*
* @note
*
* The handler is called within interrupt context, so it should do its work
* quickly and queue potentially time-consuming work to a task-level thread.
*
******************************************************************************/
void XSpi_SetStatusHandler(XSpi *InstancePtr, void *CallBackRef,
			   XSpi_StatusHandler FuncPtr)
{
	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(FuncPtr != NULL);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	InstancePtr->StatusHandler = FuncPtr;
	InstancePtr->StatusRef = CallBackRef;
}

/*****************************************************************************/
/**
*
* This is a stub for the status callback. The stub is here in case the upper
* layers forget to set the handler.
*
* @param	CallBackRef is a pointer to the upper layer callback reference
* @param	StatusEvent is the event that just occurred.
* @param	ByteCount is the number of bytes transferred up until the event
*		occurred.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
static void StubStatusHandler(void *CallBackRef, u32 StatusEvent,
				unsigned int ByteCount)
{
	(void )CallBackRef;
	(void )StatusEvent;
	(void ) ByteCount;
	Xil_AssertVoidAlways();
}

/*****************************************************************************/
/**
*
* The interrupt handler for SPI interrupts. This function must be connected
* by the user to an interrupt source. This function does not save and restore
* the processor context such that the user must provide this processing.
*
* The interrupts that are handled are:
*
* - Mode Fault Error. This interrupt is generated if this device is selected
*   as a slave when it is configured as a master. The driver aborts any data
*   transfer that is in progress by resetting FIFOs (if present) and resetting
*   its buffer pointers. The upper layer software is informed of the error.
*
* - Data Transmit Register (FIFO) Empty. This interrupt is generated when the
*   transmit register or FIFO is empty. The driver uses this interrupt during a
*   transmission to continually send/receive data until there is no more data
*   to send/receive.
*
* - Data Transmit Register (FIFO) Underrun. This interrupt is generated when
*   the SPI device, when configured as a slave, attempts to read an empty
*   DTR/FIFO.  An empty DTR/FIFO usually means that software is not giving the
*   device data in a timely manner. No action is taken by the driver other than
*   to inform the upper layer software of the error.
*
* - Data Receive Register (FIFO) Overrun. This interrupt is generated when the
*   SPI device attempts to write a received byte to an already full DRR/FIFO.
*   A full DRR/FIFO usually means software is not emptying the data in a timely
*   manner.  No action is taken by the driver other than to inform the upper
*   layer software of the error.
*
* - Slave Mode Fault Error. This interrupt is generated if a slave device is
*   selected as a slave while it is disabled. No action is taken by the driver
*   other than to inform the upper layer software of the error.
*
* - Command Error. This interrupt occurs when the first byte in the Tx FIFO,
*   after the CS is asserted, doesn't match any command in the Lookup table.
*   This interrupt is valid only for axi_qspi.
*
* @param	InstancePtr is a pointer to the XSpi instance to be worked on.
*
* @return	None.
*
* @note
*
* The slave select register is being set to deselect the slave when a transfer
* is complete.  This is being done regardless of whether it is a slave or a
* master since the hardware does not drive the slave select as a slave.
*
******************************************************************************/
void XSpi_InterruptHandler(void *InstancePtr)
{
	XSpi *SpiPtr = (XSpi *)InstancePtr;
	u32 IntrStatus;
	unsigned int BytesDone;	/* number of bytes done so far */
	u32 Data = 0;
	u32 StatusReg;
	u8  DataWidth;
	u32 DataLen;
	u32 Index;

	Xil_AssertVoid(InstancePtr != NULL);

	/*
	 * Update the statistics for the number of interrupts.
	 */
	SpiPtr->Stats.NumInterrupts++;

	/*
	 * Get the Interrupt Status. Immediately clear the interrupts in case
	 * this Isr causes another interrupt to be generated. If we clear at the
	 * end of the Isr, we may miss this newly generated interrupt. This
	 * occurs because we transmit from within the Isr, potentially causing
	 * another TX_EMPTY interrupt.
	 */
	IntrStatus = XSpi_IntrGetStatus(SpiPtr);
	XSpi_IntrClear(SpiPtr, IntrStatus);

	/*
	 * Check for mode fault error. We want to check for this error first,
	 * before checking for progress of a transfer, since this error needs
	 * to abort any operation in progress.
	 */
	if (IntrStatus & XSP_INTR_MODE_FAULT_MASK) {
		BytesDone = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes;
		SpiPtr->Stats.ModeFaults++;

		/*
		 * Abort any operation currently in progress. This includes
		 * clearing the mode fault condition by reading the status
		 * register.
		 * Note that the status register should be read after the Abort
		 * since reading the status register clears the mode fault
		 * condition and would cause the device to restart any transfer
		 * that may be in progress.
		 */
		XSpi_Abort(SpiPtr);

		(void) XSpi_GetStatusReg(SpiPtr);

		SpiPtr->StatusHandler(SpiPtr->StatusRef, XST_SPI_MODE_FAULT,
					BytesDone);

		return;		/* Do not continue servicing other interrupts */
	}

	DataWidth = SpiPtr->DataWidth;
	if ((IntrStatus & XSP_INTR_TX_EMPTY_MASK) ||
	    (IntrStatus & XSP_INTR_TX_HALF_EMPTY_MASK)) {


		/*
		 * First get the data received as a result of the transmit that
		 * just completed.  We get all the data available by reading the
		 * status register to determine when the receive register/FIFO
		 * is empty. Always get the received data, but only fill the
		 * receive buffer if it points to something (the upper layer
		 * software may not care to receive data).
		 */
		StatusReg = XSpi_GetStatusReg(SpiPtr);

		while ((StatusReg & XSP_SR_RX_EMPTY_MASK) == 0) {

			Data = XSpi_ReadReg(SpiPtr->BaseAddr, XSP_DRR_OFFSET);

			/*
			 * Data Transfer Width is Byte (8 bit).
			 */
			if (DataWidth == XSP_DATAWIDTH_BYTE) {
				if (SpiPtr->RecvBufferPtr != NULL) {
					*SpiPtr->RecvBufferPtr++ = (u8) Data;
				}
			} else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) {
				if (SpiPtr->RecvBufferPtr != NULL) {
					*(u16 *) SpiPtr->RecvBufferPtr =
							(u16) Data;
					SpiPtr->RecvBufferPtr +=2;
				}
			} else if (DataWidth == XSP_DATAWIDTH_WORD) {
				if (SpiPtr->RecvBufferPtr != NULL) {
					*(u32 *) SpiPtr->RecvBufferPtr =
							Data;
					SpiPtr->RecvBufferPtr +=4;
				}
			}

			SpiPtr->Stats.BytesTransferred += (DataWidth >> 3);
			StatusReg = XSpi_GetStatusReg(SpiPtr);
		}

		/*
		 * See if there is more data to send.
		 */
		if (SpiPtr->RemainingBytes > 0) {
			/*
			 * As master transaction inhibit is not set while filling
			 * the DTR/FIFO in the interrupt handler, so as soon as
			 * the data is written to the DTR/FIFO, it gets pushed
			 * out on to the lines and the TX_FULL never gets set.
			 * If we depend on TX_FULL flag for filling the DTR/FIFO
			 * then it will lead to RXFIFO overrun error. For filling
			 * DTR/FIFO check if TX_HALF_EMPTY is set then fill the
			 * DTR/FIFO with (TXFIFO_DEPTH/2) length or remaining length
			 * of data, whichever is less. If TX_HALF_EMPTY is not set
			 * then fill the DTR/FIFO with TXFIFO_DEPTH length or
			 * remaining length of data, whichever is less.
			 */
			if ((IntrStatus & XSP_INTR_TX_HALF_EMPTY_MASK) &&
			    (SpiPtr->RemainingBytes > (SpiPtr->FifosDepth / 2)) &&
			    (SpiPtr->FifosDepth != 0)) {
				DataLen = SpiPtr->FifosDepth / 2;
			} else if ((SpiPtr->RemainingBytes > SpiPtr->FifosDepth) &&
				   (SpiPtr->FifosDepth != 0)) {
				DataLen = SpiPtr->FifosDepth;
			} else {
				DataLen =SpiPtr->RemainingBytes;
			}
			for(Index = 0; Index < DataLen; Index += (DataWidth / 8)) {
				if (DataWidth == XSP_DATAWIDTH_BYTE) {
					/*
					 * Data Transfer Width is Byte (8 bit).
					 */
					Data = *SpiPtr->SendBufferPtr;

				} else if (DataWidth ==
						XSP_DATAWIDTH_HALF_WORD) {
					/*
					 * Data Transfer Width is Half Word
					 * (16 bit).
					 */
					Data = *(u16 *) SpiPtr->SendBufferPtr;
				} else if (DataWidth ==
						XSP_DATAWIDTH_WORD) {
					/*
					 * Data Transfer Width is Word (32 bit).
					 */
					Data = *(u32 *) SpiPtr->SendBufferPtr;
				}

				XSpi_WriteReg(SpiPtr->BaseAddr, XSP_DTR_OFFSET,
						Data);
				SpiPtr->SendBufferPtr += (DataWidth >> 3);
			}
			SpiPtr->RemainingBytes -= DataLen;

		} else {

			/*
			 * Select the slave on the SPI bus when the transfer is
			 * complete, this is necessary for some SPI devices,
			 * such as serial EEPROMs work correctly as chip enable
			 * may be connected to slave select.
			 */
			XSpi_SetSlaveSelectReg(SpiPtr,
						SpiPtr->SlaveSelectMask);
			/*
			 * No more data to send.  Disable the interrupt and
			 * inform the upper layer software that the transfer is
			 * done. The interrupt will be re-enabled when another
			 * transfer is initiated.
			 */
			XSpi_IntrDisable(SpiPtr, XSP_INTR_TX_EMPTY_MASK);

			SpiPtr->IsBusy = FALSE;

			SpiPtr->StatusHandler(SpiPtr->StatusRef,
						XST_SPI_TRANSFER_DONE,
						SpiPtr->RequestedBytes);
		}
	}

	/*
	 * Check if the device has been addressed as a slave. Report the status
	 * to the application layer.
	 */
	if (IntrStatus & XSP_INTR_SLAVE_MODE_MASK) {
		SpiPtr->StatusHandler(SpiPtr->StatusRef,
					XST_SPI_SLAVE_MODE, 0);
	}

	/*
	 * Check if the device has received data from the master. Report the
	 * status to the application layer.
	 */
	if (IntrStatus & XSP_INTR_RX_NOT_EMPTY_MASK) {
		SpiPtr->StatusHandler(SpiPtr->StatusRef,
					XST_SPI_RECEIVE_NOT_EMPTY, 0);
	}

	/*
	 * Check for slave mode fault. Simply report the error and update the
	 * statistics.
	 */
	if (IntrStatus & XSP_INTR_SLAVE_MODE_FAULT_MASK) {
		BytesDone = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes;
		SpiPtr->Stats.SlaveModeFaults++;
		SpiPtr->StatusHandler(SpiPtr->StatusRef,
				XST_SPI_SLAVE_MODE_FAULT, BytesDone);
	}

	/*
	 * Check for overrun error. Simply report the error and update the
	 * statistics.
	 */
	if (IntrStatus & XSP_INTR_RX_OVERRUN_MASK) {
		BytesDone = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes;
		SpiPtr->Stats.RecvOverruns++;
		SpiPtr->StatusHandler(SpiPtr->StatusRef,
				XST_SPI_RECEIVE_OVERRUN, BytesDone);
	}

	/*
	 * Check for underrun error. Simply report the error and update the
	 * statistics.
	 */
	if (IntrStatus & XSP_INTR_TX_UNDERRUN_MASK) {
		BytesDone = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes;
		SpiPtr->Stats.XmitUnderruns++;
		SpiPtr->StatusHandler(SpiPtr->StatusRef,
				XST_SPI_TRANSMIT_UNDERRUN, BytesDone);
	}

	/*
	 * Check for command error. Simply report the error and update the
	 * statistics.
	 */
	if (IntrStatus & XSP_INTR_CMD_ERR_MASK) {
		BytesDone = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes;
		SpiPtr->Stats.XmitUnderruns++;
		SpiPtr->StatusHandler(SpiPtr->StatusRef,
				XST_SPI_COMMAND_ERROR, BytesDone);
	}
}

/*****************************************************************************/
/**
*
* Aborts a transfer in progress by setting the stop bit in the control register,
* then resetting the FIFOs if present. The byte counts are cleared and the
* busy flag is set to false.
*
* @param	InstancePtr is a pointer to the XSpi instance to be worked on.
*
* @return	None.
*
* @note
*
* This function does a read/modify/write of the control register. The user of
* this function needs to take care of critical sections.
*
******************************************************************************/
void XSpi_Abort(XSpi *InstancePtr)
{
	u16 ControlReg;
	u32 Timeout = 1000U;

	/*
	 * Deselect the slave on the SPI bus to abort a transfer, this must be
	 * done before the device is disabled such that the signals which are
	 * driven by the device are changed without the device enabled.
	 */
	XSpi_SetSlaveSelectReg(InstancePtr,
				InstancePtr->SlaveSelectMask);
	/*
	 * Abort the operation currently in progress. Clear the mode
	 * fault condition by reading the status register (done) then
	 * writing the control register.
	 */
	ControlReg = XSpi_GetControlReg(InstancePtr);

	/*
	 * Stop any transmit in progress and reset the FIFOs if they exist,
	 * don't disable the device just inhibit any data from being sent.
	 */
	ControlReg |= XSP_CR_TRANS_INHIBIT_MASK;

	if (InstancePtr->HasFifos) {
		ControlReg |= (XSP_CR_TXFIFO_RESET_MASK |
				XSP_CR_RXFIFO_RESET_MASK);
	}

	XSpi_SetControlReg(InstancePtr, ControlReg);

	/* Wait for Tx and Rx FIFO reset to complete */
	if (InstancePtr->HasFifos) {
		Xil_WaitForEvent(InstancePtr->BaseAddr + XSP_CR_OFFSET,
				XSP_CR_TXFIFO_RESET_MASK | XSP_CR_RXFIFO_RESET_MASK,
				XSP_CR_RESET_DONE_MASK, Timeout);
	}

	InstancePtr->RemainingBytes = 0;
	InstancePtr->RequestedBytes = 0;
	InstancePtr->IsBusy = FALSE;
}

/** @} */
