include/linux/i2c.h

struct i2c_msg;
struct i2c_algorithm;
struct i2c_adapter;
struct i2c_client;
struct i2c_driver;
union i2c_smbus_data;

I2C驱动主要包含三部分:I2C核心、I2C总线驱动、I2C设备驱动,它们主要的数据结构在目录:/include/linux/i2c.h

  struct i2c_driver

1 /*
2 * A driver is capable of handling one or more physical devices present on3 * I2C adapters. This information is used to inform the driver of adapter4 * events.5 *6 * The driver.owner field should be set to the module owner of this driver.7 * The driver.name field should be set to the name of this driver.8  */
9 structi2c_driver {10     intid;11     unsigned int class;12
13     /*Notifies the driver that a new bus has appeared. This routine14 * can be used by the driver to test if the bus meets its conditions15 * & seek for the presence of the chip(s) it supports. If found, it16 * registers the client(s) that are on the bus to the i2c admin. via17 * i2c_attach_client.  (LEGACY I2C DRIVERS ONLY)18      */
19     int (*attach_adapter)(struct i2c_adapter *);20     int (*detach_adapter)(struct i2c_adapter *);21
22     /*tells the driver that a client is about to be deleted & gives it23 * the chance to remove its private data. Also, if the client struct24 * has been dynamically allocated by the driver in the function above,25 * it must be freed here.  (LEGACY I2C DRIVERS ONLY)26      */
27     int (*detach_client)(struct i2c_client *);28
29     /*Standard driver model interfaces, for "new style" i2c drivers.30 * With the driver model, device enumeration is NEVER done by drivers;31 * it's done by infrastructure.  (NEW STYLE DRIVERS ONLY)32      */
33     int (*probe)(struct i2c_client *);34     int (*remove)(struct i2c_client *);35
36     /*driver model interfaces that don't relate to enumeration*/
37     void (*shutdown)(struct i2c_client *);38     int (*suspend)(struct i2c_client *, pm_message_t mesg);39     int (*resume)(struct i2c_client *);40
41     /*a ioctl like command that can be used to perform specific functions42 * with the device.43      */
44     int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);45
46     structdevice_driver driver;47     structlist_head list;48 };

  struct i2c_client

1 /**2 * struct i2c_client - represent an I2C slave device3 * @addr: Address used on the I2C bus connected to the parent adapter.4 * @name: Indicates the type of the device, usually a chip name that's5 *    generic enough to hide second-sourcing and compatible revisions.6 * @dev: Driver model device node for the slave.7 * @driver_name: Identifies new-style driver used with this device; also8 *    used as the module name for hotplug/coldplug modprobe support.9 *10 * An i2c_client identifies a single device (i.e. chip) connected to an11 * i2c bus. The behaviour is defined by the routines of the driver.12  */
13 structi2c_client {14     unsigned short flags;        /*div., see below*/
15     unsigned short addr;        /*chip address - NOTE: 7bit*/
16                     /*addresses are stored in the*/
17                     /*_LOWER_ 7 bits*/
18     charname[I2C_NAME_SIZE];19     struct i2c_adapter *adapter;    /*the adapter we sit on*/
20     struct i2c_driver *driver;    /*and our access routines*/
21     int usage_count;        /*How many accesses currently*/
22                     /*to the client*/
23     struct device dev;        /*the device structure*/
24     int irq;            /*irq issued by device (or -1)*/
25     chardriver_name[KOBJ_NAME_LEN];26     structlist_head list;27     structcompletion released;28 };

  struct i2c_algorithm

1 /*
2 * The following structs are for those who like to implement new bus drivers:3 * i2c_algorithm is the interface to a class of hardware solutions which can4 * be addressed using the same bus algorithms - i.e. bit-banging or the PCF85845 * to name two of the most common.6  */
7 structi2c_algorithm {8     /*If an adapter algorithm can't do I2C-level access, set master_xfer9 to NULL. If an adapter algorithm can do SMBus access, set10 smbus_xfer. If set to NULL, the SMBus protocol is simulated11 using common I2C messages*/
12     /*master_xfer should return the number of messages successfully13 processed, or a negative value on error*/
14     int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs,15                        intnum);16     int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,17                        unsigned short flags, charread_write,18                        u8 command, int size, union i2c_smbus_data *data);19
20     /*--- ioctl like call to set div. parameters.*/
21     int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long);22
23     /*To determine what the adapter supports*/
24     u32 (*functionality) (struct i2c_adapter *);25 };

  struct i2c_adapter

  

1 /*
2 * i2c_adapter is the structure used to identify a physical i2c bus along3 * with the access algorithms necessary to access it.4  */
5 structi2c_adapter {6     struct module *owner;7     unsigned intid;8     unsigned int class;9     const struct i2c_algorithm *algo; /*the algorithm to access the bus*/
10     void *algo_data;11
12     /*--- administration stuff.*/
13     int (*client_register)(struct i2c_client *);14     int (*client_unregister)(struct i2c_client *);15
16     /*data fields that are valid for all devices*/
17     u8 level;             /*nesting level for lockdep*/
18     structmutex bus_lock;19     structmutex clist_lock;20
21     inttimeout;22     intretries;23     struct device dev;        /*the adapter device*/
24
25     intnr;26     structlist_head clients;27     structlist_head list;28     char name[48];29     structcompletion dev_released;30 }

I2C核心

  I2C核心提供了I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法(algorithm)上层的与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。

I2C总线驱动

  I2C总线驱动是对I2C硬件体系结构中适配器段端的实现,适配器可由CPU控制,甚至可以直接集成在CPU内部。I2C总线驱动主要包括I2C适配器数据结构i2c_adapter、I2C适配器的Algorithm数据结构i2c_algorithm和控制I2C适配器产生通信信号的函数。经由I2C总线驱动的代码,我们可以控制I2C适配器以主控方式产生开始位、停止位、读写周期,以及从设备方式读写、产生ACK等。

I2C设备驱动

I2C设备驱动即客户驱动时对I2C硬件体系结构中设备端的实现,设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。I2C设备驱动主要包含数据结构i2c_driver和i2c_client,我们需要具体设备实现其中的成员函数。

  在linux2.6内核中,所有设备都在sysfs文件系统中显示,在sysfs虚拟文件系统中存放了驱动挂载的总线以及device、driver,当我们注册一个driver后,内核会将我们注册的这个driver添加到这类驱动总线上这类总线的拥有一个共同的类似于一个基类kobject,而kset就是koject的一个集合。我们在写驱动的时候一般不会去分析kobject、kset,毕竟他们在内核里面是非常顶层的软件抽象层,但是对于内核整个驱动框架,却不能不分析这类抽象层,下图是我在树莓派所做的截图:

  我们可以看到在sys文件目录下面有bus、class等,进入bus后会看到各种设备驱动,如在I2C中我们可以看到device、drivers,当然这些目录下面都没有什么内容应为sysfs是一个虚拟文件系统主要是记录各个进程和内核方面的信息。我们的驱动设备如何和虚拟文件系统产生关系了呢,就是kobject在这儿起了作用,我们的device、driver最终都会挂载一个总线上,后面我们会看到sysfs申请内存为device或者driver建立节点。

  同样注册一个device后也会挂载在总线上。其实I2C我们也可以看成设备-总线-驱动模型,

  i2c_register_driver(THIS_MODULE, driver)

1 /*
2 * An i2c_driver is used with one or more i2c_client (device) nodes to access3 * i2c slave chips, on a bus instance associated with some i2c_adapter.  There4 * are two models for binding the driver to its device:  "new style" drivers5 * follow the standard Linux driver model and just respond to probe() calls6 * issued if the driver core sees they match(); "legacy" drivers create device7 * nodes themselves.8  */
9
10 int i2c_register_driver(struct module *owner, struct i2c_driver *driver)11 {12     intres;13
14     /*new style driver methods can't mix with legacy ones*/
15     if(is_newstyle_driver(driver)) {16         if (driver->attach_adapter || driver->detach_adapter17                 || driver->detach_client) {18 printk(KERN_WARNING19                     "i2c-core: driver [%s] is confused\n",20                     driver->driver.name);21             return -EINVAL;22 }23 }24
25     /*add the driver to the list of i2c drivers in the driver core*/
26     driver->driver.owner =owner;27     driver->driver.bus = &i2c_bus_type;28
29     /*for new style drivers, when registration returns the driver core30 * will have called probe() for all matching-but-unbound devices.31      */
32     res = driver_register(&driver->driver);33     if(res)34         returnres;35
36     mutex_lock(&core_lists);37
38     list_add_tail(&driver->list,&drivers);39     pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);40
41     /*legacy drivers scan i2c busses directly*/
42     if (driver->attach_adapter) {43         struct i2c_adapter *adapter;44
45         list_for_each_entry(adapter, &adapters, list) {46             driver->attach_adapter(adapter);47 }48 }49
50     mutex_unlock(&core_lists);51     return 0;52 }

  driver_register(&driver->driver);

  

1 /**2 *    driver_register - register driver with bus3 *    @drv:    driver to register4 *5 *    We pass off most of the work to the bus_add_driver() call,6 *    since most of the things we have to do deal with the bus7 *    structures.8  */
9 int driver_register(struct device_driver *drv)10 {11     if ((drv->bus->probe && drv->probe) ||
12         (drv->bus->remove && drv->remove) ||
13         (drv->bus->shutdown && drv->shutdown)) {14         printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);15 }16     klist_init(&drv->klist_devices, NULL, NULL);17     returnbus_add_driver(drv);18 }

  klist_init(&drv->klist_devices, NULL, NULL);

  

1 /**2 *    driver_register - register driver with bus3 *    @drv:    driver to register4 *5 *    We pass off most of the work to the bus_add_driver() call,6 *    since most of the things we have to do deal with the bus7 *    structures.8  */
9 int driver_register(struct device_driver *drv)10 {11     if ((drv->bus->probe && drv->probe) ||
12         (drv->bus->remove && drv->remove) ||
13         (drv->bus->shutdown && drv->shutdown)) {14         printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);15 }16     klist_init(&drv->klist_devices, NULL, NULL);17     returnbus_add_driver(drv);18 }

  bus_add_driver(drv);
1 /**2 *    bus_add_driver - Add a driver to the bus.3 *    @drv:    driver.4 *5  */
6 int bus_add_driver(struct device_driver *drv)7 {8     struct bus_type * bus = get_bus(drv->bus);9     int error = 0;10
11     if (!bus)12         return -EINVAL;13
14     pr_debug("bus %s: add driver %s\n", bus->name, drv->name);15     error = kobject_set_name(&drv->kobj, "%s", drv->name);16     if(error)17         gotoout_put_bus;18     drv->kobj.kset = &bus->drivers;19     if ((error = kobject_register(&drv->kobj)))20         gotoout_put_bus;21
22     if (drv->bus->drivers_autoprobe) {23         error =driver_attach(drv);24         if(error)25             gotoout_unregister;26 }27     klist_add_tail(&drv->knode_bus, &bus->klist_drivers);28     module_add_driver(drv->owner, drv);29
30     error =driver_add_attrs(bus, drv);31     if(error) {32         /*How the hell do we get out of this pickle? Give up*/
33         printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",34             __FUNCTION__, drv->name);35 }36     error =add_bind_files(drv);37     if(error) {38         /*Ditto*/
39         printk(KERN_ERR "%s: add_bind_files(%s) failed\n",40             __FUNCTION__, drv->name);41 }42
43     returnerror;44 out_unregister:45     kobject_unregister(&drv->kobj);46 out_put_bus:47 put_bus(bus);48     returnerror;49 }

  kobject_register(&drv->kobj)

1 /**2 *    kobject_register - initialize and add an object.3 *    @kobj:    object in question.4  */
5
6 int kobject_register(struct kobject *kobj)7 {8     int error = -EINVAL;9     if(kobj) {10 kobject_init(kobj);11         error =kobject_add(kobj);12         if (!error)13 kobject_uevent(kobj, KOBJ_ADD);14 }15     returnerror;16 }

 kobject_add(kobj);
1 /**2 *    kobject_add - add an object to the hierarchy.3 *    @kobj:    object.4  */
5 int kobject_add(struct kobject *kobj)6 {7     returnkobject_shadow_add(kobj, NULL);8 }

  kobject_shadow_add(kobj, NULL);  
1 /**2 *    kobject_shadow_add - add an object to the hierarchy.3 *    @kobj:    object.4 *    @shadow_parent: sysfs directory to add to.5  */
6
7 int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)8 {9     int error = 0;10     struct kobject *parent;11
12     if (!(kobj =kobject_get(kobj)))13         return -ENOENT;14     if (!kobj->k_name)15         kobj->k_name = kobj->name;16     if (!*kobj->k_name) {17         pr_debug("kobject attempted to be registered with no name!\n");18         WARN_ON(1);19 kobject_put(kobj);20         return -EINVAL;21 }22     parent = kobject_get(kobj->parent);23
24     pr_debug("kobject %s: registering. parent: %s, set: %s\n",25          kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>",26          kobj->kset ? kobj->kset->kobj.name : "<NULL>");27
28     if (kobj->kset) {29         spin_lock(&kobj->kset->list_lock);30
31         if (!parent)32             parent = kobject_get(&kobj->kset->kobj);33
34         list_add_tail(&kobj->entry,&kobj->kset->list);35         spin_unlock(&kobj->kset->list_lock);36         kobj->parent =parent;37 }38
39     error =create_dir(kobj, shadow_parent);40     if(error) {41         /*unlink does the kobject_put() for us*/
42 unlink(kobj);43 kobject_put(parent);44
45         /*be noisy on error issues*/
46         if (error == -EEXIST)47             printk(KERN_ERR "kobject_add failed for %s with"
48                    "-EEXIST, don't try to register things with"
49                    "the same name in the same directory.\n",50 kobject_name(kobj));51         else
52             printk(KERN_ERR "kobject_add failed for %s (%d)\n",53 kobject_name(kobj), error);54 dump_stack();55 }56
57     returnerror;58 }

  create_dir(kobj, shadow_parent); 

1 static int create_dir(struct kobject * kobj, struct dentry *shadow_parent)2 {3     int error = 0;4     if(kobject_name(kobj)) {5         error =sysfs_create_dir(kobj, shadow_parent);6         if (!error) {7             if ((error =populate_dir(kobj)))8 sysfs_remove_dir(kobj);9 }10 }11     returnerror;12 }

  sysfs_create_dir(kobj, shadow_parent);

1 /**2 *    sysfs_create_dir - create a directory for an object.3 *    @kobj:        object we're creating directory for.4 *    @shadow_parent:    parent parent object.5  */
6
7 int sysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent)8 {9     struct dentry * dentry =NULL;10     struct dentry *parent;11     int error = 0;12
13     BUG_ON(!kobj);14
15     if(shadow_parent)16         parent =shadow_parent;17     else if (kobj->parent)18         parent = kobj->parent->dentry;19     else if (sysfs_mount && sysfs_mount->mnt_sb)20         parent = sysfs_mount->mnt_sb->s_root;21     else
22         return -EFAULT;23
24     error = create_dir(kobj,parent,kobject_name(kobj),&dentry);25     if (!error)26         kobj->dentry =dentry;27     returnerror;28 }

  create_dir(kobj,parent,kobject_name(kobj),&dentry);

  
1 static int create_dir(struct kobject * k, struct dentry *p,2               const char * n, struct dentry **d)3 {4     interror;5     umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO |S_IXUGO;6
7     mutex_lock(&p->d_inode->i_mutex);8     *d =lookup_one_len(n, p, strlen(n));9     if (!IS_ERR(*d)) {10          if (sysfs_dirent_exist(p->d_fsdata, n))11               error = -EEXIST;12           else
13             error = sysfs_make_dirent(p->d_fsdata, *d, k, mode,14 SYSFS_DIR);15         if (!error) {16             error = sysfs_create(*d, mode, init_dir);17             if (!error) {18                 inc_nlink(p->d_inode);19                 (*d)->d_op = &sysfs_dentry_ops;20                 d_rehash(*d);21 }22 }23         if (error && (error != -EEXIST)) {24             struct sysfs_dirent *sd = (*d)->d_fsdata;25             if(sd) {26                  list_del_init(&sd->s_sibling);27 sysfs_put(sd);28 }29             d_drop(*d);30 }31         dput(*d);32     } else
33         error = PTR_ERR(*d);34     mutex_unlock(&p->d_inode->i_mutex);35     returnerror;36 }

    sysfs_create(*d, mode, init_dir);  
1 int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *))2 {3     int error = 0;4     struct inode * inode =NULL;5     if(dentry) {6         if (!dentry->d_inode) {7             struct sysfs_dirent * sd = dentry->d_fsdata;8             if ((inode =sysfs_new_inode(mode, sd))) {9                 if (dentry->d_parent && dentry->d_parent->d_inode) {10                     struct inode *p_inode = dentry->d_parent->d_inode;11                     p_inode->i_mtime = p_inode->i_ctime =CURRENT_TIME;12 }13                 gotoProceed;14 }15             else
16                 error = -ENOMEM;17         } else
18             error = -EEXIST;19     } else
20         error = -ENOENT;21     gotoDone;22
23 Proceed:24     if(init)25         error =init(inode);26     if (!error) {27 d_instantiate(dentry, inode);28         if(S_ISDIR(mode))29             dget(dentry);  /*pin only directory dentry in core*/
30     } else
31 iput(inode);32 Done:33     returnerror;34 }

  sysfs_create(*d, mode, init_dir);

  

1 int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *))2 {3     int error = 0;4     struct inode * inode =NULL;5     if(dentry) {6         if (!dentry->d_inode) {7             struct sysfs_dirent * sd = dentry->d_fsdata;8             if ((inode =sysfs_new_inode(mode, sd))) {9                 if (dentry->d_parent && dentry->d_parent->d_inode) {10                     struct inode *p_inode = dentry->d_parent->d_inode;11                     p_inode->i_mtime = p_inode->i_ctime =CURRENT_TIME;12 }13                 gotoProceed;14 }15             else
16                 error = -ENOMEM;17         } else
18             error = -EEXIST;19     } else
20         error = -ENOENT;21     gotoDone;22
23 Proceed:24     if(init)25         error =init(inode);26     if (!error) {27 d_instantiate(dentry, inode);28         if(S_ISDIR(mode))29             dget(dentry);  /*pin only directory dentry in core*/
30     } else
31 iput(inode);32 Done:33     returnerror;34 }

  

  sysfs_new_inode(mode, sd))  
1 struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *sd)2 {3     struct inode * inode =new_inode(sysfs_sb);4     if(inode) {5         inode->i_blocks = 0;6         inode->i_mapping->a_ops = &sysfs_aops;7         inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;8         inode->i_op = &sysfs_inode_operations;9         inode->i_ino = sd->s_ino;10         lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);11
12         if (sd->s_iattr) {13             /*sysfs_dirent has non-default attributes14 * get them for the new inode from persistent copy15 * in sysfs_dirent16              */
17             set_inode_attr(inode, sd->s_iattr);18         } else
19 set_default_inode_attr(inode, mode);20 }21     returninode;22 }

  

  new_inode(sysfs_sb);
1 /**2 *    new_inode     - obtain an inode3 *    @sb: superblock4 *5 *    Allocates a new inode for given superblock.6  */
7 struct inode *new_inode(struct super_block *sb)8 {9     /*
10 * On a 32bit, non LFS stat() call, glibc will generate an EOVERFLOW11 * error if st_ino won't fit in target struct field. Use 32bit counter12 * here to attempt to avoid that.13      */
14     static unsigned intlast_ino;15     struct inode *inode;16
17     spin_lock_prefetch(&inode_lock);18
19     inode =alloc_inode(sb);20     if(inode) {21         spin_lock(&inode_lock);22         inodes_stat.nr_inodes++;23         list_add(&inode->i_list, &inode_in_use);24         list_add(&inode->i_sb_list, &sb->s_inodes);25         inode->i_ino = ++last_ino;26         inode->i_state = 0;27         spin_unlock(&inode_lock);28 }29     returninode;30 }

  alloc_inode(sb);
1 static struct inode *alloc_inode(struct super_block *sb)2 {3     static const structaddress_space_operations empty_aops;4     static structinode_operations empty_iops;5     static const structfile_operations empty_fops;6     struct inode *inode;7
8     if (sb->s_op->alloc_inode)9         inode = sb->s_op->alloc_inode(sb);10     else
11         inode = (struct inode *) kmem_cache_alloc(inode_cachep, GFP_KERNEL);12
13     if(inode) {14         struct address_space * const mapping = &inode->i_data;15
16         inode->i_sb =sb;17         inode->i_blkbits = sb->s_blocksize_bits;18         inode->i_flags = 0;19         atomic_set(&inode->i_count, 1);20         inode->i_op = &empty_iops;21         inode->i_fop = &empty_fops;22         inode->i_nlink = 1;23         atomic_set(&inode->i_writecount, 0);24         inode->i_size = 0;25         inode->i_blocks = 0;26         inode->i_bytes = 0;27         inode->i_generation = 0;28 #ifdef CONFIG_QUOTA29         memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));30 #endif
31         inode->i_pipe =NULL;32         inode->i_bdev =NULL;33         inode->i_cdev =NULL;34         inode->i_rdev = 0;35         inode->dirtied_when = 0;36         if(security_inode_alloc(inode)) {37             if (inode->i_sb->s_op->destroy_inode)38                 inode->i_sb->s_op->destroy_inode(inode);39             else
40 kmem_cache_free(inode_cachep, (inode));41             returnNULL;42 }43
44         mapping->a_ops = &empty_aops;45          mapping->host =inode;46         mapping->flags = 0;47 mapping_set_gfp_mask(mapping, GFP_HIGHUSER);48         mapping->assoc_mapping =NULL;49         mapping->backing_dev_info = &default_backing_dev_info;50
51         /*
52 * If the block_device provides a backing_dev_info for client53 * inodes then use that.  Otherwise the inode share the bdev's54 * backing_dev_info.55          */
56         if (sb->s_bdev) {57             struct backing_dev_info *bdi;58
59             bdi = sb->s_bdev->bd_inode_backing_dev_info;60             if (!bdi)61                 bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;62             mapping->backing_dev_info =bdi;63 }64         inode->i_private =NULL;65         inode->i_mapping =mapping;66 }67     returninode;68 }

   kmem_cache_alloc(inode_cachep, GFP_KERNEL);这儿就是最底层为sys虚拟文件系统分配内存的函数,就是采用了高速页缓存方法,在内存中为节点分配了一块内存。

1 **
2  * kmem_cache_alloc - Allocate an object
3  * @cachep: The cache to allocate from.4  *@flags: See kmalloc().5  *
6  * Allocate an object from thiscache.  The flags are only relevant7  * ifthe cache has no available objects.8  */
9 void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)10 {11     return __cache_alloc(cachep, flags, __builtin_return_address(0));12 }

上面是关于sysfs虚拟文件系统的分析,与i2c驱动没有太大的关系,但是我们可以看出来i2c的driver和device最后都是挂在总线上的,这些都是可以归纳为:总线---设备-----驱动模型的,我们可以看出来从i2c_add_driver()函数开始内核不光是在建立一个driver同时也在忙着将这个dirver挂在这个总线上,前面贴出的代码描述了这个过程,下面在看看流程:

  i2c_add_driver()----------->i2c_register_driver()

                    |

                    |

                    driver->driver.bus = &i2c_bus_type

1 struct bus_type i2c_bus_type ={2     .name        = "i2c",3     .dev_attrs    =i2c_dev_attrs,4     .match        =i2c_device_match,5     .uevent        =i2c_device_uevent,6     .probe        =i2c_device_probe,7     .remove        =i2c_device_remove,8     .shutdown    =i2c_device_shutdown,9     .suspend    =i2c_device_suspend,10     .resume        =i2c_device_resume,11 };

  i2c_driver与i2c_client关系:

  i2c_driver对应于一套驱动方法,主要成员函数是probe()、remove()、suspend()、resume()。

  i2c_client对应于真实的物理设备,每个I2C设备都需要一个i2c_client来描述,i2c_driver与i2c_client的关系是一对多,一个i2c_drvier可以支持多个同类型的i2c_client。

  i2c_adpater与i2c_client关系

  i2c_adpater与i2c_client的关系与I2C硬件体系中适配器和设备的关系一致,即i2c_client依附于i2c_adapter。一个适配器可以连接多个I2C设备,所以一个i2c_adapter也可以被多个i2c_client依附,i2c_adapter中包括依附于它的i2c_client的链表。

  刚开始没搞懂其实i2c_client、i2c_adpater这两个数据结构都是内核抽象出来的便于对多平台的适应,每一个i2c_adpater对应于一条总线,i2c_client每一个对应于一个具体设备。

  网上的解释:简单点了, 你的开发板上有几个I2C接口,就有几个adapter , 也就是有几条I2C bus ,  I2C CLIENT 对应的就是你的外围I2C 设备,有几个就有几个CLIENT , 把这些设备插入开发板, 对应其中的一条BUS, 那么相应的就对应了其中的一个ADAPTER , 接下来的就是  CLIENT 与 ADAPTER 勾搭成对了, 后面就是做该做的事了  在编写I2C驱动的时候我们需要实现两个方面的内容:  1、提供I2C适配器的硬件驱动,探测、初始化I2C适配器、驱动CPU控制的I2C适配器从硬件上产生各种信号及处理I2C中断。  2、提供I2C适配器的算法,用具体适配器的xxx_dfer()函数填充i2c_algorithm的master_xfer指针。  3、对I2C core的接口,必须实现 struct i2c_drvier数据结构中的几个特定的功能函数。这些函数是I2C驱动与I2C总线物理层(I2C控制器)和I2C设备器件之间通信的基础。
  4、 对用户应用层的接口,必须实现struct file_operation数据结构中的一些特定功能的函数,如 open ,release , read ,write,lseek等函数。以上两类接口中,对I2C core的接口是对I2C设备访问的基础,实现对I2C总线具体的访问方法;对用户应用层的接口则是方便应用程序开发,实现设备特定功能的必不可少的部分。例如,如果是字符设备,就实现文件操作接口,实现具体设备yyy的yyy_read()、yyy_write()和yyy_ioctl()函数等;如果是声卡,就实现ALSA驱动。

  下面的函数流程就是i2c注册的过程,在注册的过程中会把i2c添加到总线上去,同时完成match过程(目前没有弄清楚的流程),难道是在这儿进行了dev和driver的比较?  i2c_add_driver()---------->i2c_register_driver()------------>driver_register()------------------->bus_add_driver()-------->driver_attach()--------->bus_for_each_dev()-------------->__driver_attach()----------------->driver_probe_device()----------------->int(*match)(struct device * dev, struct device_driver * drv)     总结一下I2C驱动的流程:  1、首先,在i2c_client_address_data的normal_i2c属性中定义好我们设备的设备地址。  2、接下来,i2c_driver就出场了,它的功能是定义i2c设备的名字,探测函数,卸载函数三个属性。  3、当程序在入口函数中注册i2c-driver驱动之后,系统就会根据我们第一步中定义的设备地址,调用attach_adapter函数进行匹配设备地址是否支持,在attach_adapter函数中主要的功能是在调用i2c_probe函数,当系统检测到设备地址匹配时,就会进入i2c_probe函数中干一些重要的事,接着就进入i2c-probe传入的at24cxx_detect函数中实现我们自己的事。  其实总结一下就下面一个流程:at24cxx_attach_adapter -> i2c_probe -> at24cxx_detect

   当我们卸载设备时,会自动调用i2c_driver中定义的卸载函数at24cxx_detach_adapter进行卸载设备。

      最后一步自然就是在出口函数中卸载i2c-driver驱动。

     因为I2C只是一种通信的方式,所以在完成前面的工作后我们需要完成我们要在I2C这种通信方式山所做的工作,我们一般在at24cxx_detect()中完成设备register_chrdev()的注册,然后填写read()、write()等函数。

     没有弄得很清楚的就是为什么没有注册i2c_add_adapter()---------->i2c_register_adapter(),适配器和device的匹配是在driver中完成的吗?

     参考的比较经典的博文:http://www.cnblogs.com/lihaiyan/p/4452875.html

              http://blog.csdn.net/chocolate001/article/details/7470873

              http://blog.sina.com.cn/s/blog_63f31f340101byb2.html

              http://www.embedu.org/Column/Column213.htm

转载于:https://www.cnblogs.com/qiuheng/p/5761865.html

linux驱动之I2C相关推荐

  1. linux驱动之i2c学习

    最近在研究linux的i2c驱动,从最底层i2c控制器初始化到应用层与i2c设备交互基本打通了. 一.linux的i2c架构可以用下图表示: IIC适配器对应一条i2c总线,linux里面用i2c_a ...

  2. linux驱动之I2C子系统

    目录 一.I2C基本原理 二.linux内核的I2C子系统详解 1.linux内核的I2C驱动框架总览 2.I2C子系统的4个关键结构体(kernel/include/linux/i2c.h) 3.关 ...

  3. 《Linux驱动:I2C驱动看这一篇就够了》

    文章目录 一,前言 二,IIC驱动的体系架构 2.1 IIC核心 2.2 IIC适配器 2.2.1 适配器驱动资源的初始化和注册 2.2.2 IIC适配器里的通信方法 2.2.3 IIC适配器和IIC ...

  4. Linux驱动分析——I2C子系统

    stm32mp157  盘古开发板  Linux内核版本4.19 目录 1.朱有鹏老师视频笔记 2.I2C子系统的4个关键结构体 3.关键文件 4.i2c-core.c初步分析 ​4.1.smbus代 ...

  5. linux驱动:i2c驱动(一)

    I2C系统框架:I2C核心层.I2C总线驱动.I2C设备驱动 --------------------------------------------------------------------- ...

  6. 【Linux驱动】I2C子系统与触摸屏驱动

    由于学习触摸屏驱动涉及到中断以及I2C相关的知识,因此先介绍一下I2C的驱动框架. 触摸屏与I2C总线的关系 关于I2C的基础概念和原理参考我的这篇博客:[裸机]嵌入式相关问题汇总(二.I2C通信概念 ...

  7. linux驱动之i2c子系统mpu6050设备驱动

    以下是mpu6050简单的驱动实现,mpu6050是I2C接口的6轴传感器,可以作为字符设备注册到内核,本代码运行环境是3.4.2内核,4.3.2版本的编译链,12.04版本的Ubuntu,硬件环境是 ...

  8. linux驱动:i2c驱动(二)

    3.驱动源码分析 IPNC_RDK_V3.8.0.1/Source/ti_tools/ipnc_psp_arago/kernel/sound/soc/codecs/tlv320aic3x.c 3.1 ...

  9. Linux驱动之i2c用户态函数调用

    一.概述 I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL.正因为这样,它方便了工程人员的布线. 二.用户态实现设备驱动 在Linux内核代码文件i2c-dev.c中实现了I2C适配器设备 ...

最新文章

  1. Struts2 验证规则配置文件
  2. python自定义随机数_python:numpy.random模块生成随机数
  3. 电子学会 软件编程(图形化)一级训练营
  4. 文巾解题 206. 反转链表
  5. TCP/IP的三层负载均衡
  6. java基础—IO类——LineNumberReader 的使用
  7. 华为Mate30系列5G版正式开售:有了5G套餐 入手正当时
  8. vue.js v-model
  9. python之路 day5
  10. 十次方社交系统开发项目 源码 视频 文档 工具 合集百度云下载地址
  11. 计算机病毒存于什么,计算机病毒防治体系存在的问题有什么
  12. 使用ARCGIS多重缓冲区分析工具建立颜色渐变行政边界
  13. 华为公司内部控制手册(干货)
  14. [印刷工艺]从正度纸,大度纸说起
  15. 用python做双人五子棋_使用python实现简单五子棋游戏
  16. windows7下面利用docker搭建jitsi-meet测试环境
  17. XRecyclerView Scrapped or attached views may not be recycled
  18. 做程序员的第八个年头——2021年个人工作总结
  19. soap-ws 获取wsdl中所有方法 (一)
  20. WGCLOUD默认登录账号密码是什么

热门文章

  1. Jacoco的原理(各个覆盖率的解释)
  2. php 获取网卡mac
  3. 《面向模式的软件体系结构2-用于并发和网络化对象模式》读书笔记(17)--- 领导者/追随者...
  4. 33 个送给 Java 程序员的练手项目合集
  5. 5个教程教你学会写爬虫!(Python)
  6. 被迫学计算机,电脑强迫人学习
  7. 卫生统计学v是什么意思_四川大学华西公共卫生学院报考常见问题答疑
  8. linux cpu平均负载,关于linux系统CPU篇---平均负载
  9. 动态规划生产存储matlab,基于Matlab的动态规划算法的实现及应用
  10. 深入理解数据库行锁与表锁