Bootstrap

6.2 pinctrl子系统的数据结构

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);
;