1. 概述
内核提供了关于硬件外设 GPIO 相关的 API,在编写驱动时可以调用这些 API 完成硬件功能的控制。
2. GPIO 子系统架构
3. 相关 API
3.1 获取设备树节点结构体指针
struct device_node *of_find_node_by_name(struct device_node *from, const char *name)
功能:通过设备树节点的名字解析设备树节点信息
参数:
from
:要寻找的设备树节点所在的子树根节点首地址,不知道就填NULL,默认从设备树根节点查找
name
:要查找的设备树节点的名字
返回值:成功返回当前节点结构体指针,失败返回
NULL
3.2 根据设备树节点信息解析出 gpio 编号
int of_get_named_gpio(struct device_node *np, const char *propname, int index)
参数:
np
:设备树节点结构体指针
proname
:建名
index
:索引号
返回值:成功返回 gpio 编号,失败返回错误码
3.3 申请指定的gpio编号
int gpio_request(unsigned gpio, const char *label)
参数:
gpio
:gpio 编号
label
:可填写任意字符串或者NULL
返回值:成功返回 0,失败返回错误码
3.4 释放 gpio 编号
void gpio_free(unsigned gpio)
3.5 设置 gpio 管脚为输入方向
int gpio_direction_input(unsigned gpio)
成功返回 0,失败返回错误码
3.6 设置 gpio 管脚为输出方向并且给定一个默认输出值
int gpio_direction_output(unsigned gpio, int value)
成功返回 0,失败返回错误码
3.7 设置 gpio 输出高低电平
void gpio_set_value(unsigned gpio, int value)
参数:
value
:1
(输出高电平),0
(输出低电平)
3.8 获取 gpio 管脚状态
int gpio_get_value(unsigned gpio)
返回值:
1
(输出高电平),0
(输出低电平)4. LED 灯设备树编写
4.1 LED 硬件原理图
GPIO 控制器的设备树节点内核中已经编写好了,在
.dtsi
文件中,我们需要编写 led 的设备节点只需要在节点中添加 gpio 控制器的对接关系即可,即在 led 的设备树节点中描述用的是哪个 gpio 控制器,用的是这个控制器的第几个输出管脚即可4.2 分析 gpio 控制器的设备树节点
设备树节点定义的位置:
stm32mp151.dtsi
pinctrl: pin-controller@50002000 { //指定子节点reg属性中有1个u32描述地址 #address-cells = <1>; //指定子节点reg属性有1个u32描述地址大小 #size-cells = <1>; //厂商信息 compatible = "st,stm32mp157-pinctrl"; //指定这一组gpio的父地址信息 ranges = <0 0x50002000 0xa400>; gpioe: gpio@50006000 { //空属性,标识当前节点是gpio控制器 gpio-controller; //表示引用当前节点作为gpio控制器时需要添加2个u32进行描述 #gpio-cells = <2>; //描述当前节点的地址信息 reg = <0x4000 0x400>; //描述当前控制器的时钟 clocks = <&rcc GPIOE>; //指定控制器的名字为GPIOE st,bank-name = "GPIOE"; //描述gpio控制器状态:disable表示未使能 okay表示使能 status = "disabled"; };
引用节点位置:
stm32mp15xxac-pinctrl.dtsi
&pinctrl { gpioe: gpio@50006000 { status = "okay";//状态使能 //描述当前控制器控制的管脚个数为16个 ngpios = <16>; //指定当前控制器管理的管脚编号范围 64表示当前节点控制的gpio起始编号,16表示管脚个数 gpio-ranges = <&pinctrl 0 64 16>; }; };
4.3 编写 LED 灯设备树节点
查看帮助手册:
linux-5.10.61/Documentation/devicetree/bindings/gpio
The following example could be used to describe GPIO pins used as device enable and bit-banged data signals: gpio0: gpio1 { gpio-controller; #gpio-cells = <2>; }; [...] data-gpios = <&gpio0 12 0>, <&gpio0 13 0>, <&gpio0 14 0>, <&gpio0 15 0>; In the above example, &gpio0 uses 2 cells to specify a gpio. The first cell is n a local offset to the GPIO line and the second cell represent consumer flags,such as if the consumer desire the line to be active low (inverted) or open drain. This is the recommended practice. Example of a node using GPIOs: node { enable-gpios = <&qe_pio_e 18 GPIO_ACTIVE_HIGH>; };
添加 LED 灯的设备树节点:
myleds{ led1=<&gpioe 10 0>; led2=<&gpiof 10 0>; led3=<&gpioe 8 0>; };
5. 实例代码
6. 新版 GPIO 子系统的使用
6.1 API 接口
新版本 API 操作核心不再是 GPIO 编号,而是 GPIO 对象。新版 API 函数名基本上以 GPIO_xxx 为特点。
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 对象,并向内核申请
参数:
node
:设备树节点信息指针
proname
:键名
index
:索引号
dflags
:设置 GPIO 默认状态GPIOD_IN
:输入GPIO_OUT_LOW
:输出低电平GPIO_OUT_HIGH
:输出高电平
label
:标签,填写 NULL
返回值:成功返回 gpio 对象指针,失败返回内核 4K 预留空间指针(错误码指针)
int gpiod_direction_output(struct gpio_desc *desc, int value) int gpiod_direction_input(struct gpio_desc *desc) void gpiod_set_value(struct gpio_desc *desc, int value) int gpiod_get_value(const struct gpio_desc *desc) void gpiod_put(struct gpio_desc *desc)//释放gpio编号