1.GPIO子系统框架
2.GPIO子系统相关API
#include<linux/of_gpio.h>
1.解析设备树节点信息
struct device_node *of_find_node_by_path(const char *path)
功能:通过路径获取设备树节点信息
path:设备树节点路径 ("/mynode@0x12345678")
返回值:成功返回目标节点首地址,失败返回NULL
2.获取对应的GPIO编号
int of_get_named_gpio(struct device_node *np,
const char *propname, int index)
功能:根据gpio相关节点的解析得到对应gpio的编号
参数:
np:设备树节点首地址
proname:键名
index:索引号
返回值:成功返回gpio编号,失败返回错误码
3. 申请要使用的gpio编号
int gpio_request(unsigned gpio, const char *label)
功能:申请要使用的gpio编号
参数:
gpio:要申请的gpio编号
label:填写任意字符串都可以,默认填NULL
返回值:成功返回0,失败返回错误码
4.int gpio_direction_input(unsigned gpio)
功能:将gpio设置为输入功能
参数:
gpio:gpio编号
返回值:成功返回0,失败返回错误码
5. int gpio_direction_output(unsigned gpio, int value)
功能:将gpio设置为输出功能并且输出一个指定电平
gpio:gpio编号
value: 1高电平 0低电平
返回值:成功返回0,失败返回错误码
6.void gpio_set_value(unsigned gpio, int value)
功能:设置gpio输出的电平值
gpio:gpio编号
value: 1高电平 0低电平
7. int gpio_get_value(unsigned gpio)
功能:获取gpio引荐状态值
参数:
gpio:gpio编号
返回值:此时的引脚状态值
8.void gpio_free(unsigned gpio)
功能:释放申请的gpio编号
参数:gpio:目标gpio编号
返回值:无
3.GPIO设备树的编写方式
3.1led的硬件连接图
3.2 GPIO控制器的设备树
stm32mp157a-fsmp1a.dts->stm32mp157.dtsi->stm32mp153.dtsi->stm32mp151.dtsi
pinctrl: pin-controller@50002000 {
#address-cells = <1>;
#size-cells = <1>;
gpioe: gpio@50006000 {
gpio-controller;//空属性,标识这个节点是gpio控制器节点
#gpio-cells = <2>;//在引用gpio控制器节点时,值的个数
reg = <0x4000 0x400>;//控制器的地址和长度
clocks = <&rcc GPIOE>;//引用gpioe控制器的时钟设备树节点
st,bank-name = "GPIOE";//gpio控制器的名字GPIOE
status = "disabled";//控制器的状态 disable不工作 okay工作
};
};
vi stm32mp15xxac_pinctrl.dtsi
&pinctrl {
gpioe: gpio@50006000 {
status = "okay";//将上面gpioe中的status属性值覆盖
ngpios = <16>;//这个控制器一共16个管脚
gpio-ranges = <&pinctrl 0 64 16>;//gpioe在整个gpio中的编号
};
};
3.3 led的设备树节点编写
内核顶层目录/Documentation/devicetree/bindings/gpio
vi gpio.txt
gpioe: gpio@50006000 {
gpio-controller;
#gpio-cells = <2>;
};
在linux-5.10.61/arch/arm/boot/dts/stm32mp157a-fsmp1a.dts文件中添加下面内容:
myleds{
// &gpioe表示引用gpioe控制器,10表示管脚是gpioe10 0表示默认状态
led1= <&gpioe 10 0>;
led2= <&gpiof 10 0>;
led3= <&gpioe 8 0>;
};
4.GPIO子系统的使用实例
#include <linux/init.h>
#include <linux/module.h>
#include<linux/of.h>
#include<linux/of_gpio.h>
#include<linux/gpio.h>
/* myleds{
// &gpioe表示引用gpioe控制器,10表示管脚是gpioe10 0表示默认状态
led1= <&gpioe 10 0>;
led2= <&gpiof 10 0>;
led3= <&gpioe 8 0>;
};
};*/
struct device_node *node;
int gpiono;
static int __init mycdev_init(void)
{
int ret;
//通过路径获取设备树节点信息
node=of_find_node_by_name(NULL,"myleds");
if(node==NULL)
{
printk("通过路径解析设备树节点信息失败\n");
return -ENODATA;
}
printk("通过路径解析设备树节点信息成功\n");
//获取gpio编号
gpiono=of_get_named_gpio(node,"led1",0);
if(gpiono<0)
{
printk("获取gpio编号失败\n");
return gpiono;
}
printk("获取gpio编号成功\n");
//申请gpio编号的使用权
ret=gpio_request(gpiono,NULL);
if(ret)
{
printk("申请gpio编号失败\n");
return ret;
}
printk("申请gpio编号成功\n");
//设置gpio的方向为输出并给一个低电平初始值
gpio_direction_output(gpiono,0);
//将led1点亮
gpio_set_value(gpiono,1);
return 0;
}
static void __exit mycdev_exit(void)
{
//卸载驱动前先关灯
gpio_set_value(gpiono,0);
//释放gpio编号
gpio_free(gpiono);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
5.GPIO子系统新版API
老版本的函数是gpio_***,新版本的接口名字,gpiod_***
1.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编号并且申请gpio编号的使用权
参数:
node:设备树节点信息结构体指针
propname:键名
index:索引号
dflags:设置使用的gpio的状态
GPIOD_IN:输入
GPIOD_OUT_LOW:输出模式并且为低电平
GPIOD_OUT_HIGH:输出模式并且为高电平
label:填NULL
返回值:成功返回gpio结构体指针,失败返回错误码指针 IS_ERR
2. int gpiod_direction_input(struct gpio_desc *desc)
3. int gpiod_direction_output(struct gpio_desc *desc, int value)
4. int gpiod_get_value(const struct gpio_desc *desc)
5. void gpiod_set_value(struct gpio_desc *desc, int value)
6.void gpiod_put(struct gpio_desc *desc)
使用实例
#include <linux/init.h>
#include <linux/module.h>
#include<linux/of.h>
#include<linux/of_gpio.h>
#include<linux/gpio.h>
/* myleds{
// &gpioe表示引用gpioe控制器,10表示管脚是gpioe10 0表示默认状态
led1= <&gpioe 10 0>;
led2= <&gpiof 10 0>;
led3= <&gpioe 8 0>;
};
};*/
struct device_node *node;
struct gpio_desc *desc;
static int __init mycdev_init(void)
{
int ret;
//通过路径获取设备树节点信息
node=of_find_node_by_name(NULL,"myleds");
if(node==NULL)
{
printk("通过路径解析设备树节点信息失败\n");
return -ENODATA;
}
printk("通过路径解析设备树节点信息成功\n");
//获取gpio编号
desc=gpiod_get_from_of_node(node,"led1",0,GPIOD_OUT_LOW,NULL);
if(IS_ERR(desc))
{
printk("申请gpio编号失败\n");
return PTR_ERR(desc);
}
printk("申请gpio编号成功\n");
//亮灯
gpiod_set_value(desc,1);
return 0;
}
static void __exit mycdev_exit(void)
{
//灭灯
gpiod_set_value(desc,0);
//释放gpio编号
gpiod_put(desc);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");