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