1.ピン制御サブシステムのソフトウェアフレームワーク図
1.機能とインターフェースの概要
一般的に言って、複雑なソフトウェアコンポーネントやソフトウェアモジュールを学ぶことは骨の折れるプロセスです。学習したいソフトウェアブロックはブラックボックスと見なすことができます。どんなに複雑であっても、最初のステップは常にその機能と外部インターフェイスの特性を理解することです。必要に応じて、内部実装を無視し、最初に内部ロジックについて考え、いくつかの質問を作成してから、これらの質問に答えてコードを確認することができます。これは多くの場合、より効果的です。
1)、機能仕様
ピン制御サブシステムの主な機能は次のとおりです。
a。管理システムで制御できるすべてのピン。システムが初期化されると、制御可能なすべてのピンが列挙され、これらのピンが識別されます。
b。これらのピンの多重化を管理します(多重化)。SOCの場合、ピンを通常のGPIOとして構成することに加えて、複数のピンがピングループを形成して特定の機能を形成することもできます。たとえば、ピン番号は{0、8、16、24}です。これらの4つのピンの組み合わせは、SPIの機能を提供するピングループを形成します。ピン制御サブシステムは、すべてのピングループを管理する必要があります。
c。これらのピンの特性を構成します。たとえば、このピンのプルアップ/ダウン抵抗を設定したり、ドライブ強度を設定したりします。
2)、インターフェース仕様
Linuxカーネルの特定のソフトウェアコンポーネントをLinuxシステムに戻して、そのインターフェイスとシステム内での位置を簡単に調べる必要があります。したがって、この章の2番目のセクションでは、各ピン制御サブシステムと他のカーネルモジュールについて説明します。システムブロックインターフェイスに基づいています。
3)、内部ロジック
サブシステムの内部ロジャーを調べるには、最初にブラックボックスを開き、モジュールを細分化してから、各モジュールの機能分析、外部インターフェイス分析、および内部ロジック分析を実行する必要があります。モジュールがまだ比較的大きく、習得が難しい場合は、引き続き細分化し、サブモジュールに分割して、上記の分析プロセスを繰り返します。この章の3番目のセクションでは、さらに分析するためにピン制御サブシステムのブラックボックスを開きます。
2.ピン制御サブシステムと他のLinuxカーネルモジュール間のインターフェイスの関係を次の図に示します。
ピン制御サブシステムは、システム内の他のドライバーへのインターフェースを提供して、ドライバーのピン構成とピンマルチプレクサを設定します。この部分のインターフェースについては、第4章で説明します。理想的な状態は、GPIO制御ドライバーがUARTやSPIなどのドライバーのようなピン制御サブシステムとのみ相互作用することです。ただし、実際には、さまざまな理由(後で詳しく説明します)により、ピン制御サブシステムとGPIOサブシステムが相互作用する必要があります。インターフェイスの概要は第5章で説明されています。第6章では、ドライバーモデルとピン制御サブシステム間のインターフェイスについて説明し、第7章では、ピン制御サブシステムのデータベースサポートを提供するデバイスツリーとマシンドライバー間のインターフェイスについて説明します。
3、ピン制御サブシステム内部ブロック図
実際、インターフェイスの内容の一部を理解した後は、ピン制御サブシステムの内部ロジックを読み取って分析するのは非常に簡単なので、この記事では分析しません。
2.ピン制御サブシステムによって他のドライバーに提供されるインターフェース
通常のLinxuドライバー(シリアルポートドライバーなど)を作成する準備をしているとき、ピン制御サブシステムによって提供されるインターフェイスはどのようになると思いますか?シンプル、もちろん最高はシンプル、最高はインターフェースなし、もちろんこれは可能です。インターフェースの第6章を参照してください。
1。概要
通常のドライバー呼び出しピン制御サブシステムの主な目標は次のとおりです。
1)デバイスの機能再利用を設定します。デバイスの機能の再利用を設定するには、2つの概念を理解する必要があります。1つは機能であり、もう1つはピングループです。functionは、SPI0などのHWロジックブロックに対応する機能の抽象化です。特定の機能名が付けられていますが、使用されているピンについてはわかりません。例:設計の柔軟性のために、チップ内のSPI0の機能はピングループ{A8、A7、A6、A5}に導出されるか、別のピングループ{G4、G3、G2、G1}に導出されますが、間違いなく、これら2つのピングループを同時にアクティブにすることはできません。結局のところ、チップ内に存在できるSPI0のロジックポイントは1つだけです。したがって、関数セレクター(いわゆるセレクターはIDまたはインデックス)と関数のピングループセレクターのみを使用して、関数muxを設定できます。
2)デバイスに対応するピンの電気的特性を設定します。
また、電源管理の要件により、デバイスがアイドルやスリープなどの特定の電源管理状態になっている場合があります。このとき、デバイスに属するすべてのピンを別の状態にする必要があります。上記の要件に基づいて、ピン制御状態の概念を定義しました。これは、デバイスが多くの状態の1つになり、デバイスドライバーがデバイスの状態を切り替えることができることを意味します。ピン制御状態の管理を容易にするために、デバイスのすべてのピン制御状態を管理するためのピン制御状態ホルダーの概念を提案しました。したがって、ピン制御サブシステムを呼び出す通常のドライバのインターフェイスは、論理的に主に次のようになります。
(1)ピン制御状態ホルダーのハンドルを取得します
(2)ピン制御状態の設定
(3)ピン制御状態ホルダーのハンドルを離します
struct pinctrl {
struct list_head node; //系统中的所有 device 的 pin control state holder 被挂入到了一个全局链表中
struct device *dev; //该 pin control state holder 对应的 device
struct list_head states; //该设备的所有的状态被挂入到这个链表中
struct pinctrl_state *state; //当前的 pin control state
struct list_head dt_maps; // mapping table
struct kref users; //reference count
};
ピン制御サブシステムと対話する必要があるシステム内のすべてのデバイスは、セットアップする前にこのハンドルを取得する必要があります。デバイスに属するすべての状態は、リンクリストにリンクされています。リンクリストの先頭は、ピン制御状態ホルダーの状態メンバーです。状態の定義は次のとおりです。
struct pinctrl_state {
struct list_head node; //挂入链表头的节点
const char *name; //该 state 的名字
struct list_head settings; //属于该状态的所有的 setting
};
ピン状態にはいくつかの設定が含まれ、すべての設定がリンクリストにハングアップします。リンクリストの先頭は、ピン状態の設定メンバーであり、次のように定義されます。
struct pinctrl_setting {
struct list_head node;
enum pinctrl_map_type type;
struct pinctrl_dev *pctldev;
const char *dev_name;
union {
struct pinctrl_setting_mux mux;
struct pinctrl_setting_configs configs;
}data;
};
ドライバがピン状態を設定すると、ピン制御サブシステムは状態の設定リンクリストをトラバースし、設定を1つずつ設定します。これらの設定にはさまざまなタイプがあり、次のように定義されています。
enum pinctrl_map_type {
PIN_MAP_TYPE_INVALID,
PIN_MAP_TYPE_DUMMY_STATE,
PIN_MAP_TYPE_MUX_GROUP, //功能复用的 setting
PIN_MAP_TYPE_CONFIGS_PIN, //设定单一一个 pin 的电气特性
PIN_MAP_TYPE_CONFIGS_GROUP, //设定单 pin group 的电气特性
};
次のように定義されたピンマルチプレクサ関連の設定(PIN_MAP_TYPE_MUX_GROUP)があります。
struct pinctrl_setting_mux {
unsigned group; //该 setting 所对应的group selector
unsigned func; //该 setting 所对应的 function selector
};
functiongに属する機能セレクターとグループセレクターを使用して、デバイスとピンマルチプレクサ関連の設定を行うことができます。電気的特性を設定するための設定は次のように定義されています。
struct pinctrl_map_configs {
const char *group_or_pin; //该pin或者pin group 的名字
unsigned long *configs; //要设定的值的列表。这个值用来写入 HW
unsigned num_configs; //列表中值的个数
};
2.特定のインターフェース
1)devm_pinctrl_get和pinctrl_get
devm_pinctrl_getはpinctrl_getのリソース管理バージョンであり、コアはpinctrl_get関数です。これらのインターフェイスは両方とも、デバイス(デバイスモデルのstruct device)のピン制御状態ホルダー(struct pinctrl)を取得するためのものです。ピン制御状態ホルダーは静的に定義されておらず、通常、関数が初めて呼び出されたときに動的に作成されます。ピン制御状態ホルダーの作成は大きなプロジェクトです。次のコードを分析してみましょう。
static struct pinctrl *create_pinctrl(struct device *dev)
{
分配pin control state holder占用的内存并初始化
p = kzalloc(sizeof(*p), GFP_KERNEL);
p->dev = dev;
INIT_LIST_HEAD(&p->states);
INIT_LIST_HEAD(&p->dt_maps);
mapping table这个database的建立也是动态的,当第一次调用pin control state holder的get函数的时候,就会通过调用pinctrl_dt_to_map来建立该device需要的mapping entry。具体请参考第七章。
ret = pinctrl_dt_to_map(p);
devname = dev_name(dev);
mutex_lock(&pinctrl_maps_mutex);
for_each_maps(maps_node, i, map) {
/* Map must be for this device */
if (strcmp(map->dev_name, devname))
continue;
ret = add_setting(p, map);----分析一个mapping entry,把这个setting的代码加入到holder中
}
mutex_unlock(&pinctrl_maps_mutex);
kref_init(&p->users);
/* 把这个新增加的pin control state holder加入到全局链表中 */
mutex_lock(&pinctrl_list_mutex);
list_add_tail(&p->node, &pinctrl_list);
mutex_unlock(&pinctrl_list_mutex);
return p;
}
2)devm_pinctrl_put和pinctrl_put
はい1)インターフェースの逆関数。Devm_pinctrl_getとpinctrl_getは、ハンドルを取得するときに多くのリソースを適用します。ハンドルは、devm_pinctrl_putとpinctrl_putで解放できます。get関数を複数回呼び出すと、サポートが繰り返し割り当てられることはなく、参照カウントのみが1つインクリメントされ、参照カウントが1つデクリメントされ、デバイスのすべてのピン制御状態ホルダーがサポートを割り当てることに注意してください。 count == 0のときに解放されます。リソース。
3)pinctrl_lookup_state
状態名に従って、ピン制御状態ホルダーで対応するピン制御状態を見つけます。特定の状態は各デバイスによって定義されますが、ピン制御サブシステムは、pinctrl-stat.hファイルで定義されているいくつかの標準的なピン制御状態を定義します。
#define PINCTRL_STATE_DEFAULT "default"
#define PINCTRL_STATE_IDLE "idle"
#define PINCTRL_STATE_SLEEP "sleep"
4)pinctrl_select_state
特定のピン制御スタイルインターフェイスを設定します。