linux内核中gpio-key驱动程序的使用

关键字

dtsi、gpio、key、input子系统、event解析、长按按键检测

gpio_keys说明

key是嵌入式开发中常用到的东西,linux内核中也早已为我们做了一套成熟的机制。

linux内核下的 drivers/input/keyboard/gpio_keys.c实现了一个体系结构无关的GPIO按键驱动,使用此按键驱动,只需在相应的设备树定义相关的数据即可。驱动的实现非常简单,但是较适合于实现独立式按键驱动。

gpio-keys是基于input架构实现的一个通用GPIO按键驱动。该驱动基于platform_driver架构,实现了驱动和设备分离,符合Linux设备驱动模型的思想。工程中的按键驱动我们一般都会基于gpio-keys来写,所以我们有必要对gpio_keys进行分析。

此处我在应用层进行了处理,使其支持长按检测(我的程序设置为长按6S打印),尝试在驱动层修改消抖时间,实现的效果很差,所以放弃了。

dtsi 设备树的实现

  • 设备树的实现大都大同小异,填写必要的参数即可,下边我做了标注。

gpio_keys {

    compatible = "gpio-keys";

    label = "gpio-keys";



    pinctrl-names = "default";

    pinctrl-0 = <&key_recovery_default>;



    recovery {

     label = "recovery";

     gpios = <&tlmm 23 GPIO_ACTIVE_HIGH>;

     linux,input-type = <1>;

     linux,code = <115>;

    /*这三项根据需求添加*/

    gpio-key,wakeup;

    debounce-interval = <15>;

    linux,can-disable;

    };

 };

1、节点名字为“gpio-keys”。

2、gpio-keys 节点的 compatible 属性值一定要设置为“gpio-keys”。

3、所有的 KEY 都是 gpio-keys 的子节点,每个子节点可以用如下属性描述自己:

gpios:KEY 所连接的 GPIO 信息。

interrupts:KEY 所使用 GPIO 中断信息,不是必须的,可以不写。

label:KEY 名字

linux,code:KEY 要模拟的按键 \color{red}{可以直接填数字}

gpio-key,wakeup:可以被唤醒

debounce-interval:消抖时间

  • 其他字段

1、如果按键要支持连按的话要加入 autorepeat

驱动程序简单分析

这就是一个标准的 platform 驱动框架,如果要使用设备树来描述 KEY 设备信息的话,设备节点的 compatible 属性值要设置为“gpio-keys”。当设备和驱动匹配以后 gpio_keys_probe 函数就会执行


static struct platform_driver gpio_keys_device_driver = {

 .probe = gpio_keys_probe,

 .driver = {

  .name = "gpio-keys",

  .pm = &gpio_keys_pm_ops,

  .of_match_table = gpio_keys_of_match,

 }

};

设备树的解析,从设备树中获取到 KEY 相关的设备节点信息


static int gpio_keys_probe(struct platform_device *pdev)

{

if (!pdata) {

  pdata = gpio_keys_get_devtree_pdata(dev);

  if (IS_ERR(pdata))

   return PTR_ERR(pdata);

 }

}

查看读取event

  • 查看event事件

ls -l /dev/input

  • 查看文件内容

hexdump /dev/input/event0

应用层解析键值


#define RECOVERY_KEY "/dev/input/event2"

#define RECOVERY_KEY_CODE 115

#define RECOVERY_KEY_PRESS 0



void recovery_key_press_timer(int sig)

{

 if(SIGALRM == sig)

 {

  printf("alarm 6s.\n");

 }



 return;

}





static void read_recovery_key_event()

{

 int fd = -1, ret = -1;

 struct input_event ev;



 fd = open(RECOVERY_KEY, O_RDONLY);

 if (fd < 0)

 {

  printf("open RECOVERY_KEY event failed.\n");

  return;

 }



 memset(&ev, 0, sizeof(struct input_event));

 ret = read(fd, &ev, sizeof(struct input_event));

 if (ret != sizeof(struct input_event))

 {

  printf("read RECOVERY_KEY event failed.\n");

  close(fd);

 }



 if( (RECOVERY_KEY_CODE == ev.code) && (RECOVERY_KEY_PRESS == ev.value) )

 {

  printf("recovery-key press.\n");

  alarm(6);

 }

 else

 {

  printf("recovery-key release.\n");

  alarm(0);

 }



 close(fd);

}



int main(int argc, char **argv)

{

    int rc = 0;

 signal(SIGALRM, recovery_key_press_timer);

 while(1)

 {

  read_recovery_key_event();

 }

    return 0;

}

参考链接

LEDE/OpenWRT处理基于GPIO的Power键

发布了162 篇原创文章 · 获赞 183 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_31339221/article/details/105233924