现在的位置: 首页 > 综合 > 正文

基于Linux内核的IIC驱动

2014年05月30日 ⁄ 综合 ⁄ 共 3693字 ⁄ 字号 评论关闭

#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);
}



抱歉!评论已关闭.