2013年11月24日 星期日

網樂通 reset 按鈕設定成 platform device

原本以為將原本完全沒設定的 reset 按鈕註冊成 platform device 會是最困難的,
之前先試著改紅外線遙控喚醒卻不好找到問題。
找了些gpio key的資料後,
順利把 reset 按鈕設定成 platform device。
除了在 dmesg 中出現下面訊息外,

evbug.c: Event. Dev: input0, Type: 1, Code: 28, Value: 1
evbug.c: Event. Dev: input0, Type: 0, Code: 0, Value: 0
evbug.c: Event. Dev: input0, Type: 1, Code: 28, Value: 0
evbug.c: Event. Dev: input0, Type: 0, Code: 0, Value: 0

意外的順利用來喚醒 suspend to ram 的系統,
雖然沒有遙控器喚醒方便,
但已經比之前只能用 WoL 和 TTL 訊號實用多了。
修改已經更新到 https://github.com/rexct/kernel-pdk7105

kernel 對於板子的設定幾乎都在 arch/sh/boards/mach-pdk7105/setup.c
在 網樂通改機俱樂部Chia-Cheng Huang (suzuke)  porting 2.6.32.59 時就存在下面的 structure 定義 LED。
static struct platform_device pdk7105_leds = {
        .name = "leds-gpio",
        .id = 0,
        .dev.platform_data = &(struct gpio_led_platform_data) {
                .num_leds = 2,
                .leds = (struct gpio_led[]) {
                        {
                                .name = "LD5",
                                .default_trigger = "heartbeat",
                                .gpio = stm_gpio(2, 4), //stpio_to_gpio(2, 4),
                        },
                        {
                                .name = "LD6",
                                .gpio = stm_gpio(2, 3), //stpio_to_gpio(2, 3),
                        },
                },
        },
};


不過在336行 的註冊用structure 中卻是變成註解

static struct platform_device *pdk7105_devices[] __initdata = {
//      &pdk7105_leds,
//      &pdk7105_phy_device,
        &spi_pio_device,
};


根據之前 控制網樂通LED 中在 user space 直接控制GPIO訊號用的針腳位置,
感覺 setup.c 中的怪怪的。
最近學會用的 cscope + vim 派上用場,
找到 include/linux/stm/gpio.h 中定義

#define stm_gpio(porst, pin) ((port) * STM_GPIO_PINS_PER_PORT + (pin))

以藍色LED port 值應該是0,pin 值是4,
以紅色LED port 值是0,pin 值是5,
reset按鈕 port值同樣是0,pin 是1。

為了解省編譯時間,
LED 和 reset 按鈕以起測試。

先在kernel 附的 Documentation/gpio.txt 文件中看到 gpio_keys ,
建議 LEDs 和 Buttons 用 kernel 內建的控制會比目前使用的 user space 方式還好。

以 gpio_keys 找到下面三個網頁:
1. arm板子使用GPIO-keys驱动方法及测试程序
2. Fred's blog: Add GPIO Keys support for Devkit8000
3. 使用Linux内核自带的GPIO 按键驱动 - [凌云嵌入式] - 嵌入式新手入门区 - 嵌入式开发联盟

從 1 和 3 可以得到要加入的 sturcture


#if defined(CONFIG_KEYBOARD_GPIO)
static struct gpio_keys_button pdk7105_keys[] = {
  {
    .gpio = stm_gpio(0, 1), /*rexct.131108: set gpio pin number(group number,sub-sequence number) */
    .code = KEY_ENTER, /*rexct.131108:KEY_ENTER = 28 ref:include/linux/input.h */
    .active_low = 1,
    .wakeup = 1,
  },
};
static struct gpio_keys_platform_data pdk7105_key_data = {
  .buttons    = pdk7105_keys,
  .nbuttons   = ARRAY_SIZE(pdk7105_keys),
};
static struct platform_device pdk7105_key_device = {
  .name       = "gpio-keys",
  .id     = -1,
  .num_resources  = 0,
  .dev        = {
  .platform_data  = &pdk7105_key_data,
    }
};
#endif

以及將寫好的裝置定義 structure pdk7105_key_device 註冊成 platform device

static struct platform_device *pdk7105_devices[] __initdata = {
  #if defined(CONFIG_KEYBOARD_GPIO)
    &pdk7105_key_device,
  #endif

};

其中為了避免在kernel .config 中沒定義第2個連結提到的 CONFIG_KEYBOARD_GPIO=y
加上
#if defined(CONFIG_KEYBOARD_GPIO)
#endif

避免沒選擇時出問題。

用structure 類型名稱  gpio_keys_button 可以找到定義在 include/linux/gpio_keys.h
.code 值可以用  KEY_ENTER 找到定義在 include/linux/input.h 中,
因為沒有 reset 的定義,
暫時用 KEY_ENTER 代替,
在 dmesg 中會出現 Code:28

另外從 1 和 3 中也可以得到 menuconfig 所需項目:
Device Drivers
  Input device support
    Keyboards
      GPIO Buttons

到這裡 reset 按鈕只要 把 kernel 編譯好就可以使用了。
另外參考了連結 1 後附的測試程式改成測試用程式含編譯完成執行檔

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <time.h>
#include <fcntl.h>
#include <linux/input.h>
int main(int argc, char **argv)
{
     int key_state;
     int fd;
     int ret;
     int code;
     struct input_event buf;
     int repeat_param[2];
     fd = open("/dev/input/event0", O_RDONLY);
     if (fd < 0)
     {
         printf("Open gpio-keys failed.\n");
         return -1;
  }
  else
  {
     printf("Open gpio-keys success.\n");
  }
     repeat_param[0]=500;//ms重复按键第一次间隔
     repeat_param[1]=66;//ms重复按键后续间隔
     ret = ioctl(fd,EVIOCSREP,(int *)repeat_param);//设置重复按键参数
     if(ret != 0)
         {
                   printf("set repeat_param fail!\n");
         }
     else
         {
                printf("set repeat_param ok.\n");
         }
     while(1)
     {
         ret = read(fd,&buf,sizeof(struct input_event));
         if(ret <= 0)
              {
                   printf("read fail!\n");
                   return -1;
              }
            
       code = buf.code;
       key_state = buf.value;
           printf("Key_%c state= %d.\n",code,key_state);
     }
     close(fd);
     printf("Key test finished.\n");
     return 0;
}




沒有留言:

張貼留言