1、概述
pinctrl子系统和GPIO子系统是linux驱动分离与分层的产物。
对于大多数的 32 位 SOC 而言,引脚的设置基本都是设置某个 PIN 的复用功能、速度、上下拉等,然后再设置 PIN 所对应的 GPIO这两方面,因此 Linux 内核针对 PIN 的配置推出了 pinctrl 子系统,对于 GPIO的配置推出了 gpio 子系统。
pinctrl子系统分融主要工作内容如下:
1)、获取设备树树中pin的信息。
2)、根据获取到的pin信息,来设置pin的复用。
3)、根据获取到的pin信息,来设置pin的电气属性,eg:上/下拉,速度,驱动能力等
其实:
需要我们做的就是在设备树中设置好某个pin的相关属性即可。其他的初始化工作都是由pin子系统来完成。
2、pin配置信息详解:
pinctrl_led: ledgrp{
fsl, pins = <MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x10B0 >;
};
其中:
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19其本质是个宏,他表示将UART1_RTS_B复用为GPIO1_IO19,通过查询内核文件,我们可以知道,这个宏的内容是:
#define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x0090 0x031C 0x0000 0x5 0x0
<mux_reg conf_reg input_reg mux_mode input_val>
1)、mux_reg 代表mux寄存器(复用寄存器)的偏移地址—》设备树下对应的设备节点的reg属性代表外示该设备的外设寄存器的起始地址。
2)、conf_reg 代表conf寄存器的偏移地址
3)、input_reg 代表input寄存器的偏移地址(有些外设没有)
4)、mux_reg 代表mux寄存器的值
5)、input_reg 代表input寄存器的值。
这个
pinctrl_led: ledgrp{
fsl, pins = <MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x10B0 >;
};
中的0x10B0就表示conf_reg寄存器的值,他用来配置一个pin的电气属性。通过此值,来设置一个IO的上/下拉,驱动能力和速度等……
3、驱动程序分析
同样,根据设备树下的compatible属性值和内核中对应驱动程序的匹配表,可以找到设备树中的设备对应得驱动程序。
在内核中,用platform_driver来描述一个结构体。当设备和驱动进行匹配以后,里面得probe函数就会执行。在probe函数中,完成:
1)、从设备树中,获取对应设备信息,其实就是电气属性和复用信息(上述6组值)。
2)、向内核注册一个pin控制器。在内核中,每个pin控制器都抽象成结构体pinctrl_desc
。注册控制器,其实就是注册这个结构体。
在结构体里面,有三个成员函数:这三个成员函数对应三个结构体,每个结构体里面都包含了很多操作函数,通过这些操作函数,我们可以完成对一个pin的配置。
扩展:
pinctrl_desc 结构体需要由用户提供,结构体里面的成员变量也是用户提供的。但
是这个用户并不是我们这些使用芯片的程序员,而是半导体厂商,半导体厂商发布的 Linux 内核源码中已经把这些工作做完了