/*********************************************************************************************************
**
** 中國軟件開源組織
**
** 嵌入式實時操作系統
**
** 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總線驅動實現源碼
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.