设备树的LED驱动开发中,虽实现了功能,但本质仍是直接操作gpio寄存器,开发方式与裸机无异。
而Linux内核作为庞大且完善的系统,有着成熟的驱动框架,像GPIO这类基础驱动,若沿用裸机方式,无疑是“大材小用”,效率低下且维护困难。为此,Linux内核提供了pinctrl和gpio子系统,本章就聚焦PINctrl子系统,后续再深入gpio子系统,助力我们掌握更高效的GPIO驱动开发方法。
1 pinctrl子系统:引脚配置的“智能管家”
1 pinctrl子系统的核心价值
Linux驱动秉持分离与分层理念,pinctrl子系统正是这一思想的产物,它和gpio子系统共同构成了GPIO驱动的核心支撑。之所以将这两个子系统前置讲解,是因为几乎所有外设驱动都离不开GPIO,掌握它们是驱动开发的基础。
LED驱动的GPIO初始化流程,可总结为两大关键步骤:一是设置引脚复用功能、上下拉、速度等,将引脚配置为GPIO功能;二是配置GPIO的输入输出属性。
这一流程与STM32等芯片的引脚配置逻辑相通,先定功能,再设电气特性,最后明确IO方向。
但多数SOC的引脚复用特性复杂,手动配置不仅繁琐,还极易出现引脚功能冲突等问题。
pinctrl子系统的出现,正是为了破解这些难题,它实现了引脚配置的自动化,让开发者无需直接操作底层寄存器,只需在设备树中清晰定义引脚需求,剩余的配置工作全由pinctrl子系统自动完成,其源码位于`drivers/pinctrl`目录下。
pinctrl子系统的核心工作可概括为:从设备树获取PIN的配置信息,进而完成引脚的复用功能设置与电气特性配置,为开发者屏蔽底层硬件细节。
2 I.MX6ULL的pinctrl子系统驱动全解析
设备树中PIN配置信息的深度解读
要使用pinctrl子系统,必须先在设备树中准确描述PIN的配置信息。以I.MX6ULL为例,打开`imx6ull.dtsi`,可找到`iomuxc`节点,它对应I.MX6ULL的IOMUXC外设,是引脚配置的核心载体。
不过,`iomuxc`节点本身并未直接呈现具体的PIN配置,真正的配置信息藏在`imx6ull-alientek-emmc.dts`中。在该文件中,`iomuxc`节点下会定义具体的引脚分组,通过`pinctrl-names`和`pinctrl-0`指定默认配置,再借助`fsl,pins`属性,用一组数据精准描述每个引脚的复用和电气参数。
这些数据包含6个关键值:`mux_reg`(复用寄存器偏移)、`conf_reg`(电气特性寄存器偏移)、`input_reg`(输入寄存器偏移,部分引脚无需此配置)、`mux_mode`(复用模式值)、`input_val`(输入值)和`config`(电气特性配置值)。
`MX6UL_PAD_UART1_RTS_B__GPIO1_IO19`为例,`mux_reg`和`conf_reg`结合`iomuxc`节点的寄存器基地址,就能定位到具体的硬件寄存器;`mux_mode`确定引脚复用为GPIO功能;`config`则负责设置上下拉、驱动能力、速度等电气参数,比如常见的`0x17059`这类值,就是根据实际硬件需求设定的寄存器配置值。
2. pinctrl子系统的驱动执行流程
I.MX6ULL的pinctrl驱动实现,核心在于`drivers/pinctrl/Freescale/pinctrl-imx6ul.c`文件。该驱动通过`of_device_id`结构体数组匹配设备树中的`iomuxc`节点,当兼容性字符串“fsl,imx6ul-iomuxc”与设备树节点匹配成功后,`imx6ul_pinctrl_probe`函数便会启动,成为I.MX6ULL引脚配置的入口。
整个驱动执行流程清晰有序:`imx6ul_pinctrl_probe`函数调用`imx_pinctrl_probe`,后者再调用`imx_pinctrl_probe_dt`,最终通过`imx_pinctrl_parse_groups`函数,从设备树的`fsl,pins`属性中解析出引脚的6个关键配置值。之后,通过`pinctrl_register`函数向Linux内核注册PIN控制器,这个控制器的核心是`pinctrl_desc`结构体,它包含三个关键操作集:`pctlops`负责引脚组管理,`pmxops`处理复用功能设置,`confops`完成电气特性配置。这些操作集对应的函数,就是实际操控硬件寄存器、实现引脚配置的“执行者”,而具体的实现逻辑由半导体厂商在内核源码中完成,开发者无需重复造轮子。
3 设备树中添加pinctrl节点的实战模板
掌握原理后,我们来看如何在实际设备树中为外设添加pinctrl节点,这里以虚拟的`test`设备为例,它需使用GPIO1_IO00引脚,具体步骤如下:
第一步,创建专属的引脚配置节点。在`imx6ull-alientek-emmc.dts`的`iomuxc`节点下的`imx6ul-evk`子节点内,新建`pinctrl_test: testgrp`节点,用于集中存放该设备的所有引脚配置信息。
第二步,添加“fsl,pins”核心属性。这是NXP(Freescale)系列SOC的pinctrl驱动识别引脚配置的关键标识,必须准确添加,属性值为后续的引脚配置数据预留位置。
第三步,填充具体的引脚配置数据。在“fsl,pins”属性中,写入`MX6UL_PAD_GPIO1_IO00__GPIO1_IO00`宏,这个宏已定义好引脚的复用寄存器、电气寄存器偏移及复用模式,再搭配对应的`config`值,就能完整描述GPIO1_IO00引脚的配置需求。
完成这三步,就完成了`test`设备的pinctrl节点配置。后续在实际驱动开发中,只需在设备节点中通过`pinctrl-0`引用这个配置好的引脚组,就能让内核自动完成引脚的初始化,极大简化了驱动开发。
pinctrl子系统解决了引脚的底层配置问题,而要让GPIO真正可用,还需gpio子系统的支持。它负责将配置好的引脚转化为通用的GPIO编号,提供标准化的API供驱动调用,让GPIO驱动开发形成完整闭环。