• Linux驱动之设备树的基础知识


    前期知识

      1. 如何编写一个简单的Linux驱动(一)——驱动的基本框架
      2. 如何编写一个简单的Linux驱动(二)——设备操作集file_operations
      3. 如何编写一个简单的Linux驱动(三)——完善设备驱动

    前言

      在前面的文章中,我们只介绍了如何对驱动和设备节点进行操作,并没有涉及到对具体硬件设备的操作。从本篇开始,将介绍对硬件设备的操作。这里,我们要引入一个新的概念——设备树。
      在学习Linux驱动时,我们一般会用到ARM开发板。ARM开发板的厂商有很多,我们熟知的有正点原子、迅为、友善之臂、天嵌等等。我们可以想象这样一种场景,每家开发板厂商都自己开发板载设备的驱动,即使使用同一款处理器,但每款板子的厂商对于板载硬件的定义是不相同的,为了板载硬件能够正常工作,每家厂商都会根据自己的板载硬件来设计不同于其他厂商的驱动,并将其提交到ARM社区,ARM社区再将它们添加到Linux内核。显然,随着使用Linux的设备越来越多,这些驱动就像是一层层的sh*t一样,糊在Linux内核上,导致Linux内核越来越臃肿。
      在几年前,ARM社区真的是这么做的,这就惹恼了大神Linus,于是Linus就给ARM社区来了套素质N连。于是,ARM社区学习了PowerPC的模式,把设备从内核中独立出来,形成设备树。

    1.什么是设备树

      设备树是用来描述板级设备的文件,板子上所有的设备信息都汇集在这一个文件中,如图。

      系统总线是设备树的主干;CAN控制器、GPIO控制器等是系统总线的分支;GPIOA、CAN1、IIC1是更进一步的分支;GPIOA1、AT24C02、MCP2515就是具体设备。这样将设备按照类别组成一棵树,就组成了一整棵设备树。我们可以在系统的"proc/device-tree"目录下看到系统的设备树信息。

    2.DTS文件和DTSI文件

      设备树源文件一般包括两种,dts文件和dtsi文件,dtsi文件是dts文件的头文件,此外,dts文件还可以像C语言那样包含.h格式的头文件。就像下面这样。

    //这是一个dts文件
    /dts-v1/;	//这条语句必须有
    #include "xxx.h"	//像C语言一样包含.h头文件
    #include "xxxx.dtsi"	//包含dtsi头文件
    ...
    ...
    

      需要注意的是,在dts文件中,文件开始处的/dts-v1/;语句是必备的。可以看到,dts文件在包含头文件方面和C语言十分相似,都使用#include
      dtsi文件一般用来描述较为通用的SOC级别的信息,比如CPU信息,外设控制器信息、主频信息等等。而dts文件则用来描述具象化的外设信息,例如要把GPIOA1用作按键,就需要在dts文件中进行描述。

    3.设备树源文件分析

    3.1根节点和普通节点

      /{}; 是根节点,其他的node_name{}; 是普通节点。当某个结点在多个关联文件中都出现时,不会产生冲突,出现的后者会对前者作为补充;如果后者与前者有相同的属性,则后者的属性会覆盖掉前者的属性。
      比如:在dtsi头文件中有对adc的描述

    adc: adc@126C0000 {
                   compatible = "samsung,exynos-adc-v1";
                   reg = <0x126C0000 0x100>;
                   interrupt-parent = <&combiner>;
                   interrupts = <10 3>;
                   clocks = <&clock CLK_TSADC>;
                   clock-names = "adc";
                   #io-channel-cells = <1>;
                   io-channel-ranges;
                   samsung,syscon-phandle = <&pmu_system_controller>;
                   status = "disabled";	//adc不工作
    };
    

      可以在dts文件中对adc描述进行追加

    &adc {
    /*vdd-supply = <&ldo3_reg>;*/
    status = "okay";	//覆盖头文件中的status,使能adc
    };
    

    3.2特殊的设备节点

    1. aliases节点:用于保存其他节点的别名。
    2. chosen节点:该节点并不是一个真的设备,它的主要功能是帮助uboot向内核传递数据,最主要的参数是bootargs参数。

    3.3设备节点的命名

      设备节点的命名方式有三种。

    1. node-name{}; ; node-name是结点名称。
    2. node-name@unit-address{}; :unit-address是设备地址或寄存器首地址。
    3. label: node-name@unit-address{}; :label是节点标签,可以使用&label快捷地访问节点。

    3.4设备树节点的标准属性

    1. 根节点的compatible属性:用于标识设备树能否与Linux内核匹配,该属性值的一半格式为"厂商,板子名称"
    2. 普通节点的compatible属性:指兼容性。该属性值的一般格式为"厂商,设备驱动名"。如果Linux内核中的匹配表中有与compatible属性中的值相同的值,则该Linux内核可以使用该设备驱动。当驱动的兼容性信息与设备树的compatible属性匹配后,会运行驱动代码里的probe函数。
    3. status属性:标识设备可用(“okay”)还是不可用(“disabled”)。当然也有其他的值。
    4. #address-cells#size-cells属性:用于标明该如何编写reg属性值。#address-cells用于标明reg属性中address所占字长数,size-cells用于标明length所占的字长数。
    5. reg属性:该属性的格式一般为reg = <address,length, address,length,…>address表示其实地址,length表示地址长度,一般用于内存中(也可以用于其他设备)。例:
    #address-cells = <2>;	//起始地址占两个字长
    #size-cells = <1>;	//地址长度占一个字长
    reg = <0x400080,0x600040,0x4000>;	//表示0x400080和0x600040是起始地址,地址长度为0x4000
    

    4. 驱动程序如何获取设备树信息

      Linux内核的"linux/of.h"文件中提供了一系列以of开头的函数,其中包含了可以获取设备树信息的函数。

    5.DTS、DTB和DTC

      dts是设备树源文件的一种格式,dtb是设备树文件编译后形成的二进制文件的格式,dtc是用来编译设备树文件的编译工具。

  • 相关阅读:
    C# 获得word中某一段落所在页的页码
    写一个安全的Java单例
    递归算法
    redis连接池连接失败的问题
    A query was run and no Result Maps were found for the Mapped Statement .....................
    解决maven默认JDK1.5报错
    mybatis控制台不报错数据库却没有值返回的问题
    LNMP 环境更换Nginx 服务器为Tengine
    简易的phpexcel导出柱状图
    Laravel学习基础篇之--路由
  • 原文地址:https://www.cnblogs.com/UnfriendlyARM/p/13669520.html
Copyright © 2020-2023  润新知