sylixos下的上s3c2440的I2C驅動實現源碼

/*********************************************************************************************************
**
**                                    中國軟件開源組織
**
**                                   嵌入式實時操作系統
**
**                                       SylixOS(TM)
**
**                               Copyright  All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文   件   名: samsungi2c.c
**
** 創   建   人: Han.Hui (韓輝)
**
** 文件創建日期: 2007 年 09 月 19 日
**
** 描        述: S3C2440 I2C 驅動(總線驅動部分)
*********************************************************************************************************/
#define  __SYLIXOS_KERNEL
#include "config.h"                                                     /*  工程配置 & 處理器相關       */
#include "SylixOS.h"
/*********************************************************************************************************
  S3C2440A I2C 波特率參數 (約爲100K)
*********************************************************************************************************/
#define __I2C_BPS_PARAM             (((PCLK / 512) / 100000) & 0xF)
/*********************************************************************************************************
  I2C CON 寄存器兩種取值定義
*********************************************************************************************************/
#define __I2C_CON_DACK(iBpsParam)   ((1 << 7) | (1 << 6) | (1 << 5) | (iBpsParam))
#define __I2C_CON_DNACK(iBpsParam)  ((0 << 7) | (1 << 6) | (1 << 5) | (iBpsParam))
/*********************************************************************************************************
  I2C 物理控制器結構
*********************************************************************************************************/
typedef struct {
    int                 iStatus;                                        /*  狀態                        */
    int                 iBpsParam;                                      /*  波特率參數                  */
    PLW_I2C_MESSAGE     pi2cmsg;                                        /*  需要處理的消息              */
    int                 iMsgPtr;                                        /*  消息內部指針                */
    int                 iMsgNum;                                        /*  消息數量                    */
    int                 iMsgIndex;                                      /*  當前處理的 msg 下標         */
} __SAMSUNGI2C_CHANNEL;
typedef __SAMSUNGI2C_CHANNEL        *__PSAMSUNGI2C_CHANNEL;
/*********************************************************************************************************
  I2C 消息數量判斷
*********************************************************************************************************/
#define __I2C_BUS_IS_LASTMSG(psamsungi2c)   (psamsungi2c->iMsgIndex >= (psamsungi2c->iMsgNum - 1))
                                                                        /*  最後一個消息或沒有消息      */
#define __I2C_BUS_IS_MSGLAST(psamsungi2c)   (psamsungi2c->iMsgPtr ==    \
                                             (psamsungi2c->pi2cmsg->I2CMSG_usLen - 1))
                                                                        /*  消息的最後一個字節          */
#define __I2C_BUS_IS_MSGEND(psamsungi2c)    (psamsungi2c->iMsgPtr >= psamsungi2c->pi2cmsg->I2CMSG_usLen)
                                                                        /*  消息結束                    */
/*********************************************************************************************************
  I2C 總線狀態
*********************************************************************************************************/
#define __I2C_BUS_STATE_IDLE        0                                   /*  總線空閒                    */
#define __I2C_BUS_STATE_START       1                                   /*  總線啓動                    */
#define __I2C_BUS_STATE_READ        2                                   /*  讀數據                      */
#define __I2C_BUS_STATE_WRITE       3                                   /*  寫數據                      */
#define __I2C_BUS_STATE_STOP        4                                   /*  總線結束                    */
/*********************************************************************************************************
  全局變量
*********************************************************************************************************/
static LW_OBJECT_HANDLE             __GhI2cSignal;                      /*  i2c 中斷                    */
#define __I2C_BUS_SIGNAL()          API_SemaphoreBPost(__GhI2cSignal)
#define __I2C_BUS_WAIT(ulTimeout)   API_SemaphoreBPend(__GhI2cSignal, ulTimeout)
static LW_I2C_FUNCS                 __Gi2cfuncSamsung;                  /*  i2c 總線函數                */
static __SAMSUNGI2C_CHANNEL         __Gsamsungi2c;                      /*  i2c 控制器                  */
/*********************************************************************************************************
  函數聲明
*********************************************************************************************************/
static VOID  __samsungI2cStart(UINT16  usAddr, UINT16  usFlag);
static VOID  __samsungI2cStop(UINT16  usFlag);
/*********************************************************************************************************
** Function name:           __samsungI2cIsr
** Descriptions:            i2c 控制器中斷處理函數
** input parameters:        psamsungi2c     控制器
** output parameters:       NONE
** Returned value:          中斷服務返回值
** Created by:              Hanhui
** Created Date:            2009-10-20
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
static irqreturn_t  __samsungI2cIsr (__PSAMSUNGI2C_CHANNEL   psamsungi2c)
{
    BYTE        ucByte;
    ULONG       ulStatus = rIICSTAT;                                    /*  i2c 狀態                    */

    INTER_CLR_PNDING(BIT_IIC);                                          /*  清除中斷標誌                */

    switch (psamsungi2c->iStatus) {                                     /*  處理不同狀態                */
    
    case __I2C_BUS_STATE_IDLE:
        break;                                                          /*  直接退出                    */
    
    case __I2C_BUS_STATE_START:
        if ((ulStatus & 0x09) ||                                        /*  出現錯誤                    */
            (__I2C_BUS_IS_LASTMSG(psamsungi2c) &&                       /*  沒有待處理的消息            */
             (psamsungi2c->pi2cmsg->I2CMSG_usLen == 0))) {
            errno = ENXIO;
            __samsungI2cStop(0);                                        /*  停止總線                    */
            break;
        }

        if (psamsungi2c->pi2cmsg->I2CMSG_usFlag & LW_I2C_M_RD) {        /*  進入讀狀態                  */
            psamsungi2c->iStatus = __I2C_BUS_STATE_READ;
            goto    __prepare_read;
        } else {
            psamsungi2c->iStatus = __I2C_BUS_STATE_WRITE;               /*  進入寫狀態                  */
            goto    __prepare_write;
        }
        break;
    
    case __I2C_BUS_STATE_READ:
        ucByte = (BYTE)rIICDS;                                          /*  讀取數據                    */
        psamsungi2c->pi2cmsg->I2CMSG_pucBuffer[psamsungi2c->iMsgPtr] = ucByte;
        psamsungi2c->iMsgPtr++;
        
__prepare_read:
        if (__I2C_BUS_IS_MSGLAST(psamsungi2c)) {                        /*  這是當前消息的最後一個字節  */
            if (__I2C_BUS_IS_LASTMSG(psamsungi2c)) {                    /*  這是最後一個消息            */
                rIICCON = __I2C_CON_DNACK(psamsungi2c->iBpsParam);      /*  啓動總線不需要 ACK          */
            }
        } else if (__I2C_BUS_IS_MSGEND(psamsungi2c)) {                  /*  當前消息已經結束            */
            if (__I2C_BUS_IS_LASTMSG(psamsungi2c)) {                    /*  這是最後一個消息            */
                psamsungi2c->iMsgPtr = 0;
                psamsungi2c->iMsgIndex++;                               /*  保證與消息數量相同          */
                __samsungI2cStop(LW_I2C_M_RD);
            } else {
                psamsungi2c->iMsgPtr = 0;
                psamsungi2c->iMsgIndex++;
                psamsungi2c->pi2cmsg++;                                 /*  開始接收下一個消息          */
                rIICCON = __I2C_CON_DACK(psamsungi2c->iBpsParam);       /*  啓動接收允許 ACK            */
            }
        } else {
            rIICCON = __I2C_CON_DACK(psamsungi2c->iBpsParam);           /*  啓動接收允許 ACK            */
        }
        break;
    
    case __I2C_BUS_STATE_WRITE:
        if ((ulStatus & 0x01) &&                                        /*  需要 ACK 但沒有接收到 ACK   */
            !(psamsungi2c->pi2cmsg->I2CMSG_usFlag & 
              LW_I2C_M_IGNORE_NAK)) {
            errno = ECONNREFUSED;
            __samsungI2cStop(0);                                        /*  停止總線                    */
            break;
        }
        
__prepare_write:
        if (!__I2C_BUS_IS_MSGEND(psamsungi2c)) {                        /*  當前消息還沒有發送完        */
            ucByte = psamsungi2c->pi2cmsg->I2CMSG_pucBuffer[psamsungi2c->iMsgPtr];
            psamsungi2c->iMsgPtr++;
            rIICDS  = ucByte;
            rIICCON = __I2C_CON_DACK(psamsungi2c->iBpsParam);           /*  發送                        */
        
        } else if (!__I2C_BUS_IS_LASTMSG(psamsungi2c)) {                /*  還有剩餘的消息沒有發送完    */
            psamsungi2c->iMsgPtr = 0;
            psamsungi2c->iMsgIndex++;
            psamsungi2c->pi2cmsg++;                                     /*  開始發送下一個消息          */
            
            if (psamsungi2c->pi2cmsg->I2CMSG_usFlag & 
                LW_I2C_M_NOSTART) {                                     /*  不需要起始位                */
                if (psamsungi2c->pi2cmsg->I2CMSG_usFlag &
                    LW_I2C_M_RD) {                                      /*  讀操作                      */
                    /*
                     *  控制器換向, 必須重啓總線
                     */
                    __samsungI2cStop(0);                                /*  不能進行讀操作              */
                }
                goto    __prepare_write;
                
            } else {
                __samsungI2cStart(psamsungi2c->pi2cmsg->I2CMSG_usAddr, 
                                  psamsungi2c->pi2cmsg->I2CMSG_usFlag); /*  重啓總線                    */
            }
        } else {
            psamsungi2c->iMsgPtr = 0;
            psamsungi2c->iMsgIndex++;                                   /*  保證與消息數量相同          */
            __samsungI2cStop(0);                                        /*  發送結束                    */
        }
        break;
    
    case __I2C_BUS_STATE_STOP:
        API_InterVectorDisable(VIC_CHANNEL_IIC);                        /*  關閉總線中斷                */
        break;
    }
    
    return  (LW_IRQ_HANDLED);
}
/*********************************************************************************************************
** Function name:           __samsungI2cInit
** Descriptions:            i2c 控制器初始化
** input parameters:        NONE
** output parameters:       NONE
** Returned value:          NONE
** Created by:              Hanhui
** Created Date:            2009-10-20
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
static VOID  __samsungI2cInit (VOID)
{
    rGPECON &= ~(0xFu << 28);
    rGPECON |=  (0xAu << 28);                                           /*  設置管腳鏈接                */

    rGPEUP   = rGPEUP | 0xC000;                                         /*  禁止內部上拉電阻            */

    rIICCON  = ((1 << 7) | (1 << 6) | (1 << 5) | (0));                  /*  初始化                      */
    rIICADD  = 0x10;                                                    /*  本地從機地址                */
    rIICSTAT =  (3 << 6) | (1 << 4);                                    /*  使能 I2C 總線               */
    rIICLC   =  (1 << 2) | (1);                                         /*  Filter enable 15 clocks     */
    
    __GhI2cSignal = API_SemaphoreBCreate("i2c_signal", LW_FALSE, LW_OPTION_OBJECT_GLOBAL, LW_NULL);
    
    API_InterVectorConnect(VIC_CHANNEL_IIC, (PINT_SVR_ROUTINE)__samsungI2cIsr, 
                           (PVOID)&__Gsamsungi2c, "i2c_isr");
}
/*********************************************************************************************************
** Function name:           __samsungI2cStart
** Descriptions:            i2c 控制器發送啓動字節
** input parameters:        usAddr      地址
**                          usFlag      標誌
** output parameters:       NONE
** Returned value:          NONE
** Created by:              Hanhui
** Created Date:            2009-10-20
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
static VOID  __samsungI2cStart (UINT16  usAddr, UINT16  usFlag)
{
    __Gsamsungi2c.iStatus = __I2C_BUS_STATE_START;                      /*  啓動總線                    */

    API_InterVectorEnable(VIC_CHANNEL_IIC);                             /*  打開總線中斷                */

    if (usFlag & LW_I2C_M_RD) {                                         /*  讀操作                      */
        rIICDS    = (BYTE)(usAddr + 1);                                 /*  設置器件讀地址              */
        rIICSTAT  = (2 << 6) | (1 << 5) | (1 << 4);                     /*  主收模式啓動                */
        rIICCON   = __I2C_CON_DACK(__Gsamsungi2c.iBpsParam);            /*  重啓總線 需要有此操作       */
    } else {
        rIICDS    = (BYTE)usAddr;
        rIICSTAT  = (3 << 6) | (1 << 5) | (1 << 4);                     /*  主發模式啓動                */
    }
}
/*********************************************************************************************************
** Function name:           __samsungI2cStop
** Descriptions:            i2c 控制器發送停止總線
** input parameters:        usFlag      標誌
** output parameters:       NONE
** Returned value:          NONE
** Created by:              Hanhui
** Created Date:            2009-10-20
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
static VOID  __samsungI2cStop (UINT16  usFlag)
{
    if (usFlag & LW_I2C_M_RD) {                                         /*  讀操作                      */
        rIICSTAT  = (2 << 6) | (0 << 5) | (1 << 4);                     /*  主收模式停止                */
    } else {                                                            /*  寫操作                      */
        rIICSTAT  = (3 << 6) | (0 << 5) | (1 << 4);                     /*  主發模式停止                */
    }

    rIICCON = __I2C_CON_DACK(__I2C_BPS_PARAM);                          /*  允許 ACK                    */
    
    __Gsamsungi2c.iStatus = __I2C_BUS_STATE_STOP;                       /*  停止總線                    */
    
    __I2C_BUS_SIGNAL();                                                 /*  激活等待任務                */
}
/*********************************************************************************************************
** Function name:           __samsungI2cTransferOne
** Descriptions:            i2c 傳輸函數
** input parameters:        pi2cadapter     i2c 適配器
**                          pi2cmsg         i2c 傳輸消息
**                          iNum            需要傳輸的 msg 數量
** output parameters:       NONE
** Returned value:          完成傳輸的消息數量
** Created by:              Hanhui
** Created Date:            2009-10-20
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
static INT  __samsungI2cDoTransfer (PLW_I2C_ADAPTER   pi2cadapter,
                                    PLW_I2C_MESSAGE   pi2cmsg,
                                    INT               iNum)
{
    __Gsamsungi2c.iStatus    = __I2C_BUS_STATE_START;
    __Gsamsungi2c.iBpsParam  = __I2C_BPS_PARAM;
    __Gsamsungi2c.pi2cmsg    = pi2cmsg;
    __Gsamsungi2c.iMsgPtr    = 0;
    __Gsamsungi2c.iMsgNum    = iNum;
    __Gsamsungi2c.iMsgIndex  = 0;                                       /*  從第一個開始發送            */

    __samsungI2cStart(pi2cmsg->I2CMSG_usAddr, pi2cmsg->I2CMSG_usFlag);  /*  啓動總線                    */
    
    __I2C_BUS_WAIT(LW_OPTION_WAIT_A_SECOND * 3);                        /*  最多等待 3 秒鐘             */
    
    /*
     *  此函數退出後如果還有 i2c 中斷, 可能導致 msg[] 局部數組無效. 程序崩潰.
     */
    API_InterVectorDisable(VIC_CHANNEL_IIC);                            /*  關閉總線中斷                */
    
    return  (__Gsamsungi2c.iMsgIndex);                                  /*  返回傳輸成功的數量          */
}
/*********************************************************************************************************
** Function name:           __samsungI2cTransfer
** Descriptions:            i2c 傳輸函數
** input parameters:        pi2cadapter     i2c 適配器
**                          pi2cmsg         i2c 傳輸消息組
**                          iNum            消息數量
** output parameters:       NONE
** Returned value:          完成傳輸的消息數量
** Created by:              Hanhui
** Created Date:            2009-10-20
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
static INT  __samsungI2cTransfer (PLW_I2C_ADAPTER   pi2cadapter,
                                  PLW_I2C_MESSAGE   pi2cmsg,
                                  INT               iNum)
{
    REGISTER INT        i;
    
    for (i = 0; i < pi2cadapter->I2CADAPTER_iRetry; i++) {
        if (__samsungI2cDoTransfer(pi2cadapter, pi2cmsg, iNum) == iNum) {
            return  (iNum);
        } else {
            API_TimeSleep(LW_OPTION_WAIT_A_TICK);                       /*  等待一個機器週期重試        */
        }
    }
    
    return  (PX_ERROR);
}
/*********************************************************************************************************
** Function name:           i2cBusFuns
** Descriptions:            初始化 i2c 總線並獲取操作函數集
** input parameters:        NONE
** output parameters:       NONE
** Returned value:          總線操作函數集
** Created by:              Hanhui
** Created Date:            2009-10-20
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
PLW_I2C_FUNCS  i2cBusFuns (VOID)
{
    __Gi2cfuncSamsung.I2CFUNC_pfuncMasterXfer = __samsungI2cTransfer;
    
    __samsungI2cInit();
    
    return  (&__Gi2cfuncSamsung);
}
/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章