Brainuxのバックライト制御~755円の電子辞書、Brain PW-SH6にて~

皆さんこんにちはこんばんは、Yukimuraです。

最近、満員電車で進捗を出す際に、小型のLinuxが欲しいなと思っていました。1

メインで使っているのはMacBook Air(13インチ)、ThinkPad X280(A4サイズ)でして、座れればよいものの2、立ちながら操作するには少々、というかだいぶ無理があるレベルで大きすぎます。基本はSSHして作業することが多く、手元での作業はちょっとしたスクリプトを回すだけなので、性能度外視、CUIが動けばよく、(重量が)軽ければ軽いほど良いという感じです。(それならスマホでいいじゃないかってそれはそうなんだがロマンがゴニョゴニョ)

そんなことを思いながらリサイクルショップであるワットマンさんをぶらぶらしていたら、見つけました。

「Brain PW-SH6」

お値段なんと驚異の1078円税込み。しかもこの日はジャンク品3割引きの日でしたので、755円税込み。筆者の普段のランチより安い。というわけで、通電だけ確認して即購入です。

いやいや、小型Linuxってことは買うならパソコンとかタブレットだろ。これ電子辞書じゃねーか、と思う方もいるでしょうが、このBrainは先輩諸賢の解析によって、Brainuxというディストリビューションが開発されおり、2026年10月現在ではDebian13が動くみたいです。すごい。

このBrainuxを動かすのはいろいろな前例があるというかチュートリアル通りにやれば動くので、今回はこいつのバックライトを制御できないという問題を解決していきます。最終的には、画面を閉じたらバックライトがオフになったりするところまでもっていきたいなと思っています。

できたもの

まず完成品がこちら。

ご覧のとおり、バックライトを段階的に調整し、消灯まで至ることに成功しました。

次からは、細かいことを書いていきます。

バックライト制御

純正の電子辞書では、蓋を閉じると画面が消えます。パソコンなら、バックライトが消えるのはもちろん、勝手にスリープしたり、ロックしたりしますよね。ところがBrainuxでは、蓋を閉じても画面が点灯したままになってしまいます。

このままでは、鞄に入れて持ち歩くには不便です。バッテリーも無駄に消費してしまいます。

そこで、Linuxからバックライトを制御できないか調べてみました。

Linuxのバックライト制御

Linuxには、バックライトを制御するためのインターフェースがあります。

/sys/class/backlight/です。

確認すると、次のようなデバイスが存在しました。

user@brain:~$ ls /sys/class/backlight/
backlight@0

さらに、輝度の設定値を確認します。

$ sudo sh -c 'B=/sys/class/backlight/backlight@0

cat "$B/brightness"
cat "$B/max_brightness"
cat "$B/actual_brightness"
'

結果は次のとおり。

7
7
7

どうやら、0〜7の8段階で輝度を制御できるようです。

そこで、

$ echo 0 | sudo tee \
  /sys/class/backlight/backlight@0/brightness

と実行してみました。

これで画面が消えるはずです。

……が、何も変わりません。

設定値を読み直すと確かに0になっているのですが、画面の明るさは変わりません。

そこで、PWM(Pulse Width Modulation)を調べてみることにしました。

PWM

Linuxのバックライト制御には、PWM(Pulse Width Modulation)が使われています。

PWMとは、一定周期で信号のON/OFFを繰り返し、そのON時間の割合を変えることで出力を制御する方式です。今回のBrainuxでは、pwm-backlightというドライバーが使用されていました。

そこで、PWMの状態を確認してみます。

$ sudo cat /sys/kernel/debug/pwm

輝度7の場合、次のような表示になりました。

pwm-0 (backlight):
requested enabled
period: 50000 ns
duty: 50000 ns
polarity: normal

period: 50,000nsに対してDuty: 50,000nsなので、Duty比は100%です。

一方、輝度を0に変更すると、

pwm-0 (backlight):
requested
period: 50000 ns
duty: 0 ns
polarity: normal

となります。(Duty比0%)

ちゃんとPWMの設定は変更されているようです。

しかし、実際の画面は明るいまま。となれば、、Linuxのバックライト制御処理は動作しているのに、実際のバックライト回路を適切に制御できていない可能性があります。

Device Treeを調べる

ここでDevice Treeを調べてみることにしました。Device Treeは、Linuxにハードウェアの構成を伝えるためのデータです。例えば、どのGPIOにどの機器が接続されているか、PWMの出力先はどこか、といった情報を記述できます。

PW-SH6では、/boot/imx28-pwsh6.dtbファイルが使用されています。このファイルをDevice Tree Compiler(dtc)で逆変換すると、次のような記述が見つかりました。

compatible = "pwm-backlight";
pwms = <0x26 0x00 0xc350>;
enable_gpios = <0x1b 0x05 0x00>;
brightness-levels =
    <0x00 0x04 0x08 0x10
     0x20 0x40 0x80 0xff>;
default-brightness-level = <0x07>;

この中で気になったのが、

enable_gpios

というプロパティです。

Linuxの標準的なpwm-backlightドライバーでは、バックライトの有効・無効を切り替えるGPIOをenable-gpiosという名前で参照します。

ところが、今回のDevice Treeでは、

enable_gpios

となっています。

間違い探しみたいな感じですが、pwm-backlightでは"enable-gpios"、Device Treeでは"enable_gpios"です。

どうも、この記述が原因でGPIOが認識されていないのではないか、という仮説が立ちました。

GPIOを調べる

まず、Device Treeのenable_gpiosの値を確認します。

$ od -An -tx1 -v \
  /proc/device-tree/backlight@0/enable_gpios

結果は以下のとおり。

00 00 00 1b
00 00 00 05
00 00 00 00

最初の0x1bはGPIOコントローラーへの参照です。

Device Tree内のphandleを追跡したところ、参照先は次のコントローラーでした。

pinctrl@80018000/gpio@3

このGPIOコントローラーは、Linux上ではGPIO 96〜127に対応しています。

指定されているピン番号は5なので、

96 + 5 = 101

つまり、GPIO 101がバックライト制御用として指定されていることになります。

ところが、LinuxのGPIO使用状況を確認しても、GPIO 101が見つかりません。

$sudo cat /sys/kernel/debug/gpio
gpiochip0: GPIOs 0-31, parent: platform/80018000.pinctrl:gpio@0, 80018000.pinctrl:gpio@0:
 gpio-26  (                    |sharp,en            ) out hi
 gpio-27  (                    |sharp,en            ) out hi

gpiochip1: GPIOs 32-63, parent: platform/80018000.pinctrl:gpio@1, 80018000.pinctrl:gpio@1:

gpiochip2: GPIOs 64-95, parent: platform/80018000.pinctrl:gpio@2, 80018000.pinctrl:gpio@2:
 gpio-76  (                    |wp                  ) in  lo
 gpio-77  (                    |regulator-can-3v3   ) out lo
 gpio-79  (                    |regulator-fec-3v3   ) out hi ACTIVE LOW
 gpio-80  (                    |matrix-out          ) out lo
 gpio-81  (                    |matrix-out          ) out lo
 gpio-82  (                    |matrix-out          ) out lo
 gpio-83  (                    |matrix-out          ) out lo
 gpio-84  (                    |matrix-out          ) out lo
 gpio-85  (                    |matrix-out          ) out lo

gpiochip3: GPIOs 96-127, parent: platform/80018000.pinctrl:gpio@3, 80018000.pinctrl:gpio@3:
 gpio-105 (                    |regulator-usb0-vbus ) out lo
 gpio-124 (                    |regulator-vddio-sd0 ) out lo ACTIVE LOW
 gpio-126 (                    |regulator-lcd-3v3   ) out lo

gpiochip4: GPIOs 128-159, parent: platform/80018000.pinctrl:gpio@4, 80018000.pinctrl:gpio@4:
 gpio-128 (                    |matrix-in           ) in  hi
 gpio-129 (                    |matrix-in           ) in  hi
 gpio-130 (                    |matrix-in           ) in  hi
 gpio-131 (                    |matrix-in           ) in  hi
 gpio-132 (                    |matrix-in           ) in  hi
 gpio-133 (                    |matrix-in           ) in  lo
 gpio-134 (                    |matrix-in           ) in  hi
 gpio-135 (                    |matrix-in           ) in  hi
 gpio-136 (                    |matrix-out          ) out lo
 gpio-144 (                    |sharp,en            ) out hi

少なくとも、バックライトドライバーによって確保されている様子はありません。

どうやら、Device Treeの記述ミスという仮説が当たっていそうです。

Device Treeを修正する

ということで、実際に修正してみます。

もちろん、カーネルを一からビルドすることもできますが、今回はDevice Treeのプロパティ名だけを変更したいので、もっと簡単な方法を使います。

みてのとおり、

enable_gpios
enable-gpios

は同じ文字数です。

そのため、既存のDTBファイル内の文字列を置換するだけで修正できます。

まずは、Brainuxでは/bootが読み取り専用でマウントされていたため、一時的に書き込み可能にしました。

$ sudo mount -o remount,rw /boot

$ sudo cp /boot/imx28-pwsh6.dtb \
        /boot/imx28-pwsh6.dtb.bak

続いて、Pythonで文字列を置換します。

$ python3 - <<'PY'
from pathlib import Path

src = Path("/boot/imx28-pwsh6.dtb")
dst = Path("/tmp/imx28-pwsh6-patched.dtb")

data = src.read_bytes()

old = b"enable_gpios\x00"
new = b"enable-gpios\x00"

if data.count(old) != 1:
    raise SystemExit("Unexpected property count.")

dst.write_bytes(data.replace(old, new, 1))
PY

修正版を作成できたので、dtcで内容を確認します。

$ dtc -I dtb -O dts \
  /tmp/imx28-pwsh6-patched.dtb \
  | grep -C 2 'enable-gpios'

結果は以下のとおり。

compatible = "pwm-backlight";
pwms = <0x26 0x00 0xc350>;
enable-gpios = <0x1b 0x05 0x00>;
brightness-levels =
    <0x00 0x04 0x08 0x10
     0x20 0x40 0x80 0xff>;

無事に変更できているようです。

そこで、元のDTBを退避した状態で修正版を配置します。

sudo cp /tmp/imx28-pwsh6-patched.dtb \
        /boot/imx28-pwsh6.new

sudo cmp /tmp/imx28-pwsh6-patched.dtb \
         /boot/imx28-pwsh6.new

sudo mv /boot/imx28-pwsh6.new \
        /boot/imx28-pwsh6.dtb

sync
sudo mount -o remount,ro /boot

※DTBの変更によってLinuxが起動しなくなる可能性があります。実施する場合は必ずバックアップを取り、microSDを別のPCで修復できる状態にしてください。また、今回の文字列置換は同じ長さのプロパティ名を置き換えられることを利用したものであり、任意のDevice Tree修正に使える方法ではありません。

さて、再起動です。

GPIOを認識!

再起動後、再びGPIOの使用状況を確認しました。

$ sudo grep 'gpio-101' \
  /sys/kernel/debug/gpio

すると、

gpio-101 ( |enable ) out hi

という表示が!

GPIO 101を認識してる!

修正前には存在しなかったGPIOが、バックライトの有効化用GPIOとして確保されています。

ということは、enable_gpiosという名前のせいで、ドライバーがGPIOを認識できていなかった可能性が高そうです。

これは期待できそうです。

バックライト実験

再び、Linuxからバックライトの明るさを変更してみます。今回は、完全に消灯できるかも確認するため、輝度を段階的に変更してみます。

$ sudo sh -c '
B=/sys/class/backlight/backlight@0
OLD=$(cat "$B/brightness")

trap "echo $OLD > $B/brightness" EXIT

for i in 7 4 2 1 0; do
    echo "$i" > "$B/brightness"

    echo "=== Brightness $i ==="

    grep "gpio-101" \
      /sys/kernel/debug/gpio

    grep "pwm-0 " \
      /sys/kernel/debug/pwm

    sleep 3
done
'

↑このスクリプトでは、輝度を7、4、2、1、0の順番で変更し、それぞれ3秒間維持した後、一番最初の輝度に戻すものです。

その結果は、冒頭お見せした通り。

見事に消灯まで、全部切り替わっています。

ただし、なぜか明度7から0に一気に落とそうとしても完全消灯しないため、単に

$ echo 0 | sudo tee /sys/class/backlight/backlight@0/brightness

とするのではなく一旦1まで下げて、0にする必要があります。すなわち

$ sudo sh -c 'echo 1 > /sys/class/backlight/backlight@0/brightness; sleep 0.3; echo 0 > /sys/class/backlight/backlight@0/brightness'

とすればよいわけです。戻すときは

$ echo 7 | sudo tee /sys/class/backlight/backlight@0/brightness

こうすればよいでしょう。特定のキーで復旧してくれるわけではないので、必ずSSHなどして作業しないと、暗中模索になります。

結局、何をすればよいのか(PW-SH6の場合)

まず、元のDTBをバックアップします。

$ sudo mount -o remount,rw /boot
$ sudo cp -n /boot/imx28-pwsh6.dtb /boot/imx28-pwsh6.dtb.bak

次に、enable_gpiosをenable-gpiosに置換します。

$ python3 - <<'PY'
from pathlib import Path

src = Path("/boot/imx28-pwsh6.dtb")
dst = Path("/tmp/imx28-pwsh6-patched.dtb")

data = src.read_bytes()
old = b"enable_gpios\x00"
new = b"enable-gpios\x00"

if data.count(old) != 1:
    raise SystemExit("Unexpected property count.")

dst.write_bytes(data.replace(old, new, 1))
PY

修正を確認して反映します。

$ dtc -I dtb -O dts /tmp/imx28-pwsh6-patched.dtb 2>/dev/null | grep enable-gpios

$ sudo cp /tmp/imx28-pwsh6-patched.dtb /boot/imx28-pwsh6.new
$ sudo cmp /tmp/imx28-pwsh6-patched.dtb /boot/imx28-pwsh6.new && sudo mv /boot/imx28-pwsh6.new /boot/imx28-pwsh6.dtb

$ sync
$ sudo mount -o remount,ro /boot
$ sudo reboot

※DTBを書き換えるため、起動できなくなった場合にmicroSDを別のPCから復元できるようにしておきます。

再起動後、以下で消灯できます。

$ sudo sh -c 'echo 1 > /sys/class/backlight/backlight@0/brightness; sleep 0.3; echo 0 > /sys/class/backlight/backlight@0/brightness'

輝度を直接0にすると完全に消えなかったため、一度1に変更してから0にしています。

点灯する場合はこちら。

$ echo 7 | sudo tee /sys/class/backlight/backlight@0/brightness

おわりに

いかがだったでしょうか。(まとめブログ感)

今回は、700円台で買った電子辞書でLinuxを動かして、かつバックライト制御の問題を解決してみたという感じです。最近技術的なことをほぼしてなかったので、リハビリがてらに、ちょうどいい感じでした。多くの部分をAI(GPT-6)に支援してもらっており、全部自力でとはいいがたい状況ですが、大変便利になり、やりたいことを簡単にできるようになったなぁとしみじみと感じています。

つぎは、蓋の開閉イベントを拾って、蓋を閉じたらバックライトを消す、開いたら点ける、というのを実装してみたいと思います。

それでは!

(文責:D3 木村悠生)

  1. 満員電車で進捗を出すなという話もある。 ↩︎
  2. 3週間に一度くらいしか、出勤で座れる日は来ない。帰りは座れるがち。 ↩︎

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

CAPTCHA