/*
 * Copyright (c) 2019-2022, NVIDIA CORPORATION.  All rights reserved.
 *
 * NVIDIA CORPORATION and its licensors retain all intellectual property
 * and proprietary rights in and to this software, related documentation
 * and any modifications thereto.  Any use, reproduction, disclosure or
 * distribution of this software and related documentation without an express
 * license agreement from NVIDIA CORPORATION is strictly prohibited.
 */

#ifndef I2C__I2C_TEGRA_H
#define I2C__I2C_TEGRA_H
#define FSP__I2C__I2C_TEGRA_H                           1

/* Compiler headers */
#include <stdint.h>
#include <stdbool.h>

/* Early FSP headers */
#include <misc/ct-assert.h>

/* Hardware headers */

/* Late FSP headers */
#include <error/common-errors.h>
#include <misc/macros.h>          // for START_RFD_BLOCK, END_RFD_BLOCK, INLINE_RFD

/* Module-specific FSP headers */
#include <i2c/i2c-config.h>

/** @file i2c-tegra.h */
/*
 * Compile-time check for FSP header files
 *   Each FSP header file contains a signature unique to that file, and the
 *   FSP project.  The CT_ASSERT macro (contained in misc/ct-assert.h) can
 *   check for this signature.  If it does not exist, then the build will
 *   abort.
 *
 *   This is a trap for projects which have their own include files of the
 *   same names, but different contents.  This trap ensures that only the
 *   files from the FSP project, are built into the FSP source code.
 */
#ifndef DOXYGEN_SHOULD_SKIP_THIS
START_RFD_BLOCK(MISRA, DEVIATE, Rule_1_2, "Approval: Bug 200531996, DR: SWE-FSP-009-SWSADR.docx",
                MISRA, DEVIATE, Rule_2_3, "Approval:  On-file, DR: SWE-FSP-010-SWSADR.docx",
                MISRA, DEVIATE, Directive_4_9, "Approval: Bug 200531995, DR: SWE-FSP-012-SWSADR.docx")
CT_ASSERT(FSP__ERROR__COMMON_ERRORS_H, "Header file missing or invalid.")
CT_ASSERT(FSP__MISC__MACROS_H, "Header file missing or invalid.")
END_RFD_BLOCK(MISRA, DEVIATE, Rule_1_2, "Approval: Bug 200531996, DR: SWE-FSP-009-SWSADR.docx",
              MISRA, DEVIATE, Rule_2_3, "Approval:  On-file, DR: SWE-FSP-010-SWSADR.docx",
              MISRA, DEVIATE, Directive_4_9, "Approval: Bug 200531995, DR: SWE-FSP-012-SWSADR.docx")
#endif

/**
 * @defgroup I2C_XFER_FLAGS Flags for I2C transfer
 * @brief Defines for I2C transfer flags constants.
 *
 * @{
 */
/** This flag tells that given transfer is read type i.e master reads data from slave. */
#define I2C_XFER_FLAG_RD                       BIT(0)
/** This flag tells that slave address is 10-bit address. */
#define I2C_XFER_FLAG_TEN                      BIT(1)
/** This flag tells that data transfer happens without repeat start. */
#define I2C_XFER_FLAG_NOSTART                  BIT(2)
/** This flag tells that transfer will continue even if there no ACK from slave. */
#define I2C_XFER_FLAG_IGNORE_NAK               BIT(3)
/** @} */

#define I2C_PKT_XFER_MAX_BYTES                 500U
#define I2C_FIFO_MAX_SIZE_W                    128U
#define I2C_PACKET_HEADER_SIZE_W               3U
#define WORD_TO_BYTES                          4U

// IWYU pragma: no_forward_declare i2c_hw_ops
struct i2c_tegra_handle;
struct i2c_hw_ops;

/**
 * @struct i2c_tegra_handle
 * @brief tegra specific controller data
 *
 * @{
 */
struct i2c_tegra_handle
{
/** Controller id */
    uint32_t ctrl_id;
/** HW specific data which is considered const throughout the unit. */
    const struct i2c_hw_handle *hi2c_hw;
/** Configurable parameters(Clock and HW timing). */
    const struct i2c_config_data *pi2c_config;
/** STate variable for pre-init sequence */
    bool pre_init_done;

    /* used at runtime */
/** suspended state - True; Resumed - False */
    bool is_suspended;
/** initialized state - True; Uninitialized - False */
    bool is_initialized;

    /* transfer specific data */
/** messages being transferred */
    struct i2c_xfer_msg *msgs;
    uint32_t num_msgs;
/** bytes remaining to transfer */
    uint32_t bytes_to_xfer;
/** Status of the current transfer among -<br>
 *  I2C_XFER_REQUESTED <br>
 *  I2C_XFER_STARTED <br>
 *  I2C_XFER_IN_PROGRESS <br>
 *  I2C_XFER_COMPLETED
 */
    uint32_t xfer_status;
/** return value from the irq handler */
    error_t isr_ret;
/** State variable to decide ending transfer */
    bool end_xfer;
/** message index for current message being transferred */
    uint32_t msg_index;
/** msg buffer index for read transfer */
    uint32_t rx_index;
/** msg buffer index for write transfer */
    uint32_t tx_index;
#ifdef I2C_ASYNC_XFER
    bool is_async_xfer;
    i2c_async_callback async_xfer_cb;
    void *client_data;
#endif
};
/** @} */

/**
 * @brief Initialize Tegra I2C controller OS Resources.
 *
 * This function implements the Tegra I2C controller specific OS resources
 * initialization. This function gets the configuration data from the static
 * data in i2c-port.c. If config data is null, corresponding error is returned.
 * Sets pre_init_done to true upon successful pre-init.
 *
 * @param[in]  ctrl_id          I2C Controller ID which need to be initialized.
 *                              The client needs to get the controller ID of
 *                              required I2C bus from i2c-tegra.c.
 * @param[out] hi2c_tegra       Pointer of tegra I2C handle structure where
 *                              tegra specific parameters for an i2c controller
 *                              are stored.
 * @retval E_SUCCESS            Initialization of controller is successful
 * @retval E_INVALID_CONFIG     Null configuration data in i2c-port.c.
 * @retval E_INVALID_PARAM      Input parameter is invalid.
 */
error_t tegra_i2c_pre_init(uint32_t ctrl_id, struct i2c_tegra_handle *hi2c_tegra);

/**
 * @brief Initialize Tegra I2C controller
 *
 * This function implements the Tegra I2C controller specific initialization.
 * This function gets the configuration data from the static data in i2c-port.c
 * If config data is null, corresponding error is returned.
 * Calls tegra_i2c_pre_init internally if pre_init_done not true.
 *
 * @param[in]  ctrl_id          I2C Controller ID which need to be initialized.
 *                              The client needs to get the controller ID of
 *                              required I2C bus from i2c-tegra.c.
 * @param[out] hi2c_tegra       Pointer of tegra I2C handle structure where
 *                              tegra specific parameters for an i2c controller
 *                              are stored.
 * @param[out] hw_ops           Pointer to Pointer of structure of I2C HW
 *                              operations. The HW specific controller driver
 *                              needs to update this structure. I2C core will
 *                              use these HW functions to access the bus and
 *                              configure the controller.
 * @retval E_SUCCESS            Initialization of controller is successful
 * @retval E_INVALID_CONFIG     Null configuration data in i2c-port.c.
 * @retval E_INVALID_PARAM      Input parameter is invalid.
 * @retval E_TIMEOUT            Possible reasons: <br>
 *                              * Flush Fifos failed due to timeout. <br>
 *                              * Failed to load config register.
 */
error_t tegra_i2c_init(uint32_t ctrl_id, struct i2c_tegra_handle *hi2c_tegra,
                   struct i2c_hw_ops **hw_ops);

/**
 * @brief Interrupt handler for the I2C controller
 *
 * This function is used to implement the I2C interrupt handler. This function
 * is called from the R5 ISR handler when I2C controller raises an interrupt.
 * In case the FW uses threaded IRQs feature, THREADED_IRQS feature needs to
 * defined. The FW needs to define the thread supposed to woken in case of the
 * interrupt.
 * The I2C controller raises the interrupt for the following reasons:
 *
 * - Space in Tx FIFO
 * - Data available in Rx FIFO
 * - Current Packet transfer completed.
 * - All Packet transfer completed.
 * - All Packets transfer Completed
 *
 * @param[in] ctrl_id Controller Id for which the interrupt is raised. This is
 *                    provided when interrupt is setup.
 */
void tegra_i2c_irq_handler(uint32_t ctrl_id);

#endif        /* FSP_I2C_I2C_TEGRA_H */
