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!\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_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\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_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\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);

i2c sub system __i2c_board_list/klist_devices/klist_drivers的更多相关文章

  1. linux下i2c驱动笔记 转

    1. 几个基本概念 1.1. 设备模型 由 总线(bus_type) + 设备(device) + 驱动(device_driver) 组成,在该模型下,所有的设备通过总线连接起来,即使有些设备没有连 ...

  2. 最新内核3.4)Linux 设备树加载I2C client adapter 的流程(内核3.4 高通)【转】

    转自:https://blog.csdn.net/lsn946803746/article/details/52515225 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转 ...

  3. Linux内核中SPI/I2c子系统剖析

    Linux内核中,SPI和I2C两个子系统的软件架构是一致的,且Linux内核的驱动模型都以bus,driver,device三种抽象对象为基本元素构建起来.下文的分析将主要用这三种抽象对象的创建过程 ...

  4. 在android下使用i2c tools

    在android使用i2c tools访问i2c,很方便,可以在https://launchpad.net/ubuntu/+source/i2c-tools 下载最新的i2c tools. 把i2c- ...

  5. 【.NET 与树莓派】气压传感器——BMP180

    BMP180 是一款数字气压计传感器,实际可读出温度和气压值.此模块使用 IIC(i2c)协议.模块体积很小,比老周的大拇指指甲还小:也很便宜,一般是长这样的.螺丝孔只开一个,也有开两个孔的. 这货基 ...

  6. am335x system upgrade kernel i2c rtc eeprom(六)

    1      Scope of Document This document describes i2c bus hardware design and support i2c-devices: ee ...

  7. I.MX6 Linux I2C device& driver hacking

    /******************************************************************************************* * I.MX6 ...

  8. i2c驱动程序全面分析,从adapter驱动程序到设备驱动程序

    开发板    :mini2440 内核版本:linux2.6.32.2 驱动程序参考:韦东山老师毕业班i2c 内容概括: 1.adapter client 简介    2.adapter 驱动框架   ...

  9. I2C总线、设备、驱动

    I2C总线.设备.驱动 框架 I2C驱动框架可分为3个部分,分别是:I2C核心层.I2C总线驱动层(适配器层)以及I2C设备驱动层: I2C核心层 提供了统一的I2C操作函数,主要有两套函数smbus ...

随机推荐

  1. 搭建maven项目简介

    http://jingyan.baidu.com/album/9f7e7ec0b714ae6f29155465.html?picindex=1 Maven学习 (一) 搭建Maven环境 http:/ ...

  2. 静默安装ORACLE【weber出品必属精品】

    安装配置系统环境安装linux ,所有服务都不选择,只是选择安装开发工具,不要安装防火墙(当然也可以在后面关闭) 打开终端,执行如下命令,检查安装包,没有的都要安装 make, glibc, liba ...

  3. xib添加手势后报错:-[UITapGestureRecognizer setFrame:]: unrecognized selector sent to instance xxx

    主要原因如下: + (instancetype)mineHeaderView { return [[NSBundle mainBundle] loadNibNamed:@"DDMineHea ...

  4. JS中window.showModalDialog()详解 HTML DOM open() 方法

    window.showModalDialog()方法用来创建一个显示HTML内容的模态对话框. window.showModelessDialog()方法用来创建一个显示HTML内容的非模态对话框.  ...

  5. MySQL FROM 子查询

    FROM 子句中的子查询 MySQL FROM 子查询是指 FROM 的子句作为子查询语句,主查询再到子查询结果中获取需要的数据.FROM 子查询语法如下: SELECT ... FROM (subq ...

  6. 使用 pm2 来守护 NoderCMS

    pm2 是一个带有负载均衡功能的Node应用的进程管理器,使用 pm2 可以帮助你守护和监控 NoderCMS 的正常运行,   基于Node.js+MongoDB的轻量级内容管理系统NoderCMS ...

  7. 1.3.1 switch 语句中的 String

    switch语句是一种高效的多路语句,可以省掉很多繁杂的嵌套if判断: 在Java 6及之前,case语句中的常量只能是byte.char.short和int(也可以是对应的封装类)或枚举常量,在Ja ...

  8. 无缝滚动js (手写通俗易懂)

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  9. setTintColor

    [self.button:[UIColor whiteColor]]; 初步研究   这个是决定的  btn的   外边框的颜色

  10. HADOOP在处理HIVE时权限错误的解决办法

    今天,小乔操作时发现问题: org.apache.hadoop.security.AccessControlException: Permission denied: user=root, acces ...