pinctrl子系统(三):pin寄存器地址与参数的解析与存储

pin function和pin group:iomuxc节点解析始末

设备树iomuxc节点层次
  • iomuxc

    • function

      • group

        fsl,pins = <
        			xxx
        			xxx
        		>;
        

      • group

    • function

层次关系说明
  • iomuxc:pinctrl子系统的设备树节点
  • function:芯片具有外设功能,一个 功能对应一个或多个IO组配置信息
  • 比如说i2c有几个功能,一个功能用一组IO引脚,另一个功能用另一组引脚
  • group:IO组中每个IO的配置信息
  • fsl,pins:imx6ull中,功能和IO组的标识属性
imx_pinctrl_probe_dt()函数

drivers/pinctrl/freescale/pinctrl-imx.c

static int imx_pinctrl_probe_dt(struct platform_device *pdev,
				struct imx_pinctrl *ipctl)
{
	//iomux节点
	struct device_node *np = pdev->dev.of_node;
	struct device_node *child;
	struct pinctrl_dev *pctl = ipctl->pctl;
	
	//用于判断iomuxc节点下面有几个fuction
	flat_funcs = imx_pinctrl_dt_is_flat_functions(np);
	//如果返回的是true说明只有一个function
	if (flat_funcs) {
		nfuncs = 1;
	} else {
		nfuncs = of_get_child_count(np);
		if (nfuncs == 0) {
			dev_err(&pdev->dev, "no functions defined\n");
			return -EINVAL;
		}
	}
	
	//创建func_desc,并加入func的基数树中
	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);
		//在pin_function_tree中插入一个function_desc节点
		mutex_unlock(&ipctl->mutex);
	}
	
	pctl->num_functions = nfuncs;
	ipctl->group_index = 0;
	
	if (flat_funcs) {
		//获取function的子节点数量,即group数量
		pctl->num_groups = of_get_child_count(np);
	} else {
		pctl->num_groups = 0;
		for_each_child_of_node(np, child)
			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++);
	}

	
imx_pinctrl_dt_is_flat_functions()函数

drivers/pinctrl/freescale/pinctrl-imx.c

static bool imx_pinctrl_dt_is_flat_functions(struct device_node *np)
{
	struct device_node *function_np;
	struct device_node *pinctrl_np;

	for_each_child_of_node(np, function_np) {//遍历一下device_node(iomuxc)的子节点 
	
		//判断一下这些子节点当中有没有fsl,pins属性,也就是说判断一下fuction节点下是否有这个属性,如果fuction下有的话说明设备只有一个fuction,因为fuction和group合并了
		if (of_property_read_bool(function_np, "fsl,pins"))
			return true;
		//判断一下这些子节点的子节点当中有没有fsl,pins属性,也就是说判断一下group节点下是否有这个属性
		for_each_child_of_node(function_np, pinctrl_np) {
			if (of_property_read_bool(pinctrl_np, "fsl,pins"))
				return false;
		}
	}

	return true;
}
imx_pinctrl_parse_functions()函数

drivers/pinctrl/freescale/pinctrl-imx.c

iomuxc节点的device_node结构体指针, ipctl, 0

static int imx_pinctrl_parse_functions(struct device_node *np,
				       struct imx_pinctrl *ipctl,
				       u32 index)
{
	struct pinctrl_dev *pctl = ipctl->pctl;
	struct device_node *child;
	struct function_desc *func;
	struct group_desc *grp;//专门用来描述每一个group下的引脚信息的
	u32 i = 0;
	
	//从基数树当中提出之前保存的function指针
	func = pinmux_generic_get_function(pctl, index);
	...
	func->name = np->name;//获取device_node中的name变量,其实就是compatible属性值
	func->num_group_names = of_get_child_count(np);//获取iomuxc的子节点数量,在这里就是获取group节点的数量
	...
	//为group的名字分配内存,分配group数量的char*数组
	func->group_names = devm_kcalloc(ipctl->dev, func->num_group_names,
					 sizeof(char *), GFP_KERNEL);
	//遍历每一个子节点,生成对应的group_desc,并加入pin_group_tree基数树
	for_each_child_of_node(np, child) {
		//func中的group_names就是来记录group名的,比如说设备树上的uartgrp1
		func->group_names[i] = child->name;
		grp = devm_kzalloc(ipctl->dev, sizeof(struct group_desc),
				   GFP_KERNEL);
				   
		mutex_lock(&ipctl->mutex);
		//将grp_desc结构体记录在基数树当中,grp的编号就是group_index
		radix_tree_insert(&pctl->pin_group_tree,
				  ipctl->group_index++, grp);
		mutex_unlock(&ipctl->mutex);

		imx_pinctrl_parse_groups(child, grp, ipctl, i++);
	}

	return 0;
}

在这里插入图片描述

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;//存放引脚编号和名字的结构体
	int size, pin_size;
	const __be32 *list, **list_p;
	u32 config;
	int i;
	
	if (info->flags & IMX8_USE_SCU)//因为info->flag没有赋值过因此为0
		pin_size = FSL_IMX8_PIN_SIZE;
	else if (info->flags & SHARE_MUX_CONF_REG)
		pin_size = FSL_PIN_SHARE_SIZE;
	else
	  //24,因为每一个引脚信息是一个宏和一个十六进制数,而宏又是五个十六进制数,一个十六进制数站4个字节,因此就是24个字节
		pin_size = FSL_PIN_SIZE;
	
	grp->name = np->name;//name是指iomuxc的子节点名
	
	list = of_get_property(np, "fsl,pins", &size);//获取到fsl,pins属性的长度到size,返回grp引脚具体的配置值都在list当中
	...
	list_p = &list;
	...
	/*该组引脚的配置个数*/
	//用fsl,pins的总长度除以每一个引脚的长度
	grp->num_pins = size / pin_size;
	
	//为每一个引脚分配一个imx_pin结构体,并分配内存,保存在data变量里
	grp->data = devm_kcalloc(ipctl->dev,
				 grp->num_pins, sizeof(struct imx_pin),
				 GFP_KERNEL);
	
	//为pins分配sizeof(unsigned int)*num_pins的内存,存pin的编号
	grp->pins = devm_kcalloc(ipctl->dev,
				 grp->num_pins, sizeof(unsigned int),
				 GFP_KERNEL);
	
	...
	//遍历grp当中的每一个pin并保存其属性信息
	for (i = 0; i < grp->num_pins; i++) {
	  //for循环依次获取data当中的imx_pin的地址
		struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];

		if (info->flags & IMX8_USE_SCU)//flags没有定义因此为0
			imx_pinctrl_parse_pin_scu(ipctl, &grp->pins[i],
				pin, list_p, config);
		else
			imx_pinctrl_parse_pin_mem(ipctl, &grp->pins[i],
				pin, list_p, config);
	}

	return 0;
}
imx_pinctrl_parse_pin_mem()函数

drivers/pinctrl/freescale/pinctrl-memmap.c

int imx_pinctrl_parse_pin_mem(struct imx_pinctrl *ipctl,
			  unsigned int *grp_pin_id, struct imx_pin *pin,
			  const __be32 **list_p, u32 generic_config)
{
	struct imx_pin_memmap *pin_memmap = &pin->pin_conf.pin_memmap;
	const struct imx_pinctrl_soc_info *info = ipctl->info;
	u32 mux_reg = be32_to_cpu(*((*list_p)++));//be32这个函数是用来大小端兼容,list_p第一个是mux寄存器的偏移地址,++之后指向下一个元素就是conf_reg
	u32 conf_reg;
	u32 config;
	unsigned int pin_id;
	struct imx_pin_reg *pin_reg;
	
	if (info->flags & SHARE_MUX_CONF_REG) {
		conf_reg = mux_reg;
	} else {
		conf_reg = be32_to_cpu(*((*list_p)++));//读取conf_reg的值
		if (!conf_reg)
			conf_reg = -1;
	}

	pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4;//用复用寄存器的值/4得到对应的引脚编号
	pin_reg = &ipctl->pin_regs[pin_id];//用引脚编号获取对应的pin寄存器描述结构体
	pin->pin = pin_id;//将芯片引脚编号赋值给imx_pin->pin
	*grp_pin_id = pin_id;//也存在了grp—>pins当中
	pin_reg->mux_reg = mux_reg;//将mux_reg记录到pin_reg上
	pin_reg->conf_reg = conf_reg;//同上
	pin_memmap->input_reg = be32_to_cpu(*((*list_p)++));//继续++读取属性值
	pin_memmap->mux_mode = be32_to_cpu(*((*list_p)++));//同上
	pin_memmap->input_val = be32_to_cpu((*(*list_p)++));//同上
	...
	config = be32_to_cpu(*((*list_p)++));//最后一个16进制整数
	...
	if (config & IMX_PAD_SION)
		pin_memmap->mux_mode |= IOMUXC_CONFIG_SION;
		//这个判断就是跟寄存器具体属性相关
	pin_memmap->config = config & ~IMX_PAD_SION;//保存属性值
	...
	
	return 0;
}

在这里插入图片描述

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值