zoukankan      html  css  js  c++  java
  • i2c_drivers个人分析

    archarmmach-mx6oard-mx6q_sabresd.c

     1 static struct i2c_board_info i2c_board_info_rtc[] __initdata = {
     2     //isl1208 does not work on the 1st board that's sent to Korea, but we should enbaled it later.
     3 #if 1
     4     {
     5         I2C_BOARD_INFO("isl1208", 0x6F),
     6         //.irq = gpio_to_irq(CYNO_GPIO_R10),
     7     },
     8 #else
     9     //pcf8563 is no longer usned.
    10     {
    11         I2C_BOARD_INFO("pcf8563", 0x51),
    12         //.irq = gpio_to_irq(CYNO_GPIO_R10),
    13     },
    14 #endif
    15 };

     这个busnum号决定了adapter->nr之间的关系,如果相等这把这个总线设备和适配器连接起来

    i2c_register_board_info(2, i2c_board_info_rtc, ARRAY_SIZE(i2c_board_info_rtc));

    下面我们再来分析下i2c_register_board_info这个文件的定义

    在drivers/i2c/i2c-boardinfo.c文件中我们找到这个函数的定义:

     1 int __init
     2 i2c_register_board_info(int busnum, //这个busnum号决定了adapter->nr之间的关系,如果相等这把这个总线设备和适配器连接起来
     3     struct i2c_board_info const *info, unsigned len)
     4 {
     5     int status;
     6 
     7     down_write(&__i2c_board_lock);
     8 
     9     /* dynamic bus numbers will be assigned after the last static one */
    10     if (busnum >= __i2c_first_dynamic_bus_num)
    11         __i2c_first_dynamic_bus_num = busnum + 1;
    12 
    13     for (status = 0; len; len--, info++) {
    14         struct i2c_devinfo    *devinfo;
    15 
    16         devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
    17         if (!devinfo) {
    18             pr_debug("i2c-core: can't register boardinfo!
    ");
    19             status = -ENOMEM;
    20             break;
    21         }
    22 
    23         devinfo->busnum = busnum;
    24         devinfo->board_info = *info;
    25         list_add_tail(&devinfo->list, &__i2c_board_list);
    26     }
    27 
    28     up_write(&__i2c_board_lock);
    29 
    30     return status;
    31 }

    在这个函数里面定义了bus_num以及RTC相关信息

    下面我们针对这个设备具体分析

    我们在/drivers/rtc/rtc-isl1208.c这个文件

    static const struct i2c_device_id isl1208_id[] = {
    { "isl1208", 0 },
    { }
    };
    MODULE_DEVICE_TABLE(i2c, isl1208_id);

    static struct i2c_driver isl1208_driver = {
    .driver = {
    .name = "rtc-isl1208",
    },
    .probe = isl1208_probe,
    .remove = isl1208_remove,
    .id_table = isl1208_id,
    };

    可以看到isl1208_driver真是这个设备所支持的驱动 

    static int i2c_register_adapter(struct i2c_adapter *adap)
    {
     int res = 0, dummy;

     mutex_init(&adap->bus_lock);    //初始化保护i2c适配器的互斥锁
     mutex_init(&adap->clist_lock);    //初始化保护adap->clients的锁
     INIT_LIST_HEAD(&adap->clients); //初始化i2c适配器上介入的设备(client)链表

     mutex_lock(&core_lock);

    //初始化adap->dev然后注册该设备
     if (adap->dev.parent == NULL) {
      adap->dev.parent = &platform_bus;
      pr_debug("I2C adapter driver [%s] forgot to specify "
        "physical device ", adap->name);
     }
     sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
     adap->dev.release = &i2c_adapter_dev_release;
     adap->dev.class = &i2c_adapter_class;
     res = device_register(&adap->dev);
     if (res)
      goto out_list;

     dev_dbg(&adap->dev, "adapter [%s] registered ", adap->name);

    //适配器驱动注册进内核后,对系统中现有的两种设备进行绑定。

     
     if (adap->nr < __i2c_first_dynamic_bus_num)//__i2c_first_dynamic_bus_num表示第一个动态分配的设备号
      i2c_scan_static_board_info(adap);  //如果适配器号和设备好一致,则会进行设备和适配器的绑定,如果不一致,则会执行下面的函数

     
     dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, 
         i2c_do_add_adapter);

    out_unlock:
     mutex_unlock(&core_lock);
     return res;

    out_list:
     idr_remove(&i2c_adapter_idr, adap->nr);
     goto out_unlock;
    }

    注册适配器后,开始调用  i2c_scan_static_board_info(adap);查找i2c_board_info的相关设备的注册信息

    __i2c_board_list中查找 我们在板级文件中以把相关i2c——device的信息注册到这个双向链表中了。。struct i2c_devinfo相对比,如果找到了,就会调用i2c_new_device()把device和适配器绑定在一起,

    static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
    {
     struct i2c_devinfo *devinfo;

     mutex_lock(&__i2c_board_lock);
     list_for_each_entry(devinfo, &__i2c_board_list, list) {
      if (devinfo->busnum == adapter->nr //如果device编号和adapter编号一致,则会调用i2c_new_device,把device和adapter绑定在一起
        && !i2c_new_device(adapter,
          &devinfo->board_info))
       printk(KERN_ERR "i2c-core: can't create i2c%d-x ",
        i2c_adapter_id(adapter),
        devinfo->board_info.addr);
     }
     mutex_unlock(&__i2c_board_lock);
    }

    下面来分析这个i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
    struct i2c_client *
    i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
    {
    struct i2c_client *client;
    int status;

    client = kzalloc(sizeof *client, GFP_KERNEL);
    if (!client)
    return NULL;

    client->adapter = adap; //在这个地方适配器和i2c_device 绑定

    client->dev.platform_data = info->platform_data;

    if (info->archdata)
    client->dev.archdata = *info->archdata;

    client->flags = info->flags;
    client->addr = info->addr;//这个地方决定了设备的地址
    client->irq = info->irq;

    strlcpy(client->name, info->type, sizeof(client->name));

    /* Check for address validity */
    status = i2c_check_client_addr_validity(client);
    if (status) {
    dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx ",
    client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);
    goto out_err_silent;
    }

    /* Check for address business */
    status = i2c_check_addr_busy(adap, client->addr);
    if (status)
    goto out_err;

    client->dev.parent = &client->adapter->dev;
    client->dev.bus = &i2c_bus_type;
    client->dev.type = &i2c_client_type;
    client->dev.of_node = info->of_node;

    dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
    client->addr);
    status = device_register(&client->dev);这个设备被绑定到了总线上面,但是这个设备所支持的drivers呢??????

    if (status)
    goto out_err;

    dev_dbg(&adap->dev, "client [%s] registered with bus id %s ",
    client->name, dev_name(&client->dev));

    return client;

    out_err:
    dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
    "(%d) ", client->name, client->addr, status);
    out_err_silent:
    kfree(client);
    return NULL;
    }

    下面分析 dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, i2c_do_add_adapter);这个函数

    static int i2c_do_add_adapter(struct i2c_driver *driver,
    struct i2c_adapter *adap)
    {
    /* Detect supported devices on that bus, and instantiate them */
    i2c_detect(adap, driver); 通过这个函数又会把设配器和设备绑定在一起,这次依靠的是driver的地址是否存在而绑定的

    /* Let legacy drivers scan this bus for matching devices */
    if (driver->attach_adapter) {
    dev_warn(&adap->dev, "%s: attach_adapter method is deprecated ",
    driver->driver.name);
    dev_warn(&adap->dev, "Please use another way to instantiate "
    "your i2c_client ");
    /* We ignore the return code; if it fails, too bad */
    driver->attach_adapter(adap);
    }
    return 0;
    }

    在struct i2c_adapter 注册到内核中后,内核时怎样把已经注册进系统中的i2c设备设备与刚注册进内核的适配器进行绑定的。分两种情况一是在板级用 i2c_register_board_info注册的,其二是通过各种struct i2c_driver注册的。其中驱动注册又有两种方法,一种是新的总线式驱动一种是老式的,这里我们对老式的方法不做介绍,老式的方法在内核中也慢慢的消亡。

    可能很多人有以后这个该死的adapter什么时候注册,那我现在说先注册顺序(讲解针对板级文件中设备的注册分析)

    步骤1:i2c_register_board_info(2, i2c_board_info_rtc, ARRAY_SIZE(i2c_board_info_rtc));

    注册这个板级文件后就会把这个device的相关信息存储到__i2c_board_list

    步骤2对于静态的注册adapter这个适配器,这个早就设定好了,所以直接注册,在这个函数i2c_register_adapter的后面几个函数就会决定设配器和device的绑定


      • int
         i2c_add_numbered_adapter(struct i2c_adapter *adap)  
      • {  
      •     int id;  
      •     int status;  
      •   
      •     if (adap->nr & ~MAX_ID_MASK)  
      •         return -EINVAL;  
      •   
      • retry:  
      •     if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)  
      •         return -ENOMEM;  
      •   
      •     mutex_lock(&core_lock);  
      •     /* "above" here means "above or equal to", sigh; 
      •      * we need the "equal to" result to force the result 
      •      */  
      •     status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);  
      •     if (status == 0 && id != adap->nr) {  
      •         status = -EBUSY;  
      •         idr_remove(&i2c_adapter_idr, id);  
      •     }  
      •     mutex_unlock(&core_lock);  
      •     if (status == -EAGAIN)  
      •         goto retry;  
      •   
      •     if (status == 0)  
      •         status = i2c_register_adapter(adap);  
      •     return status;  
      • }  

     if (adap->nr < __i2c_first_dynamic_bus_num)//__i2c_first_dynamic_bus_num表示第一个动态分配的设备号
      i2c_scan_static_board_info(adap);  //如果适配器号和设备好一致,则会进行设备和适配器的绑定,如果不一致,则会执行下面的函数

     dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, 
         i2c_do_add_adapter);

     步骤3:现在设配器和设备已经绑定了,那设备的驱动什么时候能找到这个设备呢,我们继续分析

    static struct i2c_driver isl1208_driver = {
    .driver = {
    .name = "rtc-isl1208",
    },
    .probe = isl1208_probe,
    .remove = isl1208_remove,
    .id_table = isl1208_id,
    };

    在driver/rtc/rtc-isli1208.c文件中最好几行代码会注册这个驱动,

    static int __init
    isl1208_init(void)
    {
    return i2c_add_driver(&isl1208_driver);
    }

    static void __exit
    isl1208_exit(void)
    {
    i2c_del_driver(&isl1208_driver);
    }

    我们再来分析这个i2c_add_driver函数,也许会有一点感悟

    static inline int i2c_add_driver(struct i2c_driver *driver)
    {
    return i2c_register_driver(THIS_MODULE, driver);
    }

    /*
    * An i2c_driver is used with one or more i2c_client (device) nodes to access
    * i2c slave chips, on a bus instance associated with some i2c_adapter.
    */

    int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
    {
    int res;

    /* Can't register until after driver model init */
    if (unlikely(WARN_ON(!i2c_bus_type.p)))
    return -EAGAIN;

    /* add the driver to the list of i2c drivers in the driver core */
    driver->driver.owner = owner;
    driver->driver.bus = &i2c_bus_type;

    /* When registration returns, the driver core
    * will have called probe() for all matching-but-unbound devices.
    */
    res = driver_register(&driver->driver);
    if (res)
    return res;

    /* Drivers should switch to dev_pm_ops instead. *///这个地方会通过probe函数实现
    if (driver->suspend)
    pr_warn("i2c-core: driver [%s] using legacy suspend method ",
    driver->driver.name);
    if (driver->resume)
    pr_warn("i2c-core: driver [%s] using legacy resume method ",
    driver->driver.name);

    pr_debug("i2c-core: driver [%s] registered ", driver->driver.name);

    INIT_LIST_HEAD(&driver->clients);
    /* Walk the adapters that are already present */
    i2c_for_each_dev(driver, __process_new_driver);

    return 0;

    }

    这个函数最下面有个i2c_for_each_dev(driver, __process_new_driver);这个地方不太理解,个人认为是那些可插拔设备寻找合适的适配器的方法

    那到底设备和驱动是怎么结合到一起的呢,正确的设备是怎么配对正确的驱动的呢,这个最主要的功臣当然非probe函数莫属啦

    那我们就来看看.probe = isl1208_probe这个探测函数吧

    isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
    {
    int rc = 0;
    struct rtc_device *rtc;

    if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))  //检查设备有哪些功能
    return -ENODEV;

    if (isl1208_i2c_validate_client(client) < 0) //判定这个设备是否是isl1208驱动所支持的设备,如过不是probe探测失败,
    return -ENODEV;

    dev_info(&client->dev,
    "chip found, driver version " DRV_VERSION " ");

    if (client->irq > 0) {
    rc = request_threaded_irq(client->irq, NULL,isl1208_rtc_interrupt,IRQF_SHARED,
                                                           isl1208_driver.driver.name, client);//申请中断
    if (!rc) {
    device_init_wakeup(&client->dev, 1);
    enable_irq_wake(client->irq);
    } else {
    dev_err(&client->dev,
    "Unable to request irq %d, no alarm support ",
    client->irq);
    client->irq = 0;
    }
    }

    rtc = rtc_device_register(isl1208_driver.driver.name,
    &client->dev, &isl1208_rtc_ops,  THIS_MODULE); //关键中的关键终于到来,设备和驱动完美的结合,特备强调isl1208_rtc_ops,我们看看它代表什么。

    ////////////////////static const struct rtc_class_ops isl1208_rtc_ops = {

    proc — 一个虚拟文件系统 
    /proc 文件系统是一种内核和内核模块用来向进程 (process) 发送信息的机制 (所以叫做 /proc)。这个伪文件系统让你可以和内核内部数据结构进行交互,获取 有关进程的有用信息,在运行中 (on the fly) 改变设置 (通过改变内核参数)。 与其他文件系统不同,/proc 存在于内存之中而不是硬盘上。
    ///////////////////      .proc = isl1208_rtc_proc,  这些函数不都是定义在rtc-isl1208.c这个文件里面吗,此处的配置就是为了用户在调用rtc-isl1208这个设备的时候,能够对这个设备进行相应的读写操作
    //////////////////       .read_time = isl1208_rtc_read_time,
    /////////////////        .set_time = isl1208_rtc_set_time,
    ////////////////         .read_alarm = isl1208_rtc_read_alarm,

    ////////                  .set_alarm = isl1208_rtc_set_alarm,

    ///////////////////////        };


    if (IS_ERR(rtc)) {
    rc = PTR_ERR(rtc);
    goto exit_free_irq;
    }

    i2c_set_clientdata(client, rtc);

    rc = isl1208_i2c_get_sr(client);
    if (rc < 0) {
    dev_err(&client->dev, "reading status failed ");
    goto exit_unregister;
    }

    if (rc & ISL1208_REG_SR_RTCF)
    dev_warn(&client->dev, "rtc power failure detected, "
    "please set clock. ");

    rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
    if (rc)
    goto exit_unregister;

    return 0;

    exit_unregister:
    rtc_device_unregister(rtc);
    exit_free_irq:
    if (client->irq)
    free_irq(client->irq, client);

    return rc;
    }

    至此整个I2C的体系的分析就告一段落了,下一步,usb-mouse的分析哦

    我敢肯定这里有很多不对的地方,如果被某人发现,请给我留言,谢谢 我定会更正

  • 相关阅读:
    JavaScript 用new创建对象的过程
    从输入URL到浏览器显示页面发生了什么
    JS中的this对象详解
    JS事件
    vue如何正确销毁当前组件的scroll事件?
    pg创建存储过程批量提交
    mysql去掉明文密码不安全提示
    解决npm安装node-sass太慢及编译错误问题
    解决vs code编写python输出中文乱码问题
    EditPlus配置Java编译器
  • 原文地址:https://www.cnblogs.com/haoxing990/p/4718834.html
Copyright © 2011-2022 走看看