IMX6ULL pinctrl子系统

目录

 

概述

 

设备树表示

 

内核中操作

 

总结


概述

在前面的学习过程中操作了很多的IO引脚,那么,使用一个IO引脚最重要的三部分

1、配置IO的复用,主要是MUX类的寄存器

2、配置IO的电气属性,主要配置PAD类的寄存器

3、配置IO的输入输出

 

设备树表示

设备树的引入方便开发者对设备进行描述,对于外设的一些引脚的使用,在设备树中也有描述,称为pinctrl子系统,内核根据设备树中的描述来完成对管脚的配置,这篇随着imx6ull平台的设备树分析来简单了解一些内核的pinctrl子系统,打开设备树,找到引脚复用的节点,

    	   iomuxc: iomuxc@020e0000 {
				compatible = "fsl,imx6ul-iomuxc";
				reg = <0x020e0000 0x4000>;
			};

0x020e0000就是芯片的管脚复用控制寄存器的基地址,这个是在dtsi文件中描述的,为芯片的公共资源,接下来在dts文件中找对于iomuxc节点的补充

&iomuxc {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_hog_1>;
	imx6ul-evk {
		pinctrl_hog_1: hoggrp-1 {
			fsl,pins = <
				MX6UL_PAD_UART1_RTS_B__GPIO1_IO19	0x17059 /* SD1 CD */
				MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT	0x17059 /* SD1 VSELECT */
				/* MX6UL_PAD_GPIO1_IO09__GPIO1_IO09        0x17059 SD1 RESET */
				MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID	0x13058	/* USB_OTG1_ID */
			>;
		};
}

内容有很多,写法都是类似,这些都是对具体的外设所使用的GPIO进行描述,找到一个

MX6UL_PAD_UART1_RTS_B__GPIO1_IO19   0x17059

由两部分组成,前面是一个宏,后面为一个数字,首先从宏的名字来看就知道它是UART1_RST复用为GPIO1_IO19,在设备树的引入文件中都已找到宏对应的含义

/*
 * The pin function ID is a tuple of
 * 
 */
#define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19                         0x0090 0x031C 0x0000 0x5 0x0

看到这里就知道它的含义了,这个宏对应5个值,分别为注释中的5个寄存器的值,

 mux_reg 	0x0090     io复用寄存器偏移地址
 conf_reg 	0x031C     io电气属性寄存器偏移地址
 input_reg 	0x0000     input寄存器偏移地址
 mux_mode	0x5        复用模式
 input_val 	0x0        输入值

找到UART1_RST管脚的相关寄存器

IMX6ULL pinctrl子系统_第1张图片

这个寄存器的地址是20E_0090h,上面的mux_reg的值是偏移值,加上最前面的iomuxc寄存器的基地址不就是这个寄存器的真实地址了吗,其他几个寄存器也是一样的,就不去验证了

这里着重看一下mux_mode的值,表示复用模式,查看IOMUXC_SW_MUX_CTL_PAD_UART1_RTS_B寄存器

IMX6ULL pinctrl子系统_第2张图片

UART1_RST_B复用模式为5的话,就是将这个引脚复用为GPIO1_IO19,和宏的名字是一致的。IO的复用就是这样表示的

那么,还有一个表示电气属性的值,在这个宏里只有电气属性寄存器的地址,一般电气属性可以随时修改,所以不能放在宏里表示,还记得上面宏后面还跟了一个数字吗?那个就是电气属性的值

配置一个IO所必须的在这里都可以找出来,,接下来就是看内核是如何把这些值关联起来,来配置具体的IO

 

内核中操作

根据iomuxc节点的compatible属性就可以找到相关的c文件

IMX6ULL pinctrl子系统_第3张图片

具体的代码也比较多,这里就不去全部分析出来了,主要过程总结为

1、申请一个struct pinctrl_desc *imx_pinctrl_desc;结构体类型变量,对结构体进行赋值,主要是一些操作函数集

IMX6ULL pinctrl子系统_第4张图片

2、然后就是去解析设备树,分析iomux节点的内容,获取它的引脚

IMX6ULL pinctrl子系统_第5张图片

这些信息都记录在了imx_pinctrl_desc这个结构体当中,

3、使用pinctrl_register函数,把结构体注册到系统当中,并通过厂商自己提供的操作函数来配置GPIO

 

总结

这一部分我也没有深入的去分析,但是如果我们熟悉驱动或者内核开发的流程,就可以看出它的套路

1、首先,内核定义出了一套关于GPIO配置的结构,但是它不可能去涉及到具体的单板,具体单板的GPIO的配置肯定是由厂商自己来定义的

2、厂商根据内核的框架,实现一个结构体,并根据自己的单板填充结构体的操作函数集,这个操作函数无疑就是具体的GPIO的配置,

      比如imx6ull,它就会获取设备树中的那5个值和管脚的电气属性值,然后把值写到对应的寄存器中,其他的都是类似

3、使用内核提供函数,把这个结构体注册到系统中,这样,系统跑起来的时候,只需要找到结构体,然后执行其中的函数,就可以从公共执行到具体,最终完成某款单板的IO配置

不仅仅是pinctrl子系统,内核的代码框架都是采用这种注册回调的方式来完成的。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(IMX6)