/******************************************************************************
*
* (c) Copyright 2010-2012 Xilinx, Inc. All rights reserved.
*
* This file contains confidential and proprietary information of Xilinx, Inc.
* and is protected under U.S. and international copyright and other
* intellectual property laws.
*
* DISCLAIMER
* This disclaimer is not a license and does not grant any rights to the
* materials distributed herewith. Except as otherwise provided in a valid
* license issued to you by Xilinx, and to the maximum extent permitted by
* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL
* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS,
* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE;
* and (2) Xilinx shall not be liable (whether in contract or tort, including
* negligence, or under any other theory of liability) for any loss or damage
* of any kind or nature related to, arising under or in connection with these
* materials, including for any direct, or any indirect, special, incidental,
* or consequential loss or damage (including loss of data, profits, goodwill,
* or any type of loss or damage suffered as a result of any action brought by
* a third party) even if such damage or loss was reasonably foreseeable or
* Xilinx had been advised of the possibility of the same.
*
* CRITICAL APPLICATIONS
* Xilinx products are not designed or intended to be fail-safe, or for use in
* any application requiring fail-safe performance, such as life-support or
* safety devices or systems, Class III medical devices, nuclear facilities,
* applications related to the deployment of airbags, or any other applications
* that could lead to death, personal injury, or severe property or
* environmental damage (individually and collectively, "Critical
* Applications"). Customer assumes the sole risk and liability of any use of
* Xilinx products in Critical Applications, subject only to applicable laws
* and regulations governing limitations on product liability.
*
* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE
* AT ALL TIMES.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xspips.h
*
* This file contains the implementation of the XSpiPs driver. It works for
* both the master and slave mode. User documentation for the driver functions
* is contained in this file in the form of comment blocks at the front of each
* function.
*
* An SPI device connects to an SPI bus through a 4-wire serial interface.
* The SPI bus is a full-duplex, synchronous bus that facilitates communication
* between one master and one slave. The device is always full-duplex,
* which means that for every byte sent, one is received, and vice-versa.
* The master controls the clock, so it can regulate when it wants to
* send or receive data. The slave is under control of the master, it must
* respond quickly since it has no control of the clock and must send/receive
* data as fast or as slow as the master does.
*
* <b>Initialization & Configuration</b>
*
* The XSpiPs_Config structure is used by the driver to configure itself. This
* configuration structure is typically created by the tool-chain based on HW
* build properties.
*
* To support multiple runtime loading and initialization strategies employed by
* various operating systems, the driver instance can be initialized in the
* following way:
*	- XSpiPs_LookupConfig(DeviceId) - Use the devide identifier to find the
*	static configuration structure defined in xspips_g.c. This is setup by
*	the tools. For some operating systems the config structure will be
*	initialized by the software and this call is not needed.
*	- XSpiPs_CfgInitialize(InstancePtr, CfgPtr, EffectiveAddr) - Uses a
*	configuration structure provided by the caller. If running in a system
*	with address translation, the provided virtual memory base address
*	replaces the physical address present in the configuration structure.
*
* <b>Multiple Masters</b>
*
* More than one master can exist, but arbitration is the responsibility of
* the higher layer software. The device driver does not perform any type of
* arbitration.
*
* <b>Multiple Slaves</b>
*
* Contention between multiple masters is detected by the hardware, in which
* case a mode fault occurs on the device. The device is disabled immediately
* by hardware, and the current word transfer is stopped. The Aborted word
* transfer due to the mode fault is resumed once the devie is enabled again.
*
* <b>Interrupts</b>
*
* The user must connect the interrupt handler of the driver,
* XSpiPs_InterruptHandler, to an interrupt system such that it will be
* called when an interrupt occurs. This function does not save and restore
* the processor context such that the user must provide this processing.
*
* The driver handles the following interrupts:
* - Data Transmit Register/FIFO Underflow
* - Data Receive Register/FIFO Full
* - Data Receive Register/FIFO Not Empty
* - Data Transmit Register/FIFO Full
* - Data Transmit Register/FIFO Overwater
* - Mode Fault Error
* - Data Receive Register/FIFO Overrun
*
* The Data Transmit Register/FIFO Overwater interrupt -- indicates that the
* SPI device has transmitted the data available to transmit, and now its data
* register and FIFO is ready to accept more data. The driver uses this
* interrupt to indicate progress while sending data.  The driver may have
* more data to send, in which case the data transmit register and FIFO is
* filled for subsequent transmission. When this interrupt arrives and all
* the data has been sent, the driver invokes the status callback with a
* value of XST_SPI_TRANSFER_DONE to inform the upper layer software that
* all data has been sent.
*
* The Data Transmit Register/FIFO Underflow interrupt -- indicates that,
* as slave, the SPI device was required to transmit but there was no data
* available to transmit in the transmit register (or FIFO). This may not
* be an error if the master is not expecting data. But in the case where
* the master is expecting data, this serves as a notification of such a
* condition. The driver reports this condition to the upper layer
* software through the status handler.
*
* The Data Receive Register/FIFO Overrun interrupt -- indicates that the SPI
* device received data and subsequently dropped the data because the data
* receive register and FIFO was full. The interrupt applies to both master
* and slave operation. The driver reports this condition to the upper layer
* software through the status handler. This likely indicates a problem with
* the higher layer protocol, or a problem with the slave performance.
*
* The Mode Fault Error interrupt -- indicates that while configured as a
* master, the device was selected as a slave by another master. This can be
* used by the application for arbitration in a multimaster environment or to
* indicate a problem with arbitration. When this interrupt occurs, the
* driver invokes the status callback with a status value of
* XST_SPI_MODE_FAULT. It is up to the application to resolve the conflict.
* When configured as a slave, Mode Fault Error interrupt indicates that a slave
* device was selected as a slave by a master, but the slave device was
* disabled. When configured as a master, Mode Fault Error interrupt indicates
* that another SPI device is acting as a master on the bus.
*
*
* <b>Polled Operation</b>
*
* Transfer in polled mode is supported through a separate interface function
* XSpiPs_PolledTransfer(). Unlike the transfer function in the interrupt mode,
* this function blocks until all data has been sent/received.
*
* <b>Device Busy</b>
*
* Some operations are disallowed when the device is busy. The driver tracks
* whether a device is busy. The device is considered busy when a data transfer
* request is outstanding, and is considered not busy only when that transfer
* completes (or is aborted with a mode fault error). This applies to both
* master and slave devices.
*
* <b>Device Configuration</b>
*
* The device can be configured in various ways during the FPGA implementation
* process. Configuration parameters are stored in the xspips_g.c file or
* passed in via XSpiPs_CfgInitialize(). A table is defined where each entry
* contains configuration information for an SPI device, including the base
* address for the device.
*
* <b>RTOS Independence</b>
*
* This driver is intended to be RTOS and processor independent.  It works with
* physical addresses only.  Any needs for dynamic memory management, threads or
* thread mutual exclusion, virtual memory, or cache control must be satisfied
* by the layer above this driver.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver   Who    Date     Changes
* ----- ------ -------- -----------------------------------------------
* 1.00	drg/jz 01/25/10 First release
* 1.00	sdm    10/25/11 Removed the Divide by 2 in the SPI Clock Prescaler options
*			as this is not supported in the device.
* 1.01	sg     03/07/12 Updated the code to always clear the relevant bits
*			before writing to config register.
*			Always clear the slave select bits before write and
*			clear the bits to no slave at the end of transfer
*			Modified the Polled transfer transmit/receive logic.
*			Tx should wait on TXOW Interrupt and Rx on RXNEMTY.
* 1.02a  sg    05/31/12 Updated XSPIPS_FIFO_DEPTH to 128 from 32 to match HW
*			for CR 658289
* </pre>
*
******************************************************************************/
#ifndef XSPIPS_H		/* prevent circular inclusions */
#define XSPIPS_H		/* by using protection macros */

#ifdef __cplusplus
extern "C" {
#endif

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

#include "xstatus.h"
#include "xspips_hw.h"

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

/** @name Configuration options
 *
 * The following options are supported to enable/disable certain features of
 * an SPI device.  Each of the options is a bit mask, so more than one may be
 * specified.
 *
 * <b>The Master option</b> configures the SPI device as a master.
 * By default, the device is a slave.
 *
 * The <b>Active Low Clock option</b> configures the device's clock polarity.
 * Setting this option means the clock is active low and the SCK signal idles
 * high. By default, the clock is active high and SCK idles low.
 *
 * The <b>Clock Phase option</b> configures the SPI device for one of two
 * transfer formats.  A clock phase of 0, the default, means data is valid on
 * the first SCK edge (rising or falling) after the slave select (SS) signal
 * has been asserted. A clock phase of 1 means data is valid on the second SCK
 * edge (rising or falling) after SS has been asserted.
 *
 * The <b>Slave Select Decode Enable option</b> selects how the SPI_SS_outN are
 * controlled by the SPI Slave Select Decode bits.
 * 0: Use this setting for the standard configuration of up to four slave
 * select outputs. Only one of the four slave select outputs will be low.
 * (Default)
 * 1: Use this setting for the optional configuration of an additional decoder
 * to support 16 slave select outputs. SPI_SS_outN reflects the value in the
 * register.
 *
 * The <b>SPI Force Slave Select option</b> is used to enable manual control of
 * the signals SPI_SS_outN.
 * 0: The SPI_SS_outN signals are controlled by the SPI controller during
 * transfers. (Default)
 * 1: The SPI_SS_outN signal indicated by the Slave Select Control bit is
 * forced active (driven low) regardless of any transfers in progress.
 *
 * NOTE: The driver will handle setting and clearing the Slave Select when
 * the user sets the "FORCE_SSELECT_OPTION". Using this option will allow the
 * SPI clock to be set to a faster speed. If the SPI clock is too fast, the
 * processor cannot empty and refill the FIFOs before the TX FIFO is empty
 * When the SPI hardware is controlling the Slave Select signals, this
 * will cause slave to be de-selected and terminate the transfer.
 *
 * @{
 */
#define XSPIPS_MASTER_OPTION		0x1  /**< Master mode option */
#define XSPIPS_CLK_ACTIVE_LOW_OPTION	0x2  /**< Active Low Clock option */
#define XSPIPS_CLK_PHASE_1_OPTION	0x4  /**< Clock Phase one option */
#define XSPIPS_DECODE_SSELECT_OPTION	0x8  /**< Select 16 slaves Option */
#define XSPIPS_FORCE_SSELECT_OPTION	0x10 /**< Force Slave Select */
/*@}*/


/** @name SPI Clock Prescaler options
 * The SPI Clock Prescaler Configuration bits are used to program master mode
 * bit rate. The bit rate can be programmed in divide-by-two decrements from
 * pclk/4 to pclk/256.
 *
 * @{
 */

#define XSPIPS_CLK_PRESCALE_4		0x01  /**< PCLK/4 Prescaler */
#define XSPIPS_CLK_PRESCALE_8		0x02  /**< PCLK/8 Prescaler */
#define XSPIPS_CLK_PRESCALE_16		0x03  /**< PCLK/16 Prescaler */
#define XSPIPS_CLK_PRESCALE_32		0x04  /**< PCLK/32 Prescaler */
#define XSPIPS_CLK_PRESCALE_64		0x05  /**< PCLK/64 Prescaler */
#define XSPIPS_CLK_PRESCALE_128		0x06  /**< PCLK/128 Prescaler */
#define XSPIPS_CLK_PRESCALE_256		0x07  /**< PCLK/256 Prescaler */
/*@}*/


/** @name Callback events
 *
 * These constants specify the handler events that are passed to
 * a handler from the driver.  These constants are not bit masks such that
 * only one will be passed at a time to the handler.
 *
 * @{
 */
#define XSPIPS_EVENT_MODE_FAULT		1  /**< Mode fault error */
#define XSPIPS_EVENT_TRANSFER_DONE	2  /**< Transfer done */
#define XSPIPS_EVENT_TRANSMIT_UNDERRUN	3  /**< TX FIFO empty */
#define XSPIPS_EVENT_RECEIVE_OVERRUN	4  /**< Receive data loss because
						RX FIFO full */
/*@}*/


/**************************** Type Definitions *******************************/
/**
 * The handler data type allows the user to define a callback function to
 * handle the asynchronous processing for the SPI device.  The application
 * using this driver is expected to define a handler of this type to support
 * interrupt driven mode.  The handler executes in an interrupt context, so
 * only minimal processing should be performed.
 *
 * @param	CallBackRef is the callback reference passed in by the upper
 *		layer when setting the callback functions, and passed back to
 *		the upper layer when the callback is invoked. Its type is
 *		not important to the driver, so it is a void pointer.
 * @param 	StatusEvent holds one or more status events that have occurred.
 *		See the XSpiPs_SetStatusHandler() for details on the status
 *		events that can be passed in the callback.
 * @param	ByteCount indicates how many bytes of data were successfully
 *		transferred.  This may be less than the number of bytes
 *		requested if the status event indicates an error.
 */
typedef void (*XSpiPs_StatusHandler) (void *CallBackRef, u32 StatusEvent,
					unsigned ByteCount);

/**
 * This typedef contains configuration information for the device.
 */
typedef struct {
	u16 DeviceId;		/**< Unique ID  of device */
	u32 BaseAddress;	/**< Base address of the device */
	u32 InputClockHz;	/**< Input clock frequency */
} XSpiPs_Config;

/**
 * The XSpiPs driver instance data. The user is required to allocate a
 * variable of this type for every SPI device in the system. A pointer
 * to a variable of this type is then passed to the driver API functions.
 */
typedef struct {
	XSpiPs_Config Config;	 /**< Configuration structure */
	u32 IsReady;		 /**< Device is initialized and ready */

	u8 *SendBufferPtr;	 /**< Buffer to send (state) */
	u8 *RecvBufferPtr;	 /**< Buffer to receive (state) */
	unsigned RequestedBytes; /**< Number of bytes to transfer (state) */
	unsigned RemainingBytes; /**< Number of bytes left to transfer(state) */
	u32 IsBusy;		 /**< A transfer is in progress (state) */
	u32 SlaveSelect;     /**< The slave select value when
					 XSPIPS_FORCE_SSELECT_OPTION is set */

	XSpiPs_StatusHandler StatusHandler;
	void *StatusRef;  	 /**< Callback reference for status handler */

} XSpiPs;

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

/****************************************************************************/
/**
*
* Set the contents of the slave idle count register.
*
* @param	InstancePtr is a pointer to the XSpiPs instance.
* @param	RegisterValue is the value to be writen, valid values are
*		0-65535.
*
* @return	None
*
* @note
* C-Style signature:
*	void XSpiPs_SetSlaveIdle(XSpiPs *InstancePtr, u32 RegisterValue)
*
*****************************************************************************/
#define XSpiPs_SetSlaveIdle(InstancePtr, RegisterValue)	\
	XSpiPs_Out32(((InstancePtr)->Config.BaseAddress) + 	\
		XSPIPS_SICR_OFFSET, (RegisterValue))

/****************************************************************************/
/**
*
* Get the contents of the slave idle count register. Use the XSPIPS_SICR_*
* constants defined in xspips_hw.h to interpret the bit-mask returned.
*
* @param	InstancePtr is a pointer to the XSpiPs instance.
*
* @return	A 32-bit value representing the contents of the SIC register.
*
* @note		C-Style signature:
*		u32 XSpiPs_GetSlaveIdle(XSpiPs *InstancePtr)
*
*****************************************************************************/
#define XSpiPs_GetSlaveIdle(InstancePtr)				\
	XSpiPs_In32(((InstancePtr)->Config.BaseAddress) + 		\
	XSPIPS_SICR_OFFSET)

/****************************************************************************/
/**
*
* Set the contents of the transmit FIFO watermark register.
*
* @param	InstancePtr is a pointer to the XSpiPs instance.
* @param	RegisterValue is the value to be writen, valid values are 0-15.
*
* @return	None.
*
* @note
* C-Style signature:
*	void XSpiPs_GetTXWatermark(XSpiPs *InstancePtr, u32 RegisterValue)
*
*****************************************************************************/
#define XSpiPs_SetTXWatermark(InstancePtr, RegisterValue)		\
	XSpiPs_Out32(((InstancePtr)->Config.BaseAddress) + 		\
		XSPIPS_TXWR_OFFSET, (RegisterValue))

/****************************************************************************/
/**
*
* Get the contents of the transmit FIFO watermark register.
* Use the XSPIPS_TXWR_* constants defined xspips_hw.h to interpret
* the bit-mask returned.
*
* @param	InstancePtr is a pointer to the XSpiPs instance.
*
* @return	A 32-bit value representing the contents of the TXWR register.
*
* @note		C-Style signature:
*		u32 XSpiPs_GetTXWatermark(u32 *InstancePtr)
*
*****************************************************************************/
#define XSpiPs_GetTXWatermark(InstancePtr)				\
	XSpiPs_In32((InstancePtr->Config.BaseAddress) + XSPIPS_TXWR_OFFSET)

/****************************************************************************/
/**
*
* Enable the device and uninhibit master transactions.
*
* @param	BaseAddress is the base address of the device
*
* @return	None.
*
* @note		C-Style signature:
*		void XSpiPs_Enable(u32 BaseAddress)
*
*****************************************************************************/
#define XSpiPs_Enable(BaseAddress)					\
	XSpiPs_Out32((BaseAddress) + XSPIPS_ER_OFFSET, 		\
		XSPIPS_ER_ENABLE_MASK)

/****************************************************************************/
/**
*
* Disable the device.
*
* @param	BaseAddress is the  base address of the device.
*
* @return	None.
*
* @note		C-Style signature:
*		void XSpiPs_Disable(u32 BaseAddress)
*
*****************************************************************************/
#define XSpiPs_Disable(BaseAddress)					\
	XSpiPs_Out32((BaseAddress) + XSPIPS_ER_OFFSET, 0)

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

/*
 * Initialization function, implemented in xspips_sinit.c
 */
XSpiPs_Config *XSpiPs_LookupConfig(u16 DeviceId);

/*
 * Functions implemented in xspips.c
 */
int XSpiPs_CfgInitialize(XSpiPs *InstancePtr, XSpiPs_Config * Config,
				u32 EffectiveAddr);

void XSpiPs_Reset(XSpiPs *InstancePtr);

int XSpiPs_Transfer(XSpiPs *InstancePtr, u8 *SendBufPtr, u8 *RecvBufPtr,
			unsigned ByteCount);

int XSpiPs_PolledTransfer(XSpiPs *InstancePtr, u8 *SendBufPtr,
				u8 *RecvBufPtr, unsigned ByteCount);

void XSpiPs_SetStatusHandler(XSpiPs *InstancePtr, void *CallBackRef,
				XSpiPs_StatusHandler FuncPtr);
void XSpiPs_InterruptHandler(void *InstancePtr);

void XSpiPs_Abort(XSpiPs *InstancePtr);

int XSpiPs_SetSlaveSelect(XSpiPs *InstancePtr, u8 SelectValue);
u8 XSpiPs_GetSlaveSelect(XSpiPs *InstancePtr);

/*
 * Functions for selftest, in xspips_selftest.c
 */
int XSpiPs_SelfTest(XSpiPs *InstancePtr);

/*
 * Functions for options, in xspips_options.c
 */
int XSpiPs_SetOptions(XSpiPs *InstancePtr, u32 Options);
u32 XSpiPs_GetOptions(XSpiPs *InstancePtr);

int XSpiPs_SetClkPrescaler(XSpiPs *InstancePtr, u8 Prescaler);
u8 XSpiPs_GetClkPrescaler(XSpiPs *InstancePtr);

int XSpiPs_SetDelays(XSpiPs *InstancePtr, u8 DelayBtwn, u8 DelayAfter,
			u8 DelayInit);
void XSpiPs_GetDelays(XSpiPs *InstancePtr, u8 *DelayBtwn, u8 *DelayAfter,
			u8 *DelayInit);
#ifdef __cplusplus
}
#endif

#endif /* end of protection macro */

