mirror of
https://github.com/drasko/open-ameba.git
synced 2024-11-24 23:14:17 +00:00
eeb7f808ae
Signed-off-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com>
780 lines
28 KiB
C
780 lines
28 KiB
C
/* mbed Microcontroller Library
|
|
*******************************************************************************
|
|
* Copyright (c) 2014, Realtek Semiconductor Corp.
|
|
* All rights reserved.
|
|
*
|
|
* This module is a confidential and proprietary property of RealTek and
|
|
* possession or use of this module requires written permission of RealTek.
|
|
*******************************************************************************
|
|
*/
|
|
|
|
//#include "mbed_assert.h"
|
|
#include "objects.h"
|
|
#include "PinNames.h"
|
|
//#include <osdep_api.h>
|
|
#include "hal_i2c.h"
|
|
#include "i2c_api.h"
|
|
#include "ex_api.h"
|
|
|
|
|
|
#if CONFIG_I2C_EN
|
|
|
|
//#include "cmsis.h"
|
|
#include "pinmap.h"
|
|
|
|
|
|
static const PinMap PinMap_I2C_SDA[] = {
|
|
{PD_4, RTL_PIN_PERI(I2C0, 0, S0), RTL_PIN_FUNC(I2C0, S0)},
|
|
{PH_1, RTL_PIN_PERI(I2C0, 0, S1), RTL_PIN_FUNC(I2C0, S1)},
|
|
{PC_8, RTL_PIN_PERI(I2C0, 0, S2), RTL_PIN_FUNC(I2C0, S2)},
|
|
{PE_7, RTL_PIN_PERI(I2C0, 0, S3), RTL_PIN_FUNC(I2C0, S3)},
|
|
|
|
{PC_4, RTL_PIN_PERI(I2C1, 1, S0), RTL_PIN_FUNC(I2C1, S0)},
|
|
{PH_3, RTL_PIN_PERI(I2C1, 1, S1), RTL_PIN_FUNC(I2C1, S1)},
|
|
{PD_7, RTL_PIN_PERI(I2C1, 1, S2), RTL_PIN_FUNC(I2C1, S2)},
|
|
|
|
{PB_7, RTL_PIN_PERI(I2C2, 2, S0), RTL_PIN_FUNC(I2C2, S0)},
|
|
{PE_1, RTL_PIN_PERI(I2C2, 2, S1), RTL_PIN_FUNC(I2C2, S1)},
|
|
{PC_7, RTL_PIN_PERI(I2C2, 2, S2), RTL_PIN_FUNC(I2C2, S2)},
|
|
|
|
{PB_3, RTL_PIN_PERI(I2C3, 3, S0), RTL_PIN_FUNC(I2C3, S0)},
|
|
{PE_3, RTL_PIN_PERI(I2C3, 3, S1), RTL_PIN_FUNC(I2C3, S1)},
|
|
{PE_5, RTL_PIN_PERI(I2C3, 3, S2), RTL_PIN_FUNC(I2C3, S2)},
|
|
{PD_9, RTL_PIN_PERI(I2C3, 3, S3), RTL_PIN_FUNC(I2C3, S3)},
|
|
|
|
{NC, NC, 0}
|
|
};
|
|
|
|
static const PinMap PinMap_I2C_SCL[] = {
|
|
{PD_5, RTL_PIN_PERI(I2C0, 0, S0), RTL_PIN_FUNC(I2C0, S0)},
|
|
{PH_0, RTL_PIN_PERI(I2C0, 0, S1), RTL_PIN_FUNC(I2C0, S1)},
|
|
{PC_9, RTL_PIN_PERI(I2C0, 0, S2), RTL_PIN_FUNC(I2C0, S2)},
|
|
{PE_6, RTL_PIN_PERI(I2C0, 0, S3), RTL_PIN_FUNC(I2C0, S3)},
|
|
|
|
{PC_5, RTL_PIN_PERI(I2C1, 1, S0), RTL_PIN_FUNC(I2C1, S0)},
|
|
{PH_2, RTL_PIN_PERI(I2C1, 1, S1), RTL_PIN_FUNC(I2C1, S1)},
|
|
{PD_6, RTL_PIN_PERI(I2C1, 1, S2), RTL_PIN_FUNC(I2C1, S2)},
|
|
|
|
{PB_6, RTL_PIN_PERI(I2C2, 2, S0), RTL_PIN_FUNC(I2C2, S0)},
|
|
{PE_0, RTL_PIN_PERI(I2C2, 2, S1), RTL_PIN_FUNC(I2C2, S1)},
|
|
{PC_6, RTL_PIN_PERI(I2C2, 2, S2), RTL_PIN_FUNC(I2C2, S2)},
|
|
|
|
{PB_2, RTL_PIN_PERI(I2C3, 3, S0), RTL_PIN_FUNC(I2C3, S0)},
|
|
{PE_2, RTL_PIN_PERI(I2C3, 3, S1), RTL_PIN_FUNC(I2C3, S1)},
|
|
{PE_4, RTL_PIN_PERI(I2C3, 3, S2), RTL_PIN_FUNC(I2C3, S2)},
|
|
{PD_8, RTL_PIN_PERI(I2C3, 3, S3), RTL_PIN_FUNC(I2C3, S3)},
|
|
|
|
{NC, NC, 0}
|
|
};
|
|
|
|
static uint16_t i2c_target_addr[4];
|
|
static SAL_I2C_TRANSFER_BUF i2ctxtranbuf[4];
|
|
static SAL_I2C_TRANSFER_BUF i2crxtranbuf[4];
|
|
extern u32 ConfigDebugErr;
|
|
extern u32 ConfigDebuginfo;
|
|
void i2c_init(i2c_t *obj, PinName sda, PinName scl) {
|
|
|
|
uint32_t i2c_sel;
|
|
uint32_t i2c_idx;
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_USERCB_ADPT pSalI2CUserCBAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
|
|
// Determine the I2C to use
|
|
uint32_t i2c_sda = (uint32_t)pinmap_peripheral(sda, PinMap_I2C_SDA);
|
|
uint32_t i2c_scl = (uint32_t)pinmap_peripheral(scl, PinMap_I2C_SCL);
|
|
ConfigDebugErr &= (~(_DBG_I2C_|_DBG_GDMA_));
|
|
ConfigDebugInfo&= (~(_DBG_I2C_|_DBG_GDMA_));
|
|
i2c_sel = (uint32_t)pinmap_merge(i2c_sda, i2c_scl);
|
|
i2c_idx = RTL_GET_PERI_IDX(i2c_sel);
|
|
if (unlikely(i2c_idx == NC)) {
|
|
DBG_8195A("%s: Cannot find matched port i2c\n", __FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
//DBG_8195A("i2c_sel:%x\n",i2c_sel);
|
|
//DBG_8195A("i2c_idx:%x\n",i2c_idx);
|
|
|
|
/* Get I2C device handler */
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CUserCBAdpt = (PSAL_I2C_USERCB_ADPT)&(obj->SalI2CUserCBAdpt);
|
|
|
|
|
|
|
|
/*To assign the rest pointers*/
|
|
pSalI2CMngtAdpt->MstRDCmdCnt = 0;
|
|
pSalI2CMngtAdpt->InnerTimeOut = 2000; // inner time-out count, 2000 ms
|
|
pSalI2CMngtAdpt->pSalHndPriv = &(obj->SalI2CHndPriv);
|
|
pSalI2CMngtAdpt->pSalHndPriv->ppSalI2CHnd = (void**)&(pSalI2CMngtAdpt->pSalHndPriv);
|
|
|
|
/* To assign the default (ROM) HAL OP initialization function */
|
|
#if defined(CONFIG_CHIP_A_CUT) || defined(CONFIG_CHIP_B_CUT) || defined(CONFIG_CHIP_C_CUT)
|
|
pSalI2CMngtAdpt->pHalOpInit = HalI2COpInit_Patch;
|
|
#elif defined(CONFIG_CHIP_E_CUT)
|
|
pSalI2CMngtAdpt->pHalOpInit = HalI2COpInit_V04;
|
|
#endif
|
|
/* To assign the default (ROM) HAL GDMA OP initialization function */
|
|
pSalI2CMngtAdpt->pHalGdmaOpInit = HalGdmaOpInit;
|
|
|
|
/* To assign the default (ROM) SAL interrupt function */
|
|
#if defined(CONFIG_CHIP_A_CUT) || defined(CONFIG_CHIP_B_CUT) || defined(CONFIG_CHIP_C_CUT)
|
|
pSalI2CMngtAdpt->pSalIrqFunc = I2CISRHandle_Patch;
|
|
#elif defined(CONFIG_CHIP_E_CUT)
|
|
pSalI2CMngtAdpt->pSalIrqFunc = I2CISRHandle_V04;
|
|
#endif
|
|
|
|
/* To assign the default (ROM) SAL DMA TX interrupt function */
|
|
pSalI2CMngtAdpt->pSalDMATxIrqFunc = I2CTXGDMAISRHandle;
|
|
|
|
/* To assign the default (ROM) SAL DMA RX interrupt function */
|
|
pSalI2CMngtAdpt->pSalDMARxIrqFunc = I2CRXGDMAISRHandle;
|
|
|
|
pSalI2CMngtAdpt->pHalInitDat = &(obj->HalI2CInitData);
|
|
pSalI2CMngtAdpt->pHalOp = &(obj->HalI2COp);
|
|
pSalI2CMngtAdpt->pIrqHnd = &(obj->I2CIrqHandleDat);
|
|
pSalI2CMngtAdpt->pHalTxGdmaAdp = &(obj->HalI2CTxGdmaAdpt);
|
|
pSalI2CMngtAdpt->pHalRxGdmaAdp = &(obj->HalI2CRxGdmaAdpt);
|
|
pSalI2CMngtAdpt->pHalGdmaOp = &(obj->HalI2CGdmaOp);
|
|
pSalI2CMngtAdpt->pIrqTxGdmaHnd = &(obj->I2CTxGdmaIrqHandleDat);
|
|
pSalI2CMngtAdpt->pIrqRxGdmaHnd = &(obj->I2CRxGdmaIrqHandleDat);
|
|
pSalI2CMngtAdpt->pUserCB = &(obj->SalI2CUserCB);
|
|
pSalI2CMngtAdpt->pDMAConf = &(obj->SalI2CDmaUserDef);
|
|
|
|
/* Assign the private SAL handle to public SAL handle */
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
/* Assign the internal HAL initial data pointer to the SAL handle */
|
|
pSalI2CHND->pInitDat = pSalI2CMngtAdpt->pHalInitDat;
|
|
|
|
/* Assign the internal user callback pointer to the SAL handle */
|
|
pSalI2CHND->pUserCB = pSalI2CMngtAdpt->pUserCB;
|
|
|
|
/* Assign the internal user define DMA configuration to the SAL handle */
|
|
pSalI2CHND->pDMAConf = pSalI2CMngtAdpt->pDMAConf;
|
|
|
|
/*To assign user callback pointers*/
|
|
pSalI2CMngtAdpt->pUserCB->pTXCB = pSalI2CUserCBAdpt;
|
|
pSalI2CMngtAdpt->pUserCB->pTXCCB = (pSalI2CUserCBAdpt+1);
|
|
pSalI2CMngtAdpt->pUserCB->pRXCB = (pSalI2CUserCBAdpt+2);
|
|
pSalI2CMngtAdpt->pUserCB->pRXCCB = (pSalI2CUserCBAdpt+3);
|
|
pSalI2CMngtAdpt->pUserCB->pRDREQCB = (pSalI2CUserCBAdpt+4);
|
|
pSalI2CMngtAdpt->pUserCB->pERRCB = (pSalI2CUserCBAdpt+5);
|
|
pSalI2CMngtAdpt->pUserCB->pDMATXCB = (pSalI2CUserCBAdpt+6);
|
|
pSalI2CMngtAdpt->pUserCB->pDMATXCCB = (pSalI2CUserCBAdpt+7);
|
|
pSalI2CMngtAdpt->pUserCB->pDMARXCB = (pSalI2CUserCBAdpt+8);
|
|
pSalI2CMngtAdpt->pUserCB->pDMARXCCB = (pSalI2CUserCBAdpt+9);
|
|
pSalI2CMngtAdpt->pUserCB->pGENCALLCB= (pSalI2CUserCBAdpt+10);
|
|
|
|
/* Set I2C Device Number */
|
|
pSalI2CHND->DevNum = i2c_idx;
|
|
|
|
/* Load I2C default value */
|
|
RtkI2CLoadDefault(pSalI2CHND);
|
|
|
|
/* Assign I2C Pin Mux */
|
|
pSalI2CHND->PinMux = RTL_GET_PERI_SEL(i2c_sel);
|
|
pSalI2CHND->OpType = I2C_INTR_TYPE;
|
|
pSalI2CHND->I2CMaster = I2C_MASTER_MODE;
|
|
pSalI2CHND->I2CSpdMod = I2C_SS_MODE;
|
|
pSalI2CHND->I2CClk = 100;
|
|
pSalI2CHND->I2CAckAddr = 0;
|
|
pSalI2CHND->TimeOut = 300;
|
|
pSalI2CHND->AddRtyTimeOut = 3000;
|
|
pSalI2CHND->I2CExd |= (I2C_EXD_MTR_ADDR_RTY);
|
|
|
|
pSalI2CMngtAdpt->InnerTimeOut = pSalI2CHND->TimeOut;
|
|
|
|
/* Deinit I2C first */
|
|
//i2c_reset(obj);
|
|
|
|
/* Init I2C now */
|
|
RtkI2CInitForPS(pSalI2CHND);
|
|
}
|
|
|
|
void i2c_frequency(i2c_t *obj, int hz) {
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
uint16_t i2c_default_clk = (uint16_t) pSalI2CHND->I2CClk;
|
|
uint16_t i2c_user_clk = (uint16_t) (hz/1000);
|
|
|
|
if (i2c_default_clk != i2c_user_clk) {
|
|
/* Deinit I2C first */
|
|
i2c_reset(obj);
|
|
if (i2c_user_clk <= 100) {
|
|
pSalI2CHND->I2CSpdMod = I2C_SS_MODE;
|
|
}
|
|
else if ((i2c_user_clk > 100) && (i2c_user_clk <= 400)) {
|
|
pSalI2CHND->I2CSpdMod = I2C_FS_MODE;
|
|
}
|
|
else if (i2c_user_clk > 400) {
|
|
pSalI2CHND->I2CSpdMod = I2C_HS_MODE;
|
|
}
|
|
else {
|
|
pSalI2CHND->I2CSpdMod = I2C_SS_MODE;
|
|
}
|
|
|
|
/* Load the user defined I2C clock */
|
|
pSalI2CHND->I2CClk = i2c_user_clk;
|
|
|
|
/* Init I2C now */
|
|
RtkI2CInitForPS(pSalI2CHND);
|
|
}
|
|
}
|
|
|
|
inline int i2c_start(i2c_t *obj) {
|
|
return 0;
|
|
}
|
|
|
|
inline int i2c_stop(i2c_t *obj) {
|
|
return 0;
|
|
}
|
|
|
|
// extern u32 HalDelayUs(IN u32 us);
|
|
|
|
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
|
|
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
u32 I2CInTOTcnt = 0;
|
|
u32 InTimeoutCount = 0;
|
|
u32 InStartCount = 0;
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
if (i2c_target_addr[pSalI2CHND->DevNum] != address) {
|
|
/* Deinit I2C first */
|
|
i2c_reset(obj);
|
|
|
|
/* Load the user defined I2C target slave address */
|
|
i2c_target_addr[pSalI2CHND->DevNum] = address;
|
|
pSalI2CHND->I2CAckAddr = address;
|
|
|
|
/* Init I2C now */
|
|
RtkI2CInitForPS(pSalI2CHND);
|
|
}
|
|
|
|
/* Check if the it's the last byte or not */
|
|
pSalI2CHND->I2CExd &= (~I2C_EXD_MTR_HOLD_BUS);
|
|
if (!stop) {
|
|
pSalI2CHND->I2CExd |= I2C_EXD_MTR_HOLD_BUS;
|
|
}
|
|
|
|
pSalI2CHND->pRXBuf = &i2crxtranbuf[pSalI2CHND->DevNum];
|
|
pSalI2CHND->pRXBuf->DataLen = length;
|
|
pSalI2CHND->pRXBuf->TargetAddr= pSalI2CHND->I2CAckAddr;
|
|
pSalI2CHND->pRXBuf->RegAddr = 0;
|
|
pSalI2CHND->pRXBuf->pDataBuf = (u8 *)data;
|
|
|
|
if (RtkI2CReceive(pSalI2CHND) != HAL_OK) {
|
|
length = length - pSalI2CHND->pRXBuf->DataLen;
|
|
return ((int)length);
|
|
}
|
|
else {
|
|
//DBG_8195A(">\n");
|
|
/* Calculate user time out parameters */
|
|
I2CInTOTcnt = 300;
|
|
if ((I2CInTOTcnt != 0) && (I2CInTOTcnt != I2C_TIMEOOUT_ENDLESS)) {
|
|
InTimeoutCount = (I2CInTOTcnt*1000/TIMER_TICK_US);
|
|
InStartCount = HalTimerOp.HalTimerReadCount(1);
|
|
}
|
|
while((pSalI2CHND->DevSts != I2C_STS_IDLE) &&
|
|
(pSalI2CHND->DevSts != I2C_STS_ERROR) &&
|
|
(pSalI2CHND->DevSts != I2C_STS_TIMEOUT)) {
|
|
/* Time-Out check */
|
|
if (InTimeoutCount > 0) {
|
|
if (HAL_TIMEOUT == I2CIsTimeout(InStartCount, InTimeoutCount)) {
|
|
pSalI2CHND->DevSts = I2C_STS_TIMEOUT;
|
|
pSalI2CHND->ErrType = I2C_ERR_RX_ADD_TO;
|
|
|
|
/* DeInit I2C, Init I2C */
|
|
//RtkI2CDeInit(pSalI2CHND);
|
|
//HalDelayUs(1000);
|
|
//RtkI2CInit(pSalI2CHND);
|
|
|
|
return ((int)(length));
|
|
}
|
|
}
|
|
else {
|
|
if (I2CInTOTcnt == 0) {
|
|
pSalI2CHND->DevSts = I2C_STS_TIMEOUT;
|
|
pSalI2CHND->ErrType = I2C_ERR_RX_ADD_TO;
|
|
/* DeInit I2C, Init I2C */
|
|
//RtkI2CDeInit(pSalI2CHND);
|
|
|
|
//RtkI2CInit(pSalI2CHND);
|
|
|
|
return ((int)(length));
|
|
}
|
|
}
|
|
}
|
|
//DBG_8195A("<\n");
|
|
if (pSalI2CHND->DevSts != I2C_STS_TIMEOUT)
|
|
return ((int)(length - pSalI2CHND->pRXBuf->DataLen));
|
|
else
|
|
return ((int)(length));
|
|
}
|
|
}
|
|
|
|
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
|
|
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
u32 I2CInTOTcnt = 0;
|
|
u32 InTimeoutCount = 0;
|
|
u32 InStartCount = 0;
|
|
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
if (i2c_target_addr[pSalI2CHND->DevNum] != address) {
|
|
/* Deinit I2C first */
|
|
i2c_reset(obj);
|
|
|
|
/* Load the user defined I2C target slave address */
|
|
i2c_target_addr[pSalI2CHND->DevNum] = address;
|
|
pSalI2CHND->I2CAckAddr = address;
|
|
|
|
/* Init I2C now */
|
|
RtkI2CInitForPS(pSalI2CHND);
|
|
}
|
|
|
|
/* Check if the it's the last byte or not */
|
|
pSalI2CHND->I2CExd &= (~I2C_EXD_MTR_HOLD_BUS);
|
|
if (!stop) {
|
|
pSalI2CHND->I2CExd |= I2C_EXD_MTR_HOLD_BUS;
|
|
}
|
|
|
|
pSalI2CHND->pTXBuf = &i2ctxtranbuf[pSalI2CHND->DevNum];
|
|
pSalI2CHND->pTXBuf->DataLen = length;
|
|
pSalI2CHND->pTXBuf->TargetAddr= pSalI2CHND->I2CAckAddr;
|
|
pSalI2CHND->pTXBuf->RegAddr = 0;
|
|
pSalI2CHND->pTXBuf->pDataBuf = (u8 *)data;
|
|
|
|
if (RtkI2CSend(pSalI2CHND) != HAL_OK) {
|
|
length = length - pSalI2CHND->pTXBuf->DataLen;
|
|
return ((int)length);
|
|
}
|
|
else {
|
|
//DBG_8195A("(\n");
|
|
/* Calculate user time out parameters */
|
|
I2CInTOTcnt = 300;
|
|
if ((I2CInTOTcnt != 0) && (I2CInTOTcnt != I2C_TIMEOOUT_ENDLESS)) {
|
|
InTimeoutCount = (I2CInTOTcnt*1000/TIMER_TICK_US);
|
|
InStartCount = HalTimerOp.HalTimerReadCount(1);
|
|
}
|
|
while((pSalI2CHND->DevSts != I2C_STS_IDLE) &&
|
|
(pSalI2CHND->DevSts != I2C_STS_ERROR) &&
|
|
(pSalI2CHND->DevSts != I2C_STS_TIMEOUT)) {
|
|
/* Time-Out check */
|
|
if (InTimeoutCount > 0) {
|
|
if (HAL_TIMEOUT == I2CIsTimeout(InStartCount, InTimeoutCount)) {
|
|
pSalI2CHND->DevSts = I2C_STS_TIMEOUT;
|
|
pSalI2CHND->ErrType = I2C_ERR_TX_ADD_TO;
|
|
/* DeInit I2C, Init I2C */
|
|
//RtkI2CDeInit(pSalI2CHND);
|
|
|
|
//RtkI2CInit(pSalI2CHND);
|
|
return ((int)(length));
|
|
}
|
|
}
|
|
else {
|
|
if (I2CInTOTcnt == 0) {
|
|
pSalI2CHND->DevSts = I2C_STS_TIMEOUT;
|
|
pSalI2CHND->ErrType = I2C_ERR_TX_ADD_TO;
|
|
/* DeInit I2C, Init I2C */
|
|
//RtkI2CDeInit(pSalI2CHND);
|
|
|
|
//RtkI2CInit(pSalI2CHND);
|
|
return ((int)(length));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pSalI2CHND->DevSts != I2C_STS_TIMEOUT)
|
|
return ((int)(length - pSalI2CHND->pTXBuf->DataLen));
|
|
else
|
|
return ((int)(length));
|
|
}
|
|
}
|
|
|
|
int i2c_byte_read(i2c_t *obj, int last) {
|
|
uint8_t i2cdatlocal;
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
/* Check if the it's the last byte or not */
|
|
pSalI2CHND->I2CExd &= (~I2C_EXD_MTR_HOLD_BUS);
|
|
if (!last) {
|
|
pSalI2CHND->I2CExd |= I2C_EXD_MTR_HOLD_BUS;
|
|
}
|
|
|
|
pSalI2CHND->pRXBuf = &i2crxtranbuf[pSalI2CHND->DevNum];
|
|
pSalI2CHND->pRXBuf->DataLen = 1;
|
|
pSalI2CHND->pRXBuf->TargetAddr= pSalI2CHND->I2CAckAddr;
|
|
pSalI2CHND->pRXBuf->RegAddr = 0;
|
|
pSalI2CHND->pRXBuf->pDataBuf = &i2cdatlocal;
|
|
RtkI2CReceive(pSalI2CHND);
|
|
|
|
return (int)i2cdatlocal;
|
|
}
|
|
|
|
int i2c_byte_write(i2c_t *obj, int data) {
|
|
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
pSalI2CHND->I2CExd &= (~I2C_EXD_MTR_HOLD_BUS);
|
|
pSalI2CHND->I2CExd |= I2C_EXD_MTR_HOLD_BUS;
|
|
|
|
pSalI2CHND->pTXBuf = &i2ctxtranbuf[pSalI2CHND->DevNum];
|
|
pSalI2CHND->pTXBuf->DataLen = 1;
|
|
pSalI2CHND->pTXBuf->TargetAddr= pSalI2CHND->I2CAckAddr;
|
|
pSalI2CHND->pTXBuf->RegAddr = 0;
|
|
pSalI2CHND->pTXBuf->pDataBuf = (unsigned char*)&data;
|
|
|
|
if (RtkI2CSend(pSalI2CHND) != HAL_OK) {
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void i2c_reset(i2c_t *obj) {
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
/* Deinit I2C directly */
|
|
RtkI2CDeInitForPS(pSalI2CHND);
|
|
}
|
|
|
|
void i2c_restart_enable(i2c_t *obj) {
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
uint32_t i2clocaltmp;
|
|
uint8_t i2cen;
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
i2cen = pSalI2CHND->pInitDat->I2CEn;
|
|
|
|
if (i2cen == I2C_ENABLE) {
|
|
pSalI2CHND->pInitDat->I2CEn = I2C_DISABLE;
|
|
pSalI2CMngtAdpt->pHalOp->HalI2CEnable(pSalI2CHND->pInitDat);
|
|
}
|
|
|
|
i2clocaltmp = HalI2CRead32(pSalI2CHND->DevNum, REG_DW_I2C_IC_CON);
|
|
i2clocaltmp |= BIT_IC_CON_IC_RESTART_EN;
|
|
HalI2CWrite32(pSalI2CHND->DevNum, REG_DW_I2C_IC_CON, i2clocaltmp);
|
|
|
|
if (i2cen == I2C_ENABLE) {
|
|
pSalI2CHND->pInitDat->I2CEn = I2C_ENABLE;
|
|
pSalI2CMngtAdpt->pHalOp->HalI2CEnable(pSalI2CHND->pInitDat);
|
|
}
|
|
|
|
pSalI2CHND->pInitDat->I2CReSTR = I2C_ENABLE;
|
|
|
|
}
|
|
|
|
void i2c_restart_disable(i2c_t *obj) {
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
uint32_t i2clocaltmp;
|
|
uint8_t i2cen;
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
i2cen = pSalI2CHND->pInitDat->I2CEn;
|
|
|
|
if (i2cen == I2C_ENABLE) {
|
|
pSalI2CHND->pInitDat->I2CEn = I2C_DISABLE;
|
|
pSalI2CMngtAdpt->pHalOp->HalI2CEnable(pSalI2CHND->pInitDat);
|
|
}
|
|
|
|
i2clocaltmp = HalI2CRead32(pSalI2CHND->DevNum, REG_DW_I2C_IC_CON);
|
|
i2clocaltmp &= (~BIT_IC_CON_IC_RESTART_EN);
|
|
HalI2CWrite32(pSalI2CHND->DevNum, REG_DW_I2C_IC_CON, i2clocaltmp);
|
|
|
|
if (i2cen == I2C_ENABLE) {
|
|
pSalI2CHND->pInitDat->I2CEn = I2C_ENABLE;
|
|
pSalI2CMngtAdpt->pHalOp->HalI2CEnable(pSalI2CHND->pInitDat);
|
|
}
|
|
|
|
pSalI2CHND->pInitDat->I2CReSTR = I2C_DISABLE;
|
|
|
|
}
|
|
|
|
void i2c_set_user_callback(i2c_t *obj, I2CCallback i2ccb, void(*i2c_callback)(void *)) {
|
|
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
if ((i2ccb >= I2C_TX_COMPLETE) && (i2ccb <= I2C_ERR_OCCURRED)) {
|
|
switch (i2ccb) {
|
|
case I2C_TX_COMPLETE:
|
|
pSalI2CHND->pUserCB->pTXCCB->USERCB = i2c_callback;
|
|
break;
|
|
case I2C_RX_COMPLETE:
|
|
pSalI2CHND->pUserCB->pRXCCB->USERCB = i2c_callback;
|
|
break;
|
|
case I2C_RD_REQ_COMMAND:
|
|
pSalI2CHND->pUserCB->pRDREQCB->USERCB = i2c_callback;
|
|
break;
|
|
case I2C_ERR_OCCURRED:
|
|
pSalI2CHND->pUserCB->pERRCB->USERCB = i2c_callback;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void i2c_clear_user_callback(i2c_t *obj, I2CCallback i2ccb) {
|
|
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
if ((i2ccb >= I2C_TX_COMPLETE) && (i2ccb <= I2C_ERR_OCCURRED)) {
|
|
switch (i2ccb) {
|
|
case I2C_TX_COMPLETE:
|
|
pSalI2CHND->pUserCB->pTXCCB = NULL;
|
|
break;
|
|
case I2C_RX_COMPLETE:
|
|
pSalI2CHND->pUserCB->pRXCCB = NULL;
|
|
break;
|
|
case I2C_ERR_OCCURRED:
|
|
pSalI2CHND->pUserCB->pERRCB = NULL;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int i2c_enable_control(i2c_t *obj, int enable) {
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
pSalI2CHND->pInitDat->I2CEn = enable;
|
|
|
|
pSalI2CMngtAdpt->pHalOp->HalI2CEnable(pSalI2CHND->pInitDat);
|
|
}
|
|
|
|
#if DEVICE_I2CSLAVE
|
|
|
|
void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) {
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
uint16_t i2c_default_addr = (uint16_t) pSalI2CHND->I2CAckAddr;
|
|
uint16_t i2c_user_addr = (uint16_t) address;
|
|
|
|
if (i2c_default_addr != i2c_user_addr) {
|
|
/* Deinit I2C first */
|
|
i2c_reset(obj);
|
|
|
|
/* Load the user defined I2C clock */
|
|
pSalI2CHND->I2CAckAddr = i2c_user_addr;
|
|
|
|
/* Init I2C now */
|
|
RtkI2CInitForPS(pSalI2CHND);
|
|
}
|
|
}
|
|
|
|
void i2c_slave_mode(i2c_t *obj, int enable_slave) {
|
|
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
/* Deinit I2C first */
|
|
i2c_reset(obj);
|
|
|
|
/* Load the user defined I2C clock */
|
|
pSalI2CHND->I2CMaster = I2C_MASTER_MODE;
|
|
if (enable_slave)
|
|
pSalI2CHND->I2CMaster = I2C_SLAVE_MODE;
|
|
|
|
/* Init I2C now */
|
|
RtkI2CInitForPS(pSalI2CHND);
|
|
}
|
|
|
|
// See I2CSlave.h
|
|
#define NoData 0 // the slave has not been addressed
|
|
#define ReadAddressed 1 // the master has requested a read from this slave (slave = transmitter)
|
|
#define WriteGeneral 2 // the master is writing to all slave
|
|
#define WriteAddressed 3 // the master is writing to this slave (slave = receiver)
|
|
|
|
int i2c_slave_receive(i2c_t *obj) {
|
|
|
|
int i2cslvrevsts = NoData;
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
i2cslvrevsts = RtkSalI2CSts(pSalI2CHND);
|
|
return i2cslvrevsts;
|
|
}
|
|
|
|
int i2c_slave_read(i2c_t *obj, char *data, int length) {
|
|
|
|
u32 I2CInTOTcnt = 0;
|
|
u32 InTimeoutCount = 0;
|
|
u32 InStartCount = 0;
|
|
|
|
//uint8_t i2cdatlocal;
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
pSalI2CHND->pRXBuf = &i2crxtranbuf[pSalI2CHND->DevNum];
|
|
pSalI2CHND->pRXBuf->DataLen = length;
|
|
pSalI2CHND->pRXBuf->pDataBuf = (u8 *)data;
|
|
|
|
if (RtkI2CReceive(pSalI2CHND) != HAL_OK) {
|
|
return 0; //error
|
|
}
|
|
else {
|
|
/* Calculate user time out parameters */
|
|
I2CInTOTcnt = 300;
|
|
if ((I2CInTOTcnt != 0) && (I2CInTOTcnt != I2C_TIMEOOUT_ENDLESS)) {
|
|
InTimeoutCount = (I2CInTOTcnt*1000/TIMER_TICK_US);
|
|
InStartCount = HalTimerOp.HalTimerReadCount(1);
|
|
}
|
|
while((pSalI2CHND->DevSts != I2C_STS_IDLE) &&
|
|
(pSalI2CHND->DevSts != I2C_STS_ERROR) &&
|
|
(pSalI2CHND->DevSts != I2C_STS_TIMEOUT)) {
|
|
/* Time-Out check */
|
|
if (InTimeoutCount > 0) {
|
|
if (HAL_TIMEOUT == I2CIsTimeout(InStartCount, InTimeoutCount)) {
|
|
pSalI2CHND->DevSts = I2C_STS_TIMEOUT;
|
|
pSalI2CHND->ErrType = I2C_ERR_RX_ADD_TO;
|
|
return ((int)(length));
|
|
}
|
|
}
|
|
else {
|
|
if (I2CInTOTcnt == 0) {
|
|
pSalI2CHND->DevSts = I2C_STS_TIMEOUT;
|
|
pSalI2CHND->ErrType = I2C_ERR_RX_ADD_TO;
|
|
return ((int)(length));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pSalI2CHND->DevSts != I2C_STS_TIMEOUT)
|
|
return ((int)(length - pSalI2CHND->pTXBuf->DataLen));
|
|
else
|
|
return ((int)(length));
|
|
}
|
|
}
|
|
|
|
int i2c_slave_write(i2c_t *obj, const char *data, int length) {
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
|
|
pSalI2CHND->pTXBuf = &i2ctxtranbuf[pSalI2CHND->DevNum];
|
|
pSalI2CHND->pTXBuf->DataLen = length;
|
|
//obj->i2c->pTXBuf->TargetAddr= obj->i2c->I2CAckAddr;
|
|
//obj->i2c->pTXBuf->RegAddr = 0;
|
|
pSalI2CHND->pTXBuf->pDataBuf = (u8 *)data;
|
|
|
|
if (RtkI2CSend(pSalI2CHND) != HAL_OK) {
|
|
return 0; //error
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/** \brief Description of i2c_slave_set_for_rd_req
|
|
*
|
|
* i2c_slave_set_for_rd_req is used to set/clear i2c slave RD_REQ interrupt mask.
|
|
* If RD_REQ interrupt is set, slave could invoke read request callback when it gets
|
|
* a read command from other i2c master.
|
|
*
|
|
* \param i2c_t *obj : i2c object
|
|
* \param int set : set or clear for read request. Once it's set, i2c would invoke read request callback when a
|
|
* read command is sent to it.
|
|
* \return result
|
|
*/
|
|
int i2c_slave_set_for_rd_req(i2c_t *obj, int set) {
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
PHAL_I2C_INIT_DAT pHalI2CInitDat = NULL;
|
|
PHAL_I2C_OP pHalI2COP = NULL;
|
|
u32 I2CLocalTemp;
|
|
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
pHalI2CInitDat = pSalI2CMngtAdpt->pHalInitDat;
|
|
pHalI2COP = pSalI2CMngtAdpt->pHalOp;
|
|
|
|
I2CLocalTemp = pHalI2COP->HalI2CReadReg(pHalI2CInitDat, REG_DW_I2C_IC_INTR_MASK);
|
|
|
|
if (set) {
|
|
I2CLocalTemp |= BIT_IC_INTR_MASK_M_RD_REQ;
|
|
} else {
|
|
I2CLocalTemp &= (~BIT_IC_INTR_MASK_M_RD_REQ);
|
|
}
|
|
|
|
pHalI2CInitDat->I2CIntrMSK = I2CLocalTemp;
|
|
pHalI2COP->HalI2CIntrCtrl(pHalI2CInitDat);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/** \brief Description of i2c_slave_set_for_data_nak
|
|
*
|
|
* i2c_slave_set_for_data_nak is used to set/clear i2c slave NAK or ACK data part in transfer.
|
|
*
|
|
* \param i2c_t *obj : i2c object
|
|
* \param int set : set or clear for data NAK.
|
|
* \return result
|
|
*/
|
|
int i2c_slave_set_for_data_nak(i2c_t *obj, int set_nak) {
|
|
PSAL_I2C_MNGT_ADPT pSalI2CMngtAdpt = NULL;
|
|
PSAL_I2C_HND pSalI2CHND = NULL;
|
|
PHAL_I2C_INIT_DAT pHalI2CInitDat = NULL;
|
|
PHAL_I2C_OP pHalI2COP = NULL;
|
|
u32 I2CLocalTemp;
|
|
|
|
pSalI2CMngtAdpt = &(obj->SalI2CMngtAdpt);
|
|
pSalI2CHND = &(pSalI2CMngtAdpt->pSalHndPriv->SalI2CHndPriv);
|
|
pHalI2CInitDat = pSalI2CMngtAdpt->pHalInitDat;
|
|
pHalI2COP = pSalI2CMngtAdpt->pHalOp;
|
|
I2CLocalTemp = pHalI2COP->HalI2CReadReg(pHalI2CInitDat, REG_DW_I2C_IC_STATUS);
|
|
|
|
//if (set_nak) {
|
|
while (BIT_IC_STATUS_SLV_ACTIVITY & I2CLocalTemp) {
|
|
I2CLocalTemp = pHalI2COP->HalI2CReadReg(pHalI2CInitDat, REG_DW_I2C_IC_STATUS);
|
|
}
|
|
//}
|
|
|
|
HAL_I2C_WRITE32(pSalI2CHND->DevNum, REG_DW_I2C_IC_SLV_DATA_NACK_ONLY, set_nak);
|
|
}
|
|
|
|
#endif // CONFIG_I2C_SLAVE_EN
|
|
|
|
#endif // CONFIG_I2C_EN
|
|
|