潮声隔雨深 · 2021年12月29日

全志R系列如何解决gpio-keys驱动在系统启动上报两次input事件?

请问全志R系列如何解决gpio-keys驱动在系统启动上报两次input事件?

1 个回答 得票排序 · 时间排序
极术小姐姐 · 2021年12月29日
本回答来源全志R系列如何解决gpio-keys驱动在系统启动上报两次input事件?

上报两次input事件的原因一共有两个,分别如下所示:

1.由中断状态机误报一次中断。在gpio-keys驱动在初始化时,设置了软件上拉GPIO(或者是在硬件中上拉),对于中断状态机来说,外部GPIO已经是属于高电平了。在request_irq时,中断检测电路开始初始化,当前中断状态机的移位寄存器为0000(PS:中断检测电路用4bit来表示当前的中断触发方式,比如说0000认为外部是低电平,触发低电平中断)。

当GPIO的功能寄存器设置为中断功能,中断状态机开始移位检测。因为当前GPIO为高电平,两个CLK时钟周期后,中断状态机的移位寄存器会出现0011的情况,这时候,即使未出现上升沿,也会认为触发了一次上升沿中断。

这是中断误报属于硬件寄存器的问题,无法取消,只能规避。不过这个只会误报一次,后续驱动正常工作下不会再次误报的。除非设置改GPIO的复用功能为非中断功能,然后再设置GPIO为中断功能,这时候中断状态机又会重新初始化和误报一次中断。

解决方法:

  • 在配置GPIO复用功能之后,等待一段时间,清一遍pending,去除第一次误触发中断。另外,在使用过程中,不要动态切换GPIO的复用功能。
  • 在gpio-keys驱动中,定义一些变量,强行让中断处理函数不去处理第一次中断事件。

2.由gpio-keys的gpio_keys_open()函数上报的

static int gpio_keys_open(struct input_dev *input)
{
        struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
        const struct gpio_keys_platform_data *pdata = ddata->pdata;
        int error;

        if (pdata->enable) {
                error = pdata->enable(input->dev.parent);
                if (error)
                        return error;
        }

        /* Report current state of buttons that are connected to GPIOs */
        gpio_keys_report_state(ddata);

        return 0;
}

gpio_keys_open()函数最终调用gpio_keys_report_state()函数来上报按键当前状态。在驱动probe函数和resume函数都会运行该函数。

这个函数是否需要运行主要取决于应用层的工作逻辑,不想在probe或者resume上报当前按键状态的话,也可以在代码中注释掉该函数。

你的回答
关注数
1
收藏数
0
浏览数
2453
极术小姐姐
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息