Linux在啟動后,到C入口時,會執(zhí)行以下操作,加載系統(tǒng)平臺上的總線和設(shè)備:
start_kernel() --> setup_arch() --> unflatten_device_tree()
在執(zhí)行完unflatten_device_tree()后,DTS節(jié)點信息被解析出來,保存到allnodes鏈表中,allnodes會在后面被用到。隨后,當(dāng)系統(tǒng)啟動到board文件時,會調(diào)用.init_machine,高通8974平臺對應(yīng)的是msm8974_init()。接著調(diào)用of_platform_populate(....)接口,加載平臺總線和平臺設(shè)備。
Device Tree 中的 I2C client 會透過 I2C host 驅(qū)動的 probe()函數(shù)中調(diào)用 of_i2c_register_devices(&i2c_dev->adapter);被自動展開
SPI host 驅(qū)動的 probe 函數(shù)透過 spi_register_master()注冊 master 的時候,會自動展開依附于它的 slave。
整體platform驅(qū)動架構(gòu)是這樣的。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匹配到。則會調(diào)用platform里的probe成員函數(shù)
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.通過他我們可以找到對應(yīng)于dts文件中的設(shè)備節(jié)點(定位到它就可以獲取設(shè)備參數(shù)列表了)【因為新版內(nèi)核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; }
|