pinctrl子系统分析(三)

pinctrl子系统分析(一)
pinctrl子系统分析(二)
pinctrl子系统分析(三)

这章讲解配置节点的解析以及pinctrl_state的pinctrl_setting增添,先来个图:
在这里插入图片描述

create_pinctrl:

static struct pinctrl *create_pinctrl(struct device *dev)
{
	struct pinctrl *p;
	const char *devname;
	struct pinctrl_maps *maps_node;
	int i;
	struct pinctrl_map const *map;
	int ret;

	......

	//解析配置节点
	ret = pinctrl_dt_to_map(p);
	......

	devname = dev_name(dev);

	mutex_lock(&pinctrl_maps_mutex);

	//遍历pinctrl_maps链表得到每项pinctrl_map 
	for_each_maps(maps_node, i, map) {
		
		/*判断是不是该设备的pinctrl_map  */
		if (strcmp(map->dev_name, devname))
			continue;

		//增添pinctrl_setting
		ret = add_setting(p, map);
		
		......

	}

	mutex_unlock(&pinctrl_maps_mutex);

	......

	return p;
}

重点pinctrl_dt_to_map函数:


int pinctrl_dt_to_map(struct pinctrl *p)
{
	struct device_node *np = p->dev->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;

	......

		/*  举例子说明:
			device {
				pinctrl-names = "default", "idle";
				pinctrl-0 = <&state_0_node_a>;
				pinctrl-1 = <&state_1_node_a &state_1_node_b>;
			};

      */

	//设备可能有多种状态如default、idle,所以来个for循环
	for (state = 0; ; state++) {
		
		propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
		prop = of_find_property(np, propname, &size);
		......

		list = prop->value;
		size /= sizeof(*list);

		/* 获取设备的状态名,对于上面的例子,第一次循环获取的状态名为:"default",
       第二次循环获取的状态名为:"idle",状态名保存在statename
     */
		ret = of_property_read_string_index(np, "pinctrl-names",
						    state, &statename);
		......

		//每种状态可能有多个匹配节点,所以来个for循环
		for (config = 0; config < size; config++) {
			phandle = be32_to_cpup(list++);
			
			/* 对于上面的例子,idle状态下有两个配置节点(state_1_node_a和state_1_node_b)
              调用of_find_node_by_phandle函数找到配置节点对应的device_node
           */ 
			np_config = of_find_node_by_phandle(phandle);
			......

			/* 解析配置节点 */
			ret = dt_to_map_one_config(p, statename, np_config);
			......
		}

		......
	}

	return 0;
	
	......
}

解析单个配置节点dt_to_map_one_config:

static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
				struct device_node *np_config)
{
	struct device_node *np_pctldev;
	struct pinctrl_dev *pctldev;
	const struct pinctrl_ops *ops;
	int ret;
	struct pinctrl_map *map;
	unsigned num_maps;

	/* 举例子说明:
	device {
			pinctrl-names = "default", "idle";
			pinctrl-0 = <&state_0_node_a>;
			pinctrl-1 = <&state_1_node_a &state_1_node_b>;
	};

	pincontroller {
			//配置节点
			state_0_node_a {
				...         //复用为哪个功能,引脚配置值等等
			};

			//配置节点
			state_1_node_a {
				...
			};

			//配置节点
			state_1_node_b {
				...
			};
	};
	
*/	
	
	np_pctldev = of_node_get(np_config);

	//通过配置节点找到pin控制器的device_node,这正是配置节点要位于pin控制器节点之下的原因
	for (;;) {
		np_pctldev = of_get_next_parent(np_pctldev);
		......
		
		//通过pin控制器的device_node在pinctrldev_list链表里找到对应的pinctrl_dev 
		pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
		if (pctldev)
			break;
		......

	}
	of_node_put(np_pctldev);


	ops = pctldev->desc->pctlops;
	......
	
	/* 调用pinctrl_dev->pinctrl_desc->pinctrl_ops里的dt_node_to_map函数解析配置节点
     解析得到得配置信息保存在pinctrl_map,一个配置节点的信息,对应一个或多个pinctrl_map 
   */
	ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);
	......


	/* 这些pinctrl_map在增添pinctrl_setting的时候会用到,所以把这些pinctrl_map注册进内核
     以链表的形式,插入到全局链表pinctrl_maps
   */
	return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
}

来看看数据结构pinctrl_map:

enum pinctrl_map_type {
	PIN_MAP_TYPE_INVALID,
	PIN_MAP_TYPE_DUMMY_STATE,
	PIN_MAP_TYPE_MUX_GROUP,      //复用
	PIN_MAP_TYPE_CONFIGS_PIN,    //引脚配置
	PIN_MAP_TYPE_CONFIGS_GROUP,  //一组引脚配置
};


struct pinctrl_map {
	
	//device的name
	const char *dev_name;

	//状态的名字,如"default"、"idle"
	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_mux {
	const char *group;     //group的name
	const char *function;  //function的name
};

struct pinctrl_map_configs {
	const char *group_or_pin;   //group或引脚的name
	unsigned long *configs;     //配置信息,是个数组
	unsigned num_configs;       //配置信息的个数
};

注册pinctrl_map:

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;

	/* 初始化pinctrl_map的dev_name、name等 */
	for (i = 0; i < num_maps; i++) {
		map[i].dev_name = dev_name(p->dev);
		map[i].name = statename;
		if (pctldev)
			map[i].ctrl_dev_name = dev_name(pctldev->dev);
	}

	/* 分配一个pinctrl_dt_map,用于保存多个pinctrl_map   */
	dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);
	......

	//初始化pinctrl_dt_map
	dt_map->pctldev = pctldev;
	dt_map->map = map;
	dt_map->num_maps = num_maps;

	//将pinctrl_dt_map插入到pinctrl的dt_maps链表
	list_add_tail(&dt_map->node, &p->dt_maps);

	//注册pinctrl_map
	return pinctrl_register_map(map, num_maps, false);
}


int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
			 bool dup)
{
	int i, ret;
	struct pinctrl_maps *maps_node;

	......

	//分配一个pinctrl_maps,保存多个pinctrl_map
	maps_node = kzalloc(sizeof(*maps_node), GFP_KERNEL);
	......

	//设置pinctrl_maps
	maps_node->num_maps = num_maps;

	if (dup) { //false
			......
		}
	} else {
		maps_node->maps = maps;
	}

	mutex_lock(&pinctrl_maps_mutex);
	list_add_tail(&maps_node->node, &pinctrl_maps); //插入到pinctrl_maps链表
	mutex_unlock(&pinctrl_maps_mutex);

	return 0;
}

来个整体的流程图:
在这里插入图片描述

回到create_pinctrl函数:

static struct pinctrl *create_pinctrl(struct device *dev)
{
	struct pinctrl *p;
	const char *devname;
	struct pinctrl_maps *maps_node;
	int i;
	struct pinctrl_map const *map;
	int ret;

	......


	devname = dev_name(dev);

	mutex_lock(&pinctrl_maps_mutex);

	//遍历pinctrl_maps链表得到每项pinctrl_map 
	for_each_maps(maps_node, i, map) {
		
		/*判断是不是该设备的pinctrl_map  */
		if (strcmp(map->dev_name, devname))
			continue;

		//增添pinctrl_setting
		ret = add_setting(p, map);
		
		......

	}

	mutex_unlock(&pinctrl_maps_mutex);

	......

	return p;
}

add_setting:

static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
{
	struct pinctrl_state *state;
	struct pinctrl_setting *setting;
	int ret;

	
	......

	if (map->type == PIN_MAP_TYPE_DUMMY_STATE)
		return 0;

	//分配pinctrl_setting 
	setting = kzalloc(sizeof(*setting), GFP_KERNEL);
	......

	//设置pinctrl_setting 
	setting->type = map->type;

	setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
	......

	setting->dev_name = map->dev_name;

	//通过pinctrl_map初始化pinctrl_setting 
	switch (map->type) {
	case PIN_MAP_TYPE_MUX_GROUP:
		ret = pinmux_map_to_setting(map, setting); 
		break;
	case PIN_MAP_TYPE_CONFIGS_PIN:
	case PIN_MAP_TYPE_CONFIGS_GROUP:
		ret = pinconf_map_to_setting(map, setting);
		break;
	default:
		ret = -EINVAL;
		break;
	}
	......

	//把pinctrl_setting插入到pinctrl_state的settings链表
	list_add_tail(&setting->node, &state->settings);

	return 0;
}

在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值