1-->修改板级文件arch/arm/mach-s3c2440/mach-mini2440.c
步骤:
->添加引用 #include <linux/i2c.h>
->添加IIC设备信息
static struct i2c_board_info i2c_devices[] __initdata = {
{I2C_BOARD_INFO("at24c08", 0x50),}, /* 设备名称,设备地址 */
};
->在mini2440_machine_init(void)添加函数
i2c_register_board_info(, i2c_devices, ARRAY_SIZE(i2c_devices)); /* 注册板级设备:总线数量,设备信息,设备数量 */
2-->驱动文件at24c08.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#include <asm/uaccess.h> /* copy_to_user & copy_from_user */ #define AT24C08MAJOR 155 /* 预定义主设备号,如果有冲突,则使用alloc_devno */
static struct i2c_driver at24c08_driver; /* 设备驱动 */
/*static struct i2c_adapter *at24c08_adapter; 设备适配器 */
static struct i2c_client *at24c08_client; /* i2c设备 */
static unsigned short addr = 0x50; /* i2c设备地址 */
static dev_t alloc_devno; /* 动态申请的设备号 */
static struct class at24c08_class =
{
.name = "at24c08_class",
}; /* at24c08读函数用户给出要读取的地址=args;读取数据后放到data中,再返回给用户 */
static ssize_t at24c08_read(struct file *filp, char __user *buffer, size_t size, loff_t *off)
{
struct i2c_msg msg[]; /* 封装消息 */
unsigned char args; /* 参数和数据 */
unsigned char data; /* 要返回的数据 */
if(size != )
{
return -EINVAL;
}
/* 从用户空间读取一个参数赋值给args,也就是把要读取的地址传递给内核,args就是要读取的地址,由用户给出 */
copy_from_user(&args, buffer, );
/* 封装消息->先写地址,再读取数据,一共2次通讯 */
msg[].addr = addr; /* 设备地址 */
msg[].buf = &args; /* 要读取的地址 */
msg[].len = ; /* 消息的长度 */
msg[].flags = ; /* 标志位,写0读1 */ /* 再读 */
msg[].addr = addr;
msg[].buf = &data; /* 接收读取的数据 */
msg[].len = ; /* 要读取的数据长度 */
msg[].flags = I2C_M_RD; /* 读 */ /* 与目标设备进行2次通讯 */
if(i2c_transfer(at24c08_client->adapter, msg, ) == )
{
/* 返回2,表示成功通讯2次 */
copy_to_user(buffer, &data, );
printk(KERN_INFO "at24c08_read succeed\n");
return ;
}
else
{
printk(KERN_INFO "at24c08_read failed\n");
return -EIO;
}
} /* at24c08写函数 */
static ssize_t at24c081_write(struct file *filp, const char __user *buffer, size_t size, loff_t *off)
{
struct i2c_msg msg[];
unsigned char args[];
/* args:保存从用户空间过来的数据 *buffer:用户空间的数据,包含了要写入的地址和药写入的数据*2:字节数 */
printk(KERN_INFO "at24c08_write......\n");
copy_from_user(&args, buffer, ); /* 成功返回0;失败返回未完成字节数 */
printk(KERN_INFO "write parameters : args[0] = 0x%x, args[1] = 0x%x\n", args[], args[]); /* args[0]:addr, args[1]:value */
msg[].addr = addr; /* 设备地址 */
msg[].buf = args; /* 写入的数据 */
msg[].len = ; /* 长度 */
msg[].flags = at24c08_client->flags & I2C_M_TEN; /* 写标志 */
if(i2c_transfer(at24c08_client->adapter, msg, ) == )
{
printk(KERN_INFO "at24c08_write succeed\n");
return ;
}
else
{
printk(KERN_INFO "at24c08_write failed\n");
return -EIO;
} } int at24c08_open(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "at24c08 open\n");
return ;
} /* at24c08操作集 */
static struct file_operations at24c08_fops = {
.owner = THIS_MODULE,
.read = at24c08_read,
.write = at24c081_write,
.open = at24c08_open,
}; static struct cdev i2c_cdev; /* at24c08设备文件 */
/* 设备初始化 */
static int at24c08_probe(struct i2c_client *client, const struct i2c_device_id *i2c_device)
{
int result;
result = register_chrdev_region(AT24C08MAJOR, , "at24c08"); /* 申请字符设备主设备号 */
if(result < )
{
printk(KERN_WARNING "register major number [%d] failed!\n", AT24C08MAJOR);
alloc_chrdev_region(&alloc_devno, , , "at24c08");
printk(KERN_INFO "alloc device number : major:[%d], minor:[%d] succeed!\n", MAJOR(alloc_devno), MINOR(alloc_devno));
}
else
printk(KERN_INFO "register device number : major:[%d], minor:[0] succeed!\n", AT24C08MAJOR);
cdev_init(&i2c_cdev, &at24c08_fops);
cdev_add(&i2c_cdev, MKDEV(AT24C08MAJOR, ), ); /* 向系统注册字符设备文件,此时还未创建 */
class_register(&at24c08_class); /* 设备总线类别 */
device_create(&at24c08_class, NULL, MKDEV(AT24C08MAJOR, ), NULL, "at24c08"); /* 创建at24c08字符设备文件 */
printk(KERN_INFO "create device file 'at24c08' succeed!\n"); at24c08_client = client;
printk(KERN_INFO "get i2c_client, client name = %s, addr = 0x%x\n", at24c08_client->name, at24c08_client->addr);
printk(KERN_INFO "get i2c_adapter, adapter name = %s\n", at24c08_client->adapter->name); printk(KERN_INFO "at24c08 probe()\n");
return ;
} /* 移除设备 */
static int at24c08_remove(struct i2c_client *client)
{
device_destroy(&at24c08_class, MKDEV(AT24C08MAJOR, )); /* 删除设备 */
class_destroy(&at24c08_class); /* 移除设备类别 */
cdev_del(&i2c_cdev);
unregister_chrdev_region(MKDEV(AT24C08MAJOR, ), );
printk(KERN_INFO "at24c08 remove()\n");
return ;
} /* 设备检测函数 */
static int at24c08_detect(struct i2c_client *client, int kind, struct i2c_board_info *i2c_bd_info)
{
printk(KERN_INFO "do nothing, at24c08 detect()\n");
return ;
} /* i2c设备id列表 */
static const struct i2c_device_id at24c08_id[] = {
{ "at24c08", },
{ } /* 最后一个必须为空,表示结束 */
}; static unsigned short ignore[] = { I2C_CLIENT_END };
static const unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END };
static const struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
.probe = ignore,
.ignore = ignore,
}; static struct i2c_driver at24c08_driver = {
.probe = at24c08_probe,
.remove = at24c08_remove,
.driver = {
.name = "at24c08", /* 驱动名称 */
.owner = THIS_MODULE,
},
.id_table = at24c08_id, /* id列表 */
.detect = at24c08_detect,
.address_data = &addr_data,
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD, /* 这些都是什么? */
}; static int __init at24c08_init(void)
{
i2c_add_driver(&at24c08_driver); /* 将i2c_driver注册到系统中去 */
printk(KERN_INFO "at24c08 i2c_driver was added into the system.\n");
return ;
} static void __exit at24c08_exit(void)
{
i2c_del_driver(&at24c08_driver);
printk(KERN_INFO "at24c08 i2c_driver was deleted from the system.\n");
return ;
} module_init(at24c08_init);
module_exit(at24c08_exit); MODULE_AUTHOR("edison ren");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("at24c08 device driver, 2016-10-08");
3-->应用程序
/* 配套的应用程序app.c */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/types.h> #define i2c_dev "/dev/at24c08" int main(void)
{
int fd, count = ;
fd = open(i2c_dev, O_RDWR);
unsigned char rbuffer; /* 读取的数据:片内地址+1个数据 */
rbuffer = 0x08; /* 片内地址 */
unsigned char wbuffer[]; /* 片内地址+h */
wbuffer[] = 0x08; /* 片内地址 */
wbuffer[] = 'h';
if(fd < )
{
printf("open %s failed!\n", i2c_dev);
exit();
}
else
{
printf("open %s succeed!\n", i2c_dev); printf("#####################################");
count = read(fd, &rbuffer, );
if(count > )
printf("read data succeed, data = [%d].\n", rbuffer);
rbuffer = 0x08;
printf("#####################################");
printf("write ...\n");
count = write(fd, wbuffer, );
if(count > )
printf("write data succeed, write data count = %d.\n", count);
else
{
printf("write data failed, write data count = %d.\n", count);
exit();
}
printf("#####################################");
count = read(fd, &rbuffer, );
printf("read ...\n");
if(count > )
printf("read data succeed, data = [%d].\n", rbuffer);
}
} /* 连续读和写app2.c */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/types.h> #define i2c_dev "/dev/at24c08" int main(void)
{
int fd, i = , count = ;
fd = open(i2c_dev, O_RDWR);
unsigned char rbuffer; /* 读取的数据:片内地址+1个数据 */
unsigned char address[];
address[] = 0x05;
address[] = 0x06;
address[] = 0x07;
address[] = 0x08;
address[] = 0x09;
unsigned char data[] = {'h', 'e', 'l', 'l', 'o'};
unsigned char wbuffer[]; /* 片内地址+h */
if(fd < )
{
printf("open %s failed!\n", i2c_dev);
exit();
}
else
{
printf("open %s succeed!\n", i2c_dev);
printf("\n#####################################\n");
for(i = ; i < ; i++)
{
rbuffer = address[i];
read(fd, &rbuffer, );
printf("-0x[%x]-", rbuffer);
}
printf("\n#####################################\n");
for(i = ; i < ; i++)
{
wbuffer[] = address[i];
wbuffer[] = data[i];
write(fd, wbuffer, );
}
printf("\n#####################################\n");
for(i = ; i < ; i++)
{
rbuffer = address[i];
read(fd, &rbuffer, );
printf("-0x[%x]-", rbuffer);
}
printf("\n");
}
}
4-->Makefile
ifneq ($(KERNELRELEASE),)
obj-m := at24c08.o
else
#KDIR := /lib/modules/2.6.-.el5/build
KDIR := /home/edison/linux-kernel/linux-2.6.32.2 all:
make -C $(KDIR) M=$(PWD) modules arch=arm cross_compile=arm-linux-
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order *.ko.unsigned
endif
当然也可以将驱动文件添加到对应的内核文件中,通过修改对应的KConfig和Makefile来将驱动编译到内核中