How devices in device tree and platform drivers were connected

14,272

Solution 1

The canonical answer to your question can be found at LWN: Platform Devices and Device Trees. What you need is the proper guidance on using it. A Tutorial on the Device Tree is a reasonable instruction guide. For background, you should read about Linux and the Device Tree. Also, elinux.org has a few wikis that should help, like Device Tree Linux and Device Tree Usage and Device Tree Reference.

Solution 2

in the probe function of the driver there has to be/must be this line :

probe(struct bus_client *client,
           const struct bus_device_id *id)
{

    const struct of_device_id *match;

    match = of_match_device(omap_gpio_match);
    if (!match)
            return -ENODEV;
    else
       //write the driver stuff for Probe

This is how the device tree is linked with your driver. omap_gpio_match you have already linked with the "compatible id" which you have defined in the device tree and thats how driver has been linked with the device tree.

Share:
14,272

Related videos on Youtube

jianing
Author by

jianing

Updated on June 04, 2022

Comments

  • jianing
    jianing almost 2 years

    I read some articles about this topic. but none of them describes the details.

    What I know is:

    declare "compatible" property in Device tree:

    gpio0: gpio@44e07000 {
        compatible = "ti,omap4-gpio";
        ...
    };
    

    and make the connection to platform driver by

    static const struct of_device_id omap_gpio_match[] = {
        {
            .compatible = "ti,omap4-gpio",
        },
        { },
    };
    ...
    static struct platform_driver omap_gpio_driver = {
        .probe      = omap_gpio_probe,
        .driver     = {
            .name   = "omap_gpio",
            .pm = &gpio_pm_ops,
            .of_match_table = of_match_ptr(omap_gpio_match),
        },
    };
    

    and as a result, of_match_table will be used to match the compatible property declared in Device Tree.

    and the match action performed in platform_match (drivers/base/platform.c) function. I doubt this because the I greped reference of of_match_table and the only probable result located in of_device_get_match_data (drivers/of/device.c) function.

    ~/wk/linux$ find . -name '*.c'  | xargs grep  '\<of_match_table\>' | grep -v -E 'of_match_table\s+='
    ./drivers/dma/sirf-dma.c:               (of_match_device(op->dev.driver->of_match_table,
    ./drivers/macintosh/macio_asic.c:       const struct of_device_id * matches = drv->of_match_table;
    ./drivers/macintosh/macio_asic.c:       match = of_match_device(drv->driver.of_match_table, dev);
    ./drivers/nvmem/mxs-ocotp.c:    match = of_match_device(dev->driver->of_match_table, dev);
    ./drivers/reset/sti/reset-syscfg.c:     match = of_match_device(dev->driver->of_match_table, dev);
    ./drivers/mtd/devices/m25p80.c:  * matching for .of_match_table
    ./drivers/soc/rockchip/pm_domains.c:    match = of_match_device(dev->driver->of_match_table, dev);
    ./drivers/phy/phy-rockchip-usb.c:       match = of_match_device(dev->driver->of_match_table, dev);
    ./drivers/acpi/bus.c: * @of_match_table: List of device IDs to match against.
    ./drivers/acpi/bus.c:                            const struct of_device_id *of_match_table)
    ./drivers/acpi/bus.c:   if (!of_match_table || !of_compatible)
    ./drivers/acpi/bus.c:           for (id = of_match_table; id->compatible[0]; id++)
    ./drivers/acpi/bus.c:                                       drv->of_match_table);
    ./drivers/acpi/bus.c:                                drv->acpi_match_table, drv->of_match_table);
    ./drivers/pci/host/pcie-hisi.c: match = of_match_device(driver->of_match_table, &pdev->dev);
    ./drivers/pinctrl/stm32/pinctrl-stm32.c:        match = of_match_device(dev->driver->of_match_table, dev);
    ./drivers/of/device.c:  match = of_match_device(dev->driver->of_match_table, dev);
    ./drivers/mfd/axp20x.c:         of_id = of_match_device(dev->driver->of_match_table, dev);
    ./drivers/gpu/drm/armada/armada_crtc.c:         match = of_match_device(dev->driver->of_match_table, dev);
    ./arch/powerpc/kernel/ibmebus.c:        ibmebus_create_devices(drv->driver.of_match_table);
    ./arch/powerpc/kernel/ibmebus.c:        const struct of_device_id *matches = drv->of_match_table;
    ./sound/soc/qcom/lpass-cpu.c:   match = of_match_device(dev->driver->of_match_table, dev);
    

    But this function is not used in some common modules.

    ~/wk/linux$ find . -name '*.c'  | xargs grep of_device_get_match_data
    ./drivers/dma/sh/shdmac.c:              pdata = of_device_get_match_data(&pdev->dev);
    ./drivers/dma/tegra210-adma.c:  cdata = of_device_get_match_data(&pdev->dev);
    ./drivers/dma/tegra20-apb-dma.c:        cdata = of_device_get_match_data(&pdev->dev);
    ./drivers/usb/host/xhci-tegra.c:        tegra->soc = of_device_get_match_data(&pdev->dev);
    ./drivers/usb/phy/phy-msm-usb.c:        pdata->phy_type = (enum msm_usb_phy_type)of_device_get_match_data(&pdev->dev);
    ./drivers/mtd/spi-nor/fsl-quadspi.c:    q->devtype_data = of_device_get_match_data(dev);
    ./drivers/mtd/nand/qcom_nandc.c:        dev_data = of_device_get_match_data(dev);
    ./drivers/mtd/nand/atmel_nand.c:                of_device_get_match_data(host->dev);
    ./drivers/rtc/rtc-sunxi.c:      chip->data_year = of_device_get_match_data(&pdev->dev);
    ./drivers/spi/spi-mpc512x-psc.c:        mps->type = (int)of_device_get_match_data(dev);
    ./drivers/watchdog/mpc8xxx_wdt.c:       wdt_type = of_device_get_match_data(&ofdev->dev);
    ./drivers/phy/phy-exynos-mipi-video.c:  phy_dev = of_device_get_match_data(dev);
    ./drivers/phy/phy-sun4i-usb.c:  data->cfg = of_device_get_match_data(dev);
    ./drivers/pci/host/pci-imx6.c:          (enum imx6_pcie_variants)of_device_get_match_data(&pdev->dev);
    ./drivers/pci/host/pcie-qcom.c: pcie->ops = (struct qcom_pcie_ops *)of_device_get_match_data(dev);
    ./drivers/i2c/busses/i2c-rcar.c:        priv->devtype = (enum rcar_i2c_type)of_device_get_match_data(dev);
    ./drivers/i2c/busses/i2c-tegra.c:               i2c_dev->hw = of_device_get_match_data(&pdev->dev);
    ./drivers/tty/serial/imx.c:     sport->devdata = of_device_get_match_data(&pdev->dev);
    ./drivers/gpio/gpio-mpc8xxx.c:          of_device_get_match_data(&pdev->dev);
    ./drivers/gpio/gpio-tegra.c:    config = of_device_get_match_data(&pdev->dev);
    ./drivers/clk/clk-palmas.c:     match_data = of_device_get_match_data(&pdev->dev);
    ./drivers/input/misc/pmic8xxx-pwrkey.c: pwrkey->shutdown_fn = of_device_get_match_data(&pdev->dev);
    ./drivers/input/touchscreen/edt-ft5x06.c:       chip_data = of_device_get_match_data(&client->dev);
    ./drivers/pinctrl/sh-pfc/core.c:                info = of_device_get_match_data(&pdev->dev);
    ./drivers/thermal/rcar_thermal.c:       unsigned long of_data = (unsigned long)of_device_get_match_data(dev);
    ./drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c:      data = of_device_get_match_data(&pdev->dev);
    ./drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c:       data = of_device_get_match_data(&pdev->dev);
    ./drivers/net/ethernet/renesas/sh_eth.c:                mdp->cd = (struct sh_eth_cpu_data *)of_device_get_match_data(&pdev->dev);
    ./drivers/net/ethernet/renesas/ravb_main.c:     chip_id = (enum ravb_chip_id)of_device_get_match_data(&pdev->dev);
    ./drivers/of/device.c:const void *of_device_get_match_data(const struct device *dev)
    ./drivers/of/device.c:EXPORT_SYMBOL(of_device_get_match_data);
    ./drivers/gpu/drm/nouveau/nouveau_platform.c:   func = of_device_get_match_data(&pdev->dev);
    ./drivers/gpu/drm/exynos/exynos_drm_rotator.c:                          of_device_get_match_data(dev);
    ./drivers/gpu/drm/exynos/exynos_mixer.c:        drv = of_device_get_match_data(dev);
    ./drivers/gpu/drm/exynos/exynos5433_drm_decon.c:        ctx->out_type = (unsigned long)of_device_get_match_data(dev);
    ./drivers/gpu/drm/exynos/exynos_drm_fimd.c:     ctx->driver_data = of_device_get_match_data(dev);
    ./drivers/gpu/drm/exynos/exynos_hdmi.c: hdata->drv_data = of_device_get_match_data(dev);
    ./drivers/gpu/drm/exynos/exynos_drm_dsi.c:      dsi->driver_data = of_device_get_match_data(dev);
    ./drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c:      dc_ops = (struct kirin_dc_ops *)of_device_get_match_data(dev);
    ./drivers/gpu/drm/msm/hdmi/hdmi_phy.c:  phy->cfg = (struct hdmi_phy_cfg *)of_device_get_match_data(dev);
    ./drivers/gpu/drm/msm/hdmi/hdmi.c:                      of_device_get_match_data(dev);
    ./drivers/gpu/drm/msm/msm_drv.c:        return (int) (unsigned long) of_device_get_match_data(dev);
    ./drivers/gpu/drm/rockchip/rockchip_drm_vop.c:  vop_data = of_device_get_match_data(dev);
    ./sound/soc/sh/rcar/core.c:     priv->flags     = (unsigned long)of_device_get_match_data(dev);
    ./sound/soc/sh/rcar/rsrc-card.c:                of_data = of_device_get_match_data(dev);
    ./sound/soc/sh/rcar/rsrc-card.c:        const struct rsrc_card_of_data *of_data = of_device_get_match_data(dev);
    

    anyone can give some useful information?

    • 0andriy
      0andriy over 7 years
      All ID tables (in your case OF tables) are packed in the special section in the kernel binary (and thus in the memory when loaded and unpacked). The OF core during intialization takes on input the DT blob and matches each compatible string from the DT with the list of registered (made duting compilation of kernel) drivers. Besides that the depmod database and device helper (udev, for example) help with resolving dependencies.
    • 0andriy
      0andriy over 7 years
      And for the future a hint: use git grep instead of what you did with shell. git grep -n -w of_device_get_match_data.
    • jianing
      jianing over 7 years
      thank you Andy, this git grep is great useful.
  • 0andriy
    0andriy over 7 years
    No, this is wrong since core takes care about it. See my comment above