这两种情况,内核中都有考虑,都在drivers/input/keyboard/ 下面。
GPIO 独立按键是 gpio_keys.c
GPIO 矩阵键盘是 matrix_keypad.c
具体也没有什么好分析的,主要就是采用platform 方式注册input 子系统,往应用层报键值。
在此基础上,添加相关的驱动,格式很固有化。直接上自己整理的模板吧。
GPIO 独立按键
-
#define SABRESD_VOLUME_UP IMX_GPIO_NR(1, 4) //得到gpio number 号
-
#define SABRESD_VOLUME_DN IMX_GPIO_NR(1, 5)
-
-
//定义宏
-
#ifdefined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-
#define GPIO_BUTTON(gpio_num, ev_code, act_low, descr, wake, debounce) \
-
{ \
-
.gpio = gpio_num, \
-
.type = EV_KEY, \
-
.code = ev_code, \
-
.active_low = act_low, \
-
.desc = "btn " descr, \
-
.wakeup = wake, \
-
.debounce_interval = debounce, \
-
}
-
//上面宏定义的数组
-
static struct gpio_keys_button CPU_NAME_buttons[] = {
-
GPIO_BUTTON(SABRESD_VOLUME_UP, KEY_VOLUMEUP, 1, "volume-up", 0, 1),
-
GPIO_BUTTON(SABRESD_VOLUME_DN, KEY_VOLUMEDOWN, 1, "volume-down", 0, 1),
-
GPIO_BUTTON(SABRESD_POWER_OFF, KEY_POWER, 1, "power", 1, 1),
-
};
-
-
static struct gpio_keys_platform_data CPU_NAME_button_data = {
-
.buttons = CPU_NAME_buttons,
-
.nbuttons = ARRAY_SIZE(CPU_NAME_buttons),
-
};
-
//platform device 与driver 中对应的
-
static struct platform_device CPU_NAME_button_device = {
-
.name = "gpio-keys",
-
.id = -1,
-
.num_resources = 0,
-
.dev = {
-
.platform_data = &CPU_NAME_button_data,
-
}
-
};
-
//注册设备的函数
-
static void __init CPU_NAME_add_device_buttons(void)
-
{
-
platform_device_register(&CPU_NAME_button_device);
-
}
-
#else
-
static void __init CPU_NAME_add_device_buttons(void) {}
-
#endif
有些时候因不同CPU BSP 的GPIO 封装,在driver 中会出现一些问题。比如 gpio_request 可能会重复(imx287,
得到GPIO号的时候就已经request 了,太TMD超前了) 如下这段代码要屏蔽。
-
#if 0
-
error = gpio_request(button->gpio, button->desc ?: "gpio_keys");
-
if (error < 0) {
-
pr_err("gpio-keys: failed to request GPIO %d,"
-
" error %d\n", button->gpio, error);
-
goto fail2;
-
}
-
#endif
GPIO 矩阵键盘
-
#if 1
-
/*
-
* Tosa Keyboard
-
*/
-
#include <linux/input/matrix_keypad.h>
-
//矩阵键盘按下时对应的键码表
-
static const uint32_t tosakbd_keymap[] = {
-
KEY(0, 0, KEY_1),
-
KEY(0, 1, KEY_2),
-
KEY(0, 2, KEY_3),
-
-
-
KEY(1, 0, KEY_4),
-
KEY(1, 1, KEY_5),
-
KEY(1, 2, KEY_6),
-
-
-
KEY(2, 0, KEY_7),
-
KEY(2, 1, KEY_8),
-
KEY(2, 2, KEY_9),
-
-
-
KEY(3, 0, KEY_UP),
-
KEY(3, 1, KEY_0),
-
KEY(3, 2, KEY_DOWN),
-
-
KEY(4, 0, KEY_BACK),
-
KEY(4, 1, KEY_ENTER),
-
KEY(4, 2, KEY_ESC),
-
-
-
};
-
-
static struct matrix_keymap_data tosakbd_keymap_data = {
-
.keymap = tosakbd_keymap,
-
.keymap_size = ARRAY_SIZE(tosakbd_keymap),
-
};
-
-
//列选 得到GPIO 口number 号
-
static const int tosakbd_col_gpios[] =
-
{
-
// MXS_PIN_TO_GPIO( PINID_SSP0_DATA5), // 4
-
MXS_PIN_TO_GPIO(PINID_LCD_D08), // 5
-
MXS_PIN_TO_GPIO(PINID_LCD_D09), // 6
-
MXS_PIN_TO_GPIO(PINID_LCD_D10) // 7
-
};
-
//行选 得到GPIO 口number 号
-
static const int tosakbd_row_gpios[] =
-
{
-
MXS_PIN_TO_GPIO(PINID_LCD_D11), // 2
-
MXS_PIN_TO_GPIO(PINID_LCD_D12), // 2
-
MXS_PIN_TO_GPIO(PINID_LCD_D13), // 3
-
MXS_PIN_TO_GPIO(PINID_LCD_D14), // 1
-
MXS_PIN_TO_GPIO(PINID_LCD_D15) // 0
-
};
-
//driver 中的需要的data
-
static struct matrix_keypad_platform_data CPU_NAMEkbd_pdata = {
-
.keymap_data = &tosakbd_keymap_data,
-
.row_gpios = tosakbd_row_gpios,
-
.col_gpios = tosakbd_col_gpios,
-
.num_row_gpios = ARRAY_SIZE(tosakbd_row_gpios),
-
.num_col_gpios = ARRAY_SIZE(tosakbd_col_gpios),
-
.col_scan_delay_us = 10,
-
.debounce_ms = 10,
-
.wakeup = 1,
-
-
.active_low =0 ,
-
};
-
-
static struct platform_device CPU_NAMEkbd_device = {
-
.name = "matrix-keypad",
-
.id = -1,
-
.dev = {
-
.platform_data = &CPU_NAMEkbd_pdata,
-
},
-
};
-
-
#endif
上面的两种方式,有些时候因不同CPU BSP 的GPIO 封装,在driver 中会出现一些问题。由于不同CPU GPIO口
产生中断的触发方式不同,这里出现问题的更多。
-
err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
-
matrix_keypad_interrupt,
-
IRQF_DISABLED |
-
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-
"matrix-keypad", keypad);
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING 很多CPU无法同时支持上升延与下降延触发。只能选择其中一个,要么FALLING ,要么RISING。
这两种方式,内核都已经封装成足够简单的方式了,用不着自己去写一个驱动,类似于填空就好了。
阅读(9095) | 评论(0) | 转发(0) |