[深さ]魏東山:GPIOサブシステムとPinctrlを使用して

著者:魏東山

参考資料:
。Aカーネルのドキュメント\ devicetree \バインディング\ Pinctrl \ディレクトリの下:
Pinctrl-bindings.txt

GPIOの下のBカーネルのドキュメント\ディレクトリ:.
Pinctrl-bindings.txt

。devicetree \バインディング\ GPIOディレクトリの下のCカーネルのドキュメント\:
gpio.txt

注:この章の焦点は、ビデオの「バイブルドライバー」に関する詳細な説明は「使用」にあります。
ビデオの前で、私たちは、レジスタ・ドライブの直接の書き込み操作を使用しています。これはちょうど、誰もがドライバーの本質を把握できるようにすることです、我々は実際の開発プロセス、非常に非効率的ではそうはありません!あなたがそのようにレジスタを見つけるために、開発を駆動している場合は、私たちは「エンジニアを登録する」となって、さらに裸のマイクロコントローラのライトレジスタに固執しないでください。
GPIO、Pinctrl:Linuxでのピンのための2つの重要なサブシステムを持っています。

重要な概念をサブシステム1.Pinctrl

導入1.1

どんなにチップの種類、下の図に類似した構造を有します:
ここに画像を挿入説明

; PINA、GPIOのためにBを取得するには、彼らはIOMUX GPIOモジュールに接続されるように設定する必要が
PINA、I2C、I2Cモジュールにそれらを設定するIOMUXの必要性のためにBを取得します。
彼らはあなたがIOMUXを設定する必要があり、使用する前に、GPIOので、I2Cは、並置された関係でなければなりません。時には、ちょうどそのようなプルアップ、プルダウン、オープンドレイン、などなどIOMUX、だけでなく、コンフィギュレーション・ピンを、設定されていません。

チップの百さて、いくつかのピン、あなたが怒ってすることである対応するレジスタを、見つけるために、ピンを固定することができますGPIO機能を使用している間。これらのチップのメーカーは、彼らがBSPエンジニアです──それをやらせるために懸命に手術に特化した産業、。私たちは、彼らのもとに、私たちが駆動されるエンジニアを開発しています。あなたはエンジニアを運転場合ジョークは、BSPのエンジニアは、より良い自分のチップを知っているが、あなたの進歩は限らああであることを、自分のコードを理解していません。

そのため、ピンが出て設定するには、多重化すべき、Pinctrlサブシステム、GPIO、I2C、他のモジュールを作りました。
BSPエンジニアは何をしますか?ルック:
ここに画像を挿入説明
リストに追加した後、このようなBSPエンジニアGPIOサブシステムとして、Pinctrlサブシステムは、独自のチップをサポートするために、我々は非常に簡単にこれらのピンを使用することができます。照明があまりにも簡単です。

など、図のI2CモジュールとのGPIOはそれを平行ではありませんか?なぜで引っ張ってPinctrl Shihai GPIOサブシステムの話?
GPIOモジュール内のチップ、別個のモジュールIOMUXピン多重化、構成、等、のほとんどが実現されます。
GPIOとPinctrlは非常に密接にハードウェアに関連して、彼らの関係上のソフトウェアは非常に近いです。
だから私たちは一緒にこれらの2つのサブシステムを説明します。

1.2キーコンセプト

デバイスツリーからPintrlを学習を開始することが容易になります。
主な参考文献は以下のとおりです。カーネルのドキュメント\ devicetree \バインディング\ pinctrl \ pinctrl-bindings.txt

ピンコントローラ、クライアントデバイス:これは、2つのオブジェクトが含まれます。
前者は、サービスを提供します。あなたは、多重ピンにコンフィギュレーション・ピンを使用することができます。
後者の使用サービス:彼らはそれらを設定する方法、使用する必要がピン宣言するために備えてどのような。

ピンコントローラは:.
手動ピンコントローラを見つけることができないチップでは、ソフトウェアの概念であり、あなたはそれが多重化されたピンがIOMUX──を相当と考えることができ、ピンはまた、など、など、プルダウン抵抗として(設定することができます)。
メモ、ピン制御装置とコントローラGPIOない同じことが、前者は、GPIO機能ピン、I2C機能を制御するために使用することができる。後者は、ピンは入力、出力、および他の単純な関数として設定されています。

B。クライアントデバイス
を持つクライアント「クライアント・デバイス」、?デバイスのピンを使用して、機器Pinctrlシステムを使用する顧客Pinctrlシステム。これは、ノード、ピンが使用するれた文のノードとしてデバイスツリーに定義されます。
図は、いくつかの重要な概念を以下の明確な根拠を置くことができます:
ここに画像を挿入説明
上の図、pincontroller左ノードは、右のノードクライアントデバイスれる:
A PIN州:.
「クライアント・デバイス」の場合は、例えば、持っているUARTデバイスを、 「ステータス」の複数:デフォルト、睡眠などは、そのピンはまた、これらの状態を有することができます。

どのように理解するには?
例えば、デフォルトでは、UARTデバイスは、ピンは、UART機能として交互に使用され、動作しています。
節約電力のスリープ状態では、これらのピンは、GPIO機能として多重化することができる;またはハイレベル出力それらを直接設定します。
上の図、二つの状態の定義におけるpinctrl-名前:デフォルトでは、睡眠。
pincontrollerノードの位置0状態state_0_node_aあるpinctrl-0で使用されるピンの定義、。
最初のピンがpincontrollerノードを配置state_1_node_aあるpinctrl-1で用いた定義された状態、です。
このデバイスは、デフォルトの状態にあるとき、pinctrlサブシステム自動的に情報がUART0ピン多重化機能に従って使用されていると言わ。
このデバイスは、スリープ状態にある場合、自動的にピンを構成するために使用される情報に基づいてpinctrlサブシステムは高いです。

。b基及び機能:
デバイスグループ(グループ)に分類することができる1本のまたは複数のピンを使用する、
これらのピンは、関数として多重化することができる:関数。
もちろん:マルチ・ピン・デバイスを使用することができ、例えばA1、A2等の官能基を多重F1への2本のピンA1をA2は、関数F2を多重化グループです。

C。一般的なピン多重化ノードと汎用ピン構成ノード
図ピン制御ノードの左側には、ノードは、子又はクライアントデバイスのために使用される孫ノードを有しています。
多重化情報記述するために使用することができる:グループ(グループ)ピンは機能(関数)を用いて多重化され、
コンフィギュレーション情報を記述するために使用することができる:グループ(グループ)ピン機能(設定)を設定するように構成され、そのようなプルオンなどを上のように、ドロップダウン。

注:フォーマットピンコントローラー・ノードは、統一規格ではありません!各チップは異なっています。
でも上記グループ、ファンクションキーは必ずしもありませんが、概念があります。

1.3例

ここに画像を挿入説明

どのように参照が1.4のコードをpinctrl

私たちの基本的なドライブがコントロールしていないことは明らかです。デバイスのスイッチング状態は、対応するpinctrlときに呼び出されます。
例えば、列挙プロセスとplatform_driver platform_deviceで、手順は次のとおりです。
ここに画像を挿入説明
システムが休止しているとき、またピンに対応するデバイスのスリープ状態を設定するために、我々は自身の呼び出し元のコードには必要ありません。

自分自身を呼び出す必要があり、機能があります。

devm_pinctrl_get_select_default(struct device *dev);      // 使用"default"状态的引脚
pinctrl_get_select(struct device *dev, const char *name); // 根据name选择某种状态的引脚
pinctrl_put(struct pinctrl *p);   // 不再使用, 退出时调用

2.GPIOサブシステムの重要な概念

2.1を発表

GPIOピンを動作させるために、第一ピンがPinctrlサブシステムによって達成されるGPIO機能を使用するように構成されています。
次いで、得られた──レベル状態、書込み値──高及び低出力を読み取り、ピン方向(入力または出力)に応じて設定することができます。
私たちの前にGPIOピンは、レジスタによって運営たとえ完全に異なるコードされている別のボード用のLEDドライバ。
BSPエンジニアはGPIOサブシステムを達成したとき、我々ができます:
。Aは、デバイスツリーGPIOピンで指定された
ドライバコードでB:
標準関数の使用は、GPIO方向、読み出し/設定GPIO設け、GPIO GPIOサブシステムを得ます値。
そのようなドライバコードは、ボードは無関係であろう。

デバイスツリーピンで指定された2.2

ほぼすべてのARMチップの中で、GPIOをグループに分けられ、各グループは、ピンの数を有しています。だから、GPIOサブシステムを使用する前に、あなたは最初に決定する必要があります:それはどのグループですか?グループどちらで?
デバイスツリーで、「GPIO基」は、通常、チップ製造者によって設定されたGPIOコントローラです。私たちは、このような「GPIO1」として、その名を検索することですし、そのような<&GPIO1 0>として、内部にそれを使用するピンを指定する必要があります。
そこにコードより直感的、GPIOコントローラノード図はチップ数であり、これらは一般によくxxx.dtsiファイルに、製造業者によって規定されています。
ここに画像を挿入説明

我々は、これらの2つの属性の内側だけ心配する必要があります:

gpio-controller;
#gpio-cells = <2>;

「GPIOコントローラ」は、このノードは、GPIOコントローラであり、その下のピンが多いことを示しています。
「#GPIO細胞は= <2 >」 2つの32ビット数この(セル)を使用するコントローラの各ピンであるが記載されています。
なぜ二つの数字を使うのか?実際には、複数の細胞の使用は、GPIOコントローラ自身の判断でピンを、記述します。前記細胞は、それがアクティブハイまたはアクティブローであり、さらに他の細胞特性を示すために使用されてもよいことを示すために、他の細胞とそのピンがどの示すために実施例のために使用することができます。
一般的な使用は、有効なレベルを表すために、第二のセルによって表され、ピンのセルを使用することです。

GPIO_ACTIVE_HIGH : 高电平有效
GPIO_ACTIVE_LOW  :  低电平有效

我々はそれのピンを参照してくださいどのように、定義されたGPIOコントローラチップのメーカーが行うのですか?「[ - ]のGPIO」自ノード装置の属性を使用して次のように、一例です。
ここに画像を挿入説明

図上、使用される名前 - のGPIO性であってもよい、のGPIO特性を使用することができます。

2.3 GPIOサブシステムは、ドライバのコードを呼び出します

GPIOピンは、ドライバコードを使用する方法、デバイスツリーに指定されていますか?
それは、GPIOインタフェース・サブシステムの機能がある何ですか?
ベース記述子(記述子ベース)、古い(レガシー):GPIOサブシステムは、2つのインタフェースを有しています。前者は機能接頭辞「gpiod_」を有し、それはgpio_desc Aピン構造を用いて表され、後者の関数は、整数を表すためにピンを使用する接頭語「gpio_」を有しています。

ピンを操作するには、最初にピンを取得し、その値を書き込み、読み込みの方向を設定する必要があります。

ドライバのヘッダファイルに含まれるように、
書式#include <Linuxの/ GPIO / consumer.h> //記述子ベース
または
書式#include <linuxの/ gpio.h> //レガシー

次の表に、一般的な機能:
ここに画像を挿入説明

接頭辞「devm_」とリソースの解放のための自動機構である「デバイスエクスプローラ」(管理対象デバイスのリソース)。アイデアがある「リソースがデバイスに属しているリソースを自動的に解放することができたときに、デバイスが存在しません。」
たとえば、Linuxの開発プロセスでは、最初のGPIOを適用し、メモリに適用され、メモリ割り当てが失敗した場合、GPIOのリソースを解放する必要性に返す前に。あなたは、相関関数DEVMを使用しており、メモリに障害が発生したときに、直接復帰を申請することができた場合:デバイスの破壊が自動的に機能しますのリリースでは、GPIOのリソースに対して適用されています。
これは、相関関数の「devm_」バージョンをお勧めします。

例えば、デバイス補綴装置は、ツリー内の次のノードを有します。

	foo_device {
		compatible = "acme,foo";
		...
		led-gpios = <&gpio 15 GPIO_ACTIVE_HIGH>, /* red */
			    <&gpio 16 GPIO_ACTIVE_HIGH>, /* green */
			    <&gpio 17 GPIO_ACTIVE_HIGH>; /* blue */

		power-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
	};

あなたは、ピンを取得するには、次の機能を使用することができます。

struct gpio_desc *red, *green, *blue, *power;
red = gpiod_get_index(dev, "led", 0, GPIOD_OUT_HIGH);
green = gpiod_get_index(dev, "led", 1, GPIOD_OUT_HIGH);
blue = gpiod_get_index(dev, "led", 2, GPIOD_OUT_HIGH);
power = gpiod_get(dev, "power", GPIOD_OUT_HIGH);

値gpiod_set_valueを設定する物理量に必ずしも等しくない「論理値」であることに留意されたいです。
これは何を意味するのでしょうか?
ここに画像を挿入説明

古い「gpio_」機能は、ピン番号を知っている必要があり、ピンのデバイスツリー情報に基づいて取得することはできません。

ピン番号を確認する方法?
塩基数+ N:GPIOサブシステムにおいて、各レジスタは、GPIOコントローラは、次いで、n番目のピン数のコントローラがその「塩基数」を決定します。
しかし、ハードウェアの変更ならば、デバイスツリーの変化、ベース番号と固定されるように保証することはできませんがある、あなたはベース番号を決定するためのsysfsをチェックする必要があります。

2.4のsysfsにアクセスする方法

sysfsのGPIOでのアクセスは、実際には、ピン番号の使用、古い方法です。
。最初の基準ピンGPIOコントローラ番号(塩基数)を決定し、次いで、ピンの数を計算します。
次のとおりです。
①最初の開発ボード/ SYS /クラス/ GPIOディレクトリでは、各gpiochipXXXを見つけるためのディレクトリ:
ここに画像を挿入説明

②gpiochip次いでカタログを入力し、ファイルのラベルの内容を表示する
ラベルの内容に従って③比較ツリー装置を
例えばそのベース・アドレス・レジスタなどのデバイスツリーからラベルコンテンツ。デバイスツリー(DTSIファイル)の比較で使用され、我々は、GPIOコントローラにそのどの対応を知ることができます。
図は100asK_imx6ull、デバイスツリー対応のGPIO4を比較することによって理解gpiochip96上で実行した結果である:
ここに画像を挿入説明
ピンのセットのでGPIO4基準ピン番号が再度確認するために「CATベース」であり得る、96です。

ピンSYSFSに基づいてB:
100ask_imx6ull例では、ボタン、次の図を有する:
ここに画像を挿入説明
GPIO4_14数は96 + 14 = 110であるので、動作は次のようにキー値があってもよい読み取り。

echo  110 > /sys/class/gpio/export
echo in > /sys/class/gpio/gpio110/direction
cat /sys/class/gpio/gpio110/value
echo  110 > /sys/class/gpio/unexport

注:ドライバがすでにこのピンを使用している場合、それが失敗したエクスポートします、それは次のエラーを促すメッセージが表示されます:
ここに画像を挿入説明

出力ピンは、ピン番号が、その値は次の方法のいずれかによって提供されてもよい、Nとします。

echo  N > /sys/class/gpio/export
echo out > /sys/class/gpio/gpioN/direction
echo 1 > /sys/class/gpio/gpioN/value
echo  N > /sys/class/gpio/unexport

3. LEDドライバサブシステムGPIOに基づい

3.1 Programe

このようI2C、UARTなどの他のモジュールとのGPIOステータスが同じ場所で、あなたはピンを使用するには、最初のピンに必要Pinctrlサブシステムを使用するGPIO機能として設定されている、あなたは、単にデバイスツリーを指定することができます。私たちはドライブコードに何もする必要はありません。
GPIOピンは、それは、デバイスツリーで指定する必要があり、それ自体を識別する必要があります。
カーネルデバイスツリーノードがplatform_deviceに変換されます。
プローブ関数は、レジスタplatform_driverドライバコードに対応する:ピンレジスタfile_operationsを得ます。
file_operationsで:方向、読み取り/書き込み値の値を設定します。
ここに画像を挿入説明

図は、デバイスツリーの一例です。
ここに画像を挿入説明

3.2デバイスツリーにPinctrl情報を追加します。

一部のチップはGUIインタフェースで装置木生成手段を設け、選択ピンの機能構成情報と、自動的Pinctrl子ノードを生成することができます。お使いのデバイスのファイルツリーにコピーし、その後、クライアントデバイス内のノードを参照することができます。
いくつかのチップは、その後、通常のカーネルソースディレクトリのドキュメントで、ドキュメントを読んで行く文書のみを提供\ devicetree \バインディング\ pinctrl以下、製造元のドキュメントの保存。
文書がない場合でも、あなたが唯一のカーネルソースディレクトリアーチ/腕/ブートでカーネルソースにデバイスツリーのファイルを参照することができます/ディレクトリをDTS。
最後のステップ、検索ネットワーク。
次のようにスタイルPinctrlの子はノード:
ここに画像を挿入説明

3.3デバイスツリーに情報を追加GPIO

使用される最初のチェック回路図ピンが決定され、その後、デバイスはツリーで指定された:例えばGPIO_ACTIVE_LOWような一つのピンにGPIOコントローラの使用を指定し、「[名前] -gpios」属性、フラグ他の情報を追加ように。どのように多くの細胞の特定のニーズ、GPIOコントローラのデバイスツリーノード内のプロパティ値「#GPIO-細胞」を参照してくださいする必要がピンを記述するためには、カーネルのドキュメントをも見ることができます。
例としては、次のとおりです:
ここに画像を挿入説明

3.4プログラミング例

実際の動作では、予期しない問題、解決する方法のライブデモが発生する可能性があります。
。定義され、レジスタplatform_driverの
そのプローブ関数におけるB :.
B.1はplatform_device GPIOデバイスツリー情報に従って決定:gpiod_get
定義B.2、レジスタ構造はfile_operations
B.3 GPIOサブシステムfile_operarionsに使用関数は、GPIOを操作:
gpiod_direction_output、gpiod_set_value

メリット:このコードは、コードのすべてのためにまったく同じです!
GITのコマンドセットを使用した後、ソースleddrv.cは、このディレクトリにあります:

01_all_series_quickstart\
04_快速入门_正式开始\
02_嵌入式Linux驱动开发基础知识\source\
05_gpio_and_pinctrl\
    01_led

抜粋ハイライト:
。Aはplatform_driverの登録された
デバイス・ツリーと互換性のあるノードに対応する「100ask、leddrv」、次の行122に注意を:

121 static const struct of_device_id ask100_leds[] = {
122     { .compatible = "100ask,leddrv" },
123     { },
124 };
125
126 /* 1. 定义platform_driver */
127 static struct platform_driver chip_demo_gpio_driver = {
128     .probe      = chip_demo_gpio_probe,
129     .remove     = chip_demo_gpio_remove,
130     .driver     = {
131         .name   = "100ask_led",
132         .of_match_table = ask100_leds,
133     },
134 };
135

136 / 2. * *機能レジスタplatform_driver入口/

137 static int __init led_init(void)
138 {
139     int err;
140
141     printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
142
143     err = platform_driver_register(&chip_demo_gpio_driver);
144
145     return err;
146 }

B。プローブGPIO機能を取得
コアコードライン87で、それはデバイス(デバイスツリーのノードに対応するデバイス)から「LED」と呼ばれるピンを取得します。デバイスツリーで、「LED-のGPIO」または「LED-GPIO」と呼ばれる属性が存在しなければなりません。

77 /* 4. 从platform_device获得GPIO
78  *    把file_operations结构体告诉内核:注册驱动程序
79  */
80 static int chip_demo_gpio_probe(struct platform_device *pdev)
81 {
82      //int err;
83
84      printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
85
86      /* 4.1 设备树中定义有: led-gpios=<...>; */
87     led_gpio = gpiod_get(&pdev->dev, "led", 0);
88      if (IS_ERR(led_gpio)) {
89              dev_err(&pdev->dev, "Failed to get GPIO for led\n");
90              return PTR_ERR(led_gpio);
91      }
92

登録file_operations構造C:
これは、古いルーチンです。

93      /* 4.2 注册file_operations      */
94      major = register_chrdev(0, "100ask_led", &led_drv);  /* /dev/led */
95
96      led_class = class_create(THIS_MODULE, "100ask_led_class");
97      if (IS_ERR(led_class)) {
98              printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
99              unregister_chrdev(major, "led");
100             gpiod_put(led_gpio);
101             return PTR_ERR(led_class);
102     }
103
104     device_create(led_class, NULL, MKDEV(major, 0), NULL, "100ask_led%d", 0); /* /dev/100ask_led0 */
105

。D関数呼び出しGPIOピンはオープン関数の方向に配置されました。

51 static int led_drv_open (struct inode *node, struct file *file)
52 {
53      //int minor = iminor(node);
54
55      printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
56      /* 根据次设备号初始化LED */
57      gpiod_direction_output(led_gpio, 0);
58
59      return 0;
60 }

。書き込み機能値内に配置されたE関数呼び出しGPIOピン:

34 /* write(fd, &val, 1); */
35 static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
36 {
37      int err;
38      char status;
39      //struct inode *inode = file_inode(file);
40      //int minor = iminor(inode);
41
42      printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
43      err = copy_from_user(&status, buf, 1);
44
45      /* 根据次设备号和status控制LED */
46      gpiod_set_value(led_gpio, status);
47
48      return 1;
49 }

。FリリースGPIO:

gpiod_put(led_gpio);

4.機械実験100ASK_IMX6ULL

4.1デバイスツリーノードを決定し、ピンを生成します

IMX6ULLチップ社のNXPのために、我々は、デバイスツリー生成ツールを持っています。また、このディレクトリに、loadコマンドを使用してGIT、GITを行くためにそれをアップロードします。

01_all_series_quickstart\
04_快速入门_正式开始\
02_嵌入式Linux驱动开发基础知识\source\
05_gpio_and_pinctrl\
tools\
imx\

インストールの「Pins_Tool_for_i.MX_Processors_v6_x64.exe」、オープンIMX6ULLプロファイル「MCIMX6Y2xxx08.mex」の後に実行して、あなたはGUIインターフェイスでピンを選択することができ、自動的に情報Pinctrlの子ノードを生成することができ、その機能を、設定します。
概略100ASK_IMX6ULL LEDは、以下で使用するピンがGPIO5_3見出される:
ここに画像を挿入説明
以下のようにデバイスツリーツール、操作を:
ここに画像を挿入説明

自動的に生成されたデバイス情報ツリー、アーチ/アーム/ブート/ DTS /にカーネルソース 100ask_imx6ull-14x14.dts コードは以下の通りである:
。A Pinctrl情報:

&iomuxc_snvs {
……
        myled_for_gpio_subsys: myled_for_gpio_subsys{ 
            fsl,pins = <
                MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03        0x000110A0
            >;
        };

(ルート上の)B設備ノード情報:

        myled {
            compatible = "100ask,leddrv";
            pinctrl-names = "default";
            pinctrl-0 = <&myled_for_gpio_subsys>;
            led-gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
        };

4.2コンパイラ

デバイスツリーをコンパイルした後は、デバイスツリーを更新します。
ドライバをコンパイルするとき、「leddrv_テストされていないオリジナルバージョン.Cは、」修飾されたエラーメッセージ、「leddrv.c」があります。
試験方法は、ボード上のコマンドを実行します。

#insmod  leddrv.ko
#ls /dev/100ask_led0
#./ledtest /dev/100ask_led0 on
#./ledtest /dev/100ask_led0 off
公開された135元の記事 ウォンの賞賛401 ビュー260 000 +

おすすめ

転載: blog.csdn.net/thisway_diy/article/details/105120667