第九章 理一理驱动程序的编写-9.2-9.4pinctrl子系统和gpio子系统再理解

承接:第九章 理一理驱动程序的编写

目录

9.2.什么是pinctrl子系统?

9.3.什么是gpio子系统?

9.4.gpio和pinctrl子系统怎么编写?

9.5 2个子系统是怎么被内核调用的?


9.2.什么是pinctrl子系统?

    pinctrl子系统主要用来设置pin的复用功能以及电气特性。参考STM32中用来配置引脚复用和电气特性时使用如下代码:

/*开启引脚复用功能PB14/PB15*/
GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_9);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_9);
/*引脚的配置PB14/PB15*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB,&GPIO_InitStructure);	

    pinctrl就是把上面的这些类似的代码简化为简单的语句,看下需要怎么简化。之前问过自己4个问题其实是3个问题:pinctrl是什么?怎么写?怎么用?

    pinctrl是什么?已经知道了。

    怎么写?参考文档如下图,之前分析过这些,感觉还是没有理清楚,重新理顺一下并用简练的语言把pinctrl总结出来。

第九章 理一理驱动程序的编写-9.2-9.4pinctrl子系统和gpio子系统再理解_第1张图片

    原谅我是初学对Linux系统的专有术语还不太清楚,只能用通俗的话来描述专业的东西。

    fsl,imx-pinctrl.txt,因为手里的单板是imx6ull所以先看了fsl,imx-pinctrl.txt,核心内容就是描述IOMUX Controller (IOMUXC)在设备树中是一个节点(node),用来选择引脚复用功能和配置引脚电气特性,涉及2个properties:

  • compatible: "fsl,-iomuxc",用来确定是哪块soc的iomux,soc是可变量,如果是6ull就写成"fsl,imx6ull-iomuxc",如果是7d系列就写成"fsl,imx7q-iomuxc"。
  • xxx,pins:对于这个变量配置各家不一样,比如有fsl,pins、rockchip,pins和samsung,pins等。fsl,pins的由6个整数来配置,例如,具体的内容之前分析过(https://blog.csdn.net/fendoulanyan/article/details/105152224),这里不说了。其他家也是类似的定义形式,归根结底就是对IO寄存器的配置。

    fsl,imx6ul-pinctrl.txt,没什么内容和fsl,imx-pinctrl.txt差不多。

    pinctrl-bindings.txt,共用文档,适用所有SOCs,依次说明了Pinctrl client devices即pinctrl的使用者,Pin controller devices、Generic pin multiplexing/configuration  node content。

    xxx.dtsi和.dts,具体内容不列出了。

    针对上面的各个文档,做一个mind导图,用它把思路理顺出来了,可惜图片放上来就压缩不清晰了。

    以6ull控制led为例分析下,使用IOMUXC_SNVS配置GPIO5_3:

    在imx6ull.dtsi中定义了iomuxc_snvs节点,它隶属/root/soc/aips-bus/,内容如下,内容很少,很简洁,就是定义了这个节点和属性。

iomuxc_snvs: iomuxc-snvs@02290000 {
	compatible = "fsl,imx6ull-iomuxc-snvs"; 
	reg = <0x02290000 0x10000>;
};

    在100ask_imx6ull-14x14.dts中调用&iomuxc_snvs节点,填充配置,注意&iomuxc_snvs是在根节点下,但是pinctrl_leds是孙节点,并不一定是子节点。

1&iomuxc_snvs {
2	pinctrl-names = "default_snvs";
3	pinctrl-0 = <&pinctrl_hog_2>;
4	imx6ul-evk {
5		pinctrl_hog_2: hoggrp-2 {
6			fsl,pins = <
7				MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09    0x1b0b0 /* enet1 reset */
8				MX6ULL_PAD_SNVS_TAMPER6__GPIO5_IO06    0x1b0b0 /* enet2 reset
9				MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01    0x000110A0 /*key 1*/
11			>;
12		};
13       /* 省略其他无关代码 */
14		pinctrl_leds: ledgrp {
15			fsl,pins = <
16			      MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03  0x000110A0
17			>;
18		};
};
};
--1-->引用iomuxc_snvs节点;

--14-->定义了pinctrl_leds孙节点用来配置GPIO5_IO3;
--15-->fsl,pins就是前面针对fsl SOC的properties;
--16-->前面之前已经讲过了;

--2-3-->定义了pinctrl-names和pinctrl-0,这不都是client device的properties吗?意思是iomuxc_snvs也是一个client device,可以调用pinctrl;
--3-->调用pinctrl_hog_2,默认执行pinctrl_hog_2喽;

    问题来了那谁调用pinctrl_leds呢?可以引出下一个问题了。

    小结:在.dsti中定义iomux节点,在具体单板的.dts中调用该节点并配置pinctrl


9.3.什么是gpio子系统?

    gpio子系统就是用于初始化gpio并提供统一操作接口。

    还是先看下参考文档,

    在整理这个mind的过程中发现:在.dtsi中iomuxc_snvs node并不是gpio node,只是一个tree node,只有gpio1-5才是真正的gpio node,即必须具有gpio-controller和#gpio-cells属性;在.dts中的leds_my node也只是一个普通的tree node,但它包含了pinctrl 属性就可以去调用pinctrl node,包含了xxx-gpio属性,就可以去设置某个gpio或者某组gpio。内核驱动程序怎么去调用xxx-gpio属性呢?通过board.txt中介绍的gpiod_get()/ gpiod_get_index(),即gpio子系统的API函数。

    贴一下6ull源代码吧,iomuxc_snvs和&iomuxc_snvs代码在上一节中已经贴了,这里只贴自己编写的led操作节点,如下:

1	leds_my {
2		compatible = "100ask,leddrv";
3		pinctrl-names = "default";
4		pinctrl-0 = <&pinctrl_leds>;
5		led-gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
6	};
--1-->定义leds_my节点;
--4-->定义pinctrl-0属性,调用pinctrl_leds;
--5-->定义led-gpios属性,对gpio5_io3进行初始化,GPIO_ACTIVE_LOW;

    对.dts中的pinctrl和gpio子系统做一个小结:先调用.dtsi中的iomux节点,再创建它的子节点或孙节点用于配置io为复用功能+电气特性,然后定义一个根节点,包含并配置pinctrl和gpios属性,即可。

    到此也解决了pinctrl和gpio子系统怎么编写的问题。

    编写好了之后,内核是怎么调用它们的呢?

9.4.gpio和pinctrl子系统怎么编写?

    已解决

9.5 2个子系统是怎么被内核调用的?

    后来补充:在8.3.5中知道节点中含有compatible属性才可以转成platform_device,那leds_my可以转换成platform_device,属性会存放properties结构体中。前面已经了解到使用gpiod_get()/ gpiod_get_index()可以调用led-gpios,后面再研究。

    ……

你可能感兴趣的:(I.MX6)