// kernel/drivers/i2c/busses/i2c-sc8810.c
/* sc8810_i2c_probe
*
* called by the bus driver when a suitabledevice is found
*/
static int sc8810_i2c_probe(struct platform_device *pdev)
{
struct sc8810_i2c *i2c;
struct resource *res;
int irq;
int ret;
unsigned int tmp;
i2c = kzalloc(sizeof(struct sc8810_i2c),GFP_KERNEL);
if (!i2c){
printk("I2C:kzallocfailed!\n");
return -ENOMEM;
}
res = platform_get_resource(pdev,IORESOURCE_MEM, 0);
printk("I2C:res->start=%x\n", res->start);
irq = platform_get_irq(pdev, 0);
printk("I2C: irq=%d\n", irq);
if (res == NULL || irq < 0){
printk("I2C:platform_get_resource&irqfailed!\n");
ret=-ENODEV;
goto err_irq;
}
#if 0
if (!request_mem_region(res->start,res_len(res), res->name)){
printk("I2C:request_mem_regionfailed!\n");
ret=-ENOMEM;
goto err_irq;
}
#endif
i2c->membase=res->start;//ioremap(res->start, resource_size(res));
if (!i2c->membase) {
printk("I2C:ioremapfailed!\n");
ret=-EIO;
goto err_irq;
}
i2c->irq = irq;
spin_lock_init(&i2c->lock);
init_waitqueue_head(&i2c->wait);
snprintf(i2c->adap.name,sizeof(i2c->adap.name),"%s","sc8810-i2c");
i2c->adap.owner = THIS_MODULE;
i2c->adap.retries = 4;
//这一步对i2c的读写很重要,将会在以后的i2c数据结构中详细说明
i2c->adap.algo = &sc8810_i2c_algorithm;
i2c->adap.algo_data = i2c;
i2c->adap.dev.parent =&pdev->dev;
/* initialize the i2c controller */
sc8810_i2c_init(i2c);
ret = request_irq(i2c->irq,sc8810_i2c_irq, IRQF_SHARED,pdev->name,i2c);
if (ret) {
printk("I2C:request_irqfailed!\n");
goto err_irq;
}
// adap.nr就是每个platform_device对应的总线号,这在以后会经常用到
i2c->adap.nr = pdev->id;
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0){
printk("I2C:add_adapterfailed!\n");
goto err_adap;
}
sc8810_i2c_ctl[pdev->id] = i2c;
printk("I2C:sc8810_i2c_ctl[%d]=%x",pdev->id,sc8810_i2c_ctl[pdev->id]);
platform_set_drvdata(pdev, i2c);
i2c_create_sysfs(pdev);
return 0;
err_adap:
free_irq(i2c->irq,i2c);
err_irq:
kfree(i2c);
return ret;
}
/**
* i2c_add_numbered_adapter - declare i2cadapter, use static bus number
* @adap: the adapter to register (withadap->nr initialized)
* Context: can sleep
*
* This routine is used to declare an I2Cadapter when its bus number
* matters. For example, use it for I2C adapters from system-on-chip CPUs,
* or otherwise built in to the system'smainboard, and where i2c_board_info
* is used to properly configure I2C devices.
*
* If no devices have pre-been declared forthis bus, then be sure to
* register the adapter before any dynamicallyallocated ones. Otherwise
* the required bus ID may not be available.
*
* When this returns zero, the specifiedadapter became available for
* clients using the bus number provided inadap->nr. Also, the table
* of I2C devices pre-declared usingi2c_register_board_info() is scanned,
* and the appropriate driver model devicenodes are created. Otherwise, a
* negative errno value is returned.
*/
// kernel/drivers/i2c/i2c-core.c
inti2c_add_numbered_adapter(structi2c_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;
}
// kernel/drivers/i2c/i2c-core.c
static int i2c_register_adapter(struct i2c_adapter *adap)
{
int res = 0, dummy;
/* Can't register until after drivermodel init */
if (unlikely(WARN_ON(!i2c_bus_type.p))) {
res = -EAGAIN;
goto out_list;
}
rt_mutex_init(&adap->bus_lock);
INIT_LIST_HEAD(&adap->userspace_clients);
/* Set default timeout to 1 second if notalready set */
if (adap->timeout == 0)
adap->timeout = HZ;
//i2c_adapter的名字,分别为:i2c-0、i2c-1、i2c-2、i2c-3
dev_set_name(&adap->dev,"i2c-%d", adap->nr);
adap->dev.bus = &i2c_bus_type;
adap->dev.type =&i2c_adapter_type;
//注册i2c_adapter,文件节点在sys/devices/platform/sc8810-i2c.ID/i2c-ID
res = device_register(&adap->dev);
if (res)
goto out_list;
dev_dbg(&adap->dev, "adapter[%s] registered\n", adap->name);
#ifdefCONFIG_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 classlink\n");
#endif
/* create pre-declared device nodes */
//在“一”中的i2c_register_board_info()函数中可知,__i2c_first_dynamic_bus_num的值为3。因此只会创建挂在i2c-0、i2c-1、i2c-2上的client。I2c-3不会进入此函数
if (adap->nr <__i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
/* Notify drivers */
mutex_lock(&core_lock);
dummy =bus_for_each_drv(&i2c_bus_type, NULL, adap,
__process_new_adapter);
mutex_unlock(&core_lock);
return 0;
out_list:
mutex_lock(&core_lock);
idr_remove(&i2c_adapter_idr,adap->nr);
mutex_unlock(&core_lock);
return res;
}
// kernel/drivers/i2c/i2c-core.c
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
struct i2c_devinfo *devinfo;
down_read(&__i2c_board_lock);
list_for_each_entry(devinfo,&__i2c_board_list, list) {
//遍历全局__i2c_board_list链表,分别为挂在i2c-0、i2c-1、i2c-2下的设备创建i2c_client。
if (devinfo->busnum== adapter->nr && !i2c_new_device(adapter, &devinfo->board_info))
dev_err(&adapter->dev,
"Can't createdevice at 0x%02x\n",
devinfo->board_info.addr);
}
up_read(&__i2c_board_lock);
}
/**
* i2c_new_device - instantiate an i2c device
* @adap: the adapter managing the device
* @info: describes one I2C device; bus_num isignored
* Context: can sleep
*
* Create an i2c device. Binding is handledthrough driver model
* probe()/remove() methods. A driver may be bound to this device when we
* return from this function, or any latermoment (e.g. maybe hotplugging will
* load the driver module). This call is not appropriate for use bymainboard
* initialization logic, which usually runsduring an arch_initcall() long
* before any i2c_adapter could exist.
*
* This returns the new i2c client, which maybe saved for later use with
* i2c_unregister_device(); or NULL to indicatean error.
*/
//i2c 动态注册直接调用该函数,把相应的i2c_adapter和i2c_board_info传进去
// kernel/drivers/i2c/i2c-core.c
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;
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;
status = 0;
}
/* Check for address business */
//防止同一条 i2c总线上出现多个地址相同的 I2C设备
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;
#ifdef CONFIG_OF
client->dev.of_node =info->of_node;
#endif
//i2c_client的命名规范
dev_set_name(&client->dev,"%d-%04x", i2c_adapter_id(adap), client->addr);
//将设备client->dev注册进内核,文件节点在sys/devices/platform/sc8810-i2c.ID /i2c-ID/ID-ADDR(%04x)
status = device_register(&client->dev);
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:
dev_err(&adap->dev, "Failedto register i2c client %s at 0x%02x "
"(%d)\n",client->name, client->addr, status);
out_err_silent:
kfree(client);
return NULL;
}
/**
* device_register - register a device with thesystem.
* @dev: pointer to the device structure
*
* This happens in two clean steps - initializethe device
* and add it to the system. The two steps canbe called
* separately, but this is the easiest and mostcommon.
* I.e. you should only call the two helpersseparately if
* have a clearly defined need to use andrefcount the device
* before it is added to the hierarchy.
* NOTE: _Never_ directly free @dev aftercalling this function, even
* if it returned an error! Always useput_device() to give up the
* reference initialized in this function instead.
*/
// kernel/drivers/base/core.c
int device_register(struct device *dev)
{
device_initialize(dev);
return device_add(dev);
}
/**
* device_add - add device to device hierarchy.
* @dev: device.
*
* This is part 2 of device_register(), though maybe called
* separately _iff_ device_initialize() hasbeen called separately.
*
* This adds @dev to the kobject hierarchy viakobject_add(), adds it
* to the global and sibling lists for thedevice, then
* adds it to the other relevant subsystems ofthe driver model.
*
* NOTE: _Never_ directly free @dev aftercalling this function, even
* if it returned an error! Always useput_device() to give up your
* reference instead.
*/
// kernel/drivers/base/core.c
int device_add(struct device *dev)
{
struct device *parent = NULL;
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;
}
if (!dev_name(dev)) {
error = -EINVAL;
goto name_error;
}
pr_debug("device: '%s': %s\n",dev_name(dev), __func__);
parent = get_device(dev->parent);
setup_parent(dev, parent);
/* 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 deviceaddition. This call must come
*after dpm_sysf_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);
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);
if (dev->class) {
mutex_lock(&dev->class->p->class_mutex);
/* tie the class to the device */
klist_add_tail(&dev->knode_class,
&dev->class->p->class_devices);
/* notify any interfaces that thedevice is here */
list_for_each_entry(class_intf,
&dev->class->p->class_interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev,class_intf);
mutex_unlock(&dev->class->p->class_mutex);
}
done:
put_device(dev);
return error;
DPMError:
bus_remove_device(dev);
BusError:
device_remove_attrs(dev);
AttrsError:
device_remove_class_symlinks(dev);
SymlinkError:
if (MAJOR(dev->devt))
devtmpfs_delete_node(dev);
if (MAJOR(dev->devt))
device_remove_sys_dev_entry(dev);
devtattrError:
if (MAJOR(dev->devt))
device_remove_file(dev,&devt_attr);
ueventattrError:
device_remove_file(dev,&uevent_attr);
attrError:
kobject_uevent(&dev->kobj,KOBJ_REMOVE);
kobject_del(&dev->kobj);
Error:
cleanup_device_parent(dev);
if (parent)
put_device(parent);
name_error:
kfree(dev->p);
dev->p = NULL;
goto done;
}