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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章