设备树知识小全(九):GPIO、时钟、pinmux连接

除了中断以外,在ARM Linux中时钟、GPIO、pinmux都可以通过.dts中的节点和属性进行描述。

(pinmux—Pin Multiplexing缩写,即引脚复用,通常CPU的管脚数量有限,通过复用来实现不同功能)

这设备树真的是很全面?还记得第一篇说dts可以描述的硬件信息有哪些吗?

参考资料:《Linux设备驱动开发详解》宋老师的书

1、GPIO

譬如,对于GPIO控制器而言,其对应的设备节点需声明gpio-controller属性并设置#gpio-cells的大小。

譬如,对于兼容性为fsl,imx28-pinctrl的pinctrl驱动而言,其GPIO控制器的设备节点类似于:

pinctrl@80018000 {
compatible = "fsl,imx28-pinctrl", "simple-bus";
reg = <0x80018000 2000>;
        gpio0: gpio@0 {
compatible = "fsl,imx28-gpio";
interrupts = <127>;
gpio-controller;
                #gpio-cells = <2>;
interrupt-controller;
                #interrupt-cells = <2>;
        };
        gpio1: gpio@1 {
compatible = "fsl,imx28-gpio";
interrupts = <126>;
gpio-controller;
                #gpio-cells = <2>;
interrupt-controller;
              #interrupt-cells = <2>;
        };
        ...
};

其中,#gpio-cells为2,第1 个cell为GPIO号,第2个为GPIO的极性。为0的时候是高电平有效,为1的时候则是低电平有效。

使用GPIO的设备则通过定义命名xxx-gpios属性来引用GPIO控制器的设备节点,如:

       sdhci@c8000400 {
status = "okay";
cd-gpios = <&gpio01 0>;
wp-gpios = <&gpio02 0>;
power-gpios = <&gpio03 0>;
bus-width = <4>;
        };

而具体的设备驱动则通过类似如下的方法来获取GPIO:

cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
power_gpio = of_get_named_gpio(np, "power-gpios", 0);

of_get_named_gpio()这个API的原型如下:

static inline int of_get_named_gpio(struct device_node *np,
const char *propname, int index);

在.dts和设备驱动不关心GPIO名字的情况下,也可以直接通过of_get_gpio()获取GPIO,此函数原型为:

static inline int of_get_gpio(struct device_node *np, int index);

如对于compatible="gpio-control-nand"的基于GPIO的NAND控制器而言,在.dts中会定义多个gpio属性:

gpio-nand@1,0 {
compatible = "gpio-control-nand";
reg = <1 0x0000 0x2>;
       #address-cells = <1>;
       #size-cells = <1>;
gpios = <&banka 1 0     /* rdy */
&banka 2 0     /* nce */
&banka 3 0     /* ale */
&banka 4 0     /* cle */
                0              /* nwp */>;
       partition@0 {
       ...
       };
};

在相应的驱动代码drivers/mtd/nand/gpio.c中是这样获取这些GPIO的:

plat->gpio_rdy = of_get_gpio(dev->of_node, 0);
plat->gpio_nce = of_get_gpio(dev->of_node, 1);
plat->gpio_ale = of_get_gpio(dev->of_node, 2);
plat->gpio_cle = of_get_gpio(dev->of_node, 3);
plat->gpio_nwp = of_get_gpio(dev->of_node, 4);

2、时钟

时钟和GPIO也是类似的,时钟控制器的节点被使用时钟的模块引用

clocks = <&clks 138>, <&clks 140>, <&clks 141>;
clock-names = "uart", "general", "noc";

而驱动中则使用上述的clock-names属性作为clk_get()或devm_clk_get()的第二个参数来申请时钟,譬如获取第2个时钟:

devm_clk_get(&pdev->dev, "general");

<&clks 138>里的138这个index是与相应时钟驱动中clk的表的顺序对应的,很多开发者也认为这种数字出现在设备树中不太好,因此他们把clk的index作为宏定义到了arch/arm/boot/dts/include/dt-bindings/clock中。譬如include/dt-bindings/clock/imx6qdl-clock.h中存在这样的宏:

#define IMX6QDL_CLK_STEP                        16
#define IMX6QDL_CLK_PLL1_SW                     17…
#define IMX6QDL_CLK_ARM                         104…

而arch/arm/boot/dts/imx6q.dtsi则是这样引用它们的:

clocks = <&clks IMX6QDL_CLK_ARM>,
<&clks IMX6QDL_CLK_PLL2_PFD2_396M>,
<&clks IMX6QDL_CLK_STEP>,
<&clks IMX6QDL_CLK_PLL1_SW>,
<&clks IMX6QDL_CLK_PLL1_SYS>;

3、pinmux

在设备树中,**某个设备节点使用的pinmux的引脚群是通过phandle来指定的。**譬如在arch/arm/boot/dts/atlas6.dtsi的pinctrl节点中包含所有引脚群的描述,如代码清单18.15所示。

 1 gpio: pinctrl@b0120000 {
 2         #gpio-cells = <2>;
 3         #interrupt-cells = <2>;
 4         compatible = "sirf,atlas6-pinctrl";
 5       …
 6
 7         lcd_16pins_a: lcd0@0 {
 8                lcd {
 9                       sirf,pins = "lcd_16bitsgrp";
10                       sirf,function = "lcd_16bits";
11                };
12         };
13       …
14         spi0_pins_a: spi0@0 {
15                spi {
16                       sirf,pins = "spi0grp";
17                       sirf,function = "spi0";
18                };
19         };
20         spi1_pins_a: spi1@0 {
21                spi {
22                       sirf,pins = "spi1grp";
23                       sirf,function = "spi1";
24                };
25         };
26       …
27 };

而SPI0这个硬件实际上需要用到spi0_pins_a对应的spi0grp这一组引脚,因此在atlas6-evb.dts中通过pinctrl-0引用了它,如代码清单18.16所示。

 1 spi@b00d0000 {
 2          status = "okay";
 3          pinctrl-names = "default";
 4          pinctrl-0 = <&spi0_pins_a>;
 5        …
 6 };

到目前为止,我们可以勾勒出一个设备树的全局视图,图18.2显示了设备树中的节点、属性、label以及phandle等信息。

在这里插入图片描述

下面看看当有了设备树对BSP产生了什么影响?

  • 0
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
RV1109是一款搭载了RISC-V架构的嵌入式处理器,而i2c-gpio则是一种基于GPIO模拟的I2C总线接口。在RV1109设备树中配置i2c-gpio需要进行如下步骤: 1. 在设备树中添加i2c-gpio节点 在RV1109设备树中添加i2c-gpio节点并进行相关配置,例如: ``` i2c-gpio { #address-cells = <1>; #size-cells = <0>; compatible = "i2c-gpio"; sda-gpios = <&gpio0 4 GPIO_ACTIVE_LOW>; scl-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; gpios = <&gpio0 4 GPIO_ACTIVE_LOW &gpio0 5 GPIO_ACTIVE_LOW>; clock-stretch-timeout = <5000>; i2c-gpio,delay-us = <2>; i2c-gpio,timeout-us = <20000>; status = "okay"; }; ``` 2. 配置i2c设备节点 在设备树中添加i2c设备节点,例如: ``` i2c1 { #address-cells = <1>; #size-cells = <0>; clock-frequency = <400000>; status = "okay"; my_i2c_device: my_i2c_device@50 { compatible = "my,i2c-device"; reg = <0x50>; }; }; ``` 其中,`my_i2c_device`代表你添加的I2C设备节点的名称,`50`代表I2C设备的地址。 3. 设置I2C控制器节点的属性 在设备树中添加I2C控制器节点的属性,例如: ``` &i2c1 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&i2c1_pins_a>; clock-frequency = <400000>; my_i2c_device: my_i2c_device@50 { compatible = "my,i2c-device"; reg = <0x50>; }; }; ``` 其中,`&i2c1`代表I2C控制器节点名称,`my_i2c_device`代表你添加的I2C设备节点的名称。 以上是在RV1109设备树中配置i2c-gpio的大致步骤,具体的配置会因为不同的情况而有所差异,需要根据具体情况进行配置。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TrustZone_Hcoco

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值