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

/*****************************************************************************/
/**
*
* @file xiicps.h
* @addtogroup iicps_api IICPS APIs
* @{
* @details
*
*
* <pre> MODIFICATION HISTORY:
*
* Ver   Who     Date     Changes
* ----- ------  -------- -----------------------------------------------
* 1.00a drg/jz  01/30/08 First release
* 1.00a sdm     09/21/11 Fixed an issue in the XIicPs_SetOptions and
*			 XIicPs_ClearOptions where the InstancePtr->Options
*			 was not updated correctly.
* 			 Updated the InstancePtr->Options in the
*			 XIicPs_CfgInitialize by calling XIicPs_GetOptions.
*			 Updated the XIicPs_SetupMaster to not check for
*			 Bus Busy condition when the Hold Bit is set.
*			 Removed some unused variables.
* 1.01a sg      03/30/12 Fixed an issue in XIicPs_MasterSendPolled where a
*			 check for transfer completion is added, which indicates
*			 the completion of current transfer.
* 1.02a sg	08/29/12 Updated the logic to arrive at the best divisors
*			 to achieve I2C clock with minimum error for
*			 CR #674195
* 1.03a hk  05/04/13 Initialized BestDivA and BestDivB to 0.
*			 This is fix for CR#704398 to remove warning.
* 2.0   hk  03/07/14 Added check for error status in the while loop that
*                    checks for completion.
*                    (XIicPs_MasterSendPolled function). CR# 762244, 764875.
*                    Limited frequency set when 100KHz or 400KHz is
*                    selected. This is a hardware limitation. CR#779290.
* 2.1   hk  04/24/14 Fix for CR# 789821 to handle >14 byte transfers.
*                    Explicitly reset CR and clear FIFO in Abort function
*                    and state the same in the comments. CR# 784254.
*                    Fix for CR# 761060 - provision for repeated start.
* 2.2   hk  08/23/14 Slave monitor mode changes - clear FIFO, enable
*                    read mode and clear transfer size register.
*                    Disable NACK to avoid interrupts on each retry.
* 2.3	sk	10/07/14 Repeated start feature deleted.
* 3.0	sk	11/03/14 Modified TimeOut Register value to 0xFF
* 					 in XIicPs_Reset.
* 			12/06/14 Implemented Repeated start feature.
*			01/31/15 Modified the code according to MISRAC 2012 Compliant.
*			02/18/15 Implemented larger data transfer using repeated start
*					  in Zynq UltraScale MP.
* 3.3   kvn 05/05/16 Modified latest code for MISRA-C:2012 Compliance.
*       ms  03/17/17 Added readme.txt file in examples folder for doxygen
*                    generation.
* 3.7   ask  04/17/18 Updated the Eeprom scanning mechanism
*                     as per the other examples (CR#997545)
* 3.8   ask  08/01/18   Fix for Cppcheck and Doxygen warnings
* 3.8   sd 09/06/18  Enable the Timeout interrupt
* 3.9   sg 03/09/19  Added arbitration lost support in polled transfer
* 3.11  rna  12/23/19 Added 10 bit address support for Master/Slave
* 3.11  sd   02/06/20 Added clocking support.
* 3.11  rna  02/20/20 Reorganization of driver for modularity.
*		      Added new files xiicps_xfer.c and xiicps_xfer.h.
*		      Moved internal data transfer APIs to xiicps_xfer.
* 3.13  rna  05/24/21 Fixed Misra-c violations
* 3.16  gm   05/10/22 Added support to get the status of receive valid data.
* 		      Added support for clock stretching and timeout support.
* 3.18  gm   07/14/23 Added SDT support.
* 	sd   09/06/23 Compile refclk for SDT
* 3.23  vlt  12/12/25 Update Doxygen comments to include SDT flow details.
* 3.23  vlt  03/14/26 Updated BaseAddress type from u32 to UINTPTR
*                     to support 64-bit addressing
*       vlt  04/03/26 Added prototype for XIicPs_BusRecovery API.
*
* </pre>
*
******************************************************************************/

#ifndef XIICPS_H       /* prevent circular inclusions */
#define XIICPS_H       /**< by using protection macros */

#ifdef __cplusplus
extern "C" {
#endif

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

#include "xil_types.h"
#include "xil_assert.h"
#if defined  (XCLOCKING)
#include "xil_clocking.h"
#endif
#include "xstatus.h"
#include "xiicps_hw.h"
#include "xplatform_info.h"

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

/** @name Configuration options
 *
 * The following options may be specified or retrieved for the device and
 * enable/disable additional features of the IIC.  Each of the options
 * are bit fields, so more than one may be specified.
 *
 * @{
 */
#define XIICPS_7_BIT_ADDR_OPTION	0x01U  /**< 7-bit address mode */
#define XIICPS_10_BIT_ADDR_OPTION	0x02U  /**< 10-bit address mode */
#define XIICPS_SLAVE_MON_OPTION		0x04U  /**< Slave monitor mode */
#define XIICPS_REP_START_OPTION		0x08U  /**< Repeated Start */


/** @} */

/** @name Callback events
 *
 * These constants specify the handler events that are passed to an application
 * event handler from the driver.  These constants are bit masks such that
 * more than one event can be passed to the handler.
 *
 * @{
 */
#define XIICPS_EVENT_COMPLETE_SEND	0x0001U  /**< Transmit Complete Event*/
#define XIICPS_EVENT_COMPLETE_RECV	0x0002U  /**< Receive Complete Event*/
#define XIICPS_EVENT_TIME_OUT		0x0004U  /**< Transfer timed out */
#define XIICPS_EVENT_ERROR			0x0008U  /**< Receive error */
#define XIICPS_EVENT_ARB_LOST		0x0010U  /**< Arbitration lost */
#define XIICPS_EVENT_NACK			0x0020U  /**< NACK Received */
#define XIICPS_EVENT_SLAVE_RDY		0x0040U  /**< Slave ready */
#define XIICPS_EVENT_RX_OVR			0x0080U  /**< RX overflow */
#define XIICPS_EVENT_TX_OVR			0x0100U  /**< TX overflow */
#define XIICPS_EVENT_RX_UNF			0x0200U  /**< RX underflow */
/** @} */

/** name Role constants
 *
 * These constants are used to pass into the device setup routines to
 * set up the device according to transfer direction.
 */
#define SENDING_ROLE		1  /**< Transfer direction is sending */
#define RECVING_ROLE		0  /**< Transfer direction is receiving */


#define XIICPS_MAX_TRANSFER_SIZE	((u32)255U - (u32)3U) /**< Max transfer size */

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

/**
* The handler data type allows the user to define a callback function to
* respond to interrupt events in the system. This function is executed
* in interrupt context, so that the amount of processing should be minimized.
*
* @param	CallBackRef 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 Indicates one or more status events that occurred.
*/
typedef void (*XIicPs_IntrHandler) (void *CallBackRef, u32 StatusEvent);

/**
 * This typedef contains configuration information for the device.
 */
typedef struct {
#ifndef SDT
	u16 DeviceId;     /**< Unique ID  of device */
#else
	char *Name;       /**< Name of the device */
#endif
	UINTPTR BaseAddress;  /**< Base address of the device */
	u32 InputClockHz; /**< Input clock frequency */
#ifdef SDT
	u16 IntrId;		/**< Bits[11:0] Interrupt-id Bits[15:12]
				 * trigger type and level flags */
	UINTPTR IntrParent;	/**< Bit[0] Interrupt parent type Bit[64/32:1]
				 * Parent base address */
#endif

#if defined  (XCLOCKING) || defined (SDT)
	u32 RefClk;	  /**< Input clocks */
#endif
} XIicPs_Config;

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

	u8 *SendBufferPtr;	/**< Pointer to send buffer */
	u8 *RecvBufferPtr;	/**< Pointer to recv buffer */
	s32 SendByteCount;	/**< Number of bytes still expected to send */
	s32 RecvByteCount;	/**< Number of bytes still expected to receive */
	s32 CurrByteCount;	/**< No. of bytes expected in current transfer */

	s32 UpdateTxSize;	/**< If tx size register has to be updated */
	s32 IsSend;		/**< Whether master is sending or receiving */
	s32 IsRepeatedStart;	/**< Indicates if user set repeated start */
	s32 Is10BitAddr;	/**< Indicates if user set 10 bit address */

	XIicPs_IntrHandler StatusHandler;  /**< Event handler function */
#if defined  (XCLOCKING)
	u32 IsClkEnabled;	/**< Input clock enabled */
#endif
	void *CallBackRef;	/**< Callback reference for event handler */
} XIicPs;

/************************** Variable Definitions *****************************/
extern XIicPs_Config XIicPs_ConfigTable[];	/**< Configuration table */

/***************** Macros (Inline Functions) Definitions *********************/
/****************************************************************************/
/**
*
* This function is to check if Rx data is valid or not.
*
* @param        InstancePtr	Pointer to the XIicPs instance.
*
* @return       returns '1' if Rx data is valid, '0' otherwise.
*
*
******************************************************************************/
static INLINE u32 XIicPs_RxDataValidStatus(XIicPs *InstancePtr)
{
	return ((XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_SR_OFFSET))
				& XIICPS_SR_RXDV_MASK);
}

/****************************************************************************/
/**
* Place one byte into the transmit FIFO.
*
* @param	InstancePtr Pointer to the XIicPs instance.
*
* @return	None.
*
* @note		C-Style signature:
*		void XIicPs_SendByte(XIicPs *InstancePtr)
*
*****************************************************************************/
#define XIicPs_SendByte(InstancePtr)					\
{									\
	u8 Data;							\
	Data = *((InstancePtr)->SendBufferPtr);				\
	 XIicPs_Out32((InstancePtr)->Config.BaseAddress			\
			 + (u32)(XIICPS_DATA_OFFSET), 			\
					(u32)(Data));			\
	(InstancePtr)->SendBufferPtr += 1;				\
	(InstancePtr)->SendByteCount -= 1;\
}

/****************************************************************************/
/**
*
* Receive one byte from FIFO.
*
* @param	InstancePtr Pointer to the XIicPs instance.
*
* @return	None.
*
* @note		C-Style signature:
*		u8 XIicPs_RecvByte(XIicPs *InstancePtr)
*
*****************************************************************************/
#define XIicPs_RecvByte(InstancePtr)					\
{									\
	u8 *Data, Value;						\
	Value = (u8)(XIicPs_In32((InstancePtr)->Config.BaseAddress	\
		  + (u32)XIICPS_DATA_OFFSET));  			\
	Data = &Value;							\
	*(InstancePtr)->RecvBufferPtr = *Data;				\
	(InstancePtr)->RecvBufferPtr += 1;				\
	 (InstancePtr)->RecvByteCount --; 				\
}

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

/**
 * Function for configuration lookup, in xiicps_sinit.c
 */
#ifndef SDT
XIicPs_Config *XIicPs_LookupConfig(u16 DeviceId);
#else
XIicPs_Config *XIicPs_LookupConfig(UINTPTR BaseAddress);
#endif

/**
 * Functions for general setup, in xiicps.c
 * @{
 */
s32 XIicPs_CfgInitialize(XIicPs *InstancePtr, XIicPs_Config * ConfigPtr,
				  u32 EffectiveAddr);

void XIicPs_Abort(XIicPs *InstancePtr);
void XIicPs_Reset(XIicPs *InstancePtr);

s32 XIicPs_BusIsBusy(XIicPs *InstancePtr);
s32 TransmitFifoFill(XIicPs *InstancePtr);
s32 XIicPs_BusRecovery(XIicPs *InstancePtr);
/** @} */

/**
 * Functions for interrupts, in xiicps_intr.c
 */
void XIicPs_SetStatusHandler(XIicPs *InstancePtr, void *CallBackRef,
				  XIicPs_IntrHandler FunctionPtr);

/**
 * Functions for device as master, in xiicps_master.c
 * @{
 */
void XIicPs_MasterSend(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount,
		u16 SlaveAddr);
void XIicPs_MasterRecv(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount,
		u16 SlaveAddr);
s32 XIicPs_MasterSendPolled(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount,
		u16 SlaveAddr);
s32 XIicPs_MasterRecvPolled(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount,
		u16 SlaveAddr);
void XIicPs_EnableSlaveMonitor(XIicPs *InstancePtr, u16 SlaveAddr);
void XIicPs_DisableSlaveMonitor(XIicPs *InstancePtr);
void XIicPs_MasterInterruptHandler(XIicPs *InstancePtr);
/** @} */

/**
 * Functions for device as slave, in xiicps_slave.c
 * @{
 */
void XIicPs_SetupSlave(XIicPs *InstancePtr, u16 SlaveAddr);
void XIicPs_SlaveSend(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount);
void XIicPs_SlaveRecv(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount);
s32 XIicPs_SlaveSendPolled(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount);
s32 XIicPs_SlaveRecvPolled(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount);
void XIicPs_SlaveInterruptHandler(XIicPs *InstancePtr);
void XIicPsSclHold(XIicPs *InstancePtr, u8 Enable);
void XIicPsSetTimeOut(XIicPs *InstancePtr, u8 Value);
/** @} */

/**
 * Functions for selftest, in xiicps_selftest.c
 */
s32 XIicPs_SelfTest(XIicPs *InstancePtr);

/**
 * Functions for setting and getting data rate, in xiicps_options.c
 * @{
 */
s32 XIicPs_SetOptions(XIicPs *InstancePtr, u32 Options);
s32 XIicPs_ClearOptions(XIicPs *InstancePtr, u32 Options);
u32 XIicPs_GetOptions(XIicPs *InstancePtr);

s32 XIicPs_SetSClk(XIicPs *InstancePtr, u32 FsclHz);
u32 XIicPs_GetSClk(XIicPs *InstancePtr);
/** @} */

#ifdef __cplusplus
}
#endif

#endif /* end of protection macro */
/** @} */
