Linux驱动开发实战(七):pinctrl引脚管理入门结合数据手册分析

发布于:2025-03-22 ⋅ 阅读:(12) ⋅ 点赞:(0)

Linux驱动开发实战(七):pinctrl引脚管理入门结合数据手册



一、什么是 Pinctrl

Pinctrl(引脚控制)子系统主要负责:

  • 引脚复用(Pin Multiplexing/Muxing)
  • 引脚配置(Pin Configuration)
  • 比如设置引脚用作GPIO、UART、I2C等功能,以及设置引脚的上拉下拉、驱动强度等电气特性。

二、为什么要使用 Pinctrl 子系统

2.1 硬件资源共享的需求

现代 SoC 设计面临一个基本挑战:引脚数量有限,但需要支持的功能越来越多。例如,一个只有100个引脚的芯片可能需要支持多种通信协议(UART、I2C、SPI、SDIO 等)、存储接口和各种控制信号。通过引脚复用技术单个物理引脚可以支持多种功能,大大提高了芯片的集成度和灵活性。

2.2 软件管理复杂性

没有 Pinctrl 子系统之前,Linux 内核中的引脚配置存在以下问题:

  1. 代码重复:每个驱动都需要单独配置引脚,导致大量重复代码
  2. 资源冲突不同驱动可能会尝试将同一引脚配置为不同功能
  3. 维护困难:引脚配置分散在各个驱动中,难以统一管理
  4. 板级适配繁琐:每更换一块板子,可能需要修改多个驱动的引脚配置

2.3 Pinctrl 子系统的优势

  1. 集中管理:统一管理所有引脚配置,避免冲突
  2. 解耦合设计:将引脚配置与具体功能驱动分离
  3. 状态管理:支持不同状态下(如正常运行、低功耗)切换不同的引脚配置
  4. 动态配置:支持运行时动态改变引脚功能和配置
  5. 设备树支持:通过设备树描述引脚配置,提高可读性和可维护性

三、基本概念

3.1 引脚复用

现代 SOC 的引脚通常可以复用为多种功能。例如:

  • 一个引脚可能既可以用作 GPIO
  • 也可以用作 UART 的 TX
  • 或者 I2C 的 SCL
    我们需要通过配置相应的寄存器来选择所需的功能。

3.2 引脚配置

除了功能选择,还需要配置引脚的电气特性:

  • 上拉/下拉电阻
  • 驱动强度
  • 压摆率
  • 开漏模式等

四、实例分析

pinctrl写在设备树下面
先通过下面这两段pinctrl 设备树代码来分析一下特性
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

1. 分组管理

从示例中可以看到,pinctrl 将引脚配置分为多个命名组(group):

  • pinctrl_hog_1
  • pinctrl_enet1
  • pinctrl_enet2
  • pinctrl_uart1
  • pinctrl_hog_2
  • pinctrl_spi4
    这种分组方式允许将功能相关的引脚配置放在一起,便于管理和引用。pinctrl是以组来管理的

2. 引脚控制器多样性

示例中展示了两种不同的引脚控制器:

  • &iomuxc:标准的 I/O 复用控制器
  • &iomuxc_snvs:安全非易失性存储区域的 I/O 复用控制器

这反映了现代 SoC 通常有多个引脚控制器,每个控制器负责不同区域或不同功能的引脚。

3. 默认配置与状态管理

&iomuxc {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_hog_1>;
}

&iomuxc_snvs {
    pinctrl-names = "default_snvs";
    pinctrl-0 = <&pinctrl_hog_2>;
}

这里展示了 pinctrl 的状态管理特性:

  • pinctrl-names 定义了状态名称
    pinctrl-names = “default”,“init”,“sleep”;都是状态
  • pinctrl-0 对应第一个状态的配置
  • 系统启动时会应用 “default” 状态的配置

除了 “default” 状态外,pinctrl 子系统还支持其他状态,如 “sleep”(休眠)、“idle”(空闲)等,这些状态可以根据系统运行状态动态切换。但 “default” 状态是最基础的,也是系统初始化时使用的状态。

4. HOG 组特性

“Hog” 组(pinctrl_hog_1 和 pinctrl_hog_2)是一种特殊的引脚组,用于:

  • 直接在控制器级别配置引脚,而不是通过某个特定设备
  • 通常用于配置系统启动时就需要设置的引脚,如复位线、CD 检测等
  • 被系统默认加载,不需要特定驱动来激活

5. 硬件复用能力

注意到 MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 这样的定义,这表明:

物理引脚 UART1_RTS_B 被复用为 GPIO1_IO19
同一个物理引脚可以有多种功能选择

6.配置(看数据手册)

以 i.MX6ULL 的 UART1 为例:

pinctrl_uart1: uart1grp {
    fsl,pins = <
        MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
        MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
    >;
};

这里的配置可以分解为:

引脚复用配置

MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 展开为 5 个值:
在imx6ul-pinfunc.h里面定义的

#define MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX     0x0084 0x0310 0x0000 0 0

这些值的含义是:

  1. 0x0084: MUX寄存器的偏移地址
  2. 0x0310: PAD寄存器的偏移地址
  3. 0x0000: MUX模式值(选择 ALT0 功能)
  4. 0: SELECT_INPUT寄存器偏移(如无则为0)
  5. 0: SELECT_INPUT值

为什么这么定义可以看下面我传的数据手册(重要)

PAD 控制值

0x1b0b1 是 PAD 控制值,用于配置引脚的电气特性:
这是在设备树上配置的

pinctrl_uart1: uart1grp {
    fsl,pins = <
        MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
        MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
    >;
};

0x1b0b1 = 0001 1011 0000 1011 0001

这些位的含义如下(从右到左):

HYS (bit 16):        0    - 禁用磁滞
PUS (bits 14-15):    00   - 100K欧姆下拉 (00=100K_OHM_PD, 01=47K_OHM_PU, 10=100K_OHM_PU, 11=22K_OHM_PU)
PUE (bit 13):        0    - Keeper
PKE (bit 12):        1    - 使能上拉/下拉
ODE (bit 11):        1    - 开漏输出使能
SPEED (bits 6-7):    10   - 中速率 (00=low(50MHz) 01=medium(100MHz) 10=medium(100MHz) 11=max(200MHz))
DSE (bits 3-5):      110  - 驱动能力为R0/6
SRE (bit 0):         1    - 慢转换率

0x1b0b1 是一个完整的PAD配置值,而不是地址。这个值会被写入到PAD控制寄存器中(比如地址0x20E_0310h)下面的数据手册会看到。

从上面的图片示例中可以看到其他不同PAD 配置值:

  • 0x17059:用于 SD 卡和 GPIO 配置
  • 0x1b0b0:用于以太网接口配置
  • 0x1b0b1:用于 UART 接口配置
  • 0x4001b031:用于以太网时钟引脚特殊配置
  • 0x80000000:用于 SNVS 区域的特殊配置
    这些值反映了不同引脚功能对电气特性的不同需求。

数据手册与配置值的对应

在这里插入图片描述
数据手册中显示:

SW_MUX_CTL_PAD_UART1_TX_DATA
Address: 20E_0000h base + 84h offset = 20E_0084h

基地址加偏移地址=寄存器地址
对应设备树中:

iomuxc: iomuxc@20e0000 {    // 基地址: 0x20E0000
    compatible = "fsl,imx6ul-iomuxc";
    reg = <0x20e0000 0x4000>;  // 寄存器范围
};

从数据手册(最下面的大框)可以看到:

MUX_MODE字段(位2-0)设置为000,选择ALT0模式作为UART1_TX
SION位(位4)设置为0,表示由功能决定输入路径
这正好对应了宏定义中的mux_mode = 0,选择UART1_TX功能。
这里正好对应的是上面我讲过的
imx6ul-pinfunc.h里面

#define MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX     0x0084 0x0310 0x0000 0 0

总结

Pinctrl 子系统是现代嵌入式 Linux 系统的关键组件,通过提供统一、灵活的引脚管理机制,它解决了引脚资源有限与功能需求多样之间的矛盾,是设备驱动开发中不可或缺的基础设施。下一篇我会更深入的讲解Pinctrl 子系统的内容