在上一章我们通过数据结构间的关联,说明了pinctrl子系统的软件框架。本章我们主要介绍每一个数据结构的定义,从而加深对pinctrl子系统相关的数据结构理解。本章我们依然从soc pin描述、board pin描述、设备模型与pinctrl关联三部分进行说明。
Soc pin描述相关的数据结构
在之前两章我们也说明了pinctrl相关的概念,包括pin controller device、pinctrl dev相关的info描述(pinctrl device desc)、pin引脚描述、function、group等概念。
其中pin controller device即抽象为pinctrl_dev,struct pinctrl_dev即对应一个soc pin controller的抽象描述;Pinctrl dev相关的info描述,对应的数据结构为struct pinctrl_desc,该数据结构包含该soc controller支持的引脚定义、引脚配置操作接口、mux操作接口、group操作接口mux操作接口对应的数据结构为struct pinmux_ops,包含pin request、free、set_mux、get_functions_count、get_function_groups等;group操作接口对应数据结构struct pinctrl_ops,包含get_groups_count、get_group_name、get_group_pins等接口;function操作接口对应的数据结构为struct pinconf_ops,包含pin_config_set、pin_config_get、pin_config_group_get、pin_config_group_set等接口;针对每一个引脚相应的数据结构,包含struct pinctrl_pin_desc、struct pin_desc,其中struct pinctrl_pin_desc用于描述一个pin controller的pin名称与id,仅用于定义pin controller支持的pin个数;而struct pin_desc则主要用于记录引脚的使用计数、引脚当前所属的function、group信息(该数据结构主要是pinctrl子系统用于判断一个引脚是否被多次配置不同的复用情况使用(pin_request、pin_free))。
下面即是这几个数据结构间的关联流程。
struct pinctrl_dev
该数据结构是soc pin controller的抽象,其包含如下主要信息:
struct pinctrl_desc 类型的变量desc描述该pinctrl device相关的信息(所支持的引脚个数及描述、引脚配置操作接口、group操作接口、mux操作接口);基数树pin_desc_tree主要用于存储引脚使用描述相关的变量(struct pin_desc,引脚使用情况说明),由pinctrl子系统用于判断一个引脚是否被多次配置不同的复用情况使用;基数树pin_group_tree、pin_function_tree主要用于存储group、function的描述信息,这部分内容是linux4.4以后的版本才加入的(在此之前,group、function的管理由各pin controller driver自行管理,而在新版内核中,定义了数据结构struct function_desc、struct group_desc描述function、group等信息),增加针对group、function的数据结构真的是一个很好的设计,因为大多数厂家的pin controller driver定义的function、group数据结构基本上类似,理应由pinctrl 子系统定义统一的数据结构。gpio_ranges则主要用于链接gpio range 2 pin range相关的信息,针对gpio做了相应的关联处理,不过不建议将gpio与pin子系统进行混合在一起,还是将它们分开比较好,针对gpio引脚复用也作为引脚分配的一种即可(这一点可以看下zynq的pin controller driver,它的驱动实现还是挺好的,针对每一个gpio均作为一个group,然后在gpio function时,关联相应的group即可),个人感觉不要把gpio与pinctrl搅合在一起,能分开就分开。针对pinctrl device,也定义了device pin controller holder,也包含pinctrl_state信息,这个主要是针对系统中没有对应到具体设备的引脚复用的设置。若没有特殊的设置,则可以不设置这几个变量即可。
基本上就是这些信息。
struct pinctrl_dev {struct list_head node;struct pinctrl_desc *desc;struct radix_tree_root pin_desc_tree;#ifdef CONFIG_GENERIC_PINCTRL_GROUPSstruct radix_tree_root pin_group_tree;unsigned int num_groups;#endif#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONSstruct radix_tree_root pin_function_tree;unsigned int num_functions;#endifstruct list_head gpio_ranges;struct device *dev;struct module *owner;void *driver_data;struct pinctrl *p;struct pinctrl_state *hog_default;struct pinctrl_state *hog_sleep;struct mutex mutex;#ifdef CONFIG_DEBUG_FSstruct dentry *device_root;#endif};
struct pinctrl_desc
该数据结构是pin ctrl device的info信息描述,定义如下,包含的主要信息:
定义该pin ctrl device所有的引脚描述信息(struct pinctrl_pin_desc *pin)以及引脚个数;定义该soc pin controller的引脚复用的操作接口(struct pinmux_ops *pmx_ops);定义该soc pin controller的引脚配置相关的操作接口(struct pinconf_ops *confops);定义该soc pin controller的group信息获取相关的操作接口(struct pinctrl_ops *pctlops);num_custom_params、custom_params也是4.4内核以后版本增加的内容,在新内核中增加了针对引脚配置相关的通用属性参数,包含output-high、output-low、bias-pull-up等等属性参数。但是呢若soc pin controller 支持的引脚配置属性未在引脚配置相关的通用属性参数定义中,则可以使用num_custom_params、custom_params这两个参数自定义该soc pin controller的属性参数。
struct pinctrl_desc {const char *name;const struct pinctrl_pin_desc *pins;unsigned int npins;const struct pinctrl_ops *pctlops;const struct pinmux_ops *pmxops;const struct pinconf_ops *confops;struct module *owner;#ifdef CONFIG_GENERIC_PINCONFunsigned int num_custom_params;const struct pinconf_generic_params *custom_params;const struct pin_config_item *custom_conf_items;#endif};
struct pinctrl_pin_desc struct pin_desc
这两个数据结构是对应引脚描述的,其中pinctrl_pin_desc描述引脚的名称、引脚index等;而
pin_desc则主要描述该pin当前的配置信息(所属function、group等)、pin引脚配置计数等。定义如下:
struct pinctrl_pin_desc {unsigned number;const char *name;void *drv_data;};struct pin_desc {struct pinctrl_dev *pctldev;const char *name;bool dynamic_name;void *drv_data;/* These fields only added when supporting pinmux drivers */#ifdef CONFIG_PINMUXunsigned mux_usecount;const char *mux_owner;const struct pinctrl_setting_mux *mux_setting;const char *gpio_owner;#endif};
struct pinctrl_ops
该数据结构虽然名称是pinctrl_ops,其实主要是对group的操作接口,内容如下:
get_groups_count用于获取该pinctrl_dev的group的个数;get_group_name用于获取一个group的名称(根据group的id);get_group_pins用于获取一个group对应的pin信息及个数;
struct pinctrl_ops {int (*get_groups_count) (struct pinctrl_dev *pctldev);const char *(*get_group_name) (struct pinctrl_dev *pctldev,unsigned selector);int (*get_group_pins) (struct pinctrl_dev *pctldev,unsigned selector,const unsigned **pins,unsigned *num_pins);void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,unsigned offset);int (*dt_node_to_map) (struct pinctrl_dev *pctldev,struct device_node *np_config,struct pinctrl_map **map, unsigned *num_maps);void (*dt_free_map) (struct pinctrl_dev *pctldev,struct pinctrl_map *map, unsigned num_maps);};
struct pinmux_ops
该数据接口主要定义各pinctrl device的引脚复用相关的操作接口,主要内容包含:
request、free接口用于申请或释放一个引脚;get_functions_count接口用于获取一个pinctrl device的所有function个数;get_function_name接口用于获取一个function名称(根据function id查找);get_function_groups接口用于获取一个function所关联的group;set_mux接口用于进行引脚复用设置;gpio_request_enable、gpio_disable_free、gpio_set_direction接口用于gpio的enable、disable以及direction的配置等。
struct pinmux_ops {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);int (*gpio_request_enable) (struct pinctrl_dev *pctldev,struct pinctrl_gpio_range *range,unsigned offset);void (*gpio_disable_free) (struct pinctrl_dev *pctldev,struct pinctrl_gpio_range *range,unsigned offset);int (*gpio_set_direction) (struct pinctrl_dev *pctldev,struct pinctrl_gpio_range *range,unsigned offset,bool input);bool strict;};
struct pinconf_ops
该接口主要实现一个pinctrl device的引脚配置相关的操作接口,主要内容如下:
pin_config_get接口用于获取一个引脚的当前配置;pin_config_set接口用于对一个引脚进行配置;pin_config_group_get接口用于获取一个group的引脚配置信息;pin_config_group_set即可用于对一个group的所有引脚进行配置。
struct pinconf_ops {#ifdef CONFIG_GENERIC_PINCONFbool is_generic;#endifint (*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);void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev,struct seq_file *s,unsigned offset);void (*pin_config_group_dbg_show) (struct pinctrl_dev *pctldev,struct seq_file *s,unsigned selector);void (*pin_config_config_dbg_show) (struct pinctrl_dev *pctldev,struct seq_file *s,unsigned long config);};
Board pin描述相关的数据结构
Soc pin描述相关的数据结构,已经搭建了该soc所支持的pin、function、group以及相关操作接口
等信息;而board pin描述相关的数据结构则描述一块board所使用到的function及相关的group。
而board pin描述主要包含struct pinctrl_maps、struct pinctrl_map这两个数据结构。其中一个
struct pinctrl_map对应一个function,而pinctrl_maps是多个function集合。如下是pinctrl_maps的关联。
struct pinctrl_map
该数据结构可以理解为一个function类型,主要内容如下:
dev_name对应设备名称,通过该名称可以找到具体的设备;name为该pinctrl_map对应的状态(default、idle、sleep等),前面我们说了一个设备所对应的引脚配置在不同的状态下会有所不同(如在sleep状态下可以释放该设备对应的pin复用,可由其他设备使用这些引脚),而此处的状态即表示该设备在此状态下的引脚配置(若设备在default状态需要配置成设备所需的引脚配置、在sleep状态释放引脚配置,则可为此设备定义两个pinctrl_map,分别对应不同的状态下的引脚复用与配置)。type表示pinctrl_map的类型,包括mux group、config group、config pins等类型;ctrl_dev_name为pinctrl device的名称,根据该名称可获取到soc pin controller对应的pinctrl device;而struct pinctrl_map_mux定义引脚复用的内容,该数据结构中包含function名称、group名称,通过function、group就可以确定进行引脚复用的引脚id与引脚复用值等信息;Struct pinctrl_map_configs定义引脚配置相关的内容,包括group或者pin的名称,以及该group、pin的配置信息,实现引脚配置操作。
struct pinctrl_map {const char *dev_name;const char *name;enum pinctrl_map_type type;const char *ctrl_dev_name;union {struct pinctrl_map_mux mux;struct pinctrl_map_configs configs;} data;};
而struct pinctrl_maps主要是多个pinctrl_map的集合。
设备模型与pinctrl关联
上面介绍的soc pin描述、board pin描述,主要介绍了soc支持的引脚数、group数、function数以及操作接口等信息;board pin所使用的function组合、引脚配置等信息。
我们前面介绍在设备与设备驱动match之后的probe函数里才会进行引脚复用以及引脚配置的设置,即设备是引脚配置与引脚复用的持有者,因此设备与pinctrl子系统之间也存在数据结构之间的关联。
如下是设备模型部分与pinctrl子系统相关的数据结构,主要包含struct dev_pin_info、struct pinctrl、struct pinctrl_state、struct pinctrl_setting这几个数据结构,而这些数据结构间的关系则主要根据board pin描述中的struct pinctrl_map等信息建立起来的。
struct dev_pin_info
该数据结构表示该device所对应引脚的配置与复用信息,在接口pinctrl_bind_pins中会初始化该设备的dev_pin_info,并进行相应的配置。主要内容如下:
Struct pinctrl类型的变量表示该设备支持引脚配置类型(包括支持的pinctrl状态,每一种pinctrl状态下的引脚复用以及引脚配置信息);default_state表示该device的默认状态;init_state状态表示device的init状态,一般default_state即为init_state;若支持电源管理,则还包含sleep状态、idle状态。
struct dev_pin_info {struct pinctrl *p;struct pinctrl_state *default_state;struct pinctrl_state *init_state;#ifdef CONFIG_PMstruct pinctrl_state *sleep_state;struct pinctrl_state *idle_state;#endif};
struct pinctrl
该数据结构对应一个设备的所有引脚配置相关的信息,该数据结构的定义如下
dev指向拥有该pinctrl的device;
states下链接了该设备支持的所有引脚配置状态;
/*** struct pinctrl - per-device pin control state holder* @node: global list node* @dev: the device using this pin control handle* @states: a list of states for this device* @state: the current state* @dt_maps: the mapping table chunks dynamically parsed from device tree for*this device, if any* @users: reference count*/struct pinctrl {struct list_head node;struct device *dev;struct list_head states;struct pinctrl_state *state;struct list_head dt_maps;struct kref users;};
struct pinctrl_state
该数据结构表示设备引脚的一种状态及该状态下的引脚控制信息,如default状态下,包含了设备对应
引脚的复用配置、也包含了设备对应引脚的配置信息。
name表示状态名称;
而链表头settings中则存储了该设备在该状态下的引脚配置信息(这些配置信息以struct pinctrl_setting类型表示);
struct pinctrl_state {struct list_head node;const char *name;struct list_head settings;};
struct pinctrl_setting
该数据结构表示一个设备在一个状态下的pinctrl控制信息,包含的内容如下:
type表示控制信息类型(mux group、config group、config pin等类型);
pctrldev指向对应soc pin controller device;
dev_name对应设备名称;
而struct pinctrl_setting_mux表示group的引脚复用配置,这里面包含function index、group index(依据board pin描述中的struct pinctrl_map中的mux的function name、group name、soc pin描述中的function、group信息,火气大到function index、group的index);
而struct pinctrl_setting_configs则包含了group或pin的index,也是借助board pin描述中的group或者pin的name,然后在soc pin描述中查找到对应的group或pin的index。
struct pinctrl_setting {struct list_head node;enum pinctrl_map_type type;struct pinctrl_dev *pctldev;const char *dev_name;union {struct pinctrl_setting_mux mux;struct pinctrl_setting_configs configs;} data;};
借助于数据结构struct dev_pin_info,并依据board pin描述中的pinctrl_map的信息、soc pin描述中的function、group的信息,完成该device在每一个state下的引脚配置信息的设置,并完成引脚复用以及引脚配置信息的操作(主要借助函数pinctrl_bind_pins实现);
以上即为pinctrl子系统数据结构的分析,总结如下:
Soc pin描述相关的数据结构,描述了一个soc pin controller支持的所有pin、所有可能的function、所有可能的group信息以及function、group、mux相关的操作接口;Board pin描述相关的数据结构,则依据该board的硬件设计,选定了soc pin controller中function与group组合中的一个子集;设备模型与pinctrl关联部分的数据结构,则根据board pin描述中该设备相关的pinctrl map信息,确定了该设备所有状态下所对应的mux、group/pin config信息,并依据当前设备所处的状态,选取对应mux、group/pin config信息进行配置,从而让配置生效。
下一章我们介绍具体的函数。
如果觉得《Linux pinctrl子系统分析之三 数据结构分析》对你有帮助,请点赞、收藏,并留下你的观点哦!