2018年4月12日 星期四

Press a key to control a led device on i.mx6

根據前一篇Linux input system and keypad driver on i.mx6

經過上面步驟已經可以正確傳遞keypad event並且透過evdev read function讀到key code. 透過key code可以再control led or pwm device.
透過led.h 中的led_trigger_register_simple以及led_trigger_event便可以trigger event set led brightness.
 
Sample:
evdev.c

#include 
struct led_trigger *test_led_trigger = 0;

static int __init evdev_init(void)
{
    led_trigger_register_simple("debug-leds", &test_led_trigger); //註冊test_led_trigger的trigger led label是debug-leds

    return input_register_handler(&evdev_handler);
}

static void __exit evdev_exit(void)
{
    led_trigger_unregister_simple(test_led_trigger);
    test_led_trigger = 0;
 
    input_unregister_handler(&evdev_handler);
}

在device tree中宣告
    leds {
        debug-leds {
            gpios = <&gpio1 2 0>;
            linux,default-trigger = "debug-leds";
            default-state = "off";
        };
};

接著回到evdev.c
static ssize_t evdev_read(struct file *file, char __user *buffer,
     size_t count, loff_t *ppos)
{
…
//此處會讀input event的data
while (read + input_event_size() <= count &&
       evdev_fetch_next_event(client, &event)) {
 printk("event type = %x, code = %x, value = %x\n",event.type, event.code, event.value);
            if(event.code == 0x1c){ //key code is "enter"
                printk("key code is 0x1c\n");
                led_trigger_event(test_led_trigger, LED_FULL); //設定test_led_trigger control 的led 亮度為FULL(255)
            }
 read += input_event_size();
}
…
}

如此在收到特定key code時, "gpio1 2"這顆led便會被開到全亮.
這邊要注意的是若要控制的是pwm device, 那需要先將device宣告為pwm-leds就一樣可以使用led trigger來控制. 只需在led_trigger_event第二個arguments填入0-255的數字就可以設定pwm cycle.
 
device tree example:
pwmleds {
    compatible = "pwm-leds";
    backlightk {
        label = "backlight-leds";
        pwms = <&pwm1 0 8333333>;
        linux,default-trigger = "debug-leds";
        max-brightness = <255>;
    };
};

詳細code流程如下
 
led_triggers.c
void led_trigger_register_simple(const char *name, struct led_trigger **tp)
{
 struct led_trigger *trig;
 int err;

 trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);

 if (trig) {
  trig->name = name;
  err = led_trigger_register(trig); //將led_trigger建立到list中
  if (err < 0) {
   kfree(trig);
…
}

Trigger event時
void led_trigger_event(struct led_trigger *trig,
   enum led_brightness brightness)
{
 struct list_head *entry;

 if (!trig)
  return;

 read_lock(&trig->leddev_list_lock);
 list_for_each(entry, &trig->led_cdevs) { //search list to find the trigger
  struct led_classdev *led_cdev;

  led_cdev = list_entry(entry, struct led_classdev, trig_list);
  led_set_brightness(led_cdev, brightness); //找到device之後最終調用device driver的brightness_set做亮度設定
 }
 read_unlock(&trig->leddev_list_lock);
}

沒有留言:

張貼留言