2023 年 03 月 31 日 Linux 技術ネタ
Linux には、デバイスツリーというハードウェア固有設定をコンフィグファイルとしてソースコードから切り離す便利な機能がありますが、日本語、英語ともに情報が少なく、見よう見まねで対応されている方が多いのではないでしょうか?
リネオ社内で聞いてみたところ、ネットで検索してもなかなか有力な情報が出てこないため、例えば、『サウンドの widgets と routing プロパティの設定方法 (ルール) が理解できていない。』などコメントをもらいました。
OSS の Linux は、ソースコードを誰でも読むことができる反面、情報が溢れて何が正しいのかわかりづらいケース、公式ドキュメントの説明不足でソースコードを読まないと理解できないケースが多々あります。一方で、ソースコードから機能を読み解くことは、ハードルが高く、容易なことではありません。
本ブログエントリでは、デバイスツリーとはどのようなものかと 1 事例としてサウンドの widgets と routing プロパティの設定方法について紹介します。
本ブログは全2部構成となっており、後編では「サウンドの widgets, routing プロパティの設定事例」を解説していきます。
前編はこちら。
これまで デバイスツリー がどのようなものかを説明してきました。つづいて、リネオ社内で有力な情報なく未だに理解しきれていないと情報を得た、サウンドの widgets,routing プロパティを設定の具体事例として、本ブログエントリを締めくくりたいと思います。
今回調査した結果、widgets と routing プロパティは使われなくなってきているとわかりました。arm64 SoC 搭載ボードのサウンドドライバの場合、widgets は全てハードコーディングされています。また、routing は Qualcomm の SoC のみが使用している状況です。将来使用されなくなる可能性が高いです。
現代は、ハードウェアの進化スピードが目覚ましく、少し前まで最新だった技術がすぐに当たり前となり、組込み機器でも速やかに利用可能になる時代です。サウンドカードや組込みボードに搭載されるサウンド機能は、独立した多数のオーディオコンポートから構成され、複雑化しており、オーディオコンポート全体を管理しないと必要以上に電力を無駄遣いしてしまう状況です。Linux ではオーディオサブシステム内で常に最小限の電力を使用するように設計された DAPM(Dynamic Audio Power Management)という仕組みを導入し、この問題に対応しています。
Dynamic Audio Power Management より抜粋
widgets とは、オーディオコンポートのことです。また、routing とは、オーディオコンポートと外部の入出力の接続のことです。例えば、以下は NXP 社の SGTL5000 という Codec です。widgets は、黄色の部分を指します。routing は、SGTL5000 に IN/OUT される矢印を指します。
widgets と routing で機能と外部入出力の ON/OFF を設定することで、必要最小限のオーディオコンポートを利用可能になります。
NXP Semiconductors Data Sheet: Technical Data Document Number: SGTL5000 Rev. 7, 1/2022 より抜粋
Linux カーネルには、DAPM を使用したサウンドドライバを手軽に開発するテンプレートとして、simple-card-driver が用意されています。
widgets, routing などシステム固有情報を dtb から設定する実装になっており、DAPM に対応するため、多くのドライバがこのテンプレートをベースに開発されたと推測します。しかし、このテンプレートでサポートしているのは、後で述べますが 4 種類のオーディオコンポートのみです。オーディオコンポーネントの多様化に伴い、このテンプレートではカバーできなくなり、使用されなくなったと推測します。Linux 6.1.8 の時点で DAPM がサポートするオーディオコンポーネントは、38 種類です。また、後で述べますが、widgets も routing もハードウェアで定義された正確な名前を使用しなければならないため、設定ミス含め無用な混乱を避けるためにソースコードにハードコーディングする方向に傾いたと推測します。
DAPM widgets は、様々なオーディオコンポーネントをサポートしていますが、このうち dtb の widgets でサポートしているのは、ユーザからの IN/OUT に関わる以下 4 種類のみです。
dtb でサポートする widgets(templeate-wname) | 対応する DAPM widgets | 概要 |
---|---|---|
Microphone | Mic | マイクからの入力ジャック |
Line | Line | ライン入力・出力ジャック |
Headphone | Headphone | ヘッドフォンの出力ジャック |
Speaker | Speaker | スピーカーへの出力ジャック |
書式は、以下の通りです。Linux カーネルは、奇数番目の文字列を template-wname として、偶数番目の文字列を user-supplied-wnameと認識します。
"template-wname", "user-supplied-wname"
● template-wname
上記 4 つのみが有効な文字列です。
● user-supplied-wname
ハードウェア毎に定義されている有効な名前を指定する必要があります。
For instance: simple-audio-widgets = "Microphone", "Microphone Jack", "Line", "Line In Jack", "Line", "Line Out Jack", "Headphone", "Headphone Jack", "Speaker", "Speaker External"
static const struct snd_soc_dapm_widget simple_widgets[] = { SND_SOC_DAPM_MIC("Microphone", NULL), SND_SOC_DAPM_LINE("Line", NULL), SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_SPK("Speaker", NULL), }; int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, const char *propname) { struct device_node *np = card->dev->of_node; struct snd_soc_dapm_widget *widgets; const char *template, *wname; int i, j, num_widgets; num_widgets = of_property_count_strings(np, propname); ★widgets プロパティの総数を dtb から取得 ・・・ num_widgets /= 2; ★2つずつで意味を持つので 2 で割る ・・・ for (i = 0; i < num_widgets; i++) { int ret = of_property_read_string_index(np, propname, 2 * i, &template); ★ templeate-wname を dtb から取得 ・・・ for (j = 0; j < ARRAY_SIZE(simple_widgets); j++) { if (!strncmp(template, simple_widgets[j].name, strlen(simple_widgets[j].name))) { widgets[i] = simple_widgets[j]; break; ★有効な templeate-wname か否かを確認 } } ・・・ ret = of_property_read_string_index(np, propname, (2 * i) + 1, &wname); ★user-supplied-wname を dtb から取得 ・・・ widgets[i].name = wname; } card->of_dapm_widgets = widgets; ★ dapm に登録 card->num_of_dapm_widgets = num_widgets; return 0; } EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
Linux 6.1.8 の時点で widgets をdtb から DAPM に登録する関数を使用している HardKernel 社の ODROID ボードが搭載する MAX98090 という Codec のカーネルドキュメントを見てみましょう。
Samsung Exynos Odroid XU3/XU4 audio complex with MAX98090 codec Required properties: ・・・ - samsung,audio-widgets - this property specifies off-codec audio elements like headphones or speakers, for details see widgets.txt - samsung,audio-routing - a list of the connections between audio components; each entry is a pair of strings, the first being the connection's sink, the second being the connection's source; valid names for sources and sinks are the MAX98090's pins (as documented in its binding), and the jacks on the board For Odroid X2: "Headphone Jack", "Mic Jack", "DMIC" For Odroid U3, XU3: "Headphone Jack", "Speakers" For Odroid XU4: no entries
widgets に指定可能な有効な名前がボード毎に記載されています。
ボード名 | widgets に指定可能な有効な名前 |
---|---|
Odroid X2 | "Headphone Jack", "Mic Jack", "DMIC" |
Odroid U3, XU3 | "Headphone Jack", "Speakers" |
Odroid XU4 | なし |
ハードウェアマニュアルにて widgets に指定可能な有効な名前を検索してみましたが、見つかりませんでした。ドライバに付属ドキュメントがない場合は、SoC ベンダへの確認が必要になります。
MAX98090 Ultra-Low Power Stereo Audio Codec 19-6492; Rev 4; 11/18 より抜粋
routing は、オーディオコンポーネント間の接続リストで、書式は、以下の通りです。Linux カーネルは、奇数番目の文字列を connection's sink として、偶数番目の文字列を connection's source と認識します。一方が widgets 名、もう一方が Codec のピン名になります。Codec に対する INPUT/OUTPUT によって順番が変わるため注意が必要です。また、有効な名前を指定する必要があります。
" connection's sink", " connection's source"
● connection's sink
source から信号を受信する側です。
● connection's source
信号を sink へ送信する側です。
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname) { struct device_node *np = card->dev->of_node; int num_routes; struct snd_soc_dapm_route *routes; int i; num_routes = of_property_count_strings(np, propname); ★widgets プロパティの総数を dtb から取得 ・・・ num_routes /= 2; ★2つずつで意味を持つので 2 で割る ・・・ for (i = 0; i < num_routes; i++) { int ret = of_property_read_string_index(np, propname, 2 * i, &routes[i].sink); ★ connection's sink を dtb から取得 ・・・ ret = of_property_read_string_index(np, propname, (2 * i) + 1, &routes[i].source); ★ connection's source を dtb から取得 ・・・ } card->num_of_dapm_routes = num_routes; card->of_dapm_routes = routes; ★ dapm に登録 return 0; } EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing);
上記で例に挙げた NXP 社の SGTL5000 のカーネルドキュメントを見てみましょう。 有効な名前に対してのみ電源が供給されると記述されているとともに、有効な名前がリストアップされています。
Freescale i.MX audio complex with SGTL5000 codec Required properties: ・・・ - audio-routing : A list of the connections between audio components. Each entry is a pair of strings, the first being the connection's sink, the second being the connection's source. Valid names could be power supplies, SGTL5000 pins, and the jacks on the board: Power supplies: * Mic Bias SGTL5000 pins: * MIC_IN * LINE_IN * HP_OUT * LINE_OUT Board connectors: * Mic Jack * Line In Jack * Headphone Jack * Line Out Jack * Ext Spk Example: sound { compatible = "fsl,imx51-babbage-sgtl5000", "fsl,imx-audio-sgtl5000"; model = "imx51-babbage-sgtl5000"; ssi-controller = <&ssi1>; audio-codec = <&sgtl5000>; audio-routing = "MIC_IN", "Mic Jack", "Mic Jack", "Mic Bias", "Headphone Jack", "HP_OUT"; mux-int-port = <1>; mux-ext-port = <3>; };
Example では以下のマイクとヘッドフォンをサポートする設定になっています。
connection's sink | connection's source | 信号の流れる方向 |
---|---|---|
MIC_IN | Mic Jack | ← |
Mic Jack | Mic Bias | |
Headphone Jack | HP_OUT |
ハードウェアマニュアルに記載の構成図と比較すると、INPUT/OUTPUT の方向と一致することが確認できます。
NXP Semiconductors Data Sheet: Technical Data Document Number: SGTL5000 Rev. 7, 1/2022 より抜粋
また、ハードウェアマニュアルの Pin 定義を確認すると、上記構成図の通り、HP_R と HP_L に分かれていますが、routing の source には 2 つをまとめた HP_OUT が有効な名前のようです。Pin 定義と一致しない場合がありますので、注意が必要です。ドライバに付属ドキュメントがない場合は、SoC ベンダへの確認が必要になります。
NXP Semiconductors Data Sheet: Technical Data Document Number: SGTL5000 Rev. 7, 1/2022 より抜粋
なお、SGTL5000 の widgets の設定は、以下の通りソースコードにハードコーディングされています。関数名が dts で指定する templeate-wname に対応し、第一引数が dts で指定する user-supplied-wname に対応します。
static const struct snd_soc_dapm_widget imx_sgtl5000_dapm_widgets[] = { SND_SOC_DAPM_MIC("Mic Jack", NULL), SND_SOC_DAPM_LINE("Line In Jack", NULL), SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_SPK("Line Out Jack", NULL), SND_SOC_DAPM_SPK("Ext Spk", NULL), };
本ブログエントリでは、デバイスツリーとはどのようなものかと 1 事例としてサウンドカードの widgets と routing プロパティの設定方法について紹介しました。
Linux カーネルは、現在 6.x 系まで進化し、搭載機能は、ユーザのニーズなどにより、バージョンアップとともに淘汰されてきています。今回のブログ原稿執筆によって、サウンドの widget, routing プロパティがレガシーな設定になりつつあることを知り、最終的にはソースコードを読まないと内容把握できない Linux カーネル含めた OSS の難しさを痛感しました。
弊社には、Linux カーネルに熟達したエンジニアが多数おります。お困りごとがありましたら、お力になれるかもしれませんので、遠慮なくセールスの方へお問い合わせください。
2024 年 09 月 02 日 Vigiles サポート
2024 年 03 月 01 日 Vigiles サポート
2023 年 08 月 28 日 Vigiles サポート
2024 年 03 月 26 日 Yocto Project よもやま話
2023 年 07 月 25 日 Yocto Project よもやま話
2023 年 06 月 20 日 Yocto Project よもやま話
2024 年 01 月 10 日 Linux 技術ネタ
2023 年 12 月 12 日 Linux 技術ネタ
2023 年 03 月 31 日 Linux 技術ネタ
2024 年 07 月 26 日 イベントレポート
2024 年 07 月 09 日 イベントレポート
2024 年 06 月 03 日 イベントレポート
2023 年 05 月 30 日 リクルート
2022 年 12 月 27 日 リクルート
2022 年 09 月 27 日 リクルート
2024 年 09 月 25 日 信州リネオ便り
2024 年 08 月 20 日 信州リネオ便り
2024 年 08 月 07 日 信州リネオ便り
2019 年 12 月 10 日 ソリューション統括部
2019 年 12 月 10 日 ソリューション統括部
2019 年 12 月 10 日 ソリューション統括部
2019 年 12 月 13 日 マーケティング統括部
2019 年 04 月 25 日 マーケティング統括部
2018 年 12 月 18 日 マーケティング統括部