I2C/SMBus 功能¶
引言¶
因為並非每個 I2C 或 SMBus 介面卡都實現了 I2C 規範中的所有功能,所以客戶端不能相信在被允許連線到介面卡時,它所需的一切都已實現:客戶端需要一種方法來檢查介面卡是否具有所需的功能。
功能常量¶
要獲取最新功能常量列表,請查閱 <uapi/linux/i2c.h>!
I2C_FUNC_I2C
純 I2C 級別命令(純 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 的一部分實現的。
介面卡實現¶
當你編寫新的介面卡驅動時,你必須實現一個函式回撥 functionality。典型的實現如下所示。
一個典型的純 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;
}
一個典型的完整 I2C 介面卡會使用以下內容(來自 i2c-pxa 驅動)
static u32 i2c_pxa_functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
I2C_FUNC_SMBUS_EMUL 包含了 i2c-core 能夠使用 I2C_FUNC_I2C 模擬的所有 SMBus 事務(以及 I2C 塊事務),無需介面卡驅動的任何幫助。這樣做的目的是讓客戶端驅動檢查 SMBus 函式的支援情況,而無需關心這些函式是由介面卡硬體實現,還是由 i2c-core 在 I2C 介面卡之上軟體模擬的。
客戶端檢查¶
在客戶端嘗試連線到介面卡,甚至進行測試以檢查其支援的裝置是否在介面卡上存在之前,它應該檢查所需的功能是否存在。典型的方法是(來自 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_functionality() 測試的功能常量應與你的驅動程式呼叫的 i2c_smbus_* 函式完全匹配。
請注意,上述檢查並未說明這些功能是由底層介面卡在硬體中實現,還是由 i2c-core 在軟體中模擬的。客戶端驅動程式無需關心這一點,因為 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 */