linux i2c设备驱动 .

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


 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值