Pinctrl子系统

基于MainLine Kernel(6.15-rc1) Pinctrl子系统

一、基本数据结构

1. pinctroller

pinctrl_dev 与 pinctrl_desc

struct pinctrl_dev { 
	struct list_head node;
	struct pinctrl_desc *desc;
	struct radix_tree_root pin_desc_tree;
#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
	struct radix_tree_root pin_group_tree;
	unsigned int num_groups;
#endif
#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
	struct radix_tree_root pin_function_tree;
	unsigned int num_functions;
#endif
	struct 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_FS
	struct dentry *device_root;
#endif
}

##########################################
##########################################

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_PINCONF
	unsigned int num_custom_params;
	const struct pinconf_generic_params *custom_params;
	const struct pin_config_item *custom_conf_items;
#endif
	bool link_consumers;
};

我们进入到驱动目录里 drivers\pinctrl\freescale\pinctrl-imx.c 的 .probe函数

int imx_pinctrl_probe(struct platform_device *pdev,
		      const struct imx_pinctrl_soc_info *info)
{
	struct regmap_config config = { .name = "gpr" };
	struct device_node *dev_np = pdev->dev.of_node;
	struct pinctrl_desc *imx_pinctrl_desc;
	struct device_node *np;
	struct imx_pinctrl *ipctl;
	struct regmap *gpr;
	int ret, i;
	...
	imx_pinctrl_desc->name = dev_name(&pdev->dev);
	imx_pinctrl_desc->pins = info->pins;
	imx_pinctrl_desc->npins = info->npins;
	imx_pinctrl_desc->pctlops = &imx_pctrl_ops;
	imx_pinctrl_desc->pmxops = &imx_pmx_ops;
	imx_pinctrl_desc->confops = &imx_pinconf_ops;
	imx_pinctrl_desc->owner = THIS_MODULE;
	...
}

其中比较重要的,struct pctlops 、struct pmxops,pinconf_ops,我们看看他们的结构体时怎么构造的

struct pinctrl_ops {
	int (*get_groups_count) (struct pinctrl_dev *pctldev);
	const char *(*get_group_name) (struct pinctrl_dev *pctldev,
				       unsigned int selector);
	int (*get_group_pins) (struct pinctrl_dev *pctldev,
			       unsigned int selector,
			       const unsigned int **pins,
			       unsigned int *num_pins);
	void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,
			      unsigned int offset);
	int (*dt_node_to_map) (struct pinctrl_dev *pctldev,
			       struct device_node *np_config,
			       struct pinctrl_map **map, unsigned int *num_maps);
	void (*dt_free_map) (struct pinctrl_dev *pctldev,
			     struct pinctrl_map *map, unsigned int num_maps);
};

##################################

struct pinmux_ops {
	int (*request) (struct pinctrl_dev *pctldev, unsigned int offset);
	int (*free) (struct pinctrl_dev *pctldev, unsigned int offset);
	int (*get_functions_count) (struct pinctrl_dev *pctldev);
	const char *(*get_function_name) (struct pinctrl_dev *pctldev,
					  unsigned int selector);
	int (*get_function_groups) (struct pinctrl_dev *pctldev,
				    unsigned int selector,
				    const char * const **groups,
				    unsigned int *num_groups);
	int (*set_mux) (struct pinctrl_dev *pctldev, unsigned int func_selector,
			unsigned int group_selector);
	int (*gpio_request_enable) (struct pinctrl_dev *pctldev,
				    struct pinctrl_gpio_range *range,
				    unsigned int offset);
	.....
};

#############################################
struct pinconf_ops {
#ifdef CONFIG_GENERIC_PINCONF
	bool is_generic;
#endif
	int (*pin_config_get) (struct pinctrl_dev *pctldev,
			       unsigned int pin,
			       unsigned long *config);
	int (*pin_config_set) (struct pinctrl_dev *pctldev,
			       unsigned int pin,
			       unsigned long *configs,
			       unsigned int num_configs);
	int (*pin_config_group_get) (struct pinctrl_dev *pctldev,
				     unsigned int selector,
				     unsigned long *config);
	int (*pin_config_group_set) (struct pinctrl_dev *pctldev,
				     unsigned int selector,
				     unsigned long *configs,
				     unsigned int num_configs);
	...
};

首先来解释为什么要有 pinctrl_ops 这么一个结构体呢?我们可以看到 struct pinctrl_desc 里有这么两个属性

const struct pinctrl_pin_desc *pins;
unsigned int npins;

struct pinctrl_pin_desc {
unsigned int number;
const char *name;
void *drv_data;
};

这两个属性都是用来描述单个引脚的,而看 pinctrl_ops 提供的函数,可以获得多个group里的pin信息(提供 groups、pins、group和pin之间的组织关系)。

然后再来看 pinmux_ops 结构体,比较重要的函数就是他就是set_mux(),来把 pinctrl_ops 获取 的 描述信息去设置mux寄存器(复用为什么功能,GPIO、UART、SPI之类)。

可以理解为:

驱动请求(pinctrl_select_state)
    ↓
根据设备树找 pinctrl state
    ↓
根据 pctlops 描述,找到对应的 group(s)
    ↓
调用 pmxops->set_mux,把 pins 设置到正确的功能

最后就是 pinconf_ops ,它的作用是配置 pin 的电气属性(上拉、下拉、驱动强度等)。

以上就是pinctroller端的基本数据结构.

2.注册函数

struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
				    struct device *dev, void *driver_data);

可以看到参数是一个 struct pinctrl_desc,而返回值是 struct pinctrl_dev,以后就用 pinctrl_dev 来描述一个 pincontroller。

 pinctrl_flexcan1: flexcan1grp {
         fsl,pins = <
                 MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX      0x1b020
                 MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX      0x1b020
         >;
};

上面分析的数据结构都是来描述这个 pincontroller.

4.pinctrl client

但是我们在使用中还有一个client,这部分是怎么描述的?

先看在dtb中的编写:通过 pinctrl-names 的属性来选择 pin要配置为什么模式。

device {
        pinctrl-names = "default","sleep";
        pinctrl-0 = <&pinctrl_device0>;
        pinctrl-1 = <&pinctrl_device1>;
};

首先设备树会被编译成 platform_device结构体(不全是,比如i2c_client),但是里面都会有一个 device 结构体。

struct platform_device {
	const char	*name;
	int		id;
	bool		id_auto;
	struct device	dev;           《--------------
	u64		platform_dma_mask;
	....
};
struct i2c_client {
	...
	struct i2c_adapter *adapter;	/* the adapter we sit on	*/
	struct device dev;		/* the device structure		*/               《--------------
	int init_irq;			/* irq set at initialization	*/
	int irq;			/* irq issued by device		*/
	struct list_head detected;
	...
};

所以不管被编译为什么结构体,最终都汇聚到这个 struct device 来和 pinctrl 挂钩。

struct device {
	...
	void		*platform_data;	/* Platform specific data, device
					   core doesn't touch it */
	void		*driver_data;	/* Driver data, set and get with
					   dev_set_drvdata/dev_get_drvdata */
	struct mutex		mutex;	/* mutex to synchronize calls to
					 * its driver.
					 */

    #ifdef CONFIG_PINCTRL
        struct dev_pin_info	*pins;            <-------------------------
    #endif
        struct dev_msi_info	msi;
    #ifdef CONFIG_ARCH_HAS_DMA_OPS
        const 
     ...
}

就是通过 struct dev_pin_info *pins 和 pinctrl 挂钩的。

4.1struct dev_pin_info

这个结构体只在需要使用pinctrl 子系统时构造。

可以看出这几个 pinctrl_state 结构体都是由 dtb中的 pinctrl client 的 pinctrl-names 属性构造的。

struct dev_pin_info {
	/* 存放自己添加的状态 */
	struct pinctrl *p;		
	
	struct pinctrl_state *default_state;
	struct pinctrl_state *init_state;
#ifdef CONFIG_PM
	struct pinctrl_state *sleep_state;
	struct pinctrl_state *idle_state;
#endif
};
4.2自定义状态

则都是几种常用的状态,那么有没有方法让我们自定义状态呢?

有的兄弟,有的。

我们自定义的状态会放在 struct pinctrl *p 里的 struct list_head states 链表里,(关于解析部分之后分析)。

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;
};
4.3pinctrl_map 和 pinctrl_setting

当我们的pinctrl cliend 想要去使用pinctrl,是通过 struct dev_pin_info 去建立联系的,那么我们 pinctroller 的设备节点也得需要去保存到这个结构体里。

还记得 pctlops 吗,就是它来解析的,它是来处理一组引脚的。这个结构体里有一个函数 dt_node_to_map().

int (*dt_node_to_map) (struct pinctrl_dev *pctldev,
               struct device_node *np_config,
               struct pinctrl_map **map, unsigned int *num_maps);

就是来把设备树节点转换为一系列的 pinctrl_map 结构体。

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_map —> struct pinctrl_setting ,去配置这些引脚的功能。

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 pinctrl_state {
	struct list_head node;
	const char *name;
	struct list_head settings;
};

这个 struct pinctrl_setting又存放在 pinctrl_state.settings里,以后让这个设备位于某个状态时,就会根据这些 .settings来设置引脚。

(map —>setting 这部分是内核的工作,想了解可以查看 drivers\pinctrl\core.c)

pinctrl_get()
	create_pinctrl()
		pinctrl_dt_to_map()
		add_setting()
4.4操作流程

看一下怎么来根据 .setting 来设置引脚的,进入内核目录 drivers\base\dd.c,查看 really_probe() 函数。

static int really_probe(struct device *dev, const struct device_driver *drv)
{
	bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) &&
			   !drv->suppress_bind_attrs;
	int ret, link_ret;
	...
	/* If using pinctrl, bind pins now before probing */
	ret = pinctrl_bind_pins(dev);    <-----------------
	if (ret)
		goto pinctrl_bind_failed;
}

会看到有一个 pinctrl_bind_pins(),进入查看

int pinctrl_bind_pins(struct device *dev)
{
	...
    if (IS_ERR(dev->pins->init_state)) {
    /* Not supplying this state is perfectly legal */
    dev_dbg(dev, "no init pinctrl state\n");

    ret = pinctrl_select_state(dev->pins->p,
                   dev->pins->default_state);
	} else {
		ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
	}
	...
}

找到一个选择状态函数 pinctrl_select_state(),接着进入

int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
{
	if (p->state == state)
		return 0;

	return pinctrl_commit_state(p, state);   <-------------
}

这里会判断一下初始化的状态是否正常,接着进入 pinctrl_commit_state().

static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state)
{
	struct pinctrl_setting *setting;
	struct pinctrl_state *old_state = READ_ONCE(p->state);
	int ret;
	...
	/* Apply all the settings for the new state - pinmux first */
	list_for_each_entry(setting, &state->settings, node) {         <-------------
		switch (setting->type) {
		case PIN_MAP_TYPE_MUX_GROUP:
			ret = pinmux_enable_setting(setting);
			break;
		case PIN_MAP_TYPE_CONFIGS_PIN:
		case PIN_MAP_TYPE_CONFIGS_GROUP:
			ret = 0;   //跳过
			break;
		default:
			ret = -EINVAL;
			break;
		}

		if (ret < 0)
			goto unapply_new_state;

		/* Do not link hogs (circular dependency) */
		if (p != setting->pctldev->p)
			pinctrl_link_add(setting->pctldev, p->dev);
	}

	/* Apply all the settings for the new state - pinconf after */
	list_for_each_entry(setting, &state->settings, node) {				 <-------------
		switch (setting->type) {
		case PIN_MAP_TYPE_MUX_GROUP:
			ret = 0;   // mux 已完成,跳过
			break;
		case PIN_MAP_TYPE_CONFIGS_PIN:
		case PIN_MAP_TYPE_CONFIGS_GROUP:
			ret = pinconf_apply_setting(setting);
			break;
		default:
			ret = -EINVAL;
			break;
		}
		...
}

有两个switch 语句,这样分布的机制就是为了保证在做 config 设置前,引脚已经正确映射到目标功能(比如 UART1_TX),否则如果 pin 还处于 GPIO 模式,你设置电平、上拉下拉等都没有意义。

根据 setting->type 来执行相应的配置函数,对于mux部分执行 pinmux_enable_setting(),最终调用到了 set_mux 函数来配置引脚的复用。

int pinmux_enable_setting(const struct pinctrl_setting *setting)
{
	struct pinctrl_dev *pctldev = setting->pctldev;
	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
	const struct pinmux_ops *ops = pctldev->desc->pmxops;
	...
		ret = ops->set_mux(pctldev, setting->data.mux.func,
			   setting->data.mux.group);
	...
}

对于 config 部分执行 pinconf_apply_setting(),最终调用到了 pin_config_group_set().

int pinconf_apply_setting(const struct pinctrl_setting *setting)
{
	struct pinctrl_dev *pctldev = setting->pctldev;
	const struct pinconf_ops *ops = pctldev->desc->confops;
	int ret;
	...
    ret = ops->pin_config_group_set(pctldev,
        setting->data.configs.group_or_pin,
        setting->data.configs.configs,
        setting->data.configs.num_configs);
	...
}

根据之前在.probe 分配注册的函数,就是在这里被执行的.

二、DTB解析

1.pincontroller

3.1首先是描述、获得引脚

打开内核源码目录 drivers\pinctrl\freescale\pinctrl-imx6ul.c

static const struct of_device_id imx6ul_pinctrl_of_match[] = {
	{ .compatible = "fsl,imx6ul-iomuxc", .data = &imx6ul_pinctrl_info, },
	{ .compatible = "fsl,imx6ull-iomuxc-snvs", .data = &imx6ull_snvs_pinctrl_info, },
	{ /* sentinel */ }
};
static struct platform_driver imx6ul_pinctrl_driver = {
	.driver = {
		.name = "imx6ul-pinctrl",
		.of_match_table = imx6ul_pinctrl_of_match,
		.suppress_bind_attrs = true,
	},
	.probe = imx6ul_pinctrl_probe,
};

static int imx6ul_pinctrl_probe(struct platform_device *pdev)
{
	const struct imx_pinctrl_soc_info *pinctrl_info;

	pinctrl_info = of_device_get_match_data(&pdev->dev);
	if (!pinctrl_info)
		return -ENODEV;

	return imx_pinctrl_probe(pdev, pinctrl_info);
}

可以看到 platform_driver 支持 “fsl,imx6ul-iomuxc”、"fsl,imx6ull-iomuxc-snvs"这两个平台设备,然后再probe函数调用 imx_pinctrl_probe

进入到 imx_pinctrl_probe(pdev, pinctrl_info)

int imx_pinctrl_probe(struct platform_device *pdev,
		      const struct imx_pinctrl_soc_info *info)
{
	struct regmap_config config = { .name = "gpr" };
	struct device_node *dev_np = pdev->dev.of_node;
	struct pinctrl_desc *imx_pinctrl_desc;
	struct device_node *np;
	struct imx_pinctrl *ipctl;
	struct regmap *gpr;
	int ret, i;
	...
	imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc),
					GFP_KERNEL);
	if (!imx_pinctrl_desc)
		return -ENOMEM;

	imx_pinctrl_desc->name = dev_name(&pdev->dev);
	imx_pinctrl_desc->pins = info->pins;
	imx_pinctrl_desc->npins = info->npins;
	imx_pinctrl_desc->pctlops = &imx_pctrl_ops;
	imx_pinctrl_desc->pmxops = &imx_pmx_ops;
	imx_pinctrl_desc->confops = &imx_pinconf_ops;
	imx_pinctrl_desc->owner = THIS_MODULE;
	...
	
	...
	ret = imx_pinctrl_probe_dt(pdev, ipctl);
	...
}

看重点,这里就是在构造一个 pinctrl_desc 的结构体。

那么引脚是怎么获得的呢?

3.2解析设备树

进入 imx_pinctrl_probe_dt()

static int imx_pinctrl_probe_dt(struct platform_device *pdev,
				struct imx_pinctrl *ipctl)
{
	struct device_node *np = pdev->dev.of_node;
	struct device_node *child;
	struct pinctrl_dev *pctl = ipctl->pctl;
	u32 nfuncs = 0;
	u32 i = 0;
	bool flat_funcs;

	if (!np)
		return -ENODEV;
	/* 判断设备树结构是不是 flat 模式 */
	flat_funcs = imx_pinctrl_dt_is_flat_functions(np);
	if (flat_funcs) {
		nfuncs = 1;
	} else {
		/* 获得有多少个function (多少个子节点) */
		nfuncs = of_get_child_count(np);
		if (nfuncs == 0) {
			dev_err(&pdev->dev, "no functions defined\n");
			return -EINVAL;
		}
	}

	/* 对于每一个function(子节点) 都会去分配一个 function_desc 结构体*/
	for (i = 0; i < nfuncs; i++) {
		struct function_desc *function;

		function = devm_kzalloc(&pdev->dev, sizeof(*function),
					GFP_KERNEL);
		if (!function)
			return -ENOMEM;
		
		mutex_lock(&ipctl->mutex);
		radix_tree_insert(&pctl->pin_function_tree, i, function);
		mutex_unlock(&ipctl->mutex);
	}
	pctl->num_functions = nfuncs;

	ipctl->group_index = 0;
	if (flat_funcs) {
		pctl->num_groups = of_get_child_count(np);
	} else {
		pctl->num_groups = 0;
		for_each_child_of_node(np, child)
			/* 计算子function下又有多少个group(子节点)*/
			pctl->num_groups += of_get_child_count(child);
	}

	if (flat_funcs) {
		imx_pinctrl_parse_functions(np, ipctl, 0);
	} else {
		i = 0;
		for_each_child_of_node(np, child)
			imx_pinctrl_parse_functions(child, ipctl, i++);
	}

	return 0;
}

最终调用 imx_pinctrl_parse_functions(),从设备树中提取每个 function 下的 group 和 pins,解析结构体并缓存。

补充:这里多次判断了 flat_funcs 这个值,设备树有两种组织形式:

(1)Flat 模式:所有 group 都直接定义在顶层 iomuxc 节点下

pinctrl@20e0000 {
    pinctrl_uart1: uart1grp {
        fsl,pins = <...>;
    };
    pinctrl_i2c1: i2c1grp {
        fsl,pins = <...>;
    };
};

(2)Function 分组模式(非 flat):顶层为 function,function 下再分 group

pinctrl@20e0000 {
    uart1 {
        uart1grp {
            fsl,pins = <...>;
        };
    };
    i2c1 {
        i2c1grp {
            fsl,pins = <...>;
        };
    };
};

接着来看具体怎么解析的,首先是 function

static int imx_pinctrl_parse_functions(struct device_node *np,
                           struct imx_pinctrl *ipctl,
				       u32 index)
{
	struct pinctrl_dev *pctl = ipctl->pctl;
	struct function_desc *func;
	struct group_desc *grp;
	const char **group_names;
	u32 i;

	dev_dbg(pctl->dev, "parse function(%d): %pOFn\n", index, np);

	func = pinmux_generic_get_function(pctl, index);
	if (!func)
		return -EINVAL;

	/* Initialise function */
	/* 设置为设备树 function 节点名 */
	func->func.name = np->name;
	/*  该 function 下有几个 group */
	func->func.ngroups = of_get_child_count(np);
	if (func->func.ngroups == 0) {
		dev_info(ipctl->dev, "no groups defined in %pOF\n", np);
		return -EINVAL;
	}
	/* 分配 group 名称数组,稍后填入所有 group 的名字 */
	group_names = devm_kcalloc(ipctl->dev, func->func.ngroups,
				   sizeof(*func->func.groups), GFP_KERNEL);
	if (!group_names)
		return -ENOMEM;
	i = 0;
	/* 将每个子 group 的名字填入 groups 数组,用于 framework 调用 pinmux_enable_setting() 时识别 group */
	for_each_child_of_node_scoped(np, child)
		group_names[i++] = child->name;
	func->func.groups = group_names;

	i = 0;
	/*  遍历每个 group,注册到 pinctrl */
	for_each_child_of_node_scoped(np, child) {
		grp = devm_kzalloc(ipctl->dev, sizeof(*grp), GFP_KERNEL);
		if (!grp)
			return -ENOMEM;

		mutex_lock(&ipctl->mutex);
		radix_tree_insert(&pctl->pin_group_tree,
				  ipctl->group_index++, grp);
		mutex_unlock(&ipctl->mutex);
		/* 进一步解析 fsl,pins 属性 */
		imx_pinctrl_parse_groups(child, grp, ipctl, i++);
	}

	return 0;
}

对于每个 function 都会解析成一个 function_desc 结构体

struct function_desc {
	struct pinfunction func;
	void *data;
};

struct pinfunction {
	const char *name;
	const char * const *groups;
	size_t ngroups;
};

然后再通过 imx_pinctrl_parse_groups() 将每个group 解析为一个 group_desc 结构体

struct group_desc {
	struct pingroup grp;
	void *data;
};
struct pingroup {
	const char *name;
	const unsigned int *pins;
	size_t npins;
};

进入imx_pinctrl_parse_groups()

static int imx_pinctrl_parse_groups(struct device_node *np,
				    struct group_desc *grp,
				    struct imx_pinctrl *ipctl,
				    u32 index)
{
	const struct imx_pinctrl_soc_info *info = ipctl->info;
	struct imx_pin *pin;
	unsigned int *pins;
	int size, pin_size;
	const __be32 *list;
	int i;
	...
	
    for (i = 0; i < grp->grp.npins; i++) {
    pin = &((struct imx_pin *)(grp->data))[i];
    if (info->flags & IMX_USE_SCU)
        info->imx_pinctrl_parse_pin(ipctl, &pins[i], pin, &list);
    else
    	/* 解析单个引脚 */
        imx_pinctrl_parse_pin_mmio(ipctl, &pins[i], pin, &list, np);
	}
}

这里又出现一个 struct imx_pin ,因为不管这一组group里有多少个pin,最终都是一个一个来解析的。

struct imx_pin {
	unsigned int pin;
	union {
		struct imx_pin_mmio mmio;
		struct imx_pin_scu scu;
	} conf;
};

进入 imx_pinctrl_parse_pin_mmio()

static void imx_pinctrl_parse_pin_mmio(struct imx_pinctrl *ipctl,
				       unsigned int *pin_id, struct imx_pin *pin,
				       const __be32 **list_p,
				       struct device_node *np)
{
	const struct imx_pinctrl_soc_info *info = ipctl->info;
	struct imx_pin_mmio *pin_mmio = &pin->conf.mmio;
	struct imx_pin_reg *pin_reg;
	const __be32 *list = *list_p;
	u32 mux_reg, conf_reg;
	u32 config;

	mux_reg = be32_to_cpu(*list++);

	if (!(info->flags & ZERO_OFFSET_VALID) && !mux_reg)
		mux_reg = -1;

	if (info->flags & SHARE_MUX_CONF_REG) {
		conf_reg = mux_reg;
	} else {
		conf_reg = be32_to_cpu(*list++);
		if (!conf_reg)
			conf_reg = -1;
	}

	*pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4;
	pin_reg = &ipctl->pin_regs[*pin_id];
	pin->pin = *pin_id;
	pin_reg->mux_reg = mux_reg;
	pin_reg->conf_reg = conf_reg;
	pin_mmio->input_reg = be32_to_cpu(*list++);
	pin_mmio->mux_mode = be32_to_cpu(*list++);
	pin_mmio->input_val = be32_to_cpu(*list++);

	config = be32_to_cpu(*list++);

	/* SION bit is in mux register */
	if (config & IMX_PAD_SION)
		pin_mmio->mux_mode |= IOMUXC_CONFIG_SION;
	pin_mmio->config = config & ~IMX_PAD_SION;

	*list_p = list;

	dev_dbg(ipctl->dev, "%s: 0x%x 0x%08lx", info->pins[*pin_id].name,
			     pin_mmio->mux_mode, pin_mmio->config);
}

这里可以清楚的看到,就是根据设备树的信息来记录寄存器的值,这些信息到保存到了 struct imx_pin_mmio 里。

三、pinctrl cliend使用过程

只要它是一个设备,那么就会和一个相对应的驱动去匹配,在匹配之前会调用一个 really_probe().

static int really_probe(struct device *dev, const struct device_driver *drv)
{
	...
	/* If using pinctrl, bind pins now before probing */
	ret = pinctrl_bind_pins(dev);
	...	
}
int pinctrl_bind_pins(struct device *dev)
{
	/* 上面提到的map to setting */
	dev->pins->p = devm_pinctrl_get(dev);              <------------------------------
	if (IS_ERR(dev->pins->p)) {
		dev_dbg(dev, "no pinctrl handle\n");
		ret = PTR_ERR(dev->pins->p);
		goto cleanup_alloc;
	}
	dev->pins->init_state = pinctrl_lookup_state(dev->pins->p,	 
					PINCTRL_STATE_INIT);
	if (IS_ERR(dev->pins->init_state)) {
		/* Not supplying this state is perfectly legal */
		dev_dbg(dev, "no init pinctrl state\n");
		
		/* 需要在转换之后去使用 */
		ret = pinctrl_select_state(dev->pins->p,			<------------------------------
					   dev->pins->default_state);
	} else {
		ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
	}
	
	...
}

进入 pinctrl_select_state()

pinctrl_select_state()
	pinctrl_commit_state()
static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state)
{
	...
	/* Apply all the settings for the new state - pinmux first */
	list_for_each_entry(setting, &state->settings, node) {
		switch (setting->type) {
		case PIN_MAP_TYPE_MUX_GROUP:
			ret = pinmux_enable_setting(setting);
			break;
		case PIN_MAP_TYPE_CONFIGS_PIN:
		case PIN_MAP_TYPE_CONFIGS_GROUP:
			ret = 0;
			break;
		default:
			ret = -EINVAL;
			break;
		}
		/* Apply all the settings for the new state - pinconf after */
	list_for_each_entry(setting, &state->settings, node) {
		switch (setting->type) {
		case PIN_MAP_TYPE_MUX_GROUP:
			ret = 0;
			break;
		case PIN_MAP_TYPE_CONFIGS_PIN:
		case PIN_MAP_TYPE_CONFIGS_GROUP:
			ret = pinconf_apply_setting(setting);
			break;
		default:
			ret = -EINVAL;
			break;
		}
		...
}

这个宏定义在哪里被设置的呢?

就是在最开始的 dt_node_to_map()里

static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
			struct device_node *np,
			struct pinctrl_map **map, unsigned *num_maps)
{
	...
	new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
	new_map[0].data.mux.function = parent->name;
	new_map[0].data.mux.group = np->name;
	of_node_put(parent);
	
    new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
    new_map[j].data.configs.group_or_pin =
    pin_get_name(pctldev, pin->pin);
    ...
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值