/***********************************************************************************************************************
 * Copyright [2020-2021] Renesas Electronics Corporation and/or its affiliates.  All Rights Reserved.
 *
 * This software and documentation are supplied by Renesas Electronics America Inc. and may only be used with products
 * of Renesas Electronics Corp. and its affiliates ("Renesas").  No other uses are authorized.  Renesas products are
 * sold pursuant to Renesas terms and conditions of sale.  Purchasers are solely responsible for the selection and use
 * of Renesas products and Renesas assumes no liability.  No license, express or implied, to any intellectual property
 * right is granted by Renesas. This software is protected under all applicable laws, including copyright laws. Renesas
 * reserves the right to change or discontinue this software and/or this documentation. THE SOFTWARE AND DOCUMENTATION
 * IS DELIVERED TO YOU "AS IS," AND RENESAS MAKES NO REPRESENTATIONS OR WARRANTIES, AND TO THE FULLEST EXTENT
 * PERMISSIBLE UNDER APPLICABLE LAW, DISCLAIMS ALL WARRANTIES, WHETHER EXPLICITLY OR IMPLICITLY, INCLUDING WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT, WITH RESPECT TO THE SOFTWARE OR
 * DOCUMENTATION.  RENESAS SHALL HAVE NO LIABILITY ARISING OUT OF ANY SECURITY VULNERABILITY OR BREACH.  TO THE MAXIMUM
 * EXTENT PERMITTED BY LAW, IN NO EVENT WILL RENESAS BE LIABLE TO YOU IN CONNECTION WITH THE SOFTWARE OR DOCUMENTATION
 * (OR ANY PERSON OR ENTITY CLAIMING RIGHTS DERIVED FROM YOU) FOR ANY LOSS, DAMAGES, OR CLAIMS WHATSOEVER, INCLUDING,
 * WITHOUT LIMITATION, ANY DIRECT, CONSEQUENTIAL, SPECIAL, INDIRECT, PUNITIVE, OR INCIDENTAL DAMAGES; ANY LOST PROFITS,
 * OTHER ECONOMIC DAMAGE, PROPERTY DAMAGE, OR PERSONAL INJURY; AND EVEN IF RENESAS HAS BEEN ADVISED OF THE POSSIBILITY
 * OF SUCH LOSS, DAMAGES, CLAIMS OR COSTS.
 **********************************************************************************************************************/

/***********************************************************************************************************************
 * Includes
 **********************************************************************************************************************/
#include "mcu_i2c.h"
#include "r_iic_master.h"
#if IIC_MASTER_CFG_DTC_ENABLE
 #include "r_dtc.h"
#endif



//////////////////////////////////////////////////////////////////////
///
#include <trace_probes.h>
#ifndef trace_iic_start
trace_need(iic_start)
trace_need(iic_txi)
trace_need(iic_tei)
trace_need(iic_rxi)
trace_need(iic_ei)
trace_need(iic_ei_ss)
#endif
#ifndef trace_iic_rnack
trace_need(iic_rnack)           // recv master infers nack status
trace_need(iic_rnack_spure)     // recv master unexpeted infers nack status
#endif


//////////////////////////////////////////////////////////////////////



/***********************************************************************************************************************
 * Macro definitions
 **********************************************************************************************************************/

/* "IIC" in ASCII, used to determine if channel is open. */
#define IIC_MASTER_OPEN                             (0x52494943U)

#define I2C_CODE_READ                               (0x01U)
#define I2C_CODE_10BIT                              (0xF0U)

/* The timeout interrupt enable bit */
#define IIC_MASTER_TMO_EN_BIT                       (0x01)

/* The arbitration loss detection interrupt enable bit */
#define IIC_MASTER_ALD_EN_BIT                       (0x02)

/* The start condition detection interrupt enable bit */
#define IIC_MASTER_STR_EN_BIT                       (0x04)

/* The stop condition detection interrupt enable bit */
#define IIC_MASTER_STP_EN_BIT                       (0x08)

/* The NAK reception interrupt enable bit */
#define IIC_MASTER_NAK_EN_BIT                       (0x10)

/* The receive data full interrupt enable bit */
#define IIC_MASTER_RXI_EN_BIT                       (0x20)

/* The transmit end interrupt enable bit */
#define IIC_MASTER_TEI_EN_BIT                       (0x40)

/* The transmit data empty interrupt enable bit */
#define IIC_MASTER_TXI_EN_BIT                       (0x80)

/* Bit position for STOP condition flag in ICSR2 */
#define IIC_MASTER_ICSR2_STOP_BIT                   (0x08U)

#define IIC_MASTER_BUS_RATE_REG_RESERVED_BITS       (0xE0U)
#define IIC_MASTER_INTERNAL_REF_CLOCK_SELECT_MAX    (0x07U)

#define IIC_MASTER_SLAVE_10_BIT_ADDR_LEN_ADJUST     (2U)

#define IIC_MASTER_DTC_RX_TRANSFER_SETTINGS         ((TRANSFER_MODE_NORMAL << TRANSFER_SETTINGS_MODE_BITS) |         \
                                                     (TRANSFER_SIZE_1_BYTE << TRANSFER_SETTINGS_SIZE_BITS) |         \
                                                     (TRANSFER_ADDR_MODE_FIXED << TRANSFER_SETTINGS_SRC_ADDR_BITS) | \
                                                     (TRANSFER_IRQ_END << TRANSFER_SETTINGS_IRQ_BITS) |              \
                                                     (TRANSFER_ADDR_MODE_INCREMENTED <<                              \
                                                      TRANSFER_SETTINGS_DEST_ADDR_BITS))
#define IIC_MASTER_DTC_TX_TRANSFER_SETTINGS         ((TRANSFER_MODE_NORMAL << TRANSFER_SETTINGS_MODE_BITS) | \
                                                     (TRANSFER_SIZE_1_BYTE << TRANSFER_SETTINGS_SIZE_BITS) | \
                                                     (TRANSFER_ADDR_MODE_INCREMENTED <<                      \
                                                      TRANSFER_SETTINGS_SRC_ADDR_BITS) |                     \
                                                     (TRANSFER_IRQ_END << TRANSFER_SETTINGS_IRQ_BITS) |      \
                                                     (TRANSFER_ADDR_MODE_FIXED << TRANSFER_SETTINGS_DEST_ADDR_BITS))
#define IIC_MASTER_FUNCTION_ENABLE_REG_VAL          (0x02U)
#define IIC_MASTER_INTERRUPT_ENABLE_INIT_MASK       ( IIC_MASTER_TXI_EN_BIT| IIC_MASTER_RXI_EN_BIT \
                                                    | IIC_MASTER_NAK_EN_BIT \
                                                    | IIC_MASTER_TMO_EN_BIT | IIC_MASTER_ALD_EN_BIT )
#define IIC_MASTER_FUNCTION_ENABLE_INIT_SETTINGS    (0x77U)
#define IIC_MASTER_STATUS_REGISTER_2_ERR_MASK       (0x1FU)
#define IIC_MASTER_BUS_MODE_REGISTER_1_MASK         (0x08U)
#define IIC_MASTER_BUS_MODE_REGISTER_2_MASK         (0x04U)
#define IIC_MASTER_SYSDIVCK_ICLK_MASK               (0x0F000000U)
#define IIC_MASTER_SYSDIVCK_PCLKB_MASK              (0x00000F00U)

#define IIC_MASTER_PRV_SCL_SDA_NOT_DRIVEN           (0x1FU)

//  SDAI | SCLI
#define IIC_MASTER_ICCR1_LINEIN_BIT_MASK            (0x03)
#define IIC_MASTER_ICCR1_LINE_OFFLINE               (0x03)
#define IIC_MASTER_ICCR1_ICE_BIT_MASK               (0x80)
#define IIC_MASTER_ICCR1_IICRST_BIT_MASK            (0x40)
#define IIC_MASTER_ICCR2_SP_BIT_MASK                (0x08)
#define IIC_MASTER_ICCR2_RS_BIT_MASK                (0x04)
#define IIC_MASTER_ICCR2_ST_BIT_MASK                (0x02)

#define IIC_MASTER_ICCR2_MODE_MASTER                (0x40)
#define IIC_MASTER_ICCR2_MODE_SLAVE                 (0x20)
#define IIC_MASTER_ICCR2_MODE_MASK                  (IIC_MASTER_ICCR2_MODE_SLAVE | IIC_MASTER_ICCR2_MODE_MASTER)
#define IIC_MASTER_ICMR1_WP_MODE_BIT                (0x02)


/* Worst case ratio of (ICLK/PCLKB) = 64 bytes approximately.
 * 3 PCLKB cycles is the number of cycles to wait for IICn.
 * Refer "Table 3.2 Access cycles (1 of 2)" of the RA6M3 manual R01UH0886EJ0100)
 */
#define IIC_MASTER_PERIPHERAL_REG_MAX_WAIT          (0x40U * 0x03U)

#define IIC_MASTER_HARDWARE_REGISTER_WAIT(reg, required_value, timeout) \
    while ((timeout))                                                   \
    {                                                                   \
        if ((required_value) == (reg))                                  \
        {                                                               \
            break;                                                      \
        }                                                               \
        (timeout)--;                                                    \
    }

/***********************************************************************************************************************
 * Typedef definitions
 **********************************************************************************************************************/

/* Hardware errors and events that can occur on the IIC */
typedef enum e_iic_master_err_event
{
    IIC_MASTER_ERR_EVENT_NONE             = 0,
    IIC_MASTER_ERR_EVENT_TIMEOUT          = 1,
    IIC_MASTER_ERR_EVENT_ARBITRATION_LOSS = 2,
    IIC_MASTER_ERR_EVENT_START            = 4,
    IIC_MASTER_ERR_EVENT_STOP             = 8,
    IIC_MASTER_ERR_EVENT_NACK             = 16
} iic_master_err_t;

/* IIC read/write enumeration */
typedef enum e_iic_master_transfer_dir_option
{
    IIC_MASTER_TRANSFER_DIR_WRITE = 0x0,
    IIC_MASTER_TRANSFER_DIR_READ  = 0x1
} iic_master_transfer_dir_t;

#if defined(__ARMCC_VERSION) || defined(__ICCARM__)
typedef void (BSP_CMSE_NONSECURE_CALL * iic_master_prv_ns_callback)(i2c_master_callback_args_t * p_args);
#elif defined(__GNUC__)
typedef BSP_CMSE_NONSECURE_CALL void (*volatile iic_master_prv_ns_callback)(i2c_master_callback_args_t * p_args);
#endif

/***********************************************************************************************************************
 * Private function prototypes
 **********************************************************************************************************************/

void iic_master_rxi_isr(void);
void iic_master_txi_isr(void);
void iic_master_tei_isr(void);
void iic_master_eri_isr(void);

/* Internal helper functions */
static void      iic_master_abort_seq_master(iic_master_instance_ctrl_t * const p_ctrl, bool iic_reset);
static fsp_err_t iic_master_read_write(i2c_master_ctrl_t * const p_api_ctrl,
                                       void* p_buffer, uint32_t bytes,
                                       iic_master_transfer_dir_t direction);
static fsp_err_t iic_master_continue(i2c_master_ctrl_t * const p_api_ctrl, void* p_buffer, uint32_t bytes);
static bool iic_master_continue_ok(i2c_master_ctrl_t * const p_api_ctrl);

void iic_master_notify(iic_master_instance_ctrl_t * const p_ctrl, i2c_master_event_t const event);

#if IIC_MASTER_CFG_DTC_ENABLE
static fsp_err_t iic_master_transfer_open(iic_master_instance_ctrl_t * p_ctrl, i2c_master_cfg_t const * const p_cfg);
static fsp_err_t iic_master_transfer_configure(iic_master_instance_ctrl_t * p_ctrl,
                                               transfer_instance_t const  * p_transfer,
                                               iic_master_transfer_dir_t    direction);
#endif

/* Interrupt handlers */
static void iic_master_rxi_master(iic_master_instance_ctrl_t * p_ctrl);
static void iic_master_txi_master(iic_master_instance_ctrl_t * p_ctrl);
static void iic_master_tei_master(iic_master_instance_ctrl_t * p_ctrl);
static void iic_master_err_master(iic_master_instance_ctrl_t * p_ctrl);

/* Functions that manipulate hardware */
static void iic_master_open_hw_master(iic_master_instance_ctrl_t * const p_ctrl,
                                      i2c_master_cfg_t const * const     p_cfg);
//static
fsp_err_t iic_master_run_hw_master(iic_master_instance_ctrl_t * const p_ctrl);
static void      iic_master_rxi_read_data(iic_master_instance_ctrl_t * const p_ctrl);
static void      iic_master_txi_send_address(iic_master_instance_ctrl_t * const p_ctrl);

/***********************************************************************************************************************
 * Private global variables
 **********************************************************************************************************************/

/***********************************************************************************************************************
 * Global variables
 **********************************************************************************************************************/

/* IIC Implementation of I2C device master interface */
i2c_master_api_t const g_i2c_master_on_iic =
{
    .open            = R_IIC_MASTER_Open,
    .read            = R_IIC_MASTER_Read,
    .write           = R_IIC_MASTER_Write,
    .abort           = R_IIC_MASTER_Abort,
    .slaveAddressSet = R_IIC_MASTER_SlaveAddressSet,
    .close           = R_IIC_MASTER_Close,
    .statusGet       = R_IIC_MASTER_StatusGet,
    .callbackSet     = R_IIC_MASTER_CallbackSet
};

/*******************************************************************************************************************//**
 * @addtogroup IIC_MASTER
 * @{
 **********************************************************************************************************************/

/***********************************************************************************************************************
 * Functions
 **********************************************************************************************************************/

/*******************************************************************************************************************//**
 * Opens the I2C device.
 *
 * @retval  FSP_SUCCESS                       Requested clock rate was set exactly.
 * @retval  FSP_ERR_ALREADY_OPEN              Module is already open.
 * @retval  FSP_ERR_IP_CHANNEL_NOT_PRESENT    Channel is not available on this MCU.
 * @retval  FSP_ERR_ASSERTION                 Parameter check failure due to one or more reasons below:
 *                                            1. p_api_ctrl or p_cfg is NULL.
 *                                            2. extended parameter is NULL.
 *                                            3. Callback parameter is NULL.
 *                                            4. Set the rate to fast mode plus on a channel which does not support it.
 *                                            5. Invalid IRQ number assigned
 **********************************************************************************************************************/
fsp_err_t R_IIC_MASTER_Open (i2c_master_ctrl_t * const p_api_ctrl, i2c_master_cfg_t const * const p_cfg)
{
    iic_master_instance_ctrl_t * p_ctrl = (iic_master_instance_ctrl_t *) p_api_ctrl;
#if IIC_MASTER_CFG_PARAM_CHECKING_ENABLE
    FSP_ASSERT(p_api_ctrl != NULL);
    FSP_ASSERT(p_cfg != NULL);
    FSP_ASSERT(p_cfg->p_extend != NULL);
    FSP_ASSERT(p_cfg->rxi_irq >= (IRQn_Type) 0);
    FSP_ASSERT(p_cfg->txi_irq >= (IRQn_Type) 0);
    FSP_ASSERT(p_cfg->tei_irq >= (IRQn_Type) 0);
    FSP_ASSERT(p_cfg->eri_irq >= (IRQn_Type) 0);
    FSP_ERROR_RETURN(IIC_MASTER_OPEN != p_ctrl->open, FSP_ERR_ALREADY_OPEN);

    FSP_ERROR_RETURN(BSP_FEATURE_IIC_VALID_CHANNEL_MASK & (1 << p_cfg->channel), FSP_ERR_IP_CHANNEL_NOT_PRESENT);

    /* If rate is configured as Fast mode plus, check whether the channel supports it */
    if (I2C_MASTER_RATE_FASTPLUS == p_cfg->rate)
    {
        FSP_ASSERT((BSP_FEATURE_IIC_FAST_MODE_PLUS & (1U << p_cfg->channel)));
    }
#endif
#if IIC_MASTER_CFG_DTC_ENABLE
    fsp_err_t err = FSP_SUCCESS;
#endif

    p_ctrl->p_reg = (R_IIC0_Type *) ((uint32_t) R_IIC0 + (p_cfg->channel * ((uint32_t) R_IIC1 - (uint32_t) R_IIC0)));

    /* Record the pointer to the configuration structure for later use */
    p_ctrl->p_cfg             = p_cfg;
    p_ctrl->slave             = p_cfg->slave;
    p_ctrl->addr_mode         = p_cfg->addr_mode;
    p_ctrl->p_callback        = p_cfg->p_callback;
    p_ctrl->p_context         = p_cfg->p_context;
    p_ctrl->p_callback_memory = NULL;

    R_BSP_MODULE_START(FSP_IP_IIC, p_cfg->channel);

    /* Open the hardware in master mode. Performs IIC initialization as described in hardware manual (see Section 36.3.2
     * 'Initial Settings' of the RA6M3 manual R01UH0886EJ0100). */
    iic_master_open_hw_master(p_ctrl, p_cfg);

#if IIC_MASTER_CFG_DTC_ENABLE

    /* Open the IIC transfer interface if available */
    err = iic_master_transfer_open(p_ctrl, p_cfg);
    if (FSP_SUCCESS != err)
    {
        R_BSP_MODULE_STOP(FSP_IP_IIC, p_cfg->channel);

        return err;
    }
#endif

    p_ctrl->p_buff    = NULL;
    p_ctrl->total     = 0U;
    p_ctrl->remain    = 0U;
    p_ctrl->loaded    = 0U;
    p_ctrl->read      = false;
    p_ctrl->restart   = false;
    p_ctrl->err       = 0;
    p_ctrl->errs_events=0;
    p_ctrl->restarted = false;
    p_ctrl->open      = IIC_MASTER_OPEN;

    return FSP_SUCCESS;
}

/*******************************************************************************************************************//**
 * Performs a read from the I2C device.
 * The caller will be notified when the operation has completed (successfully) by an
 * I2C_MASTER_EVENT_RX_COMPLETE in the callback.
 *
 * @retval  FSP_SUCCESS             Function executed without issue.
 * @retval  FSP_ERR_ASSERTION       p_api_ctrl, p_dest or bytes is NULL.
 * @retval  FSP_ERR_INVALID_SIZE    Provided number of bytes more than uint16_t size (65535) while DTC is used
 *                                  for data transfer.
 * @retval  FSP_ERR_IN_USE          Bus busy condition. Another transfer was in progress.
 * @retval  FSP_ERR_NOT_OPEN        Handle is not initialized.  Call R_IIC_MASTER_Open to initialize the control block.
 **********************************************************************************************************************/
fsp_err_t R_IIC_MASTER_Read (i2c_master_ctrl_t * const p_api_ctrl,
                                void* p_dest, uint32_t bytes, i2c_master_xfer_mode_t restart)
{
#if IIC_MASTER_CFG_PARAM_CHECKING_ENABLE
    FSP_ASSERT(p_api_ctrl != NULL);
    FSP_ASSERT(bytes != 0U);
#endif

#if 1
    // only write continue supports now
    FSP_ASSERT( (restart & I2C_MASTER_CONTINUE) == 0 );
    // only writes bus keep supports now
    FSP_ASSERT( ((restart & I2C_MASTER_DONE_MODE) < I2C_MASTER_BUS_KEEP) );
#else
    if ((restart & I2C_MASTER_CONTINUE) != 0){
        // only write continue supports now
        return FSP_ERR_INVALID_MODE;
    }
    if ((restart & I2C_MASTER_DONE_MODE) >= I2C_MASTER_BUS_KEEP){
        // only writes bus keep supports now
        return FSP_ERR_INVALID_MODE;
    }
#endif

    fsp_err_t err = FSP_SUCCESS;

    iic_master_instance_ctrl_t * p_ctrl = (iic_master_instance_ctrl_t *)p_api_ctrl;

    /* Record the restart information about this transfer.
     * This is done here to keep the parameter (argument) list of iic_master_read_write to 4. */
    p_ctrl->restart = restart & I2C_MASTER_DONE_MODE;

    err = iic_master_read_write(p_api_ctrl, p_dest, bytes, IIC_MASTER_TRANSFER_DIR_READ);

    return err;
}

/*******************************************************************************************************************//**
 * Performs a write to the I2C device.
 * The caller will be notified when the operation has completed (successfully) by an
 * I2C_MASTER_EVENT_TX_COMPLETE in the callback.
 *
 * @retval  FSP_SUCCESS           Function executed without issue.
 * @retval  FSP_ERR_ASSERTION     p_api_ctrl or p_src is NULL.
 * @retval  FSP_ERR_INVALID_SIZE  Provided number of bytes more than uint16_t size (65535) while DTC is used
 *                                for data transfer.
 * @retval  FSP_ERR_IN_USE        Bus busy condition. Another transfer was in progress.
 * @retval  FSP_ERR_NOT_OPEN      Handle is not initialized.  Call R_IIC_MASTER_Open to initialize the control block.
 **********************************************************************************************************************/
fsp_err_t R_IIC_MASTER_Write (i2c_master_ctrl_t * const p_api_ctrl,
                              const void* p_src, uint32_t bytes, i2c_master_xfer_mode_t  restart)
{
#if IIC_MASTER_CFG_PARAM_CHECKING_ENABLE
    FSP_ASSERT(p_api_ctrl != NULL);
#endif
    fsp_err_t err = FSP_SUCCESS;

    iic_master_instance_ctrl_t * p_ctrl = (iic_master_instance_ctrl_t *)p_api_ctrl;

    if ((restart & I2C_MASTER_CONTINUE) != 0){
        if (p_ctrl->read)
            return FSP_ERR_INVALID_MODE;

        if (!iic_master_continue_ok(p_api_ctrl)){
            // bus not locked by master, so can't continue transfer
            return FSP_ERR_INVALID_HW_CONDITION;
        }
    }

    /* Record the restart information about this transfer.
     * This is done here to keep the parameter (argument) list of iic_master_read_write to 4. */
    p_ctrl->restart = restart & I2C_MASTER_DONE_MODE;

    /* Call the common helper function to perform I2C Write operation.*/
    if ((restart & I2C_MASTER_CONTINUE) == 0)
        err = iic_master_read_write(p_api_ctrl, (void*)p_src, bytes, IIC_MASTER_TRANSFER_DIR_WRITE);
    else
        err = iic_master_continue(p_api_ctrl, (void*)p_src, bytes);

    return err;
}

/*******************************************************************************************************************//**
 * Safely aborts any in-progress transfer and forces the IIC peripheral into ready state.
 *
 *
 * @retval  FSP_SUCCESS             Channel was reset successfully.
 * @retval  FSP_ERR_ASSERTION       p_api_ctrl is NULL.
 * @retval  FSP_ERR_NOT_OPEN        Handle is not initialized.  Call R_IIC_MASTER_Open to initialize the control block.
 *
 * @note A callback will not be invoked in case an in-progress transfer gets aborted by calling this API.
 **********************************************************************************************************************/
fsp_err_t R_IIC_MASTER_Abort (i2c_master_ctrl_t * const p_api_ctrl)
{
    iic_master_instance_ctrl_t * p_ctrl = (iic_master_instance_ctrl_t *) p_api_ctrl;

#if IIC_MASTER_CFG_PARAM_CHECKING_ENABLE
    FSP_ASSERT(p_ctrl != NULL);
    FSP_ERROR_RETURN(IIC_MASTER_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
#endif

    /* Abort any transfer happening on the channel */
    iic_master_abort_seq_master(p_ctrl, true);

    return FSP_SUCCESS;
}

/*******************************************************************************************************************//**
 * Sets address and addressing mode of the slave device.
 * This function is used to set the device address and addressing mode of the slave
 * without reconfiguring the entire bus.
 *
 * @retval  FSP_SUCCESS             Address of the slave is set correctly.
 * @retval  FSP_ERR_ASSERTION       Pointer to control structure is NULL.
 * @retval  FSP_ERR_IN_USE          Another transfer was in-progress.
 * @retval  FSP_ERR_NOT_OPEN        Handle is not initialized.  Call R_IIC_MASTER_Open to initialize the control block.
 **********************************************************************************************************************/
fsp_err_t R_IIC_MASTER_SlaveAddressSet (i2c_master_ctrl_t * const    p_api_ctrl,
                                        uint32_t const               slave,
                                        i2c_master_addr_mode_t const addr_mode)
{
    iic_master_instance_ctrl_t * p_ctrl = (iic_master_instance_ctrl_t *) p_api_ctrl;

    fsp_err_t err = FSP_SUCCESS;

#if IIC_MASTER_CFG_PARAM_CHECKING_ENABLE
    FSP_ASSERT(p_ctrl != NULL);
    FSP_ERROR_RETURN(IIC_MASTER_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);

    /* Fail if there is already a transfer in progress */
    FSP_ERROR_RETURN(((0 == p_ctrl->remain) && (false == p_ctrl->restart)), FSP_ERR_IN_USE);
#endif

    /* Sets the address of the slave device */
    p_ctrl->slave = slave;

    /* Sets the mode of addressing */
    p_ctrl->addr_mode = addr_mode;

    return err;
}


/*******************************************************************************************************************//**
 * Provides driver status.
 *
 * @retval     FSP_SUCCESS                   Status stored in p_status.
 * @retval     FSP_ERR_ASSERTION             NULL pointer.
 **********************************************************************************************************************/
fsp_err_t R_IIC_MASTER_StatusGet (i2c_master_ctrl_t * const p_api_ctrl, i2c_master_status_t * p_status)
{
    iic_master_instance_ctrl_t * p_ctrl = (iic_master_instance_ctrl_t *) p_api_ctrl;

#if IIC_MASTER_CFG_PARAM_CHECKING_ENABLE
    FSP_ASSERT(p_ctrl != NULL);
    FSP_ASSERT(p_status != NULL);
#endif

    p_status->open = (IIC_MASTER_OPEN == p_ctrl->open);
    if (p_status->open) {

        p_status->pended = p_ctrl->addr_remain + p_ctrl->remain;

    #if IIC_MASTER_CFG_DTC_ENABLE
        if (p_ctrl->activation_on_txi){
            if (NULL != p_ctrl->dma_tx){
                transfer_info_t * tx_info = p_ctrl->p_cfg->p_transfer_tx->p_cfg->p_info;
                if (NULL != tx_info)
                    p_status->pended += tx_info->length;
            }
        }
    #endif

    }
    else
        p_status->pended = 0;

    return FSP_SUCCESS;
}

/*******************************************************************************************************************//**
 * Updates the user callback and has option of providing memory for callback structure.
 * Implements i2c_master_api_t::callbackSet
 *
 * @retval  FSP_SUCCESS                  Callback updated successfully.
 * @retval  FSP_ERR_ASSERTION            A required pointer is NULL.
 * @retval  FSP_ERR_NOT_OPEN             The control block has not been opened.
 * @retval  FSP_ERR_NO_CALLBACK_MEMORY   p_callback is non-secure and p_callback_memory is either secure or NULL.
 **********************************************************************************************************************/
fsp_err_t R_IIC_MASTER_CallbackSet (i2c_master_ctrl_t * const          p_api_ctrl,
                                    void (                           * p_callback)(i2c_master_callback_args_t *),
                                    void const * const                 p_context,
                                    i2c_master_callback_args_t * const p_callback_memory)
{
    iic_master_instance_ctrl_t * p_ctrl = (iic_master_instance_ctrl_t *) p_api_ctrl;

#if (IIC_MASTER_CFG_PARAM_CHECKING_ENABLE)
    FSP_ASSERT(p_ctrl);
    FSP_ASSERT(p_callback);
    FSP_ERROR_RETURN(IIC_MASTER_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
#endif

#if BSP_TZ_SECURE_BUILD

    /* Get security state of p_callback */
    bool callback_is_secure =
        (NULL == cmse_check_address_range((void *) p_callback, sizeof(void *), CMSE_AU_NONSECURE));

 #if IIC_MASTER_CFG_PARAM_CHECKING_ENABLE

    /* In secure projects, p_callback_memory must be provided in non-secure space if p_callback is non-secure */
    i2c_master_callback_args_t * const p_callback_memory_checked = cmse_check_pointed_object(p_callback_memory,
                                                                                             CMSE_AU_NONSECURE);
    FSP_ERROR_RETURN(callback_is_secure || (NULL != p_callback_memory_checked), FSP_ERR_NO_CALLBACK_MEMORY);
 #endif
#endif

    /* Store callback and context */
#if BSP_TZ_SECURE_BUILD
    p_ctrl->p_callback = callback_is_secure ? p_callback :
                         (void (*)(i2c_master_callback_args_t *))cmse_nsfptr_create(p_callback);
#else
    p_ctrl->p_callback = p_callback;
#endif
    p_ctrl->p_context         = p_context;
    p_ctrl->p_callback_memory = p_callback_memory;

    return FSP_SUCCESS;
}

/*******************************************************************************************************************//**
 * Closes the I2C device. May power down IIC peripheral.
 * This function will safely terminate any in-progress I2C transfers.
 *
 * @retval  FSP_SUCCESS         Device closed without issue.
 * @retval  FSP_ERR_ASSERTION   p_api_ctrl is NULL.
 * @retval  FSP_ERR_NOT_OPEN    Handle is not initialized.  Call R_IIC_MASTER_Open to initialize the control block.
 *
 * @note A callback will not be invoked in case an in-progress transfer gets aborted by calling this API.
 **********************************************************************************************************************/
fsp_err_t R_IIC_MASTER_Close (i2c_master_ctrl_t * const p_api_ctrl)
{
    iic_master_instance_ctrl_t * p_ctrl = (iic_master_instance_ctrl_t *) p_api_ctrl;
    i2c_master_cfg_t const *     p_cfg = p_ctrl->p_cfg;

#if IIC_MASTER_CFG_PARAM_CHECKING_ENABLE
    FSP_ASSERT(p_ctrl != NULL);
    FSP_ERROR_RETURN(IIC_MASTER_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
#endif

    /* Abort an in-progress transfer with this device only */
    iic_master_abort_seq_master(p_ctrl, true);

    /* Disable I2C interrupts. Described in hardware manual (see Section 36.2.8
     * 'I2C Bus Interrupt Enable Register (ICIER)' of the RA6M3 manual R01UH0886EJ0100). */
    p_ctrl->p_reg->ICIER = 0x00;

    /* The device is now considered closed */
    p_ctrl->open = 0U;

#if IIC_MASTER_CFG_DTC_ENABLE

    /* Close the handles for the transfer interfaces */
    if (NULL != p_ctrl->dma_rx)
    {
        iic_dma_close(p_cfg->p_transfer_rx)( p_ctrl->dma_rx);
        p_ctrl->dma_rx = NULL;
    }

    if (NULL != p_ctrl->dma_tx)
    {
        iic_dma_close(p_cfg->p_transfer_tx)( p_ctrl->dma_tx);
        p_ctrl->dma_tx = NULL;
    }
#endif

    R_BSP_IrqDisable(p_cfg->eri_irq);
    R_BSP_IrqDisable(p_cfg->rxi_irq);
    R_BSP_IrqDisable(p_cfg->tei_irq);
    R_BSP_IrqDisable(p_cfg->txi_irq);

    R_BSP_MODULE_STOP(FSP_IP_IIC, p_cfg->channel);

    return FSP_SUCCESS;
}

/*******************************************************************************************************************//**
 * @} (end addtogroup IIC_MASTER)
 **********************************************************************************************************************/

/***********************************************************************************************************************
 * Private Functions
 **********************************************************************************************************************/

/*******************************************************************************************************************//**
 * Helper function for handling I2C Read or Write.
 *
 * @param      p_api_ctrl      Pointer to control block
 * @param      p_buffer        Pointer to the buffer to store read/write data.
 * @param[in]  bytes           Number of bytes to be read/written.
 * @param[in]  direction       Read or Write
 *
 * @retval  FSP_SUCCESS           Function executed successfully.
 * @retval  FSP_ERR_ASSERTION     p_api_ctrl or p_buffer is NULL.
 * @retval  FSP_ERR_INVALID_SIZE  Provided number of bytes more than UINT16_MAX(= 65535) while DTC is used
 *                                for data transfer.
 * @retval  FSP_ERR_IN_USE        Another transfer was in progress.
 * @retval  FSP_ERR_NOT_OPEN      Handle is not initialized. Call R_IIC_MASTER_Open to initialize the control block.
 **********************************************************************************************************************/
static fsp_err_t iic_master_read_write (i2c_master_ctrl_t * const p_api_ctrl,
                                        void*                       p_buffer,
                                        uint32_t const            bytes,
                                        iic_master_transfer_dir_t direction)
{
    iic_master_instance_ctrl_t * p_ctrl = (iic_master_instance_ctrl_t *) p_api_ctrl;

#if IIC_MASTER_CFG_PARAM_CHECKING_ENABLE
    FSP_ASSERT(p_buffer != NULL);
    FSP_ERROR_RETURN((p_ctrl->open == IIC_MASTER_OPEN), FSP_ERR_NOT_OPEN);
    FSP_ASSERT(((iic_master_instance_ctrl_t *) p_api_ctrl)->p_callback != NULL);
 #if IIC_MASTER_CFG_DTC_ENABLE

    /* DTC on RX could actually receive 65535+3 = 65538 bytes as 3 bytes are handled separately.
     * Forcing to 65535 to keep TX and RX uniform with respect to max transaction length via DTC.
     */
    FSP_ERROR_RETURN((bytes <= UINT16_MAX), FSP_ERR_INVALID_SIZE);
 #endif
#endif

    fsp_err_t err = FSP_SUCCESS;

    p_ctrl->p_buff = (uint8_t*)p_buffer;
    p_ctrl->total  = bytes;

    /* Handle the (different) addressing mode(s) */
    if (p_ctrl->addr_mode == I2C_MASTER_ADDR_MODE_7BIT)
    {
        /* Set the address bytes according to a 7-bit slave read command */
        p_ctrl->addr_high  = 0U;
        p_ctrl->addr_low   = (uint8_t) ((p_ctrl->slave << 1U) | (uint8_t) direction);
        p_ctrl->addr_total = 1U;
    }

#if IIC_MASTER_CFG_ADDR_MODE_10_BIT_ENABLE
    else
    {
        /* Set the address bytes according to a 10-bit slave read command */
        p_ctrl->addr_high = (uint8_t) (((p_ctrl->slave >> 7U) | I2C_CODE_10BIT) & (uint8_t) ~(I2C_CODE_READ));
        p_ctrl->addr_low  = (uint8_t) p_ctrl->slave;

        /* Addr total = 3 for Read and 2 for Write.
         * See Section 36.3.1 "Communication Data Format" of the RA6M3 manual R01UH0886EJ0100
         */
        p_ctrl->addr_total = (uint8_t) ((uint8_t) direction + IIC_MASTER_SLAVE_10_BIT_ADDR_LEN_ADJUST);
    }
#else
    else
        return FSP_ERR_INVALID_ADDRESS;
#endif

    p_ctrl->read = (bool) direction;

    /* Kickoff the read operation as a master */
    err = iic_master_run_hw_master(p_ctrl);

    FSP_ERROR_RETURN(FSP_SUCCESS == err, err);

    return FSP_SUCCESS;
}

static bool iic_master_continue_ok(i2c_master_ctrl_t * const p_api_ctrl){
    iic_master_instance_ctrl_t * p_ctrl = (iic_master_instance_ctrl_t *) p_api_ctrl;
    I2C_TypeDef*                p_reg = p_ctrl->p_reg;
    return (p_reg->ICCR2_b.BBSY != 0);
}

static
fsp_err_t iic_master_continue(i2c_master_ctrl_t * const p_api_ctrl, void* p_buffer, uint32_t bytes){
    iic_master_instance_ctrl_t * p_ctrl = (iic_master_instance_ctrl_t *) p_api_ctrl;
    //I2C_TypeDef*                p_reg = p_ctrl->p_reg;

    fsp_err_t err = FSP_SUCCESS;

    p_ctrl->p_buff      = (uint8_t*)p_buffer;
    p_ctrl->total       = bytes;
    --p_ctrl->total;
    p_ctrl->addr_low    = *p_ctrl->p_buff++;
    p_ctrl->addr_total  = 1;
    p_ctrl->addr_remain = 1;

    /* Kickoff the read operation as a master */
    err = iic_master_run_hw_master(p_ctrl);

    FSP_ERROR_RETURN(FSP_SUCCESS == err, err);

    return FSP_SUCCESS;
}

/*******************************************************************************************************************//**
 * Single point for managing the logic around notifying a transfer has finished.
 *
 * @param[in]       p_ctrl      Pointer to transfer that is ending.
 * @param[in]       event       The event code to pass to the callback.
 **********************************************************************************************************************/
void iic_master_notify (iic_master_instance_ctrl_t * const p_ctrl, i2c_master_event_t const event)
{
    i2c_master_callback_args_t args;

    /* Store callback arguments in memory provided by user if available.  This allows callback arguments to be
     * stored in non-secure memory so they can be accessed by a non-secure callback function. */
    i2c_master_callback_args_t * p_args = p_ctrl->p_callback_memory;
    if (NULL == p_args)
    {
        /* Store on stack */
        p_args = &args;
    }
    else
    {
        /* Save current arguments on the stack in case this is a nested interrupt. */
        args = *p_args;
    }

    p_args->p_context = p_ctrl->p_context;
    p_args->event     = event;

#if IIC_MASTER_CFG_DTC_ENABLE

    i2c_master_cfg_t const *     p_cfg = p_ctrl->p_cfg;
    (void)p_cfg;

    /* Stop any DTC assisted transfer for tx */
    if ((NULL != p_ctrl->dma_tx) && (!p_ctrl->read))
    {
        iic_dma_disable(p_cfg->p_transfer_tx)(p_ctrl->dma_tx);
    }

    /* Stop any DTC assisted transfer for rx */
    if ((NULL != p_ctrl->dma_rx) && (p_ctrl->read))
    {
        iic_dma_disable(p_cfg->p_transfer_rx)(p_ctrl->dma_rx);
    }
#endif

    /* Now do the callback here */
#if BSP_TZ_SECURE_BUILD

    /* p_callback can point to a secure function or a non-secure function. */
    if (!cmse_is_nsfptr(p_ctrl->p_callback))
    {
        /* If p_callback is secure, then the project does not need to change security state. */
        p_ctrl->p_callback(p_args);
    }
    else
    {
        /* If p_callback is Non-secure, then the project must change to Non-secure state in order to call the callback. */
        iic_master_prv_ns_callback p_callback = (iic_master_prv_ns_callback) (p_ctrl->p_callback);
        p_callback(p_args);
    }

#else

    /* If the project is not Trustzone Secure, then it will never need to change security state in order to call the callback. */
    p_ctrl->p_callback(p_args);
#endif

    if (NULL != p_ctrl->p_callback_memory)
    {
        /* Restore callback memory in case this is a nested interrupt. */
        *p_ctrl->p_callback_memory = args;
    }

    /* Clear the err flags */
    p_ctrl->err = 0;
}

/*******************************************************************************************************************//**
 * Single point for managing the logic around aborting a transfer when operating as a master.
 *
 * @param[in]       p_ctrl  Pointer to control structure of specific device.
 * @param[in]       iic_reset  Flag to enable IIC reset
 **********************************************************************************************************************/
static void iic_master_abort_seq_master (iic_master_instance_ctrl_t * const p_ctrl, bool iic_reset)
{
    i2c_master_cfg_t const *    p_cfg = p_ctrl->p_cfg;
    I2C_TypeDef*                p_reg = p_ctrl->p_reg;
    (void)p_cfg;

    /* Check if there is an in-progress transfer associated with the match or an error event occurred */
    if ((0U != p_ctrl->remain) || (p_ctrl->restarted) || (0 != p_ctrl->err))
    {
        /* Reset the peripheral */
        if (true == iic_reset)
        {
            /* Disable channel interrupts */
            p_reg->ICIER = 0x00;

            /* This helper function would do a full IIC reset
             * followed by re-initializing the required peripheral registers. */
            iic_master_open_hw_master(p_ctrl, p_ctrl->p_cfg);
        }

        /* Update the transfer descriptor to show no longer in-progress and an error */
        p_ctrl->remain = 0U;

        /* Update the transfer descriptor to make sure interrupts no longer process */
        //p_ctrl->addr_loaded = p_ctrl->addr_total;
        //p_ctrl->loaded      = p_ctrl->total;
        p_ctrl->restarted   = false;
    }

    // clear bus requests
    p_reg->ICCR2 = 0;

    /* Enable Interrupts: TMOIE, ALIE, NAKIE, RIE, TIE.
     * Disable Interrupt: TEIE, STIE, SPIE
     * (see Section 36.2.8 'I2C Bus Interrupt Enable Register (ICIER)' of the RA6M3 manual R01UH0886EJ0100).
     */
    p_reg->ICIER = IIC_MASTER_INTERRUPT_ENABLE_INIT_MASK;
}

/*******************************************************************************************************************//**
 * Performs the hardware initialization sequence when operating as a master (see Section 36.3.2
 * 'Initial Settings' of the RA6M3 manual R01UH0886EJ0100).
 *
 * @param[in]  p_ctrl                Pointer to IIC specific control structure
 * @param[in]  p_cfg                 Pointer to IIC specific configuration structure.
 **********************************************************************************************************************/
static void iic_master_open_hw_master (iic_master_instance_ctrl_t * const p_ctrl, i2c_master_cfg_t const * const p_cfg)
{
    I2C_TypeDef*                p_reg = p_ctrl->p_reg;

    /* Perform IIC reset */
    p_reg->ICCR1 = (uint8_t) IIC_MASTER_PRV_SCL_SDA_NOT_DRIVEN;

    /* Reset */
    p_reg->ICCR1 = (uint8_t) (IIC_MASTER_ICCR1_IICRST_BIT_MASK | IIC_MASTER_PRV_SCL_SDA_NOT_DRIVEN);

    /* Come out of IIC reset to internal reset */
    p_reg->ICCR1 =
        (uint8_t) (IIC_MASTER_ICCR1_ICE_BIT_MASK | IIC_MASTER_ICCR1_IICRST_BIT_MASK |
                   IIC_MASTER_PRV_SCL_SDA_NOT_DRIVEN);

    /* Configure the clock settings. This is set in the configuration structure by the tooling. */
    /* Set the number of counts that the clock remains low, bit 7 to 5 should be written as 1 */
    p_reg->ICBRL =
        (uint8_t) (IIC_MASTER_BUS_RATE_REG_RESERVED_BITS |
                   ((iic_master_extended_cfg_t *) p_cfg->p_extend)->clock_settings.brl_value);

    /* Set the number of counts that the clock remains high, bit 7 to 5 should be written as 1 */
    p_reg->ICBRH = (uint8_t) (IIC_MASTER_BUS_RATE_REG_RESERVED_BITS |
                                      ((iic_master_extended_cfg_t *) p_cfg->p_extend)->clock_settings.brh_value);

    /* Set the internal reference clock source for generating IIC clock */
    p_reg->ICMR1 = (uint8_t) (IIC_MASTER_BUS_MODE_REGISTER_1_MASK |
                                      (uint8_t) ((((iic_master_extended_cfg_t *) p_cfg->p_extend)->
                                                  clock_settings.
                                                  cks_value &
                                                  IIC_MASTER_INTERNAL_REF_CLOCK_SELECT_MAX) << 4U));

    /* Allow timeouts to be generated on the low value of SCL using either long or short mode */

    /* TMOL 'Timeout L Count Control' and TMOH 'Timeout H Count Control' will be set at the time of I2C reset.
     * This will enable time out detection for both SCLn high and low.
     * Only Set/Clear TMOS here to select long or short mode.
     * (see Section 36.2.4 'I2C Bus Mode Register 2 (ICMR2)' of the RA6M3 manual R01UH0886EJ0100).
     */

    iic_master_extended_cfg_t * ecfg = (iic_master_extended_cfg_t *) p_cfg->p_extend;

    p_ctrl->timeout_mode =  (uint8_t) (IIC_MASTER_TIMEOUT_MODE_SHORT == ecfg->timeout_mode)
                         |  (uint8_t) (ecfg->timeout_scl_low << R_IIC0_ICMR2_TMOL_Pos)
                         ;

    p_reg->ICMR2 = (uint8_t)( IIC_MASTER_BUS_MODE_REGISTER_2_MASK | p_ctrl->timeout_mode );

    /* ICFER Register Settings:
     * 1. Enable timeout function.
     * 2. Enable master arbitration loss detection.
     * 3. Enable NACK arbitration loss detection.
     * 4. Disable Slave arbitration loss detection.
     * 5. Enable NACK reception transfer suspension.
     * 6. Use the digital noise filter circuit. Upon I2C reset, 'NF[1:0] Noise Filter Stage Select' will be set to 0x00
     * This would imply  'Filter out noise of up to 1 IIC cycle (single-stage filter)'
     * (see Section 36.2.5 'I2C Bus Mode Register 3 (ICMR3)' of the RA6M3 manual R01UH0886EJ0100)
     * 7. Do not use the SCL synchronous circuit.
     * 8. Enable FM+ slope circuit if fast mode plus is enabled.
     * (see Section 36.2.6 'I2C Bus Function Enable Register' of the RA6M3 manual R01UH0886EJ0100 for more details)
     */
    p_reg->ICFER =
        (uint8_t) ((uint8_t) (I2C_MASTER_RATE_FASTPLUS ==
                              p_cfg->rate) << 7U) | IIC_MASTER_FUNCTION_ENABLE_INIT_SETTINGS;

    /* Ensure the HW is in master mode and does not behave as a slave to another master on the same channel. */
    p_reg->ICSER = 0x00;

    /* Enable Interrupts: TMOIE, ALIE, NAKIE, RIE, TIE.
     * Disable Interrupt: TEIE, STIE, SPIE
     * (see Section 36.2.8 'I2C Bus Interrupt Enable Register (ICIER)' of the RA6M3 manual R01UH0886EJ0100).
     */
    p_reg->ICIER = IIC_MASTER_INTERRUPT_ENABLE_INIT_MASK;

    /* Set valid interrupt contexts and user provided priority. Enable the interrupts at the NVIC  */
    R_BSP_IrqCfgEnable(p_cfg->eri_irq, p_cfg->ipl, p_ctrl);
    R_BSP_IrqCfgEnable(p_cfg->txi_irq, p_cfg->ipl, p_ctrl);
    R_BSP_IrqCfgEnable(p_cfg->tei_irq, p_cfg->ipl, p_ctrl);
    R_BSP_IrqCfgEnable(p_cfg->rxi_irq, p_cfg->ipl, p_ctrl);

    /* Release IIC from internal reset */

    /* Reset */
    p_reg->ICCR1 = (uint8_t) (IIC_MASTER_ICCR1_ICE_BIT_MASK | IIC_MASTER_PRV_SCL_SDA_NOT_DRIVEN);
}

static inline
void iic_master_timeout_enable(I2C_TypeDef* p_reg ){
    /* Enable timeout function */
    p_reg->ICSR2_b.TMOF = 0;
    p_reg->ICFER_b.TMOE = 0U;   // clear counters
    p_reg->ICMR2 |= (R_IIC0_ICMR2_TMOH_Msk | R_IIC0_ICMR2_TMOL_Msk);
    p_reg->ICFER_b.TMOE = 1U;
}

/*******************************************************************************************************************//**
 * Performs the data transfer described by the parameters when operating as a master.
 * See 36.3.3 "Master Transmit Operation" and section 36.3.4 "Master Receive Operation"
 * of the RA6M3 manual R01UH0886EJ0100
 *
 * @param[in]       p_ctrl  Pointer to control structure of specific device.
 *
 * @retval  FSP_SUCCESS       Data transfer success.
 * @retval  FSP_ERR_IN_USE    If data transfer is in progress.
 **********************************************************************************************************************/
//static
fsp_err_t iic_master_run_hw_master (iic_master_instance_ctrl_t * const p_ctrl)
{
    trace_iic_start_on();

    I2C_TypeDef*                p_reg = p_ctrl->p_reg;
    i2c_master_cfg_t const *    p_cfg = p_ctrl->p_cfg;

    /* IICn operates using PCLKB. The ratio ICLK (System Clock)/PCLKB gives the CPU cycles for 1 ICBRL count.
     * (ICLK/PCLKB)*ICBRL gives the CPU cycles for entire ICBRL count.
     * Since each time we loop the timeout count will be decremented by 1 this would require at least 4 CPU clocks,
     * making the final timeout count as:
     * Timeout = ((ICLK/PCLKB)*ICBRL)/4.
     */
    volatile uint32_t sysdiccr =
        (uint32_t) (R_SYSTEM->SCKDIVCR & (IIC_MASTER_SYSDIVCK_ICLK_MASK | IIC_MASTER_SYSDIVCK_PCLKB_MASK));
    uint32_t pclkb         = (IIC_MASTER_SYSDIVCK_PCLKB_MASK & sysdiccr) >> 8U;
    uint32_t iclk          = sysdiccr >> 24U;
    uint32_t timeout_count = ((1U << (pclkb - iclk)) * p_reg->ICBRL) >> 2U;

    trace_iic_rnack_set( p_reg->ICMR3_b.ACKBT != 0 );

    FSP_ASSERT( NVIC_GetEnableIRQ(p_cfg->rxi_irq) != 0u );

    /* Check if this is a new transaction or a continuation */
    if (!p_ctrl->restarted)
    {
        /* As per BBSY clearing conditions in section 36.2.2 of the RA6M3 manual R01UH0886EJ0100,
         * the BBSY bit is 0 after the bus free time (ICBRL setting)
         * if a start condition is not detected after a stop condition detection.
         */
        IIC_MASTER_HARDWARE_REGISTER_WAIT(p_reg->ICCR2_b.BBSY, 0U, timeout_count);

        /* If bus is busy, return error */
        if (p_reg->ICCR2_b.BBSY != 0u)
            return FSP_ERR_IN_USE;

        /* This is not a restarted transaction. Enable TXI for the next transfer.
         * This had been disabled at the end of TXI interrupt.
         * The intention is to only enable IIC_MASTER_TXI_EN_BIT.
         * Writing the whole mask - IIC_MASTER_INTERRUPT_ENABLE_INIT_MASK saves cycles.
         */
        p_reg->ICIER = IIC_MASTER_INTERRUPT_ENABLE_INIT_MASK;
    }

    /* Initialize fields used during transfer */
    p_ctrl->addr_loaded          = 0U;
    p_ctrl->loaded               = 0U;
    p_ctrl->remain               = p_ctrl->total;
    p_ctrl->addr_remain          = p_ctrl->addr_total;
    p_ctrl->err                  = 0;
    p_ctrl->errs_events          = 0;
    p_ctrl->dummy_read_completed = false;
    p_ctrl->activation_on_rxi    = false;
    p_ctrl->activation_on_txi    = false;
    p_ctrl->address_restarted    = false;

    /* Allow timeouts to be generated on the low value of SCL using either short or long mode.
     * This gets disabled in case the previous transaction issues a restart.
     */

    /* TMOL 'Timeout L Count Control' and TMOH 'Timeout H Count Control' will be set at the time of I2C reset.
     * This will enable time out detection for both SCLn high and low.
     * Only Set/Clear TMOS here to select long or short mode.
     * (see Section 36.2.4 'I2C Bus Mode Register 2 (ICMR2)' of the RA6M3 manual R01UH0886EJ0100).
     */
    p_reg->ICMR2 = (uint8_t) (IIC_MASTER_BUS_MODE_REGISTER_2_MASK |
                                      (uint8_t) (IIC_MASTER_TIMEOUT_MODE_SHORT ==
                                                 ((iic_master_extended_cfg_t *)p_cfg->p_extend)->timeout_mode)
                                      |
                                      (uint8_t) (((iic_master_extended_cfg_t *)p_cfg->p_extend)->
                                                 timeout_scl_low << R_IIC0_ICMR2_TMOL_Pos));

    iic_master_timeout_enable( p_reg );

    /* Enable SPIE to detect unexpected STOP condition. This is disabled between communication events as it can lead
     * to undesired interrupts in multi-master setups. */
    p_reg->ICIER = IIC_MASTER_INTERRUPT_ENABLE_INIT_MASK | R_IIC0_ICIER_STIE_Msk | R_IIC0_ICIER_SPIE_Msk;

    /* If previous transaction did not end with restart, send a start condition */
    if (!p_ctrl->restarted)
    {
        /* Request IIC to issue the start condition */
        p_reg->ICCR2 = (uint8_t) IIC_MASTER_ICCR2_ST_BIT_MASK;
    }
    else
    {
        p_ctrl->restarted = false;

        // if loosed TXI IRQ after last operation, drop that
        R_BSP_IrqClearPending(p_cfg->txi_irq);
        // TODO: adress_pending MUST >0 here. need hook here if have no adress.
        iic_master_txi_send_address(p_ctrl);
    }

    /* Enable TXI. This is treated differently to support restart functionality.
     * In case the previous IIC master transaction enabled restart, the queued TXI will fire a this point.
     *
     * The TXI had been NVIC-disabled (but Peripheral enabled) before setting the
     * RS bit by the previous restart enabled transaction.
     * The RS bit mimics a "stop" followed by a "start" and keeps the bus busy.
     * As a part of the previous transaction, TXI fires at the peripheral level and is queued at the CPU.
     *
     * If the previous transaction was not restart enabled -
     * NVIC-enable TXI which will fire after the start condition below.
     */
    NVIC_EnableIRQ(p_cfg->txi_irq);

    /*
     * The Flowchart under 36.3.3 "Master Transmit Operation" and section 36.3.4 "Master Receive Operation"
     * of the RA6M3 manual R01UH0886EJ0100 is covered in the interrupts:
     *
     * 1. NACKF processing is handled in the ERI interrupt.
     *    For receive, dummy reading ICDRR is not required because the NACK processing in this driver resets the IIC peripheral.
     * 2. Data is written to ICDRT in the transmit interrupt (TDRE is set when a transmit interrupt fires).
     * 3. For transmit, stop is issued in the transmit end interrupt (TEND is set when a transmit end interrupt fires).
     * 4. For transmit, ICSR2 is cleared in the transmit end interrupt.
     * 5. For receive, remaining processing including reading ICDRR happens in the receive interrupt (RDRF is set when a receive interrupt fires).
     */

    trace_iic_start_off();
    return FSP_SUCCESS;
}

/*******************************************************************************************************************//**
 * Handles the receive data full interrupt when operating as a master.
 *
 * @param[in]       p_ctrl     The target IIC block's control block.
 **********************************************************************************************************************/
static void iic_master_rxi_master (iic_master_instance_ctrl_t * p_ctrl)
{
    trace_iic_rxi_twist();
    volatile uint8_t dummy_read;

    I2C_TypeDef* p_reg = p_ctrl->p_reg;

    /* First receive interrupt: Handle the special case of 1 or 2 byte read here */
    if (false == p_ctrl->dummy_read_completed)
    {

        trace_iic_rnack_spure_set( p_reg->ICMR3_b.ACKBT != 0 );

        /* Enable WAIT for 1 or 2 byte read */
        if (2U <= p_ctrl->total)
        {
            p_reg->ICMR3_b.WAIT = 1;
        }

        /* Enable NACK for 1 byte read, if not keep bus used */
        if (1U == p_ctrl->remain)
        {
            /* Writes to be done separately.
             * See Note 1 in Section 36.2.5 'I2C Bus Mode Register 3 (ICMR3)' of the RA6M3 manual R01UH0886EJ0100
             */
            p_reg->ICMR3_b.ACKWP = 1; /* Write enable ACKBT */
            p_reg->ICMR3_b.ACKBT = 1;
        }
        else {
            // just for sure, disable NACK if it was occured here
            // FIX: sometimes IIC core missed clear ACKBT on STOP, and it leave on next transaction
            if (1U < p_ctrl->remain) {
                p_reg->ICMR3_b.ACKWP = 1; /* Write disable ACKBT */
                p_reg->ICMR3_b.ACKBT = 0;
            }
        }

#if IIC_MASTER_CFG_DTC_ENABLE
        uint8_t volatile const * p_iic_master_rx_buffer = &(p_ctrl->p_reg->ICDRR);

        /* Enable transfer support if possible */
        if ((NULL != p_ctrl->dma_rx) && (p_ctrl->read) && (p_ctrl->total > 3U))
        {
            iic_dma_reset(p_ctrl->p_cfg->p_transfer_rx)(p_ctrl->dma_rx,
                                                       (uint8_t *) (p_iic_master_rx_buffer),
                                                       (void *) (p_ctrl->p_buff),
                                                       (uint16_t) (p_ctrl->total - 3U));

            p_ctrl->remain            = 3U;
            p_ctrl->loaded            = p_ctrl->total - 3U;
            p_ctrl->activation_on_rxi = true;
        }
#endif

        /* Update the counter */
        p_ctrl->dummy_read_completed = true;

        IRQn_Type rxi_irq = p_ctrl->p_cfg->rxi_irq;
        R_BSP_IrqClearPending(rxi_irq);

        /* Do a dummy read to clock the data into the ICDRR. */
        dummy_read = p_reg->ICDRR;
        FSP_PARAMETER_NOT_USED(dummy_read);
    }

#if IIC_MASTER_CFG_DTC_ENABLE

    /* If this is the interrupt that got fired after DTC transfer,
     * ignore it as the DTC has already taken care of the data transfer */
    else if (true == p_ctrl->activation_on_rxi)
    {
        p_ctrl->activation_on_rxi = false;
    }
#endif

    /* ICDRR contain valid received data */
    else if (0U < p_ctrl->remain)
    {
        iic_master_rxi_read_data(p_ctrl);
    }
    else
    {
        /* Do nothing */
    }
}

/*******************************************************************************************************************//**
 * Handles the transmit data empty interrupt when operating as a master.
 *
 * @param[in]       p_ctrl     The target IIC block's control block.
 **********************************************************************************************************************/
static void iic_master_txi_master (iic_master_instance_ctrl_t * p_ctrl)
{
    trace_iic_txi_twist();
    uint32_t timeout_count = IIC_MASTER_PERIPHERAL_REG_MAX_WAIT;

    /* Check if we are issuing the slave address */
    if (0U < p_ctrl->addr_remain)
    {
        iic_master_txi_send_address(p_ctrl);
    }
    else if (!p_ctrl->read)
    {
#if IIC_MASTER_CFG_DTC_ENABLE

        /* If this is the interrupt that got fired after DTC transfer,
         * ignore it as the DTC has already taken care of the data transfer */
        if (true == p_ctrl->activation_on_txi)
        {
            p_ctrl->activation_on_txi = false;
        }
        else if (p_ctrl->remain > 0U)
#else
        if (p_ctrl->remain > 0U)
#endif
        {
            /* Write the data to ICDRT register */
            p_ctrl->p_reg->ICDRT = p_ctrl->p_buff[p_ctrl->loaded];

            /* Update the number of bytes remaining for next pass */
            p_ctrl->loaded++;
            p_ctrl->remain--;
        }
        else
        {
            /* Do nothing */
        }

        /* We are done loading ICDRT, wait for TEND to send a stop/restart */
        if (0U == p_ctrl->remain)
        {
            R_IIC0_Type * p_reg = p_ctrl->p_reg;
            p_reg->ICIER_b.TIE = 0U;

            /* Wait for the value to reflect at the peripheral.
             * See 'Note' under Table 36.10 "Interrupt sources" of the RA6M3 manual R01UH0886EJ0100 */
            IIC_MASTER_HARDWARE_REGISTER_WAIT(p_reg->ICIER_b.TIE, 0U, timeout_count);

            /* Enable the transmit end IRQ, to issue a STOP or RESTART */
            /* Clear any pending TEND interrupts */
            IRQn_Type  tei_irq = p_ctrl->p_cfg->tei_irq;
            R_BSP_IrqStatusClear(tei_irq);
            NVIC_ClearPendingIRQ(tei_irq);

            /* Enable the TXEND interrupt */
            p_reg->ICIER_b.TEIE = 1U;

            /* No need to wait to check TEIE has actually become 1U; because if that's not the case,
             * no other operation can occur at this point */
        }
    }
    else
    {
        /* Do nothing */
        trace_iic_rnack_spure_set( p_ctrl->p_reg->ICMR3_b.ACKBT != 0 );
    }
}


static inline
void iic_master_timeout_disable(I2C_TypeDef* p_reg){
    /* Disable timeout function */
    p_reg->ICFER_b.TMOE = 0;
    p_reg->ICMR2 &= ~(R_IIC0_ICMR2_TMOH_Msk | R_IIC0_ICMR2_TMOL_Msk);
}
/*******************************************************************************************************************//**
 * Handles the transmit end interrupt when operating as a master.
 * @note This interrupt is configured to be generated at the end of last byte of the requested transfer.
 *
 * @param[in]       p_ctrl     The target IIC block's control block.
 **********************************************************************************************************************/
static void iic_master_tei_master (iic_master_instance_ctrl_t * p_ctrl)
{
    trace_iic_tei_twist();
    I2C_TypeDef*                p_reg = p_ctrl->p_reg;

    uint32_t timeout_count = IIC_MASTER_PERIPHERAL_REG_MAX_WAIT;

    /* Disable the interrupt as we are done with the transfer */
    p_reg->ICIER_b.TEIE = 0U;

    /* This is a 10 bit address read, issue a restart prior to the last address byte transmission  */
    if ((p_ctrl->read) && (p_ctrl->addr_remain == 1U) && (false == p_ctrl->address_restarted))
    {
#if IIC_MASTER_CFG_ADDR_MODE_10_BIT_ENABLE


        /* Wait for the value to reflect at the peripheral.
         * See 'Note' under Table 36.10 "Interrupt sources" of the RA6M3 manual R01UH0886EJ0100 */
        IIC_MASTER_HARDWARE_REGISTER_WAIT(p_reg->ICIER_b.TEIE, 0U, timeout_count);

        /* Enable TXI so that it fires after restart condition. */
        p_ctrl->p_reg->ICIER_b.TIE = 1U;

        /* Request IIC to issue the restart condition */
        p_ctrl->p_reg->ICCR2      = (uint8_t) IIC_MASTER_ICCR2_RS_BIT_MASK;
        p_ctrl->address_restarted = true;
#endif
    }
    /* We are done with the transfer, send STOP or RESTART */
    else if (0U == p_ctrl->remain)
    {
        /* Send RESTART */
        if (p_ctrl->restart == I2C_MASTER_RESTART)
        {
            iic_master_timeout_disable(p_reg);

            /* NOTE:Only disable in NVIC, disabling in I2C would cause the
             * restart condition to fail because we are using the buffered
             * interrupt to start the next sequence */
            R_BSP_IrqDisable(p_ctrl->p_cfg->txi_irq);

            /* Wait for the value to reflect at the peripheral.
             * See 'Note' under Table 36.10 "Interrupt sources" of the RA6M3 manual R01UH0886EJ0100 */
            IIC_MASTER_HARDWARE_REGISTER_WAIT(p_reg->ICIER_b.TEIE, 0U, timeout_count);

            p_reg->ICIER_b.TIE = 1U;

            /* Request IIC to issue the restart condition. At this point we will queue a TXI at the NVIC level. */
            p_reg->ICCR2 = (uint8_t) IIC_MASTER_ICCR2_RS_BIT_MASK;

            /* Remember that we issued a restart for the next transfer */
            p_ctrl->restarted = true;
        }
        /* Send STOP */
        else if (p_ctrl->restart == I2C_MASTER_RELEASE)
        {
            /* Clear STOP flag and set SP.
             * It is ok to clear other status' as this transaction is over.
             */
            p_reg->ICSR2 &= (uint8_t) ~(IIC_MASTER_ICSR2_STOP_BIT);;

            /* Request IIC to issue the stop condition */
            p_reg->ICCR2 = (uint8_t) IIC_MASTER_ICCR2_SP_BIT_MASK; /* It is safe to write 0's to other bits. */
        }
        else // if (I2C_MASTER_BUS_KEEP == p_ctrl->restart)
        {
            iic_master_timeout_disable(p_reg);

            /* NOTE:Only disable in NVIC, disabling in I2C would cause the
             * restart condition to fail because we are using the buffered
             * interrupt to start the next sequence */
            R_BSP_IrqDisable(p_ctrl->p_cfg->txi_irq);

            /* Wait for the value to reflect at the peripheral.
             * See 'Note' under Table 36.10 "Interrupt sources" of the RA6M3 manual R01UH0886EJ0100 */
            IIC_MASTER_HARDWARE_REGISTER_WAIT(p_reg->ICIER_b.TEIE, 0U, timeout_count);

            p_reg->ICIER_b.TIE = 1U;

            /* imagine that we issued a restart when doing the next transfer */
            p_ctrl->restarted = true;

            // since bus keep hold, no other IRQ rises, notify finished here
            iic_master_notify(p_ctrl, I2C_MASTER_EVENT_TX_COMPLETE);
        }
    }
    else
    {
        /* Do nothing */
    }
}

/*******************************************************************************************************************//**
 * Handles the error interrupts when operating as a master.
 *
 * @param[in]       p_ctrl  Pointer to transfer control block
 **********************************************************************************************************************/
static void iic_master_err_master (iic_master_instance_ctrl_t * p_ctrl)
{
    trace_iic_ei_twist();
    I2C_TypeDef*                p_reg = p_ctrl->p_reg;

    /* Clear all the event flags except the receive data full, transmit end and transmit data empty flags*/
    uint8_t errs_events = IIC_MASTER_STATUS_REGISTER_2_ERR_MASK & p_reg->ICSR2;
    p_reg->ICSR2 = (uint8_t) ~IIC_MASTER_STATUS_REGISTER_2_ERR_MASK;
    p_ctrl->errs_events = errs_events;

    /* If the event was an error event, then handle it */
    if ( ( errs_events & (uint8_t) ( IIC_MASTER_ERR_EVENT_TIMEOUT | IIC_MASTER_ERR_EVENT_ARBITRATION_LOSS ) )
         || ( (errs_events & (uint8_t) (IIC_MASTER_ERR_EVENT_NACK)) && (1U != p_reg->ICCR2_b.MST) )
        )
    {
        /* Conditions to get here:
         * 1. This is Timeout and/or arbitration loss error during an ongoing transaction
         * 2. This is a NACK error and this device is no longer the active master on the bus.
         *    The MST bit here can get cleared:
         *     a. In case of an arbitration loss error.also occurs.
         *     b. If the slave timeout is lesser than master timeout and the slave releases
         *        the bus by performing an internal reset.
         *        Refer Section "I2C Bus Control Register 2 (ICCR2) - Clearing conditions for MST"
         *        of the RA6M3 manual R01UH0886EJ0100
         * 3. This is a Timeout error after attempting to issue a stop after detecting a NACK previously.
         *//* Set the error flag when an error event occurred */

        int8_t err = p_ctrl->err;

        enum {
            IIC_START_MASK =  IIC_MASTER_ICCR2_ST_BIT_MASK
                            | IIC_MASTER_ICCR2_RS_BIT_MASK
                            ,
            IIC_STR_MASK = IIC_MASTER_ICCR2_SP_BIT_MASK
                            | IIC_MASTER_ICCR2_ST_BIT_MASK
                            | IIC_MASTER_ICCR2_RS_BIT_MASK
                            ,

        };

        if ( (IIC_MASTER_ICCR1_LINEIN_BIT_MASK & p_reg->ICCR1) == IIC_MASTER_ICCR1_LINE_OFFLINE){
            // bus hung at unconnected, looks cant control lines

            p_ctrl->err = 1;
            iic_master_timeout_disable(p_reg);
            iic_master_abort_seq_master(p_ctrl, false); /* Clear the transaction flags only */
            iic_master_notify(p_ctrl, I2C_MASTER_EVENT_FAIL);
            return;
        }

        if ( err <= 0) { //(p_ctrl->err & 1)
            err = 0;
            if (p_reg->ICCR2_b.BBSY != 0u){
                // try stop, setup timeout can be rapid, so we detect stop hungs rapidly

                /* Request IIC to issue the stop condition */
                p_reg->ICSR2 &= (uint8_t) ~(IIC_MASTER_ICSR2_STOP_BIT);
                p_reg->ICCR2  = (uint8_t) IIC_MASTER_ICCR2_SP_BIT_MASK; /* It is safe to write 0's to other bits. */

                /* Allow timeouts to be generated after SCL using short mode */
                p_reg->ICMR2 |= (uint8_t) R_IIC0_ICMR2_TMOS_Msk;
                iic_master_timeout_enable(p_reg);
            }
            else {
                p_ctrl->err = -2;
                // on free bus timeouts not works, and stops not works well.
                // possibly here since start not success, try start again?
                iic_master_timeout_disable(p_reg);
                iic_master_abort_seq_master(p_ctrl, false); /* Clear the transaction flags only */
                iic_master_notify(p_ctrl, I2C_MASTER_EVENT_FAIL);
            }
        }
        else  if ( err > 8 ) {
            p_ctrl->err = 1;
            /* Abort an in-progress transfer with the current device */
            iic_master_abort_seq_master(p_ctrl, true); /* This will reset the IIC Master driver */
            /* Notify anyone waiting that the transfer is Aborted due to error. */
            iic_master_notify(p_ctrl, I2C_MASTER_EVENT_FAIL);
        }
        else {
            // issue clock pulse. setup timeouts to rise after that rapidly. and on next timeout try stop
            p_reg->ICCR1_b.CLO = 1;
            iic_master_timeout_enable(p_reg);
        }

        p_ctrl->err = err +1;
    }
    else if ((errs_events & (uint8_t) (IIC_MASTER_ERR_EVENT_NACK)) && (1U == p_reg->ICCR2_b.MST))
    {
        /* MST bit must be set to issue a stop condition.
         * Refer Section "36.11.3 Issuing a Stop Condition" of the RA6M3 manual R01UH0886EJ0100
         */

        /* Set the error flag when an error event occurred
         * This will be checked after the stop condition is detected from the request below. */
        p_ctrl->err = -1;

        /* The sequence below is to handle a NACK received from slave in the middle of a write.
         * See item '[4]' under 'Figure 36.6 Example master transmission flow' of the RA6M3 manual R01UH0886EJ0100 */

        /* Request IIC to issue the stop condition */
        p_reg->ICSR2 &= (uint8_t) ~(IIC_MASTER_ICSR2_STOP_BIT);
        p_reg->ICCR2  = (uint8_t) IIC_MASTER_ICCR2_SP_BIT_MASK; /* It is safe to write 0's to other bits. */
        /* Allow timeouts to be generated on the low value of SCL using either long or short mode */
        p_reg->ICMR2 = (uint8_t) (0x02U | p_ctrl->timeout_mode );
        p_reg->ICFER_b.TMOE = 1;

        /* This interrupt will be fired again when wither stop condition is sent
         * or the hardware detects the line is stuck low causing a timeout */
    }
    /* This is a STOP, START or RESTART event. We need to process these events only at the
     * end of the requisite transfers.
     * NOTE: Do not use p_transfer->loaded or p_transfer->remain to check whether the transfer is
     * completed, since using them would lead to a race condition between txi and eri interrupts in case
     * of one byte transfer which will result in BUS arbitration loss error */
    else if ((errs_events & (uint8_t) IIC_MASTER_ERR_EVENT_STOP) ||
             ((p_ctrl->restarted) && (errs_events & (uint8_t) IIC_MASTER_ERR_EVENT_START)))
    {
        trace_iic_ei_ss_twist();
        int8_t err = p_ctrl->err;

        i2c_master_event_t event = I2C_MASTER_EVENT_ABORTED;
        if (0 == err)      /* Successful transaction */
        {
            /* Get the correct event to notify the user */
            if (p_ctrl->read)
                event =  I2C_MASTER_EVENT_RX_COMPLETE;
            else
                event =  I2C_MASTER_EVENT_TX_COMPLETE;

            /* Disable STIE/SPIE to prevent errant interrupts in multi-master scenarios */
            p_reg->ICIER = IIC_MASTER_INTERRUPT_ENABLE_INIT_MASK;
        }
        else if ((errs_events & (uint8_t) IIC_MASTER_ERR_EVENT_STOP))
        {
            if (0 > err) {
                /* This is the STOP condition requested due to a NACK error earlier. */
                ;
            }
            else if (1 >= err) {
                /* This is the STOP condition requested after timeout. */
                if (p_ctrl->loaded == 0)
                    event = I2C_MASTER_EVENT_NOSLA;
                else
                    event = I2C_MASTER_EVENT_TIMEOUT;
            }
            else {
                /* This is the STOP condition requested after un-HUNG clocked */
                event = I2C_MASTER_EVENT_HUNG;
            }
            //* Since the stop condition is successfully issued there is no need to reset the driver.
            iic_master_abort_seq_master(p_ctrl, false); /* Clear the transaction flags only */
        }
        else
        {
            iic_master_abort_seq_master(p_ctrl, false); /* Clear the transaction flags only */
        }

        /* Notify anyone waiting */
        iic_master_notify(p_ctrl, event);
    }
    else
    {
        /* Do nothing */
    }
}

/*******************************************************************************************************************//**
 * Check valid receive data and set WAIT, NACK and STOP/RESTART bit in RXI handler.
 *
 * @param[in]       p_ctrl  Pointer to transfer control block
 **********************************************************************************************************************/
static void iic_master_rxi_read_data (iic_master_instance_ctrl_t * const p_ctrl)
{
    I2C_TypeDef*                p_reg = p_ctrl->p_reg;
    trace_iic_rnack_set( p_reg->ICMR3_b.ACKBT != 0 );

    /* If next data = (final byte - 2), enable WAIT */
    if (3U == p_ctrl->remain)
    {
        p_reg->ICMR3_b.WAIT = 1;
    }
    /* If next data = (final byte - 1), enable NACK  */
    else if (2U == p_ctrl->remain)
    {
        /* Writes to be done separately.
         * See Note 1 in Section 36.2.5 'I2C Bus Mode Register 3 (ICMR3)' of the RA6M3 manual R01UH0886EJ0100
         */

        p_reg->ICMR3_b.ACKWP = 1; /* Write enable ACKBT */
        p_reg->ICMR3_b.ACKBT = 1;
    }
    /* If next data = final byte, send STOP or RESTART */
    else if (1U == p_ctrl->remain)
    {
        if (I2C_MASTER_RESTART == p_ctrl->restart)
        {
            /* NOTE:Only disable in NVIC, disabling in I2C would cause the
             * restart condition to fail because we are using the buffered
             * interrupt to start the next sequence */
            R_BSP_IrqDisable(p_ctrl->p_cfg->txi_irq);
            p_reg->ICIER_b.TIE = 1U;

            p_reg->ICMR3_b.ACKWP = 1; /* Write enable ACKBT */

            /* This bit clears to 0 automatically by issuing stop condition.
             * For restart condition, clear bit by software.
             */
            p_reg->ICMR3_b.ACKBT = 0;

            /* Request IIC to issue the restart condition */
            p_reg->ICCR2 = (uint8_t) IIC_MASTER_ICCR2_RS_BIT_MASK;

            iic_master_timeout_disable(p_reg);

            /* Remember that we issued a restart when doing the next transfer */
            p_ctrl->restarted = true;
        }
        else if (I2C_MASTER_RELEASE == p_ctrl->restart)
        {
            /* Clear STOP flag and set SP.
             * It is ok to clear other status' as this transaction is over.
             */
            p_reg->ICSR2 &= (uint8_t) ~(IIC_MASTER_ICSR2_STOP_BIT);;

            /* Request IIC to issue the stop condition */
            p_reg->ICCR2 = (uint8_t) IIC_MASTER_ICCR2_SP_BIT_MASK; /* It is safe to write 0's to other bits. */

            /* STOP flag will not be set just yet. STOP will be set only after reading the last byte from ICDRR and clearing the WAIT.
             * See Point #7 under '36.3.4 Master Receive Operation' of the RA6M3 manual R01UH0886EJ0100.
             */
        }
        else // if (I2C_MASTER_BUS_KEEP == p_ctrl->restart)
        {
            /* NOTE:Only disable in NVIC, disabling in I2C would cause the
             * restart condition to fail because we are using the buffered
             * interrupt to start the next sequence */
            R_BSP_IrqDisable(p_ctrl->p_cfg->txi_irq);
            p_reg->ICIER_b.TIE = 1U;

            iic_master_timeout_disable(p_reg);

            /* imagine that we issued a restart when doing the next transfer */
            p_ctrl->restarted = true;
        }
    }
    else
    {
        /* Do nothing */
    }

    p_ctrl->p_buff[p_ctrl->loaded] = p_reg->ICDRR;

    /* Update the counter values */
    p_ctrl->loaded++;
    p_ctrl->remain--;

    /* If we are done with the reception, clear the WAIT bit */
    if (0U == p_ctrl->remain)
    {
        p_ctrl->p_reg->ICMR3_b.WAIT = 0;

        /* If this transaction does not have the restart flag set to true,
         * last byte has been read and WAIT has been cleared.
         * Callback will be issued by the ERI once the stop condition is detected
         * In case of restart flag set to true a callback will be issued by the ERI once the start
         * (from restart) condition is detected
         */
    }
}

/*******************************************************************************************************************//**
 * Write the address byte to the iic bus
 *
 * @param[in]       p_ctrl  Pointer to transfer control block
 **********************************************************************************************************************/
static void iic_master_txi_send_address (iic_master_instance_ctrl_t * const p_ctrl)
{
    I2C_TypeDef*                p_reg = p_ctrl->p_reg;
    trace_iic_rnack_set( p_reg->ICMR3_b.ACKBT != 0 );

#if IIC_MASTER_CFG_ADDR_MODE_10_BIT_ENABLE
    /* This is a 10 bit read and we have transmitted the low byte, next is restart */
    if ((3U == p_ctrl->addr_total) && (2U == p_ctrl->addr_loaded) && (false == p_ctrl->address_restarted))
    {
        uint32_t timeout_count = IIC_MASTER_PERIPHERAL_REG_MAX_WAIT;

        /* For Read operation an extra address byte needs to be sent after issuing restart.
         * At this point we have sent the first 2 address bytes. Disable TXI.
         */
        p_ctrl->p_reg->ICIER_b.TIE = 0U;

        /* Wait for the value to reflect at the peripheral.
         * See 'Note' under Table 36.10 "Interrupt sources" of the RA6M3 manual R01UH0886EJ0100 */
        IIC_MASTER_HARDWARE_REGISTER_WAIT(p_ctrl->p_reg->ICIER_b.TIE, 0U, timeout_count);

        /* Enable the transmit end IRQ, so that we can generate a RESTART condition */
        /* Clear any pending TEND interrupts */
        R_BSP_IrqStatusClear(p_ctrl->p_cfg->tei_irq);
        NVIC_ClearPendingIRQ(p_ctrl->p_cfg->tei_irq);

        /* Enable the TXEND interrupt */
        p_ctrl->p_reg->ICIER_b.TEIE = 1U;

        /* No need to wait to check TEIE has actually become 1U; because if that's not the case,
         * no other operation can occur at this point */
    }
    else
#endif
    {
        /* Address low byte, this could either be a 7 bit address or low byte of 10 bit address */
        uint8_t address_byte = p_ctrl->addr_low;
#if IIC_MASTER_CFG_ADDR_MODE_10_BIT_ENABLE

        /* 10 bit address, handle accordingly */
        if (p_ctrl->addr_total > 1U)
        {
            /* MSB transfer, send address high byte with with R/W set to 0 */
            if (0U == p_ctrl->addr_loaded)
            {
                address_byte = p_ctrl->addr_high;
            }
            /* MSB transfer after restart of 10 bit read, send high byte with R/W set to 1 */
            else if ((2U == p_ctrl->addr_loaded) && (3U == p_ctrl->addr_total))
            {
                address_byte = p_ctrl->addr_high | (uint8_t) I2C_CODE_READ;
            }
            /* Low byte transfer */
            else
            {
                address_byte = p_ctrl->addr_low;
            }
        }
#endif

#if IIC_MASTER_CFG_DTC_ENABLE
        uint8_t volatile const * p_iic_master_tx_buffer = &(p_ctrl->p_reg->ICDRT);

        /* If this is the last address byte, enable transfer */
        if (1U == p_ctrl->addr_remain)
        {
            if ((NULL != p_ctrl->dma_tx) && !(p_ctrl->read) && (p_ctrl->total > 0U))
            {
                iic_dma_reset(p_ctrl->p_cfg->p_transfer_tx)(p_ctrl->dma_tx,
                                                           (void *) (p_ctrl->p_buff),
                                                           (uint8_t *) (p_iic_master_tx_buffer),
                                                           (uint16_t) (p_ctrl->remain));
                p_ctrl->remain            = 0U;
                p_ctrl->loaded            = p_ctrl->total;
                p_ctrl->activation_on_txi = true;
            }
        }
#endif

        /* Write the address byte */
        p_ctrl->p_reg->ICDRT = address_byte;

        /* Update the number of address bytes loaded for next pass */
        p_ctrl->addr_loaded++;
        p_ctrl->addr_remain--;
    }
}

#if IIC_MASTER_CFG_DTC_ENABLE

/*******************************************************************************************************************//**
 * Configures IIC related transfer drivers (if enabled).
 *
 * @param[in]   p_ctrl    Pointer to IIC specific control structure
 * @param[in]   p_cfg     Pointer to IIC specific configuration structure
 *
 * @retval      FSP_SUCCESS                Transfer interface initialized successfully.
 * @retval      FSP_ERR_ASSERTION          Pointer to transfer instance for I2C receive in p_cfg is NULL.
 **********************************************************************************************************************/
static fsp_err_t iic_master_transfer_open (iic_master_instance_ctrl_t * p_ctrl, i2c_master_cfg_t const * const p_cfg)
{
    fsp_err_t err = FSP_SUCCESS;

    if (NULL != p_cfg->p_transfer_rx)
    {
        p_ctrl->dma_rx = p_cfg->p_transfer_rx->p_ctrl;
        err = iic_master_transfer_configure(p_ctrl, p_cfg->p_transfer_rx, IIC_MASTER_TRANSFER_DIR_READ);
        FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
    }
    else
        p_ctrl->dma_rx = NULL;

    if (NULL != p_cfg->p_transfer_tx)
    {
        p_ctrl->dma_tx = p_cfg->p_transfer_tx->p_ctrl;
        err = iic_master_transfer_configure(p_ctrl, p_cfg->p_transfer_tx, IIC_MASTER_TRANSFER_DIR_WRITE);
        if (FSP_SUCCESS != err)
        {
            if (NULL != p_cfg->p_transfer_rx)
            {
                p_ctrl->dma_rx = NULL;
                iic_dma_close(p_cfg->p_transfer_rx)(p_cfg->p_transfer_rx->p_ctrl);
            }

            return err;
        }
    }
    else
        p_ctrl->dma_tx = NULL;

    return FSP_SUCCESS;
}

/*******************************************************************************************************************//**
 * Configures  IIC RX related transfer.
 * @param[in]     p_ctrl                     Pointer to IIC specific control structure
 * @param[in]     p_cfg                      Pointer to IIC specific configuration structure
 *
 * @retval        FSP_SUCCESS                Transfer interface is configured with valid parameters.
 * @retval        FSP_ERR_ASSERTION          Pointer to transfer instance for I2C receive in p_cfg is NULL.
 **********************************************************************************************************************/
static fsp_err_t iic_master_transfer_configure (iic_master_instance_ctrl_t * p_ctrl,
                                                transfer_instance_t const  * p_transfer,
                                                iic_master_transfer_dir_t    direction)
{
    fsp_err_t err;
    IRQn_Type irq;

    /* Set default transfer info and open receive transfer module, if enabled. */
 #if (IIC_MASTER_CFG_PARAM_CHECKING_ENABLE)
    FSP_ASSERT(NULL != p_transfer->p_api);
    FSP_ASSERT(NULL != p_transfer->p_ctrl);
    FSP_ASSERT(NULL != p_transfer->p_cfg);
    FSP_ASSERT(NULL != p_transfer->p_cfg->p_info);
 #endif
    transfer_info_t * p_cfg = p_transfer->p_cfg->p_info;
    if (IIC_MASTER_TRANSFER_DIR_READ == direction)
    {
        irq = p_ctrl->p_cfg->rxi_irq;
        p_cfg->transfer_settings_word = IIC_MASTER_DTC_RX_TRANSFER_SETTINGS;
    }
    else
    {
        irq = p_ctrl->p_cfg->txi_irq;
        p_cfg->transfer_settings_word = IIC_MASTER_DTC_TX_TRANSFER_SETTINGS;
    }

    const transfer_cfg_t* cfg = p_transfer->p_cfg;
    dtc_extended_cfg_t * p_dtc_extended_configuration = (dtc_extended_cfg_t *) (cfg->p_extend);
    p_dtc_extended_configuration->activation_source = irq;

    err = iic_dma_open(p_transfer)(p_transfer->p_ctrl, cfg);
    FSP_ERROR_RETURN((FSP_SUCCESS == err), err);

    return FSP_SUCCESS;
}

#endif

/***********************************************************************************************************************
 * Interrupt Vectors
 **********************************************************************************************************************/

/*******************************************************************************************************************//**
 * Receive data full interrupt routine.
 *
 * This function implements the IIC Receive buffer full ISR routine.
 *
 **********************************************************************************************************************/
void iic_master_rxi_isr (void)
{
    /* Clear the IR flag */
    IRQn_Type irq = R_FSP_CurrentIrqGet();
    R_BSP_IrqStatusClear(irq);

    iic_master_instance_ctrl_t * p_ctrl = (iic_master_instance_ctrl_t *) R_FSP_IsrContextGet(irq);
    iic_master_rxi_master(p_ctrl);
}

/*******************************************************************************************************************//**
 * Transmit data empty interrupt routine.
 *
 * This function implements the Transmit buffer empty ISR routine.
 *
 **********************************************************************************************************************/
void iic_master_txi_isr (void)
{
    /* Clear the IR flag */
    IRQn_Type irq = R_FSP_CurrentIrqGet();
    R_BSP_IrqStatusClear(irq);

    iic_master_instance_ctrl_t * p_ctrl = (iic_master_instance_ctrl_t *) R_FSP_IsrContextGet(irq);
    iic_master_txi_master(p_ctrl);
}

/*******************************************************************************************************************//**
 * Transmit end interrupt routine.
 *
 * This function implements the IIC Transmission End ISR routine.
 *
 **********************************************************************************************************************/
void iic_master_tei_isr (void)
{
    IRQn_Type irq = R_FSP_CurrentIrqGet();
    iic_master_instance_ctrl_t * p_ctrl = (iic_master_instance_ctrl_t *) R_FSP_IsrContextGet(irq);
    iic_master_tei_master(p_ctrl);

    /* Clear the IR flag */
    R_BSP_IrqStatusClear(R_FSP_CurrentIrqGet());
}

/*******************************************************************************************************************//**
 * Error and event interrupt routine.
 *
 * This function implements the IIC Event/Error.
 *
 **********************************************************************************************************************/
void iic_master_eri_isr (void)
{
    IRQn_Type irq = R_FSP_CurrentIrqGet();
    iic_master_instance_ctrl_t * p_ctrl = (iic_master_instance_ctrl_t *) R_FSP_IsrContextGet(irq);
    iic_master_err_master(p_ctrl);

    /* Clear the IR flag */
    R_BSP_IrqStatusClear(irq);
}
