日期:2014-05-16  浏览次数:20600 次

LinuxI2C子系统之一实例化IC2设备(Client)的四种方法(一、二)

      最近的项目工作中需要调试维护I2C控制的视频采集设备驱动代码,于是花了些时间来研究I2C驱动框架,发现其复杂度不亚于ALSA-ASOC驱动框架(仅个人感觉,勿怪)!并打算将自己的研究心得记录下来,一是自己想看时可以随时找到,二来是帮助后来者少走弯路。第一篇I2C子系统从译文开始:

原文件位置:linux源码目录\Documentation\i2c\instantiating-devices

                       ===========================================

                                                    怎么实例化I2C设备

                      ===========================================

     与PCI与USB总线不同,I2C总线不能在硬件层就将挂在其上的设备枚举出来。相反地,软件必须清楚哪个设备挂在哪个I2C总线上及各个设备的地址ID。所以,内核驱动代码必须显式地“手动”实例化I2C设备。针对不同设备操作的复杂度及项目及其他需要,目前有四种实例化I2C设备的方法:

第一:根据I2C总线号来实例化设备

    这种方法适用于用I2C作为系统总线的嵌入式设备。在这类系统中,I2C总线会事先确定一个总线号,正是这个原因,就可以提前定义(原文是pre-declare字面意思是声明,但个人感觉是定义,此处值得商榷,还请读者多提宝贵意见,下同)挂在确定了总线号的I2C总线设备了。对I2C总线设备的定义是通过结构体i2c_board_info来完成的,该结构体实例后来会被i2c_register_board_info()函数调用并挂到一个专门管理i2c_board_info结构的链表。

用omap2 h4为例来说明:

static struct i2c_board_info __initdata h4_i2c_board_info[] = {
	{
		I2C_BOARD_INFO("isp1301_omap", 0x2d),
		.irq		= OMAP_GPIO_IRQ(125),
	},
	{	/* EEPROM on mainboard */
		I2C_BOARD_INFO("24c01", 0x52),
		.platform_data	= &m24c01,
	},
	{	/* EEPROM on cpu card */
		I2C_BOARD_INFO("24c01", 0x57),
		.platform_data	= &m24c01,
	},
};

static void __init omap_h4_init(void)
{
	(...)/* 指定1号总线 */
	i2c_register_board_info(1, h4_i2c_board_info,
			ARRAY_SIZE(h4_i2c_board_info));
	(...)
}
        上面的代码在1号I2C总线上定义了3个设备,结构中包含了它们的名字(I2C设备总线驱动框架i2c_match_id()函数就是根据这个名字与i2c_driver结构中id_table成员中的名字进行匹配来完成设备与驱动程序的挂接)、设备地址以及驱动程序中要用到的私有数据。当平台驱动要注册I2C总线时,其下面的相应设备也就会被自动地实例化。

    同时,已经被实例化的设备也会在I2C总线被系统释放时被释放或者说被析构,这一般发生在系统关闭时。

第二:显式地实例化设备

    这种方法适用于I2C总线作为一个大型设备的内部通信通道的情况,一个典型的例子是TV适配器,内部包含调频器、音频解码器、视频解码器,它们往往通过I2C总线同TV适配器主芯片相连。在定义这些子设备的时候,事先不能确定I2C总线号,因此前文所述的方法将不再适用。此时,就应该使用显式地实例化设备这种方法了,这种方法通过填充结构i2c_board_info并调用i2c_new_device函数来实例化设备。

以sfe4001 网络设备驱动为例:

static struct i2c_board_info sfe4001_hwmon_info = {
	I2C_BOARD_INFO("max6647", 0x4e),
};

int sfe4001_init(struct efx_nic *efx)
{
	(...)
	efx->board_info.hwmon_client =
		i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info);

	(...)
}