rustl8710/component/soc/realtek/8195a/fwlib/rtl8195a/src/rtl8195a_i2c.c
2016-12-30 18:23:39 -05:00

539 lines
No EOL
18 KiB
C

/*
* Routines to access hardware
*
* Copyright (c) 2013 Realtek Semiconductor Corp.
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*/
#include "rtl8195a.h"
/* Used only for A~C Version */
#ifndef CONFIG_CHIP_E_CUT
//---------------------------------------------------------------------------------------------------
//Function Name:
// HalI2CSendRtl8195a
//
// Description:
// Send one byte to the I2C internal fifo, it will generate START and STOP bit
// automatically.
//
// Arguments:
// [in] VOID *Data -
// The I2C parameter data struct.
//
// Return:
// _EXIT_SUCCESS if the sending succeeded.
// _EXIT_FAILURE if the sending failed.
//
// Note:
// None
//
// See Also:
// NA
//
// Author:
// By Jason Deng, 2014-02-18.
//
//---------------------------------------------------------------------------------------------------
HAL_Status
HalI2CSendRtl8195a_Patch(
IN VOID *Data
){
PHAL_I2C_INIT_DAT pHalI2CInitData = (PHAL_I2C_INIT_DAT)Data;
u8 I2CIdx = pHalI2CInitData->I2CIdx;
u8 *pDat = pHalI2CInitData->I2CRWData;
u8 I2CCmd = pHalI2CInitData->I2CCmd;
u8 I2CStop = pHalI2CInitData->I2CStop;
u8 I2CReSTR= pHalI2CInitData->I2CReSTR;
DBG_I2C_INFO("HalI2CSendRtl8195a\n");
DBG_I2C_INFO("I2C Index: %x\n",I2CIdx);
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_DATA_CMD,
*(pDat) |
BIT_CTRL_IC_DATA_CMD_RESTART(I2CReSTR)|
BIT_CTRL_IC_DATA_CMD_CMD(I2CCmd) |
BIT_CTRL_IC_DATA_CMD_STOP(I2CStop));
return (HAL_OK);
}
//---------------------------------------------------------------------------------------------------
//Function Name:
// HalI2CInit8195a
//
// Description:
// To initialize I2C module by using the given data.
//
// Arguments:
// [in] VOID *Data -
// The I2C parameter data struct.
//
// Return:
// The status of the DeInit process.
// _EXIT_SUCCESS if the initialization succeeded.
// _EXIT_FAILURE if the initialization failed.
//
// Note:
// None
//
// See Also:
// NA
//
// Author:
// By Jason Deng, 2014-04-02.
//
//---------------------------------------------------------------------------------------------------
HAL_Status
HalI2CMassSendRtl8195a_Patch(
IN VOID *Data
){
PHAL_I2C_INIT_DAT pHalI2CInitData = (PHAL_I2C_INIT_DAT)Data;
u8 I2CIdx = pHalI2CInitData->I2CIdx;
u8 I2CCmd = pHalI2CInitData->I2CCmd;
u8 I2CDatLen = pHalI2CInitData->I2CDataLen;
u8 *pDat = pHalI2CInitData->I2CRWData;
u8 I2CStopSet = pHalI2CInitData->I2CStop;
u8 I2CSTP;
u8 I2CReSRT = 0;
u8 DatCnt = 0;
/* Send I2C data one by one. The STOP bit is only used for the last byte.*/
for (DatCnt = 0; DatCnt < I2CDatLen; DatCnt++)
{
I2CSTP = 0;
if ((DatCnt == (I2CDatLen - 1)) && (I2CStopSet != 0)) {
I2CSTP = 1;
}
if ((DatCnt == 0) && ((pHalI2CInitData->RSVD0 & BIT0) != 0)) {
I2CReSRT = 1;
}
else {
I2CReSRT = 0;
}
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_DATA_CMD,
*(pDat+DatCnt) |
BIT_CTRL_IC_DATA_CMD_CMD(I2CCmd) |
BIT_CTRL_IC_DATA_CMD_RESTART(I2CReSRT) |
BIT_CTRL_IC_DATA_CMD_STOP(I2CSTP));
}
return HAL_OK;
}
//---------------------------------------------------------------------------------------------------
//Function Name:
// HalI2CInit8195a
//
// Description:
// To initialize I2C module by using the given data.
//
// Arguments:
// [in] VOID *Data -
// The I2C parameter data struct.
//
// Return:
// The status of the DeInit process.
// _EXIT_SUCCESS if the initialization succeeded.
// _EXIT_FAILURE if the initialization failed.
//
// Note:
// None
//
// See Also:
// NA
//
// Author:
// By Jason Deng, 2014-04-02.
//
//---------------------------------------------------------------------------------------------------
HAL_Status
HalI2CInit8195a_Patch(
IN VOID *Data
)
{
PHAL_I2C_INIT_DAT pHalI2CInitData = (PHAL_I2C_INIT_DAT)Data;
u8 Master;
u8 I2CIdx;
u8 SpdMd;
u8 AddrMd;
u8 ReSTR;
u8 StartByte;
u8 Specical;
u8 GC;
u16 I2CAckAddr;
u16 SdaHd;
u8 SdaSetup;
u8 RXTL;
u8 TXTL;
u8 SlvNoAck;
u32 INTRMsk;
u8 TxDMARqLv;
u8 RxDMARqLv;
u32 I2CTmp;
/* Get the I2C parameters*/
I2CIdx = pHalI2CInitData->I2CIdx;
SpdMd = pHalI2CInitData->I2CSpdMod;
AddrMd = pHalI2CInitData->I2CAddrMod;
I2CAckAddr = pHalI2CInitData->I2CAckAddr;
Master = pHalI2CInitData->I2CMaster;
SdaHd = pHalI2CInitData->I2CSdaHd;
SdaSetup = pHalI2CInitData->I2CSetup;
ReSTR = pHalI2CInitData->I2CReSTR;
GC = pHalI2CInitData->I2CGC;
StartByte = pHalI2CInitData->I2CStartB;
SlvNoAck = pHalI2CInitData->I2CSlvNoAck;
RXTL = pHalI2CInitData->I2CRXTL;
TXTL = pHalI2CInitData->I2CTXTL;
TxDMARqLv = pHalI2CInitData->I2CTxDMARqLv;
RxDMARqLv = pHalI2CInitData->I2CRxDMARqLv;
/* Disable the IC first */
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_ENABLE,BIT_CTRL_IC_ENABLE(0));
/* Master case*/
if (Master) {
/*RESTART MUST be set in these condition in Master mode.
But it might be NOT compatible in old slaves.*/
if ((AddrMd == I2C_ADDR_10BIT) || (SpdMd == I2C_HS_MODE))
ReSTR = 1;
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_CON,
(BIT_CTRL_IC_CON_IC_SLAVE_DISABLE(1) |
BIT_CTRL_IC_CON_IC_RESTART_EN(ReSTR) |
BIT_CTRL_IC_CON_IC_10BITADDR_MASTER(AddrMd) |
BIT_CTRL_IC_CON_SPEED(SpdMd) |
BIT_CTRL_IC_CON_MASTER_MODE(Master)));
DBG_I2C_INFO("Init master, IC_CON%d[%2x]: %x\n", I2CIdx, REG_DW_I2C_IC_CON, HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_CON));
/* To set target addr.*/
Specical = 0;
if ((GC!=0) || (StartByte!=0))
Specical = 1;
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_TAR,
(BIT_CTRL_IC_TAR_IC_10BITADDR_MASTER(AddrMd) |
BIT_CTRL_IC_TAR_SPECIAL(Specical) |
BIT_CTRL_IC_TAR_GC_OR_START(StartByte) |
BIT_CTRL_IC_TAR(I2CAckAddr)));
/* To Set I2C clock*/
HalI2CSetCLKRtl8195a_Patch(pHalI2CInitData);
DBG_I2C_INFO("Init master, IC_TAR%d[%2x]: %x\n", I2CIdx, REG_DW_I2C_IC_TAR, HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_TAR));
} /*if (Master)*/
else {
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_CON,
BIT_CTRL_IC_CON_IC_10BITADDR_SLAVE(AddrMd) |
BIT_CTRL_IC_CON_IC_SLAVE_DISABLE(Master) |
BIT_CTRL_IC_CON_SPEED(SpdMd)|
BIT_CTRL_IC_CON_MASTER_MODE(Master));
DBG_I2C_INFO("Init slave, IC_CON%d[%2x]: %x\n", I2CIdx, REG_DW_I2C_IC_CON, HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_CON));
/* To set slave addr. */
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_SAR,BIT_CTRL_IC_SAR(I2CAckAddr));
DBG_I2C_INFO("Init slave, IC_SAR%d[%2x]: %x\n", I2CIdx, REG_DW_I2C_IC_SAR, HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_SAR));
/* To set slave no ack */
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_SLV_DATA_NACK_ONLY,BIT_CTRL_IC_SLV_DATA_NACK_ONLY(SlvNoAck));
/* Set ack general call. */
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_ACK_GENERAL_CALL,BIT_CTRL_IC_ACK_GENERAL_CALL(pHalI2CInitData->I2CSlvAckGC));
DBG_I2C_INFO("Init slave, I2C_IC_ACK_GC%d[%2x]: %x\n", I2CIdx, REG_DW_I2C_IC_ACK_GENERAL_CALL, HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_ACK_GENERAL_CALL));
/* to set SDA hold time */
//HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_SDA_HOLD,BIT_CTRL_IC_SDA_HOLD(SdaHd));
//4
/* to set SDA setup time */
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_SDA_SETUP,BIT_CTRL_IC_SDA_SETUP(SdaSetup));
}
/* to set SDA hold time */
INTRMsk = HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_CON);
if (BIT_GET_IC_CON_SPEED(INTRMsk) == I2C_SS_MODE) {
I2CTmp = HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_SS_SCL_LCNT);
} else if (BIT_GET_IC_CON_SPEED(INTRMsk) == I2C_FS_MODE) {
I2CTmp = HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_FS_SCL_LCNT);
} else {
I2CTmp = HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_HS_SCL_LCNT);
}
if (Master) {
if (SdaHd > (I2CTmp -2)) {
I2CTmp = I2CTmp -2;
if (I2CTmp < 1) {
I2CTmp = 1 + 1;
}
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_SDA_HOLD,BIT_CTRL_IC_SDA_HOLD(I2CTmp));
} else {
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_SDA_HOLD,BIT_CTRL_IC_SDA_HOLD(SdaHd));
}
} else {
if (SdaHd > (I2CTmp -2)) {
I2CTmp = I2CTmp -2;
if (I2CTmp < 7) {
I2CTmp = 7 + 1;
}
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_SDA_HOLD,BIT_CTRL_IC_SDA_HOLD(I2CTmp));
} else {
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_SDA_HOLD,BIT_CTRL_IC_SDA_HOLD(SdaHd));
}
}
//DBG_8195A("SDA:%x\n", HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_SDA_HOLD));
/* To set TX_Empty Level */
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_TX_TL,TXTL);
/* To set RX_Full Level */
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_RX_TL,RXTL);
/* To set TX/RX FIFO level */
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_DMA_TDLR,TxDMARqLv);
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_DMA_RDLR,RxDMARqLv);
DBG_I2C_INFO("Init i2c dev, I2C_IC_DMA_TDLR%d[%2x]: %x\n", I2CIdx, REG_DW_I2C_IC_DMA_TDLR, HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_DMA_TDLR));
DBG_I2C_INFO("Init i2c dev, I2C_IC_DMA_RDLR%d[%2x]: %x\n", I2CIdx, REG_DW_I2C_IC_DMA_RDLR, HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_DMA_RDLR));
/*I2C Clear all interrupts first*/
HalI2CClrAllIntrRtl8195a(pHalI2CInitData);
/*I2C Disable all interrupts first*/
INTRMsk = pHalI2CInitData->I2CIntrMSK;
pHalI2CInitData->I2CIntrMSK = 0;
HalI2CIntrCtrl8195a(pHalI2CInitData);
pHalI2CInitData->I2CIntrMSK = INTRMsk;
return HAL_OK;
}
//---------------------------------------------------------------------------------------------------
//Function Name:
// HalI2CSetCLKRtl8195a
//
// Description:
// To set I2C bus clock rate.
//
// Arguments:
// [in] VOID *Data -
// The I2C parameter data struct.
//
// Return:
// The status of the enable process.
// _EXIT_SUCCESS if the de-initialization succeeded.
// _EXIT_FAILURE if the de-initialization failed.
//
// Note:
// None
//
// See Also:
// NA
//
// Author:
// By Jason Deng, 2014-02-18.
//
//---------------------------------------------------------------------------------------------------
HAL_Status
HalI2CSetCLKRtl8195a_Patch(
IN VOID *Data
)
{
PHAL_I2C_INIT_DAT pHalI2CInitData = (PHAL_I2C_INIT_DAT)Data;
u8 SpdMd = pHalI2CInitData->I2CSpdMod;
u32 I2CClk = pHalI2CInitData->I2CClk;
u8 I2CIdx = pHalI2CInitData->I2CIdx;
u32 ICHLcnt;
u32 ICHtime;
u32 ICLtime;
/* Get the IC-Clk setting first for the following process*/
#ifdef CONFIG_FPGA
u32 IcClk = SYSTEM_CLK/1000000;
#else
u32 IcClk;
u32 ClkSELTmp = 0;
u32 CpuClkTmp = 0;
#if defined(CONFIG_CHIP_A_CUT)
CpuClkTmp = StartupHalGetCpuClk();
#elif (defined(CONFIG_CHIP_B_CUT) || defined(CONFIG_CHIP_C_CUT))
CpuClkTmp = HalGetCpuClk();
#endif
DBG_I2C_INFO("%s, CPU Clk:%x\n",__func__, CpuClkTmp);
ClkSELTmp = HAL_READ32(PERI_ON_BASE, REG_PESOC_CLK_SEL);
ClkSELTmp &= (~(BIT_PESOC_PERI_SCLK_SEL(3)));
HAL_WRITE32(PERI_ON_BASE,REG_PESOC_CLK_SEL,ClkSELTmp);
IcClk = (CpuClkTmp/1000000)>>1;
#if 0
if ((I2CClk > 0) && (I2CClk <= 400)) {
ClkSELTmp &= (~(BIT_PESOC_PERI_SCLK_SEL(3)));
HAL_WRITE32(PERI_ON_BASE,REG_PESOC_CLK_SEL,ClkSELTmp);
IcClk = ClkSELTmp/1000000; /*actually it's 12.5MHz*/
}
else {
ClkSELTmp &= (~(BIT_PESOC_PERI_SCLK_SEL(3)));
HAL_WRITE32(PERI_ON_BASE,REG_PESOC_CLK_SEL,ClkSELTmp);
IcClk = 100;
}
#endif
#endif
switch (SpdMd)
{
case I2C_SS_MODE:
{
ICHtime = ((1000000/I2CClk)*I2C_SS_MIN_SCL_HTIME)/(I2C_SS_MIN_SCL_HTIME+I2C_SS_MIN_SCL_LTIME);
ICLtime = ((1000000/I2CClk)*I2C_SS_MIN_SCL_LTIME)/(I2C_SS_MIN_SCL_HTIME+I2C_SS_MIN_SCL_LTIME);
ICHLcnt = (ICHtime * IcClk)/1000;
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_SS_SCL_HCNT,ICHLcnt);
DBG_I2C_INFO("IC_SS_SCL_HCNT%d[%2x]: %x\n", I2CIdx,
REG_DW_I2C_IC_SS_SCL_HCNT, HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_SS_SCL_HCNT));
ICHLcnt = (ICLtime * IcClk)/1000;
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_SS_SCL_LCNT,ICHLcnt);
DBG_I2C_INFO("IC_SS_SCL_LCNT%d[%2x]: %x\n", I2CIdx,
REG_DW_I2C_IC_SS_SCL_LCNT, HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_SS_SCL_LCNT));
break;
}
case I2C_FS_MODE:
{
ICHtime = ((1000000/I2CClk)*I2C_FS_MIN_SCL_HTIME)/(I2C_FS_MIN_SCL_HTIME+I2C_FS_MIN_SCL_LTIME);
ICLtime = ((1000000/I2CClk)*I2C_FS_MIN_SCL_LTIME)/(I2C_FS_MIN_SCL_HTIME+I2C_FS_MIN_SCL_LTIME);
ICHLcnt = (ICHtime * IcClk)/1000;
if (ICHLcnt>4)/*this part is according to the fine-tune result*/
ICHLcnt -= 4;
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_FS_SCL_HCNT,ICHLcnt);
DBG_I2C_INFO("IC_FS_SCL_HCNT%d[%2x]: %x\n", I2CIdx,
REG_DW_I2C_IC_FS_SCL_HCNT, HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_FS_SCL_HCNT));
ICHLcnt = (ICLtime * IcClk)/1000;
if (ICHLcnt>3)/*this part is according to the fine-tune result*/
ICHLcnt -= 3;
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_FS_SCL_LCNT,ICHLcnt);
DBG_I2C_INFO("IC_FS_SCL_LCNT%d[%2x]: %x\n", I2CIdx,
REG_DW_I2C_IC_FS_SCL_LCNT, HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_FS_SCL_LCNT));
break;
}
case I2C_HS_MODE:
{
ICHLcnt = 400;
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_SS_SCL_HCNT,ICHLcnt);
ICHLcnt = 470;
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_SS_SCL_LCNT,ICHLcnt);
ICHLcnt = 60;
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_FS_SCL_HCNT,ICHLcnt);
ICHLcnt = 130;
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_FS_SCL_LCNT,ICHLcnt);
ICHtime = ((1000000/I2CClk)*I2C_HS_MIN_SCL_HTIME_100)/(I2C_HS_MIN_SCL_HTIME_100+I2C_HS_MIN_SCL_LTIME_100);
ICLtime = ((1000000/I2CClk)*I2C_HS_MIN_SCL_LTIME_100)/(I2C_HS_MIN_SCL_HTIME_100+I2C_HS_MIN_SCL_LTIME_100);
DBG_I2C_INFO("ICHtime:%x\n",ICHtime);
DBG_I2C_INFO("ICLtime:%x\n",ICLtime);
ICHLcnt = (ICHtime * IcClk)/1000;
if (ICHLcnt>8)/*this part is according to the fine-tune result*/
ICHLcnt -= 3;
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_HS_SCL_HCNT,ICHLcnt);
DBG_I2C_INFO("IC_HS_SCL_HCNT%d[%2x]: %x\n", I2CIdx,
REG_DW_I2C_IC_HS_SCL_HCNT, HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_HS_SCL_HCNT));
ICHLcnt = (ICLtime * IcClk)/1000;
if (ICHLcnt>6)/*this part is according to the fine-tune result*/
ICHLcnt -= 6;
HAL_I2C_WRITE32(I2CIdx,REG_DW_I2C_IC_HS_SCL_LCNT,ICHLcnt);
DBG_I2C_INFO("IC_HS_SCL_LCNT%d[%2x]: %x\n", I2CIdx,
REG_DW_I2C_IC_HS_SCL_LCNT, HAL_I2C_READ32(I2CIdx,REG_DW_I2C_IC_HS_SCL_LCNT));
break;
}
default:
break;
}
return HAL_OK;
}
HAL_Status
HalI2CEnableRtl8195a_Patch(
IN VOID *Data
){
PHAL_I2C_INIT_DAT pHalI2CInitData = (PHAL_I2C_INIT_DAT)Data;
u8 I2CIdx = pHalI2CInitData->I2CIdx;
u8 I2CICEn = pHalI2CInitData->I2CEn;
u32 I2CTimeoutCount;
u32 I2CStartCount;
/* Enable I2C module */
HAL_I2C_WRITE32(I2CIdx, REG_DW_I2C_IC_ENABLE, BIT_CTRL_IC_ENABLE(I2CICEn));
I2CTimeoutCount = ((10000/pHalI2CInitData->I2CClk) /TIMER_TICK_US) +1;
I2CStartCount = HalTimerOp.HalTimerReadCount(1);
if (!I2CICEn) {
while (HAL_I2C_READ32(I2CIdx, REG_DW_I2C_IC_ENABLE_STATUS) & BIT_IC_ENABLE_STATUS_IC_EN) {
if (HAL_TIMEOUT == I2CIsTimeout(I2CStartCount, I2CTimeoutCount)) {
return HAL_TIMEOUT;
}
}
} else {
while (!(HAL_I2C_READ32(I2CIdx, REG_DW_I2C_IC_ENABLE_STATUS) & BIT_IC_ENABLE_STATUS_IC_EN)) {
if (HAL_TIMEOUT == I2CIsTimeout(I2CStartCount, I2CTimeoutCount)) {
return HAL_TIMEOUT;
}
}
}
return HAL_OK;
}
#endif