Linux I2C 從裝置測試單元后端

作者:Wolfram Sang <wsa@sang-engineering.com>,2020 年

此後端可用於觸發 I2C 匯流排主裝置的測試用例,這些用例需要具有特定功能的遠端裝置(且這些裝置通常不易獲得)。示例包括多主裝置測試和 SMBus 主機通知測試。對於某些測試,I2C 從裝置控制器必須能夠在主模式和從模式之間切換,因為它也需要傳送資料。

請注意,此裝置用於測試和除錯。它不應在生產版本中啟用。儘管存在一些版本控制並且我們努力保持向後相容性,但無法保證穩定的 ABI!

例項化裝置是常規操作。例如,對於匯流排 0,地址 0x30

# echo "slave-testunit 0x1030" > /sys/bus/i2c/devices/i2c-0/new_device

或者使用韌體節點。這是一個裝置樹示例(請注意,這只是一個除錯裝置,因此沒有官方的 DT 繫結)

&i2c0 {
      ...

      testunit@30 {
              compatible = "slave-testunit";
              reg = <(0x30 | I2C_OWN_SLAVE_ADDRESS)>;
      };
};

之後,裝置將開始監聽。讀取將返回一個位元組。如果測試單元空閒,其值為 0,否則為當前執行命令的命令號。

寫入時,裝置由 4 個 8 位暫存器組成,除了一些“部分”命令外,所有暫存器都必須寫入才能啟動測試用例,即通常向裝置寫入 4 位元組資料。這些暫存器是

偏移

名稱

描述

0x00

CMD

觸發哪個測試

0x01

DATAL

測試的配置位元組 1

0x02

DATAH

測試的配置位元組 2

0x03

DELAY

測試啟動前延遲 n * 10 毫秒

使用 i2c-tools 包中的 ‘i2cset’ 命令,通用命令格式如下

# i2cset -y <bus_num> <testunit_address> <CMD> <DATAL> <DATAH> <DELAY> i

DELAY 是一個通用引數,它將延遲 CMD 中測試的執行。當一個命令正在執行(包括延遲)時,新命令將不會被確認。您需要等待舊命令完成。

命令將在以下部分中描述。無效命令將導致傳輸不被確認。

命令

0x00 NOOP

保留供將來使用。

0x01 READ_BYTES

CMD

DATAL

DATAH

DELAY

0x01

要讀取資料的地址(低 7 位,最高位目前未使用)

要讀取的位元組數

n * 10 毫秒

也需要主模式。這對於測試您的匯流排主驅動程式是否正確處理多主模式很有用。您可以觸發測試單元從總線上的另一個裝置讀取位元組。如果正在測試的匯流排主裝置也想同時訪問匯流排,則匯流排將處於忙碌狀態。示例:延遲 50 毫秒後從裝置 0x50 讀取 128 位元組

# i2cset -y 0 0x30 1 0x50 0x80 5 i

0x02 SMBUS_HOST_NOTIFY

CMD

DATAL

DATAH

DELAY

0x02

要傳送的狀態字的低位元組

要傳送的狀態字的高位元組

n * 10 毫秒

也需要主模式。此測試將向主機發送一個 SMBUS_HOST_NOTIFY 訊息。請注意,目前 Linux 核心中會忽略狀態字。示例:延遲 10 毫秒後傳送狀態字為 0x6442 的通知

# i2cset -y 0 0x30 2 0x42 0x64 1 i

如果主機控制器支援 HostNotify,則應出現此除錯級別的訊息(Linux 6.11 及更高版本)

Detected HostNotify from address 0x30

0x03 SMBUS_BLOCK_PROC_CALL

CMD

DATAL

DATAH

DELAY

0x03

0x01(即會寫入一個額外位元組)

要傳送回的位元組數

省略,部分命令!

部分命令。此測試將響應 SMBus 規範中定義的塊程序呼叫。寫入的一個數據位元組指定在隨後的讀取傳輸中將返回多少位元組。請注意,在此讀取傳輸中,測試單元將預置後續位元組的長度。因此,如果您的主機匯流排驅動程式像大多數驅動程式一樣模擬 SMBus 呼叫,它需要支援 i2c_msg 的 I2C_M_RECV_LEN 標誌。這是一個很好的測試用例。返回的資料首先包含長度,然後是一個從 length-1 到 0 的位元組陣列。以下是使用 i2ctransfer 模擬 i2c_smbus_block_process_call() 的示例(您需要 i2c-tools v4.2 或更高版本)

# i2ctransfer -y 0 w3@0x30 3 1 0x10 r?
0x10 0x0f 0x0e 0x0d 0x0c 0x0b 0x0a 0x09 0x08 0x07 0x06 0x05 0x04 0x03 0x02 0x01 0x00

0x04 GET_VERSION_WITH_REP_START

CMD

DATAL

DATAH

DELAY

0x04

目前未使用

目前未使用

省略,部分命令!

部分命令。傳送此命令後,測試單元將回復一個讀取訊息,該訊息包含一個基於 UTS_RELEASE 的以 NUL 結尾的版本字串。第一個字元始終是 'v',版本字串的最大長度為 128 位元組。但是,它只會在讀取訊息透過重複啟動與寫入訊息連線時才響應。如果您的控制器驅動程式正確處理重複啟動,這將起作用

# i2ctransfer -y 0 w3@0x30 4 0 0 r128
0x76 0x36 0x2e 0x31 0x31 0x2e 0x30 0x2d 0x72 0x63 0x31 0x2d 0x30 0x30 0x30 0x30 ...

如果您有 i2c-tools 4.4 或更高版本,您可以立即打印出資料

# i2ctransfer -y -b 0 w3@0x30 4 0 0 r128
v6.11.0-rc1-00009-gd37a1b4d3fd0

兩條訊息之間的 STOP/START 組合將不起作用,因為它們不等同於重複啟動(REPEATED START)。例如,這隻會返回預設響應

# i2cset -y 0 0x30 4 0 0 i; i2cget -y 0 0x30
0x00

0x05 SMBUS_ALERT_REQUEST

CMD

DATAL

DATAH

DELAY

0x05

響應值(7 個最高有效位被解釋為 I2C 地址)

目前未使用

n * 10 毫秒

此測試透過 SMBAlert 引腳觸發中斷,主機控制器必須處理該中斷。該引腳必須作為 GPIO 連線到測試單元。GPIO 訪問不允許休眠。目前,這隻能使用韌體節點來描述。因此,對於裝置樹,您可以在測試單元節點中新增類似如下的內容

gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;

以下命令將在延遲 1 秒後觸發警報,響應值為 0xc9

# i2cset -y 0 0x30 5 0xc9 0x00 100 i

如果主機控制器支援 SMBusAlert,則應出現此除錯級別的訊息

smbus_alert 0-000c: SMBALERT# from dev 0x64, flag 1

此訊息可能會出現多次,因為測試單元是軟體而非硬體,因此可能無法足夠快地響應主機的應答。但是,中斷計數應只增加一次

# cat /proc/interrupts | grep smbus_alert
 93:          1  gpio-rcar  26 Edge      smbus_alert

如果主機在 1 秒內未響應警報,則測試將中止,測試單元將報告錯誤。

對於此測試,測試單元將暫時放棄其分配的地址,並在 SMBus 警報響應地址 (0x0c) 上監聽。之後它將重新分配其原始地址。