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的分析哦

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

  • 相关阅读:
    Postgresql HStore 插件试用小结
    postgres-xl 安装与部署 【异常处理】ERROR: could not open file (null)/STDIN_***_0 for write, No such file or directory
    GPDB 5.x PSQL Quick Reference
    postgresql 数据库schema 复制
    hive 打印日志
    gp与 pg 查询进程
    jquery table 发送两次请求 解惑
    python 字符串拼接效率打脸帖
    postgresql 日期类型处理实践
    IBM Rational Rose软件下载以及全破解方法
  • 原文地址:https://www.cnblogs.com/haoxing990/p/4718834.html
Copyright © 2011-2022 走看看