/*********************************************************************************************************
**
** 中国软件开源组织
**
** 嵌入式实时操作系统
**
** 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
*********************************************************************************************************/
sylixos下i.mxRT1050的I2C总线驱动实现源码
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.