山高疑日近,海阔觉天低

Linux设备树

在3.x 版本以前的Linux 内核中ARM 架构并没有采用设备树。在Linux 内核源码中大量的arch/arm/mach-xxx 和arch/arm/plat-xxx 文件夹,这些文件夹里面的文件就是对应平台下的板级信息。比如在arch/arm/mach-s3c24xx/mach-smdk2440.c ,其中s3c24xx是CPU,smdk2440是开发板,所以arch/arm/mach-CPU。

一,dtsi 头文件

.dtsi 文件用于描述 SOC 的内部外设信息,比如 CPU 架构、主频、外设寄存器地址范围,比如 UART、IIC 等等。比如 imx6ull.dtsi 就是描述 I.MX6ULL 这颗 SOC 内部外设情况信息的,I.MX6ULL 这颗 SOC 所有的外设都描述的清清楚楚,比如 ecspi1~4、uart1~8、usbphy1~2、i2c1~4等等。I.MX6ULL 内部分为三个域:aips1~3,这三个域分管不同的外设控制器,

{
compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";
cpus {
  #address-cells = <1>;
  #size-cells = <0>;
  //CPU0 节点
  cpu0: cpu@0 {
    compatible = "arm,cortex-a7";
    device_type = "cpu";
    reg = <0>;
  };
};
//soc 节点
soc {
  #address-cells = <1>;
  #size-cells = <1>;
  compatible = "simple-bus";
  ranges;
  //ocram 节点
  ocram: sram@00900000 {
    compatible = "fsl,lpm-sram";
    reg = <0x00900000 0x20000>;
  };
  //aips1 节点
  aips1: aips-bus@02000000 {
    compatible = "fsl,aips-bus", "simple-bus";
    #address-cells = <1>;
    #size-cells = <1>;
    reg = <0x02000000 0x100000>;
    ranges;
    iomuxc: iomuxc@020e0000 {
	  compatible = "fsl,imx6ul-iomuxc";
	  reg = <0x020e0000 0x4000>;
	};
  }
//aips2 节点
  aips2: aips-bus@02100000 {
    compatible = "fsl,aips-bus", "simple-bus";
    #address-cells = <1>;
    #size-cells = <1>;
    reg = <0x02100000 0x100000>;
    ranges;
    }
//aips3 节点
  aips3: aips-bus@02200000 {
    compatible = "fsl,aips-bus", "simple-bus";
    #address-cells = <1>;
    #size-cells = <1>;
    reg = <0x02200000 0x100000>;
    ranges;
    }
  }
}
//imx6ull-14x14-zhang.dts
/{
  model = "Freescale i.MX6 ULL 14x14 EVK Board";
  compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";
  chosen {//主要是为了 uboot 向 Linux 内核传递数据,重点是 bootargs 参数
     stdout-path = &uart1;
  };
  memory {
    reg = <0x80000000 0x20000000>;
  };
,,,

在/proc/devicetree (软连接指向:/sys/firmware/devicetree/base)目录下可以查看整个设备树,字符串用cat查看,int32 用hexdump查看
二,标准属性
1、compatible 属性
compatible 属性也叫做“兼容性”属性,这是非常重要的一个属性!compatible 属性的值是一个字符串列表,compatible 属性用于将设备和驱动绑定起来。一般驱动程序文件都会有一个 OF 匹配表,此 OF 匹配表保存着一些 compatible 值,如果设备节点的 compatible 属性值和 OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个驱动。
2、model 属性
model 属性值也是一个字符串,一般 model 属性描述设备模块信息,比如名字什么的,比如:model = “wm8960-audio”;
3、status 属性 属性
和设备状态有关的,status 属性值也是字符串,字符串是设备的状态信息:
okay” 表明设备是可操作的。
disabled” 表明设备当前是不可操作的,未来可以变为可操作的,比如热插拔设备插入以后。disabled 的具体含义还要看设备的绑定文档。
fail”表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可操作。
fail-sss” 含义和“fail”相同,后面的 sss 部分是检测到的错误内容。
4、#address-cells 和#size-cells 属性
用于描述子节点的地址信息。#address-cells 了子节点 reg 属性中地址信息(32 位),#size-cells 子节点 reg 属性中长度
5、reg属性
reg = <address1 length1 address2 length2 address3 length3……>,这是reg的一般格式。注意reg第一个地址信息一般与节点地址一致

三,of函数

设备树描述了设备的详细信息,包括数字类型的、字符串类型的、数组类型的,我们在编写驱动的时候需要获取到这些信息。比如设备树使用 reg 属性描述了某个外设的寄存器地址为 0X02005482,长度为 0X400,我们在编写驱动的时候需要获取到 reg 属性的0X02005482 和 0X400 这两个值,然后初始化外设。Linux 内核给我们提供了一系列的函数来获取设备树中的节点或者属性信息,这一系列的函数都有一个统一的前缀“of_”,所以在很多资
料里面也被叫做 OF 函数。这些 OF 函数原型都定义在 include/linux/of.h 文件中。

1、节点查找函数
1、of_find_node_by_name 函数:节点名字
2、of_find_node_by_type 函数:device_type
3、of_find_compatible_node 函数:据device_type 和 compatible
4、of_find_matching_node_and_match 函数:of_device_id
5、of_find_node_by_path 函数:路径
6,of_get_parent/of_get_next_child

2、提取属性值的 OF 函数 

1、of_find_property  函数:用于查找指定的属性
2、of_property_count_elems_of_size 函数:用于获取属性中元素的数量,比如 reg 属性值是一个数组,可以获取大小
3、of_property_read_u32_index 函数:用于从数组数组获取特定下标的值
4、of_property_read_u*_array 函数:获取数组数据
5、of_property_read_u* 函数:有些属性只有一个值,这四个函数就是用于读取这种只有一个整形值的属性
6,of_property_read_string 读取属性中字符串值
7、of_n_addr_cells/of_n_size_cell

3、gpio的 OF 函数 

&led{
reset-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>,<&gpio1 6 GPIO_ACTIVE_LOW>;
}

int gpio= of_get_named_gpio(struct device_node *np,”reset-gpios”,0)
获取设备树中的gpio,第一个参数是设备树节点,第三个参数是位置比如0是第一个
int gpio_request(unsigned gpio, const char *label)
在使用一个 GPIO 之前一定要使用 gpio_request.进行申请,请求gpio引脚函数,如果设备被占用,返回错误
void gpio_free(unsigned gpio)
如果不使用某个 GPIO 了,那么就可以调用 gpio_free 函数进行释放
int gpio_direction_input(unsigned gpio)
此函数用于设置某个 GPIO 为输入,
int gpio_direction_output(unsigned gpio, int value)
此函数用于设置某个 GPIO 为输出,并且设置默认输出值
int gpio_get_value(unsigned gpio)
获取值
void gpio_set_value(unsigned gpio, int value)
设置GPIO值
Kernel3.13之后支持新的gpio函数,注意以上gpio值设置获取,是绝对值,新加的值设定会根据gpio的极性,

struct gpio_desc * devm_gpiod_get_index(struct device *dev, const char *con_id,  unsigned int idx, enum gpiod_flags flags)

con_id:如上测是 “reset”
idx:索引位置
gpiod_flags:
GPIOD_IN:将 GPIO 设置为输入模式。
GPIOD_OUT_LOW:将 GPIO 设置为输出模式,并初始化为低电平。
GPIOD_OUT_HIGH:将 GPIO 设置为输出模式,并初始化为高电平。

gpiod_set_value(host->reset_gpiod, 1);

设置逻辑电平值

4、其它 

1、of_device_is_compatible 函数:数用于查看节点的 compatible 属性是否有包含指定的字符串
2、of_get_address 用于获取地址属性,主要是“reg”或者“assigned-addresses”
3、of_translate_address  从设备树读取到的地址转换为物理地址
4、of_address_to_resource 函数
5、of_iomap 函数 直接内存映射,以前我们会通过 ioremap 函数来完成物理地址到虚拟地址的映射,采用设备树以后就可以直接通过 of_iomap 函数来获取内存地址所对应的虚拟地址

四,pinctrl 子系统(仅仅NXP有)

Linux 驱动讲究驱动分离与分层,pinctrl 和 gpio 子系统就是驱动分离与分层思想下的产物,驱动分离与分层其实就是按照面向对象编程的设计思想而设计的设备驱动框架。pinctrl 子系统主要工作内容如下:
①、获取设备树中 pin 信息。
②、根据获取到的 pin 信息来设置 pin 的复用功能//IOMUXC_SW_MUX_CTL_PAD_*
③、根据获取到的 pin 信息来设置 pin 的电气特性,比如上/下拉、速度、驱动能力等。//后面的值
对于我们使用者来讲,只需要在设备树里面设置好某个 pin 的相关属性即可,其他的初始化工作均 pinctrl 完成,pinctrl 子系统源码目录为 drivers/pinctrl
下面是uart例子:arch/arm/boot/dts/imx6ul-pinfunc.h包含这些宏

&uart1 {
  pinctrl-names = "default";
  pinctrl-0 = <&pinctrl_uart1>;
  status = "okay";
};
..................
&iomuxc {
  pinctrl-names = "default";
  pinctrl-0 = <&pinctrl_hog_1>;
  imx6ul-evk {
  ..................
  pinctrl_uart1: uart1grp {
    fsl,pins = < 
      MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1     //UART1_TX_DATA 复用为UART1_DCE_TX,电气设置为0x1b0b1
      MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1 >;
    };

如上,是usart的引脚复用/电气设置,只要有节点引用<&pinctrl_uart1>那么这些引脚就会被初始化。

四,gpio 子系统 (仅NXP而且复用为GPIO功能)

Linux 驱动讲究驱动分离与分层

&usdhc1 {
  pinctrl-names = "default", "state_100mhz", "state_200mhz";
  pinctrl-0 = <&pinctrl_usdhc1>;
  pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
  pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
  cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
..................

如上,是sd卡的gpio引脚

1、gpio函数

头文件位于:include/linux/gpio.h

1、gpio_request/gpio_free  这2个成对出现,指定GPIO号直接申请使用
2、gpio_direction_input 函数
3、gpio_direction_output 函数
4、gpio_get_value 函数
5、gpio_set_value 函数

赞(0) 打赏
未经允许不得转载:Mr.Zhang » Linux设备树

你的打赏是我的动力

登录

找回密码

注册