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