Linux Platform驱动的注册流程

原创文章, 转载请注明出处。

1 platform device是如何挂载在platform_bus上:

linux platfrom驱动在加载的时候都有相应的优先级, linux定义了不同的initcall接口表示不同的优先级,

比如:core_initcall,arch_initcall。

本文从arch_initcall_sync(of_platform_default_populate_init)开始分析,该API将dts中的device node依次
挂载在platform_bus_type上, 接下来分析一下挂载的过程:
of_platform_default_populate_init()
->of_platform_default_populate()
->of_platform_populate() drivers/of/platform.c
{
1. 找到dts中的根节点
root = root ? of_node_get(root) : of_find_node_by_path("/")

2. 遍历根节点, 找到所有的子节点 
for_each_child_of_node(root, child) 
{
rc = of_platform_bus_create(child, matches, lookup, parent, true);
if (rc) {
of_node_put(child);
break;
}
}

3.  为每一个子节点创建一个struct platform_device的结构体,构造一个由dts中device node组成的device树
of_platform_bus_create()
{
struct platform_device *dev;

为struct platform_device *dev分配mem,初始化platform_data,配置dma memory等
dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
{

struct platform_device *dev;

dev = of_device_alloc(np, bus_id, parent);
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;
of_dma_configure(&dev->dev, dev->dev.of_node);
of_msi_configure(&dev->dev, dev->dev.of_node);
}
}

至此, 挂载在dts文件中根目录下的device node全部解析完成,并生成以struct platform_device为节点的树,
struct platform_device对应的bus为platform_bus_type, 这个bus在后面与platform_driver匹配的时候会用到。

dts中device node会有一些子节点, 比如下面的i2c node挂载了3个子节点。现在以i2c驱动为例子,对这类情况进行分析:
i2c0
->isl29023@44 
->fxos8700@1e
->max7322

i2c驱动在i2c_register_adapter()中注册i2c slave,对应的API为of_i2c_register_devices(adap):
of_i2c_register_devices(adap) drivers/i2c/i2c-core.c
{
struct i2c_client *client;

for_each_available_child_of_node(bus, node)
{
每遍历一个子节点,生成一个struct i2c_client结构体
client = of_i2c_register_device(adap, node);
{
struct i2c_client *result;

result = i2c_new_device(adap, &info);
{
struct i2c_client       *client;
client = kzalloc(sizeof *client, GFP_KERNEL);

client->flags = info->flags;
client->addr = info->addr;
client->irq = info->irq;


形成i2c节点和其子节点之间对应的父子关系
client->dev.parent = &client->adapter->dev;

return client;
}
}
}
}


2.  platform驱动的注册

platfrom驱动的注册入口为platform_driver_register, 注册入口在模块的驱动程序中,例如lpi2c驱动
的注册入口为subsys_initcall(lpi2c_imx_init),code如下:
static int __init lpi2c_imx_init(void)
{
return platform_driver_register(&lpi2c_imx_driver);
}

platform_driver_register(&lpi2c_imx_driver)
{
1.  drv->driver的初始化, drv->driver对应struct device_driver
{
drv->driver.bus = &platform_bus_type;  platform driver和platform_bus关联
drv->driver.probe = platform_drv_probe; platform device对应device driver的probe接口
}

2.  driver_register(&drv->driver);
{
1.如果driver已经挂载在bus上了,则退出
other = driver_find(drv->name, drv->bus);
if (other) 
{
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
2. 将device driver挂载到platform_bus总并attach, ret = bus_add_driver(drv);
{
1. klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);

遍历挂在bus上的device,如果和当前driver match,则probe。
2. driver_attach(drv);  
{
while ((dev = next_device(&i)) && !error)  遍历device
error = __driver_attach(dev, data);
{
if(driver_match_device(drv, dev)
{
driver_probe_device(drv, dev)=> really-probe
{
1.  ret = pinctrl_bind_pins(dev);  设置pinctrl
2. dev->pm_domain->activate(dev); 上电
3.  调驱动程序中实现的probe接口, 比如lpi2c_imx_probe
}
}
}
}
}
}
}

你可能感兴趣的:(Linux)