pinctrl子系统(四):pin group信息按state进行保存

pin state:pinctrl-names的真相

pinctrl(三)讲解的是将iomuxc当中的所有pin信息解析并存储起来。而每个外设使用一组或多组pin,每个pin state对应一组或多组pin group,根据pin state存储pin group信息。

iomuxc节点
  • 存储全部所需的引脚配置信息
  • "虚拟"外设
    • 设置pin state数量和类型
    • 设置状态对应的pin group

pin state->pin group,一对多

pin group->pin,一对多

pinctl_map

存储外设所有state下pin group的配置信息

函数层次分析

pinctrl_enable()->pinctrl_claim_hogs()

  • create_pinctrl

    ----------------------------------------------第一部分-------------------------------------

    • pinctrl_dt_to_map()

      • for (state = 0; ; state++):查找外设所有pin group的状态

        • for (config = 0; config < size; config++):查找状态的所有引脚组

          ------------------------------第二部分-------------------------------------

          • dt_to_map_one_config

            • 创建一个pinctrl_map,负责初始化引脚组的所有引脚复用

            • 创建多个pinctrl_map,每个pinctrl_map负责配置引脚中的一个引脚属性

    ----------------------------------------------第三部分-------------------------------------

    • add_setting
pinctrl_enable()函数

drivers/pinctrl/core.c

int pinctrl_enable(struct pinctrl_dev *pctldev)
{
	int error;

	error = pinctrl_claim_hogs(pctldev);
	...
	//将pctldev加入全局链表
	list_add_tail(&pctldev->node, &pinctrldev_list);
	...
	return 0;
}
pinctrl_claim_hogs()函数

drivers/pinctrl/core.c

static int pinctrl_claim_hogs(struct pinctrl_dev *pctldev)
{
	
	pctldev->p = create_pinctrl(pctldev->dev, pctldev);
	
	//第四部分(真正设置引脚状态)
	pctldev->hog_default =
		pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);
	if (IS_ERR(pctldev->hog_default)) {
		dev_dbg(pctldev->dev,
			"failed to lookup the default state\n");
	} else {
		//设置为default状态
		if (pinctrl_select_state(pctldev->p,
					 pctldev->hog_default))
			dev_err(pctldev->dev,
				"failed to select default state\n");
	}
	...
	pctldev->hog_sleep =
		pinctrl_lookup_state(pctldev->p,
		
	...
}
create_pinctrl()函数

drivers/pinctrl/core.c

static struct pinctrl *create_pinctrl(struct device *dev,
				      struct pinctrl_dev *pctldev)
{
	struct pinctrl *p;
	const char *devname;
	struct pinctrl_maps *maps_node;
	int i;
	const struct pinctrl_map *map;
	int ret;
	
	p = kzalloc(sizeof(*p), GFP_KERNEL);
	...
	p->dev = dev; //iomuxc设备device结构体
	INIT_LIST_HEAD(&p->states);//初始化链表节点
	INIT_LIST_HEAD(&p->dt_maps);
	//第一部分
	ret = pinctrl_dt_to_map(p, pctldev);
	
	devname = dev_name(dev);
	...
	for_each_maps(maps_node, i, map) {
		/* Map must be for this device */
		if (strcmp(map->dev_name, devname))
			continue;
			
        if (pctldev &&
            strcmp(dev_name(pctldev->dev), map->ctrl_dev_name))
            continue;
		//第三部分
		ret = add_setting(p, pctldev, map);
		...
	}
	...
	list_add_tail(&p->node, &pinctrl_list);
	...
}
pinctrl_dt_to_map()函数

drivers/pinctrl/devicetree.c

int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev)
{
	/*iomux节点*/
	struct device_node *np = p->dev->of_node;//iomuxc节点的of_node
	int state, ret;
	char *propname;
	struct property *prop;
	const char *statename;
	const __be32 *list;
	int size, config;
	phandle phandle;
	struct device_node *np_config;
	
	...
	for (state = 0; ; state++) {
		propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);//这里就是pinctrl-0、1...写入到propname当中
		prop = of_find_property(np, propname, &size);//根据属性名字查找对应属性,同时将属性的引脚组的总大小记录到size当中
		kfree(propname);
		
		if (!prop) {//如果属性都被找完,就会break结束for循环的执行
			if (state == 0) {
				of_node_put(np);
				return -ENODEV;
			}
			break;
		}
		list = prop->value;//首先取出了value值,value值就是各个引脚组子节点的地址即pinctrl-0 = <&pinctrl_hog_1>;中的pinctrl_hog_1也称作句柄
		//获取当前state中的group数量,用总大小除以一个引脚组的大小获取group数量
		size /= sizeof(*list);
		
		ret = of_property_read_string_index(np, "pinctrl-names",state, &statename);//读取pinctrl-name当中的状态值,是根据state大小读取的,pinctrl-names = "default","init","sleep";比如state为0的时候读取到statename的值是default
		...
		for (config = 0; config < size; config++) {
		//句柄
		phandle = be32_to_cpup(list++);
		//根据句柄查找子节点
		//根据句柄地址找到对应grp子节点此时np_config指向pinctrl_uart1
		np_config = of_find_node_by_phandle(phandle);
		
		ret = dt_to_map_one_config(p, pctldev, statename,
						   np_config);
		...
		}
   ...
}
dt_to_map_one_config()函数

drivers/pinctrl/devicetree.c

static int dt_to_map_one_config(struct pinctrl *p,
				struct pinctrl_dev *hog_pctldev,
				const char *statename,
				struct device_node *np_config)
{
	struct pinctrl_dev *pctldev = NULL;
	struct device_node *np_pctldev;
	const struct pinctrl_ops *ops;
	int ret;
	struct pinctrl_map *map;
	unsigned num_maps;
	bool allow_default = false;
	
	np_pctldev = of_node_get(np_config);//将np_config赋值给了np_pctldev,即grp子节点
	
	for (;;) {
	/*iomuxc节点*/	
	np_pctldev = of_get_next_parent(np_pctldev);//获取子节点的父节点,即iomuxc节点

	if (hog_pctldev && (np_pctldev == p->dev->of_node)) {//这个条件肯定是成立的
			pctldev = hog_pctldev;//pctldev指向pinctrl_dev节点
			break;
		}
	
	pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
	
	if (pctldev)
		break;
	}
	...
	//imx_pctrl_ops
	ops = pctldev->desc->pctlops;
	...
	//imx_dt_node_to_map
	ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);
	...
	return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
}

pinctl_map:引脚三千,只取一瓢

pinctrl_map数组//存放引脚组所有引脚的配置信息
  • pin group配置信息

    • pinctrl_map[0]:配置pin group的所有引脚复用

    • pinctrl_map[1~n]:配置pin group的每个引脚的属性

imx_dt_node_to_map()函数

drivers/pinctrl/freescale/pinctrl-imx.c

static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
			struct device_node *np,//group子节点
			struct pinctrl_map **map//构造一个map数组
			, unsigned *num_maps)
{
	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
	//从pinctrl_dev中获取imx_pinctrl
	const struct imx_pinctrl_soc_info *info = ipctl->info;
	const struct group_desc *grp;
	struct pinctrl_map *new_map;
	struct device_node *parent;
	int map_num = 1;
	int i, j;
	//通过group的name查找pinctrl基数树当中的group_desc
	grp = imx_pinctrl_find_group_by_name(pctldev, np->name);
	
	if (info->flags & IMX8_USE_SCU) {
		map_num += grp->num_pins;
	} else {
		for (i = 0; i < grp->num_pins; i++) {//遍历grp当中的所有pin取出对应的pin
			struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];

			if (!(pin->pin_conf.pin_memmap.config & IMX_NO_PAD_CTL))
				map_num++;
				//条件一定成立,因此map_num的值就等于所有pin的数量了
		}
	}
	
	new_map = kmalloc_array(map_num, sizeof(struct pinctrl_map),
				GFP_KERNEL);
				
	*map = new_map;
	*num_maps = map_num;
	
	 /*iomuxc节点*/
	 parent = of_get_parent(np);//获取节点的父节点
	 ...
	 //第一个map存储复用寄存器
	 new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
	 new_map[0].data.mux.function = parent->name;//将function赋值为parent的名字
	 new_map[0].data.mux.group = np->name;//将group赋值为子节点group的名字
	 ..
	 new_map++;//new_map指向第一个元素了
	 
	 for (i = j = 0; i < grp->num_pins; i++) {
		struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];

		if (info->flags & IMX8_USE_SCU) {
			new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
			new_map[j].data.configs.group_or_pin =
					pin_get_name(pctldev, pin->pin);
			new_map[j].data.configs.configs =
					(unsigned long *)&pin->pin_conf.pin_scu;
			new_map[j].data.configs.num_configs = 2;
			j++;
		} else if (!(pin->pin_conf.pin_memmap.config & IMX_NO_PAD_CTL)) {
			new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
			new_map[j].data.configs.group_or_pin =
					pin_get_name(pctldev, pin->pin);
					//返回引脚对应的名字
			new_map[j].data.configs.configs =
					&pin->pin_conf.pin_memmap.config;//保存了mux_reg当中的属性值
			new_map[j].data.configs.num_configs = 1;
			j++;
		}
	}
	...
}

在这里插入图片描述

dt_remember_or_free_map()函数

drivers/pinctrl/devicetree.c

static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,struct pinctrl_dev *pctldev,struct pinctrl_map *map, unsigned num_maps)
{
	int i;
	struct pinctrl_dt_map *dt_map;

	/* Initialize common mapping table entry fields */
	for (i = 0; i < num_maps; i++) {
		map[i].dev_name = dev_name(p->dev);
		map[i].name = statename;//芯片引脚状态比如default
		if (pctldev)
			map[i].ctrl_dev_name = dev_name(pctldev->dev);
	}

	/* Remember the converted mapping table entries */
	dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);

	dt_map->pctldev = pctldev;
	dt_map->map = map;
	dt_map->num_maps = num_maps; //group当中pin的数目
	list_add_tail(&dt_map->node, &p->dt_maps);//将dt_maps加入到dt_map->node

	return pinctrl_register_map(map, num_maps, false);
}

在这里插入图片描述

pinctrl_register_map()函数

drivers/pinctrl/core.c

int pinctrl_register_map(const struct pinctrl_map *maps, unsigned num_maps,
			 bool dup)
{
	int i, ret;
	struct pinctrl_maps *maps_node;
	
	for (i = 0; i < num_maps; i++) {
	
	switch (maps[i].type) {
		case PIN_MAP_TYPE_DUMMY_STATE:
			break;
		case PIN_MAP_TYPE_MUX_GROUP://第0个map会在这里执行
			//判断data.mux.function是否为空,不为空ret = 0
			ret = pinmux_validate_map(&maps[i], i);
			if (ret < 0)
				return ret;
			break;
		case PIN_MAP_TYPE_CONFIGS_PIN://后面的map会执行这里之后的
		case PIN_MAP_TYPE_CONFIGS_GROUP:
		//判断data.configs中的参数是否为空,不为空ret = 0
			ret = pinconf_validate_map(&maps[i], i);
			if (ret < 0)
				return ret;
			break;
		default:
			pr_err("failed to register map %s (%d): invalid type given\n",
			       maps[i].name, i);
			return -EINVAL;
		}
	}
	
	maps_node = kzalloc(sizeof(*maps_node), GFP_KERNEL);
	maps_node->num_maps = num_maps;
	
	if (dup) {
		maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps,
					  GFP_KERNEL);
		if (!maps_node->maps) {
			kfree(maps_node);
			return -ENOMEM;
		}
	} else {
		maps_node->maps = maps;//指向pinctrl_map数组
	}
	...
	list_add_tail(&maps_node->node, &pinctrl_maps);把这个节点加入到pinctrl_maps上面来
	...
}

在这里插入图片描述

pinmux_validate_map()函数

drivers/pinctrl/pinmux.c

int pinmux_validate_map(const struct pinctrl_map *map, int i)
{
	if (!map->data.mux.function) {
		pr_err("failed to register map %s (%d): no function given\n",
		       map->name, i);
		return -EINVAL;
	}

	return 0;
}
pinconf_validate_map()函数

drivers/pinctrl/pinmux.c

int pinconf_validate_map(const struct pinctrl_map *map, int i)
{
	if (!map->data.configs.group_or_pin) {
		pr_err("failed to register map %s (%d): no group/pin given\n",
		       map->name, i);
		return -EINVAL;
	}

	if (!map->data.configs.num_configs ||
			!map->data.configs.configs) {
		pr_err("failed to register map %s (%d): no configs given\n",
		       map->name, i);
		return -EINVAL;
	}
	//以上都不为空因此这个函数会return0

	return 0;
}

pinctl_setting:如何统一管理pin state

pinctl_map
  • 保存了所有pin state所需要的pin group信息
pinctl_setting
  • 把pin group信息按pin state分类保存
目的
  • pinctl_map->pinctl_setting
for_each_maps()宏

drivers/pinctrl/core.h

#define for_each_maps(_maps_node_, _i_, _map_) \
	list_for_each_entry(_maps_node_, &pinctrl_maps, node) \
		for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \
			_i_ < _maps_node_->num_maps; \
			_i_++, _map_ = &_maps_node_->maps[_i_])
add_setting()函数

drivers/pinctrl/core.c

static int add_setting(struct pinctrl *p, struct pinctrl_dev *pctldev,
		       const struct pinctrl_map *map)
{	
	struct pinctrl_state *state;
	struct pinctrl_setting *setting;
	
	//遍历state链表,但是没有节点返回NULL
	state = find_state(p, map->name);
	if (!state)
		//创建state节点
		state = create_state(p, map->name);
	...
	setting = kzalloc(sizeof(*setting), GFP_KERNEL);

	setting->type = map->type;//将map的type赋值给setting

	if (pctldev)
		setting->pctldev = pctldev;
	else
		setting->pctldev =
			get_pinctrl_dev_from_devname(map->ctrl_dev_name);
	
    setting->dev_name = map->dev_name;//iomuxc节点名
    
    switch (map->type) {
	case PIN_MAP_TYPE_MUX_GROUP://第一个setting执行这个
		ret = pinmux_map_to_setting(map, setting);
		break;
	case PIN_MAP_TYPE_CONFIGS_PIN:
	case PIN_MAP_TYPE_CONFIGS_GROUP://其他的setting执行这个
		ret = pinconf_map_to_setting(map, setting);
		break;
	default:
		ret = -EINVAL;
		break;
	}
	...
	list_add_tail(&setting->node, &state->settings);
	//讲解点加入state->setting上
	
	return 0;
}

在这里插入图片描述

create_state()函数

drivers/pinctrl/core.c

static struct pinctrl_state *create_state(struct pinctrl *p,const char *name)
{
	struct pinctrl_state *state;//一个状态如defualt对应一个pinctrl_state结构体

	state = kzalloc(sizeof(*state), GFP_KERNEL);
	//分配内存
	
	state->name = name;//这个name就是defualt
	INIT_LIST_HEAD(&state->settings);//初始化setting链表节点

	list_add_tail(&state->node, &p->states);//把节点加入到pinctrl的states上面去

	return state;
}

在这里插入图片描述

pinmux_map_to_setting()函数

drivers/pinctrl/pinmux.c

int pinmux_map_to_setting(const struct pinctrl_map *map,struct pinctrl_setting *setting)
{
	struct pinctrl_dev *pctldev = setting->pctldev;
	//imx_pmx_ops
	const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
	char const * const *groups;
	unsigned num_groups;
	int ret;
	const char *group;
	...
	//对比function name是否相同,相同返回0
	ret = pinmux_func_name_to_selector(pctldev, map->data.mux.function);
	...
	/*function的索引*/
	setting->data.mux.func = ret;//0
	
	//就是这个函数pinmux_generic_get_function_groups,这个函数就是去找function——desc结构体下的group_names和num_groups_names变量
	//也就是group的名字数组和数量
	ret = pmxops->get_function_groups(pctldev, setting->data.mux.func,&groups, &num_groups);
	
	//判断map中的group名与func当中的group名是否匹配
	if (map->data.mux.group) {
		//group节点名
		group = map->data.mux.group;
		//判断两个变量指向的值是否相匹配
		ret = match_string(groups, num_groups, group);
		
		...
		}
	} else {
		group = groups[0];
	}
	//在所有的group中查找与map中的group名相同的group编号并返回
	ret = pinctrl_get_group_selector(pctldev, group);
	...
	setting->data.mux.group = ret;
	...
}
	
pinmux_func_name_to_selector()函数

drivers/pinctrl/pinmux.c

static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev,
					const char *function)
{
    //imx_pmx_ops
	const struct pinmux_ops *ops = pctldev->desc->pmxops;
	
	//pinmux_generic_get_function_count
	//这个函数返回pctldev->num_function成员变量,就是function的数量为1
	unsigned nfuncs = ops->get_functions_count(pctldev);
	
	unsigned selector = 0;

	while (selector < nfuncs) {
	  //即pinmux_generic_get_function_name这个函数,获取function的name,返回iomuxc节点名
		const char *fname = ops->get_function_name(pctldev, selector);
		
		//这里都是imouxc节点名因此返回0
		if (!strcmp(function, fname))
			return selector;

		selector++;
	}

	return -EINVAL;
}
pinctrl_get_group_selector()函数

drivers/pinctrl/core.c

int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,const char *pin_group)
{
	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
	//返回group节点的数量
	unsigned ngroups = pctlops->get_groups_count(pctldev);
	unsigned group_selector = 0;
	
	//在所有的group中查找与map中的group名相同的group编号并返回
	while (group_selector < ngroups) {
	 //从基数树中找到group,返回group的名字
		const char *gname = pctlops->get_group_name(pctldev,
							    group_selector);
		if (gname && !strcmp(gname, pin_group)) {
			dev_dbg(pctldev->dev,
				"found group selector %u for %s\n",
				group_selector,
				pin_group);
			return group_selector;//进行对比,相同的话返回group编号
		}

		group_selector++;
	}

	dev_err(pctldev->dev, "does not have pin group %s\n",
		pin_group);

	return -EINVAL;
}
pinconf_map_to_setting()函数
int pinconf_map_to_setting(const struct pinctrl_map *map,
			  struct pinctrl_setting *setting)
{
	struct pinctrl_dev *pctldev = setting->pctldev;
	int pin;

	switch (setting->type) {
	case PIN_MAP_TYPE_CONFIGS_PIN:
		pin = pin_get_from_name(pctldev,
					map->data.configs.group_or_pin);
		if (pin < 0) {
			dev_err(pctldev->dev, "could not map pin config for \"%s\"",
				map->data.configs.group_or_pin);
			return pin;
		}
		setting->data.configs.group_or_pin = pin;
		break;
		...
	}
	setting->data.configs.num_configs = map->data.configs.num_configs;
	setting->data.configs.configs = map->data.configs.configs;
	...
}
    
  • 24
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值