一、前言
前面我们编写了基于设备树的 LED 驱动,但是驱动的本质还是没变,都是配置 LED 灯所使用的 GPIO 寄存器,驱动开发方式和裸机基本没啥区别。本章我们就来学习一下如何借助 pinctrl 和 gpio 子系统来简化 GPIO 驱动开发。
Linux 内核针对 PIN 的配置推出了 pinctrl 子系统,对于 GPIO的配置推出了 gpio 子系统。
本节先讲解 gpio 子系统。
二、gpio 子系统
1、gpio 子系统简介
上节讲解了 pinctrl 子系统,pinctrl 子系统重点是设置 PIN(有的 SOC 叫做 PAD)的复用和电气属性,如果 pinctrl 子系统将一个 PIN 复用为 GPIO 的话,那么接下来就要用到 gpio 子系统了。
gpio 子系统顾名思义,就是用于初始化 GPIO 并且提供相应的 API 函数,比如设置 GPIO为输入输出,读取 GPIO 的值等
gpio 子系统的主要目的是:
方便驱动开发者使用 gpio,驱动开发者在设备树中添加 gpio 相关信息,然后就可以在驱动程序中使用 gpio 子系统提供的 API函数来操作 GPIO,Linux 内核向驱动开发者屏蔽掉了 GPIO 的设置过程。
2、I.MX6ULL 的 gpio 子系统驱动
<1> 设备树中的 gpio 信息
上节我们通过pinctrl 子系统,配置了 UART1_RTS_B 这个 PIN 复用为 GPIO1_IO19(SD卡CD信号检测引脚),并设置了电气属性:
pinctrl_hog_1: hoggrp-1 {
fsl,pins = <
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
......
>;
};
要想设备的某个引脚使用 GPIO1_IO19,那么就需要在该设备对应的设备树节点中描述,在描述的同时会通过 gpio子系统配置 GPIO1_IO19。
// SD卡设备总节点
// usdhc1 节点需要描述 SD 卡所有的信息,因为驱动要使用
&usdhc1 {
pinctrl-names = "default", "state_100mhz", "state_200mhz";
pinctrl-0 = <&pinctrl_usdhc1>;
pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
keep-power-in-suspend;
enable-sdio-wakeup;
vmmc-supply = <®_sd1_vmmc>;
status = "okay";
};
<2> 设备节点中 pinctrl 信息详解
pinctrl-names 中保存了节点对应设备的不同工作状态,下面的pinctrl-0、1、2代表各个状态对应的pinctrl 配置集合,也就是说,如果设备处于default状态,会使用pinctrl-0的pinctrl 子系统配置,以此类推。但是上面为什么没有配置GPIO1_IO19 对应的pinctrl 子系统配置呢?pinctrl-0 应该是这样才对:
pinctrl-0 = <
&pinctrl_usdhc1
&pinctrl_hog_1 // 上节的pinctrl配置
>;
如果没有对GPIO1_IO19 进行功能复用,该节点的引脚就无法使用GPIO功能,这是怎么回事呢?我们可以看iomuxc节点内容(上节),我们发现iomuxc节点已经将pinctrl 配置进行初始化调用(没必要在上面的usdhc1节点中,只是进行功能复用,在哪个节点中都一样),功能复用为GPIO。
<3> 设备节点中 gpio 信息详解
usdhc1设备节点中下面的代码,用来配置该设备(SD卡)的CD引脚使用哪个IO。
cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
- “&gpio1”表示 CD 引脚所使用的 IO 属于 GPIO1 组;
- “19” 表示 GPIO1 组的第 19 号 IO,通过这两个值 SD 卡驱动程序就知道 CD 引脚使用了 GPIO1_IO19这 GPIO;
- “GPIO_ACTIVE_LOW” 表示低电平有效, “GPIO_ACTIVE_HIGH” 就表示高电平有效。
根据上面这些信息,SD 卡驱动程序就可以使用 GPIO1_IO19 来检测 SD 卡的 CD 信号了,
打开 imx6ul.dtsi,在里面找到如下所示内容:
gpio1: gpio@209c000 {
compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
reg = <0x0209c000 0x4000>;
interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
gpio-ranges = <&iomuxc 0 23 10>, <&iomuxc 10 17 6>,
<&iomuxc 16 33 16>;
};
- “gpio-controller”表示 gpio1 节点是个 GPIO 控制器。
- #gpio-cells 为 2,表示一共有两个 cell。第一个 cell 为 GPIO 编号,比如“&gpio1 3”就表示GPIO1_IO03。第二个 cell 表示 GPIO 极性 , 如果为0(GPIO_ACTIVE_HIGH) 的话表示高电平有效 , 如果为1(GPIO_ACTIVE_LOW)的话表示低电平有效。
<4> gpio 驱动程序详解
根据 dtsi 文件中 gpio1 节点(上方代码)的 compatible 属性描述了兼容性,在 Linux 内核中搜索“fsl,imx6ul-gpio”和“fsl,imx35-gpio”这两个字符串,可以查找 GPIO 驱动文件。可以得 GPIO 驱动也是个平台设备驱动,因此当设备树中的设备节点与驱动的 of_device_id 匹配以后 probe 函数就会执行,在这里就是 mxc_gpio_probe 函数。
3、设备树中添加 gpio 节点步骤(总结)
上节我们已经讲解了如何创建 test 设备的 pinctrl 节点。本节我们来学习一下如何创建 test 设备的 GPIO 节点。
👺 创建 test 设备节点
在根节点“/”下创建 test 设备子节点:
test {
/* 节点内容 */
};
👺 添加 pinctrl 信息
上节我们创建了 pinctrl_test 节点,此节点描述了 test 设备所使用的 GPIO1_IO00 这个 PIN 的信息,我们要将这节点添加到 test 设备节点中:文章来源:https://www.toymoban.com/news/detail-434959.html
test {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_test>;
/* 其他节点内容 */
};
👺 添加 GPIO 属性信息
我们最后需要在 test 节点中添加 GPIO 属性信息,表明 test 所使用的 GPIO 是哪个引脚: 文章来源地址https://www.toymoban.com/news/detail-434959.html
test {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_test>;
gpio = <&gpio1 0 GPIO_ACTIVE_LOW>;
}
到了这里,关于【Linux驱动开发】011 gpio子系统的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!