1、Princtrl子系统的主要作用:
- 获取设备树中pin信息;
- 根据获取到的pin信息来设置pin的复用功能;
- 根据获取到的pin信息来设置pin的电气特性,比如上下拉、速度等。
只需要在设备树里面设置好某个 pin 的相关属性,其他的初始化工作均由 pinctrl 子系统来完成, pinctrl 子系统源码目录为 drivers/pinctrl。
2、向设备树中添加pinctrl节点模板(以imx6ull为例):
1、创建对应的节点:
同一个外设的 PIN 都放到一个节点里面,打开 imx6ull-emmc.dts,在 iomuxc 节点中的“imx6ul-evk”子节点下添加“pinctrl_test”节点。添加完成以后如下所示:
pinctrl_test: testgrp {
/* 具体的 PIN 信息 */
};
2、添加"fsl,pins"属性:
设备树是通过属性来保存信息的,因此我们需要添加一个属性,属性名字一定要为“fsl,pins”。
pinctrl_test: testgrp {
fsl,pins = <
/* 设备所使用的 PIN 配置信息 */
>;
};
3、在"fsl,pins"属性中添加PIN配置信息:
在“fsl,pins”属性中添加具体的 PIN 配置信息。
pinctrl_test: testgrp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 config /*config 是具体设置值*/
>;
};
3、GPIO子系统
GPIO子系统的作用:用于初始化GPIO并且提供相应的API函数,如:设置GPIO为输入输出,读取GPIO等。
GPIO子系统的主要目的:方便驱动开发者使用GPIO。
驱动开发者在设备树中添加 GPIO相关信息,然后就可以在驱动程序中使用 GPIO子系统提供的 API函数来操作 GPIO, Linux 内核向驱动开发者屏蔽掉了 GPIO 的设置过程,极大的方便了驱动开发者使用 GPIO。
4、gpio子系统API函数:
gpio子系统提供以下几个常用的API函数:
1、gpio_request函数:
gpio_request 函数用于申请一个 GPIO 管脚,在使用一个 GPIO 之前一定要使用 gpio_request进行申请,函数原型如下:
int gpio_request(unsigned gpio, const char *label)
gpio
:要申请的 gpio 标号,使用 of_get_named_gpio 函数从设备树获取指定 GPIO 属性信息,此函数会返回这个 GPIO 的标号。
label
:给 gpio 设置个名字。
返回值
: 0,申请成功;其他值,申请失败。
2、gpio_free函数:
如果不使用某个 GPIO 了,那么就可以调用 gpio_free 函数进行释放。函数原型如下:
void gpio_free(unsigned gpio)
gpio
:要释放的 gpio 标号。
返回值
: 无。
3、 gpio_direction_input 函数:
此函数用于设置某个 GPIO 为输入,函数原型如下所示:
int gpio_direction_input(unsigned gpio)
gpio
:要设置为输入的 GPIO 标号。
返回值
: 0,设置成功;负值,设置失败。
4、 gpio_direction_output 函数:
此函数用于设置某个 GPIO 为输出,并且设置默认输出值,函数原型如下:
int gpio_direction_output(unsigned gpio, int value)
gpio
:要设置为输出的 GPIO 标号。
value
: GPIO 默认输出值。
返回值
: 0,设置成功;负值,设置失败。
5、 gpio_get_value 函数:
此函数用于获取某个 GPIO 的值(0 或 1),此函数是个宏,定义所示:
#define gpio_get_value __gpio_get_value
int __gpio_get_value(unsigned gpio)
gpio
:要获取的 GPIO 标号。
返回值
: 非负值,得到的 GPIO 值;负值,获取失败。
6、 gpio_set_value 函数
此函数用于设置某个 GPIO 的值,此函数是个宏,定义如下
#define gpio_set_value __gpio_set_value
void __gpio_set_value(unsigned gpio, int value)
gpio
:要设置的 GPIO 标号。
value
: 要设置的值。
返回值
: 无
5、设备树中添加gpio节点模板:
1、创建 test 设备节点:
在根节点“/”下创建 test 设备子节点,如下所示:
test {
/* 节点内容 */
}
2、添加 pinctrl 信息:
上面我们创建了 pinctrl_test 节点,此节点描述了 test 设备所使用的 GPIO1_IO00 这个 PIN 的信息,我们要将这节点添加到 test 设备节点中,如下所示:
test {
pinctrl-names = "default"; //添加 pinctrl-names 属性,此属性描述 pinctrl 名字为“default”
pinctrl-0 = <&pinctrl_test>; //添加 pinctrl-0 节点,此节点引用上面创建的 pinctrl_test 节点,表示 tset 设备的所使用的 PIN 信息保存在 pinctrl_test 节点中
/* 其他节点内容 */
};
3、添加 GPIO 属性信息:
在 test 节点中添加 GPIO 属性信息,表明 test 所使用的 GPIO 是哪个引脚,添加完成以后如下所示:
test {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_test>;
gpio = <&gpio1 0 GPIO_ACTIVE_LOW>; //test 设备所使用的 gpio
};
6、与gpio相关的OF函数:
1、 of_gpio_named_count 函数:
of_gpio_named_count 函数用于获取设备树某个属性里面定义了几个 GPIO 信息,要注意的是空的 GPIO 信息也会被统计到,此函数原型如下:
int of_gpio_named_count(struct device_node *np, const char *propname)
np
:设备节点。
propname
:要统计的 GPIO 属性。
返回值
: 正值,统计到的 GPIO 数量;负值,失败。
2、 of_gpio_count 函数
和 of_gpio_named_count 函数一样,但是不同的地方在于,此函数统计的是“gpios”这个属性的 GPIO 数量,而 of_gpio_named_count 函数可以统计任意属性的 GPIO 信息,函数原型如下所示:
int of_gpio_count(struct device_node *np)
np
:设备节点。
返回值
: 正值,统计到的 GPIO 数量;负值,失败。
3、 of_get_named_gpio 函数
此函数获取 GPIO 编号,因为 Linux 内核中关于 GPIO 的 API 函数都要使用 GPIO 编号,此函数会将设备树中类似<&gpio5 7 GPIO_ACTIVE_LOW>的属性信息转换为对应的 GPIO 编号,函数原型如下:
int of_get_named_gpio(struct device_node *np,
const char *propname,
int index)
np
:设备节点。
propname
:包含要获取 GPIO 信息的属性名。
index
: GPIO 索引,因为一个属性里面可能包含多个 GPIO,此参数指定要获取哪个 GPIO的编号,如果只有一个 GPIO 信息的话此参数为 0。
返回值
: 正值,获取到的 GPIO 编号;负值,失败。