概述
/*
*该驱动为new style方式
*驱动安装后,输入命令创建设备节点:mknod /dev/at24c08 c 250 1
*需在内核中的mach-mini2440.c中添加板级信息注册这个i2c设备,
*且注册的设备名必须和本文件中id_table的设备名一致;
在mach-mini2440.c中添加如下代码,并重新编译内核
0x50为at24c08设备的地址,"at24c08"为在板级信息中添加的i2c设备的名称;
static struct i2c_board_info i2c_devices[] __initdata = {
{ I2C_BOARD_INFO("at24c08", 0x50), },
};
static void __init mini2440_machine_init(void)
{
i2c_register_board_info(0,i2c_devices,ARRAY_SIZE(i2c_devices)); //在函数中新加的注册信息
s3c24xx_fb_set_platdata(&mini2440_fb_info);
s3c_i2c0_set_platdata(NULL);
s3c_device_nand.dev.platform_data = &mini2440_nand_info; //添加
platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
//smdk_machine_init();
}
*/
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#define AT24C08_MAJOR 250 //主设备号不能为89,为什么?
static int at24c08_major = AT24C08_MAJOR;
/**自定义的设备数据结构**/
struct at24c08_dev
{
struct i2c_client *client;
char name[30];
unsigned short current_pointer;
struct cdev cdev;
};
struct at24c08_dev *at24c08_devp;
static int at24c08_open(struct inode *inode, struct file *file)
{
file->private_data = at24c08_devp;
return 0;
}
static ssize_t at24c08_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
int i = 0;
int transferred = 0;
int ret, my_buf[512];
struct at24c08_dev *dev = (struct at24c08_dev *)file->private_data;
dev->current_pointer = *ppos;
if (i2c_check_functionality(dev->client->adapter,
I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
while (transferred < count){
ret = i2c_smbus_read_byte_data(dev->client,dev->current_pointer + i );
my_buf[i++] = (unsigned short)ret;
transferred += 1;
}
copy_to_user(buf, (void *)my_buf, transferred);
dev->current_pointer += transferred;
}
return transferred;
}
static ssize_t at24c08_write(struct file *file, char *buf, size_t count, loff_t *ppos)
{
int i = 0;
int transferred = 0;
int ret, my_buf[512];
struct at24c08_dev *dev = (struct at24c08_dev *)file->private_data;
dev->current_pointer = *ppos;
if (i2c_check_functionality(dev->client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
//判断适配器能力
copy_from_user(my_buf, buf, count);
while (transferred < count){
ret = i2c_smbus_write_byte_data(dev->client,dev->current_pointer + i,my_buf[i]);
//i2c_smbus_write_byte_data是从设备指定偏移处写入一个字节
i += 1;
transferred += 1;
}
dev->current_pointer += transferred;
}
return transferred;
}
static int at24c08_ioctl(struct inode *inodep, struct file *file, unsigned int cmd, unsigned long
arg)
{
return 0;
}
static int at24c08_release(struct inode *inodep, struct file *file)
{
file->private_data = NULL;
return 0;
}
static const struct file_operations at24c08_fops = {
.owner = THIS_MODULE,
.open = at24c08_open,
.read = at24c08_read,
.write = at24c08_write,
.ioctl = at24c08_ioctl,
.release = at24c08_release,
};
static void at24c08_setup_cdev(struct at24c08_dev *dev, int index)
{
int err;
dev_t devnum=MKDEV(at24c08_major,index); //index=1;
cdev_init(&dev->cdev,&at24c08_fops);
dev->cdev.owner = THIS_MODULE;
err=cdev_add(&dev->cdev,devnum,1);
if (err)
printk(KERN_NOTICE"Error %d adding at24c08b %d", err, index);
}
static int __devinit at24c08_probe(struct i2c_client *client,struct i2c_device_id *id)
{
printk(KERN_INFO"start at24c08 proben");
int ret;
dev_t devnum=MKDEV(at24c08_major,1);
if(at24c08_major)
ret = register_chrdev_region(devnum, 1, "at24c08"); //执行probe后才注册设备
else {
ret = alloc_chrdev_region(&devnum, 0, 1, "at24c08");
at24c08_major = MAJOR(devnum);
}
if (ret < 0)
return ret;
at24c08_devp = kmalloc(sizeof(struct at24c08_dev), GFP_KERNEL);
if (!at24c08_devp){
ret = -ENOMEM;
goto fail_malloc;
}
memset(at24c08_devp, 0, sizeof(struct at24c08_dev));
at24c08_devp->client=client;
at24c08_setup_cdev(at24c08_devp,1);//前面注册设备后需添加设置设备
return 0;
fail_malloc:
unregister_chrdev_region(devnum, 1);
return ret;
}
static const struct i2c_device_id at24c08_id[]=
{
{"at24c08",0}, //该名称必须与板级信息中的名称一致才会调用Probe函数
{}
};
static struct i2c_driver at24c08_driver=
{
.driver={
.name="at24c08",
.owner=THIS_MODULE;
},
.probe=at24c08_probe,
.remove=__devexit_p(at24c08_remove),
.id_table=at24c08_id,
};
static int __init at24c08_init()
{
printk(KERN_INFO"Init the module successn");
return i2c_add_driver(&at24c08_driver); //初始化中添加i2c设备驱动,在执行probe后才注册
}
static void at24c08_exit()
{
printk(KERN_INFO"exit the module successn");
return i2c_del_driver(&at24c08_driver);
}
module_param(at24c08_major, int, S_IRUGO);
MODULE_AUTHOR("Xie");
module_init(at24c08_init);
module_exit(at24c08_exit);
/*
*测试程序如下:
*交叉编译后在mini2440开发板上运行。
*交叉编译命令为arm-linux-gcc -static i2c-app.c -o 24c08-app3
*经测试,当输入的参数为4个以下时只能读到一个数,5~8个时读到2个数,9~12个时读到3个数;
*输入参数形式为: ./程序名 数值1 数值2 数值3 ...;数值为写入设备的十六进制值
*
*/
#include <stdio.h>
#include <linux/types.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char **argv)
{
int i,j;
unsigned int value[100];
int fd;
fd = open("/dev/at24c08", O_RDWR); //打开设备
if(fd < 0) {
printf("Open at24c08b Device Faild!n");
exit(1);
}
printf("you has input %d paramentn",argc);
j=argc-1;
for(i=0;i<j;i++)
{
sscanf(argv[i+1],"%x",&value[i]); //将输入的数作为值存入value数组中
printf("value[%d]=%xn",i,value[i]);
}
write(fd, value, j); //将value数组的值写入设备
for(i = 0; i < j; i++)
printf("write reg[%d] data: %x to at24c08n", i, value[i]);
printf("#########################################n");
sleep(1);
for(i=0;i<j;i++)
value[i]=0; //清0
read(fd, value, j); //从设备中读入j个字节的值到数组
for(i = 0; i < j; i++)
printf("read reg[%d] data: %x to at24c08n", i, value[i]);
close(fd);
return 0;
}
/*
当只写入一个数值时,能正确读出来:
当写入2个数值时,只读出来一个,不知道什么原因。
./24c08-app3 0x24 0x30
*/
最后
以上就是漂亮鞋垫为你收集整理的i2c驱动之at24c08(1)的全部内容,希望文章能够帮你解决i2c驱动之at24c08(1)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复