sylixos下i.mxRT1050的I2C總線驅動實現源碼

/*********************************************************************************************************
**
**                                    中國軟件開源組織
**
**                                   嵌入式實時操作系統
**
**                                       SylixOS(TM)
**
**                               Copyright  All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文   件   名: iic_drv.c
**
** 創   建   人: Hui.Kai (惠凱)
**
** 文件創建日期: 2017 年 12 月 26 日
**
** 描        述: I2C 驅動
*********************************************************************************************************/
#define  __SYLIXOS_KERNEL
#include <SylixOS.h>
#include "linux/compat.h"
#include "pinmux/pinmux.h"
#include "fsl_lpi2c.h"
#include "config.h"
/*********************************************************************************************************
  時鐘宏定義
*********************************************************************************************************/
#define LPI2C_CLOCK_SOURCE_SELECT     (0U)                              /*  選擇時鐘源 USB PLL (480 MHZ)*/
#define LPI2C_CLOCK_SOURCE_DIVIDER    (5U)                              /*  時鐘源分頻值                */
#define LPI2C_CLOCK_FREQUENCY         ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / \
                                       (LPI2C_CLOCK_SOURCE_DIVIDER + 1U))
                                                                        /*  LPI2C 時鐘源                */
/*********************************************************************************************************
  通道相關宏定義
*********************************************************************************************************/
#define I2C_CHANNEL_NR                (4)                               /*  I2C 通道數量                */
#define I2C_CHAN0                     (0)                               /*  I2C0                        */
#define I2C_CHAN1                     (1)                               /*  I2C1                        */
#define I2C_CHAN2                     (2)                               /*  I2C2                        */
#define I2C_CHAN3                     (3)                               /*  I2C3                        */
#define I2C_INT_PRIORITY              (0xe)                             /*  I2C 中斷優先級              */
#define I2C_TIME_OUT                  (10000)                           /*  I2C 超時時間                */
#define I2C_RETRY_NUM                 (1)                               /*  I2C 重試次數                */
#define I2C0_BUS_NAME                 "/bus/i2c/0"                      /*  I2C0 總線名                 */
#define I2C1_BUS_NAME                 "/bus/i2c/1"                      /*  I2C1 總線名                 */
#define I2C2_BUS_NAME                 "/bus/i2c/2"                      /*  I2C2 總線名                 */
#define I2C3_BUS_NAME                 "/bus/i2c/3"                      /*  I2C3 總線名                 */
/*********************************************************************************************************
  調試打印宏定義
*********************************************************************************************************/
#define I2C_DEBUG                     printk                            /*  調試打印                    */
/********************************************************************************************************
  I2C 通道類型定義
*********************************************************************************************************/
struct i2c_channel {
    addr_t                  I2CCHAN_ulAddrBase;                         /*  物理地址基地址              */
    ULONG                   I2CCHAN_ulVector;                           /*  中斷向量                    */
    UINT                    I2CCHAN_uiIntPriority;                      /*  中斷優先級                  */
    UINT                    I2CCHAN_uiSourceClock;                      /*  時鐘源頻率                  */
    LW_OBJECT_HANDLE        I2CCHAN_hSignal;                            /*  同步信號量                  */
    BOOL                    I2CCHAN_bIsInit;                            /*  是否已經初始化              */
    lpi2c_master_handle_t   I2CCHAN_masterHandle;                       /*  I2C 主設備句柄              */
    lpi2c_master_transfer_t I2CCHAN_masterXfer;                         /*  I2C 主設備傳輸事務          */
    UINT                    I2CCHAN_uiStatus;                           /*  I2C 狀態寄存器狀態          */
    UINT                    I2CCHAN_uiTimeOut;                          /*  超時時間                    */
};
typedef struct i2c_channel   __I2C_CHANNEL;
typedef struct i2c_channel  *__PI2C_CHANNEL;
/*********************************************************************************************************
  全局變量
*********************************************************************************************************/
static __I2C_CHANNEL  _G_i2cChannels[I2C_CHANNEL_NR] = {
    {
        LPI2C1_BASE,
        BSP_IRQ_TO_VECTOR(LPI2C1_IRQn),
        I2C_INT_PRIORITY,
    },
    {
        LPI2C2_BASE,
        BSP_IRQ_TO_VECTOR(LPI2C2_IRQn),
        I2C_INT_PRIORITY,
    },
    {
        LPI2C3_BASE,
        BSP_IRQ_TO_VECTOR(LPI2C3_IRQn),
        I2C_INT_PRIORITY,
    },
    {
        LPI2C4_BASE,
        BSP_IRQ_TO_VECTOR(LPI2C4_IRQn),
        I2C_INT_PRIORITY,
    },
};
/*********************************************************************************************************
  外部函數聲明
*********************************************************************************************************/
extern VOID LPI2C1_DriverIRQHandler(VOID);
/*********************************************************************************************************
** 函數名稱: __i2cIsr
** 功能描述: I2C 通道中斷服務例程
** 輸  入  : pI2cChannel               I2C 通道
**           ulVector                  中斷向量
** 輸  出  : NONE
** 返  回  : 中斷返回值
*********************************************************************************************************/
static irqreturn_t  __i2cIsr (__PI2C_CHANNEL  pI2cChannel, ULONG  ulVector)
{
    LPI2C_Type  *pBase = (LPI2C_Type  *)pI2cChannel->I2CCHAN_ulAddrBase;

    if ((pBase->MCR & LPI2C_MCR_MEN_MASK)) {                            /*  主模式使能                  */
        LPI2C_MasterTransferHandleIRQ(pBase, &pI2cChannel->I2CCHAN_masterHandle);

        return  (LW_IRQ_HANDLED);
    }

    return  (LW_IRQ_NONE);
}
/*********************************************************************************************************
** 函數名稱: __irqCallBack
** 功能描述: I2C 通道中斷服務例程
** 輸  入  : pBase          I2C 基址
**           pHandle        I2C 主設備句柄
**           iStatus        I2C 狀態
**           pvUserData     用戶數據
** 輸  出  : NONE
** 返  回  : NONE
*********************************************************************************************************/
static VOID __irqCallBack (LPI2C_Type             *pBase,
                           lpi2c_master_handle_t  *pHandle,
                           INT32                   iStatus,
                           PVOID                   pvUserData)
{
    __PI2C_CHANNEL  pI2cChannel = _LIST_ENTRY(pHandle, __I2C_CHANNEL, I2CCHAN_masterHandle);

    if (kStatus_Success  == iStatus) {                                  /*  傳輸成功                    */
        pI2cChannel->I2CCHAN_uiStatus = ERROR_NONE;
    }

    if (kStatus_Success == iStatus || kStatus_LPI2C_Nak == iStatus) {   /*  傳輸成功                    */
        API_SemaphoreBPost(pI2cChannel->I2CCHAN_hSignal);               /*  釋放同步信號                */
    }
}
/*********************************************************************************************************
** 函數名稱: __i2cTryTransfer
** 功能描述: I2C 嘗試傳輸函數
** 輸  入  : pI2cChannel     I2C 通道
**           pI2cAdapter     I2C 適配器
**           pI2cMsg         I2C 傳輸消息組
**           iNum            消息數量
** 輸  出  : NONE
** 返  回  : 完成傳輸的消息數量
*********************************************************************************************************/
static INT  __i2cTryTransfer (__PI2C_CHANNEL   pI2cChannel,
                              PLW_I2C_ADAPTER  pI2cAdapter,
                              PLW_I2C_MESSAGE  pI2cMsg,
                              INT              iNum)
{
    INT                       i;
    PLW_I2C_MESSAGE           pMsg        = LW_NULL;
    INT                       iRet        = ERROR_NONE;
    addr_t                    ulBaseAddr  = pI2cChannel->I2CCHAN_ulAddrBase;
    lpi2c_master_transfer_t  *pmasterXfer = &pI2cChannel->I2CCHAN_masterXfer;

    pI2cChannel->I2CCHAN_uiStatus = PX_ERROR;

    /*
     *  I2C傳輸消息
     */
    for (i = 0; i < iNum; i++) {
        pMsg = &pI2cMsg[i];

        pmasterXfer->slaveAddress   = pMsg->I2CMSG_usAddr;
        pmasterXfer->subaddress     = 0;
        pmasterXfer->subaddressSize = 0;
        pmasterXfer->data           = pMsg->I2CMSG_pucBuffer;
        pmasterXfer->dataSize       = pMsg->I2CMSG_usLen;

        if (i == iNum - 1) {
            pmasterXfer->flags = kLPI2C_TransferDefaultFlag;
        } else {
            pmasterXfer->flags = kLPI2C_TransferNoStopFlag;
        }

        if (pMsg->I2CMSG_usFlag & LW_I2C_M_RD) {                        /*  爲讀操作                    */
            pmasterXfer->direction = kLPI2C_Read;
        } else {                                                        /*  爲寫操作                    */
            pmasterXfer->direction = kLPI2C_Write;
        }

        iRet = LPI2C_MasterTransferNonBlocking((LPI2C_Type *)ulBaseAddr,
                                               &pI2cChannel->I2CCHAN_masterHandle,
                                               pmasterXfer);
        if (ERROR_NONE != iRet) {                                       /*  傳輸失敗返回                */
            I2C_DEBUG("I2CCHAN_hSignal transfer error\r\n");

            return  (PX_ERROR);
        }

        iRet = API_SemaphoreBPend(pI2cChannel->I2CCHAN_hSignal, pI2cChannel->I2CCHAN_uiTimeOut);
        if (ERROR_NONE != iRet) {                                       /*  傳輸超時                    */
            I2C_DEBUG("I2CCHAN_hSignal pend time out\r\n");

            return  (PX_ERROR);
        }

        iRet = pI2cChannel->I2CCHAN_uiStatus;
    }

    return  ((iRet < ERROR_NONE) ? (iRet) : (iNum));
}
/*********************************************************************************************************
** 函數名稱: __i2cTransfer
** 功能描述: I2C 傳輸函數
** 輸  入  : pI2cChannel     I2C 通道
**           pI2cAdapter     I2C 適配器
**           pI2cMsg         I2C 傳輸消息組
**           iNum            消息數量
** 輸  出  : NONE
** 返  回  : 完成傳輸的消息數量
*********************************************************************************************************/
static INT  __i2cTransfer (__PI2C_CHANNEL   pI2cChannel,
                           PLW_I2C_ADAPTER  pI2cAdapter,
                           PLW_I2C_MESSAGE  pI2cMsg,
                           INT              iNum)
{
    REGISTER INT        i;

    if (LW_NULL == pI2cAdapter ||                                       /*  入參檢查                    */
        LW_NULL == pI2cMsg     ||
        LW_NULL == pI2cChannel) {
        return  (PX_ERROR);
    }

    for (i = 0; i < pI2cAdapter->I2CADAPTER_iRetry; i++) {
        if (iNum == __i2cTryTransfer(pI2cChannel, pI2cAdapter, pI2cMsg, iNum)) {
            return  (iNum);
        } else {
            API_TimeSleep(LW_OPTION_WAIT_A_TICK);                       /*  等待一個機器週期重試        */
        }
    }

    return  (PX_ERROR);
}
/*********************************************************************************************************
** 函數名稱: __i2c0Transfer
** 功能描述: i2c0 傳輸函數
** 輸  入  : pI2cAdapter     I2C 適配器
**           pI2cMsg         I2C 傳輸消息組
**           iNum            消息數量
** 輸  出  : NONE
** 返  回  : 完成傳輸的消息數量
*********************************************************************************************************/
static INT  __i2c0Transfer (PLW_I2C_ADAPTER     pI2cAdapter,
                            PLW_I2C_MESSAGE     pI2cMsg,
                            INT                 iNum)
{
    return  (__i2cTransfer(&_G_i2cChannels[I2C_CHAN0], pI2cAdapter, pI2cMsg, iNum));
}
/*********************************************************************************************************
** 函數名稱: __i2c1Transfer
** 功能描述: i2c1 傳輸函數
** 輸  入  : pI2cAdapter     I2C 適配器
**           pI2cMsg         I2C 傳輸消息組
**           iNum            消息數量
** 輸  出  : NONE
** 返  回  : 完成傳輸的消息數量
*********************************************************************************************************/
static INT  __i2c1Transfer (PLW_I2C_ADAPTER  pI2cAdapter,
                            PLW_I2C_MESSAGE  pI2cMsg,
                            INT              iNum)
{
    return  (__i2cTransfer(&_G_i2cChannels[I2C_CHAN1], pI2cAdapter, pI2cMsg, iNum));
}
/*********************************************************************************************************
** 函數名稱: __i2c2Transfer
** 功能描述: i2c2 傳輸函數
** 輸  入  : pI2cAdapter     I2C 適配器
**           pI2cMsg         I2C 傳輸消息組
**           iNum            消息數量
** 輸  出  : NONE
** 返  回  : 完成傳輸的消息數量
*********************************************************************************************************/
static INT  __i2c2Transfer (PLW_I2C_ADAPTER     pI2cAdapter,
                            PLW_I2C_MESSAGE     pI2cMsg,
                            INT                 iNum)
{
    return  (__i2cTransfer(&_G_i2cChannels[I2C_CHAN2], pI2cAdapter, pI2cMsg, iNum));
}
/*********************************************************************************************************
** 函數名稱: __i2c3Transfer
** 功能描述: i2c3 傳輸函數
** 輸  入  : pI2cAdapter     I2C 適配器
**           pI2cMsg         I2C 傳輸消息組
**           iNum            消息數量
** 輸  出  : NONE
** 返  回  : 完成傳輸的消息數量
*********************************************************************************************************/
static INT  __i2c3Transfer (PLW_I2C_ADAPTER  pI2cAdapter,
                            PLW_I2C_MESSAGE  pI2cMsg,
                            INT              iNum)
{
    return  (__i2cTransfer(&_G_i2cChannels[I2C_CHAN3], pI2cAdapter, pI2cMsg, iNum));
}
/*********************************************************************************************************
** 函數名稱: __i2cMasterCtl
** 功能描述: I2C 控制函數
** 輸  入  : pI2cChannel     I2C 通道
**           pI2cAdapter     I2C 適配器
**           iCmd            命令
**           lArg            參數
** 輸  出  : NONE
** 返  回  : ERROR_NONE
*********************************************************************************************************/
static INT  __i2cMasterCtl (__PI2C_CHANNEL   pI2cChannel,
                            PLW_I2C_ADAPTER  pI2cAdapter,
                            INT              iCmd,
                            LONG             lArg)
{
    return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: __i2c0MasterCtl
** 功能描述: i2c0 控制函數
** 輸  入  : pI2cAdapter     I2C 適配器
**           iCmd            命令
**           lArg            參數
** 輸  出  : NONE
** 返  回  : ERROR_CODE
*********************************************************************************************************/
static INT  __i2c0MasterCtl (PLW_I2C_ADAPTER  pI2cAdapter,
                             INT              iCmd,
                             LONG             lArg)
{
    return  (__i2cMasterCtl(&_G_i2cChannels[I2C_CHAN0], pI2cAdapter, iCmd, lArg));
}
/*********************************************************************************************************
** 函數名稱: __i2c1MasterCtl
** 功能描述: i2c1 控制函數
** 輸  入  : pI2cAdapter     I2C 適配器
**           iCmd            命令
**           lArg            參數
** 輸  出  : NONE
** 返  回  : ERROR_CODE
*********************************************************************************************************/
static INT  __i2c1MasterCtl (PLW_I2C_ADAPTER  pI2cAdapter,
                             INT              iCmd,
                             LONG             lArg)
{
    return  (__i2cMasterCtl(&_G_i2cChannels[I2C_CHAN1], pI2cAdapter, iCmd, lArg));
}
/*********************************************************************************************************
** 函數名稱: __i2c2MasterCtl
** 功能描述: i2c2 控制函數
** 輸  入  : pI2cAdapter     I2C 適配器
**           iCmd            命令
**           lArg            參數
** 輸  出  : NONE
** 返  回  : ERROR_CODE
*********************************************************************************************************/
static INT  __i2c2MasterCtl (PLW_I2C_ADAPTER  pI2cAdapter,
                             INT              iCmd,
                             LONG             lArg)
{
    return  (__i2cMasterCtl(&_G_i2cChannels[I2C_CHAN2], pI2cAdapter, iCmd, lArg));
}
/*********************************************************************************************************
** 函數名稱: __i2c3MasterCtl
** 功能描述: i2c3 控制函數
** 輸  入  : pI2cAdapter     I2C 適配器
**           iCmd            命令
**           lArg            參數
** 輸  出  : NONE
** 返  回  : ERROR_CODE
*********************************************************************************************************/
static INT  __i2c3MasterCtl (PLW_I2C_ADAPTER  pI2cAdapter,
                             INT              iCmd,
                             LONG             lArg)
{
    return  (__i2cMasterCtl(&_G_i2cChannels[I2C_CHAN3], pI2cAdapter, iCmd, lArg));
}
/*********************************************************************************************************
** 函數名稱: __i2cHwInit
** 功能描述: 初始化 I2C 硬件通道
** 輸  入  : pI2cChannel     I2C 通道
** 輸  出  : NONE
** 返  回  : ERROR_CODE
*********************************************************************************************************/
static INT  __i2cHwInit (__PI2C_CHANNEL  pI2cChannel)
{
    UINT                   uiChannel = pI2cChannel - &_G_i2cChannels[0];
    lpi2c_master_config_t  i2cConfig;

    pinmuxuLpi2cEnable(uiChannel);

    /*
     *  設置 I2C 時鐘
     */
    CLOCK_SetMux(kCLOCK_Lpi2cMux, LPI2C_CLOCK_SOURCE_SELECT);
    CLOCK_SetDiv(kCLOCK_Lpi2cDiv, LPI2C_CLOCK_SOURCE_DIVIDER);

    /*
     *  I2C 主設備初始化
     */
    pI2cChannel->I2CCHAN_uiSourceClock = LPI2C_CLOCK_FREQUENCY;
    LPI2C_MasterGetDefaultConfig(&i2cConfig);
    LPI2C_MasterInit((LPI2C_Type *)pI2cChannel->I2CCHAN_ulAddrBase,
                     &i2cConfig,
                     pI2cChannel->I2CCHAN_uiSourceClock);

    return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: __i2cInit
** 功能描述: 初始化 I2C 通道
** 輸  入  : pI2cChannel     I2C 通道
** 輸  出  : NONE
** 返  回  : ERROR_CODE
*********************************************************************************************************/
static INT  __i2cInit (__PI2C_CHANNEL  pI2cChannel)
{
    CHAR  cName[LW_CFG_OBJECT_NAME_SIZE] = {0};
    UINT  uiChannel                      = pI2cChannel - &_G_i2cChannels[0];

    if (!pI2cChannel->I2CCHAN_bIsInit) {                                /*  一次性初始化標誌            */

        /*
         *  同步信號量創建
         */
        pI2cChannel->I2CCHAN_hSignal = API_SemaphoreBCreate("i2c_sync",
                                                            LW_FALSE,
                                                            LW_OPTION_OBJECT_GLOBAL,
                                                            LW_NULL);
        if (LW_OBJECT_HANDLE_INVALID == pI2cChannel->I2CCHAN_hSignal) { /*  申請信號量失敗              */
            return  (PX_ERROR);
        }

        if (ERROR_NONE != __i2cHwInit(pI2cChannel)) {                   /*  初始化失敗返回              */
            I2C_DEBUG("__i2cInit(): failed to init!\r\n");

            if (pI2cChannel->I2CCHAN_hSignal) {
                API_SemaphoreBDelete(&pI2cChannel->I2CCHAN_hSignal);
                pI2cChannel->I2CCHAN_hSignal = LW_OBJECT_HANDLE_INVALID;
            }

            return  (PX_ERROR);
        }

        LPI2C_MasterTransferCreateHandle((LPI2C_Type *)pI2cChannel->I2CCHAN_ulAddrBase,
                                         &pI2cChannel->I2CCHAN_masterHandle,
                                         __irqCallBack,
                                         LW_NULL);
        API_InterVectorSetPriority(pI2cChannel->I2CCHAN_ulVector, I2C_INT_PRIORITY);
        snprintf(cName, sizeof(cName), "i2c%d_isr", uiChannel);
        API_InterVectorConnect(pI2cChannel->I2CCHAN_ulVector,
                               (PINT_SVR_ROUTINE)__i2cIsr,
                               (PVOID)pI2cChannel,
                               cName);

        pI2cChannel->I2CCHAN_uiStatus        = PX_ERROR;               /*  清空狀態標誌                */
        pI2cChannel->I2CCHAN_uiTimeOut       = I2C_TIME_OUT;
        pI2cChannel->I2CCHAN_bIsInit         = LW_TRUE;
    }

    return  (ERROR_NONE);
}
/*********************************************************************************************************
  I2C 驅動程序
*********************************************************************************************************/
static LW_I2C_FUNCS  _G_i2cFuncs[I2C_CHANNEL_NR] = {
        {
            __i2c0Transfer,
            __i2c0MasterCtl,
        },
        {
            __i2c1Transfer,
            __i2c1MasterCtl,
        },
        {
            __i2c2Transfer,
            __i2c2MasterCtl,
        },
        {
            __i2c3Transfer,
            __i2c3MasterCtl,
        },
};
/*********************************************************************************************************
** 函數名稱: __i2cBusFuns
** 功能描述: 初始化 I2C 總線並獲取驅動程序
** 輸  入  : uiChannel         通道號
** 輸  出  : NONE
** 返  回  : I2C 總線驅動程序
*********************************************************************************************************/
static PLW_I2C_FUNCS  __i2cBusFuns (UINT  uiChannel)
{
    if (uiChannel >= I2C_CHANNEL_NR) {                                  /*  通道號錯誤                  */
        I2C_DEBUG("i2cBusFuns(): I2C channel invalid!\r\n");

        return  (LW_NULL);
    }

    if (ERROR_NONE != __i2cInit(&_G_i2cChannels[uiChannel])) {          /*  初始化失敗返回              */
        return  (LW_NULL);
    }

    return  (&_G_i2cFuncs[uiChannel]);
}
/*********************************************************************************************************
** 函數名稱: lpI2cInstall
** 功能描述: LpI2C 驅動加載模塊
** 輸  入  : NONE
** 輸  出  : NONE
** 返  回  : ERROR_CODE
*********************************************************************************************************/
INT  lpI2cInstall (VOID)
{
    PLW_I2C_FUNCS  pI2cFuncs = LW_NULL;

    API_I2cLibInit();

    pI2cFuncs = __i2cBusFuns(I2C_CHAN0);
    if (pI2cFuncs) {                                                    /*  成功獲取總線操作函數        */
        API_I2cAdapterCreate(I2C0_BUS_NAME, pI2cFuncs, I2C_TIME_OUT, I2C_RETRY_NUM);
                                                                        /*  創建 i2c0 總線適配器        */
    }

    return  (ERROR_NONE);
}
/*********************************************************************************************************
  END
*********************************************************************************************************/

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