469 lines
16 KiB
C
469 lines
16 KiB
C
/*******************************************************************************
|
|
* 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 i2c5_read().
|
|
*****************************************************************************/
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <types.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 IP1SR8_SDA5_MASK (0x0000F000U) /* bit[15:12] */
|
|
#define IP1SR8_SCL5_MASK (0x00000F00U) /* bit[11:8] */
|
|
#define IP1SR8_SDA5 (0x00000000U) /* bit[15:12] */
|
|
#define IP1SR8_SCL5 (0x00000000U) /* bit[11:8] */
|
|
#define GPSR8_SDA5 (0x00000800U) /* bit11 */
|
|
#define GPSR8_SCL5 (0x00000400U) /* bit10 */
|
|
#define MODSEL8_SDA5 (0x00000800U) /* bit11 */
|
|
#define MODSEL8_SCL5 (0x00000400U) /* bit10 */
|
|
#define PUEN8_SDA5 (0x00000800U) /* bit11 */
|
|
#define PUEN8_SCL5 (0x00000400U) /* bit10 */
|
|
|
|
#define CPG_MSTPCR_I2C5 (((uint32_t)1U) << 23U)
|
|
|
|
static void i2c5_init_pin_function(void);
|
|
|
|
void i2c5_init(void)
|
|
{
|
|
uint32_t reg;
|
|
|
|
/*
|
|
* Module Standby setting for I2C5
|
|
*/
|
|
reg = mem_read32(CPG_MSTPSR5D0);
|
|
/* If supply of clock to I2C5 is stopped */
|
|
if (FALSE != (CPG_MSTPCR_I2C5 & reg))
|
|
{
|
|
/* Supply of clock to I2C5 is start */
|
|
reg &= ~(CPG_MSTPCR_I2C5);
|
|
cpg_reg_write(CPG_MSTPCR5D0, CPG_MSTPSR5D0, reg);
|
|
}
|
|
|
|
/* PFC setting for I2C5. */
|
|
i2c5_init_pin_function();
|
|
|
|
/* clock init */
|
|
/* CDFD=1, HLSE=1, SME=1, FMPE=1 */
|
|
mem_write32((uintptr_t)I2C5_ICCCR2, 0x7U | (1 << 7));
|
|
//Clock to filter glitches = 133.3/(1 + 6) = 19Mhz
|
|
mem_write32((uintptr_t)I2C5_ICCCR, 0x6);
|
|
mem_write32((uintptr_t)I2C5_ICMPR, 21);
|
|
mem_write32((uintptr_t)I2C5_ICHPR, 133);
|
|
mem_write32((uintptr_t)I2C5_ICLPR, 150);
|
|
/* 1st bit setup cycle */
|
|
mem_write32((uintptr_t)I2C5_ICFBSCR, 0x07);
|
|
|
|
/* reset slave interface */
|
|
mem_write32((uintptr_t)I2C5_ICSIER, 0U);
|
|
mem_write32((uintptr_t)I2C5_ICSCR, FLAG_SDBS);
|
|
mem_write32((uintptr_t)I2C5_ICSAR, 0U);
|
|
mem_write32((uintptr_t)I2C5_ICSSR, 0U);
|
|
|
|
/* reset master interface */
|
|
mem_write32((uintptr_t)I2C5_ICMIER, 0U);
|
|
mem_write32((uintptr_t)I2C5_ICMCR, FLAG_MDBS);
|
|
mem_write32((uintptr_t)I2C5_ICMAR, 0U);
|
|
mem_write32((uintptr_t)I2C5_ICMSR, 0U);
|
|
}
|
|
/* End of function i2c5_init(void) */
|
|
|
|
static void i2c5_init_pin_function(void)
|
|
{
|
|
uint32_t data;
|
|
|
|
/* SDA5(GP8_11), SCL5(GP8_10) -> 0 */
|
|
data = mem_read32((uintptr_t)PFC_IP1SR8_RW);
|
|
data &= ~(IP1SR8_SDA5_MASK | IP1SR8_SCL5_MASK);
|
|
// data |= (IP1SR8_SDA5 | IP1SR8_SCL5); /* useless */
|
|
pfc_reg_write(PFC_IP1SR8_RW, data);
|
|
|
|
/* SDA5, SCL5 -> 1 */
|
|
data = mem_read32((uintptr_t)PFC_GPSR8_RW);
|
|
data |= (GPSR8_SDA5 | GPSR8_SCL5);
|
|
pfc_reg_write(PFC_GPSR8_RW, data);
|
|
|
|
/* Select SDA5 and SCL5 to I2C mode */
|
|
data = mem_read32((uintptr_t)PFC_MODSEL8_RW);
|
|
data |= (MODSEL8_SDA5 | MODSEL8_SCL5);
|
|
pfc_reg_write(PFC_MODSEL8_RW, data);
|
|
|
|
/* SDA5, SCL5 -> 0 */
|
|
data = mem_read32((uintptr_t)PFC_PUEN8_RW);
|
|
data &= ~(PUEN8_SDA5 | PUEN8_SCL5);
|
|
pfc_reg_write(PFC_PUEN8_RW, data);
|
|
}
|
|
/* End of function i2c5_init_pin_function(void) */
|
|
|
|
static void i2c5_set_address_reg(uint32_t slaveAdd, uint32_t regAdd)
|
|
{
|
|
uint32_t data;
|
|
uint32_t err_count = 0U;
|
|
uint32_t status;
|
|
|
|
while(true)
|
|
{
|
|
data = mem_read32((uintptr_t)I2C5_ICMCR);
|
|
data &= (FLAG_FSCL | FLAG_FSDA);
|
|
if(data == FLAG_FSCL)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* 107.3.10.1. Master Transmitter
|
|
(b) set value for the master control registers, first data byte, and address */
|
|
status = I2C_NG;
|
|
while(I2C_NG == status)
|
|
{
|
|
/* Clear all ICMSR */
|
|
mem_write32((uintptr_t)I2C5_ICMSR, 0U);
|
|
/* Set slave address */
|
|
slaveAdd &= ~FLG_RW; /* write mode */
|
|
mem_write32((uintptr_t)I2C5_ICMAR, slaveAdd);
|
|
/* Set register address */
|
|
mem_write32((uintptr_t)I2C5_ICTXD, regAdd);
|
|
|
|
while(true)
|
|
{
|
|
data = mem_read32((uintptr_t)I2C5_ICMCR);
|
|
data &= (FLAG_FSCL | FLAG_FSDA);
|
|
if(data == FLAG_FSCL)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* 5. set the Master Control register (ICMCR) = H'89 */
|
|
/* Set MDBS, MIE and ESG */
|
|
mem_write32((uintptr_t)I2C5_ICMCR, (FLAG_MDBS | FLAG_MIE | FLAG_ESG)); /* start condition */
|
|
|
|
/* (c) waiting for outputting address
|
|
1. wait for master event (ICMSR.MAT and ICMSR.MDE) */
|
|
/* MDE(master data empty) & MAT(master address transmitted) */
|
|
status = i2c5_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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void __i2c5_write(uint32_t slaveAdd, uint32_t regAdd, uint32_t setData)
|
|
{
|
|
uint32_t data;
|
|
uint32_t err_count = 0U;
|
|
uint32_t status;
|
|
|
|
/* 107.3.10.1. Master Transmitter */
|
|
i2c5_set_address_reg(slaveAdd, regAdd);
|
|
|
|
/* 2. set ICMCR to H'88 */
|
|
mem_write32((uintptr_t)I2C5_ICMCR, (FLAG_MDBS | FLAG_MIE));
|
|
|
|
status = I2C_NG;
|
|
while(I2C_NG == status)
|
|
{
|
|
/* 3. Clear the ICMSR.MAT and ICMSR.MDE bits. */
|
|
data = mem_read32((uintptr_t)I2C5_ICMSR);
|
|
data &= __INV(FLAG_MAT | FLAG_MDE);
|
|
mem_write32((uintptr_t)I2C5_ICMSR, data);
|
|
|
|
/* (d). Monitoring transmission of data
|
|
1. wait for master event ICMSR.MDE(master data empty) */
|
|
status = i2c5_err_check(FLAG_MDE, FLAG_NONE, FLAG_MNR);
|
|
if(I2C_NG == status)
|
|
{
|
|
err_count++;
|
|
if(err_count > ERR_MAX)
|
|
{
|
|
ERROR("2:I2C data write error\n");
|
|
panic;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 2. ICTXD = data */
|
|
mem_write32((uintptr_t)I2C5_ICTXD, setData);
|
|
|
|
/* 3. clear the ICMSR.MDE bit
|
|
Clear ICMSR.MDE after setting the last byte to be transmitted.
|
|
After the last byte data is loaded into the shift register,
|
|
ICMSR.MDE is generated. Before clearning ICMSR.MDE, you must
|
|
set ICMCR to H'8A (set the force stop control bit). */
|
|
status = I2C_NG;
|
|
while(I2C_NG == status)
|
|
{
|
|
data = mem_read32((uintptr_t)I2C5_ICMSR);
|
|
data &= __INV(FLAG_MDE);
|
|
mem_write32((uintptr_t)I2C5_ICMSR, data);
|
|
|
|
status = i2c5_err_check(FLAG_MDE, FLAG_NONE, FLAG_MNR);
|
|
if(I2C_NG == status)
|
|
{
|
|
err_count++;
|
|
if(err_count > ERR_MAX)
|
|
{
|
|
ERROR("3:I2C data write error\n");
|
|
panic;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Before clearning ICMSR.MDE, you must
|
|
set ICMCR to H'8A (set the force stop control bit). */
|
|
mem_write32((uintptr_t)I2C5_ICMCR, (FLAG_MDBS | FLAG_MIE | FLAG_FSB));
|
|
|
|
status = I2C_NG;
|
|
while(I2C_NG == status)
|
|
{
|
|
data = mem_read32((uintptr_t)I2C5_ICMSR);
|
|
data &= __INV(FLAG_MDE);
|
|
mem_write32((uintptr_t)I2C5_ICMSR, data);
|
|
|
|
/* (e) wait for end of transmission
|
|
1. wait for the master event, ICMSR.MST */
|
|
status = i2c5_err_check(FLAG_MST, FLAG_NONE, FLAG_MNR);
|
|
if(I2C_NG == status)
|
|
{
|
|
err_count++;
|
|
if(err_count > ERR_MAX)
|
|
{
|
|
ERROR("3:I2C data write error\n");
|
|
panic;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 2. clear the ICMSR.MST bit */
|
|
data = mem_read32((uintptr_t)I2C5_ICMSR);
|
|
data &= __INV(FLAG_MST);
|
|
mem_write32((uintptr_t)I2C5_ICMSR, data);
|
|
}
|
|
/* End of function i2c5_write(uint32_t slaveAdd, uint32_t regAdd, uint32_t setData) */
|
|
|
|
static void __i2c5_read(uint32_t slaveAdd, uint32_t regAdd, uint32_t *revData)
|
|
{
|
|
uint32_t data;
|
|
uint32_t err_count = 0;
|
|
uint32_t status;
|
|
|
|
/* 107.3.10.3. Master Transmitter - repeated START - Master receiver */
|
|
i2c5_set_address_reg(slaveAdd, regAdd);
|
|
|
|
status = I2C_NG;
|
|
while(I2C_NG == status)
|
|
{
|
|
/* 2. set ICMAR to address of slave ... (read mode: 1) */
|
|
/* Set slave address */
|
|
slaveAdd |= FLG_RW; /* read mode */
|
|
mem_write32((uintptr_t)I2C5_ICMAR, slaveAdd);
|
|
/* Set MDBS, MIE and ESG */
|
|
mem_write32((uintptr_t)I2C5_ICMCR, (FLAG_MDBS | FLAG_MIE | FLAG_ESG)); /* start condition */
|
|
/* 3. Clear the ICMSR.MAT and ICMSR.MDE bits. */
|
|
data = mem_read32((uintptr_t)I2C5_ICMSR);
|
|
data &= __INV(FLAG_MAT | FLAG_MDE);
|
|
mem_write32((uintptr_t)I2C5_ICMSR, data);
|
|
|
|
/* (d). Monitor transmission of data.
|
|
1. wait for master event, ICMSR.MDE */
|
|
/* MDE(master data empty) */
|
|
status = i2c5_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)
|
|
{
|
|
/* 2. set ICMCR = H'89 (MDBS = 1, MIE = 1, ESG = 1) */
|
|
mem_write32((uintptr_t)I2C5_ICMCR, (FLAG_MDBS | FLAG_MIE | FLAG_ESG)); /* start condition */
|
|
|
|
/* 3. clear the MDE bit. */
|
|
data = mem_read32((uintptr_t)I2C5_ICMSR);
|
|
data &= __INV(FLAG_MDE);
|
|
mem_write32((uintptr_t)I2C5_ICMSR, data);
|
|
|
|
/* (e) wait for outputting slave-address of master reception
|
|
1. wait for master event (ICMSR.MAT and ICMSR.MDR bits.) */
|
|
status = i2c5_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)
|
|
{
|
|
/* 2. set ICMCR to H'88(MDBS, MIE) */
|
|
mem_write32((uintptr_t)I2C5_ICMCR, (FLAG_MDBS | FLAG_MIE));
|
|
/* 3. clear the ICMSR.MAT and ICMSR.MDR bits. */
|
|
data = mem_read32((uintptr_t)I2C5_ICMSR);
|
|
data &= __INV(FLAG_MAT | FLAG_MDR);
|
|
mem_write32((uintptr_t)I2C5_ICMSR, data);
|
|
/* (f) Monitor reception of data
|
|
3. set ICMR.FSB to 1 before the last byte data transfer is started */
|
|
mem_write32((uintptr_t)I2C5_ICMCR, (FLAG_MDBS | FLAG_MIE | FLAG_FSB)); /* stop condition */
|
|
/* (g) Monitor reception of data
|
|
1. handle the receive interrupt(ICMSR.MDR) in the last byte:
|
|
that is, read the data and clear the ICMSR.MDR. */
|
|
status = i2c5_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)I2C5_ICRXD) & 0x000000FFU;
|
|
}
|
|
/* clear ICMSR.MDR */
|
|
data = mem_read32((uintptr_t)I2C5_ICMSR);
|
|
data &= __INV(FLAG_MDR);
|
|
mem_write32((uintptr_t)I2C5_ICMSR, data);
|
|
}
|
|
|
|
/* 2. wait for master event, ICMSR.MST */
|
|
while(true)
|
|
{
|
|
data = mem_read32((uintptr_t)I2C5_ICMSR);
|
|
if((data & FLAG_MST) != 0U)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* 3. clear the ICMSR.MST(master stop transmitted) bit */
|
|
data = mem_read32((uintptr_t)I2C5_ICMSR);
|
|
data &= __INV(FLAG_MST);
|
|
mem_write32((uintptr_t)I2C5_ICMSR, data);
|
|
}
|
|
/* End of function i2c5_read(uint32_t slaveAdd, uint32_t regAdd, uint32_t *revData) */
|
|
|
|
uint32_t i2c5_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)I2C5_ICMSR);
|
|
if((data & first) != 0U)
|
|
{
|
|
if((second == FLAG_NONE) || ((data & second) != 0U))
|
|
{
|
|
status = I2C_OK;
|
|
break;
|
|
}
|
|
}
|
|
if((data & error) != 0U)
|
|
{
|
|
mem_write32((uintptr_t)I2C5_ICMSR, ~error);
|
|
status = I2C_NG;
|
|
break;
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
/* End of function i2c5_err_check(uint32_t first, uint32_t second, uint32_t error) */
|
|
|
|
void i2c5_release(void)
|
|
{
|
|
mem_write32((uintptr_t)I2C5_ICCCR2, 0x00000000U);
|
|
mem_write32((uintptr_t)I2C5_ICCCR, 0x00000000U);
|
|
mem_write32((uintptr_t)I2C5_ICSCR, 0x00000000U);
|
|
mem_write32((uintptr_t)I2C5_ICSSR, 0x00000000U);
|
|
mem_write32((uintptr_t)I2C5_ICSIER, 0x00000000U);
|
|
mem_write32((uintptr_t)I2C5_ICSAR, 0x00000000U);
|
|
mem_write32((uintptr_t)I2C5_ICMCR, 0x00000000U);
|
|
mem_write32((uintptr_t)I2C5_ICMSR, 0x00000000U);
|
|
mem_write32((uintptr_t)I2C5_ICMIER, 0x00000000U);
|
|
mem_write32((uintptr_t)I2C5_ICMAR, 0x00000000U);
|
|
}
|
|
/* End of function i2c5_release(void) */
|
|
|
|
static uint32_t cur_page = 0x00;
|
|
static inline void i2c5_page_change(uint32_t slaveAdd, uint32_t new_page) {
|
|
if (cur_page != new_page) {
|
|
__i2c5_write(slaveAdd, 0x00, new_page);
|
|
__i2c5_write(slaveAdd, 0x00, new_page);
|
|
__i2c5_read(slaveAdd, 0x00, &cur_page);
|
|
if (cur_page != new_page) {
|
|
ERROR("I2C5: page change error (0x%x:0x%x)\n", cur_page, new_page);
|
|
panic;
|
|
}
|
|
}
|
|
}
|
|
|
|
void i2c5_write(uint32_t slaveAdd, uint32_t regAdd, uint32_t revData) {
|
|
i2c5_page_change(slaveAdd, (regAdd & 0xFF00) >> 8);
|
|
__i2c5_write(slaveAdd, regAdd & 0xFF, revData);
|
|
}
|
|
|
|
void i2c5_read(uint32_t slaveAdd, uint32_t regAdd, uint32_t *revData) {
|
|
i2c5_page_change(slaveAdd, (regAdd & 0xFF00) >> 8);
|
|
__i2c5_read(slaveAdd, regAdd & 0xFF, revData);
|
|
}
|