一. 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; }