首页 > 代码库 > I2C驱动框架(二)

I2C驱动框架(二)

在linux内核启动的时候最先执行的和I2C子系统相关的函数应该是driver/i2c/i2c-core.c文件中的i2c_init()函数。

 1 static int __init i2c_init(void)
 2 {
 5     retval = bus_register(&i2c_bus_type);
 9     i2c_adapter_compat_class = class_compat_register("i2c-adapter");
15     retval = i2c_add_driver(&dummy_driver);
18     return 0;
27 }

1.bus_register(&i2c_bus_type)注册i2c总线

struct bus_type i2c_bus_type = {
.name    = "i2c",
.match    = i2c_device_match,
.probe    = i2c_device_probe,
.remove    = i2c_device_remove,
.shutdown    = i2c_device_shutdown,
.pm    = &i2c_device_pm_ops,
};

该函数执行完会在/sys/bus目录下创建i2c子目录,并在i2c子目录下创建devices和drivers两个目录,以后注册到i2c总线上的设备和驱动会分别放在这两个目录。

技术分享

2.class_compat_register("i2c-adapter")在/sys/class/目录下创建i2c-adapter子类目录

技术分享

3.i2c_add_driver(&dummy_driver)在i2c-bus上注册驱动,该函数执行成功后会在/sys/bus/i2c/drivers目录下创建.driver.name = "dummy"为名字的目录。

技术分享

static struct i2c_driver dummy_driver = {
    .driver.name    = "dummy",
    .probe        = dummy_probe,
    .remove        = dummy_remove,
    .id_table    = dummy_id,
};

分析该该函数前先看一下i2c_bus_type总线-设备-驱动模型。

技术分享

struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)和

int i2c_add_adapter(struct i2c_adapter *adapter)向i2c_bus_type注册i2c_client和i2c_adapter。两种不同的设备以dev->type来区分,

struct device_type i2c_adapter_type = {
    .groups        = i2c_adapter_attr_groups,
    .release    = i2c_adapter_dev_release,
};

static struct device_type i2c_client_type = {
    .groups        = i2c_dev_attr_groups,
    .uevent        = i2c_device_uevent,
    .release    = i2c_client_dev_release,
};

static inline int i2c_add_driver(struct i2c_driver *driver)则向i2c_bus_type注册i2c_driver。

i2c_add_driver(&dummy_driver);
    --> i2c_register_driver(THIS_MODULE, driver);
        -->&dummy_driver->driver.bus = &i2c_bus_type;
        -->res = driver_register(&(&dummy_driver)->driver);//将驱动注册到i2c_bust_type
        -->i2c_for_each_dev(&dummy_driver, __process_new_driver);
            //遍历i2c_bus_type总线上的设备
            -->bus_for_each_dev(&i2c_bus_type, NULL, &dummy_driver, __process_new_driver);
                //以找到的设备和dummy_driver为参数调用__process_new_driver函数
                -->__process_new_driver(dev, &dummy_driver);

由于i2c_add_driver(&dummy_driver)执行时,i2c_bus_type总线上还没有注册设备,所以不会执行__process_new_driver函数。

但下面还是分析一下__process_new_driver函数的执行过程,该函数最终调用i2c_detect函数检测设备是否存在。

 __process_new_driver(dev,&dummy_driver)
     -->if (dev->type != &i2c_adapter_type)    return 0;//判断是i2c_adapter_type类型的设备才继续执行
     --> i2c_do_add_adapter(&dummy_driver, to_i2c_adapter(dev));
         -->i2c_detect(adap, &dummy_driver);// Detect supported devices on that bus, and instantiate them 

 

static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
    -->int adap_id = i2c_adapter_id(adapter);//获取adapter的序列号,即处理器的第几个I2C控制器
    -->const unsigned short *address_list = driver->address_list; //获取I2C从设备的地址数组
    -->if (!(adapter->class & driver->class)) return 0; //类型匹配后才继续执行
    -->struct i2c_client *temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);//分配i2c_client结构体
    -->temp_client->adapter = adapter;
    -->for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) //遍历address_list里的i2c地址
        -->temp_client->addr = address_list[i];//设置从地址到i2c_client结构体
        -->i2c_detect_address(temp_client, driver);//检测该从地址对应的设备是否存在

 

static int i2c_detect_address(struct i2c_client *temp_client,struct i2c_driver *driver)
    -->int addr = temp_client->addr;
    -->i2c_check_addr_validity(addr);//检测地址有效性
    -->i2c_check_addr_busy(adapter, addr);//检测设备是否正在使用,同一条物理I2Cbus上不能有两个相同address的器件
    -->i2c_default_probe(adapter, addr);//检测i2c物理总线上是否有设备应答
    -->struct i2c_board_info info.addr=temp_client->addr
    -->driver->detect(temp_client, &info);//调用i2c_driver的detect函数检测设备,并经info.type赋值
    -->struct i2c_client *client = i2c_new_device(adapter, &info);//在i2b_bus_type总线上创建i2c_client设备
    -->list_add_tail(&client->detected, &driver->clients);//创建设备成功则将该i2c_client挂到i2c_driver的链表上

 

I2C驱动框架(二)