I2C设备驱动

来源:互联网 发布:完美root软件 编辑:程序博客网 时间:2024/06/08 14:01

以前我们的probe只打印,现在我们做一些有用的事情 同样也是在我们以前的驱动程序里面去改

我们来看看我们芯片的时序图,当我想写的时候,

先发设备地址,然后发存储地址,最后发出数据

我们有两套函数可以用,第一套是smbus,另外一套是i2c_trasfer,这个SMBUS意思是system manager 就是系统管理总线的意思

这个smbus是I2C里面的一小部分,内核推荐我们用smbus


因为什么,因为有一些适配器只支持smbus,这篇文档上也告诉你了用哪些函数,比如


看我们这个写函数

看这里我们可以看到他发出了什么,S信号,地址,WR表示写,A表示回应,然后数据,然后回应,然后停止,我们不能用这个函数,因为我驱动里面还要发地址啊

我们接着往下看


write_byte_data,我们可以用这个函数,S表示开始信号,然后地址,然后写,然后回应,然后写要写入的地址,然后回应,然后数据,然后回应,然后停止位

这下面的S Addr Wr [A] Comm [A] Data [A] P 其实就是我们的时序图,跟我们上面的完全一样



读操作,我们看看有什么函数可以提供给我们读


这个函数刚好符合我们的时序图


#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include<linux/cdev.h>
#include<linux/init.h>
#include<linux/device.h>
#include<linux/fs.h>
#include<linux/io.h>
struct cdev cdev;
dev_t devno;
#define DRIVER_NAME "at24clxx_i2c"
struct class *my_class;
static struct i2c_client *at24xx_client;
/*假设应用程序传进来两个数据,BUF[0],BUF[1]
BUF[0]是地址,你要访问芯片的那个地址
BUF[1]是date
*/
static ssize_t at24clxx_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
unsigned char ker_buf[2];
unsigned char addr,data;
copy_from_user(ker_buf,buf,2);
addr=ker_buf[0];
data=ker_buf[1];
//但是我怎么把这两个数据写进去呢
//第一个参数是设备,第二个参数是addr,第三个参数是我们的date;
if(!i2c_smbus_write_byte_data(at24xx_client,addr,data))
{
return 2;
}
else
return -EIO;


}


/*读我们也这么来,
 传入BUF[0],addr
 输出的数据BUF[1] data
 */
static ssize_t at24clxx_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
unsigned char addr,data;
copy_from_user(&addr,buf,1);
data =i2c_smbus_read_byte_data(at24xx_client,addr);
copy_to_user(buf,&data,1);


return 1;


}


static struct file_operations at24clxx_fops={
.owner = THIS_MODULE,
.read  =at24clxx_read,
.write =at24clxx_write,
};


static int  at24cl04_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
at24xx_client=client;
cdev_init(&cdev,&at24clxx_fops);
alloc_chrdev_region(&devno,0,1,DRIVER_NAME);
cdev_add(&cdev,devno,1);
my_class=class_create(THIS_MODULE,"at24clxx_class");
if(IS_ERR(my_class))
{
printk("Err: failed in creating class.\n");
return -1;
}
device_create(my_class, NULL, devno,NULL,DRIVER_NAME);


printk("24cl04_probe\n");

return 0;


}


static int at24cl04_remove(struct i2c_client *client)
{
printk("24cl04_remove\n");
device_destroy(my_class,devno);
class_destroy(my_class);
cdev_del(&cdev);
unregister_chrdev_region(devno,1);
return 0;
}
static const struct i2c_device_id at24cl04_id_table[] = {
{"gh24cl04",0x50},
{}
};
static struct i2c_driver at24cl04_driver = {
.driver = {
.name = "24cl04",
.owner = THIS_MODULE,
},
.probe = at24cl04_probe,
.remove = at24cl04_remove,
.id_table = at24cl04_id_table,
};


/*1. 分配/设置 i2c_driver*/
static int at24cl04_driver_init(void)
{
//printk("init\n");
int ret;
printk("init\n");
ret = i2c_add_driver(&at24cl04_driver);
if (ret != 0)
pr_err("Failed to register 88PM860x I2C driver: %d\n", ret);
return ret;
}


static void at24cl04_driver_exit(void)
{
i2c_del_driver(&at24cl04_driver);


}
module_init(at24cl04_driver_init);
module_exit(at24cl04_driver_exit);
MODULE_LICENSE("GPL");


测试程序如下

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>


void print_usage(char *file)
{
printf("%s r addr\n",file);
printf("%s w addr val \n",file);
}


int main(int argc,char **argv)
{
    unsigned char buf[2];
int fd;
fd=open("/dev/at24clxx_i2c",0x666);
if(fd<0)
{
printf("can't open /dev/at24clxx\n");
return -1;
}


printf("1\n");
if(strcmp(argv[1],"r")==0)
{
printf("3\n");
buf[0]=strtoul(argv[2],NULL,0);
read(fd,buf,1);
printf("data : %c,%d,0x%x\n",buf[0],buf[0],buf[0]);
}
else if (strcmp(argv[1],"w")==0)
{
printf("4");
buf[0]=strtoul(argv[2],NULL,0);
buf[1]=strtoul(argv[3],NULL,0);
if(write(fd,buf,2)!=2)
{
printf("write error\n");

}

}
else
{
printf("2\n");
print_usage(argv[0]);


}
return 0;
}

运行结果如下




原创粉丝点击