Linux I2C驱动分析与实现(二)

====本文系本站原创,欢迎转载! 转载请注明出处:http://blog.csdn.net/yyplc====
通过上篇《Linux I2C驱动分析与实现(二)》,我们对Linux子系统已经不陌生,那么如何实现I2C驱动呢?

编写客户驱动的方法

在内核中有两种方式的i2c客户驱动的编写方法,一种叫legacy传统方式,另一种是newstyle方式. 前

一种legacy是一种旧式的方法,在2.6内核以后的标准驱动模型编写中逐渐被newstyle方式取代。本文编程实例是基于newstyle方式的来实现at24c02的驱

动。

客户驱动程序开发的一般步骤

(1)注册板载i2c设备信息

 

(2)定义i2c驱动设备id

 

(3)定义i2c_driver结构并完成其相应函数

 

(4)模块初始化时添加/撤销时删除i2c_driver

 

(5)/dev  entry 访问方法 /sysfs访问方法

 

客户设备驱动开发实例

内核为linux-2.6.30.4

基于arm9 S3c2440平台

开发一个at24c02 eeprom的客户驱动

开发一个应用程序访问I2C设备

-----------------------------------------------------------------

根据开发客户驱动程序步骤实现对i2c设备at24c02的读写操作。

(分析at24c02 datasheet)

(1)注册板载信息

mach-smdk2440.c文件中静态声明一个I2C设备

static struct i2c_board_info i2c_devices[] __initdata = {

    {I2C_BOARD_INFO("24c02", 0x50), },

     {}

};

smdk2440_machine_init()函数中,向总线注册I2C设备信息:

i2c_register_board_info(0,i2c_devices,ARRAY_SIZE(i2c_devices));

(2)定义i2c驱动设备id:

static struct i2c_device_id foo_idtable[] = {

    { “24c01", 0x51 },

    {“20402”,0x50 },

    {}

};

(3)定义i2c_driver结构并完成其相应函数:

static struct i2c_driver my_i2c_driver = {

    .driver = {

      .name = "i2c_demo",

      .owner = THIS_MODULE,

    },

    .probe = my_i2c_probe,

    .remove = my_i2c_remove,

    .id_table = my_ids,

};

(4)模块初始化时添加/撤销时删除i2c_driver

static int __init  my_i2c_client(void)

{

   return i2c_add_driver(&my_i2c_driver);

}

static void __exit my_i2c_exit(void)

{

   i2c_del_driver(&my_i2c_driver);

}

(5)使用/dev entry 访问方法

注册字符设备

register_chrdev(I2C_MAJOR,DEVICE_NAME,&i2c_fops);

创建类class_create(THIS_MODULE, DEVICE_NAME);

在/dev下创建设备节点

device_create(my_dev_class, &client->dev,MKDEV(I2C_MAJOR, 0), NULL, DEVICE_NAME);


"实现代码附件下载",有需要请留言,邮件发~

谁能告诉我csdn为什么不可以上传附件?


代码测试结果:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/smp_lock.h>
#include <linux/jiffies.h>
#include <asm/uaccess.h>
#include <linux/delay.h>


#define DEBUG 1
#ifdef DEBUG
#define dbg(x...) printk(x)
#else 
#define dbg(x...) (void)(0)
#endif

#define I2C_MAJOR 89
#define DEVICE_NAME "at24c02"
static struct class *my_dev_class;
static struct i2c_client *my_client;
static struct i2c_driver my_i2c_driver;


static struct i2c_device_id my_ids[] = {
	{"24c01",0x50},
	{"24c02",0x50},
	{"24c08",0x50},
	{}
};

MODULE_DEVICE_TABLE(i2c,my_ids);

static int my_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	int res;
	struct device *dev;

	dbg("probe:name = %s,flag =%d,addr = %d,adapter = %d,driver = %s\n",client->name,
		 client->flags,client->addr,client->adapter->nr,client->driver->driver.name );

	dev = device_create(my_dev_class, &client->dev,
				     MKDEV(I2C_MAJOR, 0), NULL,
				     DEVICE_NAME);
	if (IS_ERR(dev))
	{
		dbg("device create error\n");
		goto out;
	}
	my_client = client;
	
	return 0;
out:
	return -1;
}
static int  my_i2c_remove(struct i2c_client *client)
{

	dbg("remove\n");
	return 0;
}

static ssize_t at24c02_read(struct file *fd, char *buf, ssize_t count, loff_t *offset)
{
	char *tmp;
	int ret;
	char data_byte;
	char reg_addr = 0,i;
	struct i2c_client *client = (struct i2c_client*) fd->private_data;
	struct i2c_msg msgs[2];

	dbg("read:count = %d,offset = %ld\n",count,*offset);
	tmp = kmalloc(count,GFP_KERNEL);

	if (!tmp)
	{
		dbg("malloc error in read function\n");
		goto out;
	}

	reg_addr = *offset;
	msgs[0].addr = client->addr;
	msgs[0].flags = client->flags & (I2C_M_TEN|I2C_CLIENT_PEC) ;
	msgs[0].len = 1;
	msgs[0].buf = (char *)®_addr;
	
	msgs[1].addr= client->addr;
	msgs[1].flags = client->flags & (I2C_M_TEN|I2C_CLIENT_PEC);
	msgs[1].flags |= I2C_M_RD;
	msgs[1].len = count;
	msgs[1].buf = (char*)tmp;

	ret = i2c_transfer(client->adapter,&msgs,2);
	if (ret != 2)
		goto out;
	if (copy_to_user(buf, tmp, count))
		goto out;
	
	kfree(tmp);
	return count;
out:
	kfree(tmp);
	return -1;	
	
}


static int at24c02_ioctl(struct file *fd, unsigned int cmd, unsigned long arg)
{
	dbg("ioctl code ...\n");
	return 0;
}

static ssize_t at24c02_write(struct file *fd, char *buf, ssize_t count, loff_t *offset)
{
	int ret,i;
	char *tmp;
	int errflg;
	struct i2c_msg msg;
 	struct i2c_client *client = (struct i2c_client*) fd->private_data;
	char tmp_data[2];

 	dbg("write:count = %d,offset = %ld\n",count,*offset);
	tmp = kmalloc(count, GFP_KERNEL);
	if (!tmp)
		goto out;
	if (copy_from_user(tmp, buf, count))
		goto out;
	msg.addr = client->addr;
	msg.flags = client->flags & (I2C_M_TEN | I2C_CLIENT_PEC);
	for (i = 0; i < count; i++) {
		msg.len = 2;
		tmp_data[0] = *offset + i;
		tmp_data[1] = tmp[i];
		msg.buf = tmp_data;
		ret = i2c_transfer(client->adapter,&msg,1);
		if (ret != 1)
			goto out;
		msleep(1);
	} 
	kfree(tmp);

	return ((ret == 1) ? count:ret);
out:
	kfree(tmp);
	return -1;
	
}
static int at24c02_open(struct inode *inode, struct file *fd)
{

	fd->private_data =(void*)my_client;
	return 0;

}

static int at24c02_release(struct inode *inode, struct file *fd)
{
	dbg("release\n");
	fd->private_data = NULL;
	
	return 0;	

}

static const struct file_operations i2c_fops = {
	.owner = THIS_MODULE,
	.open 	= at24c02_open,
	.read  = at24c02_read,
	.write = at24c02_write,
	.unlocked_ioctl = at24c02_ioctl,
	.release = at24c02_release,
};

static struct i2c_driver my_i2c_driver = {
	.driver = {
		.name = "i2c_demo",
		.owner = THIS_MODULE,
	},
	.probe = my_i2c_probe,
	.remove = my_i2c_remove,
	.id_table = my_ids,
};

static int __init my_i2c_init(void)
{
	int res;
	
	
	res = register_chrdev(I2C_MAJOR,DEVICE_NAME,&i2c_fops);
	if (res)
	{
		dbg("register_chrdev error\n");
		return -1;
	}
	my_dev_class = class_create(THIS_MODULE, DEVICE_NAME);
	if (IS_ERR(my_dev_class))
	{
		dbg("create class error\n");
		unregister_chrdev(I2C_MAJOR, DEVICE_NAME);
		return -1;
	}
	return i2c_add_driver(&my_i2c_driver);
}

static void __exit my_i2c_exit(void)
{
	unregister_chrdev(I2C_MAJOR, DEVICE_NAME);
	class_destroy(my_dev_class);
	i2c_del_driver(&my_i2c_driver);
	
}

MODULE_AUTHOR("itspy<itspy.wei@gmail.com>");
MODULE_DESCRIPTION("i2c client driver demo");
MODULE_LICENSE("GPL");
module_init(my_i2c_init);
module_exit(my_i2c_exit);

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值