IIC学习(一):如何实例化一个IIC设备

不像PCI或者usb设备,I2C设备在硬件层次上不具备枚举特性。因此软件上必须知道哪些设备在IIC总线上,这些设备使用什么地址。因为这些原因,内核代码必须实例化这些设备。有实现这一点的几种方法,根据上下文或需求。

  • 方法一:按总线号声明I2C设备

当I2C总线是系统总线时(与许多嵌入式系统一样),此方法适用。 在这样的系统上,每个I2C总线都有一个事先已知的编号。 因此可以预先声明该总线上的I2C设备。 这是通过调用i2c_register_board_info()注册的struct i2c_board_info数组完成的。

例如:(from 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)
{
	(...)
	i2c_register_board_info(1, h4_i2c_board_info,
			ARRAY_SIZE(h4_i2c_board_info));
	(...)
}

上面的代码在I2C总线1上声明了3个设备,包括它们各自的驱动程序所需的地址和自定义数据。 当I2C总线进入
问题已注册,I2C设备将自动实例化由i2c-core。当设备所在的I2C总线消失时(如果有的话),它们将自动解除绑定并销毁。

解释:

1.上述方法定义了一个i2c_board_info,包括:名字, 设备地址, 然后i2c_register_board_info(busnum, ...)   (把它们放入__i2c_board_list链表)——>  list_add_tail(&devinfo->list, &__i2c_board_list);

2. i2c_register_adapter > i2c_scan_static_board_info函数通过匹配总线号码,创建一个 i2c_new_device

注意:这种方法首先创建i2c_board_info,加入链表,然后才可以i2c_register_adapter > i2c_scan_static_board_info通过匹配总线号码,这样有序才可以。所以:不适合我们动态加载insmod。

  • 方法二:显式实例化设备

当较大的设备将I2C总线用于内部沟通。 一个典型的例子是电视适配器。 它们可以具有通常通过I2C总线连接到主芯片的调谐器,视频解码器,音频解码器等。 您不会事先知道I2C总线的编号,因此无法使用上述方法1。 相反,您可以显式实例化I2C设备。 这是通过填充struct i2c_board_info并调用i2c_new_device()来完成的。

例如:(from the sfe4001 network driver)

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);

	(...)
}

上面的代码实例化了所讨论的网络适配器上I2C总线上的1个I2C设备。

这种情况的一种变体是当您不确定是否存在I2C设备时(例如,可选功能,该功能在板的廉价变体中不存在,但您无法区分它们),或者 它的地址可能从一个板到另一个板(制造商在不另行通知的情况下更改其设计)具有不同的地址。 在这种情况下,您可以调用i2c_new_probed_device()而不是i2c_new_device()。

  • 方法3:探查某些设备的I2C总线

有时您没有关于I2C设备的足够信息,甚至没有调用i2c_new_probed_device()。 典型的情况是PC主板上的硬件监视芯片。 有几十种模型,它们可以存在于25个不同的地址。 鉴于那里有大量的主板,几乎不可能建立一个完整的硬件监控芯片清单。 幸运的是,这些芯片大多数都有制造商和设备ID寄存器,因此可以通过探测来识别它们。

在这种情况下,IIC设备既没有探测也没有显式声明, 取而代之的是,i2c-core会在驱动程序加载后立即检测此类设备,如果找到了驱动程序,则会自动实例化I2C设备。 为了防止此机制的任何不当行为,适用以下限制:
1.I2C设备驱动程序必须实现detect()方法,该方法 通过从任意寄存器读取来识别支持的设备。
2.仅对可能具有受支持的设备并同意进行探测的总线进行探测。 例如,这避免了探测电视适配器上的硬件监视芯片。

例:
请参阅drivers / hwmon / lm90.c中的lm90_driver和lm90_detect()

当成功检测到实例化的I2C设备时,检测到它们的驱动程序将被删除,或者当基础I2C总线本身被销毁时(以先发生者为准),它们将被自动销毁。

那些熟悉2.4内核和早期2.6内核的i2c子系统的人会发现,此方法3本质上与此处所做的相似。两个重要区别是:
   *探测只是现在实例化I2C设备的一种方法,而那是那时的唯一方法。在可能的情况下,应首选方法1和2。

 *现在,I2C总线必须明确地说明哪些I2C驱动程序类可以对其进行探测(通过类位域),而所有I2C总线默认情况下都在那时进行探测。默认值为空类,这意味着不进行探测。类位域的目的是限制上述不利的副作用。

再一次,应尽可能避免使用方法3。显式设备实例化(方法1和2)是更可取的,因为它更安全且快点。

方法4:从用户空间实例化
-------------------------------------

通常,内核应该知道连接了哪些I2C设备以及它们位于什么地址。但是,在某些情况下却没有,因此添加了sysfs接口,以使用户提供信息。该接口由2个属性文件组成,这些文件在每个I2C总线目录中创建:new_device和delete_device。这两个文件都是只写的,并且必须为它们写入正确的参数,以正确地实例化或删除I2C设备。

文件new_device具有2个参数:I2C设备的名称(字符串)和I2C设备的地址(一个数字,通常以十六进制表示,以0x开头,但也可以以十进制表示。)

文件delete_device使用一个参数:I2C的地址设备。由于没有两个设备可以在给定的I2C上位于相同的地址段,所以该地址足以唯一标识要使用已删除的设备。

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

在无法进行内核设备声明时才应使用此接口,在许多情况下它可能会有所帮助:

* I2C驱动程序通常会检测设备(上述方法3),但总线设备所处的网段未设置适当的类别位,因此不会触发检测。
* I2C驱动程序通常会检测到设备,但是您的设备位于意外地址中。
* I2C驱动程序通常会检测到设备,但由于检测程序太严格,或者因为尚未正式支持您的设备但您知道它是兼容的,所以未检测您的设备。
*您正在测试板上开发驱动程序,您在此处自行焊接了I2C器件。

该接口替代了一些I2C的force_ *模块参数驱动程序实现。在i2c核心而不是每个核心中实施单独使用设备驱动程序,它不仅效率更高,而且还具有优点是您不必重新加载驱动程序即可更改设置。您也可以在加载驱动程序之前甚至是实例化设备可用,并且您不需要知道设备需要什么驱动程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值