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
*********************************************************************************************************/

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