Linux在启动后,到C入口时,会执行以下操作,加载系统平台上的总线和设备:
start_kernel() --> setup_arch() --> unflatten_device_tree()
在执行完unflatten_device_tree()后,DTS节点信息被解析出来,保存到allnodes链表中,allnodes会在后面被用到。随后,当系统启动到board文件时,会调用.init_machine,高通8974平台对应的是msm8974_init()。接着调用of_platform_populate(....)接口,加载平台总线和平台设备。
Device Tree 中的 I2C client 会透过 I2C host 驱动的 probe()函数中调用 of_i2c_register_devices(&i2c_dev->adapter);被自动展开
SPI host 驱动的 probe 函数透过 spi_register_master()注册 master 的时候,会自动展开依附于它的 slave。
整体platform驱动架构是这样的。platform bus一旦把platform driver里的of_device_id
static struct of_device_id gpio_keys_of_match[] = {
{ .compatible = "gpio-keys", },
{ },
}; 与dts(platform device)
gpio-keys { compatible = "gpio-keys"; power { label = "Power Button"; gpios = <&gpio3 29 1>; linux,code = <116>; /* KEY_POWER */ gpio-key,wakeup; };
volume-up { label = "Volume Up"; gpios = <&gpio1 4 1>; linux,code = <115>; /* KEY_VOLUMEUP */ };
volume-down { label = "Volume Down"; gpios = <&gpio1 5 1>; linux,code = <114>; /* KEY_VOLUMEDOWN */ }; }; 里的compatible匹配到。则会调用platform里的probe成员函数
static int gpio_keys_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
。。。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。
}
struct platform_device *pdev指向匹配成功的platform device.通过他我们可以找到对应于dts文件中的设备节点(定位到它就可以获取设备参数列表了)【因为新版内核struct device中包含了成员 struct device_node *of_node; /* associated device tree node */】
代码如下
gpio_keys_get_devtree_pdata(struct device *dev) { struct device_node *node, *pp; struct gpio_keys_platform_data *pdata; struct gpio_keys_button *button; int error; int nbuttons; int i;
node = dev->of_node; if (!node) { error = -ENODEV; goto err_out; }
nbuttons = of_get_child_count(node); if (nbuttons == 0) { error = -ENODEV; goto err_out; }
pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button), GFP_KERNEL); if (!pdata) { error = -ENOMEM; goto err_out; }
pdata->buttons = (struct gpio_keys_button *)(pdata + 1); pdata->nbuttons = nbuttons;
pdata->rep = !!of_get_property(node, "autorepeat", NULL);
i = 0; for_each_child_of_node(node, pp) { int gpio; enum of_gpio_flags flags;
if (!of_find_property(pp, "gpios", NULL)) { pdata->nbuttons--; dev_warn(dev, "Found button without gpios\n"); continue; }
gpio = of_get_gpio_flags(pp, 0, &flags); if (gpio < 0) { error = gpio; if (error != -EPROBE_DEFER) dev_err(dev, "Failed to get gpio flags, error: %d\n", error); goto err_free_pdata; }
button = &pdata->buttons[i++];
button->gpio = gpio; button->active_low = flags & OF_GPIO_ACTIVE_LOW;
if (of_property_read_u32(pp, "linux,code", &button->code)) { dev_err(dev, "Button without keycode: 0x%x\n", button->gpio); error = -EINVAL; goto err_free_pdata; }
button->desc = of_get_property(pp, "label", NULL);
if (of_property_read_u32(pp, "linux,input-type", &button->type)) button->type = EV_KEY;
button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
if (of_property_read_u32(pp, "debounce-interval", &button->debounce_interval)) button->debounce_interval = 5; }
if (pdata->nbuttons == 0) { error = -EINVAL; goto err_free_pdata; }
|