Pincontroller构造过程情景分析-基于IMX6ULL

参考文档

Linux 4.x内核文档

  • Documentation\pinctrl.txt
  • Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt
  • arch/arm/boot/dts/imx6ull-14x14-evk.dts
  • arch/arm/boot/dts/100ask_imx6ull-14x14.dts
  • drivers\pinctrl\freescale\pinctrl-imx6ul.c
  • drivers\pinctrl\freescale\pinctrl-imx.c

一、设备树

Pincontroller构造过程情景分析-基于IMX6ULL_第1张图片

二、驱动代码执行流程

驱动程序位置:

drivers\pinctrl\freescale\pinctrl-imx6ul.c
drivers\pinctrl\freescale\pinctrl-imx.c
//drivers\pinctrl\freescale\pinctrl-imx6ul.c
static 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 int imx6ul_pinctrl_probe(struct platform_device *pdev)
{
    const struct of_device_id *match;
    struct imx_pinctrl_soc_info *pinctrl_info;

    match = of_match_device(imx6ul_pinctrl_of_match, &pdev->dev);		//和设备树中的compatible对比

    if (!match)
        return -ENODEV;

    pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;		//附对应的结构体

    return imx_pinctrl_probe(pdev, pinctrl_info);
}

static struct imx_pinctrl_soc_info imx6ul_pinctrl_info = {
	.pins = imx6ul_pinctrl_pads,			//描述了很多个引脚,描述了第几号引脚,名字是什么
	.npins = ARRAY_SIZE(imx6ul_pinctrl_pads),			//引脚的个数
	.gpr_compatible = "fsl,imx6ul-iomuxc-gpr",
};

通用的probe函数干的事情:

int imx_pinctrl_probe(struct platform_device *pdev,
		      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;
	//.....

	imx_pinctrl_desc->name = dev_name(&pdev->dev);			//设置pinctrl_desc结构体
	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, info);				//解析设备树
	if (ret) {
		dev_err(&pdev->dev, "fail to probe dt properties\n");
		return ret;
	}

	ipctl->info = info;
	ipctl->dev = info->dev;
	platform_set_drvdata(pdev, ipctl);
	ipctl->pctl = devm_pinctrl_register(&pdev->dev,
					    imx_pinctrl_desc, ipctl);
	//....
}

三、作用1:描述、获得引脚(解析设备树)

3.1 单个引脚

	imx_pinctrl_desc->pins = info->pins;
	imx_pinctrl_desc->npins = info->npins;
# 在开发板上查看,支持的单个引脚数
root@npi:~# cat /sys/kernel/debug/pinctrl/20e0000.iomuxc/pins
registered pins: 129
pin 0 (MX6UL_PAD_RESERVE0) 20e0000.iomuxc
pin 1 (MX6UL_PAD_RESERVE1) 20e0000.iomuxc
pin 2 (MX6UL_PAD_RESERVE2) 20e0000.iomuxc
pin 3 (MX6UL_PAD_RESERVE3) 20e0000.iomuxc
pin 4 (MX6UL_PAD_RESERVE4) 20e0000.iomuxc
pin 5 (MX6UL_PAD_RESERVE5) 20e0000.iomuxc
pin 6 (MX6UL_PAD_RESERVE6) 20e0000.iomuxc
pin 7 (MX6UL_PAD_RESERVE7) 20e0000.iomuxc
pin 8 (MX6UL_PAD_RESERVE8) 20e0000.iomuxc
pin 9 (MX6UL_PAD_RESERVE9) 20e0000.iomuxc
pin 10 (MX6UL_PAD_RESERVE10) 20e0000.iomuxc
pin 11 (MX6UL_PAD_SNVS_TAMPER4) 20e0000.iomuxc
pin 12 (MX6UL_PAD_RESERVE12) 20e0000.iomuxc
pin 13 (MX6UL_PAD_RESERVE13) 20e0000.iomuxc
pin 14 (MX6UL_PAD_RESERVE14) 20e0000.iomuxc
pin 15 (MX6UL_PAD_RESERVE15) 20e0000.iomuxc
pin 16 (MX6UL_PAD_RESERVE16) 20e0000.iomuxc
pin 17 (MX6UL_PAD_JTAG_MOD) 20e0000.iomuxc
pin 18 (MX6UL_PAD_JTAG_TMS) 20e0000.iomuxc

# 查看支持的组
root@npi:~# cat /sys/kernel/debug/pinctrl/20e0000.iomuxc/pingroups
registered pin groups:
group: uart2grp
pin 37 (MX6UL_PAD_UART2_TX_DATA)
pin 38 (MX6UL_PAD_UART2_RX_DATA)

group: sai2grp
pin 20 (MX6UL_PAD_JTAG_TDI)
pin 19 (MX6UL_PAD_JTAG_TDO)
pin 22 (MX6UL_PAD_JTAG_TRST_B)
pin 21 (MX6UL_PAD_JTAG_TCK)
pin 18 (MX6UL_PAD_JTAG_TMS)

group: bluegrp
pin 120 (MX6UL_PAD_CSI_HSYNC)

group: grngrp
pin 120 (MX6UL_PAD_CSI_HSYNC)

group: redgrp
pin 27 (MX6UL_PAD_GPIO1_IO04)

group: tscresetgrp
pin 69 (MX6UL_PAD_LCD_RESET)

# 可以使用这个命令反汇编dtb文件
book@100ask:~/imx6ull/linux-4.9.88/arch/arm/boot/dts$ dtc -I dtb -O dts imx6ull-14x14-ebf.dtb > 1.dts
# 里面的内容都是一一对应的
                    uart2grp {
                        fsl,pins = <0x94 0x320 0x0 0x0 0x0 0x1b0b1 0x98 0x324 0x62c 0x0 0x1 0x1b0b1>;
                    };
                     sai2grp {
                        fsl,pins = <0x50 0x2dc 0x5f8 0x2 0x0 0x17088 0x4c 0x2d8 0x5fc 0x2 0x0 0x17088 0x58 0x2e4 0x0 0x2 0x0 0x11088 0x54 0x2e0 0x5f4 0x2 0x0 0x11088 0x48 0x2d4 0x5f0 0x2 0x0 0x17088>;
                        linux,phandle = <0xb>;
                        phandle = <0xb>;
                    };
                    tscresetgrp {
                        fsl,pins = <0x114 0x3a0 0x0 0x5 0x0 0x5>;
                        linux,phandle = <0x2a>;
                        phandle = <0x2a>;
                    };
# 这些支持的信息完全来自设备树

root@npi:/sys/kernel/debug/pinctrl/20e0000.iomuxc# cat pinmux-functions
function: iomuxc, groups = [ uart2grp sai2grp bluegrp grngrp redgrp tscresetgrp pwm1grp lcdifdatgrp lcdifctrlgrp wifigrp hdmigrp adc1grp i2c2grp i2c1grp hoggrp-1 enet1grp enet2grp uart1grp usdhc1grp usdhc1grp100mhz usdhc1grp200mhz usdhc2grp usdhc2grp_8bit usdhc2grp_8bit_100mhz usdhc2grp_8bit_200mhz ledgrp ]
# iomuxc, groups 代表开发板


3.2 某组引脚

static const struct pinctrl_ops imx_pctrl_ops = {
	.get_groups_count = imx_get_groups_count,			//支持多少组引脚
	.get_group_name = imx_get_group_name,			//每一组引脚的名字
	.get_group_pins = imx_get_group_pins,			//某一组的引脚里支持哪些引脚
	.pin_dbg_show = imx_pin_dbg_show,
	.dt_node_to_map = imx_dt_node_to_map,
	.dt_free_map = imx_dt_free_map,
};

3.3 设备树解析情景分析


struct imx_pinctrl_soc_info {
	struct device *dev;
	const struct pinctrl_pin_desc *pins;				//单个引脚的信息
	unsigned int npins;				//支持多少个引脚
	struct imx_pin_reg *pin_regs;
	struct imx_pin_group *groups;					//组的信息
	unsigned int ngroups;					//有多少组引脚
	unsigned int group_index;
	struct imx_pmx_func *functions;			//指向imx_pmx_func结构体
	unsigned int nfunctions;				//=1,设备树里只支持单个板子
	unsigned int flags;
	const char *gpr_compatible;

	/* MUX_MODE shift and mask in case SHARE_MUX_CONF_REG */
	unsigned int mux_mask;
	u8 mux_shift;
	u32 ibe_bit;
	u32 obe_bit;
};

struct imx_pmx_func {
	const char *name;				//节点的名字,imx6ull-evk
	const char **groups;			//char*数组用来保存组的名字
	unsigned num_groups;			//组的个数
};

struct imx_pin_group {
	const char *name;
	unsigned npins;
	unsigned int *pin_ids;
	struct imx_pin *pins;
};

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

	if (!np)
		return -ENODEV;

//确定支持多少个单板,多少个功能
	flat_funcs = imx_pinctrl_dt_is_flat_functions(np);
	if (flat_funcs) {
		nfuncs = 1;
	} else {
		nfuncs = of_get_child_count(np);			//有多少个子节点,imx6ull只有1个
		if (nfuncs <= 0) {
			dev_err(&pdev->dev, "no functions defined\n");
			return -EINVAL;
		}
	}

	info->nfunctions = nfuncs;
	info->functions = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct imx_pmx_func),		//分配一个结构体
					GFP_KERNEL);
	if (!info->functions)
		return -ENOMEM;

	//确定有多少个组
	info->group_index = 0;
	if (flat_funcs) {
		info->ngroups = of_get_child_count(np);
	} else {
		info->ngroups = 0;
		for_each_child_of_node(np, child)
			info->ngroups += of_get_child_count(child);
	}
	info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct imx_pin_group),
					GFP_KERNEL);		//分配对应个数的组的结构体
	if (!info->groups)
		return -ENOMEM;

	if (flat_funcs) {
		imx_pinctrl_parse_functions(np, info, 0);			//解析里面的每一个功能
	} else {
		for_each_child_of_node(np, child)
			imx_pinctrl_parse_functions(child, info, i++);
	}

	return 0;
}

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) {
		if (of_property_read_bool(function_np, "fsl,pins"))			//如果根节点下有fsl,pins信息
			return true;

		for_each_child_of_node(function_np, pinctrl_np) {
			if (of_property_read_bool(pinctrl_np, "fsl,pins"))		//再根节点下没有fsl,pins而再子节点下有fsl,pins信息
				return false;
		}
	}

	return true;
}

static int imx_pinctrl_parse_functions(struct device_node *np,
				       struct imx_pinctrl_soc_info *info,
				       u32 index)
{
	struct device_node *child;
	struct imx_pmx_func *func;
	struct imx_pin_group *grp;
	u32 i = 0;

	dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);

	func = &info->functions[index];			//取出一个数组

	/* Initialise function */				//初始化相关的值
	func->name = np->name;
	func->num_groups = of_get_child_count(np);			//获得子节点的个数
	if (func->num_groups == 0) {
		dev_err(info->dev, "no groups defined in %s\n", np->full_name);
		return -EINVAL;
	}
	func->groups = devm_kzalloc(info->dev,
			func->num_groups * sizeof(char *), GFP_KERNEL);			//分配num_groups个组信息

	for_each_child_of_node(np, child) {
		func->groups[i] = child->name;				//指向对应组的名字
		grp = &info->groups[info->group_index++];			//指向对应组的imx_pin_group
		imx_pinctrl_parse_groups(child, grp, info, i++);
	}

	return 0;
}

static int imx_pinctrl_parse_groups(struct device_node *np,
				    struct imx_pin_group *grp,
				    struct imx_pinctrl_soc_info *info,
				    u32 index)
{
	int size, pin_size;
	const __be32 *list, **list_p;
	int i;

	dev_dbg(info->dev, "group(%d): %s\n", index, np->name);

	if (info->flags & IMX8_USE_SCU)
		pin_size = FSL_IMX8_PIN_SIZE;
	else if (info->flags & SHARE_MUX_CONF_REG)
		pin_size = SHARE_FSL_PIN_SIZE;
	else
		pin_size = FSL_PIN_SIZE;
	/* Initialise group */
	grp->name = np->name;				//grp的name等于组的名字

	/*
	 * the binding format is fsl,pins = ,
	 * do sanity check and calculate pins number
	 */
	list = of_get_property(np, "fsl,pins", &size);		//计算fs,pins有多大,6x4=24字节描述一个引脚
	if (!list) {
		dev_err(info->dev, "no fsl,pins property in node %s\n", np->full_name);
		return -EINVAL;
	}

	list_p = &list;

	/* we do not check return since it's safe node passed down */
	if (!size || size % pin_size) {
		dev_err(info->dev, "Invalid fsl,pins property in node %s\n", np->full_name);
		return -EINVAL;
	}

	grp->npins = size / pin_size;					//引脚的个数
	grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(struct imx_pin),		//pins指向imx_pin数组
				GFP_KERNEL);
	grp->pin_ids = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
				GFP_KERNEL);
	if (!grp->pins || ! grp->pin_ids)
		return -ENOMEM;

	for (i = 0; i < grp->npins; i++) {
		if (info->flags & IMX8_USE_SCU)
			imx_pinctrl_parse_pin_scu(info, &grp->pin_ids[i],
				&grp->pins[i], list_p);					//使用函数解析引脚
		else
			imx_pinctrl_parse_pin_mem(info, &grp->pin_ids[i],
				&grp->pins[i], list_p);					//使用函数解析引脚
	}

	return 0;
}

struct imx_pin {						//用来表示单个引脚
	unsigned int pin;
	union {
		struct imx_pin_memmap pin_memmap;
		struct imx_pin_scu pin_scu;
	} pin_conf;
};

int imx_pinctrl_parse_pin_mem(struct imx_pinctrl_soc_info *info,
			  unsigned int *grp_pin_id, struct imx_pin *pin,
			  const __be32 **list_p)
{
	struct imx_pin_memmap *pin_memmap = &pin->pin_conf.pin_memmap;
	u32 mux_reg = be32_to_cpu(*((*list_p)++));
	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)++));
		if (!conf_reg)
			conf_reg = -1;
	}
	/* 根据设备树信息的值,记录为寄存器的地址。设备树上每个值都有特定的含义 */
	pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4;
	pin_reg = &info->pin_regs[pin_id];
	pin->pin = pin_id;
	*grp_pin_id = pin_id;
	pin_reg->mux_reg = mux_reg;
	pin_reg->conf_reg = conf_reg;
	pin_memmap->input_reg = be32_to_cpu(*((*list_p)++));			//记录reg
	pin_memmap->mux_mode = be32_to_cpu(*((*list_p)++));
	pin_memmap->input_val = be32_to_cpu((*(*list_p)++));		//记录value

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

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

	return 0;
}

四、总结

            iomuxc@020e0000 {				//这个节点下的子节点表示一个或者多个单板
                compatible = "fsl,imx6ul-iomuxc";
                reg = <0x20e0000 0x4000>;
                pinctrl-names = "default";

                imx6ul-evk {			//这里只有一种板子,在一种单板下,有一个或者多个group表示引脚的组

                    remote_control {			//在一个group下,有fsl,pins属性来描述一个或者多个引脚
                        fsl,pins = <0x94 0x320 0x0 0x0 0x0 0x10b1>;
                        linux,phandle = <0x3f>;
                        phandle = <0x3f>;
                    };

                    mylcd_pingrp {
                        fsl,pins = <0x7c 0x308 0x0 0x5 0x0 0x10b0 0x104 0x390 0x0 0x0 0x0 0x10b0 0x118 0x3a4 0x0 0x0 0x0 0x10b0 0x11c 0x3a8 0x0 0x0 0x0 0x10b0 0x120 0x3ac 0x0 0x0 0x0 0x10b0 0x124 0x3b0 0x0 0x0 0x0 0x10b0 0x128 0x3b4 0x0 0x0 0x0 0x10b0 0x12c 0x3b8 0x0 0x0 0x0 0x10b0 0x130 0x3bc 0x0 0x0 0x0 0x10b0 0x134 0x3c0 0x0 0x0 0x0 0x10b0 0x138 0x3c4 0x0 0x0 0x0 0x10b0 0x13c 0x3c8 0x0 0x0 0x0 0x10b0 0x140 0x3cc 0x0 0x0 0x0 0x10b0 0x144 0x3d0 0x0 0x0 0x0 0x10b0 0x148 0x3d4 0x0 0x0 0x0 0x10b0 0x14c 0x3d8 0x0 0x0 0x0 0x10b0 0x150 0x3dc 0x0 0x0 0x0 0x10b0 0x154 0x3e0 0x0 0x0 0x0 0x10b0 0x158 0x3e4 0x0 0x0 0x0 0x10b0 0x15c 0x3e8 0x0 0x0 0x0 0x10b0 0x160 0x3ec 0x0 0x0 0x0 0x10b0 0x164 0x3f0 0x0 0x0 0x0 0x10b0 0x168 0x3f4 0x0 0x0 0x0 0x10b0 0x16c 0x3f8 0x0 0x0 0x0 0x10b0 0x170 0x3fc 0x0 0x0 0x0 0x10b0 0x174 0x400 0x0 0x0 0x0 0x10b0 0x108 0x394 0x0 0x0 0x0 0x10b0 0x10c 0x398 0x5dc 0x0 0x0 0x10b0 0x110 0x39c 0x0 0x0 0x0 0x10b0>;
                        linux,phandle = <0x37>;
                        phandle = <0x37>;
                    };
				//.....
				};

在解析设备树时,就是去构造这个imx_pinctrl_soc_info结构体的过程:
imx_pinctrl_soc_info结构体用来描述一个pinctroller。
unsigned int nfunctions;属性表示支持多少种单板
imx_pmx_func结构体,是针对单板。上面只有一个是imx6ul-evk节点
imx_pin_group表示节点下所有的组节点

struct imx_pinctrl_soc_info {
	struct device *dev;
	const struct pinctrl_pin_desc *pins;				//单个引脚的信息
	unsigned int npins;				//支持多少个引脚
	struct imx_pin_reg *pin_regs;
	struct imx_pin_group *groups;					//组的信息
	unsigned int ngroups;					//有多少组引脚
	unsigned int group_index;
	struct imx_pmx_func *functions;			//指向imx_pmx_func结构体
	unsigned int nfunctions;				//=1,设备树里只支持单个板子
	unsigned int flags;
	const char *gpr_compatible;

	/* MUX_MODE shift and mask in case SHARE_MUX_CONF_REG */
	unsigned int mux_mask;
	u8 mux_shift;
	u32 ibe_bit;
	u32 obe_bit;
};

针对单板,有一个imx_pmx_func结构体,对应设备树的imx6ul-evk的节点

struct imx_pmx_func {
    const char *name;
    const char **groups;				//这里的group的名字数组,和imx_pin_group里的名字是一一对应的关系
    unsigned num_groups;
};

//对于imx_pinctrl_soc_info下的每一个function的节点,一一解析
        for_each_child_of_node(np, child)
            imx_pinctrl_parse_functions(child, info, i++);

对于设备树下的所有子节点,都会用imx_pin_group来表示

struct imx_pin_group {
    const char *name;
    unsigned npins;
    unsigned int *pin_ids;
    struct imx_pin *pins;
};

//对于function下的每一个group节点,都一一解析
    for_each_child_of_node(np, child) {
        func->groups[i] = child->name;
        grp = &info->groups[info->group_index++];
        imx_pinctrl_parse_groups(child, grp, info, i++);
    }

imx_pin表示在每一个group下有多个pin引脚的结构体

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


    for (i = 0; i < grp->npins; i++) {
        if (info->flags & IMX8_USE_SCU)
            imx_pinctrl_parse_pin_scu(info, &grp->pin_ids[i],
                &grp->pins[i], list_p);
        else
            imx_pinctrl_parse_pin_mem(info, &grp->pin_ids[i],
                &grp->pins[i], list_p);
    }

你可能感兴趣的:(#,Pinctrl,100ask,imx6ull,pin,controller,pincontroller,kernel)