AT24C08提供8192位的串行电可擦写可编程只读存储器(EEPROM), 16字节页写模式。

内核版本:2.6.32。

实验所用开发板mini2440。
第一步:在arch/arm/mach-s3c2440/mach-mini2440.c添加E2PROM的板级信息
1、添加头文件:
#include <linux/i2c.h>
#include <linux/i2c/at24.h>
2、添加平台板级信息

  1. static struct at24_platform_data at24_platdata = {
  2.         .byte_len = 8192,//字节大小
  3.         .page_size = 16,//页数大小
  4. };
  5. static struct i2c_board_info mini2440_i2c_devices[] = {
  6.         {
  7.                 I2C_BOARD_INFO("24c08",0x50),//第一个参数是硬件名称,驱动的名字匹配不上的时候,会和这个匹配,第二个参数是IIC硬件地址。
  8.                 .platform_data = &at24_platdata,
  9.         }
  10. };

3、在mini2440_machine_init(void)函数中添加
  1. i2c_register_board_info(0,mini2440_i2c_devices,ARRAY_SIZE(mini2440_i2c_devices));//注册板级信息
4、编译内核并重新烧写开发板的zImage
  1. make zImage
第二步:编写驱动代码
  1. #include<linux/init.h>
  2. #include<linux/module.h>
  3. #include<linux/i2c.h>
  4. #include<linux/fs.h>
  5. #include<linux/device.h>
  6. #include<linux/slab.h>
  7. #include<asm/uaccess.h>
  8. #define E2PROM_MAJOR 250//可以通过cat /proc/devices查看哪些设备号没有被使用
  9. MODULE_LICENSE("GPL");
  10. struct e2prom_device{
  11. struct i2c_client *at24c02_client;
  12. struct class  *at24c02_class;
  13. struct device     *at24c02_device;
  14. };
  15. struct e2prom_device *e2prom_dev;
  16. struct i2c_device_id e2prom_table[]={
  17. [0]={
  18. .name ="24c02",
  19. .driver_data =0,
  20. },
  21. [1]={
  22. .name ="24c08",
  23. .driver_data =0,
  24. },
  25. };
  26. static int i2c_read_byte(char *buf,int count)
  27. {
  28. int ret=0;
  29. struct i2c_msg msg;
  30. msg.addr =e2prom_dev->at24c02_client->addr;//0x05
  31. msg.flags =1;//1 代表读 0 代表写
  32. msg.len =count;
  33. msg.buf =buf;
  34. ret=i2c_transfer(e2prom_dev->at24c02_client->adapter,&msg,1);
  35. if(ret<0){
  36. printk("i2c transfer failed!\n");
  37. return -EINVAL;
  38. }
  39. return ret;
  40. }
  41. static int i2c_write_byte(char *buf,int count)
  42. {
  43. int ret=0;
  44. struct i2c_msg msg;
  45. msg.addr =e2prom_dev->at24c02_client->addr;//0x05
  46. msg.flags =0; //写
  47. msg.len =count;
  48. msg.buf =buf;
  49. ret=i2c_transfer(e2prom_dev->at24c02_client->adapter,&msg,1);
  50. if(ret<0){
  51. printk("i2c transfer failed!\n");
  52. return -EINVAL;
  53. }
  54. return ret;
  55. }
  56. static int e2prom_open(struct inode *inode, struct file *file)
  57. {
  58. return 0;
  59. }
  60. static size_t e2prom_read(struct file *filep, char __user *buf, size_t size, 
  61. loff_t *ppos)
  62. {
  63. int ret = 0;
  64. char *tmp;
  65. tmp = kmalloc(size,GFP_KERNEL);
  66. if(tmp==NULL){
  67. printk("malloc failed!\n");
  68. return -ENOMEM;
  69. }
  70. ret = i2c_read_byte(tmp,size);
  71. if(ret<0){
  72. printk("read byte failed!\n");
  73. ret = -EINVAL;
  74. goto err0;
  75. }
  76. ret = copy_to_user(buf,tmp,size);
  77. if(ret){
  78. printk("copy data failed!\n");
  79. ret =-EINVAL;
  80. goto err0;
  81. }
  82. kfree(tmp);
  83. return size;
  84. err0:
  85. kfree(tmp);
  86. return ret;
  87. }
  88. static ssize_t e2prom_write(struct file *filep, const char __user *buf, size_t size,
  89.  loff_t *ppos)
  90. {
  91. int ret = 0;
  92. char *tmp;
  93. tmp = kmalloc(size,GFP_KERNEL);
  94. if(tmp == NULL){
  95. printk("malloc failed!\n");
  96. return -ENOMEM;
  97. goto err0;
  98. }
  99. ret = copy_from_user(tmp,buf,size);
  100. if(ret){
  101. printk("copy data failed!\n");
  102. ret =-EFAULT;
  103. goto err0;
  104. }
  105. ret = i2c_write_byte(tmp,size);
  106. if(ret<0){
  107. printk("write byte failed!\n");
  108. ret = -EINVAL;
  109. goto err0;
  110. }
  111. kfree(tmp);
  112. return size;
  113. err0:
  114. kfree(tmp);
  115. return ret;
  116. }
  117. struct file_operations e2prom_fops = {
  118. .owner =THIS_MODULE,
  119. .open =e2prom_open,
  120. .read   =e2prom_read,
  121. .write   =e2prom_write,
  122. };
  123. static int e2prom_probe(struct i2c_client *client,
  124.       const struct i2c_device_id *id)
  125. {
  126. int ret;
  127. printk("enter probe!\n");
  128. e2prom_dev = kmalloc(sizeof(struct e2prom_device),GFP_KERNEL);
  129. if(e2prom_dev == NULL){
  130. printk("malloc failed\n");
  131. return -ENOMEM;
  132. }
  133. e2prom_dev->at24c02_client = client;
  134. /*给用户提供接口*/
  135. ret = register_chrdev(E2PROM_MAJOR,"e2prom_module",&e2prom_fops);
  136. if(ret < 0)
  137. {
  138. printk("register major failded\n");
  139. ret =-EINVAL;
  140. goto err0;
  141. }
  142. /*创建设备类*/
  143. e2prom_dev->at24c02_class = class_create(THIS_MODULE,"e2prom_class");
  144. if(IS_ERR(e2prom_dev->at24c02_class)){
  145. printk("class create failed\n");
  146. ret =PTR_ERR(e2prom_dev->at24c02_client);
  147. goto err1;
  148. }
  149. /*创建设备文件*/
  150. e2prom_dev->at24c02_device=device_create(e2prom_dev->at24c02_class,NULL,MKDEV(E2PROM_MAJOR,0),NULL,"at24c08");
  151. if(IS_ERR(e2prom_dev->at24c02_device)){
  152. printk("class create failed\n");
  153. ret =PTR_ERR(e2prom_dev->at24c02_device);
  154. goto err1;
  155. }
  156. return 0;
  157. err1:
  158. unregister_chrdev(E2PROM_MAJOR,"e2prom_module");
  159. err0:
  160. kfree(e2prom_dev);
  161. return ret;
  162. }
  163. static int e2prom_remove(struct i2c_client *client)
  164. {
  165. unregister_chrdev(E2PROM_MAJOR,"e2prom_module");
  166. device_destroy(e2prom_dev->at24c02_class, MKDEV(E2PROM_MAJOR,0));
  167. class_destroy(e2prom_dev->at24c02_class);
  168. kfree(e2prom_dev);
  169. return 0;
  170. }
  171. /*构建一个struct i2c_driver结构体*/
  172. static struct i2c_driver e2prom_driver={
  173. .probe =e2prom_probe,
  174. .remove =e2prom_remove,
  175. .id_table   =e2prom_table,//记录此驱动服务于哪些设备
  176. .driver ={
  177. .name ="e2prom",//
  178. },
  179. };
  180. static int __init e2prom_init(void)
  181. {
  182. /*注册平台特定驱动
  183. *1)将i2c驱动加入i2c总线的驱动链表
  184. *2)搜索i2c总线的设备链表,每搜索一个都会调用i2c总线的match
  185. * 实现client->name与id->name进行匹配,匹配成功就会调用
  186. * i2c驱动中的probe函数
  187. */
  188. i2c_add_driver(&e2prom_driver);
  189. return 0;
  190. }
  191. static void __exit e2prom_exit(void)
  192. {
  193. i2c_del_driver(&e2prom_driver);
  194. }
  195. module_init(e2prom_init);
  196. module_exit(e2prom_exit);
第三步:编写测试程序

读写的操作方式采用Byte Write方式读,和Random Read方式写。
其中Random Read方式需要对写入的地址进行确认。也就是读操作的时候,需要写一次,再读一次。具体步骤如下图所示:
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <errno.h>
  6. #include <unistd.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. /*
  10.     ./i2c_test w data    
  11.     ./i2c_test r 
  12. */
  13. int main(int argc,char **argv)
  14. {
  15.    int fd;
  16.    char register_addr = 0x78;//要写入的地址
  17.    char wbuf[2];//写缓冲区
  18.    char rbuf[2];//读缓冲区
  19.    //打开设备
  20.    fd = open("/dev/at24c08", O_RDWR);
  21.    if (fd < 0) 
  22.    {
  23.        perror("open error\n");
  24.        exit(1);
  25.    }
  26.    if(strcmp(argv[1],"w") == 0)
  27.    {//写操作 Byte Write
  28.     wbuf[0] = register_addr;
  29.        wbuf[1] = atoi(argv[2]);
  30.        /向register_addr地址中写入数据,因为设备地址已经在板级信息中确定了,所以不需要通过ioctl设置设备地址*/
  31. if(res = write(fd, wbuf, 2) != 2) 
  32.        {
  33.         perror("write error\n"); 
  34.         exit(1);
  35.       }
  36. }
  37.    else 
  38.   {//读操作 Random Read
  39.     if(write(fd, &register_addr, 1) != 1) //验证是否从register_addr地址读出
  40.         perror("write error\n"); 
  41.         exit(1);
  42.        }
  43.        if(read(fd, &rbuf, 1) != 1) 
  44. {
  45.     perror("read error\n");
  46.            exit(1);
  47.        } 
  48.        else 
  49.        {
  50.         printf("rbuf[0] = %d\n",rbuf[0]);
  51.        }  
  52. }
  53.    return 0;
  54. }
第四步:验证结果

测试成功!

at24c08 E2PROM的I2C设备驱动实例——基于mini2440相关推荐

  1. i2c设备驱动实例 ds1307为例

    i2c设备驱动实例 ds1307为例 http://blog.csdn.net/airk000/article/details/21345457 http://blog.csdn.net/creazy ...

  2. Linux 设备驱动篇之I2c设备驱动

    ******************************************************************************************** 装载声明:希望 ...

  3. Linux设备驱动篇——[I2C设备驱动-1]

    Linux 设备驱动篇之I2c设备驱动 fulinux 一.I2C驱动体系 虽然I2C硬件体系结构和协议都很容易理解,但是Linux I2C驱动体系结构却有相当的复杂度,它主要由3部分组成,即I2C设 ...

  4. 手把手教你写Linux I2C设备驱动

    手把手教你写Linux I2C设备驱动 标签:Linux 设备 驱动 详解 i2c 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http:/ ...

  5. linux探测i2c设备连接状态,手把手教你写Linux I2C设备驱动

    Linux I2C驱动是嵌入式Linux驱动开发人员经常需要编写的一种驱动,因为凡是系统中使用到的I2C设备,几乎都需要编写相应的I2C驱动去配置和控制它,例如 RTC实时时钟芯片.音视频采集芯片.音 ...

  6. linux i2c detect函数,手把手教你写Linux I2C设备驱动

    Linux I2C驱动是嵌入式Linux驱动开发人员经常需要编写的一种驱动,因为凡是系统中使用到的I2C设备,几乎都需要编写相应的I2C驱动去配置和控制它,例如 RTC实时时钟芯片.音视频采集芯片.音 ...

  7. Linux添加一个i2c设备,手把手教你写Linux I2C设备驱动

    Linux I2C驱动是嵌入式Linux驱动开发人员经常需要编写的一种驱动,因为凡是系统中使用到的I2C设备,几乎都需要编写相应的I2C驱动去配置和控制它,例如 RTC实时时钟芯片.音视频采集芯片.音 ...

  8. 用户空间访问I2C设备驱动

    2012-01-11 15:33:43 标签:Linux I2C 字符设备 设备驱动 用户空间 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任. ...

  9. RT-Thread I2C设备驱动框架的对接使用

    I2C和SPI是MCU和板载芯片之间最常用的通讯方式,现在先介绍下I2C总线.I2C的基本原理也很简单,只需要两根线(时钟线SCL和信号线SDA)即可实现挂载在I2C总线上设备之间的相互通讯.I2C协 ...

  10. 使用RT-Thread Studio DIY 迷你桌面时钟(二)| 获取温湿度传感器数据(I2C设备驱动+SHT3x软件包)

    寻求更清爽的阅读体验,请移步:Mculover666的个人博客. 1. 项目进度 桌面Mini时钟项目用来演示如何使用RT-Thread Stduio开发项目,整个项目的架构如下: 在上一篇博文中简单 ...

最新文章

  1. Flutter开发之MVC设计模式:新建文件与导入文件(八)
  2. 子域名/目录暴力工具Gobuster
  3. 安利一个我爱不释手的PDF神器网站
  4. 关于android开发环境的创建
  5. 使用脚本动态操作 SVG 文档
  6. python输出个数、给定一个n*n的矩阵m_简述Numpy
  7. ansys中模态扩展是什么意思_ANSYS模态分析教程与实例讲解.ppt
  8. H5动画实现简单的转盘抽奖。
  9. 通配符(一般用来查找文件)
  10. 浏览器获取服务器CA证书与认证流程-HTTPS
  11. 复盘 2019 ,展望 2020
  12. 手机扫描答题卡阅卷的小程序
  13. 老挑毛u盘一键装系统计算机意外地,揭谜一键Ghost的“恶”事 大白菜、老毛桃、通用都不干净...
  14. 关于SMTP邮件无法发送到 SMTP服务器,传输错误代码为 0x80040217
  15. [BugKu Web]ez_serialize
  16. 美国人怎么看 2020 年的产业数字化|趋势
  17. 世界互联网大会“互联网之光”博览会-蚂蚁金服展台掠影
  18. 期货价格怎么算出来的?
  19. valgrind 工具使用
  20. 携程3+2工作模式,极大刺激着领导们的安全感

热门文章

  1. 聊一聊自来水营业收费系统
  2. 计算机应用技术三级学科,三个计算机专业的区别是什么?
  3. ns3在packet中加入自定义数据
  4. 机器人操作系统、自动驾驶等研发工具整理
  5. 互亿无线短信平台接口java实现
  6. 电梯控制系统设计(PLC及组态)
  7. Web应用程序安全原理(Web服务面临的威胁)
  8. win10启用php_zip,win10右键没有压缩文件选项怎么办
  9. matlab数值微积分与方程数值求解,六、数值微积分与方程求解(MATLAB学习笔记)
  10. 前端面试题(JavaScript基础篇)