i2c驱动

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即可

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值