#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
MODULE_LICENSE("GPL");
dev_t dev;
struct at24cxx_dev
{
struct i2c_client *client;
struct cdev cdev;
};
struct at24cxx_dev *at24cxx_devp = NULL;
static struct class *dev_class = NULL;
static struct device *dev_device = NULL;
/*本driver所支持的client列表*/
static const struct i2c_device_id at24cxx_id[]=
{
{"at24cxx",0},
{} /*结束标志*/
};
static ssize_t at24cxx_read(struct file *file, char __user *buf,
size_t size, loff_t *offset)
{
unsigned char address;
unsigned char data;
struct i2c_msg msg[2];
if(size != 1)
{
return -EINVAL;
}
/*从用户空间拷贝要读设备的偏移值*/
copy_from_user(&address, buf, 1);
/*数据传输三要素:源 目的 长度*/
/*i2c总线上从设备地址即目的地址*/
msg[0].addr = at24cxx_devp->client->addr;
msg[0].buf = &address;
msg[0].len = 1;
msg[0].flags = 0;/*表示写入*/
msg[1].addr = at24cxx_devp->client->addr;
msg[1].buf = &data;
msg[1].len = 1;
msg[1].flags = 1;/*表示读*/
/*
* adapter,有一条I2C总线就对应有一个adapter
* msgs,消息内容地址
* num,消息个数
* 该函数封装了START ... ACK... ACK...START...STOP
*/
i2c_transfer(at24cxx_devp->client->adapter,
msg, 2);
copy_to_user(buf, &data, 1);
return 1;
}
static ssize_t at24cxx_write(struct file *file, const char __user *buf,
size_t size, loff_t *offset)
{
struct i2c_msg msg[1];
unsigned char val[2];
int ret;
if(size != 2)
{
return -EINVAL;
}
/*用户空间传入了要写芯片内的偏移
*地址,和相应的值
*/
copy_from_user(val, buf, 2);
msg[0].addr = at24cxx_devp->client->addr;/*从设备地址*/
msg[0].buf = val;/*偏移地址 + 写入的值*/
msg[0].len = 2;/*buf所指向的缓冲区包含的数据长度*/
msg[0].flags = 0;/*表示写入*/
ret = i2c_transfer(at24cxx_devp->client->adapter,
msg,1);
if(ret == 1)
{
return 2;
}
else
{
return -EIO;
}
}
static struct file_operations at24cxx_fops =
{
.owner = THIS_MODULE,
.read = at24cxx_read,
.write = at24cxx_write,
};
static int at24cxx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
/*1 注册设备号*/
alloc_chrdev_region(&dev,0,1,"at24cxx");
/*2 申请cdev空间*/
at24cxx_devp = kmalloc(sizeof(struct at24cxx_dev), GFP_KERNEL);
memset(at24cxx_devp, 0, sizeof(struct at24cxx_dev));
/*3 配置*/
at24cxx_devp->client = client;
/*4 添加cdev到内核*/
cdev_init(&(at24cxx_devp->cdev),&at24cxx_fops);
cdev_add(&(at24cxx_devp->cdev),dev,1);
/*5 创建设备节点文件*/
dev_class = class_create(THIS_MODULE, "AT24CXX");
dev_device = device_create(dev_class, NULL, dev, NULL,
"at24cxx%d",MINOR(dev));
return 0;
}
static int at24cxx_remove(struct i2c_client *client)
{
device_destroy(dev_class,dev);
class_destroy(dev_class);
cdev_del(&(at24cxx_devp->cdev));
kfree(at24cxx_devp);
unregister_chrdev_region(dev,1);
return 0;
}
static struct i2c_driver at24cxx_driver =
{
.driver =
{
.name = "at24cxx",
.owner = THIS_MODULE,
},
.probe = at24cxx_probe,
.remove = at24cxx_remove,
/*i2c match 会用到*/
.id_table = at24cxx_id,
};
static int __init at24cxx_init(void)
{
/*向I2C CORE添加driver*/
i2c_add_driver(&at24cxx_driver);
return 0;
}
static void __exit at24cxx_exit(void)
{
/*删除driver*/
i2c_del_driver(&at24cxx_driver);
}
module_init(at24cxx_init);
module_exit(at24cxx_exit);