GPIO Drv API
GPIO 除了在應用層中使用外,其實更多的是在其他複雜驅動中調用。比如SD卡驅動中要使用一個GPIO來監測卡的插入與拔出,網卡驅動中需要使用一個GPIO來控制phy芯片硬復位,某些情況需要用GPIO來模擬I2C總線等等。驅動中使用GPIO時,爲了提高效率並不是調用GPIO設備文件,而是使用SylixOS提供的GPIO調用接口。
/*********************************************************************************************************
GPIO API (以下 API 僅供驅動程序內部使用, 應用程序不可使用)
*********************************************************************************************************/
LW_API VOID API_GpioInit(VOID);
LW_API INT API_GpioChipAdd(PLW_GPIO_CHIP pgchip);
LW_API INT API_GpioChipDelete(PLW_GPIO_CHIP pgchip);
LW_API PLW_GPIO_CHIP API_GpioChipFind(PVOID pvData, BOOL (*pfuncMatch)(PLW_GPIO_CHIP pgchip, PVOID pvData));
LW_API INT API_GpioIsValid(UINT uiGpio);
LW_API INT API_GpioHasDrv(UINT uiGpio);
LW_API INT API_GpioRequest(UINT uiGpio, CPCHAR pcLabel);
LW_API INT API_GpioRequestOne(UINT uiGpio, ULONG ulFlags, CPCHAR pcLabel);
LW_API VOID API_GpioFree(UINT uiGpio);
LW_API INT API_GpioRequestArray(PLW_GPIO pgArray, size_t stNum);
LW_API VOID API_GpioFreeArray(PLW_GPIO pgArray, size_t stNum);
LW_API INT API_GpioGetFlags(UINT uiGpio, ULONG *pulFlags);
LW_API VOID API_GpioOpenDrain(UINT uiGpio, BOOL bOpenDrain);
LW_API VOID API_GpioOpenSource(UINT uiGpio, BOOL bOpenSource);
LW_API INT API_GpioSetDebounce(UINT uiGpio, UINT uiDebounce);
LW_API INT API_GpioSetPull(UINT uiGpio, UINT uiType);
LW_API INT API_GpioDirectionInput(UINT uiGpio);
LW_API INT API_GpioDirectionOutput(UINT uiGpio, INT iValue);
LW_API INT API_GpioGetValue(UINT uiGpio);
LW_API VOID API_GpioSetValue(UINT uiGpio, INT iValue);
LW_API ULONG API_GpioGetIrq(UINT uiGpio, BOOL bIsLevel, UINT uiType);
LW_API ULONG API_GpioSetupIrq(UINT uiGpio, BOOL bIsLevel, UINT uiType);
LW_API VOID API_GpioClearIrq(UINT uiGpio);
LW_API irqreturn_t API_GpioSvrIrq(UINT uiGpio);
GPIO Drv API的實現基於GPIO控制器對象,實現相對簡單,主要包括數據有效性檢查,數據管理,防止重如保護,參數類型轉換,調用GPIO控制器對象中的相應回調函數等。SylixOS通過一個雙向鏈表來管理GPIO控制器對象,通過一個結構體數組來管理所有GPIO。
數據定義及宏定義
#define __SYLIXOS_KERNEL
#include "../SylixOS/kernel/include/k_kernel.h"
#include "../SylixOS/system/include/s_system.h"
/*********************************************************************************************************
裁剪宏
*********************************************************************************************************/
#if LW_CFG_GPIO_EN > 0
/*********************************************************************************************************
內部變量
*********************************************************************************************************/
static LW_LIST_LINE_HEADER _G_plineGpioChips; /* 驅動程序鏈表 */
static LW_GPIO_DESC _G_gdesc[LW_CFG_MAX_GPIOS]; /* 每個管腳描述符 */
static LW_SPINLOCK_DEFINE (_G_slGpio);
/*********************************************************************************************************
內部操作宏
*********************************************************************************************************/
#define GPIO_LOCK(pintreg) LW_SPIN_LOCK_QUICK(&_G_slGpio, (pintreg))
#define GPIO_UNLOCK(intreg) LW_SPIN_UNLOCK_QUICK(&_G_slGpio, (intreg))
#define GPIO_CHIP_HWGPIO(pgdesc) ((pgdesc) - &(pgdesc)->GD_pgcChip->GC_gdDesc[0])
#define GPIO_TO_DESC(gpio) (&_G_gdesc[(gpio)])
#define DESC_TO_GPIO(pgdesc) ((pgdesc)->GD_pgcChip->GC_uiBase + GPIO_CHIP_HWGPIO(pgdesc))
#define GPIO_IS_VALID(gpio) ((gpio) < LW_CFG_MAX_GPIOS)
支持函數實現
/*********************************************************************************************************
** 函數名稱: __gpioGetDirection
** 功能描述: 獲得指定 GPIO 方向
** 輸 入 : pgdesc GPIO 管腳描述符
** 輸 出 : 0: 輸入 1: 輸出
*********************************************************************************************************/
static INT __gpioGetDirection (PLW_GPIO_DESC pgdesc)
{
INT iError;
PLW_GPIO_CHIP pgchip = pgdesc->GD_pgcChip;
if (!pgchip->GC_pfuncGetDirection) {
return (PX_ERROR);
}
iError = pgchip->GC_pfuncGetDirection(pgchip, GPIO_CHIP_HWGPIO(pgdesc));
if (iError > 0) {
pgdesc->GD_ulFlags |= LW_GPIODF_IS_OUT;
return (1);
} else if (iError == 0) {
pgdesc->GD_ulFlags &= ~LW_GPIODF_IS_OUT;
return (0);
} else {
return (PX_ERROR);
}
}
/*********************************************************************************************************
** 函數名稱: __gpioGetDesc
** 功能描述: 通過 GPIO 號獲得指定 GPIO 描述符
** 輸 入 : uiGpio GPIO 號
** bRequested 是否檢查請求
** 輸 出 : GPIO 管腳描述符
*********************************************************************************************************/
static PLW_GPIO_DESC __gpioGetDesc (UINT uiGpio, BOOL bRequested)
{
PLW_GPIO_DESC pgdesc;
if (!GPIO_IS_VALID(uiGpio)) {
return (LW_NULL);
}
pgdesc = GPIO_TO_DESC(uiGpio);
if (bRequested && !(pgdesc->GD_ulFlags & LW_GPIODF_REQUESTED)) {
return (LW_NULL);
}
return (pgdesc);
}
/*********************************************************************************************************
** 函數名稱: __gpioSetValueOpenDrain
** 功能描述: 設置一個 OPEN DRAIN 屬性的 GPIO
** 輸 入 : pgdesc GPIO 管腳描述符
** iValue 設置的值
** 輸 出 : NONE
*********************************************************************************************************/
static VOID __gpioSetValueOpenDrain (PLW_GPIO_DESC pgdesc, INT iValue)
{
INT iError;
PLW_GPIO_CHIP pgchip = pgdesc->GD_pgcChip;
if (iValue) {
iError = pgchip->GC_pfuncDirectionInput(pgchip, GPIO_CHIP_HWGPIO(pgdesc));
if (iError == ERROR_NONE) {
pgdesc->GD_ulFlags &= ~LW_GPIODF_IS_OUT;
}
} else {
iError = pgchip->GC_pfuncDirectionOutput(pgchip, GPIO_CHIP_HWGPIO(pgdesc), 0);
if (iError == ERROR_NONE) {
pgdesc->GD_ulFlags |= LW_GPIODF_IS_OUT;
}
}
}
/*********************************************************************************************************
** 函數名稱: __gpioSetValueOpenSource
** 功能描述: 設置一個 OPEN SOURCE 屬性的 GPIO
** 輸 入 : pgdesc GPIO 管腳描述符
** iValue 設置的值
** 輸 出 : NONE
*********************************************************************************************************/
static VOID __gpioSetValueOpenSource (PLW_GPIO_DESC pgdesc, INT iValue)
{
INT iError;
PLW_GPIO_CHIP pgchip = pgdesc->GD_pgcChip;
if (iValue) {
iError = pgchip->GC_pfuncDirectionOutput(pgchip, GPIO_CHIP_HWGPIO(pgdesc), 1);
if (iError == ERROR_NONE) {
pgdesc->GD_ulFlags |= LW_GPIODF_IS_OUT;
}
} else {
iError = pgchip->GC_pfuncDirectionInput(pgchip, GPIO_CHIP_HWGPIO(pgdesc));
if (iError == ERROR_NONE) {
pgdesc->GD_ulFlags &= ~LW_GPIODF_IS_OUT;
}
}
}
GPIO 控制器對象操作接口
/*********************************************************************************************************
** 函數名稱: _GpioInit
** 功能描述: 初始化 GPIO 庫
** 輸 入 : NONE
** 輸 出 : NONE
*********************************************************************************************************/
LW_API
VOID API_GpioInit (VOID)
{
LW_SPIN_INIT(&_G_slGpio);
}
/*********************************************************************************************************
** 函數名稱: API_GpioChipAdd
** 功能描述: 加入一個 GPIO 芯片驅動
** 輸 入 : pgchip GPIO 驅動
** 輸 出 : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
LW_API
INT API_GpioChipAdd (PLW_GPIO_CHIP pgchip)
{
INTREG iregInterLevel;
UINT i;
PLW_LIST_LINE plineTemp;
PLW_LIST_LINE plinePrev;
PLW_GPIO_CHIP pgchipTemp;
if (!pgchip) {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
if (pgchip->GC_ulVerMagic != LW_GPIO_VER_MAGIC) { /* 驅動不匹配 */
_DebugHandle(__ERRORMESSAGE_LEVEL,
"GPIO driver version not matching to current system.\r\n");
_ErrorHandle(EFTYPE);
return (PX_ERROR);
}
if ((!GPIO_IS_VALID(pgchip->GC_uiBase)) ||
(!GPIO_IS_VALID(pgchip->GC_uiBase + pgchip->GC_uiNGpios - 1))) {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
GPIO_LOCK(&iregInterLevel); /* 鎖定 GPIO */
for (plineTemp = _G_plineGpioChips;
plineTemp != LW_NULL;
plineTemp = _list_line_get_next(plineTemp)) {
pgchipTemp = _LIST_ENTRY(plineTemp, LW_GPIO_CHIP, GC_lineManage);
if (pgchipTemp->GC_uiBase >= (pgchip->GC_uiBase + pgchip->GC_uiNGpios)) {
break;
}
}
if (plineTemp) {
plinePrev = _list_line_get_prev(plineTemp);
if (plinePrev) {
pgchipTemp = _LIST_ENTRY(plinePrev, LW_GPIO_CHIP, GC_lineManage);
if ((pgchipTemp->GC_uiBase + pgchipTemp->GC_uiNGpios) > pgchip->GC_uiBase) {
GPIO_UNLOCK(iregInterLevel); /* 解鎖 GPIO */
_DebugHandle(__ERRORMESSAGE_LEVEL,
"GPIO integer space overlap, cannot add chip.\r\n");
_ErrorHandle(EBUSY);
return (PX_ERROR);
}
}
_List_Line_Add_Left(&pgchip->GC_lineManage, plineTemp);
} else if (_G_plineGpioChips) { /* 新加入點 base 最大 */
_List_Line_Add_Right(&pgchip->GC_lineManage, &pgchipTemp->GC_lineManage);
} else {
_List_Line_Add_Ahead(&pgchip->GC_lineManage, &_G_plineGpioChips);
}
pgchip->GC_gdDesc = &_G_gdesc[pgchip->GC_uiBase];
for (i = 0; i < pgchip->GC_uiNGpios; i++) {
PLW_GPIO_DESC pgdesc = &pgchip->GC_gdDesc[i];
pgdesc->GD_pgcChip = pgchip;
if (pgchip->GC_pfuncDirectionInput == LW_NULL) { /* 沒有輸入功能 */
pgdesc->GD_ulFlags = LW_GPIODF_IS_OUT;
} else {
pgdesc->GD_ulFlags = 0ul; /* 默認爲輸入態(芯片都這樣設計)*/
}
}
GPIO_UNLOCK(iregInterLevel); /* 解鎖 GPIO */
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: API_GpioChipDelete
** 功能描述: 刪除一個 GPIO 芯片驅動
** 輸 入 : pgchip GPIO 驅動
** 輸 出 : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
LW_API
INT API_GpioChipDelete (PLW_GPIO_CHIP pgchip)
{
INTREG iregInterLevel;
UINT i;
if (!pgchip) {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
GPIO_LOCK(&iregInterLevel); /* 鎖定 GPIO */
for (i = 0; i < pgchip->GC_uiNGpios; i++) {
if (pgchip->GC_gdDesc[i].GD_ulFlags & LW_GPIODF_REQUESTED) {
GPIO_UNLOCK(iregInterLevel); /* 解鎖 GPIO */
_ErrorHandle(EBUSY);
return (PX_ERROR);
}
}
for (i = 0; i < pgchip->GC_uiNGpios; i++) {
pgchip->GC_gdDesc[i].GD_pgcChip = LW_NULL;
}
_List_Line_Del(&pgchip->GC_lineManage, &_G_plineGpioChips);
GPIO_UNLOCK(iregInterLevel); /* 解鎖 GPIO */
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: API_GpioChipFind
** 功能描述: 查詢一個 GPIO 芯片驅動
** 輸 入 : pvData 匹配函數參數
** pfuncMatch 查詢匹配函數 (此函數返回 LW_TRUE 表示找到)
** 輸 出 : 查詢到的驅動結構
*********************************************************************************************************/
LW_API
PLW_GPIO_CHIP API_GpioChipFind (PVOID pvData, BOOL (*pfuncMatch)(PLW_GPIO_CHIP pgchip, PVOID pvData))
{
INTREG iregInterLevel;
PLW_GPIO_CHIP pgchip;
PLW_LIST_LINE plineTemp;
if (!pfuncMatch) {
_ErrorHandle(EINVAL);
return (LW_NULL);
}
GPIO_LOCK(&iregInterLevel); /* 鎖定 GPIO */
for (plineTemp = _G_plineGpioChips;
plineTemp != LW_NULL;
plineTemp = _list_line_get_next(plineTemp)) {
pgchip = _LIST_ENTRY(plineTemp, LW_GPIO_CHIP, GC_lineManage);
if (pfuncMatch(pgchip, pvData)) {
GPIO_UNLOCK(iregInterLevel); /* 解鎖 GPIO */
return (pgchip);
}
}
GPIO_UNLOCK(iregInterLevel); /* 解鎖 GPIO */
return (LW_NULL);
}
常用GPIO操作接口
/*********************************************************************************************************
** 函數名稱: API_GpioRequest
** 功能描述: 請求使用一個 GPIO
** 輸 入 : uiGpio 請求 GPIO 號
** pcLabel 標籤
** 輸 出 : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
LW_API
INT API_GpioRequest (UINT uiGpio, CPCHAR pcLabel)
{
INTREG iregInterLevel;
INT iError;
PLW_GPIO_DESC pgdesc;
PLW_GPIO_CHIP pgchip;
if (!GPIO_IS_VALID(uiGpio)) {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
pgdesc = GPIO_TO_DESC(uiGpio);
GPIO_LOCK(&iregInterLevel); /* 鎖定 GPIO */
pgchip = pgdesc->GD_pgcChip;
if (!pgchip) {
GPIO_UNLOCK(iregInterLevel); /* 解鎖 GPIO */
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
if (pgdesc->GD_ulFlags & LW_GPIODF_REQUESTED) { /* 已經在使用中 */
GPIO_UNLOCK(iregInterLevel); /* 解鎖 GPIO */
_ErrorHandle(EBUSY);
return (PX_ERROR);
}
pgdesc->GD_ulFlags |= LW_GPIODF_REQUESTED;
pgdesc->GD_pcLabel = pcLabel ? pcLabel : "?";
if (pgchip->GC_pfuncRequest) {
GPIO_UNLOCK(iregInterLevel); /* 解鎖 GPIO */
iError = pgchip->GC_pfuncRequest(pgchip, GPIO_CHIP_HWGPIO(pgdesc));
GPIO_LOCK(&iregInterLevel); /* 鎖定 GPIO */
if (iError < ERROR_NONE) {
pgdesc->GD_ulFlags &= ~LW_GPIODF_REQUESTED;
pgdesc->GD_pcLabel = LW_NULL;
GPIO_UNLOCK(iregInterLevel); /* 解鎖 GPIO */
return (iError);
}
}
if (pgchip->GC_pfuncGetDirection) {
GPIO_UNLOCK(iregInterLevel); /* 解鎖 GPIO */
__gpioGetDirection(pgdesc);
} else {
GPIO_UNLOCK(iregInterLevel); /* 解鎖 GPIO */
}
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: API_GpioRequestOne
** 功能描述: 請求使用一個 GPIO
** 輸 入 : uiGpio 請求 GPIO 號
** ulFlags 需要設置的屬性
** pcLabel 標籤
** 輸 出 : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
LW_API
INT API_GpioRequestOne (UINT uiGpio, ULONG ulFlags, CPCHAR pcLabel)
{
INT iError;
PLW_GPIO_DESC pgdesc;
iError = API_GpioRequest(uiGpio, pcLabel);
if (iError < ERROR_NONE) {
return (iError);
}
pgdesc = GPIO_TO_DESC(uiGpio);
if (ulFlags & LW_GPIOF_OPEN_DRAIN) {
pgdesc->GD_ulFlags |= LW_GPIODF_OPEN_DRAIN;
}
if (ulFlags & LW_GPIOF_OPEN_SOURCE) {
pgdesc->GD_ulFlags |= LW_GPIODF_OPEN_SOURCE;
}
if (ulFlags & LW_GPIOF_DIR_IN) {
iError = API_GpioDirectionInput(uiGpio);
} else {
iError = API_GpioDirectionOutput(uiGpio, (ulFlags & LW_GPIOF_INIT_HIGH) ? 1 : 0);
}
if (iError < ERROR_NONE) {
API_GpioFree(uiGpio);
return (iError);
}
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: API_GpioFree
** 功能描述: 釋放使用一個 GPIO
** 輸 入 : uiGpio GPIO 號
** 輸 出 : NONE
*********************************************************************************************************/
LW_API
VOID API_GpioFree (UINT uiGpio)
{
INTREG iregInterLevel;
PLW_GPIO_DESC pgdesc;
PLW_GPIO_CHIP pgchip;
pgdesc = __gpioGetDesc(uiGpio, LW_TRUE);
if (!pgdesc) {
return;
}
GPIO_LOCK(&iregInterLevel); /* 鎖定 GPIO */
pgchip = pgdesc->GD_pgcChip;
if (pgchip && (pgdesc->GD_ulFlags & LW_GPIODF_REQUESTED)) {
if (pgchip->GC_pfuncFree) {
GPIO_UNLOCK(iregInterLevel); /* 解鎖 GPIO */
pgchip->GC_pfuncFree(pgchip, GPIO_CHIP_HWGPIO(pgdesc));
GPIO_LOCK(&iregInterLevel); /* 鎖定 GPIO */
}
pgdesc->GD_ulFlags &= ~(LW_GPIODF_REQUESTED | LW_GPIODF_TRIGGER_MASK);
pgdesc->GD_pcLabel = LW_NULL;
}
GPIO_UNLOCK(iregInterLevel); /* 解鎖 GPIO */
}
/*********************************************************************************************************
** 函數名稱: API_GpioDirectionInput
** 功能描述: 設置指定 GPIO 爲輸入模式
** 輸 入 : uiGpio GPIO 號
** 輸 出 : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
LW_API
INT API_GpioDirectionInput (UINT uiGpio)
{
INT iError;
PLW_GPIO_DESC pgdesc;
PLW_GPIO_CHIP pgchip;
pgdesc = __gpioGetDesc(uiGpio, LW_TRUE);
if (!pgdesc) {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
pgchip = pgdesc->GD_pgcChip;
if (!pgchip || !pgchip->GC_pfuncGet || !pgchip->GC_pfuncDirectionInput) {
_ErrorHandle(ENOTSUP);
return (PX_ERROR);
}
iError = pgchip->GC_pfuncDirectionInput(pgchip, GPIO_CHIP_HWGPIO(pgdesc));
if (iError == ERROR_NONE) {
pgdesc->GD_ulFlags &= ~LW_GPIODF_IS_OUT;
}
return (iError);
}
/*********************************************************************************************************
** 函數名稱: API_GpioDirectionOutput
** 功能描述: 設置指定 GPIO 爲輸出模式
** 輸 入 : uiGpio GPIO 號
** iValue 1: 高電平 0: 低電平
** 輸 出 : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
LW_API
INT API_GpioDirectionOutput (UINT uiGpio, INT iValue)
{
INT iError;
PLW_GPIO_DESC pgdesc;
PLW_GPIO_CHIP pgchip;
pgdesc = __gpioGetDesc(uiGpio, LW_TRUE);
if (!pgdesc) {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
pgchip = pgdesc->GD_pgcChip;
if (!pgchip || !pgchip->GC_pfuncSet || !pgchip->GC_pfuncDirectionOutput) {
_ErrorHandle(ENOTSUP);
return (PX_ERROR);
}
iError = pgchip->GC_pfuncDirectionOutput(pgchip, GPIO_CHIP_HWGPIO(pgdesc), iValue);
if (iError == ERROR_NONE) {
pgdesc->GD_ulFlags |= LW_GPIODF_IS_OUT;
}
return (iError);
}
/*********************************************************************************************************
** 函數名稱: API_GpioGetValue
** 功能描述: 獲取指定 GPIO 的值
** 輸 入 : uiGpio GPIO 號
** 輸 出 : GPIO 當前電平狀態 1: 高電平 0: 低電平
*********************************************************************************************************/
LW_API
INT API_GpioGetValue (UINT uiGpio)
{
PLW_GPIO_DESC pgdesc;
PLW_GPIO_CHIP pgchip;
pgdesc = GPIO_TO_DESC(uiGpio); /* 不做任何檢查, 加快速度 */
pgchip = pgdesc->GD_pgcChip;
return (pgchip->GC_pfuncGet(pgchip, GPIO_CHIP_HWGPIO(pgdesc)));
}
/*********************************************************************************************************
** 函數名稱: API_GpioSetValue
** 功能描述: 設置指定 GPIO 的值
** 輸 入 : uiGpio GPIO 號
** iValue 1: 高電平 0: 低電平
** 輸 出 : NONE
*********************************************************************************************************/
LW_API
VOID API_GpioSetValue (UINT uiGpio, INT iValue)
{
PLW_GPIO_DESC pgdesc;
PLW_GPIO_CHIP pgchip;
pgdesc = GPIO_TO_DESC(uiGpio); /* 不做任何檢查, 加快速度 */
pgchip = pgdesc->GD_pgcChip;
if (pgdesc->GD_ulFlags & LW_GPIODF_OPEN_DRAIN) {
__gpioSetValueOpenDrain(pgdesc, iValue);
} else if (pgdesc->GD_ulFlags & LW_GPIODF_OPEN_SOURCE) {
__gpioSetValueOpenSource(pgdesc, iValue);
} else {
pgchip->GC_pfuncSet(pgchip, GPIO_CHIP_HWGPIO(pgdesc), iValue);
}
}
GPIO 中斷操作接口
/*********************************************************************************************************
** 函數名稱: API_GpioGetIrq
** 功能描述: 根據指定 GPIO 號返回對應的 IRQ 號
** 輸 入 : uiGpio GPIO 號
** bIsLevel 是否爲電平觸發
** uiType 如果爲電平觸發, 1 表示高電平觸發, 0 表示低電平觸發
** 如果爲邊沿觸發, 1 表示上升沿觸發, 0 表示下降沿觸發, 2 表示雙邊沿觸發
** 輸 出 : IRQ 號, 錯誤返回 LW_VECTOR_INVALID
*********************************************************************************************************/
LW_API
ULONG API_GpioGetIrq (UINT uiGpio, BOOL bIsLevel, UINT uiType)
{
PLW_GPIO_DESC pgdesc;
PLW_GPIO_CHIP pgchip;
pgdesc = __gpioGetDesc(uiGpio, LW_TRUE);
if (!pgdesc) {
_ErrorHandle(EINVAL);
return (LW_VECTOR_INVALID);
}
pgchip = pgdesc->GD_pgcChip;
if (pgchip->GC_pfuncGetIrq) {
return (pgchip->GC_pfuncGetIrq(pgchip, GPIO_CHIP_HWGPIO(pgdesc), bIsLevel, uiType));
} else {
_ErrorHandle(ENXIO);
return (LW_VECTOR_INVALID);
}
}
/*********************************************************************************************************
** 函數名稱: API_GpioSetupIrq
** 功能描述: 根據指定 GPIO 號設置相應的外部中斷, 並返回對應的 IRQ 號
** 輸 入 : uiGpio GPIO 號
** bIsLevel 是否爲電平觸發
** uiType 如果爲電平觸發, 1 表示高電平觸發, 0 表示低電平觸發
** 如果爲邊沿觸發, 1 表示上升沿觸發, 0 表示下降沿觸發, 2 表示雙邊沿觸發
** 輸 出 : IRQ 號, 錯誤返回 LW_VECTOR_INVALID
*********************************************************************************************************/
LW_API
ULONG API_GpioSetupIrq (UINT uiGpio, BOOL bIsLevel, UINT uiType)
{
ULONG ulVector;
PLW_GPIO_DESC pgdesc;
PLW_GPIO_CHIP pgchip;
pgdesc = __gpioGetDesc(uiGpio, LW_TRUE);
if (!pgdesc) {
_ErrorHandle(EINVAL);
return (LW_VECTOR_INVALID);
}
pgchip = pgdesc->GD_pgcChip;
if (pgchip->GC_pfuncSetupIrq) {
ulVector = pgchip->GC_pfuncSetupIrq(pgchip, GPIO_CHIP_HWGPIO(pgdesc), bIsLevel, uiType);
if (ulVector != LW_VECTOR_INVALID) { /* 外部中斷設置成功 */
if (bIsLevel) {
pgdesc->GD_ulFlags |= LW_GPIODF_TRIG_LEVEL;
}
if (uiType == 0) {
pgdesc->GD_ulFlags |= LW_GPIODF_TRIG_FALL;
} else if (uiType == 1) {
pgdesc->GD_ulFlags |= LW_GPIODF_TRIG_RISE;
} else if (uiType == 2) {
pgdesc->GD_ulFlags |= (LW_GPIODF_TRIG_FALL | LW_GPIODF_TRIG_RISE);
}
}
return (ulVector);
} else {
_ErrorHandle(ENXIO);
return (LW_VECTOR_INVALID);
}
}
/*********************************************************************************************************
** 函數名稱: API_GpioClearIrq
** 功能描述: GPIO 爲外部中斷輸入模式時, 在中斷上下文中清除中斷請求操作
** 輸 入 : uiGpio GPIO 號
** 輸 出 : NONE
*********************************************************************************************************/
LW_API
VOID API_GpioClearIrq (UINT uiGpio)
{
PLW_GPIO_DESC pgdesc;
PLW_GPIO_CHIP pgchip;
pgdesc = GPIO_TO_DESC(uiGpio); /* 不做任何檢查, 加快速度 */
pgchip = pgdesc->GD_pgcChip;
if (pgchip->GC_pfuncClearIrq) {
pgchip->GC_pfuncClearIrq(pgchip, GPIO_CHIP_HWGPIO(pgdesc));
}
}
/*********************************************************************************************************
** 函數名稱: API_GpioSvrIrq
** 功能描述: GPIO 爲外部中斷輸入模式時, 判斷當前是否爲指定的 GPIO 中斷
** 輸 入 : uiGpio GPIO 號
** 輸 出 : LW_IRQ_HANDLED 表示當前中斷是指定 GPIO 產生的中斷
** LW_IRQ_NONE 表示當前中斷不是指定 GPIO 產生的中斷
*********************************************************************************************************/
LW_API
irqreturn_t API_GpioSvrIrq (UINT uiGpio)
{
irqreturn_t irqret = LW_IRQ_NONE;
PLW_GPIO_DESC pgdesc;
PLW_GPIO_CHIP pgchip;
pgdesc = GPIO_TO_DESC(uiGpio); /* 不做任何檢查, 加快速度 */
pgchip = pgdesc->GD_pgcChip;
if (pgchip->GC_pfuncSvrIrq) {
irqret = pgchip->GC_pfuncSvrIrq(pgchip, GPIO_CHIP_HWGPIO(pgdesc));
}
return (irqret);
}
不常用GPIO操作接口實現
/*********************************************************************************************************
** 函數名稱: API_GpioIsValid
** 功能描述: GPIO 號是否有效
** 輸 入 : uiGpio GPIO 號
** 輸 出 : 1: 有效 0:無效
*********************************************************************************************************/
LW_API
INT API_GpioIsValid (UINT uiGpio)
{
return (GPIO_IS_VALID(uiGpio));
}
/*********************************************************************************************************
** 函數名稱: API_GpioHasDrv
** 功能描述: GPIO 是否有對應的驅動程序
** 輸 入 : uiGpio GPIO 號
** 輸 出 : 1: 有 0:無
*********************************************************************************************************/
LW_API
INT API_GpioHasDrv (UINT uiGpio)
{
PLW_GPIO_DESC pgdesc;
pgdesc = GPIO_TO_DESC(uiGpio);
return (pgdesc->GD_pgcChip ? 1 : 0);
}
/*********************************************************************************************************
** 函數名稱: API_GpioRequestArray
** 功能描述: 請求使用一組 GPIO
** 輸 入 : pgArray GPIO 數組
** stNum 數組元素個數
** 輸 出 : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
LW_API
INT API_GpioRequestArray (PLW_GPIO pgArray, size_t stNum)
{
INT i;
INT iError;
if (!pgArray || !stNum) {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
for (i = 0; i < stNum; i++, pgArray++) {
iError = API_GpioRequestOne(pgArray->G_ulGpio, pgArray->G_ulFlags, pgArray->G_pcLabel);
if (iError < ERROR_NONE) {
goto __error_handle;
}
}
return (ERROR_NONE);
__error_handle:
while (i) {
pgArray--;
i--;
API_GpioFree(pgArray->G_ulGpio);
}
return (iError);
}
/*********************************************************************************************************
** 函數名稱: API_GpioFreeArray
** 功能描述: 釋放一組 GPIO
** 輸 入 : pgArray GPIO 數組
** stNum 數組元素個數
** 輸 出 : NONE
*********************************************************************************************************/
LW_API
VOID API_GpioFreeArray (PLW_GPIO pgArray, size_t stNum)
{
if (!pgArray) {
return;
}
while (stNum) {
API_GpioFree(pgArray->G_ulGpio);
pgArray++;
stNum--;
}
}
/*********************************************************************************************************
** 函數名稱: API_GpioGetFlags
** 功能描述: 獲取一個 GPIO flags
** 輸 入 : uiGpio 請求 GPIO 號
** pulFlags 獲取的 flags
** 輸 出 : NONE
*********************************************************************************************************/
LW_API
INT API_GpioGetFlags (UINT uiGpio, ULONG *pulFlags)
{
PLW_GPIO_DESC pgdesc;
if (!pulFlags) {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
pgdesc = __gpioGetDesc(uiGpio, LW_TRUE);
if (!pgdesc) {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
*pulFlags = pgdesc->GD_ulFlags;
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: API_GpioOpenDrain
** 功能描述: 設置一個 GPIO OPEN DRAIN 參數
** 輸 入 : uiGpio 請求 GPIO 號
** bOpenDrain 參數
** 輸 出 : NONE
*********************************************************************************************************/
LW_API
VOID API_GpioOpenDrain (UINT uiGpio, BOOL bOpenDrain)
{
PLW_GPIO_DESC pgdesc;
pgdesc = __gpioGetDesc(uiGpio, LW_TRUE);
if (!pgdesc) {
return;
}
if (bOpenDrain) {
pgdesc->GD_ulFlags |= LW_GPIODF_OPEN_DRAIN;
} else {
pgdesc->GD_ulFlags &= ~LW_GPIODF_OPEN_DRAIN;
}
}
/*********************************************************************************************************
** 函數名稱: API_GpioOpenSource
** 功能描述: 設置一個 GPIO OPEN SOURCE 參數
** 輸 入 : uiGpio 請求 GPIO 號
** bOpenSource 參數
** 輸 出 : NONE
*********************************************************************************************************/
LW_API
VOID API_GpioOpenSource (UINT uiGpio, BOOL bOpenSource)
{
PLW_GPIO_DESC pgdesc;
pgdesc = __gpioGetDesc(uiGpio, LW_TRUE);
if (!pgdesc) {
return;
}
if (bOpenSource) {
pgdesc->GD_ulFlags |= LW_GPIODF_OPEN_SOURCE;
} else {
pgdesc->GD_ulFlags &= ~LW_GPIODF_OPEN_SOURCE;
}
}
/*********************************************************************************************************
** 函數名稱: API_GpioSetDebounce
** 功能描述: 設置指定 GPIO 去抖動時間參數
** 輸 入 : uiGpio GPIO 號
** uiDebounce 去抖動時間參數
** 輸 出 : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
LW_API
INT API_GpioSetDebounce (UINT uiGpio, UINT uiDebounce)
{
PLW_GPIO_DESC pgdesc;
PLW_GPIO_CHIP pgchip;
pgdesc = __gpioGetDesc(uiGpio, LW_TRUE);
if (!pgdesc) {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
pgchip = pgdesc->GD_pgcChip;
if (!pgchip || !pgchip->GC_pfuncSetDebounce) {
_ErrorHandle(ENOTSUP);
return (PX_ERROR);
}
return (pgchip->GC_pfuncSetDebounce(pgchip, GPIO_CHIP_HWGPIO(pgdesc), uiDebounce));
}
/*********************************************************************************************************
** 函數名稱: API_GpioSetPull
** 功能描述: 設置指定 GPIO 上下拉參數
** 輸 入 : uiGpio GPIO 號
** uiType 上下拉參數 0: 開路 1: 上拉 pull up 2: 下拉 pull down
** 輸 出 : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
LW_API
INT API_GpioSetPull (UINT uiGpio, UINT uiType)
{
PLW_GPIO_DESC pgdesc;
PLW_GPIO_CHIP pgchip;
pgdesc = __gpioGetDesc(uiGpio, LW_TRUE);
if (!pgdesc) {
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
pgchip = pgdesc->GD_pgcChip;
if (!pgchip || !pgchip->GC_pfuncSetPull) {
_ErrorHandle(ENOTSUP);
return (PX_ERROR);
}
return (pgchip->GC_pfuncSetPull(pgchip, GPIO_CHIP_HWGPIO(pgdesc), uiType));
}