一、为什么引入gpiod子系统
- 在新版本内核中引入gpiod子系统
- gpiod子系统和gpio子系统的功能框架实现是一致,只不过封装的接口不一样
- gpiod子系统功能框架会更为强大
二、gpiod子系统API接口
void gpiod_set_value(struct gpio_desc *desc, int value); //设置gpio引脚输出高低电平
int gpiod_get_value(const struct gpio_desc *desc); //读取gpio引脚值
int gpiod_direction_input(struct gpio_desc *desc); //设置gpio引脚为输入模式
int gpiod_direction_output(struct gpio_desc *desc, int value); //设置gpio引脚输出高低电平
void gpiod_put(struct gpio_desc *desc); //释放gpio引脚
//如何从设备树中,直接获取到gpio_desc结构体指针
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
const char *propname, int index,
enum gpiod_flags dflags,
const char *label);
函数功能:直接从设备树中获取到gpio_desc结构体指针
参数:
node:节点结构体指针
propname:属性的名称
index:索引号
dflags:
GPIOD_OUT_LOW:gpio引脚输出低电平
GPIOD_OUT_HIGH:gpio引脚输出高电平
label:NULL
返回值:
成功返回gpio_desc结构体指针
失败 借助IS_ERR
三、gpiod子系统示例
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
/*
myled{//基于gpio子系统设备树节点
core-led{ //核心板设备树子节点
led = <&gpioz 5 0>,<&gpioz 6 0>,<&gpioz 7 0>; //led1 PZ5 led2 PZ6 led3 PZ7
};
extend-led{ //扩展板设备树子节点
led1 = <&gpioe 10 0>; //led1 PE10
led2 = <&gpiof 10 0>; //led2 PF10
led3 = <&gpioe 8 0>; //led3 PE8
};
};
*/
struct device_node* node;
struct device_node* enode;
struct device_node* cnode;
struct gpio_desc* cdesc[3];
struct gpio_desc* edesc[3];
char* name[3] = {"led1","led2","led3"};
static int __init demo_init(void)
{
int i = 0;
//获取myled节点
node = of_find_node_by_path("/myled");
if(node == NULL){
printk("of find node by path is error\n");
return -EIO;
}
//获取核心板设备树子节点
cnode = of_get_child_by_name(node,"core-led");
if(cnode == NULL){
printk("of get cchild by name is error\n");
return -EIO;
}
//获取扩展板设备树子节点
enode = of_get_child_by_name(node,"extend-led");
if(enode == NULL){
printk("of get echild by name is error\n");
return -EIO;
}
for(i=0;i<3;i++)
{
//直接从设备树中获取到核心板gpio_desc结构体指针
cdesc[i] = gpiod_get_from_of_node(cnode,"led",i,GPIOD_OUT_LOW,NULL);
if(IS_ERR(cdesc[i])){ //将错误码转换为地址,判断地址是否在4K空间
printk("gpiod get from of cnode is error\n");
return PTR_ERR(cdesc[i]); //将地址转换为错误码
}
//设置gpio核心板引脚输出高电平
gpiod_direction_output(cdesc[i],1);
//直接从设备树中获取到扩展板gpio_desc结构体指针
edesc[i] = gpiod_get_from_of_node(enode,name[i],0,GPIOD_OUT_LOW,NULL);
if(IS_ERR(edesc[i])){ //将错误码转换为地址,判断地址是否在4K空间
printk("gpiod get from of enode is error\n");
return PTR_ERR(edesc[i]); //将地址转换为错误码
}
//设置gpio扩展板引脚输出高电平
gpiod_direction_output(edesc[i],1);
}
return 0;
}
static void __exit demo_exit(void)
{
int i = 0;
for(i=0;i<3;i++)
{
//设置gpio引脚输出低电平
gpiod_direction_output(cdesc[i],0);
gpiod_direction_output(edesc[i],0);
//释放gpio编号
gpiod_put(cdesc[i]);
gpiod_put(edesc[i]);
}
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");