之前写的i2c驱动程序对应的linux-2.6的内核,在移植到linux-3.4时,发现好多API不一样了。让我们打开/linux-3.4.2/Documentation/i2c/instantiating-devices,一探究竟。
不像PCI或USB设备,I2C设备不在硬件级枚举。相反,软件必须知道连接在每个I2C总线段的设备,以及这些设备正在使用什么地址。因为这个原因,内核代码必须显式地实例化I2C设备。有实现这一目标的几种方法,取决于上下文和要求。
方法1:通过总线号来声明I2C设备
当I2C总线是系统总线的情况下,对于许多嵌入式系统这种方法是适当的。在这样的系统中,每个I2C总线有一个数字这是事先知道的。因此,可以预先声明附加在这个总线上的I2C设备。这是通过一个调用i2c_register_board_info()注册的结构体数组i2c_board_info。
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核心。
当他们依附的I2C总线消失时,设备将自动绑定并销毁(如果有的话)。
方法2:明确实例化设备
当一个较大的设备使用I2C总线内部沟通,这种方法是适当的。一个典型的例子是电视适配器。这些可以有调谐器、视频解码器、音频解码器等通常连接到主芯片采用I2C总线的方式。你不能提前知道I2C的总线数量,因此上述方法1不能使用。相反,您可以明确实例化您的I2C设备。这时填充结构i2c_board_info并调用i2c_new_device()。
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);
(...)
}
上面的代码中实例化1 个网络适配器I2C总线上的设备。
当你不知道如果一个I2C设备是否存在(例如在廉价的单板不存在的可选功能,但你没有办法告诉他们分开),或它可能有不同的地址在不同单板(制造商改变其设计,没有通知),您可以调用 i2c_new_probed_device()而不是i2c_new_device()。
static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
static int __devinit usb_hcd_nxp_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(struct i2c_board_info));
strlcpy(i2c_info.type, "isp1301_nxp", I2C_NAME_SIZE);
isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
normal_i2c, NULL);
i2c_put_adapter(i2c_adap);
(...)
}
上面的代码中实例化了1 个OHCI适配器I2C总线的设备。它第一次尝试在地址0x2c,如果没有发现尝试0x2d,如果仍然没有找到,它干脆放弃。
清理时实例化I2C设备的驱动程序负责销毁它。这是通过调用i2c_unregister_device()使用i2c_new_device()或i2c_new_probed_device()返回的指针。
方法3:探测某些设备的I2C总线
有时你没有足够的信息的I2C设备,甚至调用i2c_new_probed_device()。典型案例是在PC主板芯片的硬件监控。有几十种型号,可以使用25个不同的地址。鉴于主板的大量存在,要建立一个详尽正在使用的监控芯片硬件清单是不可能的。幸运的是,这些芯片大多制造商和设备ID寄存器,所以他们可以识别探测。
方法4:从用户空间实例化
一般来说,内核应该知道哪些I2C设备连接和他们住在什么住址。然而,在某些情况下,它没有,所以sysfs接口的加入,让用户提供信息。这接口是由2个属性文件,这是创建在每个I2C总线目录:new_device和delete_device。这两个文件只写和你为了正确实例化,必须将正确的参数写入它们,分别删除,一个I2C设备。
# echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-3/new_device
补充:支持设备树以后
i2c1: i2c@400a0000 {
/* ... master properties skipped ... */
clock-frequency = <100000>;
flash@50 {
compatible = "atmel,24c256";
reg = <0x50>;
};
pca9532: gpio@60 {
compatible = "nxp,pca9532";
gpio-controller;
#gpio-cells = <2>;
reg = <0x60>;
};
};