承接:第九章 理一理驱动程序的编写
目录
9.2.什么是pinctrl子系统?
9.3.什么是gpio子系统?
9.4.gpio和pinctrl子系统怎么编写?
9.5 2个子系统是怎么被内核调用的?
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总结出来。
原谅我是初学对Linux系统的专有术语还不太清楚,只能用通俗的话来描述专业的东西。
fsl,imx-pinctrl.txt,因为手里的单板是imx6ull所以先看了fsl,imx-pinctrl.txt,核心内容就是描述IOMUX Controller (IOMUXC)在设备树中是一个节点(node),用来选择引脚复用功能和配置引脚电气特性,涉及2个properties:
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。
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子系统怎么编写的问题。
编写好了之后,内核是怎么调用它们的呢?
已解决
后来补充:在8.3.5中知道节点中含有compatible属性才可以转成platform_device,那leds_my可以转换成platform_device,属性会存放properties结构体中。前面已经了解到使用gpiod_get()/ gpiod_get_index()可以调用led-gpios,后面再研究。
……