at24c08 E2PROM的I2C设备驱动实例——基于mini2440

2 篇文章 0 订阅
1 篇文章 0 订阅
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. { 
  41.         perror("write error\n"); 
  42.         exit(1);
  43.        }
  44.        if(read(fd, &rbuf, 1) != 1) 
  45. {
  46.     perror("read error\n");
  47.            exit(1);
  48.        } 
  49.        else 
  50.        {
  51.         printf("rbuf[0] = %d\n",rbuf[0]);
  52.        }  
  53. }
  54.    return 0;
  55. }

第四步:验证结果

 

 测试成功!
 

 

 




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值