前言
前几节引入了设备数下的led驱动,但它本质上还是配置led驱动的寄存器,与裸机开发并无区别。本节引入了pinctrl子系统和gpio子系统来简化led驱动的配置。
一、pinctrl子系统
(1)pinctrl 子系统简介
大多数SOC的PIN都是支持复用的,所以在配置时要考虑复用的设置,此外还要配置PIN的电气特性,比如上下拉、速度、驱动等。pinctrl子系统的主要工作内容:
获取设备树中pin信息
根据获得到的pin信息来设置pin的复用功能
根据获得到的pin信息来设置pin的电气特性,比如上下拉、速度、驱动能力
(2)设备树中添加 pinctrl 节点
- 设备树中的 iomuxc 节点就是 I.MX6ULL 的 IOMUXC 外设对应的节点
- “iomuxc”节点下引用了 pinctrl_hog_1 节点, Linux 内核中的 iomuxc 驱动自动初始化 pinctrl_hog_1 节点下的所有 PIN
在设备树(imx6ull-alientek-emmc.dts)创建一个节点来描述 PIN 的配置信息
1、创建对应节点
2、添加“fsl,pins”属性
3、 在“ fsl,pins ”属性中添加 PIN 配置信息
例:
在 iomuxc 节点中的“imx6ul-evk ”子节点下添加“ pinctrl_test ”节点。
pinctrl_test: testgrp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 config /*config 是具体设置值*/
>;
};
(3)Linux 内核的 pinctrl 子系统实现原理
imx6ul_pinctrl_probe 函数就是 I.MX6ULL 这个 SOC 的 PIN 配置入口函数,其实现原理如下所示:
二、gpio 子系统
(1)gpio 子系统简介
- gpio 子系统用于初始化 GPIO 并且提供相应的 API 函数,比如设置 GPIO 为输入输出,读取 GPIO 的值等。
- 在设备树中添加 gpio 相关信息,在驱动程序中使用 gpio 子系统提供的 API 函数来操作 GPIO。
(2)gpio 子系统 API 函数
申请 GPIO 管脚 | int gpio_request (unsigned gpio, const char *label) 0 :申请成功; 其他值:申请失败 |
释放 GPIO 管脚 | void gpio_free (unsigned gpio) gpio :要释放的 gpio 标号 |
设置 GPIO 为输入 | int gpio_direction_input (unsigned gpio) 0 :设置成功; 负值:设置失败 |
设置 GPIO 为输出 | int gpio_direction_output (unsigned gpio, int value) 0 :设置成功; 负值:设置失败 |
获取 GPIO 的值 (0 或 1) | #define gpio_get_value __gpio_get_value 非负值:得到的 GPIO 值; 负值:获取失败 |
设置 GPIO 的值 | #define gpio_set_value __gpio_set_value void __gpio_set_value (unsigned gpio, int value) gpio :要设置的 GPIO 标号。 value : 要设置的值。 |
(3)设备树中添加 gpio 节点
1、创建 test 设备节点
2、添加 pinctrl 信息
3、添加 GPIO 属性信息
例:
test {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_test>;
gpio = <&gpio1 0 GPIO_ACTIVE_LOW>;
};
(4)与 gpio 相关的 OF 函数
获取设备树某个属性里面的 GPIO 数量 (统计任意属性的 GPIO 信息) | int of_gpio_named_count (struct device_node *np, const char *propname) 正值:统计到的 GPIO 数量; 负值:失败 |
获取设备树某个属性里面的 GPIO 数量 (统计“gpios”属性的 GPIO 数量 | int of_gpio_count (struct device_node *np) 正值:统计到的 GPIO 数量; 负值:失败 |
获取 GPIO 编号 | int of_get_named_gpio (struct device_node *np, const char *propname, int index) 正值:获取到的 GPIO 编号; 负值:失败 |