/*******************************************************************************
 * DISCLAIMER
 * This software is supplied by Renesas Electronics Corporation and is only
 * intended for use with Renesas products. No other uses are authorized. This
 * software is owned by Renesas Electronics Corporation and is protected under
 * all applicable laws, including copyright laws.
 * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
 * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
 * LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
 * TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
 * ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
 * FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
 * ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * Renesas reserves the right, without notice, to make changes to this software
 * and to discontinue the availability of this software. By using this software,
 * you agree to the additional terms and conditions found by accessing the
 * following link:
 * http://www.renesas.com/disclaimer
 * Copyright 2023-2024 Renesas Electronics Corporation All rights reserved.
 *******************************************************************************/

/*******************************************************************************
 * DESCRIPTION   : I2C driver
 ******************************************************************************/
/******************************************************************************
 * @file          i2c.c
 * - Version      : 0.02
 * @brief         I2C driver.
 * .
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 16.11.2023 0.01     First Release
 *         : 24.06.2024 0.02     Remove pre-process branch of i2c3_read().
 *****************************************************************************/

#include <stdbool.h>
#include <stdint.h>
#include <cpg.h>
#include <cpg_register.h>
#include <i2c.h>
#include <i2c_register.h>
#include <log.h>
#include <mem_io.h>
#include <pfc.h>
#include <pfc_register.h>

/* Setting value for PFC */
#define IP0SR4_SDA3         (0xF0000000U)   /* bit[31:28] */
#define IP0SR4_SCL3         (0x0F000000U)   /* bit[27:24] */
#define GPSR4_SDA3          (0x00000080U)   /* bit7 */
#define GPSR4_SCL3          (0x00000040U)   /* bit6 */
#define MODSEL4_SDA3        (0x00000080U)   /* bit7 */
#define MODSEL4_SCL3        (0x00000040U)   /* bit6 */
#define PUEN4_SDA3          (0x00000080U)   /* bit7 */
#define PUEN4_SCL3          (0x00000040U)   /* bit6 */

static void i2c3_init_pin_function(void);

void i2c3_init(void)
{
    /*
     * Module Standby setting for I2C3 is not nessesary
     * because H/W initial value is 'Enables supply of the clock signal'.
     */

    /* PFC setting for I2C3. */
    i2c3_init_pin_function();

    /* CDFD=0, HLSE=0, SME=0 */
    mem_write32((uintptr_t)I2C3_ICCCR2, 0x00000000U);
    /* SCGD=H'3, CDF=H'6 */
    mem_write32((uintptr_t)I2C3_ICCCR,  (SET_SCGD | SET_CDF));

    mem_write32((uintptr_t)I2C3_ICSCR,  0x00000000U);
    mem_write32((uintptr_t)I2C3_ICSSR,  0x00000000U);
    mem_write32((uintptr_t)I2C3_ICSIER, 0x00000000U);
    mem_write32((uintptr_t)I2C3_ICSAR,  0x00000000U);
    mem_write32((uintptr_t)I2C3_ICMCR,  (FLAG_MDBS | FLAG_MIE));
    mem_write32((uintptr_t)I2C3_ICMSR,  0x00000000U);
    mem_write32((uintptr_t)I2C3_ICMIER, 0x00000000U);
    mem_write32((uintptr_t)I2C3_ICMAR,  0x00000000U);
}
/* End of function i2c3_init(void) */

static void i2c3_init_pin_function(void)
{
    uint32_t data;

    /* SDA3, SCL3 -> 0 */
    data  = mem_read32((uintptr_t)PFC_IP0SR4_RW);
    data &= ~(IP0SR4_SDA3 | IP0SR4_SCL3);
    pfc_reg_write(PFC_IP0SR4_RW, data);

    /* SDA3, SCL3 -> 1 */
    data  = mem_read32((uintptr_t)PFC_GPSR4_RW);
    data |= (GPSR4_SDA3 | GPSR4_SCL3);
    pfc_reg_write(PFC_GPSR4_RW, data);

    /* Select SDA3 and SCL3 to I2C mode */
    data  = mem_read32((uintptr_t)PFC_MODSEL4_RW);
    data |= (MODSEL4_SDA3 | MODSEL4_SCL3);
    pfc_reg_write(PFC_MODSEL4_RW, data);

    /* SDA3, SCL3 -> 0 */
    data  = mem_read32((uintptr_t)PFC_PUEN4_RW);
    data &= ~(PUEN4_SDA3 | PUEN4_SCL3);
    pfc_reg_write(PFC_PUEN4_RW, data);
}
/* End of function i2c3_init_pin_function(void) */

void i2c3_write(uint32_t slaveAdd, uint32_t regAdd, uint32_t setData)
{
    uint32_t data;
    uint32_t err_count = 0U;
    uint32_t status;

    while(true)
    {
        data  = mem_read32((uintptr_t)I2C3_ICMCR);
        data &= (FLAG_FSCL | FLAG_FSDA);
        if(data == FLAG_FSCL)
        {
            break;
        }
    }

    status = I2C_NG;
    while(I2C_NG == status)
    {
        /* Set MDBS and MIE (initialize) */
        mem_write32((uintptr_t)I2C3_ICMCR, (FLAG_MDBS | FLAG_MIE));
        /* Set slave address */
        slaveAdd &= ~FLG_RW;    /* write mode */
        mem_write32((uintptr_t)I2C3_ICMAR, slaveAdd);
        /* Set register address */
        mem_write32((uintptr_t)I2C3_ICTXD, regAdd);

        while(true)
        {
            data  = mem_read32((uintptr_t)I2C3_ICMCR);
            data &= (FLAG_FSCL | FLAG_FSDA);
            if(data == FLAG_FSCL)
            {
                break;
            }
        }

        /* Set MDBS, MIE and ESG */
        mem_write32((uintptr_t)I2C3_ICMCR, (FLAG_MDBS | FLAG_MIE | FLAG_ESG));  /* start condition */

        /* MDE(master data empty) & MAT(master address transmitted */
        status = i2c3_err_check(FLAG_MDE, FLAG_MAT, (FLAG_MNR|FLAG_MAL));
        if(I2C_NG == status)
        {
            err_count++;
            if(err_count > ERR_MAX)
            {
                ERROR("1:I2C data write error\n");
                panic;
            }
        }
    }

    mem_write32((uintptr_t)I2C3_ICMCR, (FLAG_MDBS | FLAG_MIE));

    status = I2C_NG;
    while(I2C_NG == status)
    {
        /* MDE and MAT clear */
        data  = mem_read32((uintptr_t)I2C3_ICMSR);
        data &= (FLAG_MNR | FLAG_MAL | FLAG_MST | FLAG_MDT | FLAG_MDR);
        mem_write32((uintptr_t)I2C3_ICMSR, data);
        /* MDE(master data empty) & MDT(master data transmitted) */
        status = i2c3_err_check(FLAG_MDE, FLAG_MDT, FLAG_MNR);
        if(I2C_NG == status)
        {
            err_count++;
            if(err_count > ERR_MAX)
            {
                ERROR("2:I2C data write error\n");
                panic;
            }
        }
    }

    status = I2C_NG;
    while(I2C_NG == status)
    {
        /* send voltage */
        mem_write32((uintptr_t)I2C3_ICTXD, setData);
        /* MDE and MAT clear */
        data  = mem_read32((uintptr_t)I2C3_ICMSR);
        data &= (FLAG_MNR | FLAG_MAL | FLAG_MST | FLAG_MDR | FLAG_MAT);
        mem_write32((uintptr_t)I2C3_ICMSR, data);
        /* MDE(master data empty) & MDT(master data transmitted) */
        status = i2c3_err_check(FLAG_MDE, FLAG_MDT, FLAG_MNR);
        if(I2C_NG == status)
        {
            err_count++;
            if(err_count > ERR_MAX)
            {
                ERROR("3:I2C data write error\n");
                panic;
            }
        }
    }

    /* Set MDBS, MIE and FSB */
    mem_write32((uintptr_t)I2C3_ICMCR, (FLAG_MDBS | FLAG_MIE | FLAG_FSB));  /* stop condition */
    mem_write32((uintptr_t)I2C3_ICMSR, 0x00000000U);    /* MST(master stop transmitted) clear */

    while(true)
    {
        data = mem_read32((uintptr_t)I2C3_ICMSR);
        if((data & FLAG_MST) != 0U) /* MST(master stop transmitted) */
        {
            break;
        }
    }

    mem_write32((uintptr_t)I2C3_ICMSR, 0x00000000U);
    mem_write32((uintptr_t)I2C3_ICMCR, (FLAG_MDBS | FLAG_MIE));

}
/* End of function i2c3_write(uint32_t slaveAdd, uint32_t regAdd, uint32_t setData) */

void i2c3_read(uint32_t slaveAdd, uint32_t regAdd, uint32_t *revData)
{
    uint32_t data;
    uint32_t err_count = 0;
    uint32_t status;

    while(true)
    {
        data  = mem_read32((uintptr_t)I2C3_ICMCR);
        data &= (FLAG_FSCL | FLAG_FSDA);
        if(data == FLAG_FSCL)
        {
            break;
        }
    }

    status = I2C_NG;
    while(I2C_NG == status)
    {
        /* Set MDBS and MIE (initialize) */
        mem_write32((uintptr_t)I2C3_ICMCR, (FLAG_MDBS | FLAG_MIE));
        /* Set slave address */
        slaveAdd &= ~FLG_RW;    /* write mode */
        mem_write32((uintptr_t)I2C3_ICMAR, slaveAdd);
        /* Set register address */
        mem_write32((uintptr_t)I2C3_ICTXD, regAdd);

        while(true)
        {
            data  = mem_read32((uintptr_t)I2C3_ICMCR);
            data &= (FLAG_FSCL | FLAG_FSDA);
            if(data == FLAG_FSCL)
            {
                break;
            }
        }

        /* Set MDBS, MIE and ESG */
        mem_write32((uintptr_t)I2C3_ICMCR, (FLAG_MDBS | FLAG_MIE | FLAG_ESG));  /* start condition */

        /* MDE(master data empty) & MAT(master address transmitted */
        status = i2c3_err_check(FLAG_MDE, FLAG_MAT, (FLAG_MNR|FLAG_MAL));
        if(I2C_NG == status)
        {
            err_count++;
            if(err_count > ERR_MAX)
            {
                ERROR("1:I2C data read  error\n");
                panic;
            }
        }
    }

    mem_write32((uintptr_t)I2C3_ICMCR, (FLAG_MDBS | FLAG_MIE));

    status = I2C_NG;
    while(I2C_NG == status)
    {
        /* MDE and MAT clear */
        data  = mem_read32((uintptr_t)I2C3_ICMSR);
        data &= 0x000000F6U;
        mem_write32((uintptr_t)I2C3_ICMSR, data);
        /* MDE(master data empty) */
        status = i2c3_err_check(FLAG_MDE, FLAG_NONE, FLAG_MNR);
        if(I2C_NG == status)
        {
            err_count++;
            if(err_count > ERR_MAX)
            {
                ERROR("2:I2C data read  error\n");
                panic;
            }
        }
    }

    status = I2C_NG;
    while(I2C_NG == status)
    {
        /* Set slave address */
        slaveAdd |= FLG_RW; /* read mode */
        mem_write32((uintptr_t)I2C3_ICMAR, slaveAdd);
        /* Set MDBS, MIE and ESG */
        mem_write32((uintptr_t)I2C3_ICMCR, (FLAG_MDBS | FLAG_MIE | FLAG_ESG));  /* start condition */
        mem_write32((uintptr_t)I2C3_ICMSR, 0x00000000U);

        /* MDR(master data recieved) & MAT(master address transmitted) */
        status = i2c3_err_check(FLAG_MDR, FLAG_MAT, (FLAG_MNR|FLAG_MAL));
        if(I2C_NG == status)
        {
            err_count++;
            if(err_count > ERR_MAX)
            {
                ERROR("3:I2C data read  error\n");
                panic;
            }
        }
    }

    status = I2C_NG;
    while(I2C_NG == status)
    {
        /* Set MDBS, MIE and FSB */
        mem_write32((uintptr_t)I2C3_ICMCR, (FLAG_MDBS | FLAG_MIE | FLAG_FSB));  /* stop condition */
        /* MDE and MAT clear */
        data  = mem_read32((uintptr_t)I2C3_ICMSR);
        data &= 0x000000FCU;
        mem_write32((uintptr_t)I2C3_ICMSR, data);
        status = i2c3_err_check(FLAG_MDR, FLAG_NONE, FLAG_MNR);
        if(I2C_NG == status)
        {
            err_count++;
            if(err_count > ERR_MAX)
            {
                ERROR("4:I2C data read error\n");
                panic;
            }
        }
        if(I2C_OK == status)
        {
            *revData = mem_read32((uintptr_t)I2C3_ICRXD) & 0x000000FFU;
        }
        mem_write32((uintptr_t)I2C3_ICMSR, 0x00000000U);    /* MST(master stop transmitted) clear */
    }

    while(true)
    {
        data = mem_read32((uintptr_t)I2C3_ICMSR);
        if((data & FLAG_MST) != 0U)
        {
            break;
        }
    }

    mem_write32((uintptr_t)I2C3_ICMSR, 0x00000000U);
    mem_write32((uintptr_t)I2C3_ICMCR, (FLAG_MDBS | FLAG_MIE));
}
/* End of function i2c3_read(uint32_t slaveAdd, uint32_t regAdd, uint32_t *revData) */

uint32_t i2c3_err_check(uint32_t first, uint32_t second, uint32_t error)
{
    uint32_t data;
    uint32_t status = I2C_OK;

    while(true)
    {
        data = mem_read32((uintptr_t)I2C3_ICMSR);
        if((data & first) != 0U)
        {
            if((second == FLAG_NONE) || ((data & second) != 0U))
            {
                status = I2C_OK;
                break;
            }
        }
        if((data & error) != 0U)
        {
            mem_write32((uintptr_t)I2C3_ICMSR, ~error);
            status = I2C_NG;
            break;
        }
    }
    return status;
}
/* End of function i2c3_err_check(uint32_t first, uint32_t second, uint32_t error) */

void i2c3_release(void)
{
    mem_write32((uintptr_t)I2C3_ICCCR2, 0x00000000U);
    mem_write32((uintptr_t)I2C3_ICCCR,  0x00000000U);
    mem_write32((uintptr_t)I2C3_ICSCR,  0x00000000U);
    mem_write32((uintptr_t)I2C3_ICSSR,  0x00000000U);
    mem_write32((uintptr_t)I2C3_ICSIER, 0x00000000U);
    mem_write32((uintptr_t)I2C3_ICSAR,  0x00000000U);
    mem_write32((uintptr_t)I2C3_ICMCR,  0x00000000U);
    mem_write32((uintptr_t)I2C3_ICMSR,  0x00000000U);
    mem_write32((uintptr_t)I2C3_ICMIER, 0x00000000U);
    mem_write32((uintptr_t)I2C3_ICMAR,  0x00000000U);
}
/* End of function i2c3_release(void) */
