pinctrl子系统和GPIO子系统的匹配过程(imx6ull)

pinctrl子系统和GPIO子系统的匹配过程(imx6ull)

个人声明:转发请注明出处,个人原创,实属不易。本人水平有限,文章若有不妥之处,还请留言批评指正,不胜感激。

pinctrl子系统和GPIO子系统是驱动分层下的产物

  1. pinctrl子系统
    1.1 借助pinctrl来设置PIN的复用电气属性

1.2 PIN信息的添加:在.dtsi文件中添加,以宏的方式添加,格式为<引脚宏定义 电气属性值>
比如: MX6UL_PAD_UART1_RTS_B__GPIO1_IO09 0x17059

1.3 PIN宏定义在imx6ul-pinfunc.h或在imx6ull-pinfunc.h
比如: MX6UL_PAD_UART1_RTS_B__GPIO1_IO09 0x0090 0x031C 0x0000 0x5 0x0

• <mux_reg             conf_reg              input_reg     mux_mode     input_val>
  0x0090                0x031C                0x0000         0x5           0x0
• 含义
mux_reg:复用寄存器偏移地址 
conf_reg: 电气属性配置寄存器偏移地址
input_reg:输入寄存器偏移(偏移为0表示此PIN没有input功能)
mux_mode:复用模式
input_val:写入input_reg的值

PIN的电气属性配置寄存器的值:0x17059,即是conf_reg要设置的值

  1. GPIO子系统
    2.1 初始化GPIO和提供对GPIO操作的API函数

  2. 匹配
    3.1 imx6ull.dtsi文件下的

	iomuxc: iomuxc@020e0000 {
					compatible = "fsl,imx6ul-iomuxc";	/* compatible属性非常重要 */
					reg = <0x020e0000 0x4000>;
				};

3.2 pinctrl-imx6ul.c文件下的匹配表

	static struct of_device_id imx6ul_pinctrl_of_match[] = {
	/* 这个匹配表的compatible值和设备树imx6ull.dtsi下iomuxc节点的compatible属性值一致 */
		{ .compatible = "fsl,imx6ul-iomuxc", .data = &imx6ul_pinctrl_info, },
		{ .compatible = "fsl,imx6ull-iomuxc-snvs", .data = &imx6ull_snvs_pinctrl_info, },
		{ /* sentinel */ }
	};

3.2.1 驱动文件下的platform_driver结构体初始化

	static struct platform_driver imx6ul_pinctrl_driver = {
		.driver = {
			.name = "imx6ul-pinctrl",
			.owner = THIS_MODULE,
			.of_match_table = of_match_ptr(imx6ul_pinctrl_of_match),
		},
		.probe = imx6ul_pinctrl_probe,
		.remove = imx_pinctrl_remove,
	};

3.2.2 imx6ul_pinctrl_probe函数

	static int imx6ul_pinctrl_probe(struct platform_device *pdev)
	{
		const struct of_device_id *match;
		/*pinctrl_info信息就会在pinctrl_register向系统注册结构体之前的imx_pinctrl_desc->pctlops使用
		pinctrl_info保存了platform_device下的设备和imx6ul_pinctrl_of_match匹配表的匹配结果,即最佳匹配的of_device_id
		而of_device_id就是platform驱动框架下开发人员必须定义的设备匹配表
		*/
		struct imx_pinctrl_soc_info *pinctrl_info;    
	
		match = of_match_device(imx6ul_pinctrl_of_match, &pdev->dev);
	
		if (!match)
			return -ENODEV;
	
		pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;
	
		return imx_pinctrl_probe(pdev, pinctrl_info);
	}
  1. 最终调用pinctrl-imx.c文件下的imx_pinctrl_probe函数
	int imx_pinctrl_probe(struct platform_device *pdev, struct imx_pinctrl_soc_info *info)
	{
		……
		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
		ipctl->base = devm_ioremap_resource(&pdev->dev, res);
		……
		imx_pinctrl_desc->name = dev_name(&pdev->dev);
		imx_pinctrl_desc->pins = info->pins;
		imx_pinctrl_desc->npins = info->npins;
		/* 三个重要的ops结构体 */
		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);
		……
		ipctl->info = info;
		ipctl->dev = info->dev;
		
		ipctl->pctl = pinctrl_register(imx_pinctrl_desc, &pdev->dev, ipctl);
	}

pinctrl_register向系统注册imx_pinctrl_desc结构体和platform_device结构体下的设备&pdev->dev。

4.1三个重要的ops结构体
4.1.1 imx_pctrl_ops

static const struct pinctrl_ops imx_pctrl_ops = {
			……
			.dt_node_to_map = imx_dt_node_to_map,
			……
		}

imx_pctrl_ops结构体下的imx_dt_node_to_map成员,首先通过imx_pinctrl_find_group_by_name(info, np->name);在对应的组中查找节点(通过节点名字查找)

static const inline struct imx_pin_group *imx_pinctrl_find_group_by_name(
					const struct imx_pinctrl_soc_info *info,
					const char *name)

函数的第一个*info参数非常重要,有没有发现imx_pinctrl_soc_info此结构体很熟悉啊!!!此结构体就是imx6ul_pinctrl_probe函数中获取到的匹配设备信息。用户向内核注册驱动时,将platform驱动结构体通过platform_driver_register()函数传递给内核,其中这个结构体就包括了驱动的匹配列表!!!

4.1.2 imx_pmx_ops:设置PIN的复用

static const struct pinmux_ops imx_pmx_ops = {
	……
	.set_mux = imx_pmx_set,
	……
};
static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, unsigned group){
	……
	/* 配置PIN的复用模式 */
	……
}

4.1.3 imx_pinconf_ops:设置PIN的电气属性

static const struct pinconf_ops imx_pinconf_ops = {
				……
	.pin_config_set = imx_pinconf_set,
				……
	for (i = 0; i < num_configs; i++) {
		if (info->flags & SHARE_MUX_CONF_REG) {
		/* 共享复用配置寄存器???所以采样 "读->改->写" 的方式 ?*/
			u32 reg;
			reg = readl(ipctl->base + pin_reg->conf_reg);  /* 读出寄存器的值 */
			reg &= ~0xffff;
			reg |= configs[i];    /* 修改寄存器的值 */
			writel(reg, ipctl->base + pin_reg->conf_reg);    /* 将修改的结果写入寄存器 */
		} else {
			writel(configs[i], ipctl->base + pin_reg->conf_reg);
		}
}
  1. imx_pinctrl_probe中的imx_pinctrl_probe_dt函数
imx_pinctrl_probe_dt(struct platform_device *pdev,struct imx_pinctrl_soc_info *info)
		->for_each_child_of_node(np, child)    /* 解析每个子节点 */
			imx_pinctrl_parse_functions(child, info, i++);
				->imx_pinctrl_parse_groups(child, grp, info, i++);
					pin_reg->mux_reg = mux_reg;
					pin_reg->conf_reg = conf_reg;
					pin->input_reg = be32_to_cpu(*list++);
					pin->mux_mode = be32_to_cpu(*list++);
					pin->input_val = be32_to_cpu(*list++);
					......
<mux_reg    conf_reg    input_reg    mux_mode   input_val>

这五个变量的值是不是很熟悉!!!这不就是在imx6ul-pinfunc.h或在imx6ull-pinfunc.h文件下PIN的宏定义吗!!至此,pinctrl完成了PIN的复用和电气属性值的获取。
imx_pinctrl_probe中的三个ops结构体完成PIN的复用设置和电气属性的设置。
总结:

  1. 驱动文件下的platform驱动结构体通过platform_driver_register()函数传递给内核,而platform驱动结构体包含了匹配列表成员,此匹配列表的compatible属性就是通过总线的设备和驱动匹配中找到对应的设备,此设备的描述信息就在设备树对应的节点下;
  2. 匹配在文中的3.2.2小节的imx6ul_pinctrl_probe函数中已经完成
  3. 完成匹配之后,调用imx_pinctrl_probe用于获取和设置PIN的复用与电气属性。

<下一篇将介绍具体的匹配过程:of_match_device>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值