进行嵌入式Linux驱动开发时,不可避免的会涉及到DTS相关的编写工作,而其中,最为重要的一项工作就是pinctrl相关的配置,这包括pins的功能选择(作为普通IO,还是作为外围控制器的pins)以及pins的配置(pull-up/pull-down、驱动能力、三态等)。 内核中的pinctrl子系统抽象了不同SoC中关于pins的管理方式,Linux内核之pinctrl子系统对于pinctrl子系统进行了简要的概述,如果想要了解pinctrl子系统,可以参考这篇博文。
本文主要讲解对于一个具体的设备驱动,如何在DTS中基于pinctrl实现关于pins的管理,这包括:
- 如何定义pin功能
- 驱动程序如何引用pin
如何定义pin功能
利用内核文档
市面上存在很多的SoC,一般情况下,不同的SoC在DTS中关于pin的管理方式会有一些不同。SoC厂商在发布时,会编写相关的pinctrl驱动程序,同时,会在内核目录Documentation/devicetree/bindings/pinctrl下,编写相关的配置说明,比如,fsl,imx-pinctrl.txt 里面说明了 Freescale IOMUX Controller (IOMUXC) for I.MX相关的配置说明;rockchipi, pinctrl.txt里面说面了Rockchip Pinmux Controller相关的配置说明。
所以,当我们拿到一块电路板时,首先,需要确定其使用的SoC,然后,去Documentation/devicetree/bindings/pinctrl目录下,找到关于该款SoC相关的pinctrl的配置说明。这里需要注意的时,某个厂商的SoC一般遵循相同的pinctrl配置方式,所以,在未找到具体SoC的 pinctrl使用说明时,可以直接查看这个SoC厂商的说明文档,比如,我们如果使用的是s3c6410,可以看到该目录下,没有s3c6410相关的说明,但是,我们可以找到samsung-pinctrl.txt,参照这个文档,同样可以在DTS中配置pinctrl。
pin配置举例
下面拿一个例子,说明一下如何在DTS中定义pin的功能。
Freescale IOMUX
关于Freescale SoC的pinctrl配置,主要完成一下两项内容:
- 确定SoC的pinctrl控制器的兼容性: compatible: "fsl,-iomuxc",关于SoC的IOMUX的兼容性,需要到fsl,-pinctrl.txt中获得。
- 配置具体的pins: fsl,pins/,该字段定义了pin的功能,其一般定义一组pins的功能,这一组pins服务于同一function,比如spi控制器。每个配置项包括6字段分别是:前5个字段分别是,可以到/arch/arm/boot/dts的imx*-pinfunc.h中找到他们的定义,
比如,imx6ul-pinfunc.h定义imx6ul这款SoC的所有pins。6个字段是pin的配置参数,比如:pull-up/pull-down等。
下面是sd卡所用到的pin的功能配置定义:
usdhc@219c000 { /* uSDHC4 */ non-removable; vmmc-supply = <®_3p3v>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usdhc4_1>; }; iomuxc@20e0000 { compatible = "fsl,imx6q-iomuxc"; reg = <0x020e0000 0x4000>; /* shared pinctrl settings */ usdhc4 { pinctrl_usdhc4_1: usdhc4grp-1 { fsl,pins = < MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 >; }; .... };
- iomuxc的兼容性为"fsl,imx6q-iomuxc";
- 节点pinctrl_usdhc4_1定义了设备uSDHC4所使用的pins功能。
驱动程序如何使用pins
对于普通的设备,如何定义其使用到的pin呢?上面关于Freescale IOMUX的举例,说明了uSDHC4这个设备如何定义pins的功能。文档pinctrl-bindings.txt中说明了一般情况下如何在DTS中定义一个设备驱动的pins功能。
如果一个设备使用到某些pins,那么,在其DTS节点中至少包含下面两项内容:
- pinctrl-names:定义设备不同的工作状态,一般包括下面几个:default、init、sleep、idle。其中,sleep、idle用于系统的电源管理,以达到控制系统功耗的目的。
- pinctrl-0:定义了一个phandles的列表,每个phandle指向一个pinctrl的节点。该配置项定义了该设备的一种工作状态,其对应于pinctrl-names中首个工作状态。
下面举例说明一下: deviceA { pinctrl-names = "defalut", "idle"; pinctrl-0 = <&state_0_node_a>; pinctrl-1 = <&state_1_node_a &state_1_node_b>; };
deviceA节点,定义了"default","idle"两种工作状态,所以,下面依次定义了pinctrl-0和pinctrl-1两个pins列表,分别对应于上面两个状态。
上面内容,说明了一个设备如何在DTS中配置其所用到的pins,后面文章还具体分析pinctrl子系统在DTS中的配置方式。