pinctrl 架构
pinctrl 框架分为两个部分,分别是引脚复用控制器 pinctrl_dev 和使用引脚的 pinctrl client。
pinctrl_dev :提供服务,可以用它来复用引脚、配置引脚
pinctrl client :使用服务,即使用 Pinctrl 系统的设备
struct pinctrl_dev 对象
pinctrl_dev 表示一个引脚复用控制器,核心成员如下:
//描述 pinctrl_dev
struct pinctrl_desc *desc;
//指向父设备对象
struct device *dev;
//一个 pinctrl_gpio_range 类型的链表,内部可能包含一些列的pinctrl_gpio_range,用来描述 GPIO 子系统中的 GPIO 编号与 pinctrl 控制器中的引脚编号之间的对应关系,是将 GPIO 与 pinctrl 子系统进行关联的重要数据结构
struct list_head gpio_ranges;
struct pinctrl_desc 对象
pinctrl_desc 对象用于描述一个 pinctrl_dev ,其核心成员如下:
//名称
const char *name;
//描述引脚的数组,对于单个引脚的获取通过此参数实现
const struct pinctrl_pin_desc *pins;
//引脚描述数组(pins数组)的长度
unsigned int npins;
//操作函数集合,主要用于获取引脚组的引脚和处理设备树
const struct pinctrl_ops *pctlops;
//操作函数集合,引脚复用功能选择和 GPIO 相关操作
const struct pinmux_ops *pmxops;
//操作函数集合,引脚配置
const struct pinconf_ops *confops;
struct pinctrl_ops 对象
pinctrl_ops 对象主要实现获取引脚组的引脚、设备树映射和取消映射的功能,其核心成员如下:
//获取引脚组数量,即有多少个引脚组
int (*get_groups_count) (struct pinctrl_dev *pctldev);
//获取指定引脚组的名称
const char *(*get_group_name) (struct pinctrl_dev *pctldev, unsigned selector);
//获取指定引脚组的引脚及其个数,引脚通过 pins 数组返回,个数通过num_pins返回,
int (*get_group_pins) (struct pinctrl_dev *pctldev, unsigned selector, const unsigned **pins, unsigned *num_pins);
//解析设备树的引脚复用功能配置节点并进行映射
int (*dt_node_to_map) (struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, unsigned *num_maps);
//释放 dt_node_to_map 创建的映射
void (*dt_free_map) (struct pinctrl_dev *pctldev, struct pinctrl_map *map, unsigned num_maps);
struct pinmux_ops 对象
pinmux_ops 对象主要实现引脚复用功能选择和 GPIO 操作相关功能,其核心成员如下:
//获取引脚
int (*request) (struct pinctrl_dev *pctldev, unsigned offset);
//释放引脚
int (*free) (struct pinctrl_dev *pctldev, unsigned offset);
//返回引脚支持多少种复用功能
int (*get_functions_count) (struct pinctrl_dev *pctldev);
//返回指定复用功能的名称
const char *(*get_function_name) (struct pinctrl_dev *pctldev, unsigned selector);
//返回支持此复用功能的引脚组
int (*get_function_groups) (struct pinctrl_dev *pctldev, unsigned selector, const char * const **groups, unsigned *num_groups);
//设置引脚组的复用功能
int (*set_mux) (struct pinctrl_dev *pctldev, unsigned func_selector, unsigned group_selector);
//在指定引脚上启用 GPIO 功能
int (*gpio_request_enable) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset);
//与 gpio_request_enable 操作相反
void (*gpio_disable_free) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset);
//配置 GPIO 方向
int (*gpio_set_direction) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset, bool input);
struct pinconf_ops 对象
pinconf_ops 对象主要实现引脚配置(主要用于配置电气特性)相关功能,其核心成员如下:
//获取引脚当前配置
int (*pin_config_get) (struct pinctrl_dev *pctldev, unsigned pin, unsigned long *config);
//配置指定引脚
int (*pin_config_set) (struct pinctrl_dev *pctldev, unsigned pin, unsigned long *configs, unsigned num_configs);
//获取引脚组的当前配置
int (*pin_config_group_get) (struct pinctrl_dev *pctldev, unsigned selector, unsigned long *config);
//配置指定引脚组
int (*pin_config_group_set) (struct pinctrl_dev *pctldev, unsigned selector, unsigned long *configs, unsigned num_configs);
//在 debugfs 中为指定引脚提供设备信息
void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset);
dev_pin_info 对象
在 device 对象中包含一个 dev_pin_info 对象,它用于暂存 device 所引用的 pinctrl 信息,其主要成员如下:
//指向此 dev_pin_info 的 pinctrl 信息,内部包含了所有的 pinctrl 状态,一个状态一般对应到设备树的一个引脚复用功能配置节点
struct pinctrl *p;
//默认的 pinctrl 状态,状态名称为 default
struct pinctrl_state *default_state;
//初始化的 pinctrl 状态,状态名称为 init
struct pinctrl_state *init_state;
//睡眠的 pinctrl 状态,状态名称为 sleep
struct pinctrl_state *sleep_state;
//空闲的 pinctrl 状态,状态名称为 idle
struct pinctrl_state *idle_state;
pinctrl 对象
pinctrl 对象用于描述设备的 pinctrl 信息,其主要成员如下:
//链表节点,用于构成链表
struct list_head node;
//所属设备
struct device *dev;
//pinctrl_state 链表,一个 pinctrl 一般包含多个状态
struct list_head states;
//当前状态
struct pinctrl_state *state;
//pinctrl_map 链表,包含从设备树中的到的一系列的 pinctrl_map ,这些 pinctrl_map 在转换为 pinctrl_setting 后按 pinctrl_map 的名称归类到相应的 pinctrl_state 中,pinctrl_map 的名称一般在设备树中通过pinctrl-names指定
struct list_head dt_maps;
pinctrl_state 对象
pinctrl_state 对象用于描述引脚的状态信息,其核心成员如下:
//链表节点,用于构成链表,因为一个设备有多个 pinctrl_state,利用此链表节点可以将多个 pinctrl_state 构建成一个链表
struct list_head node;
//此状态的名字,一般在设备树中通过pinctrl-names指定
const char *name;
//pinctrl_setting 链表,包含一系列 pinctrl_setting
struct list_head settings;
pinctrl_setting 对象
pinctrl_setting 对象用于描述 pinctrl_state 的配置参数,其核心成员如下:
//链表节点,用于构成链表
struct list_head node;
//pinctrl_setting 类型,是复用功能配置参数还是电气特性配置参数
enum pinctrl_map_type type;
//所属的 pinctrl_dev
struct pinctrl_dev *pctldev;
//使用此 pinctrl_setting 的设备的名称(不是pinctrl_dev的名称)
const char *dev_name;
union {
//引脚复用参数
struct pinctrl_setting_mux mux;
//引脚配置参数
struct pinctrl_setting_configs configs;
} data;
pinctrl_map 对象
pinctrl_map 对象用于描述设备树中引脚复用功能配置节点的信息,它通过调用 pinctrl_dev 的 dt_node_to_map 得到,然后又将其转换为 pinctrl_setting ,其核心成员如下:
//使用此 pinctrl_map 的设备的名称
const char *dev_name;
//pinctrl_map 的名称,按此名称归类到不同的 pinctrl_state 中,pinctrl_map 的名称一般在设备树中通过pinctrl-names指定
const char *name;
//pinctrl_map 的类型
enum pinctrl_map_type type;
//对应的 pinctrl_dev 名称
const char *ctrl_dev_name;
union {
//引脚复用信息
struct pinctrl_map_mux mux;
//引脚配置信息
struct pinctrl_map_configs configs;
} data;
dev_pin_info 构造过程
设备和驱动匹配成功后,在调用驱动或总线的 probe 函数之前会先调用 int really_probe(struct device *dev, struct device_driver *drv) 函数,在此函数中会通过 pinctrl_bind_pins 构建 device 对象中的 dev_pin_info 对象,其大至过程如下:
pinctrl_bind_pins
//为设备分配 dev_pin_info 对象
devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
devm_pinctrl_get
pinctrl_get
//创建 pinctrl 对象
create_pinctrl
//分配一个 pinctrl 对象
kzalloc(sizeof(*p), GFP_KERNEL);
//解析设备树,得到 pinctrl_map ,并将解析出来的 pinctrl_map 添加到 pinctrl_maps 链表
//中
pinctrl_dt_to_map
//遍历 pinctrl_maps 链表,将与设备匹配的 pinctrl_map 转换为 pinctrl_setting
for_each_maps(maps_node, i, map)
//转换时根据 pinctrl_map 名称将得到的 pinctrl_setting 归到相应的 pinctrl_state 中
//即 pinctrl_map 的名称决定了它所转换出来的 pinctrl_setting 属于那个 pinctrl_state
ret = add_setting(p, map)
//查找default状态的pinctrl_state
pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_DEFAULT);
//查找init状态的pinctrl_state
pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_INIT);
//选择default状态或init状态的pinctrl_state
if (IS_ERR(dev->pins->init_state)) {
ret = pinctrl_select_state(dev->pins->p, dev->pins->default_state);
} else {
ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
}
//查找sleep状态和idle状态的pinctrl_state
pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_SLEEP);
pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_IDLE);