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

你可能感兴趣的:(嵌入式,Linux内核)