MEMORY | INTERRUPT | TIMER | 并发与同步 | 进程管理 | 调度 | uboot | DTB | ARMV8 | ATF | Kernel Data Structure | PHY | LINUX2.6 | 驱动合集 | UART子系统 | USB专题 |

Linux pinctrl 子系统

文章代码分析基于linux-5.19.13,架构基于aarch64(ARM64)。

1. Linux 5.x官方参考文档

Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt

2. Pinctrl的引入

 想要pinA、B用于GPIO,需要设置IOMUX让它们连接到GPIO模块;要想让pinA、B用于I2C,需要设置IOMUX让它们连接到I2C模块,这里GPIO、UART应该是并列的关系,它们能够使用之前,需要设置复用关系IOMUX,有时还要配置引脚,比如上拉、下拉、开漏等等。现在芯片一般动辄几百个引脚,在使用到GPIO、I2C等功能时,若一个引脚一个引脚去找对应的寄存器进行配置非常浪费时间和精力,所以内核引入了Pinctrl子系统,把引脚的复用和配置抽象出来,只需要芯片厂商把自家芯片的支持进去,就可以很方便的配置引脚。

Pinctrl:Pin Controller,顾名思义,就是用来控制引脚的:

  • 引脚枚举与命名(Enumerating and naming)
  • 引脚复用(Multiplexing):比如用作GPIO、I2C或其他功能
  • 引脚配置(Configuration):比如上拉、下拉、开漏、驱动强度等

3. Pinctrl重要概念

Pinctrl子系统涉及2个对象:

  • Pin controller devices
    提供服务,可以用它来复用引脚、配置引脚,是一个软件上的概念。注意:Pin controller和GPIO Controller不同,前者控制的引脚可用于GPIO功能、UART功能;后者只是把引脚配置为输入、输出等简单的功能。两者的关系是先用Pin controller把引脚配置为GPIO,再用GPIO Controler把引脚配置为输入或输出。
  • Pinctrl client devices
    使用服务,Pinctrl系统的客户,即使用Pinctrl系统的设备。声明自己要使用哪些引脚的哪些功能,怎么配置它们。

在设备树中,上述两个对象被定义成两个节点,如下图所示。左边是Pin controller节点,右边是client device节点:

  • Pin state
     对于一个client device,比如他是一个uart设备,它有多个“状态”:如default、sleep等,那对应的引脚也有这些状态。比如“default”状态下,UART设备是工作的,那么所用的引脚就要复用为UART功能(RTS和TXD常常与UART(通用步收发传输器)或RS-232(串行通信接口标准)相关联);在“sleep”状态下,为了省电,可以把这些引脚复用为GPIO功能,或者直接把它们配置输出高电平。上图中,pinctrl-names属性里定义了2种状态:default、sleep。
    第0种状态用到的引脚在pinctrl-0中定义,它是state_0_node_a,位于Pin controller节点中。 第1种状态用到的引脚在pinctrl-1中定义,它是state_1_node_a和state_1_node_b,也位于pin controller节点中。
     (1)当这个设备处于default状态时,pinctrl子系统会自动根据上述信息把所用引脚复用为uart功能。
     (2)当这个设备处于sleep状态时,pinctrl子系统会自动根据上述信息把所用引脚配置为高电平,下拉。

  • groups、function和pins
     一个设备会用到一个或多个引脚pin,这些引脚就可以归为一组group,复用为某个功能function;当然:一个设备可以用到多组引脚,比如A1、A2两组引脚,A1组复用为F1功能,A2组复用为F2功能。

  • pin multiplexing node和pin configuration node
    在上图Pin controller节点中,有子节点或孙节点,它们是给client device使用的。
     可以用来描述复用信息:哪组(group)引脚复用为哪个功能(function);
     可以用来描述配置信息:哪组(group)引脚配置为哪个设置功能(setting),比如上拉、下拉等。

注意:Pin controller节点的格式,没有统一的格式。不同厂家都不太一样,甚至上面的group、function关键字也不一定有,但是相对的概念是存在的。而client device节点的格式是统一的。

3. 数据结构

3.1 pincontroller

3.1.1 pinctrl_desc和pinctrl_dev结构体

提供一个pinctrl_desc,然后调用pinctrl_init_controller或者pinctrl_register就可以得到一个pinctrl_dev。

3.1.2 pinctrl_descs示例

1.引脚的枚举与命名

/**
 * struct pinctrl_pin_desc - boards/machines provide information on their
 */
struct pinctrl_pin_desc {
	unsigned number;    //引脚的序号
	const char *name;	//引脚的名称
	void *drv_data;
};

2.引脚的控制操作,用来获取某组引脚,解析设备树节点创建映射

pinctrl_ops {
	int (*get_groups_count) (struct pinctrl_dev *pctldev);       //获取group的个数
	const char *(*get_group_name) (struct pinctrl_dev *pctldev,
				       unsigned selector);                       //获取group的名称
	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);                                  //debugfs提供每个引脚的信息
	int (*dt_node_to_map) (struct pinctrl_dev *pctldev,
			       struct device_node *np_config,
			       struct pinctrl_map **map, unsigned *num_maps);//解析设备树节点,转换成pinctrl_map,非常非常重要
	void (*dt_free_map) (struct pinctrl_dev *pctldev,
			     struct pinctrl_map *map, unsigned num_maps);//释放map
};

dt_node_to_map主要功能:处理设备树中pin controller中的某个节点创建映射,把device_node转换为一系列的pinctrl_map。

3.引脚的复用操作

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); //获取func数量
	const char *(*get_function_name) (struct pinctrl_dev *pctldev,
					  unsigned selector);                     //获取func名称
	int (*get_function_groups) (struct pinctrl_dev *pctldev,
				  unsigned selector,
				  const char * const **groups,
				  unsigned *num_groups);                      //获取func下的组
	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;
};

4.引脚的配置操作

struct pinconf_ops {
#ifdef CONFIG_GENERIC_PINCONF
	bool is_generic;
#endif
	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);               //配置某组引脚
	int (*pin_config_dbg_parse_modify) (struct pinctrl_dev *pctldev,
					   const char *arg,
					   unsigned long *config);            //debugfs修改pin配置信息的功能
	void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev,
				     struct seq_file *s,
				     unsigned offset);                    //debugfs提供pin配置信息的功能   
	void (*pin_config_group_dbg_show) (struct pinctrl_dev *pctldev,
					   struct seq_file *s,
					   unsigned selector);                //debugfs提供group配置信息的功能
	void (*pin_config_config_dbg_show) (struct pinctrl_dev *pctldev,
					    struct seq_file *s,
					    unsigned long config);            //debugfs解析并显示pin的配置的功能
};

3.1.3 使用pinctrl_desc注册得到pinctrl_dev

|---ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL);
|---imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc),GFP_KERNEL)
|---devm_pinctrl_register_and_init(&pdev->dev,imx_pinctrl_desc, ipctl, &ipctl->pctl)
|		|---  struct pinctrl_dev **ptr
|		|---  ptr = devres_alloc(devm_pinctrl_dev_release, sizeof(*ptr), GFP_KERNEL)
|		|---  pinctrl_register_and_init(pctldesc, dev, driver_data, pctldev)
|		|	|--- struct pinctrl_dev *p;
|		|	|--- p = pinctrl_init_controller(pctldesc, dev, driver_data);
|		|	| 	|--- pctldev->desc = pctldesc;
|		|	|	|--- pctldev->driver_data = driver_data;
|		|	|	|--- pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins)//注册所有的引脚
|		| 	|--- *pctldev = p
|		|---*ptr = *pctldev
|---pinctrl_enable(ipctl->pctl)
	|---mutex_lock(&pinctrldev_list_mutex);
	|---list_add_tail(&pctldev->node, &pinctrldev_list);//添加到链表
	|---mutex_unlock(&pinctrldev_list_mutex);
	|---pinctrl_init_device_debugfs(pctldev);

调用devm_pinctrl_register_and_init(devm_pinctrl_register或pinctrl_register也可以),根据pinctrl_desc构造出pinctrl_dev,并且把pinctrl_dev放入链表。

3.2 client

在设备树中,使用pinctrl的格式如下:

&usdhc2 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_sd2_sd2>, <&pinctrl_sd2_sd2gpio>;
	pinctrl-1 = <&pinctrl_sd2_sd2_100mhz>, <&pinctrl_sd2_sd2gpio>;
	pinctrl-2 = <&pinctrl_sd2_sd2_200mhz>, <&pinctrl_sd2_sd2gpio>;
	cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
	bus-width = <4>;
	vmmc-supply = <&reg_usdhc2_vmmc>;
	status = "okay";
};

3.2.1 dev_pin_info的定义

  设备节点被转换为platform_device,或者其他结构体i2c_client,spi_controller等,但是里面都会有一个device结构体,device结构体会有dev_pin_info结构体的定义:

3.2.2 dev_pin_info、pinctrl、pinctrl_map和pinctrl_setting的关系

假设芯片上有多个pin controller,那么这个设备使用哪个pin controller ?
这需要通过设备树来确定:

分析设备树,找到pin controller
对于每个状态,比如default、init,去分析pin controller中的设备树节点

  • 使用pin controller的pinctrl_ops.dt_node_to_map来处理设备树的pinctrl节点信息,例如pinctrl-0 = <&pinctrl_sd2_sd2>, <&pinctrl_sd2_sd2gpio>,pinctrl_sd2_sd2和pinctrl_sd2_sd2gpio节点分别被解析为一系列的pinctrl_map;
  • 每一个节点解析的多个pinctrl_map存放在struct pinctrl_maps结构体中。这些struct pinctrl_maps又被放在pinctrl.dt_maps链表中;
  • 每个pinctrl_map都被转换为pinctrl_setting,放在对应的pinctrl_state.settings链表中
  • 选择状态时,遍历settings链表,执行pin controller复用或配置函数

4. Pincontroller构造过程

4.1 设备树节点

pinctrl_sd2_sd2gpio: sd2_sd2gpio_grp {
	fsl,pins = <
		MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12	0x1c4
		MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19	0x41
	>;
};
pinctrl_sd2_sd2: sd2_sd2_grp {
	fsl,pins = <
		MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x190
		MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d0
		MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d0
		MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d0
		MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d0
		MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d0
	>;
};

4.2 驱动代码执行流程

/* Convenience macro to define a single named or anonymous pin descriptor */
#define PINCTRL_PIN(a, b) { .number = a, .name = b }
#define IMX_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin)
/* Pad names for the pinmux subsystem */
static const struct pinctrl_pin_desc imx8mm_pinctrl_pads[] = {
	IMX_PINCTRL_PIN(MX8MM_PAD_RESERVE0),
	IMX_PINCTRL_PIN(MX8MM_PAD_RESERVE1),
	...
	IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO00),
	IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO01),
	IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO02),
	...
	IMX_PINCTRL_PIN(MX8MM_IOMUXC_UART4_TXD),
};
static struct imx_pinctrl_soc_info imx8mm_pinctrl_info = {
	.pins = imx8mm_pinctrl_pads,
	.npins = ARRAY_SIZE(imx8mm_pinctrl_pads),
	.gpr_compatible = "fsl,imx8mm-iomuxc-gpr",
};

static struct of_device_id imx8mm_pinctrl_of_match[] = {
	{ .compatible = "fsl,imx8mm-iomuxc", .data = &imx8mm_pinctrl_info, },
	{ /* sentinel */ }
};
|---imx8mm_pinctrl_probe(struct platform_device *pdev)
	|---match = of_match_device(imx8mm_pinctrl_of_match, &pdev->dev)
	|---pinctrl_info = (struct imx_pinctrl_soc_info *) match->data //获取开发板的私有数据data
	|---imx_pinctrl_probe(pdev, pinctrl_info)
		|---info->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*info->pin_regs) *info->npins, GFP_KERNEL)
		|---for (i = 0; i < info->npins; i++) //初始化
		|	|---info->pin_regs[i].mux_reg = -1;
		|	|---info->pin_regs[i].conf_reg = -1
		|
		|---//pincontroller的地址映射
		|---res = platform_get_resource(pdev, IORESOURCE_MEM, 0)
		|---ipctl->base = devm_ioremap_resource(&pdev->dev, res)
		|
		|---imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc),GFP_KERNEL)
		|---imx_pinctrl_desc->name = dev_name(&pdev->dev);
		|---//1.引脚的枚举与命名
		|---imx_pinctrl_desc->pins = info->pins;
		|---imx_pinctrl_desc->npins = info->npins;
		|---//2.引脚的控制操作,用来获取某组引脚,解析设备树节点创建映射
		|---imx_pinctrl_desc->pctlops = &imx_pctrl_ops;
		|---//3.引脚的复用操作
		|---imx_pinctrl_desc->pmxops = &imx_pmx_ops;
		|---//4.引脚的配置操作
		|---imx_pinctrl_desc->confops = &imx_pinconf_ops;
		|---imx_pinctrl_desc->owner = THIS_MODULE;
		|
		|---//使用pinctrl_desc注册得到pinctrl_dev,参考3.1.3
		|---ipctl->info = info;
		|---ipctl->dev = info->dev;
		|---platform_set_drvdata(pdev, ipctl);
		|---ret = devm_pinctrl_register_and_init(&pdev->dev,imx_pinctrl_desc, ipctl, &ipctl->pctl);
		|
		|---//
		|---imx_pinctrl_probe_dt(pdev, ipctl)
		|
		|---//把pinctrl_dev放入链表pinctrldev_list(static LIST_HEAD(pinctrldev_list))
		|---pinctrl_enable(ipctl->pctl)
			|---mutex_lock(&pinctrldev_list_mutex);
			|---list_add_tail(&pctldev->node, &pinctrldev_list);//添加到链表
			|---mutex_unlock(&pinctrldev_list_mutex);
			|---pinctrl_init_device_debugfs(pctldev);

1. 引脚的枚举与命名

imx_pinctrl_desc->pins = info->pins;
imx_pinctrl_desc->npins = info->npins;

2.引脚的控制操作,用来获取某组引脚,解析设备树节点创建映射

static const struct pinctrl_ops imx_pctrl_ops = {
	.get_groups_count = pinctrl_generic_get_group_count,
	.get_group_name = pinctrl_generic_get_group_name,
	.get_group_pins = pinctrl_generic_get_group_pins,
	.pin_dbg_show = imx_pin_dbg_show,    //debugfs用
	.dt_node_to_map = imx_dt_node_to_map,//参见5.2.1 
	.dt_free_map = imx_dt_free_map,
};

imx_pinctrl_desc->pctlops = &imx_pctrl_ops;

3.引脚的复用操作

struct pinmux_ops imx_pmx_ops = {
	.get_functions_count = pinmux_generic_get_function_count,
	.get_function_name = pinmux_generic_get_function_name,
	.get_function_groups = pinmux_generic_get_function_groups,
	.set_mux = imx_pmx_set, //重要
};
imx_pinctrl_desc->pmxops = &imx_pmx_ops

4.引脚的配置操作

static const struct pinconf_ops imx_pinconf_ops = {
	.pin_config_get = imx_pinconf_get,
	.pin_config_set = imx_pinconf_set,
	.pin_config_dbg_show = imx_pinconf_dbg_show,
	.pin_config_group_dbg_show = imx_pinconf_group_dbg_show,
};

imx_pinctrl_desc->confops = &imx_pinconf_ops;

5.单板强相关的专有操作,解析group和配置
把每个pin的配置信息保存在对应的结构体struct imx_pin_reg和struct imx_pin中:

/**
 * struct imx_pin_reg - describe a pin reg map
 * @mux_reg: mux register offset
 * @conf_reg: config register offset
 */
struct imx_pin_reg {
	s16 mux_reg;  //第0个数值
	s16 conf_reg; //第1个数值
};
/**
 * struct imx_pin - describes a single i.MX pin
 * @pin: the pin_id of this pin
 * @mux_mode: the mux mode for this pin.
 * @input_reg: the select input register offset for this pin if any
 *	0 if no select input setting needed.
 * @input_val: the select input value for this pin.
 * @configs: the config for this pin.
 */
struct imx_pin_memmap {
	unsigned int mux_mode; //第3个数值
	u16 input_reg;         //第2个数值
	unsigned int input_val;//第5个数值
	unsigned long config;  //第6个数值
};

struct imx_pin {
	unsigned int pin;
	union {
		struct imx_pin_memmap pin_memmap;
		struct imx_pin_scu pin_scu;
	} pin_conf;
};

5. client端使用pinctrl过程的分析

5.1 设备树节点

&usdhc2 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_sd2_sd2>, <&pinctrl_sd2_sd2gpio>;
	pinctrl-1 = <&pinctrl_sd2_sd2_100mhz>, <&pinctrl_sd2_sd2gpio>;
	pinctrl-2 = <&pinctrl_sd2_sd2_200mhz>, <&pinctrl_sd2_sd2gpio>;
	cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
	bus-width = <4>;
	vmmc-supply = <&reg_usdhc2_vmmc>;
	status = "okay";
};

5.2 client节点如何使用pinctrl

  device匹配driver会执行probe探测函数,执行到驱动中真正的probe函数之前,会进行pinctrl的处理,处理函数为pinctrl_bind_pins,调用过程如下:

|---really_probe(struct device *dev, struct device_driver *drv)
	|---/* If using pinctrl, bind pins now before probing */
	|---ret = pinctrl_bind_pins(dev);//非常重要
	|---if (dev->bus->probe) {
	|	|---dev->bus->probe(dev);
	|---else if (drv->probe)
	|	|---drv->probe(dev)

pinctrl_bind_pins的主要用功能:

  • 构造pinctrl
    • 通过pinctrl_ops.dt_node_to_map将设备树节点转换成一系列的pinctrl_map;
    • 再把pinctrl_map转换成pinctrl_setting,并放入settings链表,记录在pinctrl_state中;
  • 选择state,遍历settings链表,进行pinctrl的mux和config

5.2.1 client节点构造pinctrl的过程分析

函数调用过程解析:

|---really_probe(struct device *dev, struct device_driver *drv)
	|---/* If using pinctrl, bind pins now before probing */
	|---ret = pinctrl_bind_pins(dev);             //非常重要
		|---dev->pins->p = devm_pinctrl_get(dev)  //分配dev_pin_info结构体
			|---pinctrl_get(dev)
				|---p = find_pinctrl(dev);        //首次进入的肯定为空
				|---if (p) 
				|	|---return p
				|---create_pinctrl(dev, NULL)     //构建pinctrl
					|---struct pinctrl *p
					|---p = kzalloc(sizeof(*p), GFP_KERNEL)//分配
					|---pinctrl_dt_to_map(p, pctldev)      //1. 设备树节点转换为pinctrl_map
					|
					|---for_each_maps(maps_node, i, map)   //2. 每个pinctrl_map,又被转换为一个pinctrl_setting,添加到setting链表
					|	|---add_setting(p, pctldev, map)
					|
					|---list_add_tail(&p->node, &pinctrl_list) //新创建的struct pinctrl添加到pinctrl_list链表

设备引用pin controller中的某个节点时,这个节点会被转换为一系列的pinctrl_map:

  • 转换为多少个pinctrl_map,由具体的驱动决定;
  • 每个pinctrl_map,又被转换为一个pinctrl_setting

举例
设备节点里有:pinctrl-1 = <&state_1_node_a &state_1_node_b>

  • pinctrl-1对应状态"idle",会得到一个pinctrl_state;
  • state_1_node_a/state_1_node_b节点分别被解析为一系列的pinctrl_map;
  • 这一系列的pinctrl_map又被转换为一系列的pinctrl_setting;
  • 这些pinctrl_setting被放入对应pinctrl_state("default", "state_100mhz", "state_200mhz")的settings链表;

1. 设备树节点转换为pinctrl_map
这些设备树节点信息会被转换为一些列的pinctrl_map,以imyimx8mm的usdhc2节点举例

函数调用过程解析:

|---pinctrl_dt_to_map(p, pctldev)
	|---dt_gpio_assert_pinctrl(p)
	|---for (state = 0; ; state++)
		|---propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state) // 取出pinctrl-%d节点属性
		|---prop = of_find_property(np, propname, &size)
		|---list = prop->value;
		|---size /= sizeof(*list);
		|---of_property_read_string_index(np, "pinctrl-names",state, &statename)
		|---for (config = 0; config < size; config++)             //对pinctrl-%d中的每一个phandle进行pinctrl_map转换
			|---phandle = be32_to_cpup(list++)
			|---np_config = of_find_node_by_phandle(phandle)      //根据phandle找到对应节点
			|---dt_to_map_one_config(p, pctldev, statename,np_config)
				|---ops = pctldev->desc->pctlops
				|---ops->dt_node_to_map(pctldev, np_config, &map, &num_maps)     //调用Pincontroller中dt_node_to_map函数,构造pinctrl_map
				|---dt_remember_or_free_map(p, statename, pctldev, map, num_maps)//pinctrl_map添加到maps链表
					|---struct pinctrl_dt_map *dt_map
					|---for (i = 0; i < num_maps; i++)
					|	|---map[i].dev_name = dev_name(p->dev)
					|	|---map[i].name = statename
					|	|---map[i].ctrl_dev_name = dev_name(pctldev->dev)
					|---dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL)
					|---dt_map->pctldev = pctldev;
					|---dt_map->map = map;
					|---dt_map->num_maps = num_maps;
					|---list_add_tail(&dt_map->node, &p->dt_maps);           //存放dt_map(struct pinctrl_dt_map类型)到pinctrl的成员dt_maps链表
					|---pinctrl_register_map(map, num_maps, false)           //存放dt_map(struct pinctrl_dt_map类型)到全局链表pinctrl_maps
						|---struct pinctrl_maps *maps_node
						|---maps_node = kzalloc(sizeof(*maps_node), GFP_KERNEL);
						|---maps_node->num_maps = num_maps
						|---list_add_tail(&maps_node->node, &pinctrl_maps);  //LIST_HEAD(pinctrl_maps)

2. pinctrl_map转换为pinctrl_setting

函数调用过程解析:

|---for_each_maps(maps_node, i, map) //每个pinctrl_map,又被转换为一个pinctrl_setting,添加到setting链表
	|---add_setting(p, pctldev, map)
		|---struct pinctrl_state *state;
		|---struct pinctrl_setting *setting;
		|---state = find_state(p, map->name)
		|---if (!state)                                //第一次添加state到states链表
		|	|---state = create_state(p, map->name);
		|---setting = kzalloc(sizeof(*setting), GFP_KERNEL)
		|---setting->type = map->type                  //将map的name和tpye赋值给setting
		|---setting->dev_name = map->dev_name
		|---switch (map->type)
		|	|---//MUX类型
		|	|---case PIN_MAP_TYPE_MUX_GROUP
		|	|	|---pinmux_map_to_setting(map, setting)
		|	|		|---const struct pinmux_ops *pmxops = pctldev->desc->pmxops
		|	|		|---//将pinctrl_map中的function字符串转换为序号,赋值给setting
		|	|		|---ret = pinmux_func_name_to_selector(pctldev, map->data.mux.function)
		|	|		|---setting->data.mux.func = ret   //赋值给setting
		|	|		|
		|	|		|---//将pinctrl_map中的group字符串转换为序号,赋值给setting
		|	|		|---pmxops->get_function_groups(pctldev, setting->data.mux.func, &groups, &num_groups)
		|	|		|---if (map->data.mux.group) {
		|	|		|	|---group = map->data.mux.group;
		|	|		|	|---ret = match_string(groups, num_groups, group);
		|	|		|---else
		|	|		|	|---group = groups[0]
		|	|		|---ret = pinctrl_get_group_selector(pctldev, group)
		|	|		|---setting->data.mux.group = ret  //赋值给setting
		|	|
		|	|---//CONFIGS类型
		|	|---case PIN_MAP_TYPE_CONFIGS_PIN
		|	|---case PIN_MAP_TYPE_CONFIGS_GROUP
		|		|---pinmux_map_to_setting(map, setting)
		|			|---int pin;
		|			|---switch (setting->type)
		|				|---//配置单个PIN
		|				|---case PIN_MAP_TYPE_CONFIGS_PIN
		|				|	|---pin = pin_get_from_name(pctldev,map->data.configs.group_or_pin)//从pinctrl_map取出pin
		|				|	|---setting->data.configs.group_or_pin = pin//赋值给setting
		|				|
		|				|---//配置GROUP
		|				|---case PIN_MAP_TYPE_CONFIGS_GROUP
		|				|	|---pin = pinctrl_get_group_selector(pctldev,map->data.configs.group_or_pin)////从pinctrl_map取出group
		|				|	|---setting->data.configs.group_or_pin = pin//赋值给setting
		|				| 
		|				|---setting->data.configs.num_configs = map->data.configs.num_configs
		|				|---setting->data.configs.configs = map->data.configs.configs
		|
		|---list_add_tail(&setting->node, &state->settings) //添加到该state(例子对应"default"状态)的settings链表

5.2.2 client节点如何设置管脚的复用、配置(每个厂家实现各不相同)

6. 使用debugfs调试

1. pinctrl-devices

root@imx8mmevk:/sys/kernel/debug/pinctrl# cat pinctrl-devices
name [pinmux] [pinconf]
30330000.pinctrl yes yes

2. pinctrl-handles

root@imx8mmevk:/sys/kernel/debug/pinctrl# cat pinctrl-handles
Requested pin control handlers their pinmux maps:

device: 30b40000.mmc current state: default
  state: default
    type: MUX_GROUP controller 30330000.pinctrl group: sd1_sd1_grp (7) function: myimx8mm (0)
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_CLK (40)config 00000190
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_CMD (41)config 000001d0
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_DATA0 (42)config 000001d0
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_DATA1 (43)config 000001d0
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_DATA2 (44)config 000001d0
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_DATA3 (45)config 000001d0
  state: state_100mhz
    type: MUX_GROUP controller 30330000.pinctrl group: sd1_sd1_100mhz_grp (8) function: myimx8mm (0)
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_CLK (40)config 00000194
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_CMD (41)config 000001d4
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_DATA0 (42)config 000001d4
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_DATA1 (43)config 000001d4
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_DATA2 (44)config 000001d4
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_DATA3 (45)config 000001d4
  state: state_200mhz
    type: MUX_GROUP controller 30330000.pinctrl group: sd1_sd1_200mhz_grp (9) function: myimx8mm (0)
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_CLK (40)config 00000196
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_CMD (41)config 000001d6
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_DATA0 (42)config 000001d6
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_DATA1 (43)config 000001d6
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_DATA2 (44)config 000001d6
    type: CONFIGS_PIN controller 30330000.pinctrl pin MX8MM_IOMUXC_SD1_DATA3 (45)config 000001d6
    ...

3. pinctrl-maps

root@imx8mmevk:/sys/kernel/debug/pinctrl# cat pinctrl-maps
...
device 30b60000.mmc
state default
type MUX_GROUP (2)
controlling device 30330000.pinctrl
group nand_usdhc3_grp
function myimx8mm

device 30b60000.mmc
state state_100mhz
type MUX_GROUP (2)
controlling device 30330000.pinctrl
group nand_usdhc3_100mhz_grp
function myimx8mm

device 30b60000.mmc
state state_200mhz
type MUX_GROUP (2)
controlling device 30330000.pinctrl
group nand_usdhc3_200mhz_grp
function myimx8mm
...

4. pinconf-groups
显示group的信息

root@imx8mmevk:/sys/kernel/debug/pinctrl/30330000.pinctrl# cat pinconf-groups
Pin config settings per pin group
Format: group (name): configs
0 (nand_gpioled_grp):
  MX8MM_IOMUXC_NAND_READY_B: 0x19

  ....

2 (nand_usdhc3_grp):
  MX8MM_IOMUXC_NAND_WE_B: 0x196
  MX8MM_IOMUXC_NAND_WP_B: 0x1d6
  MX8MM_IOMUXC_NAND_DATA04: 0x1d6
  MX8MM_IOMUXC_NAND_DATA05: 0x1d6
  MX8MM_IOMUXC_NAND_DATA06: 0x1d6
  MX8MM_IOMUXC_NAND_DATA07: 0x1d6
  MX8MM_IOMUXC_NAND_RE_B: 0x1d6
  MX8MM_IOMUXC_NAND_CE2: 0x1d6
  MX8MM_IOMUXC_NAND_CE3: 0x1d6
  MX8MM_IOMUXC_NAND_CLE: 0x1d6
  MX8MM_IOMUXC_NAND_CE1: 0x196

3 (nand_usdhc3_100mhz_grp):
  MX8MM_IOMUXC_NAND_WE_B: 0x196
  MX8MM_IOMUXC_NAND_WP_B: 0x1d6
  MX8MM_IOMUXC_NAND_DATA04: 0x1d6
  MX8MM_IOMUXC_NAND_DATA05: 0x1d6
  MX8MM_IOMUXC_NAND_DATA06: 0x1d6
  MX8MM_IOMUXC_NAND_DATA07: 0x1d6
  MX8MM_IOMUXC_NAND_RE_B: 0x1d6
  MX8MM_IOMUXC_NAND_CE2: 0x1d6
  MX8MM_IOMUXC_NAND_CE3: 0x1d6
  MX8MM_IOMUXC_NAND_CLE: 0x1d6
  MX8MM_IOMUXC_NAND_CE1: 0x196

4 (nand_usdhc3_200mhz_grp):
  MX8MM_IOMUXC_NAND_WE_B: 0x196
  MX8MM_IOMUXC_NAND_WP_B: 0x1d6
  MX8MM_IOMUXC_NAND_DATA04: 0x1d6
  MX8MM_IOMUXC_NAND_DATA05: 0x1d6
  MX8MM_IOMUXC_NAND_DATA06: 0x1d6
  MX8MM_IOMUXC_NAND_DATA07: 0x1d6
  MX8MM_IOMUXC_NAND_RE_B: 0x1d6
  MX8MM_IOMUXC_NAND_CE2: 0x1d6
  MX8MM_IOMUXC_NAND_CE3: 0x1d6
  MX8MM_IOMUXC_NAND_CLE: 0x1d6
  MX8MM_IOMUXC_NAND_CE1: 0x196
  ...

5. pingroups
显示group的信息,带有pin的编号

root@imx8mmevk:/sys/kernel/debug/pinctrl/30330000.pinctrl# cat pingroups
registered pin groups:
...
group: nand_usdhc3_grp
pin 78 (MX8MM_IOMUXC_NAND_WE_B)
pin 79 (MX8MM_IOMUXC_NAND_WP_B)
pin 71 (MX8MM_IOMUXC_NAND_DATA04)
pin 72 (MX8MM_IOMUXC_NAND_DATA05)
pin 73 (MX8MM_IOMUXC_NAND_DATA06)
pin 74 (MX8MM_IOMUXC_NAND_DATA07)
pin 76 (MX8MM_IOMUXC_NAND_RE_B)
pin 64 (MX8MM_IOMUXC_NAND_CE2)
pin 65 (MX8MM_IOMUXC_NAND_CE3)
pin 66 (MX8MM_IOMUXC_NAND_CLE)
pin 63 (MX8MM_IOMUXC_NAND_CE1)

group: nand_usdhc3_100mhz_grp
pin 78 (MX8MM_IOMUXC_NAND_WE_B)
pin 79 (MX8MM_IOMUXC_NAND_WP_B)
pin 71 (MX8MM_IOMUXC_NAND_DATA04)
pin 72 (MX8MM_IOMUXC_NAND_DATA05)
pin 73 (MX8MM_IOMUXC_NAND_DATA06)
pin 74 (MX8MM_IOMUXC_NAND_DATA07)
pin 76 (MX8MM_IOMUXC_NAND_RE_B)
pin 64 (MX8MM_IOMUXC_NAND_CE2)
pin 65 (MX8MM_IOMUXC_NAND_CE3)
pin 66 (MX8MM_IOMUXC_NAND_CLE)
pin 63 (MX8MM_IOMUXC_NAND_CE1)

group: nand_usdhc3_200mhz_grp
pin 78 (MX8MM_IOMUXC_NAND_WE_B)
pin 79 (MX8MM_IOMUXC_NAND_WP_B)
pin 71 (MX8MM_IOMUXC_NAND_DATA04)
pin 72 (MX8MM_IOMUXC_NAND_DATA05)
pin 73 (MX8MM_IOMUXC_NAND_DATA06)
pin 74 (MX8MM_IOMUXC_NAND_DATA07)
pin 76 (MX8MM_IOMUXC_NAND_RE_B)
pin 64 (MX8MM_IOMUXC_NAND_CE2)
pin 65 (MX8MM_IOMUXC_NAND_CE3)
pin 66 (MX8MM_IOMUXC_NAND_CLE)
pin 63 (MX8MM_IOMUXC_NAND_CE1)
...

6. pins
显示pin的信息

root@imx8mmevk:/sys/kernel/debug/pinctrl/30330000.pinctrl# cat pins
registered pins: 149
pin 0 (MX8MM_PAD_RESERVE0) 30330000.pinctrl
pin 1 (MX8MM_PAD_RESERVE1) 30330000.pinctrl
pin 2 (MX8MM_PAD_RESERVE2) 30330000.pinctrl
pin 3 (MX8MM_PAD_RESERVE3) 30330000.pinctrl
pin 4 (MX8MM_PAD_RESERVE4) 30330000.pinctrl
pin 5 (MX8MM_PAD_RESERVE5) 30330000.pinctrl
pin 6 (MX8MM_PAD_RESERVE6) 30330000.pinctrl
pin 7 (MX8MM_PAD_RESERVE7) 30330000.pinctrl
pin 8 (MX8MM_PAD_RESERVE8) 30330000.pinctrl
pin 9 (MX8MM_PAD_RESERVE9) 30330000.pinctrl
pin 10 (MX8MM_IOMUXC_GPIO1_IO00) 30330000.pinctrl
...
pin 148 (MX8MM_IOMUXC_UART4_TXD) 30330000.pinctrl

7. pinconf-pins
显示pin的配置

root@imx8mmevk:/sys/kernel/debug/pinctrl/30330000.pinctrl# cat pinconf-pins
imx8mm-pinctrl 30330000.pinctrl: Pin(MX8MM_PAD_RESERVE0) does not support config function
imx8mm-pinctrl 30330000.pinctrl: Pin(MX8MM_PAD_RESERVE1) does not support config function
imx8mm-pinctrl 30330000.pinctrl: Pin(MX8MM_PAD_RESERVE2) does not support config function
imx8mm-pinctrl 30330000.pinctrl: Pin(MX8MM_PAD_RESERVE3) does not support config function
...
imx8mm-pinctrl 30330000.pinctrl: Pin(MX8MM_IOMUXC_UART4_RXD) does not support config function
imx8mm-pinctrl 30330000.pinctrl: Pin(MX8MM_IOMUXC_UART4_TXD) does not support config function
Pin config settings per pin
Format: pin (name): configs
pin 0 (MX8MM_PAD_RESERVE0): N/A
pin 1 (MX8MM_PAD_RESERVE1): N/A
pin 2 (MX8MM_PAD_RESERVE2): N/A
pin 3 (MX8MM_PAD_RESERVE3): N/A
pin 4 (MX8MM_PAD_RESERVE4): N/A
pin 5 (MX8MM_PAD_RESERVE5): N/A
pin 6 (MX8MM_PAD_RESERVE6): N/A
pin 7 (MX8MM_PAD_RESERVE7): N/A
pin 8 (MX8MM_PAD_RESERVE8): N/A
pin 9 (MX8MM_PAD_RESERVE9): N/A
pin 10 (MX8MM_IOMUXC_GPIO1_IO00): 0x41
...
pin 148 (MX8MM_IOMUXC_UART4_TXD): N/A

8. pinmux-functions
显示functions的信息,该单板只有一个function-"myimx8mm"。

root@imx8mmevk:/sys/kernel/debug/pinctrl/30330000.pinctrl# cat pinmux-functions
function: myimx8mm, groups = [ nand_gpioled_grp nand_qspi0_grp nand_usdhc3_grp nand_usdhc3_100mhz_grp nand_usdhc3_200mhz_grp enet_enet1_grp sd1_gpio_grp sd1_sd1_grp sd1_sd1_100mhz_grp sd1_sd1_200mhz_grp sd2_pciewake_grp sd2_sd2gpio_grp sd2_sd2_grp sd2_sd2_100mhz_grp sd2_sd2_200mhz_grp i2c4_gpio_grp i2c1_i2c1_grp i2c2_i2c2_grp i2c3_i2c3_grp i2c4_pcieclk_grp uart1_uart1_grp uart3_uart3_grp uart2_uart2_grp saix_gpio_grp sai1_sai1_grp sai1_sai1dsd_grp sai2_gpio_grp sai2_tsio_grp sai2_dsi_rst_grp sai2_pcienrst_grp sai2_audnmute_grp sai3_sai3_grp sai5_sai5_grp sai5_pdm_grp spdif_spdif1_grp ecspi1_ecspi1_grp ecspi1_ecspi1ss_grp ecspi2_ecspi2_grp ecspi2_ecspi2ss_grp gpio_gpio_grp gpio1_gpio_grp gpio1_dsibl_grp gpio1_pmicnint_grp gpio1_pciendis_grp gpio1_csi_grp gpio1_csipwdn_grp gpio1_enetio_grp gpio1_ioexp_grp gpio1_irrecv_grp spi_can_int ]

9. pinmux-pins
显示pin的复用

root@imx8mmevk:/sys/kernel/debug/pinctrl/30330000.pinctrl# cat pinmux-pins
Pinmux settings per pin
Format: pin (name): mux_owner gpio_owner hog?
pin 0 (MX8MM_PAD_RESERVE0): (MUX UNCLAIMED) (GPIO UNCLAIMED)
...
pin 63 (MX8MM_IOMUXC_NAND_CE1): 30b60000.mmc (GPIO UNCLAIMED) function myimx8mm group nand_usdhc3_200mhz_grp
pin 64 (MX8MM_IOMUXC_NAND_CE2): 30b60000.mmc (GPIO UNCLAIMED) function myimx8mm group nand_usdhc3_200mhz_grp
pin 65 (MX8MM_IOMUXC_NAND_CE3): 30b60000.mmc (GPIO UNCLAIMED) function myimx8mm group nand_usdhc3_200mhz_grp
pin 66 (MX8MM_IOMUXC_NAND_CLE): 30b60000.mmc (GPIO UNCLAIMED) function myimx8mm group nand_usdhc3_200mhz_grp
pin 67 (MX8MM_IOMUXC_NAND_DATA00): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 68 (MX8MM_IOMUXC_NAND_DATA01): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 69 (MX8MM_IOMUXC_NAND_DATA02): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 70 (MX8MM_IOMUXC_NAND_DATA03): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 71 (MX8MM_IOMUXC_NAND_DATA04): 30b60000.mmc (GPIO UNCLAIMED) function myimx8mm group nand_usdhc3_200mhz_grp
pin 72 (MX8MM_IOMUXC_NAND_DATA05): 30b60000.mmc (GPIO UNCLAIMED) function myimx8mm group nand_usdhc3_200mhz_grp
pin 73 (MX8MM_IOMUXC_NAND_DATA06): 30b60000.mmc (GPIO UNCLAIMED) function myimx8mm group nand_usdhc3_200mhz_grp
pin 74 (MX8MM_IOMUXC_NAND_DATA07): 30b60000.mmc (GPIO UNCLAIMED) function myimx8mm group nand_usdhc3_200mhz_grp
pin 75 (MX8MM_IOMUXC_NAND_DQS): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 76 (MX8MM_IOMUXC_NAND_RE_B): 30b60000.mmc (GPIO UNCLAIMED) function myimx8mm group nand_usdhc3_200mhz_grp
pin 77 (MX8MM_IOMUXC_NAND_READY_B): leds (GPIO UNCLAIMED) function myimx8mm group nand_gpioled_grp
pin 78 (MX8MM_IOMUXC_NAND_WE_B): 30b60000.mmc (GPIO UNCLAIMED) function myimx8mm group nand_usdhc3_200mhz_grp
pin 79 (MX8MM_IOMUXC_NAND_WP_B): 30b60000.mmc (GPIO UNCLAIMED) function myimx8mm group nand_usdhc3_200mhz_grp
...
pin 148 (MX8MM_IOMUXC_UART4_TXD): (MUX UNCLAIMED) (GPIO UNCLAIMED)

10. pinconf-config
显示pin的配置,该单板实现为空,pin脚 的配置信息存放在pinconf-pins文件中

root@imx8mmevk:/sys/kernel/debug/pinctrl/30330000.pinctrl# cat pinconf-config
No config found for dev/state/pin, expected:
Searched dev:
Searched state:
Searched pin:
Use: modify config_pin <devname> <state> <pinname> <value>

优质参考文章

[1] pinctrl 子系统介绍

posted on 2023-08-02 21:47  BSP-路人甲  阅读(522)  评论(0编辑  收藏  举报

导航