1.在设备树上对应的i2c接口编写设备节点信息
2.写驱动
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#define MAJORNO 1890
#define COUNT 1
#define address_W 0xa0 //从机的地址和写入标志
#define address_R 0xa1 //从机的地址和读取标志
static DEFINE_SPINLOCK(my_lock);
typedef struct {
struct mutex mutex;
struct cdev cdev;
struct i2c_client *client;
struct class *class;
}vintouch_data_t;
//read is OK
ssize_t vintouch_read(struct file *fip,char __user *buff,size_t count ,loff_t *offp)
{
struct cdev *cdev = fip->f_path.dentry->d_inode->i_cdev;
vintouch_data_t *data = container_of(cdev,vintouch_data_t,cdev);
int ret,sum,i;
struct i2c_msg msgs[2];
if(count < 1) {
printk("read error length\n");
return -EINVAL;
}
char data_rcv[count];
struct i2c_client *client = data->client;
char addr[1] = {address_R};
mutex_lock(&data->mutex);
msgs[0].addr = client->addr;
msgs[0].flags = 0;
msgs[0].len = 1;
msgs[0].buf = addr;
msgs[1].addr = client->addr;
msgs[1].flags = I2C_M_RD;
msgs[1].len = count;
msgs[1].buf = data_rcv;
ret = i2c_transfer(client->adapter,msgs,2);
udelay(100);
if(ret != 2) goto out;
if(copy_to_user(buff,data_rcv,count)){
ret = -EFAULT;
goto out;
}
*offp += count;
ret = count;
out:
mutex_unlock(&data->mutex);
return ret;
}
ssize_t vintouch_write(struct file *fip,const char __user *buff,size_t count ,loff_t *offp )
{
struct cdev *cdev = fip->f_path.dentry->d_inode->i_cdev;
vintouch_data_t *data = container_of(cdev,vintouch_data_t,cdev);
int ret,sum,i;
struct i2c_msg msgs;
if(count < 1){
printk("write error length\n");
return -EINVAL;
}
char data_snd[count+1];
data_snd[0] = address_W;
if(copy_from_user(&data_snd[1],buff,count)){
ret = -EFAULT;
goto out;
}
printk("send buf:");
for(i =0;i < count +1;i++)
{
printk("%x ",data_snd[i]);
}
printk("\n");
struct i2c_client *client = data->client;
mutex_lock(&data->mutex);
msgs.addr = client->addr;
msgs.flags = 0;
msgs.len = count +1;
msgs.buf = data_snd;
ret = (i2c_transfer(client->adapter,&msgs,1) == 1) ? 0 : -1;
mutex_unlock(&data->mutex);
udelay(100);
out:
return ret;
}
struct file_operations fops = {
.owner = THIS_MODULE,
.read = vintouch_read,
.write = vintouch_write,
};
/*After kernel3.8, __devexit __devexit_p已从内核中移除 */
static int vintouch_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
static int minorNo = 0;
vintouch_data_t *data;
dev_t devid;
int ret;
devid = MKDEV(MAJORNO,minorNo);
printk("device name is %s\n",client->name);
ret = register_chrdev_region(devid,COUNT,client->name);
if(ret < 0){
printk("register failed\n");
goto err0;
}
data = kzalloc(sizeof(*data),GFP_KERNEL);
if(data == NULL){
printk("kzalloc error!\n");
ret = -ENOMEM;
goto err1;
}
cdev_init(&data->cdev,&fops);
data->cdev.owner =THIS_MODULE;
ret = cdev_add(&data->cdev,devid,COUNT);
if(ret < 0){
printk("cdev_add error!\n");
goto err2;
}
mutex_init(&data->mutex);
data->class = class_create(THIS_MODULE,client->name);
device_create(data->class,NULL,devid,NULL,"%s%d",client->name,minorNo++);
data->client = client;
i2c_set_clientdata(client,data);
printk("add device successfully!\n");
//dev_set_drvdata(&cli->dev, data);
return 0;
err2:
kfree(data);
err1:
unregister_chrdev_region(devid,COUNT);
err0:
return ret;
}
static int vintouch_i2c_driver_remove(struct i2c_client *client)
{
printk("remove!\n");
//dev_get_drvdata(&cli->dev);
vintouch_data_t *data = i2c_get_clientdata(client);
device_destroy(data->class,data->cdev.dev);
class_destroy(data->class);
cdev_del(&data->cdev);
unregister_chrdev_region(data->cdev.dev,COUNT);
kfree(data);
return 0;
}
static const struct i2c_device_id vintouch_i2c_driver_id[] ={
{"vintouch",0},
{}
};
MODULE_DEVICE_TABLE(i2c,vintouch_i2c_driver_id);
int vintouch_i2c_driver_detect(struct i2c_client *client,struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
int vendor,device,revision;
if(!i2c_check_functionality(adapter,I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV;
//Couldn't get the boardinfo
//if(i2c_smbus_read_byte_data(client,XXXX_CHIP_ID_RED) != XXXX_CHIP_ID) return -ENODEV;
const char *type_name = "vintouch";
strlcpy(info->type,type_name,I2C_NAME_SIZE);
return 0;
}
static const unsigned short normal_i2c[]={0x50,I2C_CLIENT_END};
static struct i2c_driver vintouch_i2c_driver = {
.class = I2C_CLASS_HWMON,
.probe = vintouch_i2c_probe,
.remove = vintouch_i2c_driver_remove,
.id_table = vintouch_i2c_driver_id,
.driver = {
.name = "vintouch",
.owner = THIS_MODULE,
},
.detect = vintouch_i2c_driver_detect,
.address_list = normal_i2c,
};
static int __init vintouch_init(void)
{
printk("init successfully!\n");
return i2c_add_driver(&vintouch_i2c_driver);
}
static void __exit vintouch_release(void)
{
i2c_del_driver(&vintouch_i2c_driver);
printk("release successfully!\n");
}
module_init(vintouch_init);
module_exit(vintouch_release);
MODULE_LICENSE("GPL");
3.编译驱动
4.运行
insmod vintouch.ko
5.设备节点为
/dev/vintouch0
6.测试驱动
自己写个应用程序,打开设备节点 open read write即可