這篇基本上就是"Documentation/devicetree/usage-model.txt", The Linux usage model for device tree data的筆記
DT(Device Tree,或稱Open Firmware Device Tree)是一個資料結構(data structure)用於讓OS讀取硬體周邊訊息動態執行,因此OS就不用hard code硬體驅動。
所謂的"bindings"就是一組通用的DTS設定,用來描述其硬體,包含了data busses, interrupt lines, GPIO connections, and peripheral devices等等。
盡可能使用現有的binding來描述硬體,以最大限度地利用現有的代碼,但由於property和node名稱只是字串,因此通過定義新property和node可以輕鬆擴展現有binding。 不要沒做功課就自己建立新的binding,i2c busses就因為沒有先確認是否已經有人定義了相關的binding,就建立了新的binding,導致現在有兩套不相容的binding發生。
DT所做的只是提供一種language將硬體設定從device driver分離開來,如此可以透過傳入不同的DT給OS,以適應不同的硬體設定裝置. 進而減少一些重複的code。
DT在Linux底下有三個主要目的 1) platform identification, 2) runtime configuration, and 3) device population.
platform identification
首先kernel會先使用DT來辨識特定的機器,並且執行相關的初始化,比如ARM會在setup_arch()呼叫setup_machine_fdt()尋找適合的DT(比對DT root底下的"compatible" property。compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3";上面的例子定義了"ti,omap3-beagleboard-xm",也宣稱相容"OMAP 3450 SOC"與"OMAP3"系列的SoC,你會注意到這樣的宣稱會從最具體的board到SoC的家族,關於compatible的值必須進行記錄說明其含義。
runtime configuration
一般來說,DT是firmware傳遞資料給kernel的唯一方法,PowerPC呼叫of_scan_flat_dt(early_init_dt_scan_root, NULL)執行early init,ARM則是呼叫mdesc = setup_machine_fdt(__atags_pointer)device population
在early configuration之後,kernel會用 unflatten_device_tree()將DT轉成device node tree,讓之後的init_early(), init_irq() and init_machine()等等使用,init_early()用於任何需要在啟動過程中儘早執行的設置,init_irq()用於設置中斷處理,而init_machine()負責建立Linux platform device,這裡主要呼叫of_platform_populate()建構platform device。之後的driver也是透過of_platform_populate()建構platform device。i2c_add_driver( ) @ i2c.h |-> i2c_register_driver() @i2c-core.c /* 將device_driver中的bus_type設成i2c_bus_type */ |--> driver_register() @driver.c |--> bus_add_driver() @bus.c /* 建立sysfs file node 與 attr */ |--> driver_attach() @dd.c |--> bus_for_each_dev(drv->bus, NULL, drv, __driver_attach) @bus.c |--> __driver_attach @dd.c |--> driver_match_device(drv, dev) @base.h |--> i2c_device_match() @i2c-core.c /*********************************************** 如果是device tree, 會透過 of_driver_match_device()去做匹配的動作 如果不是device tree就改用 i2c_match_id()去完成匹配的動作 ***************************************************/ /* Attempt an OF style match */ if (of_driver_match_device(dev, drv)) return 1; /* Then ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1; driver = to_i2c_driver(drv); /* match on an id table if there is one */ if (driver->id_table) return i2c_match_id(driver->id_table, client) != NULL; |--> driver_probe_device() @dd.c /*如果匹配成功, 接下來就要準備 call driver 中的 probe function*/ |--> really_probe() @dd.c |--> i2c_device_probe() @i2c-core.c |--> rt5627_i2c_probe() @rt5627.c from http://janbarry0914.blogspot.com/2014/08/device-tree-i2c-device-driver-match.html
-
參考資料:
- "Documentation/devicetree/usage-model.txt", The Linux usage model for device tree data
- 在device tree的架構下, i2c device 與 driver 是如何 match