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 */
本文来自博客园,作者:闹闹爸爸,转载请注明原文链接:https://www.cnblogs.com/wanglouxiaozi/p/15162169.html