• I2C驱动框架(二)


    参考:I2C子系统之I2C bus初始化——I2C_init()

    在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的链表上
  • 相关阅读:
    CSS知识点:清除浮动
    CSS3的应用,你学会了吗?
    必须掌握的JavaScript基本知识
    一个搜索框的背后
    mybatis 中 foreach collection的三种用法
    基于Pipe的PureMVC FLEX框架的多核共享消息技术
    Flex与Java通信之HttpService
    python + eclipse + django + postgresql 开发网站(二)
    python + eclipse + django + postgresql 开发网站(一)
    [转]Python集合(set)类型的操作
  • 原文地址:https://www.cnblogs.com/yangjiguang/p/6218724.html
Copyright © 2020-2023  润新知