pinctrl和gpio子系统
1. 关于pinctrl
1.1 作用
- pin的枚举和命名
- pin的复用
- pin的配置(上下拉、驱动能力、是否开漏等)
1.2 pinctrl的核心数据结构
- 使用struct pinctrl_desc描述一个pin ctroller
1 |
|
使用struct pinctrl_pin_desc描述单个引脚
在pinctrl_pin_desc中以数组形式存在,与npins成员构成索引,方便驱动和具体的pin对应
1 |
|
使用group_desc描述一组特定引脚,如IIC、UART等
1
2
3
4
5
6struct group_desc{
const char *name;
int *pins; //应该group中pins对应的npins成员的下标数组
int num_pins; //group中pin的个数
void *data;
};pinctrl_ops函数族 主要从设备树中获取group节点信息并map
1 |
|
- pinmux_ops函数族 引脚复用相关
1 |
|
- pinconf_ops函数族 引脚配置相关
1 |
|
1.3 pin state
设备在某一状态下,其pin(group)、function(功能)、configuratio(配置)是唯一确定的,把这三个元素组成的状态抽象为pin state.核心数据结构为pictrl_map。由pinctrl_ops函数族中的dt_node_to_map函数完成。
1 |
|
2 pinctrl和GPIO的设备树和基本API
(源码位置 drivers/pinctrl)
2.1 pin配置信息详解
一般在设备树中创建一个节点描述pin信息,以imx6u为例:
imx6ull.dtsi中有iomuxc节点描述外设pin信息
1 |
|
reg属性中的0x020e0000为iomuxc外设节点的首地址。
在.dts文件中以&iomuxc引用方式向.dtsi文件中iomuxc节点追加信息
1 |
|
在内核源码中全局搜索iomuxc节点的compatible属性即可得到pinctrl驱动文件源码。
以pinctrl_hog_1节点为例,MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059
- MX6UL_PAD_UART1_RTS_B__GPIO1_IO19是一个宏定义,定义在arch/arm/boot/dts/imx6ul-pinfunc.h。定义如下:
#define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x0090 0x031C 0x0000 0x5 0x0
- 0x0090(mux_reg寄存器偏移地址): 为IOMUXC_SW_MUX_CTL_PAD_UART1_RTS_B寄存器地址基于IOMUXC外设首地址的偏移量(复用配置)
- 0x031C(conf_reg寄存器偏移地址): 为IOMUXC_SW_PAD_CTL_PAD_UART1_RTS_B寄存器地址基于IOMUXC外设首地址的偏移量(电器属性配置)
- 0x0000(input_reg寄存器偏移地址): 有些外设有input_reg寄存器,此值为input_reg寄存器偏移量
- 0x5(mux_reg寄存器值): 设置IOMUXC_SW_MUX_CTL_PAD_UART1_RTS_B寄存器值为0x5
- 0x0(input_reg寄存器值): 设置input_reg寄存器值,此处无效
- 0x17059 为confg_reg寄存器的值,根据具体需求配置
注:.dtsi文件引用imx6ull-pinfunc.h文件,而imx6ull-pinfunc.h文件再引用imx6ull-pinfunc.h
2.2设备树中添加pinctrl节点
例:虚拟一个名为“test”的设备,设备使用GPIO1_IO00这个PIN的GPIO功能。
具体步骤如下:
- 在dts文件中iomuxc节点下的imx6ul-evk节点下添加”pinctrl_test”节点,前缀必须为”pinctrl_”
1
2
3pinctrl_test:testgrp{
待添加的具体的PIN信息
}; - 添加”fsl,pins”属性,pinctrl驱动通过读取设备树中”fsl,pins”属性的内容来获取PIN的配置信息,不同芯片属性可能会有差别
1
2
3
4
5pinctrl_test:testgrp{
fsl,pins<
待添加的PIN的配置信息
>;
}; - 添加pin的配置信息,即复用引脚和config值
1
2
3
4
5pinctrl_test:testgrp{
fsl,pins<
MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 config
>;
};
gpio子系统的作用:初始化GPIO并提供相应的API函数
- 设备树中的GPIO信息
- 添加pinctrl名字
pinctrl-name = "defaul";
- 在设备节点中添加设备所需的PIN的pinctrl信息所在子节点信息
pinctrl-n = <&pinctrl_xxx>;
驱动根据pinctrl信息设置pin的复用功能和电气属性 - 在设备节点中添加描述GPIO属性的语句
xxx_gpios = <&GPIO组 pin号 有效电平>
比如cd_gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
- gpio子系统函数
- API函数 <linux/gpio.h>
int gpio_request(unsigned gpio, const char *label)
gpio:要申请的gpio标号,通过of_get_named_gpio函数获取此标号
label:给此gpio设置一个名字
返回值:0-申请成功 其他值-申请失败- 释放GPIO管脚
void gpio_free(unsigned gpio)
gpio:要释放的gpio标号 - 设置gpio为输入模式
int gpio_direction_input(unsigned gpio)
gpio:要设置的gpio标号
返回值:0-设置成功 其他值-失败 - 设置gpio为输出模式
int gpio_direction_output(unsigned gpio)
gpio:要设置的gpio标号
返回值:0-设置成功 其他值-失败 - 获取gpio的值(宏函数)
int gpio_get_value(unsigned gpio)
gpio:要获取的gpio标号
返回值:gpio值 - 设置gpio的值(宏函数)
void gpio_set_value(unsigned gpio, int value)
gpio:要设置的gpio标号
value:要设置的gpio值
- 释放GPIO管脚
- gpio相关的of函数 <linux/of_gpio.h>
- 获取某属性中定义gpio信息的个数
int of_gpio_named_count(struct device_node* np, const char *propname)
np:设备节点
propname:要统计gpio个数的属性名
返回值:gpio数目 负值表示失败 - 获取”gpios”属性的gpio信息的个数
int of_gpio_count(struct device_node* np)
np:设备节点
返回值:gpio数目 负值表示失败 - 获取GPIO标号
int of_get_named_gpio(struct device_node* np, const char *propname, int index)
np:设备节点
propname:要获取的GPIO所属属性名
index:GPIO索引,一个属性中可能含有多个GPIO信息
返回值:gpio标号 负值表示失败
- 获取某属性中定义gpio信息的个数