
一般工作流程:linux/gpio/consumer.h
头文件:
获取描述:
gpiod_get(最基础的函数)
gpiod_count(计算有几个GPIO)
gpiod_get_optional (判NULL为依据)
gpiod_get_index(索引到对应的GPIO)
方向:
gpiod_direction_output
gpiod_direction_input(struct gpio_desc *desc)
value值:
gpiod_get_value
gpiod_set_value
整数型 与 描述符型的转换:
Int 与 gpio_desc 对转换
desc_to_gpio
gpio_to_desc
一、GPIO函数介绍
gpiod 开头的 ---- 基于描述符
gpio 开头 ---- 基于整数型 (最早的API)
1.1、获取 GPIO 描述符函数
功能 这个函数用来在Linux系统中获取GPIO(通用输入输出)的描述符(即GPIO的"标识"),方便后续操作。
函数原型
struct gpio_desc *__must_check gpiod_get(struct device *dev,
const char *con_id,
enum gpiod_flags flags);2
3
需包含的头文件
`#include <linux/gpio/consumer.h>`参数说明
设备指针(dev)
- 需要操作GPIO的设备的结构体指针。比如,如果你在驱动某个LED模块,这里的设备指针就是这个LED模块的设备结构。
GPIO名称(con_id)
一个字符串,用于在设备树(Device Tree)中匹配具体的GPIO。
例如:"reset"、"power"或"led",这个名字需要和设备树中定义的GPIO名称一致。
模式标志(flags)
通过标志设置GPIO的工作模式:
GPIOD_INPUT:设置为输入模式(如读取按键状态)。GPIOD_OUTPUT:设置为输出模式(如控制LED亮灭)。GPIOD_ACTIVE_LOW:表示低电平有效(如信号线反转)。GPIOD_OPEN_DRAIN:开漏输出模式(需外接上拉电阻)。GPIOD_OPEN_SOURCE:开源输出模式(需外接下拉电阻)。
返回值
成功:返回一个GPIO描述符(
struct gpio_desc指针),后续操作(如读写电平)都通过它进行。失败:返回
NULL,表示找不到对应的GPIO或配置错误。
1.2、其他获取 GPIO 描述符函数
在 Linux 内核中还有另外三个同样是获取 GPIO 描述符资源的函数, 三个函数内容如下所示:
struct gpio_desc *gpiod_get_index(struct device *dev, const char *con_id, unsigned int idx, enum gpiod_flags
flags);
struct gpio_desc *gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags);
struct gpio_desc *gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum
gpiod_flags flags);2
3
4
5
相比之前的gpiod_get函数,这三个新函数增加了两个特点:
index参数:当设备树中某个GPIO属性包含多个引脚时,用这个参数指定具体要操作的哪个引脚(比如第0个、第1个)。
可选的optional后缀:函数名可能带或不带"optional()",功能相同(都是获取GPIO描述符),但失败时的返回值不同。
返回值区别:
带optional()的函数:如果找不到GPIO,直接返回
NULL。不带optional的函数:如果找不到GPIO,返回一个特殊值(表示获取失败,而不是
NULL)。
1.3、释放 GPIO 描述符
作用: 释放之前申请的 GPIO 资源。
函数定义:
void gpiod_put(struct gpio_desc *desc);使用前需包含头文件:
`#include <linux/gpio/consumer.h>`参数说明:
desc:要释放的 GPIO 描述符(即之前通过gpiod_get()等函数获取的 GPIO 标识)。
功能描述: 当你不再需要某个 GPIO 引脚时,调用此函数释放它,以便系统可以重新分配该资源。
返回值: 不返回任何值(无意义返回)。
1.4、获取 GPIO 的方向函数:
作用:
该函数的作用是查看某个GPIO引脚是输入还是输出。
函数定义:
void gpiod_put(struct gpio_desc *desc);使用前需包含头文件:
`#include <linux/gpio/consumer.h>`参数说明:
要使用这个函数:
需要包含头文件:#include
<linux/gpio/consumer.h>函数需要传入GPIO的描述符(即该GPIO的标识信息)
调用方式: int result = gpiod_get_direction(你的_gpio描述符);
返回结果说明:
如果返回0,说明该GPIO设置为输入模式
如果返回1,说明该GPIO设置为输出模式
如果返回负数(比如-1),说明操作失败(可能GPIO未正确初始化)
简单来说,这个函数就像询问GPIO当前是"接收信号"状态还是"发送信号"状态。得到结果后,你可以根据需要进行下一步操作,比如确认配置是否正确,或决定如何处理该引脚的信号。
1.5、配置 GPIO 的方向函数:
::: 函数原型:
int gpiod_direction_input(struct gpio_desc *desc);
int gpiod_direction_output(struct gpio_desc *desc, int value);
头文件:
#include <linux/gpio/consumer.h>
参数:
desc: 指向 GPIO 描述符的指针。
value(仅适用于 gpiod_direction_output) : 初始输出值, 可以是 0 或 1。
函数功能:
gpiod_direction_input 函数用于配置 GPIO 的方向为输入。
gpiod_direction_output 函数用于配置 GPIO 的方向为输出, 并可指定初始输出值。
返回值:
返回值为整型, 表示配置 GPIO 方向的结果。
如果成功配置 GPIO 方向, 返回值为 0。
如果配置失败, 返回值为负数, 表示错误码。 :::
这两个函数用于配置 GPIO 的方向。 gpiod_direction_input 将给定的 GPIO 描述符所代表的GPIO 配置为输入模式。 而 gpiod_direction_output 将 GPIO 配置为输出模式, 并可以指定初始输出值。
1.6、读取 GPIO 的电平状态函数
::: 函数原型:
int gpiod_get_value(const struct gpio_desc *desc);
头文件:
#include <linux/gpio/consumer.h>
参数:
desc: 指向 GPIO 描述符的指针。
函数功能:
gpiod_get_value 函数用于读取 GPIO 的电平状态。
返回值:
返回值为整型, 表示 GPIO 的电平状态。
如果成功读取到 GPIO 的电平状态, 返回值为 0 或 1, 分别表示低电平和高电平。
如果读取失败, 返回值为负数, 表示错误码。 :::
该函数用于读取给定 GPIO 描述符所代表的 GPIO 的电平状态。 通过调用该函数, 可以获取 GPIO 当前的电平状态, 以便进一步处理和判断 GPIO 的状态。
1.7、读取 GPIO 的电平状态函数
::: 函数原型:
void gpiod_set_value(struct gpio_desc *desc, int value);
头文件:
#include <linux/gpio/consumer.h>
参数:
desc: 指向 GPIO 描述符的指针。
value: 要设置的 GPIO 的电平状态, 可以是 0 或 1。
函数功能:
gpiod_set_value 函数用于设置 GPIO 的电平状态。
返回值: 无(void)
该函数用于设置给定 GPIO 描述符所代表的 GPIO 的电平状态。 通过调用该函数, 您可以将 GPIO设置为特定的电平状态, 以便控制外部设备或执行其他相关操作。 :::
value 参数表示要设置的 GPIO 的电平状态, 可以是 0 或 1。 当 value 为 0 时, 表示设置GPIO 为低电平; 当 value 为 1 时, 表示设置 GPIO 为高电平。
该函数没有返回值, 因为它只是执行设置操作而不需要返回任何结果。
在使用该函数之前, 需要确保 GPIO 已经被正确地配置为输出模式。
1.8、GPIO 描述符转换为中断编号函数
::: 函数原型:
int gpiod_to_irq(const struct gpio_desc *desc);
头文件:
#include <linux/gpio/consumer.h>
参数:
desc: 指向 GPIO 描述符的指针。
函数功能:
gpiod_to_irq 函数用于将 GPIO 描述符转换为中断号。
返回值:
返回值为整型, 表示中断号。
如果成功将 GPIO 描述符转换为中断号, 返回值为大于等于 0 的中断号。
如果转换失败, 返回值为负数, 表示错误码。 :::
该函数用于将给定 GPIO 描述符所代表的 GPIO 转换为对应的中断号。
二、实验
源代码下载:git clone git@gitee.com:yangxuesong314/linux-driver.git(若之前已git拉取代码可以忽略) 代码位于:linux-driver/09.GPIO子系统/01.基于描述符的GPIO接口
2.1、设备树
my_gpio:gpiol_a0 {
compatible = "mygpio";
my-gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>,<&gpio1 RK_PB0 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&mygpio_ctrl>;
};2
3
4
5
6
compatible: 用于指定设备的兼容性字符串, 与驱动程序中的值相匹配。
my-gpios: 指定了与该设备相关联的 GPIO。
&gpio1 表示 GPIO 控制器的句柄(handle)
RK_PA0 是与该 GPIO 相关的资源描述符(resource specifier)
GPIO_ACTIVE_HIGH 表示 GPIO 的默认电平为高电平。
pinctrl-names 和 pinctrl-0: 用于指定引脚控制器(pinctrl) 的配置。 pinctrl-names 表示引脚控制器配置的名称, 这里为 "default"。 pinctrl-0 指定了与该配置相关联的引脚控制器句柄, 这里为 &mygpio_ctrl。
mygpio {
mygpio_ctrl: my-gpio-ctrl {
rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
};
};2
3
4
5
在第三行的内容中,
1 表示引脚索引(x :哪个大组GPIO1)
RK_PA0: (GPIOx_A0)表示资源描述符, 用于标识与该引脚相关联的物理资源, 表示引脚所属的功能组,
RK _FUNC_GPI0 表示将引脚的功能设置为 GPIO,
&pcfg_pull_none 表示引脚配置为无上下拉。
pcfg_pull_up
pcfg_pull_down
pcfg_pull_none
pcfg_pull_none_drv_level_0
2.2、驱动
`#include <linux/module.h>`
`#include <linux/interrupt.h>`
`#include <linux/platform_device.h>`
`#include <linux/of.h>`
`#include <linux/gpio/consumer.h>`
`#include <linux/kthread.h>`
`#include <linux/delay.h>`
`#include <linux/atomic.h>`
static struct task_struct *blink_thread;
static struct gpio_desc *gpio;
static atomic_t keep_blinking = ATOMIC_INIT(1);
static int blink_thread_func(void *data) {
int value = 0;
while (atomic_read(&keep_blinking)) {
gpiod_set_value(gpio, value);
msleep(500);
value = !value;
gpiod_set_value(gpio, value);
printk(KERN_INFO "GPIO state: %d\n", value);
if (kthread_should_stop())
break;
}
return 0;
}
static int my_probe(struct platform_device *pdev) {
gpio = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW);
if (IS_ERR(gpio)) {
dev_err(&pdev->dev, "Failed to get GPIO: %ld\n", PTR_ERR(gpio));
return PTR_ERR(gpio);
}
blink_thread = kthread_run(blink_thread_func, NULL, "gpio_blinker");
if (IS_ERR(blink_thread)) {
return PTR_ERR(blink_thread);
}
dev_info(&pdev->dev, "GPIO control initialized\n");
return 0;
}
static int my_remove(struct platform_device *pdev) {
atomic_set(&keep_blinking, 0);
if (blink_thread) {
kthread_stop(blink_thread);
blink_thread = NULL;
}
gpiod_set_value(gpio, 0);
dev_info(&pdev->dev, "GPIO control released\n");
return 0;
}
static const struct of_device_id my_of_match[] = {
{ .compatible = "my_platform_gpio" },
{}
};
MODULE_DEVICE_TABLE(of, my_of_match);
static struct platform_driver my_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.name = "my_platform_driver",
.of_match_table = my_of_match,
},
};
module_platform_driver(my_driver);
MODULE_LICENSE("GPL");2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
Makefile 我们编译到内核里面
obj-y += gpiodesc.c实验:内核启动后对应的打印如下:

