zoukankan      html  css  js  c++  java
  • 如何实例化i2c_client(四法)

    一、在板文件进行client的实例化

    在内核的初始化中(例如在板文件中)定义设备的信息。这种操作的前提是内核编译的时候已经确定有哪些i2c设备和它们的地址还要知道连接的总线的编号

    比如在板文件/arch/arm/mach-XXX/board_XXX.c中可以用类似下面的代码来注册i2c设备的信息。

    1.  static struct i2c_board_info __initdata uio_i2c_board_info[] = { 

    2.           { 

    3.                  I2C_BOARD_INFO("dev_name0", 0x2d), 

    5.           }, 

    6.           {        

    7.                   I2C_BOARD_INFO("dev_name1", 0x52), 

    9.           }, 

    10.          {        

    11.                  I2C_BOARD_INFO("dev_name2", 0x57), 

    13.          }, 

    14. }; 

    15.   

    16. static void __init uio_init(void) 

    17. { 

    18.          (...) 

    19.          i2c_register_board_info(1, uio_i2c_board_info, 

    20.                          ARRAY_SIZE(uio_i2c_board_info)); 

    21.          (...) 

    22. } 

    这样注册之后,i2c_adapter注册的时候就会扫描所有的已注册的i2c_board_info,并为连接自己的i2c设备实例化一个i2c_client。

    这样一来,i2c_driver注册的时候,i2c_client就会和i2c_driver绑定了(注册的NAME必须一致),i2c_driver的probe函数被调用。

    二、枚举设备

    使用i2c_new_device()或者i2c_new_probed_device()在设备驱动文件进行client的实例化。

    上文中提到的第一种方法有诸多限制,必须在编译内核之前就知道有哪些i2c设备和它们的地址以及说i2c的总线编号

    但有时内核开发者移植系统的时候也不知道有哪些i2c设备或者到底有多少i2c总线。在这种情况下就需要用到i2c_new_device()了。它的原型是:

    struct i2c_client *

    i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);

    这个函数将会使用info提供的信息建立一个i2c_client并与第一个参数指向的i2c_adapter绑定。返回的参数是一个i2c_client指针。

    驱动中可以直接使用i2c_client指针和设备通信了。这个方法是一个比较简单的方法。

    获取i2c_adapter指针的函数是:

    struct i2c_adapter* i2c_get_adapter(int id);// idi2c总线编号。

    使用完要释放:

    void i2c_put_adapter(struct i2c_adapter *adap);

    如果连i2c设备的地址提前都步子道,甚至在不同的板子上有不同的地址,可以提供一个地址列表供系统探测。

    此时应该使用的函数是i2c_new_probe_device。用法如下:

    2.  static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; 

    3.  static int __devinit uio_probe(struct platform_device *pdev) 

    4.  { 

    5.           (...) 

    6.           struct i2c_adapter *i2c_adap; 

    7.           struct i2c_board_info i2c_info; 

    8.           (...) 

    9.           i2c_adap = i2c_get_adapter(2); 

    10.          memset(&i2c_info, 0, sizeof(struct i2c_board_info)); 

    11.          strlcpy(i2c_info.name, "isp1301_pnx", I2C_NAME_SIZE); 

    12.          isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info, 

    13.                                                     normal_i2c); 

    14.          i2c_put_adapter(i2c_adap); 

    15.          (...) 

    16. }  

    i2c_new_probed_device的原型是:

    struct i2c_client *

    i2c_new_probed_device(struct i2c_adapter *adap,

                    struct i2c_board_info *info,

                    unsigned short const *addr_list);

    这个函数将会在指定的总线上探测addr_list中的地址,将第一个有ACK反馈的地址赋给info->addr,

    然后使用前两个参数调用i2c_new_device。它的返回值也是一个可用的i2c_client指针。

    i2c_unregister_device() 可以注销i2c_new_device()/i2c_new_probed_device()申请的i2c_client。

    补充:如何知道一个物理i2c总线的编号?

    [root@zq /]# cat /sys/class/i2c-dev/i2c-0/name

    PNX4008-I2C0

    [root@zq /]# cat /sys/class/i2c-dev/i2c-1/name

    PNX4008-I2C1

    [root@zq /]# cat /sys/class/i2c-dev/i2c-2/name

    USB-I2C

    三、在所有i2c总线上探测特定设备。

    内核文档中关于方法2的限制及方法3的好处我没看懂。说一下自己的理解,那就是方法2虽然可以探测多个地址,但是仅仅能在一个指定的总线上探测,并且探测到第一个可用的地址就停止探测了。如果之前并不确定总线的编号,或者一次探测多个i2c设备,就需要用到第三种方法了。

    实现第三种方法需要两个条件:

    l         实现i2c_driver的detect成员。这个成员函数原型是:

    int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *);

    这个函数必须检查第二个参数的addr域是否自己支持的地址,是的话则至少填充info->type,info的其它成员也可以填充,但不应该修改addr。如果是就返回0,否则返回-ENODEV。

    l         初始化i2c_driver的address_list成员。i2c_driver注册的时候,i2c_core会在所有已经注册的i2c_adapter上探测address_list中的所有地址,硬件探测成功之后后调用i2c_driver的detect成员,然后根据detect填充的info建立一个i2c_client。如果两个总线上有相同的地址的设备,那么会分别建立两个i2c_client。如果address_list中的多个地址都有设备占用,那么会建立多个i2c_client。

    但实际上,内核文档不推荐这种方法,而是优先选用方法1和2,可能是因为这种方法过于灵活。

    四、从用户空间枚举。

    如果编写驱动之前确实无法得知i2c设备的地址(甚至连地址列表都不得而知),那就需要系统运行后从用户空间输入了。

    用户空间通过两个sysfs属性文件来建立和删除i2c_client:new_device和delete_device。这两个文件都是只写的。

    new_device有两个参数:i2c设备的名字(字符串)和地址(以0x开头的16进制数)。delete_device只有一个参数,那就是设备的地址。

    举例说明:

    # echo device-name 0x50 > /sys/bus/i2c/devices/i2c-3/new_device

    可以看到,此时已经指定了总线编号。

     (更详细的内容请参看kernel文档噢)O(∩_∩)O

  • 相关阅读:
    NVelocity模板引擎用法之模板中直接调用类的方法
    GridView的编辑,更新,取消,删除等功能演示
    页面加载后检查用户登录状态,通过ajax实现
    通过ajax方式实现用户名存在性检查
    各个大神大公司的UED
    ASP.NET中的DataView用法详解
    周期三角脉冲信号的生成_Matlab实现
    课后题:冲激函数习题讨论
    [KeilC51] 有关出栈时sp原子性的疑虑
    [KeilC51]软件简单PWM波生成
  • 原文地址:https://www.cnblogs.com/welhzh/p/4786705.html
Copyright © 2011-2022 走看看