📄 hw_i2c.c
字号:
/******************************************************************/
/* Copyright (C) 2007 ROCK-CHIPS FUZHOU . All Rights Reserved. */
/*******************************************************************
File : hw_i2c.c
Desc : I2C接口函数的实现
Author : huangxinyu
Date : 2007-06-06
Notes :
$Log: hw_i2c.c,v $
Revision 1.3 2008/06/19 04:43:31 Administrator
代码整理!
Revision 1.2 2008/05/15 08:01:19 HXY
取消LDK/Porsche宏
Revision 1.1.1.1 2008/05/07 04:15:08 Administrator
no message
Revision 1.1.1.1 2008/03/06 13:29:05 Lingzhaojun
no message
Revision 1.12 2007/11/24 03:40:59 Huangxinyu
优化I2C超时处理的timeout值,以适应有些I2C设备应答较慢的情况
Revision 1.11 2007/11/19 06:37:33 Huangxinyu
I2C_Deinit恢复IO切换
Revision 1.10 2007/11/19 06:19:33 Huangxinyu
I2C_Read的timeout初始化
Revision 1.9 2007/11/14 08:42:23 Huangxinyu
调试后更新
Revision 1.8 2007/11/14 06:28:38 Huangxinyu
增加I2C应答的timeout处理,如果i2C设备没有应答,超时后将继续run
Revision 1.7 2007/11/07 03:17:57 Huangxinyu
优化互斥量的释放顺序
Revision 1.6 2007/11/06 07:34:27 Huangxinyu
I2C Init和Deint中增加模块clock的处理
Revision 1.5 2007/11/02 04:06:24 Huangxinyu
进一步增强slaveaddr应答条件判断,防止误判
Revision 1.4 2007/10/15 09:15:47 Huangxinyu
根据RK27提交修改driver
Revision 1.3 2007/10/08 02:38:44 Lingzhaojun
添加版本自动注释脚本
*********************************************************************/
#include "include.h"
#include "hw_include.h"
#include "hw_i2c.h"
#include "..\hwintr\hw_interrupt.h"
#define pI2CReg ((pI2CReg_t)I2C_REG_BASE)
static UINT8 I2C_slaveaddr = 0x00;
static UINT16 I2C_oldspeed = 0x00;
/**************************************************************************
* 函数描述: I2C start
* 入口参数: 无
* 出口参数: 无
* 返回值: 无
***************************************************************************/
void I2CStart(void)
{
// Set start to LCMR
SetRegBits32(&pI2CReg->I2C_LCMR, I2C_LCMR_RESUME | I2C_LCMR_START);
}
/**************************************************************************
* 函数描述: I2C stop
* 入口参数: 无
* 出口参数: 无
* 返回值: 无
***************************************************************************/
void I2CStop(void)
{
int timeout;
timeout = 200000 / I2C_oldspeed; // timeout要足够长,以适应个别I2C应答较慢的情况
// stop
SetRegBits32(&pI2CReg->I2C_LCMR, I2C_LCMR_RESUME | I2C_LCMR_STOP);
#if 1
while (((ReadReg32(&pI2CReg->I2C_LCMR)&I2C_LCMR_STOP) != 0) && (timeout > 0))
{
USDELAY(1);
timeout--;
}
#endif
WriteReg32(&pI2CReg->I2C_IER, 0x0);
// Clear status register
WriteReg32(&pI2CReg->I2C_ISR, 0x0);
}
/**************************************************************************
* 函数描述: 向I2C从设备发送数据
* 入口参数: Data -- 待发送的数据(UINT8)
* 出口参数: 无
* 返回值: 0 -- 发送成功
* 非0 -- 发送失败
***************************************************************************/
BOOL I2CSendData(UINT8 Data, BOOL StartBit)
{
int intstatus;
int ackcorestatus;
int timeout; // 如果I2C设备没有应答也需要超时退出
START:
timeout = 200000 / I2C_oldspeed; // timeout要足够长,以适应个别I2C应答较慢的情况
// 设置为主设备发送
MaskRegBits32(&pI2CReg->I2C_CONR, I2C_CONR_MASTER_MASK, I2C_CONR_MTX);
// Set MTXR
WriteReg32(&pI2CReg->I2C_MTXR, Data);
if (StartBit)
WriteReg32(&pI2CReg->I2C_LCMR, I2C_LCMR_RESUME | I2C_LCMR_START);
else
WriteReg32(&pI2CReg->I2C_LCMR, I2C_LCMR_RESUME);
// ACK 释放SDA线,等待从设备应答
ClrRegBits32(&pI2CReg->I2C_CONR, I2C_CON_NACK);
// waiting ACK
do
{
intstatus = ReadReg32(&pI2CReg->I2C_ISR);
// If Arbitration Lost, will stop and return
if ((intstatus & I2C_INT_AL) != 0)
{
// Clear INT_AL status
ClrRegBits32(&pI2CReg->I2C_ISR, I2C_INT_AL);
// stop
I2CStop();
return FALSE;
}
USDELAY(1);
ackcorestatus = ReadReg32(&pI2CReg->I2C_LSR);
timeout--;
}
while ((((ackcorestatus&I2C_LSR_NACK) != 0) || ((intstatus& I2C_INT_MACK) == 0)) && (timeout > 0));
// Clear INT_MACK status
ClrRegBits32(&pI2CReg->I2C_ISR, I2C_INT_MACK);
if (timeout)
{
return TRUE;
}
else
{
return FALSE;
}
}
/**************************************************************************
* 函数描述: 从I2C从设备读取数据
* 入口参数: 无
* 出口参数: 无
* 返回值: Data -- 读到的数据
***************************************************************************/
BOOL I2CReadData(UINT8 *Data)
{
int intstatus;
int timeout; // 如果I2C设备没有应答也需要超时退出
timeout = 200000 / I2C_oldspeed; // timeout要足够长,以适应个别I2C应答较慢的情况
SetRegBits32(&pI2CReg->I2C_LCMR, I2C_LCMR_RESUME);
// waiting ACK
do
{
intstatus = ReadReg32(&pI2CReg->I2C_ISR);
// Clear INT_MACK status
// If Arbitration Lost, will stop and return
if ((intstatus & I2C_INT_AL) != 0)
{
// Clear INT_AL status
ClrRegBits32(&pI2CReg->I2C_ISR, I2C_INT_AL);
// stop
I2CStop();
return FALSE;
}
USDELAY(1);
timeout--;
}
while (((intstatus& I2C_INT_MACKP) == 0) && (timeout > 0));
*Data = (UINT8)ReadReg32(&pI2CReg->I2C_MRXR);
// Clear INT_MACKP status
ClrRegBits32(&pI2CReg->I2C_ISR, I2C_INT_MACKP);
return TRUE;
}
/**************************************************************************
* 函数描述: 设置I2C速度
* 入口参数: speed -- I2C速度(以K为单位) eg. speed = 400 即 400K
* 出口参数: 无
* 返回值: TRUE -- 设置成功
* FALSE -- 设置失败
***************************************************************************/
BOOL I2CSetSpeed(UINT16 speed)
{
UINT32 exp;
UINT32 rem;
UINT32 scalespeed;
UINT32 freqbase;
/*
SCL Divisor = (I2CCDVR[5:3] + 1) x 2^((I2CCDVR[2:0] + 1)
SCL = PCLK/ 5*SCLK Divisor
rem = I2CCDVR[5:3]
exp = I2CCDVR[2:0]
*/
freqbase = Pll_get_apb_freq() / 5;
scalespeed = speed << 3; // speed以K为单位 (rem+1)<=8 ,先以8来确定exp
for (exp = 0;exp < 7;exp++)
{
scalespeed = scalespeed << 1;
if (scalespeed > freqbase)
{
break;
}
}
rem = (freqbase) / speed / (1 << (exp + 1)) - 1;
MaskRegBits32(&pI2CReg->I2C_OPR, I2C_OPR_DIV_SPEED_MASK, ((rem << 3) | exp));
return TRUE;
}
/**************************************************************************
* 函数描述: 初始化I2C模块
* 入口参数: 无
* 出口参数: 无
* 返回值: TRUE -- 初始化成功
* FALSE -- 初始化失败
***************************************************************************/
BOOL I2C_Init(UINT8 SlaveAddress, UINT16 nKHz)
{
// 获取互斥量 -- 在OS中
#ifndef DRIVER_ONLY
RockSemObtain(&gHwI2CSem);
#endif
Scu_ClockEnable(I2C_CLOCK);
SetRegBits32(&pI2CReg->I2C_OPR, I2C_OPR_RESET);
USDELAY(1);
ClrRegBits32(&pI2CReg->I2C_OPR, I2C_OPR_RESET);
I2C_slaveaddr = SlaveAddress & 0xfe;
// 如i2c address is internal codec, switch i2c to internal, else switch to external
if (I2C_slaveaddr == (0x27 << 1))
{
IOMUX_SetI2CType(I2C_Internal);
}
else
{
#ifndef DRIVER_ONLY
// RockSemObtain( &gHwIOmuxI2CSem ); // 暂时注释掉,避免文件系统信号量死锁
OSSchedLock();
#endif
IOMUX_SetI2CType(I2C_External);
}
if (I2C_oldspeed != nKHz)
{
// Disable the I2C
ClrRegBits32(&pI2CReg->I2C_OPR, I2C_OPR_ENABLE);
I2CSetSpeed(nKHz);
I2C_oldspeed = nKHz;
}
// Disable I2C interrupt mask
// Set I2C_IER to disable all kind of I2C’s interrupt type.
WriteReg32(&pI2CReg->I2C_IER, 0x0);
// Enable I2C Adapter Module
SetRegBits32(&pI2CReg->I2C_OPR, I2C_OPR_ENABLE); // Set bit 6 of I2C_OPR to enable I2C controller.
return TRUE;
}
/**************************************************************************
* 函数描述: 向I2C设备写数据
* 入口参数: RegAddr -- I2C设备内寄存器地址
*pData -- I2C设备内寄存器地址内数据
size -- 一次I2C写操作的数据大小(单位byte)
mode -- NormalMode/DirectMode
* 出口参数: 无
* 返回值: TRUE -- 写成功
* FALSE -- 写失败
***************************************************************************/
BOOL I2C_Write(UINT8 RegAddr, UINT8 *pData, UINT16 size, eI2C_mode_t mode)
{
BOOL ret = TRUE;
// Set I2C_IER to disable all kind of I2C’s interrupt type.
WriteReg32(&pI2CReg->I2C_IER, 0x0);
// Clear status register
WriteReg32(&pI2CReg->I2C_ISR, 0x0);
if (I2CSendData(I2C_slaveaddr | I2C_WRITE_BIT, TRUE) == FALSE)
{
ret = FALSE;
goto error;
}
if (mode == NormalMode)
{
if (I2CSendData(RegAddr, FALSE) == FALSE)
{
ret = FALSE;
goto error;
}
}
// Write data
while (size)
{
if (I2CSendData(*pData, FALSE) == FALSE)
{
ret = FALSE;
goto error;
}
pData++;
size --;
}
error:
// Set CONR ACK 释放SDA总线
ClrRegBits32(&pI2CReg->I2C_CONR, I2C_CON_NACK);
I2CStop();
return ret;
}
/**************************************************************************
* 函数描述: 从I2C设备读数据
* 入口参数: RegAddr -- I2C设备内寄存器地址
size -- 数据的大小
mode -- NormalMode/DirectMode
* 出口参数: *pData -- I2C设备内寄存器地址内数据
* 返回值: TRUE -- 读成功
* FALSE -- 读失败
***************************************************************************/
BOOL I2C_Read(UINT8 RegAddr, UINT8 *pData, UINT16 size, eI2C_mode_t mode)
{
BOOL ret = TRUE;
// Set I2C_IER to disable all kind of I2C’s interrupt type.
WriteReg32(&pI2CReg->I2C_IER, 0x0);
// Clear status register
WriteReg32(&pI2CReg->I2C_ISR, 0x0);
if (mode == NormalMode) // 为了以后扩展
{
if (I2CSendData(I2C_slaveaddr | I2C_WRITE_BIT, TRUE) == FALSE)
{
ret = FALSE;
goto error;
}
if (I2CSendData(RegAddr, FALSE) == FALSE)
{
ret = FALSE;
goto error;
}
I2CStop(); // I2C_CONR = 0x1C , I2C_CONR = 0xC
if (I2CSendData(I2C_slaveaddr | I2C_READ_BIT, TRUE) == FALSE)
{
ret = FALSE;
goto error;
}
}
else if (mode == DirectMode) // FM5767
{
if (I2CSendData(I2C_slaveaddr | I2C_READ_BIT, TRUE) == FALSE)
{
ret = FALSE;
goto error;
}
}
// 设置为主设备接收
MaskRegBits32(&pI2CReg->I2C_CONR, I2C_CONR_MASTER_MASK, I2C_CONR_MRX);
while (size)
{
if (FALSE == I2CReadData(pData))
{
ret = FALSE;
goto error;
}
// the last read (size = 1)is NACK , other is ACK
if (1 == size)
SetRegBits32(&pI2CReg->I2C_CONR, I2C_CON_NACK);
else
ClrRegBits32(&pI2CReg->I2C_CONR, I2C_CON_NACK);
pData++;
size --;
}
error:
I2CStop();
return ret;
}
/**************************************************************************
* 函数描述: 反初始化I2C模块
* 入口参数: 无
* 出口参数: 无
* 返回值: TRUE -- 初始化成功
* FALSE -- 初始化失败
***************************************************************************/
BOOL I2C_Deinit(void)
{
// Disable the I2C
ClrRegBits32(&pI2CReg->I2C_OPR, I2C_OPR_ENABLE);
Scu_ClockDisable(I2C_CLOCK);
if (I2C_slaveaddr != (0x27 << 1))
{
IOMUX_SetI2CType(I2C_External);
// RockSemRelease( &gHwIOmuxI2CSem ); // 暂时注释掉,避免文件系统信号量死锁
OSSchedUnlock();
}
else
{
IOMUX_SetI2CType(I2C_Internal);
}
// 释放互斥量
RockSemRelease(&gHwI2CSem);
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -