11

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?

jianing
  • 153
  • 1
  • 1
  • 9
  • 3
    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 Sep 03 '16 at 21:12
  • 1
    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`. – 0andriy Sep 03 '16 at 21:14
  • 1
    thank you Andy, this `git grep` is great useful. – jianing Nov 10 '16 at 01:51

3 Answers3

8

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.

JonS
  • 621
  • 7
  • 25
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.

Raulp
  • 7,758
  • 20
  • 93
  • 155
1

When you register your platform driver you initialize driver.bus with platform_bus_type callbacks:

int __platform_driver_register(struct platform_driver *drv, struct module *owner)
{
    drv->driver.owner = owner;
    drv->driver.bus = &platform_bus_type;

One of these callbacks is platform_match:

struct bus_type platform_bus_type = {
    .name       = "platform",
    .dev_groups = platform_dev_groups,
    .match      = platform_match,

And this callback is used to bind driver to the device in device tree style if there is one:

static int platform_match(struct device *dev, struct device_driver *drv)
{
    struct platform_device *pdev = to_platform_device(dev);
    struct platform_driver *pdrv = to_platform_driver(drv);

    /* When driver_override is set, only bind to the matching driver */
    if (pdev->driver_override)
        return !strcmp(pdev->driver_override, drv->name);

    /* Attempt an OF style match first */
    if (of_driver_match_device(dev, drv))
        return 1;

    /* Then try ACPI style match */
    if (acpi_driver_match_device(dev, drv))
        return 1;

    /* Then try to match against the id table */
    if (pdrv->id_table)
        return platform_match_id(pdrv->id_table, pdev) != NULL;

    /* fall-back to driver name match */
    return (strcmp(pdev->name, drv->name) == 0);
}
Azeem
  • 11,148
  • 4
  • 27
  • 40
Dražen G.
  • 358
  • 3
  • 10