Linux Device Tree
疑問
- 裝置樹是怎麼和Linux 裝置驅動模型結合在一起的呢?
- 裝置樹是什麼解析,驅動是什麼時候繫結的?
- 驅動是一起被掃描繫結的,還是會分為不同的時間段?
- 裝置樹驅動之間是怎麼互相呼叫介面的,是需要在驅動中自己實現呢,還是Linux裝置驅動模型已經幫我們處理好了?
裝置樹的使用
首先我們來看一個例子:
lcd0: display {
compatible = "osddisplays,osd057T0559-34ts", "panel-dpi";
label = "lcd";
backlight = <&lcd_bl>;
enable-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
panel-timing {
clock-frequency = <33000000>;
hactive = <800>;
vactive = <600>;
hfront-porch = <210>;
hback-porch = <46>;
hsync-len = <1>;
vback-porch = <23>;
vfront-porch = <12>;
vsync-len = <1>;
hsync-active = < 0>;
vsync-active = <0>;
de-active = <1>;
pixelclk-active = <1>;
};
關於一些基礎的使用在這裡就不累述了。
我們會想,enable-gpios這個屬性,看名字,我們就知道應該是GPIO驅動要做的事情,那麼我們在我們這個驅動中使用了這個。
那麼核心是怎麼進行處理的呢?是GPIO驅動在載入過程中,遍歷所有的節點,找到所有的enable-gpios屬性,然後進行配置的嗎?還是說,這個是由我們LCD驅動自己配置的,呼叫了GPIO驅動的介面,也就是說,在這種情況下,如果我們的LCD沒有實現的話,那麼這個屬性將不會起任何作用。
下面,我們就帶著這些疑問,從程式碼中來,從程式碼中去吧。
一、找到相應的驅動
我們可以通過compatible屬性找到我們這個裝置樹會適配的驅動。找到:\drivers\video\fbdev\omap2\omapfb\displays\panel-dpi.c
匹配:
static const struct of_device_id panel_dpi_of_match[] = {
{ .compatible = "omapdss,panel-dpi", },
{},
};
MODULE_DEVICE_TABLE(of, panel_dpi_of_match);
static struct platform_driver panel_dpi_driver = {
.probe = panel_dpi_probe,
.remove = __exit_p(panel_dpi_remove),
.driver = {
.name = "panel-dpi",
.of_match_table = panel_dpi_of_match,
.suppress_bind_attrs = true,
},
};
module_platform_driver(panel_dpi_driver);
我們知道,裝置樹是通過.driver.name來找到對應的驅動的。如果匹配到後會呼叫probe函式,在我們這個驅動裡就是panel_dpi_probe函式。
static int panel_dpi_probe(struct platform_device *pdev)
{
struct panel_drv_data *ddata;
struct omap_dss_device *dssdev;
int r;
---***************省略程式碼**************************-
if (dev_get_platdata(&pdev->dev)) {
r = panel_dpi_probe_pdata(pdev);
if (r)
return r;
} else if (pdev->dev.of_node) {
r = panel_dpi_probe_of(pdev); //判斷是否是由裝置樹匹配到的,如果是的話,那麼就傳遞裝置樹的節點進去
if (r)
return r;
} else {
return -ENODEV;
}
if (gpio_is_valid(ddata->backlight_gpio)) {
r = devm_gpio_request_one(&pdev->dev, ddata->backlight_gpio,
GPIOF_OUT_INIT_LOW, "panel backlight");
if (r)
goto err_gpio;
}
---***************省略程式碼**************************-
}
在上面的程式碼中,有個if語句來去判斷,到底我們這個驅動是在什麼情況下被匹配到的。
有兩種情況,一種是通過在程式碼中註冊裝置來實現匹配的。而一種是使用裝置樹被匹配到的。
也就是說,如果我們的驅動是通過,裝置樹進行匹配的,那麼其pdev->dev.of_node就會指向,當前該裝置在裝置樹中node節點。
從這裡我們也可以知道,驅動程式是隻知道它當前的node節點,而不是整個裝置樹的根節點。
如果判斷是通過裝置樹匹配驅動成功的,那麼就會呼叫panel_dpi_probe_of函式。
那麼我們來看看這個函式都做了什麼。
static int panel_dpi_probe_of(struct platform_device *pdev)
{
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct device_node *node = pdev->dev.of_node;
struct omap_dss_device *in;
int r;
struct display_timing timing;
struct videomode vm;
struct gpio_desc *gpio;
gpio = devm_gpiod_get_optional(&pdev->dev, "enable", GPIOD_OUT_LOW); // -------a
if (IS_ERR(gpio))
return PTR_ERR(gpio);
ddata->enable_gpio = gpio;
ddata->backlight_gpio = -ENOENT;
r = of_get_display_timing(node, "panel-timing", &timing);
if (r) {
dev_err(&pdev->dev, "failed to get video timing\n");
return r;
}
videomode_from_timing(&timing, &vm);
videomode_to_omap_video_timings(&vm, &ddata->videomode);
in = omapdss_of_find_source_for_first_ep(node);
if (IS_ERR(in)) {
dev_err(&pdev->dev, "failed to find video source\n");
return PTR_ERR(in);
}
ddata->in = in;
return 0;
}
程式碼a:
這個函式一上來,就給我呼叫了這麼一個devm_gpiod_get_optional()函式。通過這個函式名字,我們也可以大概知道它是和GPIO相關的,好傢伙,我們就是要研究我們這個LCD驅動是怎麼驅動GPIO的,那麼我們就研究這個函式好了。
這個函式的第二個引數是”enable”,是不是看著很眼熟?
是的。這個和我們在LCD的裝置樹中的”enable-gpios”貌似有著千絲萬縷的關係。而且,此刻!這個函式名也指向了GPIO。那麼我們完全有理由相信,這個函式就是處理裝置樹中”enable-gpios”屬性的。
在這裡,如果我們跟著進行檢視的話,我們會發現,這個函式就是在處理這個節點關於GPIO操作的程式碼。所以,我們之前的一個問題就可以得到了解答:
問:裝置樹驅動之間是怎麼互相呼叫介面的,是需要在驅動中自己實現呢,還是Linux裝置驅動模型已經幫我們處理好了?
答:如果我們在我們的程式中呼叫其他驅動的功能,那麼我們需要使用其他驅動提供的介面,不需要我們自己去將每個屬性的功能實現一遍。
未完待續,07-08-11