一、概述
在使用 pinctrl
和 gpio
子系统之前,开发gpio驱动,需要在驱动代码中直接操作所涉及的 GPIO 寄存器(配置IO 复用,配置IO口为输出方,设置IO输出高低电平),驱动开发方式和裸机开发基本没区别。
Linux 内核提供了 pinctrl 和 gpio 子系统用于 GPIO 驱动,简化了GPIO 驱动开发。下面以 点亮一个LED 为例,介绍pinctrl 子系统的使用。
二、 主要工作内容
- 获取设备树中 pin 信息。
- 根据获取到的 pin 信息来设置 pin 的复用功能。
- 根据获取到的 pin 信息来设置 pin 的电气特征,比如 上下拉,速度,驱动能力等。
对于我们使用者来说,只需要在设备树里面设置好某个pin 的相关属性即可,其他的初始化工作均由 pinctrl 子系统来完成。
pinctrl 子系统源码目录为 drivers/pinctrl
三、 设备树PIN的配置信息分析
1. 设备树中的pinctrl 子节点
pinctrl_led:ledgrp{
fsl,pins = <
MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x10B0
>
};
MX6UL_PAD_GPIO1_IO03__GPIO1_IO03
的定义在 imx6ul-pinfunc.h ,定义如下:
#define MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x0068 0x02F4 0x0000 0x5 0x0
2. pinctrl 配置数据与寄存器对应关系
各个寄存器和值的解析
- mux_reg 寄存器偏移地址 : 值为
0x0068
。 从 iomuxc 节点的 reg 属性可以知道,iomuxc 外设寄存器的起始地址为 0x020E0000 。因此,0x020E0000 + 0x0068 = 0x020E0068, 刚好是寄存器IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03
的地址。 - conf_reg 寄存器偏移地址:值为
0x02F4
。同理,0x020E0000 + 0x02F4 = 0x020E02F4, 刚好是寄存器IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03
的地址。 - input_reg 寄存器偏移地址:值为 0x0000 。有些外设没有 input_reg 寄存器,有 input_reg 寄存器的外设需要配置 input_reg 寄存器,没有的话,就不需要。当前IO 作为 GPIO1_IO03 时没有 input_reg 寄存器,因此这里 input_reg 是无效的。
- mux_reg 寄存器的值 : 值为 0x05 。这里相当于设置
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03
寄存器为 0x05 ,也就是设置ALT5 — Select mux mode: ALT5 mux port: GPIO1_IO03 of instance: gpio1
。 - input_reg 寄存器值: 值为0x00 。前面说到这里不需要 设置 input_reg 寄存器,所以这个值也是无效的。
- conf_reg 寄存器的值: 值为0x10B0 。这里相当于给
IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03
寄存器赋值 0x10B0 。这里设置 一个 IO 的上/下 拉,驱动能力 和速度等。
四、如何在设备树配置 pin 信息
关于 I.MX 系列 SOC 的pinctrl 设备树绑定信息可以参考文档 fsl,imx-pinctrl.txt 。
1. 创建对应的节点
同一个外设的 PIN 都放到一个节点里面,打开 imx6ull-alientek-emmc.dts ,在 iomuxc 节点中的 “imx6ul-evk “ 子节点下添加 “pinctrl_led” 节点。
pinctrl_led:ledgrp{
};
2. 添加 “fsl,pins” 属性
设备树是通过属性来保存信息的,因此我们需要添加一个属性,属性名字是一定要为 “fsl,pins
” , 因为 对于 I.MX 系列 SOC 而已,pinctrl 驱动 程序 是通过读取 “ fsl,pins
” 属性值来获取 PIN 的配置信息。
pinctrl_led:ledgrp{
fsl,pins = <
MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x10B0
>
};
3. fsl,pins 属性值的确定
芯片厂家为 每个pin 的每一种复用都定义好了对应的宏,我们根据我们的复用要求,选择对应的宏就行。这个宏定义在 文件 imx6ul-pinfunc.h 文件中。