pinctrl 子系统的作用
pinctrl 子系统即引脚配置子系统,它从设备树获取引脚配置信息,并完成对引脚复用功能和电气特性的配置,如下是一个MPU框图的一部分,其中包括IIC、UART、GPIO等外设,这些外设共用外部的引脚,而引脚在同一时刻只能有一种功能,所以此时需要配置引脚复用控制器,决定引脚给那个外设使用,此外在不同的应用场合还对引脚的电气特性有不同的要求,此时还需要配置引脚的电气特性控制器(在STM32MP157中将GPIO控制器、引脚复用功能配置、引脚电气特性配置打包为了一个外设模块,叫做GPIO外设)
pinctrl 子系统的设备树
pinctrl 子系统的设备树没有统一的标准,各大厂家提供的 pinctrl 驱动与其对应的设备树都不一样,但是有些相似,如下是STM32MP157的 pinctrl 设备树节点
在stm32mp157 中有两个 pinctrl 节点,分别是 pinctrl: pin-controller@50002000 和 pinctrl_z: pin-controller-z@54
004000 , pinctrl: pin-controller@50002000 节点描述的是 GPIOA~K 的引脚复用功能和电气特性, pinctrl_z: pin-co
ntroller-z@54004000 的是 GPIOZ 的引脚复用功能和电气特性,两个节点基本相似,下面是 pinctrl: pin-controller@50
002000 展开后的内容:
pinctrl: pin-controller@50002000 {
#address-cells = <1>; //表示 pinctrl 子节点中 reg 属性的地址为长度为32位
#size-cells = <1>; //表示 pinctrl 子节点中 reg 属性的地址范围为长度为32位
compatible = "st,stm32mp157-pinctrl"; //驱动匹配名称
ranges = <0 0x50002000 0xa400>; //地址范围转换,GPIOA~GPIOK 这 11 组 GPIO 的寄存器都在一起,其起始地址为 0X50002000,终止地址为0X5000C3FF,其中子节点的地址0x00000000对应父节点的地址0x50002000
interrupt-parent = <&exti>; //表示父中断控制器为exti
st,syscfg = <&exti 0x60 0xff>;
hwlocks = <&hsem 0 1>;
pins-are-numbered;
gpioa: gpio@50002000 {
gpio-controller; //表示此节点是一个GPIO控制器
#gpio-cells = <2>; //表示引用此GPIO节点时要传递2个参数
interrupt-controller; //表示此节点是一个中断控制器
#interrupt-cells = <2>; //表示使用此中断控制器时需要传递两个参数
reg = <0x0 0x400>; //GPIOA 控制器的寄存器基地址偏移为 0X400
clocks = <&rcc GPIOA>; //clocks 属性指定这个 GPIOA 控制器的时钟。
st,bank-name = "GPIOA";
status = "disabled";
};
......
gpiok: gpio@5000c000 {
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0xa000 0x400>;
clocks = <&rcc GPIOK>;
st,bank-name = "GPIOK";
status = "disabled";
};
//引脚复用功能配置节点
//一组配置节点节点可以由多个 pins 组成
m_can1_pins_a: m-can1-0 {
pins1 {
//一个 pins 可以描述多个引脚,但是只能使用相同的电气特性
pinmux = <STM32_PINMUX('H', 13, AF9)>; //配置引脚互用功能,将GPIOH13的复用功能配置为第9种模式,参考 “STM32MP157A&D 数据手册”
//引脚电器特性:
// bias-disable bootlean 禁止使用內部偏置电压
// bias-pull-down bootlean 内部下拉
// bias-pull-up bootlean 内部上拉
// drive-push-pull bootlean 推挽输出
// drive-open-drain bootlean 开漏输出
// output-low bootlean 输出低电平
// output-high bootlean 输出高电平
// slew-rate enum 引脚的速度,可设置: 0~3, 0 最慢, 3 最高
slew-rate = <1>;
drive-push-pull;
bias-disable;
};
pins2 {
pinmux = <STM32_PINMUX('I', 9, AF9)>; /* CAN1_RX */
bias-disable;
};
};
m_can1_sleep_pins_a: m_can1-sleep-0 {
pins {
pinmux = <STM32_PINMUX('H', 13, ANALOG)>, /* CAN1_TX */
<STM32_PINMUX('I', 9, ANALOG)>; /* CAN1_RX */
};
};
......
};
使用 pinctrl 子系统
- 添加引脚复用功能配置节点
在根节点外通过 &pinctrl 引用 pinctrl: pin-controller@50002000 节点,或通过 pinctrl_z 引用 pinctrl_z: pin-controller-z@54004000 节点,然后在内部添加或修改相应的引脚配置节点,如下是在 pinctrl: pin-controller@50002000 添加一个串口引脚复用的配置节点:
&pinctrl {
//添加一个名字为 uart4_pins 的节点来描述 uart4 的引脚复用信息
uart4_pins_a: uart4-0 {
pins1 {
pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
bias-disable;
drive-push-pull;
slew-rate = <0>;
};
pins2 {
pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
bias-disable;
};
};
uart4_idle_pins_a: uart4-idle-0 {
pins1 {
pinmux = <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
};
pins2 {
pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
bias-disable;
};
};
uart4_sleep_pins_a: uart4-sleep-0 {
pins {
pinmux = <STM32_PINMUX('G', 11, ANALOG)>, /* UART4_TX */
<STM32_PINMUX('B', 2, ANALOG)>; /* UART4_RX */
};
};
}
- 在设备节点中引用相应的引脚复用功能配置节点
在描述设备的节点中使用 pinctrl-n(n从0开始) 引用相应的引脚复用功能配置节点,并通过 pinctrl-names 设置相应 pinctrl-n 的状态名称,如下是在串口中引用引脚复用功能配置节点的示例:
&uart4 {
//分别指定 pinctrl-0~2 的状态为 "default", "sleep", "idle",设备驱动匹配过程中会自动default对应的pinctrl配置引脚
pinctrl-names = "default", "sleep", "idle";
pinctrl-0 = <&uart4_pins_a>;
pinctrl-1 = <&uart4_sleep_pins_a>;
pinctrl-2 = <&uart4_idle_pins_a>;
/delete-property/dmas;
/delete-property/dma-names;
status = "okay";
};
pinctrl 子系统与总线设备驱动框架的关系
在总线设备驱动框架中,调用驱动的 probe 函数之前会将设备与其引用的引脚配置节点进行绑定,并初始化 "default"或 “init” 状态的引脚
pinctrl 子系统与 gpio 子系统关系
一般 pinctrl 子系统默认将未配置复用功能的引脚作为 GPIO ,此时可以通过 GPIO 子系统对其进行控制