GPIO Drv接口的實現

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));
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章