(本文的部分内容来源自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.c的lm90_driver和lm90_detect()
当侦测到的设备被删除时或是所在总线注销时,成功侦测并且初始化的I2C设备最后要被首先自动销毁。
方式3与之前所熟悉的2.4内核和早期的2.6内核的i2c子系统所做的工作本质上及其相似
两个显着的区别是:
* 现在,探测是I2C设备初始化的唯一方法,而这是当时唯一的办法。在可能的情况下,方法1和2应该是首选。 在没有别的办法时才可应用于方法3,因为它可以有 不良的副作用。
* 当所有I2C总线被探测到默认的返回时,I2C总线现在必须明确地说,它可以探测I2C驱动程序类。默认是一个空的类,这意味着没有探测发生。位域的目的是为了限制产生上述不良作用。
最后,方法3应尽可能避免。明确设备实例(方法1和2)是首选,因为它是更安全更快。(有一点不明白,手册推荐的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中执行胜过每个设备驱动单独执行,更改设置时你不必重新加载驱动程序,这样做更有效,也更有优势。还可以在设备加载或可用之前初始化的设备的驱动程序,你不需要知道驱动设备的需求是什么。