本系列均为正点原子 Linux 驱动的学习笔记, 以便加深笔者记忆。如读者想进一步学习,可以到正点原子官网中下载资料进行学习。
修改设备树,添加相应的节点,节点里面重点是设置 reg 属性,reg 属性包括了 GPIO 相关寄存器。
获 取 reg 属 性 中 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 和 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 这两个寄存器地址,并且初始化这两个寄存器,这两个寄存器用于设置 GPIO1_IO03 这个 PIN 的复用功能、上下拉、速度等。也就是设置引脚复用和电气特性的配置信息。即本节所说的 pinctrl 子系统的功能。
如果将 GPIO1_IO03 这个 PIN 复用为了 GPIO 功能,因此需要设置 GPIO1_IO03 这个 GPIO 相关的寄存器,也就是 GPIO1_DR 和 GPIO1_GDIR 这两个寄存器。下节将介绍的 gpio 子系统的功能。
总结起来就是第二步完成 GPIO_IO03 这个引脚的复用功能以及上下拉,速度等配置,第三步配置 GPIO 为输入 / 输出。
因此 Linux 内核针对 PIN 的配置推出了 pinctrl 子系统,针对 GPIO 的配置推出了 gpio 子系统。
大多数 SOC 的 pin 都是支持复用的,比如 I.MX6ULL 的 GPIO1_IO03 既可以作为普通的 GPIO 使用,也可以作为 I2C1 的 SDA 等等。此外我们还需要配置 pin 的电气特性,比如上 / 下拉、速度、驱动能力等等。传统的配置 pin 的方式就是直接操作相应的寄存器,但是这种配置方式比较繁琐、而且容易出问题 (比如 pin 功能冲突)。pinctrl 子系统就是为了解决这个问题而引入的,pinctrl 子系统主要工作内容如下:
获取设备树中 pin 信息。
根据获取到的 pin 信息来设置 pin 的复用功能
根据获取到的 pin 信息来设置 pin 的电气特性,比如上 / 下拉、速度、驱动能力等。
对于我们驱动开发来讲,只需要在设备树里面设置好某个 pin 的相关属性即可,其他的初始化工作均由 pinctrl 子系统来完成,pinctrl 子系统源码目录为 drivers/pinctrl
。
要使用 pinctrl 子系统,需要在设备树里面设置 PIN 的详细配置,pinctrl 子系统需要根据提供的配置信息来配置 PIN 的功能,一般会在设备树里面创建一个节点来描述 PIN 的配置信息。打开 imx6ull.dtsi 文件,如下
iomuxc: iomuxc@020e0000 {
compatible = "fsl, imx6ull-iomuxc";
reg = <0x020e0000 0x4000>;
};
iomuxc 节点就是 I.MX6ULL 的 IOMUXC 外设对应的节点,看起来内容很少,没有什么 PIN 相关的配置,在 imx6ull-alientek-emmc.dts 文件中
&iomuxc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog_1>;
imx6ul-evk {
pinctrl_hog_1: hoggrp-1 {
fsl,pins = <
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059
MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059
MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059
MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID 0x13058
>;
};
......
pinctrl_flexcan1: flexcan1grp{
fsl,pins = <
MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX 0x1b020
MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX 0x1b020
>;
};
......
pinctrl_wdog: wdoggrp {
fsl,pins = <
MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY 0x30b0
>;
};
};
};
不同的外设使用的 PIN 不同、其配置也不同,因此一个萝卜一个坑,将某个外设所使用的所有 PIN 都组织在一个子节点里面。示例代码 45.1.2.2 中 pinctrl_hog_1 子节点就是和热插拔有关的 PIN 集合,比如 USB OTG 的 ID 引脚。pinctrl_flexcan1 子节点是 flexcan1 这个外设所使用的 PIN,pinctrl_wdog 子节点是 wdog 外设所使用的 PIN。如果需要在 iomuxc 中添加我们自定义外设的 PIN,那么需要新建一个子节点,然后将这个自定义外设的所有 PIN 配置信息都放到这个子节点中。
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059
这两个值代表了具体的配置参数
#define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x0090 0x031C 0x0000 0x5 0x0
该宏的具体含义如下
位 | 含义 |
---|---|
mux_reg | mux_reg 寄存器偏移地址 |
conf_reg | conf_reg 寄存器偏移地址 |
input_reg | input_reg 寄存器偏移地址 有些外设有 input_reg 寄存器,有 input_reg 寄存器的外设需要配置 input_reg 寄存器。没有的话就不需要设置, |
mux_mode | mux_reg 寄存器值 |
input_val | input_reg 寄存器值 |
0x17059 就是 conf_reg 寄存器值!此值由用户自行设置,通过此值来设置个 IO 的上/下拉、驱动能力和速度等。在这里就相当于设置寄存器 IOMUXC_SW_PAD_CTL_PAD_UART1_RTS_B 的值为 0x17059。
关于 I.MX 系 列 SOC 的 pinctrl 设备树绑定信息可以参考文档 Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt
。
同一个外设的 PIN 都放到一个节点里面,打开 imx6ull-alientek-emmc.dts,在 iomuxc 节点中的 imx6ul-evk 子节点下添加 pinctrl_test 节点,注意!节点前缀一定要为 pinctrl_ 。添加完成以后如下所示:
pinctrl_test: testgrp {
/* 具体的 PIN 信息 */
};
设备树是通过属性来保存信息的,因此我们需要添加一个属性,属性名字一定要为“fsl,pins”,因为对于 I.MX 系列 SOC 而言,pinctrl 驱动程序是通过读取“fsl,pins”属性值来获取 PIN 的配置信息,完成以后如下所示:
pinctrl_test: testgrp {
fsl,pins <
/* 设备所使用的 PIN 配置信息 */
>
};
最后在 fsl,pins 属性中添加具体的 PIN 配置信息,完成以后如下所示:
pinctrl_test: testgrp {
fsl,pins <
MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 config /*config 是具体设置值*/
>
};
至此,我们已经在 imx6ull-alientek-emmc.dts 文件中添加好了 test 设备所使用的 PIN 配置信息。