⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hw_i2c.c

📁 瑞星微公司RK27XX系列芯片的SDK开发包
💻 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 + -