闲话不说,先给出完整的示例代码,加好注释,后面再进一步解释。

  1. //
  2. //  COPYRIGHT NOTICE
  3. //  Copyright (c) 2012, 华中科技大学 卢俊(版权声明)
  4. //  All rights reserved.
  5. //
  6. /// @file    mydev.c
  7. /// @brief   i2c driver示例代码
  8. ///
  9. /// Linux2.6.32 new i2c driver model example
  10. ///
  11. /// @version 1.0
  12. /// @author  lujun
  13. /// @E-mail  lujun.hust@gmail.com
  14. /// @date    2012/08/24
  15. //
  16. //
  17. //  修订说明:
  18. //
  19. #include <linux/kernel.h>
  20. #include <linux/module.h>
  21. #include <linux/fs.h>
  22. #include <linux/slab.h>
  23. #include <linux/init.h>
  24. #include <linux/list.h>
  25. #include <linux/i2c.h>
  26. #include <linux/i2c-dev.h>
  27. #include <linux/smp_lock.h>
  28. #include <linux/jiffies.h>
  29. #include <asm/uaccess.h>
  30. #include <linux/delay.h>
  31. #define I2C_DEV_NAME "MyDevice" //这个名字要跟board_info中的名字一致,才会与I2C_Client匹配
  32. static struct i2c_device_id my_id[] = {
  33. {I2C_DEV_NAME,0}, //作为i2c client 与 driver 匹配的关键词
  34. {}
  35. };
  36. MODULE_DEVICE_TABLE(i2c, my_id);
  37. //I2c client对象指针,给本模块i2c read/write提供参数,在probe成功后获取
  38. static struct i2c_client *my_client;
  39. //新的I2C Client模型采用probe方式,老的接口采用的是attach_adapter
  40. static int my_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
  41. {
  42. //系统探测到了本模块的i2c设备,保存得到的i2c对象指针,供read/write参数
  43. my_client = client;
  44. return 0;
  45. }
  46. static int my_i2c_remove(struct i2c_client *client)
  47. {
  48. //释放I2C Client对象
  49. if( my_client != NULL ) {
  50. i2c_unregister_device(my_client);
  51. }
  52. return 0;
  53. }
  54. static struct i2c_driver my_driver = {
  55. .driver   = {
  56. .name  = "my i2c driver",
  57. .owner = THIS_MODULE,
  58. },
  59. .probe    = my_i2c_probe,
  60. .remove   = __devexit_p(my_i2c_remove),
  61. .id_table = my_id,
  62. };
  63. static int __init my_i2c_init(void)
  64. {
  65. //i2c_add_driver函数内部会根据my_driver提供的id_table在注册到系统中的boardinfo列表中找到匹配的client,然后调用my_driver的probe函数,将构造出来的i2c client传递过来
  66. return i2c_add_driver(&my_driver);
  67. }
  68. static void __exit my_i2c_exit(void)
  69. {
  70. //删除驱动,解除绑定
  71. i2c_del_driver(&my_driver);
  72. }
  73. int my_i2c_write( uint8_t reg,uint8_t data )
  74. {
  75. unsigned char buffer[2];
  76. buffer[0] = reg;
  77. buffer[1] = data;
  78. if( 2!= i2c_master_send(my_client,buffer,2) ) {
  79. printk( KERN_ERR "my i2c send fail! \n" );
  80. return -1;
  81. }
  82. return 0;
  83. }
  84. int my_i2c_read( uint8_t reg,uint8_t *data )
  85. {
  86. // write reg addr
  87. if( 1!= i2c_master_send(my_client,&reg,1) ) {
  88. printk( KERN_ERR "my i2c recv fail! \n" );
  89. return -1;
  90. }
  91. // wait
  92. msleep(10);
  93. // read
  94. if( 1!= i2c_master_recv(my_client,data,1) ) {
  95. printk( KERN_ERR "my i2c recv fail! \n" );
  96. return -1;
  97. }
  98. return 0;
  99. }
  100. MODULE_DESCRIPTION("my i2c driver");
  101. MODULE_AUTHOR("Lujun @HUST");
  102. MODULE_LICENSE("GPL");
  103. module_init(my_i2c_init);
  104. module_exit(my_i2c_exit);

上面的代码还不能完全成功运行,因为还没有添加自己的I2C设备信息到系统中,模块Probe函数不会被调用执行。注释中已经提到,i2c_add_driver的时候会扫描本模块的 id_table 中的名称是否与注册到系统中的boardinfo列表中有名称匹配的client,如果有,则会构造 i2c_client 对象,并调用本模块的 probe 函数。

那么,如何注册自己的i2c设备信息到系统的 boardinfo 列表中呢?Linux内核文档:Documentation/i2c/instantiating-devices 中讲了多种方式,我在此只说2种方式。

第一种方式,在内核的初始化中定义你的I2C设备的信息。比如在/arch/arm/mach-xxxx/board_xxxx.c 中添加一个新的 Boardinfo信息:

  1. static struct i2c_board_info __initdata i2c_info[] =  {
  2. {
  3. I2C_BOARD_INFO("24c256", 0x50),
  4. .platform_data  = &eeprom_info,
  5. },
  6. {
  7. I2C_BOARD_INFO("MyDevice", (0xbc>>1)),
  8. .platform_data  = NULL,
  9. },
  10. };

注意,添加的新的 I2C_BOARD_INFO的名称一定要与本模块的driver的名称字符串一致,地址是I2C设备地址右移1位以后的地址。

第二种方式,使用i2c_new_device()。相关函数如下:

  1. //这个函数将会使用info提供的信息建立一个i2c_client并与第一个参数指向的i2c_adapter绑定。返回的参数是一个i2c_client指针。
  2. struct i2c_client * i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
  3. //获取i2c_adapter的函数如下,它的参数是i2c总线编号。
  4. struct i2c_adapter* i2c_get_adapter(int id);
  5. //如何知道i2c总线编号呢
  6. ls /sys/class/i2c-adapter/
  7. //即可看到对应的I2C adapter编号,i2c-0代表编号为0,i2c-1代表编号为1

那么,使用第二种方式的示例代码如下,在 my_i2c_init 函数开头,添加如下代码,动态注册 I2C 设备信息到内核 Boardinfo 列表中。

  1. //自定义boardinfo信息
  2. static struct i2c_board_info my_dev_info[] __initdata = {
  3. {
  4. I2C_BOARD_INFO(I2C_DEV_NAME,I2C_DEV_ADDR),  //设备名称和地址(很关键)
  5. .platform_data= NULL,    // 传递私有数据,赋值给client->dev->platform_data
  6. },
  7. };
  8. //ls /sys/class/i2c-adapter/得到的编号
  9. static int sys_adap_bus_num = 0;
  10. static int __init my_i2c_init(void)
  11. {
  12. struct i2c_adapter* adap = i2c_get_adapter(sys_adap_bus_num);
  13. if(adap==NULL) {
  14. printk("[LUJUN-DEBUG] i2c_get_adapter fail!\n");
  15. return -1;
  16. }
  17. //动态构造i2c client对象
  18. my_client = i2c_new_device(adap, &my_dev_info[0]);
  19. if( my_client==NULL ){
  20. printk("[LUJUN-DEBUG] i2c_new_device fail!\n");
  21. return -1;
  22. }
  23. //释放资源
  24. i2c_put_adapter(adap);
  25. //函数内部会找到匹配的driver和client,然后调用probe
  26. return i2c_add_driver(&my_driver);
  27. }

本文转自 Jhuster 51CTO博客,原文链接:http://blog.51cto.com/ticktick/971738,如需转载请自行联系原作者

New Linux2.6 I2C Driver Model Example相关推荐

  1. UEFI Drivers UEFI Driver Model

     1. UEFI Drivers UEFI Drivers是UEFI Image的一种,UEFI Drivers与UEFI Applications的区别: Objects managed by UE ...

  2. I2C 子系统(三):I2C Driver

    I2C driver 分四个部分来写 I2C SW Architecture I2C Data Structure I2C Register Flow I2C Data Transfer 文章以 MT ...

  3. qcom I2C driver i2c-msm-v2.c code analysis

    I2C client通过接口逐步的调用到I2C driver的master_xfer函数,I2C driver中实现master_xfer() static const struct i2c_algo ...

  4. I2C driver编写指导二:编写i2c client driver指南

    原文地址::http://blog.csdn.net/guoshaobei/archive/2010/06/08/5656001.aspx 译者:郭少悲 日期:2010/06/08 源文:linux- ...

  5. I2C driver编写常用接口

    1.struct i2c_driver:描述从设备驱动的一个对象 2.struct i2c_client:作用是描述一个从设备信息,不需要自己创建由adapter创建(内部创建的时候调用的是:stru ...

  6. Linux设备驱动模型概述(Linux device driver model overview)

    平台(platform)设备和平台驱动是连接到平台总线(bus)的linux驱动模型接口,总线将设备和驱动绑定,这个伪总线(platform bus)以最小的基础结构被用来连接设备到总线上.在系统每注 ...

  7. v4l2视频采集驱动框架(vfe, camera i2c driver,v4l2_subdev等之间的联系)

    2014年的博文就从这篇文章开始吧,又一次回到linux,过去的一年从dm3730再到dm6437,这次来到了全志的A31 4核处理器,每一次都是全新的事物,但是偶然间还是可以感受到对新事物的消化能力 ...

  8. 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】PowerPC + Linux2.6.25平台下的I2C驱动架构分析

    PowerPC + Linux2.6.25平台下的I2C驱动架构分析 Sailor_forever  sailing_9806#163.com (本原创文章发表于Sailor_forever 的个人b ...

  9. 原理图查看I2C设备地址以及使用STM32和Zephyr Driver进行IC通讯时的注意事项

    如下图,是一个WM8994CODER的从设备地址,它的地址是:00110100 转化为16进制就是0x34,但这不是它的实际地址,实际地址是右移一位:00011010,0x1A. 为什么需要右移一位呢 ...

最新文章

  1. 泛前端知识图谱(Web/iOS/Android/RN)
  2. linux用户和组帐户管理
  3. 网络协议,我明明学过的呀?
  4. XML 命名空间以及它们如何影响 XPath 和 XSLT (Extreme XML)
  5. CODEVS 1205 单词反转
  6. stm32滴答计时器_STM32的系统滴答定时器(Systick)
  7. 关于position定位下的各种属性说明!-softbar
  8. 数据交互什么意思_学习编程怎么样才可以不枯燥?什么是前端语言?
  9. HTML 与 microsoftOffice word中字体对照表
  10. 设计一款照片一键加水印的小工具
  11. matlab的特殊字符(上下标和希腊字母等)
  12. ElasticSearch分布式搜索引擎安装教程
  13. [转]word只能用安全模式才能打开怎么解决
  14. 自定义 iPhone 铃声
  15. 自动化测试po模式是什么?自动化测试po分层如何实现?-附详细源码
  16. 阿里面试官:说一下公平锁和非公平锁的区别?
  17. 周超臣:支付宝的套路是我走过最长的路
  18. 12月19日科技资讯|富士康员工涉嫌盗卖 iPhone 零件遭调查;IntelliJ IDEA 2019.3.1 发布
  19. AFM测试常见问题及解答(二)
  20. [转...转] 国内软件破解下载网站列表!

热门文章

  1. Android Launcher 分析
  2. TortoiseSVN Launch Failed Error:系统找不到指定路径
  3. android LinkedList的基本用法
  4. Android 高级Drawable资源---复合Drawable----状态列表Drawable
  5. linux(CentOS)下安装mongodb
  6. 实现一个在JNI中调用Java对象的工具类,从此只需一行代码
  7. OO第三单元JML总结
  8. [SDOI2009]学校食堂(状态压缩)
  9. PHP设计模式之适配器模式
  10. cocos2dx + vs安装使用