linux设备树-pinctrl子系统
----------------------------------------------------------------------------------------------------------------------------
内核版本:linux 5.2.8根文件系统: 1.25.0u-boot:2016.05----------------------------------------------------------------------------------------------------------------------------
一、IO概述 1.1 硬件功能分类
ARM based SoC的中总有一个章节叫做GPIO (或者I/O ports)的章节来描述如何配置、使用SoC的引脚。虽然GPIO 的硬件描述中充满了大量的寄存器的描述,但是这些寄存器的功能大概分成下面三个类别:
(1) 有些硬件逻辑是和IO port本身的功能设定相关的,我们称这个HW block为pin 。软件通过设定pin 这个硬件单元的寄存器可以实现:
(2)如果一组GPIO被配置成SPI,那么这些pin脚被连接到了SPI ,如果配置成GPIO,那么控制这些引脚的就是GPIO 。通过访问GPIO 的寄存器,软件可以:
(3)如果一组GPIO有中断控制器的功能,虽然控制寄存器在中的I/O ports章节描述,但是实际上这些GPIO已经被组织成了一个 的硬件block,它更像是一个GPIO类型的中断控制器,通过访问GPIO中断控制寄存器,软件可以:
1.2 抽象硬件差异
传统的GPIO 是负责上面三大类的控制,而新的linux 中的GPIO 则用三个软件模块来对应上面三类硬件功能:
总体来说,pin 和GPIO 都是数字输入/输出控制的IP核,但其控制的对象不同,前者控制的引脚可用于GPIO功能、I2C功能等;后者只是把引脚配置为输入、输出等简单的功能。两者的关系是先用把引脚配置为GPIO,再用GPIO 把引脚配置为输入或输出。
1.3 外部中断 1.3.1 外部中断资源
一共有24个外部中断,分别对应24个GPIO引脚:
1.3.2 外部中断初始化
以GPF7为例,如果将该引脚配置为上升沿外部中断:
二、子系统
在许多SoC内部都包含有pin ,通过pin 的寄存器,我们可以配置一个或者一组引脚的功能和特性。
各个厂商SoC的pin脚在使用中,都有许多共同的特性,要么配置,要么复用pin脚。所以内核提供了一套代码来管理这些pin,这就是 。主要实现的功能:
2.1 重要概念
涉及到了两个对象:
2.2 设备节点
以arch/arm/boot/dts/-.dtsi为例,描述了 pin 的dts结构,内容如下:
pinctrl_0: pinctrl@56000000 {compatible = "samsung,s3c2440-pinctrl";reg = <0x56000000 0x1000>;wakeup-interrupt-controller {compatible = "samsung,s3c2410-wakeup-eint";interrupts = <0 0 0 3>,<0 0 1 3>,<0 0 2 3>,<0 0 3 3>,<0 0 4 4>,<0 0 5 4>;};/** Pin banks*/gpa: gpa {gpio-controller;#gpio-cells = <2>;};......gpj: gpj {gpio-controller;#gpio-cells = <2>;};/** Pin groups*/uart0_data: uart0-data {samsung,pins = "gph-2", "gph-3";samsung,pin-function = ;};.....};
如上所示:@内部定义了一些自己的属性,比如、reg,此外还定义了大量的子节点,这些子节点我们称之为引脚配置(pin )。
定义pin 的目的是为了让 引用。例如串口设备:
在pin node中定义的pin 可以分为两大类:pin bank和pin group。
2.2.1 bank
所谓的pin bank,个人理解就是一组GPIO端口,这一组GPIO端口同属于一个GPIO控制器。以为例,分为了9 个GPIO控制器:
GPIO控制器
GPIO端口名称
GPIO端口数量
GPIOA
GPA0~GPA24
25
GPIOB
GPB0~GPB10
11
GPIOC
GPC0~GPC15
16
GPIOD
GPD0~GPD15
16
GPIOE
GPE0~GPE15
16
GPIOF
GPF0~GPF7
GPIOG
GPG0~GPG15
16
GPIOH
GPH0~GPH10
11 (这里明明11个,说的总共9个)
GPIOJ
GPJ0~GPJ12
13
所以在arch/arm/boot/dts/-.dtsi文件中就把这9组GPIO端口枚举成pin bank,如下:
/** Pin banks*/
gpa: gpa {gpio-controller;#gpio-cells = <2>;
};gpb: gpb {gpio-controller;#gpio-cells = <2>;
};gpc: gpc {gpio-controller;#gpio-cells = <2>;
};gpd: gpd {gpio-controller;#gpio-cells = <2>;
};gpe: gpe {gpio-controller;#gpio-cells = <2>;
};gpf: gpf {gpio-controller;#gpio-cells = <2>;interrupt-controller;#interrupt-cells = <2>;
};gpg: gpg {gpio-controller;#gpio-cells = <2>;interrupt-controller;#interrupt-cells = <2>;
};gph: gph {gpio-controller;#gpio-cells = <2>;
};gpj: gpj {gpio-controller;#gpio-cells = <2>;
};
View Code
如gpa: gpa 这个child node就是描述GPIOA这个组,也就是gpa bank.。pin bank中支持如下属性:
gpf、gpg本身也充当一个中断控制器,它的 也是-@,gpf的 cell是2,表示引用gpf的一个中断需要2个参数来描述。
GPIO控制器支持两种类型的外部中断:外部GPIO中断和外部唤醒中断。两者之间的区别在于,外部唤醒中断可以用作系统唤醒事件。
更多信息可以参考:////-.txt。
2.2.2 group
以功能为依据,具有相同功能的引脚称为一个pin group,比如:
所以在arch/arm/boot/dts/-.dtsi文件中定义到了大量的pin group,如下:
/** Pin groups*/uart0_data: uart0-data {samsung,pins = "gph-2", "gph-3";samsung,pin-function = ;
};uart1_data: uart1-data {samsung,pins = "gph-4", "gph-5";samsung,pin-function = ;
};uart2_data: uart2-data {samsung,pins = "gph-6", "gph-7";samsung,pin-function = ;
};uart2_fctl: uart2-fctl {samsung,pins = "gph-6", "gph-7";samsung,pin-function = ;
};extuart_clk: extuart-clk {samsung,pins = "gph-8";samsung,pin-function = ;
};i2c0_bus: i2c0-bus {samsung,pins = "gpe-14", "gpe-15";samsung,pin-function = ;
};spi0_bus: spi0-bus {samsung,pins = "gpe-11", "gpe-12", "gpe-13";samsung,pin-function = ;
};sd0_clk: sd0-clk {samsung,pins = "gpe-5";samsung,pin-function = ;
};sd0_cmd: sd0-cmd {samsung,pins = "gpe-6";samsung,pin-function = ;
};sd0_bus1: sd0-bus1 {samsung,pins = "gpe-7";samsung,pin-function = ;
};sd0_bus4: sd0-bus4 {samsung,pins = "gpe-8", "gpe-9", "gpe-10";samsung,pin-function = ;
};/*添加Nand Flash所用的管脚*/
nand_pinctrl: nand_pinctrl {samsung,pins = "gpa-17", "gpa-18", "gpa-19","gpa-20", "gpa-22";samsung,pin-function = <1>;
};
View Code
其中:
还可以选择性地指定应用于“,pins”属性中列出的所有引脚上的一个或多个引脚配置。支持以下引脚配置属性:
更多信息可以参考:////-.txt。
2.2. 引用
当一个 想引用某个"引脚配置节点"应该如何进行描述呢?一个典型的 tree中的外设节点定义如下:
device-node-name { .......pinctrl-names = "sleep", "active"; pinctrl-0 = ; pinctrl-1 = ;
};
其中-names属性和-%d属性格外重要,因为它们是内核设定的属性,我们下面来介绍;
(1) -names定义了一个state列表,那么什么是state呢?
对于一个 ,比如它是一个串口设备,它有多种状态,比如、sleep等。那么对应的引脚也有这些状态,比如:
state有两种标识:一种就是-names定义的字符串列表,另外一种就是ID。ID从0开始,依次加一。以上面例子为例:
内核自己定义了"","init","idel","sleep"状态;也可以是其它自己定义的状态, 比如串口的""状态(使用流量控制)。
(2)-x的定义。-x是一个句柄()列表,每个句柄指向一个"引脚配置节点",有时候,一个state可以用到多组pin,比如A1、A2两组pin,A1组pin复用为F1功能,A2组pin复用为F2功能。
我们以串口0设备节点定义为例:
&uart_0 {status = "okay";pinctrl-names = "default";pinctrl-0 = <&uart0_data>;
};
其中:
2.3 框架
下图描述了 的模块图:
中间层是pin core,用于管理系统中的pin 。pin core汇总了pin 的通用操作:
基本上这个软件框架图和GPIO 是一样的,其软件抽象的思想也是一样的,当然其内部具体的实现不一样。
2.4 目录结构 2.4.1 源文件
linux内核将驱动相关的代码放在/目录下,这下面的文件还是比较多的,我们大概了解一下即可。
其中:
在pin 文档中 ,我们以的pin 为例,描述了一个具体的low level的,这个涉及的文件包括-.c,-.h和-.c。
2.4.2 头文件
会向系统中的其它提供接口以便进行该的引脚配置和引脚复用功能的设定,下面这些头文件就定义了 的外部接口以及相关的数据结构:
.h:这是for linux内核的驱动模型模块( model)使用的接口。 中包括了一个 *pins的成员,这个成员描述了该设备的引脚的初始状态信息,在probe之前, model中的core 在调用的probe函数之前会先设定pin state;.h:模块的接口;
提供给底层pin 的头文件列表如下:
2.5 数据结构
学习pin ,首先要了解 涉及到的数据结构,知道每个数据结构以及成员的含义之后,再去看源码就容易了。
我们从pin 和 视角去介绍 涉及到的数据结构,其中:
三、pin 3.
pin core使用 抽象一个pin ,其定义在//core.h文件,如下:
/*** struct pinctrl_dev - pin control class device* @node: node to include this pin controller in the global pin controller list* @desc: the pin controller descriptor supplied when initializing this pin* controller* @pin_desc_tree: each pin descriptor for this pin controller is stored in* this radix tree* @pin_group_tree: optionally each pin group can be stored in this radix tree* @num_groups: optionally number of groups can be kept here* @pin_function_tree: optionally each function can be stored in this radix tree* @num_functions: optionally number of functions can be kept here* @gpio_ranges: a list of GPIO ranges that is handled by this pin controller,* ranges are added to this list at runtime* @dev: the device entry for this pin controller* @owner: module providing the pin controller, used for refcounting* @driver_data: driver data for drivers registering to the pin controller* subsystem* @p: result of pinctrl_get() for this device* @hog_default: default state for pins hogged by this device* @hog_sleep: sleep state for pins hogged by this device* @mutex: mutex taken on each pin controller specific action* @device_root: debugfs root for this device*/
struct pinctrl_dev {struct list_head node;struct pinctrl_desc *desc;struct radix_tree_root pin_desc_tree;
#ifdef CONFIG_GENERIC_PINCTRL_GROUPSstruct radix_tree_root pin_group_tree;unsigned int num_groups;
#endif
#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONSstruct radix_tree_root pin_function_tree;unsigned int num_functions;
#endifstruct list_head gpio_ranges;struct device *dev;struct module *owner;void *driver_data;struct pinctrl *p;struct pinctrl_state *hog_default;struct pinctrl_state *hog_sleep;struct mutex mutex;
#ifdef CONFIG_DEBUG_FSstruct dentry *device_root;
#endif
};
其中部分参数含义如下: