• i2c sub system __i2c_board_list/klist_devices/klist_drivers


    i2c_devinfo全局链表: __i2c_board_list 用来挂接 i2c_board_info,这个信息用来生成 i2c_client

    i2c_client 链表: i2c_bus_type->p->klist_devices

    i2c_driver 链表i2c_bus_type->p->klist_drivers 

    硬件i2c控制器硬件初始化完成,注册 adapter时,依据__i2c_board_list 中信息生成i2c_client,并挂接在klist_devices链表上

    在注册 adapter时,即:i2c_add_numbered_adapter( struct i2c_adapter*),会做三件事情:

    1、遍历 __i2c_board_list 链表,查找和 adapter->nr 相同的 i2c_devinfo->busnum,查找成功就会生成 i2c_client

    2、将生成的 i2c_client->dev 挂接到 klist_devices 链表

    3、如果第一步生成 i2c_client 成功,那么遍历 klist_drivers 链表,查找和 i2c_client->name 相同的 i2c_driver->id_table->name,查找成功调用 i2c_driver->probe()

    在注册i2c_driver时,即:i2c_add_driver(struct i2c_driver*),会做两件事情:

    1、将 i2c_driver->drv 挂接到此链表

    2、遍历 klist_devices 链表,查找与 i2c_driver->id_table->name 相同的 i2c_client->name。

    如果查找成功调用 i2c_driver->probe()

    如果查找失败,有两个原因:

    a、硬件i2c控制器尚未初始化,即 __i2c_board_list 尚未转化为 i2c_client;

    b、 硬件i2c控制器已经初始化,但是 i2c_board_info 注册失败。i2c_board_info 注册失败又分两种:1、没有注册  2、注册了而且挂接到了__i2c_board_list,但是挂接时,硬件i2c控制器早就初始化完成,所以没有生成 i2c_client,klist_devices 链表中就不会有此i2c_client 信息。

    误区:曾经以为 在 i2c_board_info 注册成功后,module_init()结束时,就一定会执行 i2c_driver->probe()。

    现在看来,

    1、i2c_add_driver()早于硬件i2c控制器硬件初始化,那么会在注册 adapter 时,i2c_client->name 匹配 i2c_driver->id_table->name 成功,执行 i2c_driver->probe()

    2、i2c_add_driver()晚于硬件i2c控制器硬件初始化,那么会在i2c_add_driver()时,i2c_driver->id_table->name 匹配 i2c_client 成功,执行 i2c_driver->probe()

    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,
    };
    EXPORT_SYMBOL_GPL(i2c_bus_type);

    struct bus_type {
    const char  *name;
    const char  *dev_name;
    struct device  *dev_root;
    struct bus_attribute*bus_attrs;
    struct device_attribute*dev_attrs;
    struct driver_attribute*drv_attrs;
    int (*match)(struct device *dev, struct device_driver *drv);
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
    int (*probe)(struct device *dev);
    int (*remove)(struct device *dev);
    void (*shutdown)(struct device *dev);
    int (*suspend)(struct device *dev, pm_message_t state);
    int (*resume)(struct device *dev);
    const struct dev_pm_ops *pm;
    struct iommu_ops *iommu_ops;
    struct subsys_private *p;
    };

    struct subsys_private {
    struct kset subsys;
    struct kset *devices_kset;
    struct list_head interfaces;
    struct mutex mutex;
    struct kset *drivers_kset;

    struct klist klist_devices; // 挂接 i2c_client->dev 的链表
    struct klist klist_drivers;  // 挂接 i2c_driver->drv 的链表

    struct blocking_notifier_head bus_notifier;
    unsigned int drivers_autoprobe:1;
    struct bus_type *bus; // 总线类型,此处为 &i2c_bus_type
    struct kset glue_dirs;
    struct class *class;
    };

    kernel/drivers/i2c/i2c-boardinfo.c

    struct i2c_client 中的name/addr/irq 等信息是从 struct i2c_board_info得来的,关于如何得到见下文。

    所有的i2c_board_info 都要添加到全局链表 __i2c_board_list 中,而且应该在硬件i2c控制器模块加载前添加,以便控制器模块加载时生成 i2c_client。生成的 i2c_client 通过其 struct device* 成员被添加到 i2c_bus_type 总线上。原因见下文。

    /**
     * struct i2c_board_info - template for device creation
     * @type: chip type, to initialize i2c_client.name
     * @flags: to initialize i2c_client.flags
     * @addr: stored in i2c_client.addr
     * @platform_data: stored in i2c_client.dev.platform_data
     * @archdata: copied into i2c_client.dev.archdata
     * @of_node: pointer to OpenFirmware device node
     * @irq: stored in i2c_client.irq

    */

    struct i2c_board_info {
    char type[I2C_NAME_SIZE];
    unsigned shortflags;
    unsigned shortaddr;
    void *platform_data;
    struct dev_archdata*archdata;
    struct device_node *of_node;
    int irq;
    };

    int __init

    i2c_register_board_info(int busnum,
    struct i2c_board_info const *info, unsigned len)
    {
    int status;
    down_write(&__i2c_board_lock);
    /* dynamic bus numbers will be assigned after the last static one */
    if (busnum >= __i2c_first_dynamic_bus_num)
    __i2c_first_dynamic_bus_num = busnum + 1;
    for (status = 0; len; len--, info++) {
    struct i2c_devinfo*devinfo;
    devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
    if (!devinfo) {
    pr_debug("i2c-core: can't register boardinfo! ");
    status = -ENOMEM;
    break;
    }
    devinfo->busnum = busnum;    //在硬件i2c控制器注册adapter时, 这个busnum 将和adapter->nr匹配,生成i2c_client。
    devinfo->board_info = *info;
    list_add_tail(&devinfo->list, &__i2c_board_list);

    }
    up_write(&__i2c_board_lock);
    return status;

    }

    在struct i2c_adapter 注册时,将链表 __i2c_board_list 中的 i2c_devinfo->busnum 和 i2c_adapter->nr 进行比较,相同则进行 i2c_client生成,并且通过 struct i2c_client的struct device* 成员添加到 i2c_bus_type->p->klist_devices 链表中。

    那么在进行struct i2c_driver 注册时,就可以到 klist_devices 链表中查找 name 域和 i2c_driver->id_table->name 相同的 i2c_client 了。

    如果查找到,就可以继续调用 struct i2c_driver->probe()函数了,并且将此 i2c_client 和 i2c_driver->id_table 作为参数。

    int i2c_add_numbered_adapter(struct i2c_adapter *adap)
    {
    int id;
    int status;
    printk("[i2c-core][i2c_add_numbered_adapter] start ");
    if (adap->nr == -1) /* -1 means dynamically assign bus id */
    return i2c_add_adapter(adap);
    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;
    }
    EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);

    static int i2c_register_adapter(struct i2c_adapter *adap)
    {
    int res = 0;
    printk("[i2c-core][i2c_register_adapter] start ");
    /* Can't register until after driver model init */
    if (unlikely(WARN_ON(!i2c_bus_type.p))) {
    res = -EAGAIN;
    goto out_list;
    }
    /* Sanity checks */
    if (unlikely(adap->name[0] == '')) {
    pr_err("i2c-core: Attempt to register an adapter with "
          "no name! ");
    return -EINVAL;
    }
    if (unlikely(!adap->algo)) {
    pr_err("i2c-core: Attempt to register adapter '%s' with "
          "no algo! ", adap->name);
    return -EINVAL;
    }
    rt_mutex_init(&adap->bus_lock);
    mutex_init(&adap->userspace_clients_lock);
    INIT_LIST_HEAD(&adap->userspace_clients);

    /* Set default timeout to 1 second if not already set */
    if (adap->timeout == 0)
    adap->timeout = HZ;

    dev_set_name(&adap->dev, "i2c-%d", adap->nr);
    adap->dev.bus = &i2c_bus_type;
    adap->dev.type = &i2c_adapter_type;

    res = device_register(&adap->dev);
    if (res)
    goto out_list;
    dev_dbg(&adap->dev, "adapter [%s] registered ", adap->name);
    #ifdef CONFIG_I2C_COMPAT
    res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
          adap->dev.parent);
    if (res)
    dev_warn(&adap->dev,
    "Failed to create compatibility class link ");
    #endif
    /* create pre-declared device nodes */
    if (adap->nr < __i2c_first_dynamic_bus_num)
    i2c_scan_static_board_info(adap);
    /* Notify drivers */
    mutex_lock(&core_lock);
    bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
    mutex_unlock(&core_lock);
    printk("[i2c-core][i2c_register_adapter] end ");
    return 0;
    out_list:
    。。。。。。。
    }

    遍历 __i2c_board_list 链表上的 i2c_board_info ,比较其 busnum 和 指定的 adapter->nr 是否相同,相同则生成 struct i2c_client ,并且将 i2c_client 的 struct device* 成员挂接到 i2c_bus_type->p->klist_devices 链表上,等到 struct i2c_driver 注册时,将会遍历此链表,寻找和 i2c_driver->id_table->name 相同的 i2c_client。

    static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
    {
    struct i2c_devinfo*devinfo;
    printk("[i2c-core][i2c_scan_static_board_info] ");
    down_read(&__i2c_board_lock);


    list_for_each_entry(devinfo, &__i2c_board_list, list) {
    if (devinfo->busnum == adapter->nr
    && !i2c_new_device(adapter,
    &devinfo->board_info))
    printk(
    "Can't create device at 0x%02x ",
    devinfo->board_info.addr);
    }
    up_read(&__i2c_board_lock);
    }

    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;
    client->dev.platform_data = info->platform_data;      // 生成 struct i2c_client
    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;
    /* For 10-bit clients, add an arbitrary offset to avoid collisions */
    dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
        client->addr | ((client->flags & I2C_CLIENT_TEN)
        ? 0xa000 : 0));
    status = device_register(&client->dev); // 将 i2c_client 的struct device* 成员挂接到 i2c_bus_type->p->klist_devices 链表上。
    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:
    。。。。。。。
    }
    EXPORT_SYMBOL_GPL(i2c_new_device);

    int device_register(struct device *dev)
    {
    device_initialize(dev);
    return device_add(dev);
    }

    int device_add(struct device *dev)
    {
    struct device *parent = NULL;
    struct kobject *kobj;
    struct class_interface *class_intf;
    int error = -EINVAL;
    dev = get_device(dev);
    if (!dev)
    goto done;
    if (!dev->p) {
    error = device_private_init(dev);
    if (error)
    goto done;
    }
    /*
    * for statically allocated devices, which should all be converted
    * some day, we need to initialize the name. We prevent reading back
    * the name, and force the use of dev_name()
    */
    if (dev->init_name) {
    dev_set_name(dev, "%s", dev->init_name);
    dev->init_name = NULL;
    }
    /* subsystems can specify simple device enumeration */
    if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
    dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
    if (!dev_name(dev)) {
    error = -EINVAL;
    goto name_error;
    }
    pr_debug("device: '%s': %s ", dev_name(dev), __func__);
    parent = get_device(dev->parent);
    kobj = get_device_parent(dev, parent);
    if (kobj)
    dev->kobj.parent = kobj;
    /* use parent numa_node */
    if (parent)
    set_dev_node(dev, dev_to_node(parent));
    /* first, register with generic layer. */
    /* we require the name to be set before, and pass NULL */
    error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
    if (error)
    goto Error;
    /* notify platform of device entry */
    if (platform_notify)
    platform_notify(dev);
    error = device_create_file(dev, &uevent_attr);
    if (error)
    goto attrError;
    if (MAJOR(dev->devt)) {
    error = device_create_file(dev, &devt_attr);
    if (error)
    goto ueventattrError;
    error = device_create_sys_dev_entry(dev);
    if (error)
    goto devtattrError;
    devtmpfs_create_node(dev);
    }
    error = device_add_class_symlinks(dev);
    if (error)
    goto SymlinkError;
    error = device_add_attrs(dev);
    if (error)
    goto AttrsError;
    error = bus_add_device(dev);
    if (error)
    goto BusError;
    error = dpm_sysfs_add(dev);
    if (error)
    goto DPMError;
    device_pm_add(dev);
    /* Notify clients of device addition.  This call must come
    * after dpm_sysfs_add() and before kobject_uevent().
    */
    if (dev->bus)
    blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
        BUS_NOTIFY_ADD_DEVICE, dev);
    kobject_uevent(&dev->kobj, KOBJ_ADD);
    bus_probe_device(dev); // 如果i2c_driver的注册先于硬件i2c控制器模块的加载,这时 __i2c_board_list里面的信息 还没有生成 i2c_client,i2c_driver->probe() 就要等到此时执行。


    if (parent)
    klist_add_tail(&dev->p->knode_parent,
          &parent->p->klist_children);

    if (dev->class) {
    mutex_lock(&dev->class->p->mutex);
    /* tie the class to the device */
    klist_add_tail(&dev->knode_class,
          &dev->class->p->klist_devices);

    /* notify any interfaces that the device is here */
    list_for_each_entry(class_intf,
       &dev->class->p->interfaces, node)
    if (class_intf->add_dev)
    class_intf->add_dev(dev, class_intf);
    mutex_unlock(&dev->class->p->mutex);
    }
    done:
    。。。。。。。。。。。
    }

    int bus_add_device(struct device *dev)
    {
    struct bus_type *bus = bus_get(dev->bus);
    int error = 0;
    if (bus) {
    pr_debug("bus: '%s': add device %s ", bus->name, dev_name(dev));
    error = device_add_attrs(bus, dev);
    if (error)
    goto out_put;
    error = sysfs_create_link(&bus->p->devices_kset->kobj,
    &dev->kobj, dev_name(dev));
    if (error)
    goto out_id;
    error = sysfs_create_link(&dev->kobj,
    &dev->bus->p->subsys.kobj, "subsystem");
    if (error)
    goto out_subsys;
    klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices); // 将 i2c_client 挂接到 i2c_bus_type->p->klist_devices 上。
    }
    return 0;
    out_subsys:
    sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
    out_id:
    device_remove_attrs(bus, dev);
    out_put:
    bus_put(dev->bus);
    return error;
    }

    void bus_probe_device(struct device *dev)
    {
    struct bus_type *bus = dev->bus;
    struct subsys_interface *sif;
    int ret;
    if (!bus)
    return;
    if (bus->p->drivers_autoprobe) {
    ret = device_attach(dev);
    WARN_ON(ret < 0);
    }
    mutex_lock(&bus->p->mutex);
    list_for_each_entry(sif, &bus->p->interfaces, node)
    if (sif->add_dev)
    sif->add_dev(dev, sif);
    mutex_unlock(&bus->p->mutex);
    }

    int device_attach(struct device *dev)
    {
    int ret = 0;
    device_lock(dev);
    if (dev->driver) {
    if (klist_node_attached(&dev->p->knode_driver)) {
    ret = 1;
    goto out_unlock;
    }
    ret = device_bind_driver(dev);
    if (ret == 0)
    ret = 1;
    else {
    dev->driver = NULL;
    ret = 0;
    }
    } else {
    pm_runtime_get_noresume(dev);
    ret = bus_for_each_drv(dev->bus, NULL, dev,__device_attach);
    pm_runtime_put_sync(dev);
    }
    out_unlock:
    device_unlock(dev);
    return ret;
    }
    EXPORT_SYMBOL_GPL(device_attach);

    遍历 i2c_bus_type->p->klist_drivers 链表,对比 i2c_driver->id_table->name 和 i2c_client->name,相同则调用 i2c_driver->probe()。

    int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
        void *data, int (*fn)(struct device_driver *, void *))
    {
    struct klist_iter i;
    struct device_driver *drv;
    int error = 0;
    if (!bus)
    return -EINVAL;
    klist_iter_init_node(&bus->p->klist_drivers, &i,
        start ? &start->p->knode_bus : NULL);
    while ((drv = next_driver(&i)) && !error)
    error = fn(drv, data);
    klist_iter_exit(&i);
    return error;
    }
    EXPORT_SYMBOL_GPL(bus_for_each_drv);

    static int __device_attach(struct device_driver *drv, void *data)
    {
    struct device *dev = data;

    if (!driver_match_device(drv, dev)) // ->i2c_device_match() ->i2c_match_id()
    return 0;
    return driver_probe_device(drv, dev); //  ->i2c_device_probe() ->i2c_driver->probe(client, i2c_match_id(driver->id_table, client))
    }

    注册 struct i2c_driver 。

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

    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. */
    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 */
    int ret =0;
    ret = i2c_for_each_dev(driver, __process_new_driver);
    printk("[i2c-core][i2c_register_driver] ret:%d driver-name:%s ",ret, driver->driver.name);
    return 0;
    }
    EXPORT_SYMBOL(i2c_register_driver);

    int driver_register(struct device_driver *drv)
    {
    int ret;
    struct device_driver *other;
    BUG_ON(!drv->bus->p);
    if ((drv->bus->probe && drv->probe) ||
       (drv->bus->remove && drv->remove) ||
       (drv->bus->shutdown && drv->shutdown))
    printk(KERN_WARNING "Driver '%s' needs updating - please use "
    "bus_type methods ", drv->name);
    other =driver_find(drv->name, drv->bus);  //查看此i2c_driver是否已经注册过
    if (other) {
    printk(KERN_ERR "Error: Driver '%s' is already registered, "
    "aborting... ", drv->name);
    return -EBUSY;
    }
    ret =bus_add_driver(drv);
    if (ret)
    return ret;
    ret = driver_add_groups(drv, drv->groups);
    if (ret)
    bus_remove_driver(drv);
    return ret;
    }
    EXPORT_SYMBOL_GPL(driver_register);

    int bus_add_driver(struct device_driver *drv)
    {
    struct bus_type *bus;
    struct driver_private *priv;
    int error = 0;
    bus = bus_get(drv->bus);
    if (!bus)
    return -EINVAL;
    pr_debug("bus: '%s': add driver %s ", bus->name, drv->name);
    priv = kzalloc(sizeof(*priv), GFP_KERNEL);
    if (!priv) {
    error = -ENOMEM;
    goto out_put_bus;
    }
    klist_init(&priv->klist_devices, NULL, NULL);
    priv->driver = drv;
    drv->p = priv;
    priv->kobj.kset = bus->p->drivers_kset;
    error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
        "%s", drv->name);
    if (error)
    goto out_unregister;

    if (drv->bus->p->drivers_autoprobe) {
    error = driver_attach(drv); // 遍历  i2c_bus_type->p->klist_devices 链表上的 device ,查看是否可以找到和 i2c_driver->id_table->name 相同的 i2c_client->name 。有,则i2c_driver->probe()。


    if (error)
    goto out_unregister;
    }
    klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); //将 struct i2c_driver 的 struct device_driver* 成员挂接到 i2c_bus_type->p->klist_drivers 上。
    module_add_driver(drv->owner, drv);
    error = driver_create_file(drv, &driver_attr_uevent);
    if (error) {
    printk(KERN_ERR "%s: uevent attr (%s) failed ",
    __func__, drv->name);
    }
    error = driver_add_attrs(bus, drv);
    if (error) {
    /* How the hell do we get out of this pickle? Give up */
    printk(KERN_ERR "%s: driver_add_attrs(%s) failed ",
    __func__, drv->name);
    }
    if (!drv->suppress_bind_attrs) {
    error = add_bind_files(drv);
    if (error) {
    /* Ditto */
    printk(KERN_ERR "%s: add_bind_files(%s) failed ",
    __func__, drv->name);
    }
    }
    kobject_uevent(&priv->kobj, KOBJ_ADD);
    return 0;
    out_unregister:
    kobject_put(&priv->kobj);
    kfree(drv->p);
    drv->p = NULL;
    out_put_bus:
    bus_put(bus);
    return error;
    }

    int driver_attach(struct device_driver *drv)
    {
    return bus_for_each_dev(drv->bus, NULL, drv,__driver_attach); //遍历 i2c_bus_type->p->devices 链表上的 struct device,并以此获得 i2c_client,作为 //__driver_attach() 的参数
    }

    static int __driver_attach(struct device *dev, void *data)
    {
    struct device_driver *drv = data;
    /*
    * Lock device and try to bind to it. We drop the error
    * here and always return 0, because we need to keep trying
    * to bind to devices and some drivers will return an error
    * simply if it didn't support the device.
    *
    * driver_probe_device() will spit a warning if there
    * is an error.
    */
    if (!driver_match_device(drv, dev))
    return 0;
    if (dev->parent)/* Needed for USB */
    device_lock(dev->parent);
    device_lock(dev);
    if (!dev->driver)
    driver_probe_device(drv, dev);
    device_unlock(dev);
    if (dev->parent)
    device_unlock(dev->parent);
    return 0;
    }

    static inline int driver_match_device(struct device_driver *drv,
         struct device *dev)
    {
    return drv->bus->match ? drv->bus->match(dev, drv) : 1; // i2c_device_match()->i2c_match_id()
    }

    static int i2c_device_match(struct device *dev, struct device_driver *drv)
    {
    struct i2c_client*client = i2c_verify_client(dev);
    struct i2c_driver*driver;
    if (!client)
    return 0;
    /* Attempt an OF style match */
    if (of_driver_match_device(dev, drv))
    return 1;
    driver = to_i2c_driver(drv);
    /* match on an id table if there is one */
    if (driver->id_table)
    return i2c_match_id(driver->id_table,client) != NULL;
    printk("[i2c-core][i2c_device_match] end ");
    return 0;
    }

    static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
    const struct i2c_client *client)
    {
    while (id->name[0]) {
    if (strcmp(client->name, id->name) == 0)
    return id;
    id++;
    }
    return NULL;
    }

    int driver_probe_device(struct device_driver *drv, struct device *dev)
    {
    int ret = 0;
    if (!device_is_registered(dev))
    return -ENODEV;
    pr_debug("bus: '%s': %s: matched device %s with driver %s ",
    drv->bus->name, __func__, dev_name(dev), drv->name);
    pm_runtime_get_noresume(dev);
    pm_runtime_barrier(dev);
    ret = really_probe(dev, drv);
    pm_runtime_put_sync(dev);
    return ret;
    }

    static int really_probe(struct device *dev, struct device_driver *drv)
    {
    int ret = 0;
    atomic_inc(&probe_count);
    pr_debug("bus: '%s': %s: probing driver %s with device %s ",
    drv->bus->name, __func__, drv->name, dev_name(dev));
    WARN_ON(!list_empty(&dev->devres_head));
    dev->driver = drv;
    if (driver_sysfs_add(dev)) {
    printk(KERN_ERR "%s: driver_sysfs_add(%s) failed ",
    __func__, dev_name(dev));
    goto probe_failed;
    }
    if (dev->bus->probe) {
    ret = dev->bus->probe(dev); // i2c_device_probe()->i2c_driver->probe()
    if (ret)
    goto probe_failed;
    } else if (drv->probe) {
    ret = drv->probe(dev);
    if (ret)
    goto probe_failed;
    }
    driver_bound(dev);
    ret = 1;
    pr_debug("bus: '%s': %s: bound device %s to driver %s ",
    drv->bus->name, __func__, dev_name(dev), drv->name);
    goto done;

    probe_failed:
    。。。。。。。。。。。。。。
    }

    static int i2c_device_probe(struct device *dev)
    {
    struct i2c_client*client = i2c_verify_client(dev);
    struct i2c_driver*driver;
    int status;
    if (!client)
    return 0;
    driver = to_i2c_driver(dev->driver);
    if (!driver->probe || !driver->id_table)
    return -ENODEV;
    client->driver = driver;
    if (!device_can_wakeup(&client->dev))
    device_init_wakeup(&client->dev,
    client->flags & I2C_CLIENT_WAKE);
    dev_dbg(dev, "probe ");
    printk("[i2c-core][i2c_device_probe] ");

    status = driver->probe(client,i2c_match_id(driver->id_table,client));
    if (status) {
    client->driver = NULL;
    i2c_set_clientdata(client, NULL);
    }
    return status;
    }

    硬件i2c控制器模块加载,共有3个;通过 module_init() 加载,顺序为6,所以 i2c_board_info 应该在这之前注册。

    加载时会初始化硬件,初始化完成后才能进行 i2c_driver 的注册,否则在 i2c_driver->probe() 时进行 i2c 通信会失败。

    static struct platform_device mt_device_i2c[] = {
        {
            .name           = "mt-i2c",
            .id             = 0,
            .num_resources  = ARRAY_SIZE(mt_resource_i2c0),
            .resource       = mt_resource_i2c0,
        },
        {
            .name           = "mt-i2c",
            .id             = 1,
            .num_resources  = ARRAY_SIZE(mt_resource_i2c1),
            .resource       = mt_resource_i2c1,
        },
      {
            .name           = "mt-i2c",
            .id             = 2,
            .num_resources  = ARRAY_SIZE(mt_resource_i2c2),
            .resource       = mt_resource_i2c2,
        },
       
    };

    __init int mt_board_init(void)
    {

    for (i = 0; i < ARRAY_SIZE(mt_device_i2c); i++){
    retval = platform_device_register(&mt_device_i2c[i]);
    if (retval != 0){
    return retval;
    }
    }

    。。。。。。。。。

    }

    static U32 mt_i2c_functionality(struct i2c_adapter *adap)
    {
      return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
    }
    static struct i2c_algorithm mt_i2c_algorithm = {
      .master_xfer   = mt_i2c_transfer,
      .smbus_xfer    = NULL,
      .functionality = mt_i2c_functionality,
    };
    static inline void mt_i2c_init_hw(mt_i2c *i2c)
    {
      i2c_writel(i2c,OFFSET_SOFTRESET, 0x0001);
      i2c_writel(i2c,OFFSET_DCM_EN, 0x0);
    }

    static S32 mt_i2c_probe(struct platform_device *pdev)
    {
      S32 ret, irq;
      mt_i2c *i2c = NULL;
      struct resource *res;
      /* Request platform_device IO resource*/
      res   = platform_get_resource(pdev, IORESOURCE_MEM, 0);
      irq   = platform_get_irq(pdev, 0);
      if (res == NULL || irq < 0)
           return -ENODEV;
      /* Request IO memory */
      if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
        return -ENOMEM;
      }
      if (NULL == (i2c = kzalloc(sizeof(mt_i2c), GFP_KERNEL)))
        return -ENOMEM;
      /* initialize mt_i2c structure */
      i2c->id   = pdev->id;
      i2c->base = IO_PHYS_TO_VIRT(res->start);
      //i2c->base = 0x11011000;
      i2c->irqnr  = irq;
      #if (defined(CONFIG_MT_I2C_FPGA_ENABLE))
        i2c->clk  = I2C_CLK_RATE;
      #else
        i2c->clk  = mt_get_bus_freq();// is not ready
        switch(i2c->id){
          case 0:
            i2c->pdn = MT_CG_PERI_I2C0;
            break;
          case 1:
            i2c->pdn = MT_CG_PERI_I2C1;
            break;
          case 2:
            i2c->pdn = MT_CG_PERI_I2C2;
            break;
          default:
            dev_err(&pdev->dev, "Error id %d ", i2c->id);
            break;
        }
      #endif
      i2c->dev  = &i2c->adap.dev;
      i2c->adap.dev.parent  = &pdev->dev;
      i2c->adap.nr      = i2c->id;
      i2c->adap.owner     = THIS_MODULE;
      i2c->adap.algo      = &mt_i2c_algorithm; // i2c通信算法的具体实现
      i2c->adap.algo_data   = NULL;
      i2c->adap.timeout   = 2 * HZ; /*2s*/
      i2c->adap.retries   = 1; /*DO NOT TRY*/

      snprintf(i2c->adap.name, sizeof(i2c->adap.name), I2C_DRV_NAME);
      i2c->pdmabase = AP_DMA_BASE + 0x200 + (0x80*(i2c->id));
      spin_lock_init(&i2c->lock);
      init_waitqueue_head(&i2c->wait);

      ret = request_irq(irq, mt_i2c_irq, IRQF_TRIGGER_LOW, I2C_DRV_NAME, i2c);
      if (ret){
        dev_err(&pdev->dev, "Can Not request I2C IRQ %d ", irq);
        goto free;
      }
      mt_i2c_init_hw(i2c); // 硬件i2c控制器的初始化
      i2c_set_adapdata(&i2c->adap, i2c);
      ret = i2c_add_numbered_adapter(&i2c->adap); // 遍历 __i2c_board_list 链表,生成 i2c_client ,并且挂接到 i2c_bus_type->p->klist_devices 上。
      if (ret){
        dev_err(&pdev->dev, "failed to add i2c bus to i2c core ");
        goto free;
      }
      platform_set_drvdata(pdev, i2c);
    #ifdef I2C_DEBUG_FS
      ret = device_create_file(i2c->dev, &dev_attr_debug);
      if ( ret ){
        /*Do nothing*/
      }
    #endif
      printk("[i2c][mt_i2c_probe] i2c->adap.nr:%d ", i2c->adap.nr);
      return ret;
    free:
      mt_i2c_free(i2c);
      return ret;
    }

    static struct platform_driver mt_i2c_driver = {
      .probe   = mt_i2c_probe,
      .remove  = mt_i2c_remove,
      .suspend = mt_i2c_suspend,
      .resume  = mt_i2c_resume,
      .driver  = {
            .name  = I2C_DRV_NAME,
            .owner = THIS_MODULE,
        },
    };
    static S32 __init mt_i2c_init(void)
    {
      return platform_driver_register(&mt_i2c_driver);
    }
    static void __exit mt_i2c_exit(void)
    {
      platform_driver_unregister(&mt_i2c_driver);
    }
    module_init(mt_i2c_init); 
    module_exit(mt_i2c_exit);

  • 相关阅读:
    js获取下拉框的值
    根据SNP的位置从基因组提取上下游序列
    PCA分析的疑问
    os删除文件或者文件夹
    python scipy包进行GO富集分析p值计算
    生物信息等级的划分
    docker笔记
    GATK4注意事项
    centos7修改yum源为阿里镜像
    idea如何通过数据库生成实体类
  • 原文地址:https://www.cnblogs.com/AlwaysOnLines/p/3832245.html
Copyright © 2020-2023  润新知