I2C/SMBus 功能检查

介绍

因为不是每个I2C或SMBus适配器都实现了I2C规范中的所有内容,当client被赋予附加到适配器的选项时,它不能相信它需要的所有东西都实现了:client需要一些方法来检查适配器是否具有所需的功能。

功能常量

关于最新的功能常量列表,请查看<uapi/linux/i2c.h>!

I2C_FUNC_I2C

纯i2c-level命令(纯SMBus适配器通常不能执行这些命令)

I2C_FUNC_10BIT_ADDR

处理10位地址扩展

I2C_FUNC_PROTOCOL_MANGLING

了解I2C_M_IGNORE_NAK, I2C_M_REV_DIR_ADDR 和 I2C_M_NO_RD_ACK标志(修改I2C协议!)

I2C_FUNC_NOSTART

可以跳过重复的启动顺序

I2C_FUNC_SMBUS_QUICK

处理SMBus write_quick命令

I2C_FUNC_SMBUS_READ_BYTE

处理SMBus read_byte命令

I2C_FUNC_SMBUS_WRITE_BYTE

处理SMBus write_byte命令

I2C_FUNC_SMBUS_READ_BYTE_DATA

处理SMBus read_byte_data命令

I2C_FUNC_SMBUS_WRITE_BYTE_DATA

处理SMBus write_byte_data命令

I2C_FUNC_SMBUS_READ_WORD_DATA

处理SMBus read_word_data命令

I2C_FUNC_SMBUS_WRITE_WORD_DATA

处理SMBus write_byte_data命令

I2C_FUNC_SMBUS_PROC_CALL

处理SMBus process_call命令

I2C_FUNC_SMBUS_READ_BLOCK_DATA

处理SMBus read_block_data命令

I2C_FUNC_SMBUS_WRITE_BLOCK_DATA

处理SMBus write_block_data命令

I2C_FUNC_SMBUS_READ_I2C_BLOCK

处理SMBus read_i2c_block_data命令

I2C_FUNC_SMBUS_WRITE_I2C_BLOCK

处理SMBus write_i2c_block_data命令

 

为了方便起见,还定义了上述标志的一些组合:

I2C_FUNC_SMBUS_BYTE

处理SMBus read_byte和write_byte命令

I2C_FUNC_SMBUS_BYTE_DATA

处理SMBus read_byte_data和write_byte_data命令

I2C_FUNC_SMBUS_WORD_DATA

处理SMBus read_word_data和write_word_data命令

I2C_FUNC_SMBUS_BLOCK_DATA

处理SMBus read_block_data和write_block_data命令

I2C_FUNC_SMBUS_I2C_BLOCK

处理SMBus read_i2c_block_data和write_i2c_block_data命令

I2C_FUNC_SMBUS_EMUL

处理所有可以由真正的I2C适配器模拟的SMBus命令 (使用透明仿真层)

在3.5之前的内核版本中,I2C_FUNC_NOSTART作为I2C_FUNC_PROTOCOL_MANGLING的一部分实现。

适配器(Adapter)实现

当您编写一个新的适配器驱动程序时,您必须实现一个函数回调功能。下面给出了典型的实现。

典型的仅SMBus适配器将列出它支持的所有SMBus事务。这个例子来自于i2c-piix4驱动程序:

static u32 piix4_func(struct i2c_adapter *adapter)
{
      return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
             I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
             I2C_FUNC_SMBUS_BLOCK_DATA;
}

典型的 full-I2C 适配器将使用以下内容(来自i2c-pxa驱动程序):

static u32 i2c_pxa_functionality(struct i2c_adapter *adap)
{
      return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}

I2C_FUNC_SMBUS_EMUL包含了所有的SMBus事务(添加了I2C块事务),i2c-core可以使用I2C_FUNC_I2C模拟这些事务,而无需适配器驱动程序的任何帮助。其思想是让客户端驱动程序检查对SMBus函数的支持,而不必关心所述函数是由适配器在硬件中实现的,还是由i2c-core 在I2C适配器上软件模拟的。

Client 检查

在client尝试附加到adapter,或甚至进行测试以检查其支持的某个设备是否存在于adapter上之前,应该检查所需的功能是否存在。典型的方法是(从lm75驱动程序摘录):

static int lm75_detect(...)
{
      (...)
      if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
                                   I2C_FUNC_SMBUS_WORD_DATA))
              goto exit;
      (...)
}

在这里,lm75驱动程序检查适配器是否可以同时执行SMBus字节数据和SMBus字数据事务。如果没有,那么驱动程序将不能在这个适配器上工作,也就没有继续下去的意义。如果上面的检查成功,那么驱动程序知道它可以调用以下函数: i2c_smbus_read_byte_data(), i2c_smbus_write_byte_data(), i2c_smbus_read_word_data() 和 i2c_smbus_write_word_data()。作为经验法则,用 i2c_check_functions() 测试的功能常量应该与驱动程序调用的 i2c_smbus_* 函数完全匹配。

注意,上面的检查并不能说明这些功能是由底层适配器在硬件中实现的,还是由 i2c-core 在软件中模拟的。Client 驱动程序不必关心这一点,因为 i2c-core 将在I2C适配器上透明地实现SMBus事务。

通过/dev检查

如果试图从用户空间程序访问适配器,则必须使用/dev接口。当然,您仍然需要检查您需要的功能是否得到支持。这是使用I2C_FUNCS ioctl完成的。下面是一个改编自i2cdetect程序的示例:

int file;
if (file = open("/dev/i2c-0", O_RDWR) < 0) {
      /* Some kind of error handling */
      exit(1);
}
if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
      /* Some kind of error handling */
      exit(1);
}
if (!(funcs & I2C_FUNC_SMBUS_QUICK)) {
      /* Oops, the needed functionality (SMBus write_quick function) is
         not available! */
      exit(1);
}
/* Now it is safe to use the SMBus write_quick command */

 

posted @ 2021-08-19 15:48  闹闹爸爸  阅读(806)  评论(0编辑  收藏  举报