I2c设备初始化方法--通过总线编号初始化i2c设备

来源:互联网 发布:学五笔的软件 编辑:程序博客网 时间:2024/05/16 14:59

(本文的部分内容来源自Documentation/i2c/instantiating-devices)

I2c不像PCI或是USB设备,它不能在硬件层被枚举,软件部分必须明确了解哪些i2c设备连接到总线上了,以及哪些地址可用。因此,内核代码必须明确初始化i2c设备。I2c初始化方式有4种:

a)       通过总线编号初始化i2c设备;

b)       直接初始化设备;

c)       侦测一个指定的i2c设备;

d)       从用户空间初始化i2c设备;

下面就对上述四种初始化方法进行详细解释:

 

方式1:通过总线编号初始化i2c设备

-----------------------------------------------

这种方式使用于大多数嵌入式系统中使用I2C总线作为一种系统总线的情况。在这种系统中,每一个I2C设备都有一个预先分配好的地址,因此才可能预定义总线上的I2C设备。预定义工作是通过调用一个被注册的结构数组i2c_board_info实现的。

 

以smdk6410开发板的I2C设备初始化为例:

 

staticstruct i2c_board_info i2c_devs0[] __initdata = {

    { I2C_BOARD_INFO("24c08", 0x50),},

    { I2C_BOARD_INFO("wm8580", 0x1b),},

 

#ifdefCONFIG_SMDK6410_WM1192_EV1

    { I2C_BOARD_INFO("wm8312", 0x34),

     .platform_data = &smdk6410_wm1192_pdata,

      .irq= S3C_EINT(12),

    },

#endif

 

#ifdefCONFIG_SMDK6410_WM1190_EV1

    { I2C_BOARD_INFO("wm8350", 0x1a),

     .platform_data = &smdk6410_wm8350_pdata,

      .irq= S3C_EINT(12),

    },

#endif

};

 

staticvoid __init smdk6410_machine_init(void)

{

    s3c_i2c0_set_platdata(NULL);

    s3c_i2c1_set_platdata(NULL);{

    (...)

    i2c_register_board_info(0, i2c_devs0,ARRAY_SIZE(i2c_devs0));

    (...)

}

 

上面的代码在I2C bus 0上声明了4个设备(其中"24c08"、"wm8580"为固定声明的设备"wm8312"、"wm8350"需要通过编译CONFIG_SMDK6410_WM1192_EV1和CONFIG_SMDK6410_WM1190_EV1实现),声明包括地址和驱动程序所需的数据。当I2C总线按要求注册后,I2C设备会被i2c-core自动初始化创建。

当I2C设备移除时会被自动取消绑定和销毁。


/****************************************************************************************************************************************************************************************/

(本文的部分内容翻译自Documentation/i2c/instantiating-devices)

方法2:初始化确定设备

这种方式使用于当一个大的设备使用I2C bus作为内部通讯使用。TV adapter是一种典型的情况,其中包括了调谐器、视频编码、音频编码等,一般通过一个类似I2C总线连接到主芯片上。你不知道I2C设备会预先连接的数量,所以方式1不能使用在这种情况下。所以另外的方法是初始化确定的设备。这种操作只要填充structi2c_board_info 然后调用i2c_new_device()即可。

 

例程取自于 sfe4001 网络驱动:

 

staticstruct i2c_board_info sfe4001_hwmon_info = {

    I2C_BOARD_INFO("max6647", 0x4e),

};

 

intsfe4001_init(struct efx_nic *efx)

{

    (...)

    efx->board_info.hwmon_client =

        i2c_new_device(&efx->i2c_adap,&sfe4001_hwmon_info);

 

    (...)

}

 

上面的代码在未知的网络适配器上使用I2C总线初始化了一个I2C设备。

 

另外一种情况,当你不知道一个I2C设备是否存在(例如有一些可选项在低端的板子上是不存在的),或是在一个电路中与另外一个电路中的地址不同(涉及时未声明但在加工时改变)。在这种情况下可以使用i2c_new_probed_device() 代替 i2c_new_device()

 

例程取自于 pnx4008 OHCI 驱动:

 

staticconst unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };

 

staticint __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)

{

    (...)

    struct i2c_adapter *i2c_adap;

    struct i2c_board_info i2c_info;

 

    (...)

    i2c_adap = i2c_get_adapter(2);

    memset(&i2c_info, 0, sizeof(structi2c_board_info));

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

    isp1301_i2c_client =i2c_new_probed_device(i2c_adap, &i2c_info,

                           normal_i2c, NULL);

    i2c_put_adapter(i2c_adap);

    (...)

}

 

上述代码在OHCI adapter未知情况下在I2C bus初始化了一个I2C设备。程序会先尝试0x2c地址,如果没找到,会再尝试地址0x2d,如果仍未找到,就放弃创建。

 

创建I2C设备的驱动程序还要负责销毁和清楚设备。这些工作通过调用i2c_unregister_device(),这个工作是针对得是之前的i2c_new_device() 或i2c_new_probed_device().

/**********************************************************************************************************************************/


(本文的部分内容翻译自Documentation/i2c/instantiating-devices)


方式3:侦测一个指定的I2C设备

有时候,你对一个I2C设备没有足够的相关信息,甚至不能调用i2c_new_probed_device()。典型的例子是电脑主板上的硬件监控芯片。有几十个型号,可以存放在25个不同的地址。鉴于有大量的主板,它几乎是不可能建立一个详尽的监测芯片硬件列表。幸运的是,这些芯片的都有制造商和设备ID寄存器,所以他们可以被识别探测。

 

在这种情况下,I2C设备既不声明,也不明确初始化。相反,一旦驱动程序被加载,i2c-core将探测设备,如果被发现,任何一个I2C器件将自动初始化。为了防止这种机制的任何不当行为,适用下列限制:

 

*  I2C设备驱动程序必须实现detect()方法,  通过读取专用寄存器表示一个可支持的设备;

* 只有在总线,很可能存在一个支持的设备并同意探测才回去侦测探测。例如,这样就避免了监控电视适配器上的硬件探测芯片(好绕口啊。。。)。

 

例如:

请参阅在drivers/hwmon/lm90.clm90_driverlm90_detect()

 

当侦测到的设备被删除时或是所在总线注销时,成功侦测并且初始化的I2C设备最后要被首先自动销毁。

 

方式3与之前所熟悉的2.4内核和早期的2.6内核的i2c子系统所做的工作本质上及其相似

两个显着的区别是:

 

* 现在,探测是I2C设备初始化的唯一方法,而这是当时唯一的办法。在可能的情况下,方法12应该是首选。  在没有别的办法时才可应用于方法3,因为它可以有  不良的副作用。

* 当所有I2C总线被探测到默认的返回时,I2C总线现在必须明确地说,它可以探测I2C驱动程序类。默认是一个空的类,这意味着没有探测发生。位域的目的是为了限制产生上述不良作用。

 

最后,方法3应尽可能避免。明确设备实例(方法12)是首选,因为它是更安全更快。(有一点不明白,手册推荐的i2c初始化的方法是方式1和方式2,但网上的文章都说更习惯使用方式3,这还需要更多实践检验)。

/**********************************************************************************************************************************/


(本文的部分内容翻译自Documentation/i2c/instantiating-devices)


方式4:从用户空间初始化I2C设备

在一般情况下,内核应该知道哪些I2C设备被连接以及他们的地址是什么。

然而,在某些情况下,它没有,所以sysfs接口用作让用户提供信息。这接口是由2属性组成,在每一个I2C总线上创建的文件目录:new_device和delete_device。这两个文件只写而且为了完成初始化、分别删除一个I2C设备你必须写正确的参数,给他们以正确的实例。

文件new_device需要2个参数:I2C设备的名称和I2C器件的地址。

文件delete_device需要一个参数:I2C设备地址。由于没有两个设备可以定义在同一地址上,地址是足以唯一标识一个需要删除的设备。

 

例如:
#echo eeprom 0x50 > / sys/bus/i2c/devices/i2c-3/new_device

虽然这个接口只用于当内核中的设备声明不能生效时,有各种不同的情况下它是非常有用的:

 

* I2C驱动程序通常会检测设备(方法3),但总线的设备存在不适当的位组,  因此检测不会触发。

* I2C驱动程序通常会检测设备,但您的​​设备在一个未知的地址。

* I2C驱动程序通常会检测设备,但您的​​设备没有被检测到。 要么因为过于严格的检测程序,或者是因为您  设备不能正常支持,但你知道它是兼容的。

*你正在开发一个自己焊接在测试板上的I2C设备驱动程序。

 

此接口是I2C驱动工具FORCE_ *模块的一些参数的替代品。在i2c-core中执行胜过每个设备驱动单独执行,更改设置时你不必重新加载驱动程序,这样做更有效,也更有优势。还可以在设备加载或可用之前初始化的设备的驱动程序,你不需要知道驱动设备的需求是什么。




原创粉丝点击