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来将驱动编译到内核中

i2c之at24c08驱动及应用程序的更多相关文章

  1. AM335x kernel 4.4.12 i2c eeprom AT24c02驱动移植

    kernel 4.4.12 i2c eeprom AT24c02驱动移植 在kernel make menuconfig ARCH=ARM 中打开: Device Drivers ---> Mi ...

  2. openwrt驱动与应用程序的联系

    应用程序与驱动之间需要进行命令的传递,因而它们之间需要共同定义一套双方都可以识别的数据结构,实际使用时它们include的是名字和内容相同但位置不同的头文件. 比如spi_gpio_ad7193.h这 ...

  3. MPU6050带字符驱动的i2c从设备驱动1

    开干: 1.闲言碎语 这个驱动,越写觉的越简单,入门难,入门之后感觉还好.Linux开发还是比较友好的. 2.编写MPU6050带字符驱动的i2c从设备驱动 要实现的功能就是,将MPU6050作为字符 ...

  4. linux 设备驱动与应用程序异步通知

    一.异步通知机制简介 异步通知机制的意思:一旦设备准备就绪,可以主动的通知应用程序进行相应的操作,从而使得应用程序不必去查询设备的状态. 异步通知比较准确的称谓是"信号驱动的异步IO&quo ...

  5. I2C用户态驱动设计

    一.用户态驱动模型 1.1 I2C通用驱动代码 i2c_dev_init: static int __init i2c_dev_init(void) { int res; printk(KERN_IN ...

  6. Linux I2C总线设备驱动模型分析(ov7740)

    1. 框架1.1 硬件协议简介1.2 驱动框架1.3 bus-drv-dev模型及写程序a. 设备的4种构建方法a.1 定义一个i2c_board_info, 里面有:名字, 设备地址 然后i2c_r ...

  7. [国嵌攻略][155][I2C用户态驱动设计]

    用户态驱动模型 用户态驱动模型首先是一个应用程序,其次是在这个用户程序中通过内核调用来驱动设备. IIC通用驱动代码 IIC通用驱动程序的代码在/drivers/i2c/i2c-dev.c中.一次读操 ...

  8. I2C子系统之驱动SSD1306 OLED

    理解I2C设备驱动框架,主要围绕四个结构体去分析就容易了. struct i2c_algorithm:提供I2C协议的实现的操作,如:master_xfer实现数据收发的最基本方法. struct i ...

  9. Linux I2C总线控制器驱动(S3C2440)

    s3c2440的i2c控制器驱动(精简DIY),直接上代码,注释很详细: #include <linux/kernel.h> #include <linux/module.h> ...

随机推荐

  1. js加密解密

    <script> document.write("<xmp>"); document.write(function(p,a,c,k,e,r){}(''.sp ...

  2. 第一周 总结笔记 / 斯坦福-Machine Learning-Andrew Ng

    课程主页:https://www.coursera.org/learn/machine-learning/home/welcome 收集再多的资料也没用,关键是要自己理解总结,做笔记就是一个归纳总结的 ...

  3. log4j.properties

    ### set log levels ### log4j.rootLogger = INFO, stdout , D , E ### \u8F93\u51FA\u5230\u63A7\u5236\u5 ...

  4. struts 标签的使用<转>

    Struts2常用标签总结 一 介绍 1.Struts2的作用 Struts2标签库提供了主题.模板支持,极大地简化了视图页面的编写,而且,struts2的主题.模板都提供了很好的扩展性.实现了更好的 ...

  5. testlink部署与迁移

    几个特殊的文件: 1.D:\xampp\htdocs\testlink\config.inc  安装配置文件,此处需要修改安装目录(g_repositoryPath.log_path) 2.D:\xa ...

  6. 严重:Error listenerStart

    转自: http://1985wanggang.blog.163.com/blog/static/7763833200942611050436/ 近日浏览论坛,发现好多人提问,都说在运行web程序时, ...

  7. MySQL DML 整理

    DML(Data Manipulation Language)数据操纵语言statements are used for managing data within schema objects. 由D ...

  8. 不注册Tomcat服务,运行Tomcat不弹出JAVA控制台窗口

    http://blog.csdn.net/yangholmes_blog/article/details/52881296

  9. JS与树本(复杂)

    <!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>树形 ...

  10. Nodejs express中创建ejs项目,解决express下默认创建jade,无法创建ejs问题

    最近在看<Node.js开发指南>,看到使用nodejs进行web开发的时候,准备创建ejs项目遇到问题了, 书上命令为: express -t ejs microblog 可是执行后,仍 ...