Raspberry Pi BのLinux Kernel 3.2.27を、Raspberry Pi B+で起動させるとGPIO 16が使えない

ここ数年、Raspberry Pi B(以降、RPiB)で動作するLinux Kernel 3.2.27をカスタムしたKernelを使用することがあります。このRPiBで使用していたKernelをRaspberry Pi B+(以降、RPiB+)で起動させた時に、何故かGPIO 16だけが使えないという現象に見舞われました。

色々と調査した結果、RPiB+のGPIO 16も使えるようになったので、その解決手段を残しておきます。
同じような現象で苦しんでいる人は滅多にいないと思いますが、参考になれば幸いです。

RPiBではpinの数が26本、RPiB+では40本と、14本もpinが増えています。
当初は、pin数は増えたとしても、RPiBで動作させていたKernelなので増えた14本は使えないだろうと予想していました。

しかし、予想に反して、増えた14本のpinの中で、GPIOとして使える9本のうちGPIO 16だけが使えませんでした。

自分の検証手順が悪かったのだろうと何度も試してみましたが、結果は変わらず、仕方なくGoogle大先生に尋ねると、以下のページを発見しました。

http://www.mztn.org/rpi/rpi42.html

上記ページによると、GPIO 16はRPiBではSDカードのアクセスを示すLEDとして使われていて、RPiB+ではGPIO 47を使うように変更されているようです。
あとは、RPiB+ではPWRのLEDにGPIO 35を使うように変更されているみたいですね。

上記の内容を信じてみて、rpi-3.2.27のソースコードを探しに探してみたところ、arch/arm/mach-bcm2708/bcm2708.cにそれっぽい箇所を見つけ出しました。

826 #if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
827 #include <linux/leds.h>
828
829 static struct gpio_led bcm2708_leds[] = {
830     [0] = {
831            .gpio = 16,
832            .name = "led0",
833            .default_trigger = "mmc0",
834            .active_low = 1,
835            },
836 };
837
838 static struct gpio_led_platform_data bcm2708_led_pdata = {
839     .num_leds = ARRAY_SIZE(bcm2708_leds),
840     .leds = bcm2708_leds,
841 };
842
843 static struct platform_device bcm2708_led_device = {
844     .name = "leds-gpio",
845     .id = -1,
846     .dev = {
847         .platform_data = &bcm2708_led_pdata,
848         },
849 };
850
851 static void __init bcm2708_init_led(void)
852 {
853     platform_device_register(&bcm2708_led_device);
854 }
855 #else
856 static inline void bcm2708_init_led(void)
857 {
858 }
859 #endif

831行目で16と指定されている部分を47に変更します。

ついでに、主目的からちょっと外れるので詳細な説明は省きますが、3.6くらいから使用されているDevice treeという仕組みを使用するためのRPiB+用のファイルを確認したり、LEDの点灯消灯動作の直観的なイメージとして、SDカードにアクセスしたらLEDが点灯して、アクセスしていない時には消灯するという動作が望ましかったので、最終的に以下のように変更しました。

diff --git a/kernel_rpi/linux-rpi-3.2.27-himalis/arch/arm/mach-bcm2708/bcm2708.c b/kernel_rpi/linux-
index 93fb75d..832a19e 100644
--- a/kernel_rpi/linux-rpi-3.2.27-himalis/arch/arm/mach-bcm2708/bcm2708.c
+++ b/kernel_rpi/linux-rpi-3.2.27-himalis/arch/arm/mach-bcm2708/bcm2708.c
@@ -828,9 +828,15 @@ struct sys_timer bcm2708_timer = {

 static struct gpio_led bcm2708_leds[] = {
        [0] = {
-              .gpio = 16,
+              .gpio = 47,
               .name = "led0",
               .default_trigger = "mmc0",
+              .active_low = 0,
+              },
+       [1] = {
+              .gpio = 35,
+              .name = "led1",
+              .default_trigger = "input",
               .active_low = 1,
               },
 };

変更後、カーネルをコンパイルし、SDカードに書き込み直して起動させたところ、意図通り、GPIO 16が動作するようになりました。

root@bit:~# echo 16 > /sys/class/gpio/export
root@bit:~# echo in > /sys/class/gpio/gpio16/direction
root@bit:~# cat /sys/class/gpio/gpio16/value
0
root@bit:~#

また、ついでに変更したSDカードにアクセスした時のLEDの点灯についても意図通り動作するようになりました。
めでたし、めでたし。

上記で確認したDevice treeのファイルや内容については以下のURLのページを参考にしてください。

bcm2708-rpi-b.dts
arch/arm/boot/dts/bcm2708-rpi-b.dts
gpio.txt
Documentation/devicetree/bindings/gpio/gpio.txt

コメントを残す

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

*