一. i2c的结构体
1. i2c适配器
- struct i2c_adapter {
- struct module *owner; //模块所有者
- unsigned int id __deprecated;
- unsigned int class; //支持的类别(I2C_CLASS_HWMON,I2C_CLASS_DDC,I2C_CLASS_SPD)
- const struct i2c_algorithm *algo; //i2c算法结构体
- void *algo_data;
- struct rt_mutex bus_lock;
- int timeout; //超时值默认是1s
- int retries; //通讯重试次数
- struct device dev; //设备文件
- int nr; //id号,次设备号
- char name[48]; //i2c适配器名
- struct completion dev_released;
- struct mutex userspace_clients_lock;
- struct list_head userspace_clients; //挂接的设备链表头
- };
2. i2c设备
- struct i2c_client {
- unsigned short flags; //标志(读/写)
- unsigned short addr; //i2c地址
- char name[I2C_NAME_SIZE]; //i2c设备名
- struct i2c_adapter *adapter; //匹配的i2c适配器
- struct i2c_driver *driver; //匹配的i2c驱动
- struct device dev; //设备文件
- int irq;
- struct list_head detected; //"检测到"链表头
- };
3. i2c驱动
- struct i2c_driver {
- unsigned int class;
- int (*attach_adapter)(struct i2c_adapter *); //连接i2c适配器
- int (*detach_adapter)(struct i2c_adapter *); //分离i2c适配器
- int (*probe)(struct i2c_client *, const struct i2c_device_id *); //probe方法
- int (*remove)(struct i2c_client *); //remove方法
- void (*shutdown)(struct i2c_client *); //关闭
- int (*suspend)(struct i2c_client *, pm_message_t mesg); //挂起
- int (*resume)(struct i2c_client *); //唤醒
- void (*alert)(struct i2c_client *, unsigned int data);
- int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
- struct device_driver driver; //设备驱动文件
- const struct i2c_device_id *id_table; //支持的i2c设备id表
- int (*detect)(struct i2c_client *, struct i2c_board_info *); //检测
- const unsigned short *address_list;
- struct list_head clients; //匹配的设备链表
- };
4. i2c板级信息
- struct i2c_board_info {
- char type[I2C_NAME_SIZE]; //设备名
- unsigned short flags; //标志(读/写)
- unsigned short addr; //i2c地址
- void *platform_data; //平台资源
- struct dev_archdata *archdata;
- #ifdef CONFIG_OF
- struct device_node *of_node;
- #endif
- int irq;
- };
4.1 i2c板级信息辅助宏(一般声明在板级初始化函数中)
- #define I2C_BOARD_INFO(dev_type, dev_addr) \
- .type = dev_type, .addr = (dev_addr)
5. i2c消息
- struct i2c_msg {
- __u16 addr; //i2c设备地址
- __u16 flags; //标志(读/写)
- __u16 len; //消息长度
- __u8 *buf; //缓冲区
- };
5.1 i2c读写控制数据结构体
- struct i2c_rdwr_ioctl_data {
- struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
- __u32 nmsgs; /* number of i2c_msgs */
- };
6. i2c算法
- struct i2c_algorithm {
- int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,int num); //主机传输方式
- int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,unsigned short flags, //smbus传输方式
- char read_write,u8 command, int size, union i2c_smbus_data *data);
- u32 (*functionality) (struct i2c_adapter *); //功能检测
- };
二. i2c总线,适配器,驱动,设备的初始化
1. i2c总线类型
- struct bus_type i2c_bus_type = {
- .name = "i2c",
- .match = i2c_device_match, //i2c设备与驱动匹配
- .probe = i2c_device_probe, //i2c设备probe方法
- .remove = i2c_device_remove, //移除
- .shutdown = i2c_device_shutdown, //关闭
- .pm = &i2c_device_pm_ops, //电源管理
- };
1.1 i2c设备与驱动的匹配i2c_device_match
- static int i2c_device_match(struct device *dev, struct device_driver *drv)
- {
- struct i2c_client *client = i2c_verify_client(dev); //根据设备文件获取i2c_client
- struct i2c_driver *driver;
- if (!client)
- return 0;
- if (of_driver_match_device(dev, drv)) //设备文件与设备驱动文件的匹配
- return 1;
- driver = to_i2c_driver(drv); //根据设备驱动文件获取i2c_driver
- if (driver->id_table) //i2c_driver的id_table存在
- return i2c_match_id(driver->id_table, client) != NULL; //匹配i2c_client和i2c_driver
- return 0;
- }
1.1.1 i2c_match_id函数
- static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,const struct i2c_client *client)
- {
- while (id->name[0]) { //判断i2c_driver->id_table->name数组中有与i2c_client->name相同的项没
- if (strcmp(client->name, id->name) == 0)
- return id;
- id++;
- }
- return NULL;
- }
1.2 i2c探测函数
- 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); //获得i2c_driver
- if (!driver->probe || !driver->id_table)
- return -ENODEV;
- client->driver = driver; //设置i2c_client->driver成员,i2c设备与驱动捆绑
- if (!device_can_wakeup(&client->dev)) //i2c设备支持唤醒
- device_init_wakeup(&client->dev,client->flags & I2C_CLIENT_WAKE); //则唤醒
- dev_dbg(dev, "probe\n");
- status = driver->probe(client, i2c_match_id(driver->id_table, client)); //调用i2c_driver->probe方法
- if (status) {
- client->driver = NULL;
- i2c_set_clientdata(client, NULL);
- }
- return status;
- }
2. i2c总线的注册
- static int __init i2c_init(void)
- {
- int retval;
- retval = bus_register(&i2c_bus_type);
- if (retval)
- return retval;
- #ifdef CONFIG_I2C_COMPAT
- i2c_adapter_compat_class = class_compat_register("i2c-adapter"); //创建"/sys/class/i2c-adapter"
- if (!i2c_adapter_compat_class) {
- retval = -ENOMEM;
- goto bus_err;
- }
- #endif
- retval = i2c_add_driver(&dummy_driver);
- if (retval)
- goto class_err;
- return 0;
- class_err:
- #ifdef CONFIG_I2C_COMPAT
- class_compat_unregister(i2c_adapter_compat_class);
- bus_err:
- #endif
- bus_unregister(&i2c_bus_type);
- return retval;
- }
3. i2c设备的初始化工作
- static int __init i2c_dev_init(void)
- {
- int res;
- printk(KERN_INFO "i2c /dev entries driver\n");
- res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops); //注册字符设备,#define I2C_MAJOR 89
- if (res)
- goto out;
- i2c_dev_class = class_create(THIS_MODULE, "i2c-dev"); //创建"/sys/class/i2c-dev"
- if (IS_ERR(i2c_dev_class)) {
- res = PTR_ERR(i2c_dev_class);
- goto out_unreg_chrdev;
- }
- res = i2c_add_driver(&i2cdev_driver); //注册i2c驱动 i2cdev_driver
- if (res)
- goto out_unreg_class;
- return 0;
- out_unreg_class:
- class_destroy(i2c_dev_class);
- out_unreg_chrdev:
- unregister_chrdev(I2C_MAJOR, "i2c");
- out:
- printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
- return res;
- }
3.1 i2c字符设备操作函数集
- static const struct file_operations i2cdev_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = i2cdev_read, //读
- .write = i2cdev_write, //写
- .unlocked_ioctl = i2cdev_ioctl, //控制
- .open = i2cdev_open, //打开
- .release = i2cdev_release, //释放
- };
3.1.1 打开i2c字符设备
- static int i2cdev_open(struct inode *inode, struct file *file)
- {
- unsigned int minor = iminor(inode); //根据节点获取次设备号
- struct i2c_client *client;
- struct i2c_adapter *adap;
- struct i2c_dev *i2c_dev;
- i2c_dev = i2c_dev_get_by_minor(minor); //根据次设备号获取i2c_dev
- if (!i2c_dev)
- return -ENODEV;
- adap = i2c_get_adapter(i2c_dev->adap->nr); //获取i2c_adapter
- if (!adap)
- return -ENODEV;
- client = kzalloc(sizeof(*client), GFP_KERNEL); //分配i2c_client内存
- if (!client) {
- i2c_put_adapter(adap);
- return -ENOMEM;
- }
- snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr); //修改i2c_client->name
- client->driver = &i2cdev_driver; //设置i2c_client->driver为i2cdev_driver
- client->adapter = adap; //设置i2c_client->adapter
- file->private_data = client; //将i2c_client放在文件的私有数据段
- return 0;
- }
3.1.2 读i2c字符设备
- static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count,loff_t *offset)
- {
- char *tmp;
- int ret;
- struct i2c_client *client = file->private_data; //从私有数据段取出i2c_client
- if (count > 8192)
- count = 8192;
- tmp = kmalloc(count, GFP_KERNEL); //分配临时缓冲区
- if (tmp == NULL)
- return -ENOMEM;
- pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",iminor(file->f_path.dentry->d_inode), count);
- ret = i2c_master_recv(client, tmp, count); //调用i2c_master_recv函数(见 七 详述)
- if (ret >= 0)
- ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret; //复制数据到用户空间
- kfree(tmp);
- return ret;
- }
3.1.3 写i2c字符设备
- static ssize_t i2cdev_write(struct file *file, const char __user *buf,size_t count, loff_t *offset)
- {
- int ret;
- char *tmp;
- struct i2c_client *client = file->private_data; //从私有数据段取出
- if (count > 8192)
- count = 8192;
- tmp = memdup_user(buf, count);
- if (IS_ERR(tmp))
- return PTR_ERR(tmp);
- pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",iminor(file->f_path.dentry->d_inode), count);
- ret = i2c_master_send(client, tmp, count); //i2c发送数据 (见 七 详述)
- kfree(tmp);
- return ret;
- }
3.1.4 控制i2c字符设备
- static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
- {
- struct i2c_client *client = file->private_data;
- unsigned long funcs;
- dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",cmd, arg);
- switch (cmd) {
- case I2C_SLAVE:
- case I2C_SLAVE_FORCE:
- if ((arg > 0x3ff) ||
- (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
- return -EINVAL;
- if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
- return -EBUSY;
- client->addr = arg;
- return 0;
- case I2C_TENBIT:
- if (arg)
- client->flags |= I2C_M_TEN;
- else
- client->flags &= ~I2C_M_TEN;
- return 0;
- case I2C_PEC:
- if (arg)
- client->flags |= I2C_CLIENT_PEC;
- else
- client->flags &= ~I2C_CLIENT_PEC;
- return 0;
- case I2C_FUNCS:
- funcs = i2c_get_functionality(client->adapter);
- return put_user(funcs, (unsigned long __user *)arg);
- case I2C_RDWR:
- return i2cdev_ioctl_rdrw(client, arg); //i2c读写命令 (第 七 详述)
- case I2C_SMBUS:
- return i2cdev_ioctl_smbus(client, arg); //i2c读写命令 SMBUS
- case I2C_RETRIES:
- client->adapter->retries = arg;
- break;
- case I2C_TIMEOUT:
- client->adapter->timeout = msecs_to_jiffies(arg * 10);
- break;
- default:
- return -ENOTTY;
- }
- return 0;
- }
3.2 i2cdev_driver驱动
- static struct i2c_driver i2cdev_driver = {
- .driver = {
- .name = "dev_driver",
- },
- .attach_adapter = i2cdev_attach_adapter, //连接适配器
- .detach_adapter = i2cdev_detach_adapter, //断开适配器
- };
三. i2c适配器的添加与删除
1. 添加适配器
- int i2c_add_adapter(struct i2c_adapter *adapter)
- {
- int id, res = 0;
- retry:
- if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) //根据idr机制获取适配器编号
- return -ENOMEM;
- mutex_lock(&core_lock);
- res = idr_get_new_above(&i2c_adapter_idr, adapter,__i2c_first_dynamic_bus_num, &id);
- mutex_unlock(&core_lock);
- if (res < 0) {
- if (res == -EAGAIN)
- goto retry;
- return res;
- }
- adapter->nr = id; //设置i2c_adapter->nr
- return i2c_register_adapter(adapter); //注册i2c_adapter
- }
1.1 i2c_register_adapter
- static int i2c_register_adapter(struct i2c_adapter *adap)
- {
- int res = 0;
- if (unlikely(WARN_ON(!i2c_bus_type.p))) {
- res = -EAGAIN;
- goto out_list;
- }
- 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); //初始化支持i2c_client链表头
- if (adap->timeout == 0)
- adap->timeout = HZ; //设置超时值
- dev_set_name(&adap->dev, "i2c-%d", adap->nr); //设置i2c_adapter->dev->name
- adap->dev.bus = &i2c_bus_type; //设置i2c_adapter->dev.bus为i2c_bus_type
- adap->dev.type = &i2c_adapter_type; //设置i2c_adapter->dev.type
- res = device_register(&adap->dev); //注册i2c_adapter的设备文件
- 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); //创建"/sys/class/i2c-adapter/i2c-XX"链接文件
- if (res)
- dev_warn(&adap->dev,"Failed to create compatibility class link\n");
- #endif
- if (adap->nr < __i2c_first_dynamic_bus_num) //__i2c_first_dynamic_bus_num数值在i2c_register_board_info中设置
- i2c_scan_static_board_info(adap); //扫描用板级声明的i2c设备并添加,后面细化
- mutex_lock(&core_lock); //遍历i2c_bus_type总线类型的设备文件,调用__process_new_adapter
- bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);//最终会调用i2c_driver->attach_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;
- }
这里还有一个函数可以添加适配器i2c_add_numbered_adapter原理一样.
2. 删除适配器
- int i2c_del_adapter(struct i2c_adapter *adap)
- {
- int res = 0;
- struct i2c_adapter *found;
- struct i2c_client *client, *next;
- mutex_lock(&core_lock);
- found = idr_find(&i2c_adapter_idr, adap->nr);
- mutex_unlock(&core_lock);
- if (found != adap) {
- pr_debug("i2c-core: attempting to delete unregistered adapter [%s]\n", adap->name);
- return -EINVAL;
- }
- mutex_lock(&core_lock); //遍历i2c_bus_type 总线类型的设备文件,调用__process_removed_adapter
- res = bus_for_each_drv(&i2c_bus_type, NULL, adap,__process_removed_adapter); //最终调用i2c_driver->detach_adapter
- mutex_unlock(&core_lock);
- if (res)
- return res;
- mutex_lock(&adap->userspace_clients_lock);
- list_for_each_entry_safe(client, next, &adap->userspace_clients,detected) { //遍历所有挂载适配器上的i2c设备
- dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name,client->addr);
- list_del(&client->detected); //移出"检测到"链表
- i2c_unregister_device(client); //注销i2c_client
- }
- mutex_unlock(&adap->userspace_clients_lock);
- res = device_for_each_child(&adap->dev, NULL, __unregister_client);
- #ifdef CONFIG_I2C_COMPAT
- class_compat_remove_link(i2c_adapter_compat_class, &adap->dev,adap->dev.parent); //删除"/sys/class/i2c-adapter/"的链接
- #endif
- dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
- init_completion(&adap->dev_released);
- device_unregister(&adap->dev); //注销设备文件
- wait_for_completion(&adap->dev_released);
- mutex_lock(&core_lock);
- idr_remove(&i2c_adapter_idr, adap->nr); //移除idr数值
- mutex_unlock(&core_lock);
- memset(&adap->dev, 0, sizeof(adap->dev));
- return 0;
- }
四. 添加删除i2c_driver
1. 添加i2c_driver
- static inline int i2c_add_driver(struct i2c_driver *driver)
- {
- return i2c_register_driver(THIS_MODULE, driver); //注册i2c_driver
- }
1.1 i2c_register_driver
- int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
- {
- int res;
- if (unlikely(WARN_ON(!i2c_bus_type.p)))
- return -EAGAIN;
- driver->driver.owner = owner; //设置驱动模块所有者
- driver->driver.bus = &i2c_bus_type; //设置设备驱动文件的总线类型为i2c_bus_type
- res = driver_register(&driver->driver); //注册设备驱动文件
- if (res)
- return res;
- pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
- INIT_LIST_HEAD(&driver->clients); //初始化i2c_driver支持i2c_client链表头
- mutex_lock(&core_lock); //遍历i2c_bus_type总线类型的设备文件,调用__process_new_driver函数
- bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver); //最终调用i2c_driver->attach_adapter
- mutex_unlock(&core_lock);
- return 0;
- }
2. 删除i2c_driver
- void i2c_del_driver(struct i2c_driver *driver)
- {
- mutex_lock(&core_lock); //遍历i2c_bus_type总线类型的设备文件,调用__process_removed_driver函数
- bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_removed_driver); //最终调用i2c_driver->detach_adapter
- mutex_unlock(&core_lock);
- driver_unregister(&driver->driver); //注销设备驱动文件
- pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
- }
五. 注册i2c板级信息
1. 注册板级i2c驱动
- 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; //设置全局变量__i2c_first_dynamic_bus_num
- 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; //设置devinfo
- devinfo->board_info = *info; //设置devinfo的板级别信息
- list_add_tail(&devinfo->list, &__i2c_board_list); //添加到全局__i2c_board_list链表中
- }
- up_write(&__i2c_board_lock);
- return status;
- }
这里有多少个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函数
- 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链表
- if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter,&devinfo->board_info))
- //匹配的i2c适配器下,添加devinfo的板级信息指定的i2c_device
- dev_err(&adapter->dev,"Can't create device at 0x%02x\n",devinfo->board_info.addr);
- }
- up_read(&__i2c_board_lock);
- }
3. 板级声明的i2c_client的注册
- 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); //分配i2c_client内存
- if (!client)
- return NULL;
- client->adapter = adap; //指定i2c_client的适配器
- client->dev.platform_data = info->platform_data; //设置i2c_client设备文件的平台数据
- if (info->archdata)
- client->dev.archdata = *info->archdata;
- client->flags = info->flags; //设置i2c_client->flags
- client->addr = info->addr; //设置i2c_client地址
- client->irq = info->irq; //设置i2c_client中断号
- strlcpy(client->name, info->type, sizeof(client->name)); //设置i2c_client->name
- status = i2c_check_client_addr_validity(client); //检测i2c_client地址合法性(0x01~0x7f)
- 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 = i2c_check_addr_busy(adap, client->addr); //检测地址是否给占用
- if (status)
- goto out_err;
- client->dev.parent = &client->adapter->dev; //设置i2c_client的父设备
- client->dev.bus = &i2c_bus_type; //设置i2c_client的总线类型
- client->dev.type = &i2c_client_type; //设置i2c_client的设备类型
- #ifdef CONFIG_OF
- client->dev.of_node = info->of_node;
- #endif
- dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),client->addr); //设置i2c_client设备文件的设备名
- 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, "Failed to register i2c client %s at 0x%02x(%d)\n", client->name, client->addr, status);
- out_err_silent:
- kfree(client);
- return NULL;
- }
六. attach和detach
1. 前面i2c_adapter和i2c_driver驱动添加和删除都会遍历i2c_bus_type总线类型的设备,然后调用各自的函数,__process_new_adapter,__process_removed_adapter,__process_new_driver,__process_removed_driver
- __process_new_adapter -->i2c_do_add_adapter -->attach_adapter
- __process_new_driver -->i2c_do_add_adapter -->attach_adapter
- __process_removed_adapter -->i2c_do_del_adapter -->detach_adapter
- __process_removed_driver -->i2c_do_del_adapter -->detach_adapter
七. i2c主机读写
1. 发送i2c_master_send
- int i2c_master_send(struct i2c_client *client, const char *buf, int count)
- {
- int ret;
- struct i2c_adapter *adap = client->adapter; //获得i2c_adapter
- struct i2c_msg msg;
- msg.addr = client->addr; //设置i2c_msg的地址
- msg.flags = client->flags & I2C_M_TEN; //设置标志
- msg.len = count; //设置i2c_msg长度
- msg.buf = (char *)buf; //设置i2c_msg缓冲区
- ret = i2c_transfer(adap, &msg, 1); //调用i2c_transfer函数
- return (ret == 1) ? count : ret;
- }
2. 接收i2c_master_recv
- int i2c_master_recv(struct i2c_client *client, char *buf, int count)
- {
- struct i2c_adapter *adap = client->adapter; //获得i2c_adapter
- struct i2c_msg msg;
- int ret;
- msg.addr = client->addr; //设置i2c_msg地址
- msg.flags = client->flags & I2C_M_TEN; //设置标志
- msg.flags |= I2C_M_RD; //设置标志为读
- msg.len = count; //设置i2c_msg长度
- msg.buf = buf; //设置i2c_msg缓冲区
- ret = i2c_transfer(adap, &msg, 1); //调用i2c_transfer函数
- return (ret == 1) ? count : ret;
- }
3. 控制
- static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,unsigned long arg)
- {
- struct i2c_rdwr_ioctl_data rdwr_arg;
- struct i2c_msg *rdwr_pa;
- u8 __user **data_ptrs;
- int i, res;
- if (copy_from_user(&rdwr_arg,(struct i2c_rdwr_ioctl_data __user *)arg,sizeof(rdwr_arg))) //用户空间复制信息数据
- return -EFAULT;
- if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) //最大支持同时发生1024个消息
- return -EINVAL;
- rdwr_pa = kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL); //分配i2c_msg数据内存
- if (!rdwr_pa)
- return -ENOMEM;
- if (copy_from_user(rdwr_pa, rdwr_arg.msgs,rdwr_arg.nmsgs * sizeof(struct i2c_msg))) { //用户空间复制i2c_msg数据
- kfree(rdwr_pa);
- return -EFAULT;
- }
- data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); //分配临时数据内存
- if (data_ptrs == NULL) {
- kfree(rdwr_pa);
- return -ENOMEM;
- }
- res = 0;
- for (i = 0; i < rdwr_arg.nmsgs; i++) {
- if ((rdwr_pa[i].len > 8192) ||(rdwr_pa[i].flags & I2C_M_RECV_LEN)) { //判断i2c_msg数据长度和标志的合法性
- res = -EINVAL;
- break;
- }
- data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
- rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len); //复制i2c_msg数据到rdwr_pa
- if (IS_ERR(rdwr_pa[i].buf)) {
- res = PTR_ERR(rdwr_pa[i].buf);
- break;
- }
- }
- if (res < 0) {
- int j;
- for (j = 0; j < i; ++j)
- kfree(rdwr_pa[j].buf);
- kfree(data_ptrs);
- kfree(rdwr_pa);
- return res;
- }
- res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs); //调用i2c_transfer函数传输i2c_msg
- while (i-- > 0) {
- if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {
- if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf,rdwr_pa[i].len)) //将数据复制到用户空间
- res = -EFAULT;
- }
- kfree(rdwr_pa[i].buf);
- }
- kfree(data_ptrs);
- kfree(rdwr_pa);
- return res;
- }
4. i2c_transfer函数
- int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
- {
- unsigned long orig_jiffies;
- int ret, try;
- if (adap->algo->master_xfer) { //若适配器的算法结构体中定义了master_xfer方法
- if (in_atomic() || irqs_disabled()) {
- ret = i2c_trylock_adapter(adap);
- if (!ret)
- return -EAGAIN;
- } else {
- i2c_lock_adapter(adap);
- }
- orig_jiffies = jiffies;
- for (ret = 0, try = 0; try <= adap->retries; try++) { //重试次数
- ret = adap->algo->master_xfer(adap, msgs, num); //则调用其master_xfer方法
- if (ret != -EAGAIN)
- break;
- if (time_after(jiffies, orig_jiffies + adap->timeout)) //开启超时定时器
- break;
- }
- i2c_unlock_adapter(adap);
- return ret;
- } else {
- dev_dbg(&adap->dev, "I2C level transfers not supported\n");
- return -EOPNOTSUPP;
- }
- }
八. 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
- Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]
- i2cdetect -F I2CBUS
- i2cdetect -l //检测i2c适配器
- I2CBUS is an integer or an I2C bus name
- If provided, FIRST and LAST limit the probing range.
2. i2c读写工具(不支持smbus)
- #include <sys/types.h>
- #include <fcntl.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <linux/i2c.h>
- #include <linux/i2c-dev.h>
- //r devaddr reg value
- //w devaddr reg value
- int main(int argc ,char **argv){
- int fd=0;
- int status=0;
- struct i2c_rdwr_ioctl_data data;
- struct i2c_msg *msgs=NULL;
- unsigned int addr;
- unsigned char reg;
- unsigned char val;
- unsigned char buf[2];
- if(argc!=5)
- {
- printf("***********************************************\n");
- printf("***** i2c read/write tool ******\n");
- printf("*****read : r devaddr regaddr num ******\n");
- printf("*****write: w devaddr regaddr val ******\n");
- printf("***** copyright by mahongbin ******\n");
- printf("***********************************************\n");
- printf("*****what the fuck of you !error command!******\n");
- return -1;
- }
- msgs=(struct i2c_msg *) malloc(sizeof(struct i2c_msg)*2);
- if(msgs==NULL){
- printf("malloc msgs error!\n");
- return -1;
- }
- fd=open("/dev/i2c-2",O_RDWR);
- if(fd<0){
- printf("can not open i2c device!\n");
- return -1;
- }
- addr=strtoul(argv[2],NULL,0);
- buf[0]=strtoul(argv[3],NULL,0);
- buf[1]=strtoul(argv[4],NULL,0);
- //write devaddr
- //read register value
- if(strcmp(argv[1],"r")==0){
- msgs[0].addr=addr;
- msgs[0].flags=0;
- msgs[0].len=1;
- msgs[0].buf=&buf[0];
- msgs[1].addr=addr;
- msgs[1].flags=1;
- msgs[1].len=1;
- msgs[1].buf=&buf[1];
- data.msgs=msgs;
- data.nmsgs=2;
- status=ioctl(fd,I2C_RDWR,&data);
- if(status<0){
- printf("i2c read error!\n");
- }
- printf("[0x%02x]-(0x%02x)=0x%02x\n",addr,buf[0],buf[1]);
- }
- //write register
- else if(strcmp(argv[1],"w")==0){
- msgs[0].addr=addr;
- msgs[0].flags=0;
- msgs[0].len=2;
- msgs[0].buf=&buf[0];
- //msgs[1].addr=addr;
- //msgs[1].flags=0;
- //msgs[1].len=1;
- //msgs[1].buf=&buf[0];
- data.msgs=msgs;
- data.nmsgs=1;
- status=ioctl(fd,I2C_RDWR,&data);
- if(status<0){
- printf("i2c write error2!\n");
- }
- printf("[0x%02x]-(0x%02x)=0x%02x\n",addr,buf[0],buf[1]);
- }
- else{
- printf("***********************************************\n");
- printf("***** i2c read/write tool ******\n");
- printf("*****read : r devaddr regaddr ******\n");
- printf("*****write: w devaddr regaddr val ******\n");
- printf("***** copyright by mahongbin ******\n");
- printf("***********************************************\n");
- }
- free(msgs);
- close(fd);
- return 0;
- }