基本原理
通过前面几篇的讲解,已说明SylixOS中的GPIO在应用层和驱动层如何调用,这一篇讲如何向系统增加GPIO设备。
一个计算机系统内的GPIO都是呈组出现的,同一组内的GPIO特性基本相同,使用同一个驱动。像一般的SOC芯片,自身就会有一组GPIO做为片内外设存在,也可以通过PCI、I2C等其他总线外扩GPIO芯片或模块,这样就会增加一组或多组不同驱动的GPIO设备。
SylixOS中将每一组GPIO抽象为一个GPIO控制器对象,通过结构体LW_GPIO_CHIP来实现。LW_GPIO_CHIP结构体内有描述该组GPIO的数据和控制其操作的函数指针,驱动框架通过这些数据和函数指针就能使用这些GPIO,同时进一步封装出GPIO设备文件。
系统提供了添加和删除GPIO控制器对象的函数,这样向系统增加一组GPIO的方法其实就是通过 API_GpioChipAdd
函数添加一个LW_GPIO_CHIP对象到系统中。而实现这组GPIO的驱动就是实例化LW_GPIO_CHIP结构体中各数据和函数指针。
操作函数
/*********************************************************************************************************
** 函数名称: _GpioInit
** 功能描述: 初始化 GPIO 库
** 输 入 : NONE
** 输 出 : NONE
*********************************************************************************************************/
LW_API VOID API_GpioInit(VOID);
/*********************************************************************************************************
** 函数名称: API_GpioChipAdd
** 功能描述: 加入一个 GPIO 芯片驱动
** 输 入 : pgchip GPIO 驱动
** 输 出 : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
LW_API INT API_GpioChipAdd(PLW_GPIO_CHIP pgchip);
/*********************************************************************************************************
** 函数名称: API_GpioChipDelete
** 功能描述: 删除一个 GPIO 芯片驱动
** 输 入 : pgchip GPIO 驱动
** 输 出 : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
LW_API INT API_GpioChipDelete(PLW_GPIO_CHIP pgchip);
/*********************************************************************************************************
** 函数名称: API_GpioChipFind
** 功能描述: 查询一个 GPIO 芯片驱动
** 输 入 : pvData 匹配函数参数
** pfuncMatch 查询匹配函数 (此函数返回 LW_TRUE 表示找到)
** 输 出 : 查询到的驱动结构
*********************************************************************************************************/
LW_API PLW_GPIO_CHIP API_GpioChipFind(PVOID pvData, BOOL (*pfuncMatch)(PLW_GPIO_CHIP pgchip, PVOID pvData));
GPIO控制器对象
/*********************************************************************************************************
GPIO 控制器
GC_pfuncRequest
表示请求一个 GPIO 如果驱动没有特殊操作, 例如电源管理等等, 则可以为 LW_NULL
GC_pfuncFree
释放一个正在被使用的 GPIO, 如果当前是中断模式则, 放弃中断输入功能.
GC_pfuncGetDirection
获得当前 GPIO 方向, 1 表示输出, 0 表示输入
GC_pfuncDirectionInput
设置 GPIO 为输入模式 (如果当前是中断模式则, 放弃中断输入功能)
GC_pfuncGet
获得 GPIO 输入值
GC_pfuncDirectionOutput
设置 GPIO 为输出模式 (如果当前是中断模式则, 放弃中断输入功能)
GC_pfuncSetDebounce
设置 GPIO 去抖动参数
GC_pfuncSetPull
设置 GPIO 控制器上下拉功能, 0: 开路 1: 上拉 pull up 2: 下拉 pull down
GC_pfuncSet
设置 GPIO 输出值
GC_pfuncGetIrq
获取 GPIO IRQ 向量号, 不设置 GPIO 中断, 仅仅获取 IRQ 号
bIsLevel 1: 电平触发 0:边沿触发, uiType 1:上升沿触发 0:下降沿触发 2:双边沿触发
GC_pfuncSetupIrq
设置 GPIO 为外部中断输入口, 同时返回对应的 IRQ 向量号
bIsLevel 1: 电平触发 0:边沿触发, uiType 1:上升沿触发 0:下降沿触发 2:双边沿触发
GC_pfuncClearIrq
GPIO 为外部中断输入模式时, 发生中断后, 在中断上下文中清除中断请求操作.
GC_pfuncSvrIrq
GPIO 产生外部中断时会调用此函数, 如果是本 GPIO 产生的中断, 则返回 LW_IRQ_HANDLED
如果不是, 则返回 LW_IRQ_NONE.
以上函数 uiOffset 参数为针对 GC_uiBase 的偏移量, GPIO 驱动程序需要通过此数值确定对应的硬件寄存器.
注意: 相同条件下 GC_pfuncGetIrq, GC_pfuncSetupIrq 返回值必须相同.
*********************************************************************************************************/
struct lw_gpio_desc;
typedef struct lw_gpio_chip {
CPCHAR GC_pcLabel;
LW_LIST_LINE GC_lineManage;
ULONG GC_ulVerMagic;
#define LW_GPIO_VER_MAGIC 0xfffffff1
INT (*GC_pfuncRequest)(struct lw_gpio_chip *pgchip, UINT uiOffset);
VOID (*GC_pfuncFree)(struct lw_gpio_chip *pgchip, UINT uiOffset);
INT (*GC_pfuncGetDirection)(struct lw_gpio_chip *pgchip, UINT uiOffset);
INT (*GC_pfuncDirectionInput)(struct lw_gpio_chip *pgchip, UINT uiOffset);
INT (*GC_pfuncGet)(struct lw_gpio_chip *pgchip, UINT uiOffset);
INT (*GC_pfuncDirectionOutput)(struct lw_gpio_chip *pgchip, UINT uiOffset, INT iValue);
INT (*GC_pfuncSetDebounce)(struct lw_gpio_chip *pgchip, UINT uiOffset, UINT uiDebounce);
INT (*GC_pfuncSetPull)(struct lw_gpio_chip *pgchip, UINT uiOffset, UINT uiType);
VOID (*GC_pfuncSet)(struct lw_gpio_chip *pgchip, UINT uiOffset, INT iValue);
ULONG (*GC_pfuncGetIrq)(struct lw_gpio_chip *pgchip, UINT uiOffset,BOOL bIsLevel, UINT uiType);
ULONG (*GC_pfuncSetupIrq)(struct lw_gpio_chip *pgchip, UINT uiOffset, BOOL bIsLevel, UINT uiType);
VOID (*GC_pfuncClearIrq)(struct lw_gpio_chip *pgchip, UINT uiOffset);
irqreturn_t (*GC_pfuncSvrIrq)(struct lw_gpio_chip *pgchip, UINT uiOffset);
UINT GC_uiBase;
UINT GC_uiNGpios;
struct lw_gpio_desc *GC_gdDesc;
ULONG GC_ulPad[16]; /* 保留未来扩展 */
} LW_GPIO_CHIP;
typedef LW_GPIO_CHIP *PLW_GPIO_CHIP;