基于Linux内核的IIC驱动


此例是在一个模块中注册了设备和驱动,可以作为一个快速调试i2c的模块来用;
 但在一般工程中,有两种实现方法:
 1,在 drivers/i2c/chips/下创建一个i2c设备,生成一个i2c_client,然后 EXPORT_SYMBOL()导出,在其他地方直接使用,也就是读写操作;
 2,在 arch/arm/boot/dts 下创建一个i2c设备,然后在某个地方使用i2c,创建i2c_driver,然后注册i2c_add_driver,这样就会在 下找到i2c设备,然后调用i2c_probe;

#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>


//分配初始化设备ID信息
static struct i2c_device_id at24c02_id[] = {
{"at24c02", 0} //这个名称很重要,用于匹配
};


static struct i2c_client *g_client;


static int major;
static struct class *cls;


/*
unsigned char addr = 0x10;
unsigned char buf[2];
buf[0] = addr;
read(fd, buf, 1);
*/
static ssize_t at24c02_read(struct file *file,
char __user *buf,
size_t count,
loff_t *ppos)
{
/*1.获取用户要访问的地址内容*/
unsigned char addr;
unsigned char data;
unsigned char buffer[2];


copy_from_user(&addr, buf, 1);


/*2.利用SMBUS协议提供的访问接口,将地址信息
传递给I2C总线驱动实现数据传输。SMBUS协议
规定的操作接口和使用方法参看文档:
smbus-protocol,还要利用匹配成功的i2c_client,
因为i2c_client中有总线驱动的信息还有
设备地址信息
*/
data = i2c_smbus_read_byte_data(g_client, addr);
if (data < 0) {
printk("read error!\n");
return -EIO;
} else {
copy_to_user(buf, &data, 1);
}
return count;
}


/*
unsigned char buf[2];
buf[0] = 0x10;
buf[1] = 89;
write(fd, buf, 2);
*/
static ssize_t at24c02_write(struct file *file,
const char __user *buf,
size_t count,
loff_t *ppos)
{
/*1.获取用户要操作的地址和数据*/
unsigned char buffer[2];
unsigned char addr;
unsigned char data;
int ret;

copy_from_user(buffer, buf, 2);
addr = buffer[0];
data = buffer[1];

/*2.利用SMBUS协议提供的访问接口,将地址信息
传递给I2C总线驱动实现数据传输。SMBUS协议
规定的操作接口和使用方法参看文档:
smbus-protocol,还要利用匹配成功的i2c_client,
因为i2c_client中有总线驱动的信息还有
设备地址信息
*/
ret = i2c_smbus_write_byte_data(g_client, addr, data);
if (ret < 0)
return -EIO;

return count;
}


//驱动操作集合
static struct file_operations at24c02_fops = {
.owner = THIS_MODULE, 
.read = at24c02_read,
.write = at24c02_write
};


//如果一旦匹配成功,调用probe函数
//client指针指向匹配成功的设备结构i2c_client,
//可以从中获取总线驱动和设备地址等信息
static int at24c02_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
//注册字符设备驱动
major = register_chrdev(major, "at24c02",
&at24c02_fops);


//自动创建设备节点
cls = class_create(THIS_MODULE, "at24c02");
device_create(cls, NULL, MKDEV(major, 0),
NULL, "at24c02");
return 0;
}


static int at24c02_remove(struct i2c_client *client)
{
/*1.删除设备节点*/
device_destroy(cls, MKDEV(major, 0));
class_destroy(cls);


unregister_chrdev(major, "at24c02");
return 0;
}


//分配初始化i2c_driver
static struct i2c_driver at24c02_drv = {
.driver = {
.owner = THIS_MODULE,
.name = "tarena"
},
.probe = at24c02_probe,
.remove = at24c02_remove,
.id_table = at24c02_id
};


static int at24c02_init(void)
{
//存放at24c02设备信息
struct i2c_board_info info;
//获取总线驱动信息
struct i2c_adapter *adapter;

/*1.注册i2c_driver*/
/*1.1向总线的drv链表添加节点*/
/*1.2遍历dev链表,取出i2c_client,进行匹配*/
i2c_add_driver(&at24c02_drv);


/*2.采用内核方法2来实现i2c_client*/
/*2.1初始化at24c02的硬件信息*/
memset(&info, 0, sizeof(info));
//指定设备名称,很重要,匹配靠它
strlcpy(info.type, "at24c02", I2C_NAME_SIZE);
//指定设备地址
info.addr = 0x50;


/*2.2 获取总线驱动信息*/
//参数是at24c02设备所在的总线编号,看原理图
adapter = i2c_get_adapter(0); 


/*3.实例化i2c_client(分配,初始化,注册)*/
/*3.1 添加节点i2c_client到dev链表*/
/*3.2 遍历drv链表,进行匹配,如果匹配成功,
调用i2c_driver.probe函数,并且
将注册的i2c_client指针给probe函数
*/
g_client = i2c_new_device(adapter, &info);

return 0;
}


static void at24c02_exit(void)
{
//卸载
i2c_del_driver(&at24c02_drv);
//释放i2c_client
i2c_unregister_device(g_client);
}


module_init(at24c02_init);
module_exit(at24c02_exit);

MODULE_LICENSE("GPL v2");

**************************************************************************************

                                             测试代码:

**************************************************************************************

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


/*
./at24c02_test r 0x10 
./at24c02_test w 0x10 97
*/
int main(int argc, char *argv[])
{
unsigned char buf[2];
int fd;


if((argc != 3) && (argc != 4)) {
printf("usage:\n %s r addr\n", argv[0]);
printf("%s w addr data\n", argv[0]);
return -1;
}


fd = open("/dev/at24c02", O_RDWR);
if (fd < 0) {
printf("open at24c02 failed.\n");
return -1;
}


if (strcmp(argv[1], "r") == 0) {
buf[0] = strtoul(argv[2], NULL, 0);
read(fd, &buf[0], 1);
printf("data: %c %d %#x\n", buf[0], buf[0],
buf[0]);
} else if (strcmp(argv[1], "w") == 0) {
buf[0] = strtoul(argv[2], NULL, 0);
buf[1] = strtoul(argv[3], NULL, 0);
write(fd, buf, 2);
}
close(fd);
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值