linux設備樹語法


設備樹語法及綁定

概述

Device Tree是一種用來描述硬件的數據結構,類似板級描述語言,起源於OpenFirmware(OF)。

就ARM平台來說,設備樹文件存放在arch/arm/boot/dts下,綁定文檔存在Documentation/devicetree/bindings下。

設備樹由一系列被命名的節點(node)和屬性(property)組成,而節點本身可包含子節點。所謂屬性,就是成對出現的名稱和值。

在設備樹中可描述的信息包括(原來這些信息大多被編碼在內核中):

》CPU數量和類別

》內存基地址和大小

》總線和橋

》外設連接

》中斷控制器和中斷使用情況

》GPIO控制器和GPIO使用情況

》時鍾控制器和時鍾使用情況

它基本上就是畫一棵電路板上CPU、總線、設備組成的樹,Bootloader會將這棵樹傳遞給內核,然后內核可以識別這棵樹,並根據它展開出Linux內核中的platform_device、i2c_client、spi_device等設備,而這些設備用到的內存、IRQ等資源,也被傳遞給了內核,內核會將這些資源綁定給展開的相應的設備。

對於設備樹上的節點和屬性具體是如何來描述設備的硬件細節的,一般需要綁定文件(.txt)說明:

rtc/rtc-cmos.txt

Motorola mc146818 compatible RTC
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Required properties:
  - compatible : "motorola,mc146818"
  - reg : should contain registers location and length.

Optional properties:
  - interrupts : should contain interrupt.
  - interrupt-parent : interrupt source phandle.
  - ctrl-reg : Contains the initial value of the control register also
    called "Register B". 
  - freq-reg : Contains the initial value of the frequency register also
    called "Regsiter A". 

"Register A" and "B" are usually initialized by the firmware (BIOS for 
instance). If this is not done, it can be performed by the driver.

ISA Example:

    rtc@70 {
             compatible = "motorola,mc146818";
             interrupts = <8 3>; 
             interrupt-parent = <&ioapic1>;
             ctrl-reg = <2>;
             freq-reg = <0x26>;
             reg = <1 0x70 2>;
     };

基本可以看出,設備樹綁定文檔的主要內容包括:

》關於該模塊的最基本的描述。

》必要屬性的描述

》可選屬性的描述

》一個示例

又如常見的GPIO控制LED,屬性綁定示例,gpio/led.txt

LEDs connected to GPIO lines

Required properties:
- compatible : should be "gpio-leds".

Each LED is represented as a sub-node of the gpio-leds device.  Each
node's name represents the name of the corresponding LED.

LED sub-node properties:
- gpios :  Should specify the LED's GPIO, see "Specifying GPIO information
  for devices" in Documentation/devicetree/booting-without-of.txt.  Active
  low LEDs should be indicated using flags in the GPIO specifier.
- label :  (optional) The label for this LED.  If omitted, the label is
  taken from the node name (excluding the unit address).
- linux,default-trigger :  (optional) This parameter, if present, is a
  string defining the trigger assigned to the LED.  Current triggers are:
    "backlight" - LED will act as a back-light, controlled by the framebuffer
          system
    "default-on" - LED will turn on, but see "default-state" below
    "heartbeat" - LED "double" flashes at a load average based rate
    "ide-disk" - LED indicates disk activity
    "timer" - LED flashes at a fixed, configurable rate
- default-state:  (optional) The initial state of the LED.  Valid
  values are "on", "off", and "keep".  If the LED is already on or off
  and the default-state property is set the to same value, then no
  glitch should be produced where the LED momentarily turns off (or
  on).  The "keep" setting will keep the LED at whatever its current
  state is, without producing a glitch.  The default is off if this
  property is not present.

Examples:

leds {
    compatible = "gpio-leds";
    hdd {
        label = "IDE Activity";
        gpios = <&mcu_pio 0 1>; /* Active low */
        linux,default-trigger = "ide-disk";
    };

    fault {
        gpios = <&mcu_pio 1 0>;
        /* Keep LED on if BIOS detected hardware fault */
        default-state = "keep";
    };
};

run-control {
    compatible = "gpio-leds";
    red {
        gpios = <&mpc8572 6 0>;
        default-state = "off";
    };
    green {
        gpios = <&mpc8572 7 0>;
        default-state = "on";
    };
}

linux內核下scripts/checkpatch.pl會運行一個檢查,如果有人在設備樹中新添加了compatible字符串,而沒有添加相應的文檔進行解釋,checkpatch程序會報出警告:UNDOCUMENTED_DT_STRINGDT compatible string xxx appears un-documented。

設備樹語法

設備樹文件包括兩種:dts和dtsi。dtsi相當於頭文件,其可能包含一些板卡設備的共用部分(被提煉出來,如CPU信息等,多種類板卡共用同一CPU),dts可通過include包含dtsi。

#include "xxx.dtsi"
/include/ "xxx.dtsi"

 下面看個示例

/*
 * Allwinner Technology CO., Ltd. sun50iw1p1 platform
 * modify base on juno.dts
 */

#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/gpio/gpio.h>
 #include "sun50iw1p1-clk.dtsi"
 #include "sun50iw1p1-pinctrl.dtsi"
 / {
     model = "sun50iw1p1";
     compatible = "arm,sun50iw1p1", "arm,sun50iw1p1";
     interrupt-parent = <&gic>;
     #address-cells = <2>;
     #size-cells = <2>;
 
     aliases {
         serial0 = &uart0;
         ......
         ......
         ......
         boot_disp = &boot_disp;
     };
 
     chosen {
         bootargs = "earlyprintk=sunxi-uart,0x01c28000 loglevel=8 initcall_debug=1 console=ttyS0 init=/init";
         linux,initrd-start = <0x0 0x0>;
         linux,initrd-end = <0x0 0x0>;
     };
 
     cpus {
         #address-cells = <2>;
         #size-cells = <0>;
 
         cpu@0 {
             device_type = "cpu";
             compatible = "arm,cortex-a53","arm,armv8";
             reg = <0x0 0x0>;
             enable-method = "psci";
             cpufreq_tbl = < 480000 600000 720000 816000 1008000 
                     1104000 1152000 1200000 1344000>;
             clock-latency = <2000000>;
             clock-frequency = <1008000000>;
             cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0 &SYS_SLEEP_0>;
         };
         cpu@1 {
             device_type = "cpu";
             compatible = "arm,cortex-a53","arm,armv8";
             reg = <0x0 0x1>;
             enable-method = "psci";
             clock-frequency = <1008000000>;
             cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0 &SYS_SLEEP_0>;
         };
         cpu@2 {
             ......
             ......
             ......
         };
         cpu@3 {
             ......
             ......
             ......
         };
     };
 
     memory@40000000 {
         device_type = "memory";
         reg = <0x00000000 0x40000000 0x00000000 0x40000000>;
     };
 
     gic: interrupt-controller@1c81000 {
         compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
         #interrupt-cells = <3>;
         #address-cells = <0>;
         device_type = "gic"; 
         interrupt-controller;
         reg = <0x0 0x01c81000 0 0x1000>, /* GIC Dist */
               <0x0 0x01c82000 0 0x2000>, /* GIC CPU */
               <0x0 0x01c84000 0 0x2000>, /* GIC VCPU Control */
               <0x0 0x01c86000 0 0x2000>; /* GIC VCPU */
         interrupts = <GIC_PPI 9 0xf04>; /* GIC Maintenence IRQ */
     };
 
     soc: soc@01c00000 {
         compatible = "simple-bus";
         #address-cells = <2>;
         #size-cells = <2>;
         ranges;
         device_type = "soc";
 
         uart0: uart@01c28000 {
             compatible = "allwinner,sun50i-uart";
             device_type = "uart0";
             reg = <0x0 0x01c28000 0x0 0x400>;
             interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
             clocks = <&clk_uart0>;
             pinctrl-names = "default", "sleep";
             pinctrl-0 = <&uart0_pins_a>;
             pinctrl-1 = <&uart0_pins_b>;
             uart0_port = <0>;
             uart0_type = <2>;
             status = "disabled";
             ......
             ......
             ......            
         };
         ......
         ......
         ......
     };
 };

 *note:<name>[@<unit-address>]是節點的格式,其中unit-address是單位偏移地址,[]可省略。

“/"代表根節點;

“model”是板的ID;

"compatible"是平台兼容,一般格式是"manufacturer,model"。內核或者uboot依靠這個屬性找到相對應driver,若"compatible"出現多個屬性,按序匹配driver;

“#address-cells”是address的單位(32bit);

“#size-cells”是length的單位(32bit);

"reg"是寄存器,格式是"<address,length>",作為平台內存資源;

"aliase" 是別名,必須節點全稱,可以通過地址引用獲取;

”chosen“是板級啟動參數;

"cpus"是SOC的CPU信息,可以改變運行頻率或者開關CPU;

"memory"是板級內存的信息。

"interrupts"是中斷控制器,根據SOC自定義格式,這里是<輸入類型 中斷號 觸發方式>,作為平台中斷資源;

“interrupt-controller”指示這個節點是中斷控制節點;

"[label:]"如gic: interrupt-controller@1c81000,這個標簽可以作為地址賦值到其他節點的屬性;

“device_type":設備類型,尋找節點可以依據這個屬性;

"status"是開關節點設備的狀態,取值"okay"或者"ok"表示使能,"disabled"表示失能。

根節點兼容性

 一個最簡單的設備樹必須包含根節點,cpus節點,memory節點。根節點的名字及全路徑都是“/”,至少需要包含model和compatible兩個屬性。

model屬性我是用來描述產品型號的,類型為字符串,推薦的格式為“manufacturer,model-number”(非強制的)。根節點的model屬性描述的是板子的型號或者芯片平台的型號,如:

model = "Atmel AT91SAM9G20 family SoC"
model = "Samsung SMDK5420 board based on EXYNOS5420"
從軟件的層面講model屬性僅僅表示一個名字而已,沒有更多的作用。

compatible屬性則不同,該屬性決定軟件如何匹配硬件對硬件進行初始化。compatible屬性的類型是字符串數組,按照范圍從小到大的順序排列,每個字符串表示一種匹配類型。根節點的compatible屬性表示平台如何匹配,比如

compatible = "samsung,smdk5420", "samsung,exynos5420", "samsung,exynos5"

表示軟件應該首先匹配'samsung,smdk5420',這個是一款開發板。

如果無法匹配,再試着匹配"samsung,exynos5420",這個是一款芯片平台。

如果還是無法匹配,還可以試着匹配 "samsung,exynos5",這是一個系列的芯片平台。

這里說的匹配是指軟件根據該信息找到對應的代碼,如對應的初始化函數。

根節點表示的是整個板子或者芯片平台,所以在系統初始化比較早的時候就需要確認是什么平台,怎樣初始化。對於Linux,是通過在start_kernel函數調用setup_arch函數實現的。不同的架構,setup_arch函數的實現不同,對於arm架構,setup_arch函數源代碼位於arch/arm/kernel/setup.c中。

void __init setup_arch(char **cmdline_p)
{
    struct machine_desc *mdesc;

    setup_processor();
    mdesc = setup_machine_fdt(__atags_pointer);
    if (!mdesc)
        mdesc = setup_machine_tags(machine_arch_type);
    machine_desc = mdesc;
    machine_name = mdesc->name;
...
}

過去,ARM Linux針對不同的電路板會建立由MACHINE_START和MACHINE_END包圍起來的針對這個machine的一系列callback,譬如:

MACHINE_START(AM335XEVM, "am335xevm")
    /* Maintainer: Texas Instruments */
    .atag_offset    = 0x100,
    .map_io     = am335x_evm_map_io,
    .init_early = am33xx_init_early,
    .init_irq   = ti81xx_init_irq,
    .handle_irq     = omap3_intc_handle_irq,
    .timer      = &omap3_am33xx_timer,
    .init_machine   = am335x_evm_init,
MACHINE_END

這些不同的machine會有不同的MACHINE ID,Uboot在啟動Linux內核時會將MACHINE ID存放在r1寄存器,Linux啟動時會匹配Bootloader傳遞的MACHINE ID和MACHINE_START聲明的MACHINE ID,然后執行相應machine的一系列初始化函數。

引入Device Tree之后,MACHINE_START變更為DT_MACHINE_START,其中含有一個.dt_compat成員,用於表明相關的machine與.dts中root結點的compatible屬性兼容關系。如果Bootloader傳遞給內核的Device Tree中root結點的compatible屬性出現在某machine的.dt_compat表中,相關的machine就與對應的Device Tree匹配,從而引發這一machine的一系列初始化函數被執行。

static const char *omap3_boards_compat[] __initdata = { 
    "ti,omap3",
    NULL,
};

DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)")
    .atag_offset    = 0x100,
    .reserve    = omap_reserve,
    .map_io     = omap3_map_io,
    .init_early = omap3430_init_early,
    .init_irq   = omap3_init_irq,
    .handle_irq = omap3_intc_handle_irq,
    .init_machine   = omap3_init,
    .timer      = &omap3_timer,
    .dt_compat  = omap3_boards_compat,
MACHINE_END

Linux倡導針對多個SoC、多個電路板的通用DT machine,即一個DT machine的.dt_compat表含多個電路板.dts文件的root結點compatible屬性字符串。之后,如果的電路板的初始化序列不一樣,可以透過

int of_machine_is_compatible(const char *compat)

API判斷具體的電路板是什么。

158 static char const *exynos5_dt_compat[] __initdata = {
159         "samsung,exynos5250",
160         "samsung,exynos5440",
161         NULL
162 };
163
177 DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)")
178         /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
179         .init_irq       = exynos5_init_irq,
180         .smp            = smp_ops(exynos_smp_ops),
181         .map_io         = exynos5_dt_map_io,
182         .handle_irq     = gic_handle_irq,
183         .init_machine   = exynos5_dt_machine_init,
184         .init_late      = exynos_init_late,
185         .timer          = &exynos4_timer,
186         .dt_compat      = exynos5_dt_compat,
187         .restart        = exynos5_restart,
188         .reserve        = exynos5_reserve,
189 MACHINE_END

它的.init_machine成員函數就針對不同的machine進行了不同的分支處理:

126 static void __init exynos5_dt_machine_init(void)
127 {
128149
150         if (of_machine_is_compatible("samsung,exynos5250"))
151                 of_platform_populate(NULL, of_default_bus_match_table,
152                                      exynos5250_auxdata_lookup, NULL);
153         else if (of_machine_is_compatible("samsung,exynos5440"))
154                 of_platform_populate(NULL, of_default_bus_match_table,
155                                      exynos5440_auxdata_lookup, NULL);
156 }

 

根節點還可能包含的屬性為#address-cells和#size-cells,規范中說明這兩個屬性是必須的,實際應用時是可選的,還記得屬性那一節說這兩個屬性如果沒有都是有默認值的,#address-cells默認值為2,#size-cells默認值為1。根節點下必須包含的子節點為cpus和memory,后邊會說明cpus下邊還有每個cpu的子節點,memory節點下邊定義的就是memory的起始地址及大小,所以根節點的#address-cells和#size-cells屬性實際上說明的就是從cpu角度看系統總線的地址長度和大小。

設備節點兼容性

如何查找節點屬性

每個節點都有一個兼容屬性(compatible),兼容屬性用於驅動和設備的綁定。

兼容屬性值都應在綁定文檔中描述,即Documentation/devicetree/bindings下文檔,通過搜索兼容屬性值可查找到該節點應包含的屬性,如上述綁定文檔。

如需了解通過GPIO連接的LED的屬性,可這樣查詢:

#cd Documentation/devicetree/bindings
#grep 'gpio' ./* -rn
#grep 'led' ./* -rn

主要文件為gpio/led.txt,compatible = “gpio-leds”,每個子節點的屬性包括gpios,label,default-status等。 

驅動中綁定

使用設備樹后,驅動需要與dts中描述的設備節點進行匹配,從而使驅動的probe()函數執行。新的驅動、設備的匹配變成了設備樹節點的兼容屬性和設備驅動中of_match_table的匹配。

對於platform_driver而言,需要添加一個OF匹配表,比如gpio-leds的驅動程序位於drivers/leds/leds-gpio.c。

static const struct of_device_id of_gpio_leds_match[] = {
    { .compatible = "gpio-leds", },
    {},
};
static struct platform_driver gpio_led_driver = {
    .probe      = gpio_led_probe,
    .remove     = gpio_led_remove,
    .driver     = {
        .name   = "leds-gpio",
        .owner  = THIS_MODULE,
        .of_match_table = of_match_ptr(of_gpio_leds_match),
    },
};

module_platform_driver(gpio_led_driver);

of_match_table添加匹配的dts中相關節點的兼容屬性。

驅動中設備樹解析

設備樹的解析一般放在probe()中,當兼容性匹配時驅動執行probe()函數,此時解析設備樹。為了兼容,若設備采用以前方式注冊則不必解析設備樹。

通過宏定義CONFIG_OF_GPIO實現編譯選擇。

還以drivers/leds/leds-gpio.c為例示意:

/* Code to create from OpenFirmware platform devices */
#ifdef CONFIG_OF_GPIO
static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
{
    struct device_node *np = pdev->dev.of_node, *child;
    struct gpio_leds_priv *priv;
    int count, ret;

    /* count LEDs in this device, so we know how much to allocate */
    count = of_get_available_child_count(np);
    if (!count)
        return ERR_PTR(-ENODEV);

 for_each_available_child_of_node(np, child)
        if (of_get_gpio(child, 0) == -EPROBE_DEFER)
            return ERR_PTR(-EPROBE_DEFER);

    priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(count),
            GFP_KERNEL);
    if (!priv)
        return ERR_PTR(-ENOMEM);
    for_each_available_child_of_node(np, child) {
        struct gpio_led led = {};
        enum of_gpio_flags flags;
        const char *state;

        led.gpio = of_get_gpio_flags(child, 0, &flags);
        led.active_low = flags & OF_GPIO_ACTIVE_LOW;
        led.name = of_get_property(child, "label", NULL) ? : child->name;
        led.default_trigger =
            of_get_property(child, "linux,default-trigger", NULL);
        state = of_get_property(child, "default-state", NULL);
        if (state) {
            if (!strcmp(state, "keep"))
                led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
            else if (!strcmp(state, "on"))
                led.default_state = LEDS_GPIO_DEFSTATE_ON;
            else
                led.default_state = LEDS_GPIO_DEFSTATE_OFF;
        }
        ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
                      &pdev->dev, NULL);
        if (ret < 0) {
            of_node_put(child);
            goto err;
        }
    }

    return priv;

err:
    for (count = priv->num_leds - 2; count >= 0; count--)
        delete_gpio_led(&priv->leds[count]);
    return ERR_PTR(-ENODEV);
}

static const struct of_device_id of_gpio_leds_match[] = {
    { .compatible = "gpio-leds", },
    {},
};
#else /* CONFIG_OF_GPIO */
static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
{
    return ERR_PTR(-ENODEV);
}
#endif /* CONFIG_OF_GPIO */

再看下probe()函數的實現:

static int gpio_led_probe(struct platform_device *pdev)
{
    struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
    struct gpio_leds_priv *priv;
    int i, ret = 0;


    if (pdata && pdata->num_leds) {
        priv = devm_kzalloc(&pdev->dev,
                sizeof_gpio_leds_priv(pdata->num_leds),
                    GFP_KERNEL);
        if (!priv)
            return -ENOMEM;

        priv->num_leds = pdata->num_leds;
        for (i = 0; i < priv->num_leds; i++) {
            ret = create_gpio_led(&pdata->leds[i],
                          &priv->leds[i],
                          &pdev->dev, pdata->gpio_blink_set);

            if (ret < 0) {
                /* On failure: unwind the led creations */
                for (i = i - 1; i >= 0; i--)
                    delete_gpio_led(&priv->leds[i]);
                return ret;
            }
        }
    } else {
        priv = gpio_leds_create_of(pdev);
        if (IS_ERR(priv))
            return PTR_ERR(priv);
    }
    platform_set_drvdata(pdev, priv);

    return 0;
}

設備節點語法

1. 如果一個節點描述的設備有地址,則應該給出@unit-address。多個相同類型設備節點的name可以一樣,只要unit-address不同即可。

2. 對於掛在內存空間的設備而言,@字符后面跟的一般就是該設備在內存空間的基地址。

3. 可以給一個設備節點添加label,之后可以通過&label的形式訪問這個label,這種引用是通過phandle(pointer handle)進行的。

4. 可尋址的設備使用如下信息在設備樹中編碼地址信息:

reg   
    #address-cells
    #size-cells

其中reg的組織形式為reg = <address1 length1 [address2 length2] [address3 length3] ... >,其中的每一組address length表明了設備使用的一個地址范圍。address為1個或多個32位的整型(即cell),而length的意義則意味着從address到address+length-1的地址范圍都是屬於該節點。若#size-cells = 0,則length字段為空。

address和length字段是可變長的,父節點的#address-cells和#size-cells分別決定了子節點reg屬性的address和length字段的長度。

#address-cells決定了該reg的前address-cells個cells(整型數)為address,代表地址;

#size-cells決定了該reg的代表長度的cells個數,#size-cells代表沒有字段代表地址的length。

舉例如下:

external-bus結點的#address-cells = <2>和#size-cells = <1>;決定了其下的ethernet、i2c、flash的reg字段形如reg = <0 0 0x1000>;、reg = <1 0 0x1000>;和reg = <2 0 0x4000000>;。其中,address字段長度為0,開始的第一個cell(0、1、2)是對應的片選,第2個cell(0,0,0)是相對該片選的基地址,即reg的前兩個cells代表地址;第3個cell(0x1000、0x1000、0x4000000)為length,為一個cells,即reg的第3個cells代表長度

ranges = <0 0  0x10100000   0x10000     // Chipselect 1, Ethernet
    1 0  0x10160000   0x10000     // Chipselect 2, i2c controller  
    2 0  0x30000000   0x1000000>; // Chipselect 3, NOR Flash      

ranges 是地址轉換表,其中的每個項目是一個子地址、父地址以及在子地址空間的大小的映射。映射表中的子地址、父地址分別采用子地址空間的#address- cells和父地址空間的#address-cells大小。對於本例而言,子地址空間的#address-cells為2,父地址空間 的#address-cells值為1,因此0 0  0x10100000   0x10000的前2個cell為external-bus后片選0上偏移0,即子地址#adress-cells(為2),第3個cell表示external-bus后片選0上偏移0的地址空間被映射到CPU的0x10100000位置,即父地址#address-cells(為1)第4個cell表示映射的大小為0x10000(為1)

特別要留意的是i2c結點中定義的 #address-cells = <1>;和#size-cells = <0>;作用到了I2C總線上連接的RTC,它的address字段為0x58,是設備的I2C地址,長度字段空。

5. 中斷連接。終端相關綁定信息定義在Documentation/devicetree/bindings/interrupt-controller/interrupts.txt。

interrupt-parent: 設備節點通過它來指定它所依附的中斷控制器的phandle,當節點沒有interrupt-parent時,則從父節點繼承。

interrupts: 用到了中斷的設備節點,通過它指定中斷號/觸發方法等,這個屬性具體有多少個cell,由它依附的中斷控制器節點的#interrupt-cells屬性指定。而每個cell具體含義一般由驅動的實現決定,而且也會在設備樹的綁定文檔中說明。

        i2c@7000c000 {
        gpioext: gpio-adnp@41 {
            compatible = "ad,gpio-adnp";
            reg = <0x41>;

            interrupt-parent = <&gpio>;
            interrupts = <160 1>;

            gpio-controller;
            #gpio-cells = <1>;

            interrupt-controller;
            #interrupt-cells = <2>;

            nr-gpios = <64>;
        };


        sx8634@2b {
            compatible = "smtc,sx8634";
            reg = <0x2b>;

            interrupt-parent = <&gpioext>;
            interrupts = <3 0x8>;

            #address-cells = <1>;
            #size-cells = <0>;

            threshold = <0x40>;
            sensitivity = <7>;
        };
    }; 

 

參考:

http://www.eefocus.com/marianna/blog/cate_18142_0.html?p=2

http://www.eefocus.com/marianna/blog/14-10/306247_821be.html

ARM Linux 3.x的設備樹(Device Tree)

設備樹概述

設備樹實例(一)

設備樹實例(二)

內核移植之設備樹

我眼中的Linux設備樹(五 根節點)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM