Linux驱动(2)DTS

设备树(DTS)是Linux驱动中用于描述硬件结构的重要概念,它由节点和属性组成,描述了CPU、内存、总线、外设等信息。节点属性如compatible用于标识平台和设备兼容性,name@unit-address描述设备类型和地址,reg表示设备地址,ranges处理地址映射,interrupts管理中断。DTS配置文件在特定路径下,通过修改status和compatible属性来使能控制器和匹配驱动。
摘要由CSDN通过智能技术生成

设备树的概念

  设备树,顾名思义,就是设备组成的树。树这个玩意吧,数据结构里也有,只不过数据结构里的树的叶子是数据,设备树的叶子则是设备,并且没有数据结构那么复杂。是否想起了曾经被各种树支配的恐惧

  Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子节点。属性就是成对出现的键值对name和value。在DTS中,可描述的信息包括:CPU的数量和类别、内存基地址和大小、总线和桥、外设链接、中断控制器和中断使用情况、GPIO控制器和GPIO使用情况、clock控制器和clock使用情况。

/ {
	node1 {
		a-string-property = "A string";
		a-string-list-property = "first string","second string";
		a-byte-data-property = [0x01 0x23 0x34 0x56];
		child-node1 {
			first-child-property;
			second-child-property = <1>;
		};
		child-node2 {
		};
	}
	node2 {
		an-empty-property;
		a-cell-property = <1 2 3 4>;
		child-node1 {
		};
	}
}
  • 1./:根节点,也可以叫root节点,root节点下面含一系列子节点。
    2.node:子节点。
    3.child-node:根节点的子节点的子节点。

节点属性

1.compatible:

  “<manufacturer>,<model>”,可通过根节点的compatible判断属于哪个平台。在根节点的子节点中可判断设备的兼容性。
举个栗子

/ {
	...
	compatible = "mediatek,M78XY";
	...
	fingerprint@0 {
		...
		compatible = "mediatek,fingerx1","fxx,fingerx2";
		...
	}
}

  说明一下,根节点地下的那个compatible属性里说明了这个项目用的是联发科的M78XY平台。然后根节点下面那个子节点中的compatible属性说明这个指纹(fingerprint)不仅支持联发科的fingerx1还兼容fxx的fingerx2。当然,其实这个compatible和驱动那边有关系,为了匹配上这么写的。

2.name@unit-address:

  <name>[@<unit-address>](<>为必须,[]为可选)。name为一个ASCII字符串,用于描述节点对应的设备类型。如果一个节点描述的设备有地址,则应该给出@unit-address。多个相同类型的设备节点的name可以一样,只要unit-address不同即可。设备的unit-address地址也经常在其对应节点的reg属性中给出。
举个栗子

/ {
	...
	compatible = "mediatek,M78XY";
	...
	cpus {
		...
		cpu@000 {
			...
			compatible = "mediatek,cortex-M78";
			...
		}
		cpu@001 {
			...
			compatible = "mediatek,cortex-M78";
			...
		}
	}
	spi@11010000{
		fingerprint@0 {
			...
			compatible = "mediatek,fingerx1","fxx,fingerx2";
			...
		}
	}
}

  说明一下,emmmmm…感觉没啥好说的…就像这样,cpu相同类型设备,但其地址不同。

3.reg:

  <address1 length1[address2 length2][address3 length3]>。父类的address-cells和size-cells决定了子类的相关属性,要包含多少个cell。如果子节点有特殊需求,可自己再定义,这样就可以摆脱父节点的控制。address-cells:决定了address1、2、3包含了几个cell。size-cells:决定了length1、2、3包含了几个cell。子节点中对address-cells与size-cells重赋值可称为重写…吧?…
举个栗子

/ {
	...
	#address-cells = <2>;
	#size-cells = <2>;
	compatible = "mediatek,M78XY";
	...
	cpus {
		...
		#address-cells = <1>;
		#size-cells = <0>;
		cpu@000 {
			...
			reg = <0x000>;
			compatible = "mediatek,cortex-M78";
			...
		}
		cpu@001 {
			...
			reg = <0x001>;
			compatible = "mediatek,cortex-M78";
			...
		}
	}
	spi@11010000{
		...
		reg = <0 0x11010000 0 0x1000>;
		fingerprint@0 {
			...
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <0>;
			compatible = "mediatek,fingerx1","fxx,fingerx2";
			...
		}
	}
}

  说明一下,根节点两个address-cells和两个size-cells,spi继承了它,所以reg的前两个值是指address,后两个值则指size。但是呢,指纹没有继承spi,spi中也么有重定义address-cells和size-cells,而是自己重新定义了那两,只有一个address没有size,所以reg里只有一个值,就是他自己本身重新定义的address-cells。

4.ranges:

  描述一个从设备地址空间到CPU地址空间的映射关系,为一个地址转换表。表中的每一行都包括了子地址、父地址、在子地址空间内的区域大小。他们的大小(包含的cell)分别由子节点的address-cells的值、父节点的address-cells的值和子节点的size-cells来决定。
这个就不举栗子了吧,太重了

5.interrupt:

  (1).interrupt-controller:一个空属性用来声明这个node接收中断信号。
  (2).#interrupt-cells:这是个中断控制器节点的属性,用来标识这个控制器。必须要几个单位做中断描述符。
  (3).interrupt-parent:标识此设备节点属于哪一个中断控制器,如果没有设置这个属性,会自动依附父节点的。
  (4).interrupts:一个中断标识列表,标识每一个中断输出信号。
举个栗子

/ {
	...
	#address-cells = <2>;
	#size-cells = <2>;
	compatible = "mediatek,M78XY";
	interrupt-parents = <&sysirq>;//(3)
	cpus {
		#address-cells = <1>;
		#size-cells = <0>;
		cpu@000 {
			device_type = "cpu";//类似于name,就是个名字。
			reg = <0x000>;
			compatible = "mediatek,cortex-M78";
			enable-method = "pisc";//使能方法。
			clock-frequency = 168000000;//时钟频率。
		}
		cpu@001 {
			device_type = "cpu";
			reg = <0x001>;
			compatible = "mediatek,cortex-M78";
			enable-method = "pisc";
			clock-frequency = 168000000;
		}
	}
	spi@11010000{
		compatible = "mediatek,M78XY-spi";
		reg = <0 0x11010000 0 0x1000>;
		inperrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_LOW>;
		fingerprint@0 {
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <0>;
			spi-max-frequency = <8000000>;
			interrupt-parent = <&pio>;
			int-gpio = <&pio 5 0>;
			interrupts = <GIC_SPI 5 IRQ_TYPE_EDGE_FALLING>;
			compatible = "mediatek,fingerx1","fxx,fingerx2";
			pinctrl = ...
			...
			status = "okey";
		}
	}
}

  说明一下昂,这…根节点的中断属于系统中断控制器,而spi未标明interrupt-parent属性,则说明spi依附于根节点中断控制器,而fingerprint中标明其interrupt-parent是pio,所以fingerprint将使用gpio的中断控制器,int-gpio声明一下将要被用作中断的pinctrl,接下来就是为这个pin标明中断方式。
  interrupts第一个属性,GIC_SPI,表示共享中断(SPI),这个值实际上是0,在include\dt-bindings\Interrupt-controller\arm-gic.h被定义,还有GIC_PPI代表每个处理器有独立的中断,第二个属性,就是上面所声明的pin引脚,第三个属性就是中断方式,FALLING下降沿触发。

DTS配置

  • 配置文件路径:
    32位芯片:kernel/arch/arm/boot/dts/
    64位芯片:kernel/arch/arm64/boot/dts/
    ps:这是arm-dts的位置,mips、powerpc请自行替换arm…

  • 使能总线上的控制器:
    默认的status值为disable,改为okey为使能的意思,会覆盖默认值(平台dts)。

  • 添加设备dto节点,在dts中添加(项目dts)。
    device@x,@后是设备地址,平台方案控制器通过片选而来,不需要指定的设备地址,@x也可以没有。
    compatible的值与驱动代码中定义的相匹配:与match内.compatible属性值相同。

  • GPIO配置
    参考GPIO配置表。

(目前就这样吧,等有啥改动了,回头再改…)

转载请注明出处,谢谢...0.0

根据提供的引用内容,可以了解到在Linux驱动程序中,需要读取Linux内核中附带的dts文件,并操作设备树DTS的相关节点。同时,还提到了在MTK平台上分析Linux的i2c框架。 对于Linux的i2c设备树(DTS)操作,可以按照以下步骤进行: 1. 首先,需要在设备树中定义i2c控制器和i2c设备节点。在设备树中,使用`i2c`关键字来定义i2c控制器,使用`i2c_device`关键字来定义i2c设备。例如: ```dts i2c { compatible = "i2c"; #address-cells = <1>; #size-cells = <0>; i2c@0 { compatible = "i2c-device"; reg = <0>; // 其他属性 }; }; ``` 2. 在驱动程序中,可以使用`of_find_node_by_name()`函数来查找设备树中的节点。该函数接受一个参数,即节点名称,返回一个指向节点的指针。例如: ```c struct device_node *node; node = of_find_node_by_name(NULL, "i2c"); if (node) { // 找到了i2c节点 // 进行其他操作 } ``` 3. 通过节点指针,可以使用`of_property_read_u32()`函数来读取节点的属性值。该函数接受三个参数,分别是节点指针、属性名称和一个指向变量的指针,用于存储属性值。例如: ```c u32 value; if (of_property_read_u32(node, "reg", &value) == 0) { // 读取成功,可以使用value进行其他操作 } ``` 4. 可以使用`of_get_child_by_name()`函数来获取节点的子节点。该函数接受两个参数,分别是父节点指针和子节点名称,返回一个指向子节点的指针。例如: ```c struct device_node *child; child = of_get_child_by_name(node, "i2c@0"); if (child) { // 找到了子节点 // 进行其他操作 } ``` 5. 最后,记得在驱动程序中使用`of_node_put()`函数来释放节点指针。例如: ```c of_node_put(node); ``` 这样,就可以在Linux驱动程序中进行设备树节点的操作了。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值