目次
方法 1b: デバイス ツリーを通じて I2C デバイスを宣言する
次のコンテンツは ./Linux-4.9.88/Documentation/i2c/instantiating-devices からのもので、中国語に翻訳されたものです。
I2C デバイスをインスタンス化する方法
PCI や USB デバイスとは異なり、I2C デバイスはハードウェア レベルで列挙されません。代わりに、ソフトウェアは各 I2C バス セグメントにどのデバイスが接続されているか、およびそれらのデバイスが使用するアドレスを認識する必要があります。したがって、カーネル コードは I2C デバイスを明示的にインスタンス化する必要があります。コンテキストと要件に応じて、これを実現するにはいくつかの方法があります。
方法 1a: バス番号で I2C デバイスを宣言する
このアプローチは、多くの組み込みシステムの場合と同様、I2C バスがシステム バスである場合に適しています。このようなシステムでは、各 I2C バスには既知の番号があります。したがって、このバス上の I2C デバイスは事前に宣言できます。これは、 構造体の配列のi2c_register_board_info()
Register を呼び出すことによってi2c_board_info
行われます。
例 (omap2 h4 から):
static struct i2c_board_info h4_i2c_board_info[] __initdata = {
{
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-core によって自動的にインスタンス化されます。
接続されている I2C バスが消滅すると (消滅した場合)、デバイスは自動的にバインドを解除され、破棄されます。
方法 1b: デバイス ツリーを通じて I2C デバイスを宣言する
この方法は方法 1a と同じ意味です。I2C デバイスの宣言は、マスター コントローラーの子ノードとしてデバイス ツリーを通じて行われます。
例:
i2c1: i2c@400a0000 {
/* ... 跳过主属性 ... */
clock-frequency = <100000>;
flash@50 {
compatible = "atmel,24c256";
reg = <0x50>;
};
pca9532: gpio@60 {
compatible = "nxp,pca9532";
gpio-controller;
#gpio-cells = <2>;
reg = <0x60>;
};
};
ここでは、2 つのデバイスが 100kHz の速度のバスを使用して接続されています。デバイスに設定する必要があるその他のプロパティについては、Documentation/devicetree/bindings/ にあるデバイス ツリーのドキュメントを参照してください。
方法 1c: ACPI 経由で I2C デバイスを宣言する
ACPI は I2C デバイスを記述することもできます。これに関する特別なドキュメントは現在、Documentation/acpi/enumeration.txt にあります。
方法 2: デバイスを明示的にインスタンス化する
この方法は、より大きなデバイスが内部通信に I2C バスを使用する場合に適しています。通常、これは TV アダプターです。チューナー、ビデオ デコーダー、オーディオ デコーダーなどを搭載することができ、通常は I2C バスを介してメイン チップに接続されます。I2C バスの番号は事前にわからないため、上記の方法 1 は使用できません。代わりに、I2C デバイスを明示的にインスタンス化できます。i2c_board_info
これは、構造体 を埋めてそれを呼び出すことによって i2c_new_device()
行われます。
例 (sfe4001 ネットワークドライバーから):
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);
(...)
}
上記のコードは、ネットワーク アダプターの I2C バス上で I2C デバイスをインスタンス化します。
I2C デバイスが存在するかどうかが不明な場合 (たとえば、ボードの安価なモデルには存在しないが区別できないオプション機能の場合)、またはボードごとにアドレスが異なる可能性があります (メーカーは予告なくデザインを変更します)。この場合、 i2c_new_probed_device()
代わりに を 呼び出すことができますi2c_new_device()
。
例 (nxp OHCI ドライバーから):
static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
static int 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);
(...)
}
上記のコードは、OHCI アダプタの I2C バス上で最大 1 つの I2C デバイスをインスタンス化します。最初にアドレス 0x2c を試行し、そこで何も見つからない場合は、次にアドレス 0x2d を試行します。それでも何も見つからない場合は、単純に諦めます。
I2C デバイスをインスタンス化するドライバーは、クリーンアップ時にデバイスを破棄する責任があります。i2c_new_device()
これは、または によって以前に 返されたi2c_new_probed_device()
ポインタを呼び出すことによって行われます 。i2c_unregister_device()
方法 3: 一部のデバイスの I2C バスをプローブする
I2C デバイスについて、「 」と呼ぶほど十分な知識がない場合もあります i2c_new_probed_device()
。通常、これは PC マザーボード上のハードウェア監視チップです。数十のモデルが 25 か所の異なる場所で入手可能です。マザーボードの数が膨大であることを考えると、使用されているハードウェア監視チップの完全なリストを作成することはほぼ不可能です。幸いなことに、これらのチップのほとんどにはメーカー ID レジスタとデバイス ID レジスタがあるため、プローブすることで識別できます。
この場合、I2C デバイスは宣言も明示的にインスタンス化もされません。代わりに、ドライバーがロードされると、i2c-core はこれらのデバイスを探索し、デバイスが見つかった場合は、自動的に I2C デバイスをインスタンス化します。このメカニズムの誤動作を防ぐために、次の制限が適用されます。
- I2C デバイス ドライバーは、
detect()
任意のレジスタから読み取ることによってサポートされているデバイスを識別するメソッドを実装する必要があります。 - サポートデバイスがあり、プローブされることに同意したバスのみがプローブされます。これにより、たとえば、TV アダプター上のハードウェア監視チップのプローブを回避できます。
例: drivers/hwmon/lm90.c の lm90_driver および lm90_detect() を参照してください。
検出が成功した結果としてインスタンス化された I2C デバイスは、ドライバの削除が検出されたとき、または基礎となる I2C バス自体が破壊されたときのいずれかが先に発生したときに、自動的に破棄されます。
2.4 カーネルおよびそれ以前の 2.6 カーネルの i2c サブシステムに精通している人は、このアプローチ 3 が当時行われていたものと本質的に似ていることがわかるでしょう。注目すべき違いは次の 2 つです。
- 今ではプロービングは I2C デバイスをインスタンス化するための単なる方法ですが、当時はそれが唯一の方法でした。可能であれば、方法 1 と 2 を優先してください。方法 3 は、望ましくない副作用が発生する可能性があるため、他に利用可能な方法がない場合にのみ使用してください。
- すべての I2C バスがデフォルトでプローブされる場合、I2C バスはどの I2C ドライバ クラスがプローブできるかを (クラス ビット フィールド経由で) 明示的に指定する必要があります。デフォルトは空のカテゴリーです。これは、プローブが行われないことを意味します。クラス ビット フィールドの目的は、上記の望ましくない副作用を制限することです。
繰り返しになりますが、方法 3 は可能な限り避けてください。明示的なデバイスのインスタンス化 (方法 1 および 2) は、より安全で高速であるため、推奨されます。
方法 4: ユーザー空間からインスタンスを作成する
通常、カーネルは、どの I2C デバイスが接続されているか、およびそれらがどこに配置されているかを認識している必要があります。ただし、場合によっては不明なため、ユーザーが情報を提供できるように sysfs インターフェイスが追加されました。インターフェイスは、各 I2C バス ディレクトリに作成される 2 つのプロパティ ファイル (new_device と delete_device) で構成されます。どちらのファイルも書き込み専用なので、I2C デバイスを適切にインスタンス化または削除するには、正しいパラメータをファイルに書き込む必要があります。
ファイル new_device には、I2C デバイスの名前 (文字列) と I2C デバイスのアドレス (通常は 0x で始まる 16 進数で表されますが、10 進数で表すこともできる数値) の 2 つのパラメーターが必要です。
ファイル delete_device には、I2C デバイスのアドレスという 1 つのパラメータが必要です。特定の I2C セグメント上では 2 つのデバイスが同じアドレスに存在することはできないため、削除するデバイスを一意に識別するにはアドレスがあれば十分です。
例:
echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-3/new_device
このインターフェイスはカーネル デバイス宣言を完了できない場合にのみ使用されますが、次のようないくつかの状況で役立ちます。
- 通常、I2C ドライバーはデバイスを検出しますが (上記の方法 3)、デバイスが接続されているバス セグメントには正しいクラス ビットが設定されていないため、検出はトリガーされません。
- I2C ドライバーは通常デバイスを検出しますが、デバイスは予期しないアドレスにあります。
- 多くの場合、I2C ドライバーはデバイスを検出しますが、デバイスが検出されません。これは、検出ルーチンが厳密すぎるか、デバイスがまだ正式にサポートされていないため、互換性があることがわかっているためです。
- あなたは、I2C デバイスを自分で半田付けしたテスト ボード上でドライバを開発しています。
このインターフェイスは、一部の I2C ドライバーによって実装される Force_* モジュール パラメーターの代替品です。各デバイスドライバーに個別に実装されるのではなく、i2c-core に実装されるため、より効率的であり、設定を変更するときにドライバーを再ロードする必要がないという利点があります。ドライバーが読み込まれる前、または使用可能になる前にデバイスをインスタンス化することもでき、デバイスに必要なドライバーを知る必要はありません。