Chinaunix首页 | 论坛 | 博客
  • 博客访问: 542465
  • 博文数量: 252
  • 博客积分: 1068
  • 博客等级: 少尉
  • 技术积分: 1775
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-05 21:33
文章分类

全部博文(252)

文章存档

2013年(21)

2012年(231)

分类:

2012-07-12 16:14:12

原文地址:I2c设备的读写 作者:sparkle-cliz

一,为了方便i2c设备的调试,我写了一个I2c设备的读写驱动及其应用程序。

(基于TCC8900 + linux-2.6.28

二,驱动:

#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <bsp.h>
#include <asm/io.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/spinlock.h>
#include <linux/cdev.h>

#define I2C_ACCESS_CTRL_MAJOR            207
#define IOCTL_I2C_WRITE        _IO(I2C_ACCESS_CTRL_MAJOR, 1)
#define IOCTL_I2C_READ        _IO(I2C_ACCESS_CTRL_MAJOR, 2)

static struct class * cls_i2c_access;
struct i2c_access_dev {
    struct cdev cdev;
};
static struct i2c_access_dev * i2c_devp;

struct i2c_client * i2c_access_client = NULL;
static struct i2c_driver i2c_access_driver;
#define SENSOR_DEVICE_I2C 0x45
static unsigned short probe[] = { 0, SENSOR_DEVICE_I2C, I2C_CLIENT_END };
static unsigned short dummy[] = {I2C_CLIENT_END};

static struct i2c_client_address_data addr_data = {
    .normal_i2c = dummy,
    .probe = probe,
    .ignore = dummy,
};
struct i2c_reg {
    unsigned char reg;
    unsigned char val;
};

static int i2c_write(u8 reg, u8 val)
{
    unsigned char data[25];
    unsigned char bytes;

    data[0]= reg;
    data[1]=val;
    bytes = 2;

    if (i2c_master_send(i2c_access_client, data, bytes) == bytes)
    {
     mdelay(1);                
     return 0;
    }
    else
    {
        printk("write error!!!! \n");
     return -EIO;
    }
}


static u8 i2c_read(u8 reg)
{
    int ret;
    u8 data;
    ret = i2c_master_send(i2c_access_client, &reg, 1);
    if (ret < 0)
        return ret;
    ret = i2c_master_recv(i2c_access_client, &data, 1);
    if (ret != 1){
        printk(KERN_WARNING "Error while reading i2c\n");
        return -EIO;
    }
    return data;
}


static int i2c_control_open(struct inode *inode, struct file *file)
{

    return 0;
}


static int i2c_control_release(struct inode *inode, struct file *file)
{
    
    return 0;
}



static int i2c_control_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg)
{
    u8 val;
    struct i2c_reg i2c_data;
    
    switch(cmd){
        case IOCTL_I2C_WRITE:
         if (copy_from_user((void *)&i2c_data,(const void *)arg, sizeof(struct i2c_reg))) {
         printk("(%s:%d) cannot copy data from user !!!\n", __func__, __LINE__);
         return -EFAULT;
         }
             i2c_write(i2c_data.reg, i2c_data.val);
            break;
            
        case IOCTL_I2C_READ:
             if (copy_from_user((void *)&i2c_data, arg, sizeof(struct i2c_reg))) {
         printk("(%s:%d) cannot copy data from user !!!\n", __func__, __LINE__);
         return -EFAULT;
         }
             i2c_data.val = i2c_read(i2c_data.reg);
             if (copy_to_user((void *)arg,(void *)&i2c_data, sizeof(struct i2c_reg))) {
         printk("(%s:%d) cannot copy data to user !!!\n", __func__, __LINE__);
         return -EFAULT;
         }
         break;
            
        default:
            printk("(%s:%d) unknown ioctl cmd (0x%x)\n", __func__, __LINE__, cmd);
            return -EINVAL;

    }

    
    return 0;
}



static struct file_operations i2c_control_fops = {
     .owner        = THIS_MODULE,
     .open        = i2c_control_open,
     .ioctl        = i2c_control_ioctl,
     .release    = i2c_control_release,
};
static int i2c_access_probe(struct i2c_adapter *adap, int addr, int kind)
{
    struct i2c_client *i2c;
    int ret;

    i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
    if (!i2c)
        return -ENOMEM;
    strcpy(i2c->name, "i2c_access");
    i2c->flags = 0;
    i2c->addr = addr;
    i2c->adapter = adap;
    i2c->driver = &i2c_access_driver;

    i2c_access_client = i2c;

    /* attach i2c client device */
    ret = i2c_attach_client(i2c);
    if (ret < 0) {
        printk("%s: failed to attach codec at addr %x\n", __func__, addr);
        goto err;
    }

    return ret;
err:
    kfree(i2c);
    return ret;
}
static int i2c_access_attach(struct i2c_adapter *adap)
{
    return i2c_probe(adap, &addr_data, i2c_access_probe);
}

static int i2c_access_detach(struct i2c_client *client)
{
    i2c_detach_client(client);

    if(i2c_access_client)
    {
        kfree(i2c_access_client);
        i2c_access_client = NULL;
    }
    return 0;
}

static struct i2c_driver i2c_access_driver = {
    .driver = {
        .name = "tcc-i2c-access",
        .owner = THIS_MODULE,
    },
    .id = -1,
    .attach_adapter = i2c_access_attach,
    .detach_client = i2c_access_detach,
    .command = NULL,
};

static int __init i2c_access_init(void)
{
    int ret = 0;
    dev_t devno;
    int reg_val,reg_tref,reg_tmref;
    printk(KERN_INFO "Register i2c access driver.\n");


     ret = i2c_add_driver(&i2c_access_driver);
     if (ret != 0){
     printk(KERN_ERR "Failed to register I2C client.\n");
     return ENODEV;
     }
    
      devno = MKDEV(I2C_ACCESS_CTRL_MAJOR, 0);
      ret = register_chrdev_region(devno, 1, "i2c_access");

    if (ret){
        printk(KERN_INFO "register i2c_access_driver failed");
        return -ENODEV;
    }

    i2c_devp = (struct i2c_access_dev *)kmalloc(sizeof(struct i2c_access_dev), GFP_KERNEL);
    if (NULL == i2c_devp){
        printk(KERN_INFO "i2c_access:kmalloc failed");
        ret=-ENOMEM;
        goto fail_malloc;
    }
    memset(i2c_devp,0,sizeof(struct i2c_access_dev));
    cdev_init(&i2c_devp->cdev, &i2c_control_fops);
    i2c_devp->cdev.owner = THIS_MODULE;
    ret = cdev_add(&i2c_devp->cdev, devno, 1);
    if(ret) {
        printk(KERN_INFO "adding cdev failed");
        ret=-ENOMEM;
        goto fail_cdev;
    }
    cls_i2c_access=class_create(THIS_MODULE, "i2c_access");
    device_create(cls_i2c_access,NULL,devno,NULL,"i2c_access");
    
    return 0;
fail_cdev:
    kfree(i2c_devp);    
fail_malloc:
    unregister_chrdev_region(devno,1);
    return ret;
}
static void __exit i2c_access_exit(void)
{
    dev_t devno;
    printk(KERN_INFO "Unregister i2c access driver.\n");
    
    devno = MKDEV(I2C_ACCESS_CTRL_MAJOR, 0);
    device_destroy(cls_i2c_access,devno);
    class_destroy(cls_i2c_access);
    cdev_del(&i2c_devp->cdev);
    kfree(i2c_devp);
    unregister_chrdev_region(devno, 1);
}


module_init(i2c_access_init);
module_exit(i2c_access_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("J.H.Luo");
MODULE_VERSION("0.1");
MODULE_DESCRIPTION("i2c access driver");



三,相应的应用程序:

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

#define I2C_ACCESS_CTRL_MAJOR            207
#define IOCTL_I2C_WRITE        _IO(I2C_ACCESS_CTRL_MAJOR, 1)
#define IOCTL_I2C_READ        _IO(I2C_ACCESS_CTRL_MAJOR, 2)

struct i2c_reg {
    unsigned char reg;
    unsigned char val;
};

int main(int argc,char * argv[])
{
    int dev_addr,reg,val;
    char cmd;
    int fd;
    struct i2c_reg i2c_data;
    if((fd = open("/dev/i2c_access", O_RDWR))< 0) {
            printf("Device open failure\n");
                return -1;
        }
    
    printf("do you want to read or write (r/w)\n");
    cmd=getchar();
    if(cmd=='r'){
        while(1){
            printf("reg:0x");
            scanf("%x", &i2c_data.reg);
            if (ioctl(fd,IOCTL_I2C_READ, &i2c_data) < 0){
                 printf("failed to read data\n");
                return -1;
            }            
             printf("val:0x%x\n",i2c_data.val);
        }
    }
    else if(cmd=='w'){
        while(1){
            printf("reg:0x");
            scanf("%x", &i2c_data.reg);
            printf("val:0x");
            scanf("%x", &i2c_data.val);
                
            if (ioctl(fd,IOCTL_I2C_WRITE, &i2c_data) < 0){
                 printf("failed to read data\n");
                return -1;
            }            
        }
    
    }

    close(fd);
    return 0;

}


四,测试如下(对tw9910进行i2c的读写):

/nand2 # insmod i2c_access_driver.ko
/nand2 # ./i2c_access_app
do you want to read or write (r/w)
w
reg:0x07
val:0x2c
reg:0x^C
/nand2 # ./i2c_access_app
do you want to read or write (r/w)
r
reg:0x07
val:0x2c



阅读(1492) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~