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_typestruct 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!\n");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\n");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\n");/* 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] == '\0')) { pr_err("i2c-core: Attempt to register an adapter with " "no name!\n");return -EINVAL;}if (unlikely(!adap->algo)) { pr_err("i2c-core: Attempt to register adapter '%s' with " "no algo!\n", 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\n", adap->name);#ifdef CONFIG_I2C_COMPATres = 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\n");#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\n");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]\n");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\n",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_clientif (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\n",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\n",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\n", 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\n", 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\n",driver->driver.name);if (driver->resume)pr_warn("i2c-core: driver [%s] using legacy resume method\n",driver->driver.name);pr_debug("i2c-core: driver [%s] registered\n", 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 \n",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\n", drv->name);other =driver_find(drv->name, drv->bus); //查看此i2c_driver是否已经注册过if (other) { printk(KERN_ERR "Error: Driver '%s' is already registered, ""aborting...\n", 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\n", 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\n",__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\n",__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\n",__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\n");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\n",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\n",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\n",__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\n",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\n");printk("[i2c-core][i2c_device_probe] \n");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\n", 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\n", 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\n"); 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 \n", 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);