Linux pinctrl子系统学习(二)
3 Pinctrl子系统与consumer关系
- 从"pinctrl子系统关系图"中得知,linux kernel中的各种consumer调用了pinctrl子系统的功能。linux kernel中的统一设备驱动模型提供了driver 和device的绑定机制,一旦匹配就会调用driver 的probe函数。
- 而在调用probe函数时,consumer就会调用pinctrl子系统里的回调函数,进行pin的申请。consumer的probe函数可以通过devm_pinctrl_get获得pinctrl的句柄,再自行调用pinctrl_select_state设置pin state。
3.1 设备树中的pin state
在device tree source 文件中可以在驱动节点中定义该驱动需要用到的pin配置。
device-node-name{
//定义该device自己的属性
pinctrl-names= "sleep","default";
pinctrl-0 = &xxx_state_sleep;
pinctrl-1 = &xxx_state_default;
}
-
pinctrl-0 pinctrl-1 …表示了该设备的一个个状态,这里我们定义了两个pinctrl-0 pinctrl-1,数字0、1就是pinctrl-names中对应的字符串数组的index。其中pinctrl-0就是“sleep”状态,pinctrl-1就是“default”状态。而xxx_state_sleep,xxx_state_default,xxx_state_idel就是驱动具体的pin配置项了,需要在pinctrl设备节点处定义:
pinctrl@e01b0000{ xxx_state_ default:xxx_ default { pins = "PC10", "PC11", "PC12", "PC13", "PC14", "PC15"; function = "spi0"; }; };
-
Consumer在pinctrl子系统加载时,会调用pinctrl_dt_to_map函数将dts文件中有关pinctrl的配置项解析出来,并根据dts各驱动节点对pinctrl的引用关系,将和自己有关的pinctrl子节点挂到自己驱动的device tree节点上,Consumer就可以获得自己的pinctrl state配置了。
3.2 pinctrl关键词表
3.2.1 pin命名表
pin的命名遵循芯片datasheet上的命名。
在dts中使用关键词“pins”(不同厂商不同)后跟名字数组来定义需要使用哪些pin,
如:
spi0_0: spi0 {
pins = "PC10", "PC11", "PC12", "PC13", "PC14", "PC15";
function = "spi0";
}
3.2.2 MUX pin-function
相同的pin,可以通过设置Mux Function的方式改变IC内部连通性,使得相同的pin用作不同的功能,例如:
gpio0_0: gpio0 {
pins = "PE0", "PE1", "PE2", "PE3";
function = "gpio";
}
spi2_0: spi2 {
pins = "PE0", "PE1", "PE2", "PE3";
function = "spi2";
};
3.2.3 Mux Group命名表
Mux Group的意义在于,将一些具有相同功能的pin作为一个集合group管理起来,方便consumer在需要配置多个管脚时,更加的简洁方便。
在dts中使用关键词“groups”后跟mux Group名字数组来定义需要使用哪些Mux group,如:
sd0 {
groups = "mfp2_8_7";
function = "sd0";
};
3.2.4 MUX Group-function
Mux Group所控制的pin,可以通过设置Mux Function的方式改变IC内部连通性,使得同一组pin用作不同的功能,例如:
jtag {
groups ="mfp2_8_7";
function = "jtag";
};
3.2.5 Pin drive
对于某些pin可以设置pin的驱动能力(即供电能力),可以通过配置pin的等级对pin的驱动能力进行配置。
在dts中使用关键词“xxx,drive”后跟驱动能力等级来pin用哪种驱动能力,如:
i2c0_0: i2c0
{
pins = "PB0", "PB1";
function = "i2c0";
amicro,drive = <xxx_PINCTRL_12_MA>;
amicro,pull = <xxx_PINCTRL_PULL_UP>;
};
3.2.6 Pin Pull Up/Down
在dts中使用关键词“xxx,pull”后跟上下拉数据定义指定的pin组使用哪种上下拉,如:
i2c0_0: i2c0 {
pins = "PB0", "PB1";
function = "i2c0";
amicro,drive = <xxx_PINCTRL_12_MA>;
amicro,pull = <xxx_PINCTRL_PULL_UP>;
};
表示将i2c0这两个pin上拉。
#define xxx_PINCTRL_NO_PULL 0
#define xxx_PINCTRL_PULL_UP 1
#define xxx_PINCTRL_PULL_DOWN 2
3.3 v3s的pin信息表
通过分析pinctrl-sunxi-v3s.c可以看到,v3s的所有pin信息被保存在了一个类型为自定义结构体xxx_pinctrl_desc的数组sunxi_v3s_pinctrl_data中。
static struct sunxi_pinctrl_desc sunxi_v3s_pinctrl_data = {
.pins = sunxi_v3s_pins, /*单个pin的信息表*/
.npins = ARRAY_SIZE(sunxi_v3s_pins), /*pin的总数*/
.banks = sunxi_v3s_banks, /*banks的分组信息*/
.nbanks = ARRAY_SIZE(sunxi_v3s_banks), /*banks分组数量*/
.nirqs = 16, /*外部中断线数量*/
};
单个pin的信息被集合到了一个类型为自定义结构体sunxi_desc_pin的sunxi_v3s_pins数组中去,分析结构体成员可以看看到底保存了什么内容。
struct sunxi_desc_pin {
struct pinctrl_pin_desc pin; /*pinctrl通用的结构体,保存pin的编号,名字,以及pinctrl设备私有数据,内核可以识别*/
struct sunxi_desc_function *functions; /*am780自定义结构体,与功能有关*/
};
struct sunxi_desc_function {
const char *name; /*功能名字*/
u8 muxval; /*datasheet上复用功能编号*/
};
可以看到,v3s的pin信息表所保存的数据包括
1、 pin的编号,如PA0的编号为0,PB0编号为16
2、 pin的名字,如“PA0”,“PE14”
3、 复用功能映射编号,从datasheet中获取,如PA0:gpio为0,adc1为2,spi0为3
这些信息的作用是与各自平台的pinctrl子系统的pinconf和pinmux这些底层回调函数有关,最终的目的是通过这些信息来操作相关寄存器(最底层操作)。