1. 程式人生 > >Linux Device Tree

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