Linux 驱动学习笔记 - pinctrl 子系统 (七)

Linux 驱动学习笔记 - pinctrl 子系统 (七)

本系列均为正点原子 Linux 驱动的学习笔记, 以便加深笔者记忆。如读者想进一步学习,可以到正点原子官网中下载资料进行学习。

LED 初始化流程

  • 修改设备树,添加相应的节点,节点里面重点是设置 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 子系统。

pinctrl 子系统

大多数 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 的详细配置,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。

设备树中添加 pinctrl 节点

关于 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 属性

设备树是通过属性来保存信息的,因此我们需要添加一个属性,属性名字一定要为“fsl,pins”,因为对于 I.MX 系列 SOC 而言,pinctrl 驱动程序是通过读取“fsl,pins”属性值来获取 PIN 的配置信息,完成以后如下所示:

pinctrl_test: testgrp {
    fsl,pins <
    /* 设备所使用的 PIN 配置信息 */
    >
};

在 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 配置信息。

你可能感兴趣的:(Linux)