linux i2c设备驱动

一. i2c的结构体

     1. i2c适配器

[cpp]  view plain copy
  1. struct i2c_adapter {  
  2.     struct module *owner;   //模块所有者  
  3.     unsigned int id __deprecated;  
  4.     unsigned int class//支持的类别(I2C_CLASS_HWMON,I2C_CLASS_DDC,I2C_CLASS_SPD)  
  5.     const struct i2c_algorithm *algo;   //i2c算法结构体  
  6.     void *algo_data;  
  7.     struct rt_mutex bus_lock;  
  8.     int timeout;    //超时值默认是1s  
  9.     int retries;    //通讯重试次数  
  10.     struct device dev;      //设备文件  
  11.     int nr; //id号,次设备号  
  12.     char name[48];  //i2c适配器名  
  13.     struct completion dev_released;  
  14.     struct mutex userspace_clients_lock;  
  15.     struct list_head userspace_clients; //挂接的设备链表头  
  16. };  

     2. i2c设备

[cpp]  view plain copy
  1. struct i2c_client {  
  2.     unsigned short flags;   //标志(读/写)  
  3.     unsigned short addr;    //i2c地址  
  4.     char name[I2C_NAME_SIZE];   //i2c设备名  
  5.     struct i2c_adapter *adapter;    //匹配的i2c适配器  
  6.     struct i2c_driver *driver;      //匹配的i2c驱动  
  7.     struct device dev;      //设备文件  
  8.     int irq;  
  9.     struct list_head detected;  //"检测到"链表头  
  10. };  

     3. i2c驱动

[cpp]  view plain copy
  1. struct i2c_driver {  
  2.     unsigned int class;  
  3.     int (*attach_adapter)(struct i2c_adapter *);    //连接i2c适配器  
  4.     int (*detach_adapter)(struct i2c_adapter *);    //分离i2c适配器  
  5.     int (*probe)(struct i2c_client *, const struct i2c_device_id *);    //probe方法  
  6.     int (*remove)(struct i2c_client *); //remove方法  
  7.     void (*shutdown)(struct i2c_client *);  //关闭  
  8.     int (*suspend)(struct i2c_client *, pm_message_t mesg); //挂起  
  9.     int (*resume)(struct i2c_client *); //唤醒  
  10.     void (*alert)(struct i2c_client *, unsigned int data);  
  11.     int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);  
  12.     struct device_driver driver;    //设备驱动文件  
  13.     const struct i2c_device_id *id_table;   //支持的i2c设备id表  
  14.     int (*detect)(struct i2c_client *, struct i2c_board_info *);    //检测  
  15.     const unsigned short *address_list;   
  16.     struct list_head clients;   //匹配的设备链表  
  17. };  

     4. i2c板级信息

[cpp]  view plain copy
  1. struct i2c_board_info {  
  2.     char        type[I2C_NAME_SIZE];    //设备名  
  3.     unsigned short  flags;  //标志(读/写)  
  4.     unsigned short  addr;   //i2c地址  
  5.     void        *platform_data; //平台资源  
  6.     struct dev_archdata *archdata;  
  7. #ifdef CONFIG_OF  
  8.     struct device_node *of_node;  
  9. #endif  
  10.     int     irq;  
  11. };  

    4.1 i2c板级信息辅助宏(一般声明在板级初始化函数中)

[cpp]  view plain copy
  1. #define I2C_BOARD_INFO(dev_type, dev_addr) \  
  2.     .type = dev_type, .addr = (dev_addr)  

     5. i2c消息

[cpp]  view plain copy
  1. struct i2c_msg {  
  2.     __u16 addr; //i2c设备地址  
  3.     __u16 flags;    //标志(读/写)  
  4.     __u16 len;  //消息长度  
  5.     __u8 *buf;  //缓冲区  
  6. };  

     5.1  i2c读写控制数据结构体

[cpp]  view plain copy
  1. struct i2c_rdwr_ioctl_data {  
  2.     struct i2c_msg __user *msgs;    /* pointers to i2c_msgs */  
  3.     __u32 nmsgs;            /* number of i2c_msgs */  
  4. };  

    6. i2c算法

[cpp]  view plain copy
  1. struct i2c_algorithm {  
  2.     int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,int num); //主机传输方式  
  3.     int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,unsigned short flags,     //smbus传输方式  
  4.         char read_write,u8 command, int size, union i2c_smbus_data *data);  
  5.     u32 (*functionality) (struct i2c_adapter *);    //功能检测  
  6. };  


二. i2c总线,适配器,驱动,设备的初始化

     1. i2c总线类型

[cpp]  view plain copy
  1. struct bus_type i2c_bus_type = {  
  2.     .name       = "i2c",  
  3.     .match      = i2c_device_match, //i2c设备与驱动匹配  
  4.     .probe      = i2c_device_probe, //i2c设备probe方法  
  5.     .remove     = i2c_device_remove,    //移除  
  6.     .shutdown       = i2c_device_shutdown,  //关闭  
  7.     .pm     = &i2c_device_pm_ops,   //电源管理  
  8. };  

      1.1 i2c设备与驱动的匹配i2c_device_match

[cpp]  view plain copy
  1. static int i2c_device_match(struct device *dev, struct device_driver *drv)  
  2. {  
  3.     struct i2c_client   *client = i2c_verify_client(dev);   //根据设备文件获取i2c_client  
  4.     struct i2c_driver   *driver;  
  5.     if (!client)  
  6.         return 0;  
  7.     if (of_driver_match_device(dev, drv))   //设备文件与设备驱动文件的匹配  
  8.         return 1;  
  9.   
  10.     driver = to_i2c_driver(drv);    //根据设备驱动文件获取i2c_driver  
  11.     if (driver->id_table)    //i2c_driver的id_table存在  
  12.         return i2c_match_id(driver->id_table, client) != NULL;   //匹配i2c_client和i2c_driver  
  13.   
  14.     return 0;  
  15. }  

     1.1.1 i2c_match_id函数

[cpp]  view plain copy
  1. static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,const struct i2c_client *client)  
  2. {  
  3.     while (id->name[0]) {    //判断i2c_driver->id_table->name数组中有与i2c_client->name相同的项没  
  4.         if (strcmp(client->name, id->name) == 0)  
  5.             return id;  
  6.         id++;  
  7.     }  
  8.     return NULL;  
  9. }  

     1.2 i2c探测函数

[cpp]  view plain copy
  1. static int i2c_device_probe(struct device *dev)  
  2. {  
  3.     struct i2c_client   *client = i2c_verify_client(dev);  
  4.     struct i2c_driver   *driver;  
  5.     int status;  
  6.   
  7.     if (!client)  
  8.         return 0;  
  9.     driver = to_i2c_driver(dev->driver);     //获得i2c_driver  
  10.     if (!driver->probe || !driver->id_table)  
  11.         return -ENODEV;  
  12.     client->driver = driver; //设置i2c_client->driver成员,i2c设备与驱动捆绑  
  13.     if (!device_can_wakeup(&client->dev))    //i2c设备支持唤醒  
  14.         device_init_wakeup(&client->dev,client->flags & I2C_CLIENT_WAKE); //则唤醒  
  15.     dev_dbg(dev, "probe\n");  
  16.     status = driver->probe(client, i2c_match_id(driver->id_table, client));   //调用i2c_driver->probe方法  
  17.     if (status) {  
  18.         client->driver = NULL;  
  19.         i2c_set_clientdata(client, NULL);  
  20.     }  
  21.     return status;  
  22. }  

     2. i2c总线的注册

[cpp]  view plain copy
  1. static int __init i2c_init(void)  
  2. {  
  3.     int retval;  
  4.     retval = bus_register(&i2c_bus_type);  
  5.     if (retval)  
  6.         return retval;  
  7. #ifdef CONFIG_I2C_COMPAT  
  8.     i2c_adapter_compat_class = class_compat_register("i2c-adapter");    //创建"/sys/class/i2c-adapter"  
  9.     if (!i2c_adapter_compat_class) {  
  10.         retval = -ENOMEM;  
  11.         goto bus_err;  
  12.     }  
  13. #endif  
  14.     retval = i2c_add_driver(&dummy_driver);  
  15.     if (retval)  
  16.         goto class_err;  
  17.     return 0;  
  18. class_err:  
  19. #ifdef CONFIG_I2C_COMPAT  
  20.     class_compat_unregister(i2c_adapter_compat_class);  
  21. bus_err:  
  22. #endif  
  23.     bus_unregister(&i2c_bus_type);  
  24.     return retval;  
  25. }  

    3. i2c设备的初始化工作

[cpp]  view plain copy
  1. static int __init i2c_dev_init(void)  
  2. {  
  3.     int res;  
  4.     printk(KERN_INFO "i2c /dev entries driver\n");  
  5.     res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);  //注册字符设备,#define I2C_MAJOR 89  
  6.     if (res)  
  7.         goto out;  
  8.   
  9.     i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");   //创建"/sys/class/i2c-dev"  
  10.     if (IS_ERR(i2c_dev_class)) {  
  11.         res = PTR_ERR(i2c_dev_class);  
  12.         goto out_unreg_chrdev;  
  13.     }  
  14.     res = i2c_add_driver(&i2cdev_driver);   //注册i2c驱动 i2cdev_driver   
  15.     if (res)  
  16.         goto out_unreg_class;  
  17.     return 0;  
  18. out_unreg_class:  
  19.     class_destroy(i2c_dev_class);  
  20. out_unreg_chrdev:  
  21.     unregister_chrdev(I2C_MAJOR, "i2c");  
  22. out:  
  23.     printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);  
  24.     return res;  
  25. }   

      3.1 i2c字符设备操作函数集

[cpp]  view plain copy
  1. static const struct file_operations i2cdev_fops = {  
  2.     .owner      = THIS_MODULE,  
  3.     .llseek     = no_llseek,  
  4.     .read       = i2cdev_read,  //读  
  5.     .write      = i2cdev_write, //写  
  6.     .unlocked_ioctl = i2cdev_ioctl, //控制  
  7.     .open       = i2cdev_open,  //打开  
  8.     .release        = i2cdev_release, //释放  
  9. };  

     3.1.1 打开i2c字符设备

[cpp]  view plain copy
  1. static int i2cdev_open(struct inode *inode, struct file *file)  
  2. {  
  3.     unsigned int minor = iminor(inode); //根据节点获取次设备号  
  4.     struct i2c_client *client;  
  5.     struct i2c_adapter *adap;  
  6.     struct i2c_dev *i2c_dev;  
  7.   
  8.     i2c_dev = i2c_dev_get_by_minor(minor);  //根据次设备号获取i2c_dev  
  9.     if (!i2c_dev)  
  10.         return -ENODEV;  
  11.     adap = i2c_get_adapter(i2c_dev->adap->nr);    //获取i2c_adapter  
  12.     if (!adap)  
  13.         return -ENODEV;  
  14.     client = kzalloc(sizeof(*client), GFP_KERNEL);  //分配i2c_client内存  
  15.     if (!client) {  
  16.         i2c_put_adapter(adap);  
  17.         return -ENOMEM;  
  18.     }  
  19.     snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);    //修改i2c_client->name  
  20.     client->driver = &i2cdev_driver; //设置i2c_client->driver为i2cdev_driver  
  21.     client->adapter = adap;      //设置i2c_client->adapter  
  22.     file->private_data = client; //将i2c_client放在文件的私有数据段  
  23.     return 0;  
  24. }  

     3.1.2 读i2c字符设备

[cpp]  view plain copy
  1. static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count,loff_t *offset)  
  2. {  
  3.     char *tmp;  
  4.     int ret;  
  5.     struct i2c_client *client = file->private_data;  //从私有数据段取出i2c_client  
  6.     if (count > 8192)  
  7.         count = 8192;  
  8.     tmp = kmalloc(count, GFP_KERNEL);   //分配临时缓冲区  
  9.     if (tmp == NULL)  
  10.         return -ENOMEM;  
  11.     pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",iminor(file->f_path.dentry->d_inode), count);  
  12.     ret = i2c_master_recv(client, tmp, count);  //调用i2c_master_recv函数(见 七 详述)  
  13.     if (ret >= 0)  
  14.         ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret;    //复制数据到用户空间  
  15.     kfree(tmp);  
  16.     return ret;  
  17. }  

     3.1.3 写i2c字符设备

[cpp]  view plain copy
  1. static ssize_t i2cdev_write(struct file *file, const char __user *buf,size_t count, loff_t *offset)  
  2. {  
  3.     int ret;  
  4.     char *tmp;  
  5.     struct i2c_client *client = file->private_data;  //从私有数据段取出  
  6.     if (count > 8192)  
  7.         count = 8192;  
  8.     tmp = memdup_user(buf, count);  
  9.     if (IS_ERR(tmp))  
  10.         return PTR_ERR(tmp);  
  11.     pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",iminor(file->f_path.dentry->d_inode), count);  
  12.     ret = i2c_master_send(client, tmp, count);  //i2c发送数据 (见 七 详述)  
  13.     kfree(tmp);  
  14.     return ret;  
  15. }  

     3.1.4 控制i2c字符设备

[cpp]  view plain copy
  1. static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  
  2. {  
  3.     struct i2c_client *client = file->private_data;  
  4.     unsigned long funcs;  
  5.     dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",cmd, arg);  
  6.     switch (cmd) {  
  7.     case I2C_SLAVE:  
  8.     case I2C_SLAVE_FORCE:  
  9.         if ((arg > 0x3ff) ||  
  10.             (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))  
  11.             return -EINVAL;  
  12.         if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))  
  13.             return -EBUSY;  
  14.         client->addr = arg;  
  15.         return 0;  
  16.     case I2C_TENBIT:  
  17.         if (arg)  
  18.             client->flags |= I2C_M_TEN;  
  19.         else  
  20.             client->flags &= ~I2C_M_TEN;  
  21.         return 0;  
  22.     case I2C_PEC:  
  23.         if (arg)  
  24.             client->flags |= I2C_CLIENT_PEC;  
  25.         else  
  26.             client->flags &= ~I2C_CLIENT_PEC;  
  27.         return 0;  
  28.     case I2C_FUNCS:  
  29.         funcs = i2c_get_functionality(client->adapter);  
  30.         return put_user(funcs, (unsigned long __user *)arg);  
  31.     case I2C_RDWR:  
  32.         return i2cdev_ioctl_rdrw(client, arg);  //i2c读写命令 (第 七 详述)  
  33.     case I2C_SMBUS:  
  34.         return i2cdev_ioctl_smbus(client, arg); //i2c读写命令 SMBUS  
  35.     case I2C_RETRIES:  
  36.         client->adapter->retries = arg;  
  37.         break;  
  38.     case I2C_TIMEOUT:  
  39.         client->adapter->timeout = msecs_to_jiffies(arg * 10);  
  40.         break;  
  41.     default:  
  42.         return -ENOTTY;  
  43.     }  
  44.     return 0;  
  45. }  

      3.2 i2cdev_driver驱动

[cpp]  view plain copy
  1. static struct i2c_driver i2cdev_driver = {  
  2.     .driver = {  
  3.         .name   = "dev_driver",  
  4.     },  
  5.     .attach_adapter = i2cdev_attach_adapter,    //连接适配器  
  6.     .detach_adapter = i2cdev_detach_adapter,    //断开适配器  
  7. };  

三. i2c适配器的添加与删除
     1. 添加适配器

[cpp]  view plain copy
  1. int i2c_add_adapter(struct i2c_adapter *adapter)  
  2. {  
  3.     int id, res = 0;  
  4. retry:  
  5.     if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) //根据idr机制获取适配器编号  
  6.         return -ENOMEM;  
  7.     mutex_lock(&core_lock);  
  8.     res = idr_get_new_above(&i2c_adapter_idr, adapter,__i2c_first_dynamic_bus_num, &id);  
  9.     mutex_unlock(&core_lock);  
  10.     if (res < 0) {  
  11.         if (res == -EAGAIN)  
  12.             goto retry;  
  13.         return res;  
  14.     }  
  15.     adapter->nr = id;    //设置i2c_adapter->nr  
  16.     return i2c_register_adapter(adapter);   //注册i2c_adapter  
  17. }  

     1.1 i2c_register_adapter

[cpp]  view plain copy
  1. static int i2c_register_adapter(struct i2c_adapter *adap)  
  2. {  
  3.     int res = 0;  
  4.     if (unlikely(WARN_ON(!i2c_bus_type.p))) {  
  5.         res = -EAGAIN;  
  6.         goto out_list;  
  7.     }  
  8.     if (unlikely(adap->name[0] == '\0')) {  
  9.         pr_err("i2c-core: Attempt to register an adapter with no name!\n");  
  10.         return -EINVAL;  
  11.     }  
  12.     if (unlikely(!adap->algo)) {  
  13.         pr_err("i2c-core: Attempt to register adapter '%s' with no algo!\n", adap->name);  
  14.         return -EINVAL;  
  15.     }  
  16.     rt_mutex_init(&adap->bus_lock);  
  17.     mutex_init(&adap->userspace_clients_lock);  
  18.     INIT_LIST_HEAD(&adap->userspace_clients);    //初始化支持i2c_client链表头  
  19.     if (adap->timeout == 0)  
  20.         adap->timeout = HZ;  //设置超时值  
  21.     dev_set_name(&adap->dev, "i2c-%d", adap->nr); //设置i2c_adapter->dev->name  
  22.     adap->dev.bus = &i2c_bus_type;   //设置i2c_adapter->dev.bus为i2c_bus_type  
  23.     adap->dev.type = &i2c_adapter_type;  //设置i2c_adapter->dev.type  
  24.     res = device_register(&adap->dev);   //注册i2c_adapter的设备文件  
  25.     if (res)  
  26.         goto out_list;  
  27.     dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);  
  28. #ifdef CONFIG_I2C_COMPAT  
  29.     res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,adap->dev.parent);    //创建"/sys/class/i2c-adapter/i2c-XX"链接文件  
  30.     if (res)  
  31.         dev_warn(&adap->dev,"Failed to create compatibility class link\n");  
  32. #endif  
  33.     if (adap->nr < __i2c_first_dynamic_bus_num)   //__i2c_first_dynamic_bus_num数值在i2c_register_board_info中设置  
  34.         i2c_scan_static_board_info(adap);   //扫描用板级声明的i2c设备并添加,后面细化  
  35.     mutex_lock(&core_lock); //遍历i2c_bus_type总线类型的设备文件,调用__process_new_adapter   
  36.     bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);//最终会调用i2c_driver->attach_adapter  
  37.     mutex_unlock(&core_lock);  
  38.     return 0;  
  39. out_list:  
  40.     mutex_lock(&core_lock);  
  41.     idr_remove(&i2c_adapter_idr, adap->nr);  
  42.     mutex_unlock(&core_lock);  
  43.     return res;  
  44. }  

这里还有一个函数可以添加适配器i2c_add_numbered_adapter原理一样.

     2. 删除适配器

[cpp]  view plain copy
  1. int i2c_del_adapter(struct i2c_adapter *adap)  
  2. {  
  3.     int res = 0;  
  4.     struct i2c_adapter *found;  
  5.     struct i2c_client *client, *next;  
  6.     mutex_lock(&core_lock);  
  7.     found = idr_find(&i2c_adapter_idr, adap->nr);  
  8.     mutex_unlock(&core_lock);  
  9.     if (found != adap) {  
  10.         pr_debug("i2c-core: attempting to delete unregistered adapter [%s]\n", adap->name);  
  11.         return -EINVAL;  
  12.     }  
  13.     mutex_lock(&core_lock); //遍历i2c_bus_type 总线类型的设备文件,调用__process_removed_adapter  
  14.     res = bus_for_each_drv(&i2c_bus_type, NULL, adap,__process_removed_adapter);    //最终调用i2c_driver->detach_adapter  
  15.     mutex_unlock(&core_lock);  
  16.     if (res)  
  17.         return res;  
  18.     mutex_lock(&adap->userspace_clients_lock);  
  19.     list_for_each_entry_safe(client, next, &adap->userspace_clients,detected) {  //遍历所有挂载适配器上的i2c设备  
  20.         dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name,client->addr);  
  21.         list_del(&client->detected); //移出"检测到"链表  
  22.         i2c_unregister_device(client);  //注销i2c_client  
  23.     }  
  24.     mutex_unlock(&adap->userspace_clients_lock);  
  25.     res = device_for_each_child(&adap->dev, NULL, __unregister_client);  
  26. #ifdef CONFIG_I2C_COMPAT  
  27.     class_compat_remove_link(i2c_adapter_compat_class, &adap->dev,adap->dev.parent);  //删除"/sys/class/i2c-adapter/"的链接  
  28. #endif  
  29.     dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);  
  30.     init_completion(&adap->dev_released);  
  31.     device_unregister(&adap->dev);   //注销设备文件  
  32.     wait_for_completion(&adap->dev_released);  
  33.     mutex_lock(&core_lock);  
  34.     idr_remove(&i2c_adapter_idr, adap->nr);  //移除idr数值  
  35.     mutex_unlock(&core_lock);  
  36.     memset(&adap->dev, 0, sizeof(adap->dev));  
  37.     return 0;  
  38. }  

四. 添加删除i2c_driver

     1. 添加i2c_driver

[cpp]  view plain copy
  1. static inline int i2c_add_driver(struct i2c_driver *driver)  
  2. {  
  3.     return i2c_register_driver(THIS_MODULE, driver);    //注册i2c_driver  
  4. }  

     1.1 i2c_register_driver

[cpp]  view plain copy
  1. int i2c_register_driver(struct module *owner, struct i2c_driver *driver)  
  2. {  
  3.     int res;  
  4.     if (unlikely(WARN_ON(!i2c_bus_type.p)))  
  5.         return -EAGAIN;  
  6.     driver->driver.owner = owner;    //设置驱动模块所有者  
  7.     driver->driver.bus = &i2c_bus_type;  //设置设备驱动文件的总线类型为i2c_bus_type  
  8.     res = driver_register(&driver->driver);  //注册设备驱动文件  
  9.     if (res)  
  10.         return res;  
  11.     pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);  
  12.     INIT_LIST_HEAD(&driver->clients);    //初始化i2c_driver支持i2c_client链表头  
  13.     mutex_lock(&core_lock); //遍历i2c_bus_type总线类型的设备文件,调用__process_new_driver函数  
  14.     bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);    //最终调用i2c_driver->attach_adapter  
  15.     mutex_unlock(&core_lock);  
  16.     return 0;  
  17. }  

      2. 删除i2c_driver

[cpp]  view plain copy
  1. void i2c_del_driver(struct i2c_driver *driver)  
  2. {  
  3.     mutex_lock(&core_lock); //遍历i2c_bus_type总线类型的设备文件,调用__process_removed_driver函数  
  4.     bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_removed_driver);    //最终调用i2c_driver->detach_adapter   
  5.     mutex_unlock(&core_lock);  
  6.     driver_unregister(&driver->driver);  //注销设备驱动文件  
  7.     pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);  
  8. }  

五. 注册i2c板级信息

     1. 注册板级i2c驱动

[cpp]  view plain copy
  1. int __init i2c_register_board_info(int busnum,struct i2c_board_info const *info, unsigned len)  
  2. {  
  3.     int status;  
  4.     down_write(&__i2c_board_lock);  
  5.     /* dynamic bus numbers will be assigned after the last static one */  
  6.     if (busnum >= __i2c_first_dynamic_bus_num)  
  7.         __i2c_first_dynamic_bus_num = busnum + 1;   //设置全局变量__i2c_first_dynamic_bus_num  
  8.     for (status = 0; len; len--, info++) {  
  9.         struct i2c_devinfo  *devinfo;  
  10.         devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);  
  11.         if (!devinfo) {  
  12.             pr_debug("i2c-core: can't register boardinfo!\n");  
  13.             status = -ENOMEM;  
  14.             break;  
  15.         }  
  16.         devinfo->busnum = busnum;    //设置devinfo  
  17.         devinfo->board_info = *info; //设置devinfo的板级别信息  
  18.         list_add_tail(&devinfo->list, &__i2c_board_list);    //添加到全局__i2c_board_list链表中  
  19.     }  
  20.     up_write(&__i2c_board_lock);  
  21.     return status;  
  22. }  

 这里有多少个i2c总线,就必须调用多少次i2c_register_board_info带入的busnum依次递增(i2c_register_board_info(1,...);i2c_register_board_info(2,...)....)
全局变量__i2c_first_dynamic_bus_num值i2c_add_adapter函数中调用到. 

     2. 回顾下前面i2c_add_adapter函数中提到的i2c_scan_static_board_info函数

[cpp]  view plain copy
  1. static void i2c_scan_static_board_info(struct i2c_adapter *adapter)  
  2. {  
  3.     struct i2c_devinfo  *devinfo;  
  4.     down_read(&__i2c_board_lock);  
  5.     list_for_each_entry(devinfo, &__i2c_board_list, list) { //遍历全局__i2c_board_list链表  
  6.         if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter,&devinfo->board_info))     
  7.         //匹配的i2c适配器下,添加devinfo的板级信息指定的i2c_device  
  8.             dev_err(&adapter->dev,"Can't create device at 0x%02x\n",devinfo->board_info.addr);  
  9.     }  
  10.     up_read(&__i2c_board_lock);  
  11. }  

     3. 板级声明的i2c_client的注册

[cpp]  view plain copy
  1. struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)  
  2. {  
  3.     struct i2c_client   *client;  
  4.     int status;  
  5.     client = kzalloc(sizeof *client, GFP_KERNEL);   //分配i2c_client内存  
  6.     if (!client)  
  7.         return NULL;  
  8.     client->adapter = adap;  //指定i2c_client的适配器  
  9.     client->dev.platform_data = info->platform_data;  //设置i2c_client设备文件的平台数据  
  10.     if (info->archdata)  
  11.         client->dev.archdata = *info->archdata;  
  12.     client->flags = info->flags;  //设置i2c_client->flags  
  13.     client->addr = info->addr;        //设置i2c_client地址  
  14.     client->irq = info->irq;  //设置i2c_client中断号  
  15.     strlcpy(client->name, info->type, sizeof(client->name));   //设置i2c_client->name  
  16.     status = i2c_check_client_addr_validity(client);    //检测i2c_client地址合法性(0x01~0x7f)  
  17.     if (status) {  
  18.         dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n",client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);  
  19.         goto out_err_silent;  
  20.     }  
  21.     status = i2c_check_addr_busy(adap, client->addr);    //检测地址是否给占用  
  22.     if (status)  
  23.         goto out_err;  
  24.     client->dev.parent = &client->adapter->dev;    //设置i2c_client的父设备  
  25.     client->dev.bus = &i2c_bus_type;     //设置i2c_client的总线类型  
  26.     client->dev.type = &i2c_client_type;     //设置i2c_client的设备类型  
  27. #ifdef CONFIG_OF  
  28.     client->dev.of_node = info->of_node;  
  29. #endif  
  30.     dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),client->addr); //设置i2c_client设备文件的设备名  
  31.     status = device_register(&client->dev);  //注册设备文件  
  32.     if (status)  
  33.         goto out_err;  
  34.     dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",client->name, dev_name(&client->dev));  
  35.     return client;  
  36. out_err:  
  37.     dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x(%d)\n", client->name, client->addr, status);  
  38. out_err_silent:  
  39.     kfree(client);  
  40.     return NULL;  
  41. }  

 

六. attach和detach

1. 前面i2c_adapter和i2c_driver驱动添加和删除都会遍历i2c_bus_type总线类型的设备,然后调用各自的函数,__process_new_adapter,__process_removed_adapter,__process_new_driver,__process_removed_driver

[cpp]  view plain copy
  1. __process_new_adapter -->i2c_do_add_adapter -->attach_adapter   
  2. __process_new_driver -->i2c_do_add_adapter -->attach_adapter  
  3.   
  4. __process_removed_adapter -->i2c_do_del_adapter -->detach_adapter  
  5. __process_removed_driver -->i2c_do_del_adapter -->detach_adapter  


七. i2c主机读写

     1.  发送i2c_master_send

[cpp]  view plain copy
  1. int i2c_master_send(struct i2c_client *client, const char *buf, int count)  
  2. {  
  3.     int ret;  
  4.     struct i2c_adapter *adap = client->adapter;  //获得i2c_adapter  
  5.     struct i2c_msg msg;  
  6.     msg.addr = client->addr; //设置i2c_msg的地址  
  7.     msg.flags = client->flags & I2C_M_TEN;   //设置标志  
  8.     msg.len = count;    //设置i2c_msg长度  
  9.     msg.buf = (char *)buf;  //设置i2c_msg缓冲区  
  10.     ret = i2c_transfer(adap, &msg, 1);  //调用i2c_transfer函数  
  11.     return (ret == 1) ? count : ret;  
  12. }  

     2. 接收i2c_master_recv

[cpp]  view plain copy
  1. int i2c_master_recv(struct i2c_client *client, char *buf, int count)  
  2. {  
  3.     struct i2c_adapter *adap = client->adapter;  //获得i2c_adapter  
  4.     struct i2c_msg msg;   
  5.     int ret;  
  6.     msg.addr = client->addr; //设置i2c_msg地址  
  7.     msg.flags = client->flags & I2C_M_TEN;   //设置标志  
  8.     msg.flags |= I2C_M_RD;  //设置标志为读  
  9.     msg.len = count;    //设置i2c_msg长度  
  10.     msg.buf = buf;  //设置i2c_msg缓冲区  
  11.     ret = i2c_transfer(adap, &msg, 1);  //调用i2c_transfer函数  
  12.     return (ret == 1) ? count : ret;  
  13. }  

     3. 控制

[cpp]  view plain copy
  1. static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,unsigned long arg)  
  2. {  
  3.     struct i2c_rdwr_ioctl_data rdwr_arg;  
  4.     struct i2c_msg *rdwr_pa;  
  5.     u8 __user **data_ptrs;  
  6.     int i, res;  
  7.   
  8.     if (copy_from_user(&rdwr_arg,(struct i2c_rdwr_ioctl_data __user *)arg,sizeof(rdwr_arg)))    //用户空间复制信息数据  
  9.         return -EFAULT;  
  10.     if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)        //最大支持同时发生1024个消息  
  11.         return -EINVAL;  
  12.     rdwr_pa = kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL); //分配i2c_msg数据内存  
  13.     if (!rdwr_pa)  
  14.         return -ENOMEM;  
  15.     if (copy_from_user(rdwr_pa, rdwr_arg.msgs,rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {   //用户空间复制i2c_msg数据  
  16.         kfree(rdwr_pa);  
  17.         return -EFAULT;  
  18.     }  
  19.     data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);  //分配临时数据内存  
  20.     if (data_ptrs == NULL) {  
  21.         kfree(rdwr_pa);  
  22.         return -ENOMEM;  
  23.     }  
  24.     res = 0;  
  25.     for (i = 0; i < rdwr_arg.nmsgs; i++) {  
  26.         if ((rdwr_pa[i].len > 8192) ||(rdwr_pa[i].flags & I2C_M_RECV_LEN)) { //判断i2c_msg数据长度和标志的合法性  
  27.             res = -EINVAL;  
  28.             break;  
  29.         }  
  30.         data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;  
  31.         rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len); //复制i2c_msg数据到rdwr_pa  
  32.         if (IS_ERR(rdwr_pa[i].buf)) {  
  33.             res = PTR_ERR(rdwr_pa[i].buf);  
  34.             break;  
  35.         }  
  36.     }  
  37.     if (res < 0) {  
  38.         int j;  
  39.         for (j = 0; j < i; ++j)  
  40.             kfree(rdwr_pa[j].buf);  
  41.         kfree(data_ptrs);  
  42.         kfree(rdwr_pa);  
  43.         return res;  
  44.     }  
  45.     res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);    //调用i2c_transfer函数传输i2c_msg  
  46.     while (i-- > 0) {  
  47.         if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {  
  48.             if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf,rdwr_pa[i].len))  //将数据复制到用户空间  
  49.                 res = -EFAULT;  
  50.         }  
  51.         kfree(rdwr_pa[i].buf);  
  52.     }  
  53.     kfree(data_ptrs);  
  54.     kfree(rdwr_pa);  
  55.     return res;  
  56. }  

     4. i2c_transfer函数

[cpp]  view plain copy
  1. int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)  
  2. {  
  3.     unsigned long orig_jiffies;  
  4.     int ret, try;  
  5.     if (adap->algo->master_xfer) {    //若适配器的算法结构体中定义了master_xfer方法  
  6.         if (in_atomic() || irqs_disabled()) {  
  7.             ret = i2c_trylock_adapter(adap);  
  8.             if (!ret)  
  9.                 return -EAGAIN;  
  10.         } else {  
  11.             i2c_lock_adapter(adap);  
  12.         }  
  13.         orig_jiffies = jiffies;  
  14.         for (ret = 0, try = 0; try <= adap->retries; try++) { //重试次数  
  15.             ret = adap->algo->master_xfer(adap, msgs, num);   //则调用其master_xfer方法  
  16.             if (ret != -EAGAIN)  
  17.                 break;  
  18.             if (time_after(jiffies, orig_jiffies + adap->timeout))   //开启超时定时器  
  19.                 break;  
  20.         }  
  21.         i2c_unlock_adapter(adap);  
  22.   
  23.         return ret;  
  24.     } else {  
  25.         dev_dbg(&adap->dev, "I2C level transfers not supported\n");  
  26.         return -EOPNOTSUPP;  
  27.     }  
  28. }  

 

八. i2c驱动编写

     1. 针对i2c适配器

定义i2c_adapter和对应的i2c_algorithm结构体,配置参数,然后调用i2c_add_adapter添加适配器

     2.针对i2c设备

驱动端:定义i2c_driver结构体,配置id_table等参数,调用i2c_add_driver

设备端:声明板级信息I2C_BOARD_INFO,并调用i2c_register_board_info注册,或者直接使用i2c_new_device函数

上面这种写法是做在内核层,一般的目的只是为了设备和驱动匹配而调用驱动的probe方法来做i2c设备的初始化工作

又或者是像ds1307-RTC等需要给系统提供接口,频繁操作的情况.

如果设备压根就不需要初始化,那么其实做在应用层,直接用操作/dev/i2c-X,操作适配器完成读写工作便可.


九. 应用层

     1.工具i2cdetect

[cpp]  view plain copy
  1. Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]  
  2.        i2cdetect -F I2CBUS  
  3.        i2cdetect -l //检测i2c适配器  
  4.   I2CBUS is an integer or an I2C bus name  
  5.   If provided, FIRST and LAST limit the probing range.  

    2. i2c读写工具(不支持smbus)

[cpp]  view plain copy
  1. #include <sys/types.h>  
  2. #include <fcntl.h>  
  3. #include <string.h>  
  4. #include <stdlib.h>  
  5. #include <stdio.h>  
  6. #include <linux/i2c.h>  
  7. #include <linux/i2c-dev.h>  
  8. //r devaddr reg value  
  9. //w devaddr reg value  
  10. int main(int argc ,char **argv){  
  11.     int fd=0;  
  12.     int status=0;  
  13.     struct i2c_rdwr_ioctl_data data;  
  14.     struct i2c_msg *msgs=NULL;  
  15.     unsigned int addr;  
  16.     unsigned char reg;  
  17.     unsigned char val;  
  18.     unsigned char buf[2];  
  19.     if(argc!=5)  
  20.     {  
  21.         printf("***********************************************\n");  
  22.         printf("*****        i2c read/write tool         ******\n");  
  23.         printf("*****read : r devaddr regaddr num        ******\n");  
  24.         printf("*****write: w devaddr regaddr val        ******\n");  
  25.         printf("*****             copyright by mahongbin ******\n");  
  26.         printf("***********************************************\n");  
  27.         printf("*****what the fuck of you !error command!******\n");  
  28.         return -1;  
  29.     }     
  30.     msgs=(struct i2c_msg *) malloc(sizeof(struct i2c_msg)*2);  
  31.     if(msgs==NULL){  
  32.         printf("malloc msgs error!\n");  
  33.         return -1;    
  34.     }  
  35.       
  36.     fd=open("/dev/i2c-2",O_RDWR);  
  37.     if(fd<0){  
  38.         printf("can not open i2c device!\n");  
  39.         return -1;  
  40.     }  
  41.   
  42.     addr=strtoul(argv[2],NULL,0);  
  43.     buf[0]=strtoul(argv[3],NULL,0);  
  44.     buf[1]=strtoul(argv[4],NULL,0);  
  45.   
  46. //write devaddr   
  47.   
  48.     //read register value  
  49.     if(strcmp(argv[1],"r")==0){  
  50.   
  51.         msgs[0].addr=addr;  
  52.         msgs[0].flags=0;  
  53.         msgs[0].len=1;  
  54.         msgs[0].buf=&buf[0];  
  55.       
  56.         msgs[1].addr=addr;  
  57.         msgs[1].flags=1;  
  58.         msgs[1].len=1;  
  59.         msgs[1].buf=&buf[1];  
  60.           
  61.         data.msgs=msgs;  
  62.         data.nmsgs=2;  
  63.         status=ioctl(fd,I2C_RDWR,&data);  
  64.         if(status<0){  
  65.             printf("i2c read  error!\n");         
  66.         }  
  67.         printf("[0x%02x]-(0x%02x)=0x%02x\n",addr,buf[0],buf[1]);  
  68.     }  
  69.     //write register   
  70.     else if(strcmp(argv[1],"w")==0){  
  71.           
  72.         msgs[0].addr=addr;  
  73.         msgs[0].flags=0;  
  74.         msgs[0].len=2;  
  75.         msgs[0].buf=&buf[0];  
  76.   
  77.         //msgs[1].addr=addr;  
  78.         //msgs[1].flags=0;  
  79.         //msgs[1].len=1;  
  80.         //msgs[1].buf=&buf[0];  
  81.   
  82.         data.msgs=msgs;  
  83.         data.nmsgs=1;  
  84.         status=ioctl(fd,I2C_RDWR,&data);  
  85.         if(status<0){  
  86.             printf("i2c write error2!\n");        
  87.         }  
  88.         printf("[0x%02x]-(0x%02x)=0x%02x\n",addr,buf[0],buf[1]);  
  89.     }  
  90.     else{  
  91.         printf("***********************************************\n");  
  92.         printf("*****        i2c read/write tool         ******\n");  
  93.         printf("*****read : r devaddr regaddr            ******\n");  
  94.         printf("*****write: w devaddr regaddr val        ******\n");  
  95.         printf("*****             copyright by mahongbin ******\n");  
  96.         printf("***********************************************\n");  
  97.     }  
  98.   
  99.     free(msgs);  
  100.     close(fd);  
  101.     return 0;  
  102. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值