iTop-4418使用矩阵键盘

三星S5P4418没有SAMSUNG矩阵键盘控制器,因此需要使用Linux自带的matrix-keypad驱动程序驱动矩阵键盘。

配置GPIO

iTop-4418的GPIO初始化配置文件位于kernel/arch/arm/plat-s5p4418/topeet/include/cfg_gpio.h,每个GPIO脚通过5组在头文件kernel/arch/arm/plat-s5p4418/topeet/include/cfg_type.h中的宏定义的或运算组合实现配置。

同时,在uBoot代码仓库u-boot/board/s5p4418/drone2/include/cfg_gpio.h中,也有格式相同的、用于GPIO配置的头文件。

第一组:PAD_MODE_XXX,用于设置GPIO为对应模式(复用功能/输入/输出/中断)。

第二组:PAD_FUNC_ALT[0:3],用于配置GPIO的复用功能。

第三组:PAD_LEVEL_XXX,用于配置GPIO输出电平或中断条件。

第四组:PAD_PULL_XX,用于配置输入模式的内部上拉或者下拉。

第五组:PAD_STRENGTH_[0..3],用于设置GPIO的驱动能力。

第一组:PAD_MODE_XXX

用于设置GPIO为对应模式,可选参数包括:

PAD_MODE_ALT配置GPIO引脚使用S5P4418手册定义的复用功能,此时GPIO引脚的功能选择由第二组宏定义选择。

PAD_MODE_IN配置GPIO引脚为输入模式。

PAD_MODE_OUT配置GPIO引脚为输出模式。

PAD_MODE_INT配置GPIO引脚为中断模式。

/* gpio mode, altfunction, gpio in/out or interrput */
enum {
    PAD_MODE_ALT    = (0 << PAD_MODE_SHIFT),
    PAD_MODE_IN     = (1 << PAD_MODE_SHIFT),
    PAD_MODE_OUT    = (2 << PAD_MODE_SHIFT),
    PAD_MODE_INT    = (3 << PAD_MODE_SHIFT),
};

第二组:PAD_FUNC_ALT[0:3]

用于配置GPIO的复用功能。这些复用功能由S5P4418手册I/O Function Description一节定义。可选参数包括:

PAD_FUNC_ALT0配置引脚使用手册定义的Alternate Function 0

PAD_FUNC_ALT1配置引脚使用手册定义的Alternate Function 1

PAD_FUNC_ALT2配置引脚使用手册定义的Alternate Function 2

PAD_FUNC_ALT3配置引脚使用手册定义的Alternate Function 3

/* gpio altfunction, refer to NX_GPIO_PADFUNC in nx_gpio.h */
enum {
    PAD_FUNC_ALT0   = (0 << PAD_FUNC_SHIFT),
    PAD_FUNC_ALT1   = (1 << PAD_FUNC_SHIFT),
    PAD_FUNC_ALT2   = (2 << PAD_FUNC_SHIFT),
    PAD_FUNC_ALT3   = (3 << PAD_FUNC_SHIFT),
};

第三组:PAD_LEVEL_XXX

用于配置GPIO输出电平或中断条件。可选参数包括:

PAD_LEVEL_LOW输出低电平或低电平中断,Alive GPIO使用异步中断。

PAD_LEVEL_HIGH输出高电平或高电平中断,Alive GPIO使用异步中断。

PAD_LEVEL_FALLINGEDGE下降沿中断,Alive GPIO使用异步中断。

PAD_LEVEL_RISINGEDGE上升沿中断,Alive GPIO使用异步中断。

PAD_LEVEL_LOW_SYNC同步低电平中断,适用于Alive GPIO,普通GPIO不支持。

PAD_LEVEL_HIGH_SYNC同步高电平中断,适用于Alive GPIO,普通GPIO不支持。

PAD_LEVEL_BOTHEDGE下降沿-上升沿中断,Alive GPIO不支持。

PAD_LEVEL_ALTGPIO使用复用功能。

/* ouput level or interrupt detect mode, refer to NX_GPIO_INTMODE in nx_gpio.h */
enum {
    PAD_LEVEL_LOW         = (0 << PAD_LEVEL_SHIFT),     /* if alive, async lowlevel */
    PAD_LEVEL_HIGH        = (1 << PAD_LEVEL_SHIFT),     /* if alive, async highlevel */
    PAD_LEVEL_FALLINGEDGE = (2 << PAD_LEVEL_SHIFT),     /* if alive, async fallingedge */
    PAD_LEVEL_RISINGEDGE  = (3 << PAD_LEVEL_SHIFT),     /* if alive, async eisingedge */
    PAD_LEVEL_LOW_SYNC    = (4 << PAD_LEVEL_SHIFT),     /* if gpio , not support */
    PAD_LEVEL_HIGH_SYNC   = (5 << PAD_LEVEL_SHIFT),     /* if gpio , not support */
    PAD_LEVEL_BOTHEDGE    = (4 << PAD_LEVEL_SHIFT),     /* if alive, not support */
    PAD_LEVEL_ALT         = (6 << PAD_LEVEL_SHIFT),     /* if pad function is alt, not set */
};

第四组:PAD_PULL_XX

用于配置输入模式的内部上拉或者下拉。可选参数包括:

PAD_PULL_DN下拉。

PAD_PULL_UP上拉。

PAD_PULL_OFF无。

enum {
    PAD_PULL_DN     = (0 << PAD_PULLUP_SHIFT),          /* Do not support Alive-GPIO */
    PAD_PULL_UP     = (1 << PAD_PULLUP_SHIFT),
    PAD_PULL_OFF    = (2 << PAD_PULLUP_SHIFT),
};

第五组:PAD_STRENGTH_[0..3]

用于设置GPIO的驱动能力。可选参数为PAD_STRENGTH_0PAD_STRENGTH_3四个等级。

enum {
    PAD_STRENGTH_0 = (0 << PAD_STRENGTH_SHIFT),
    PAD_STRENGTH_1 = (1 << PAD_STRENGTH_SHIFT),
    PAD_STRENGTH_2 = (2 << PAD_STRENGTH_SHIFT),
    PAD_STRENGTH_3 = (3 << PAD_STRENGTH_SHIFT),
};

配置样例

参考:

https://blog.csdn.net/Ace_Shiyuan/article/details/110958057

https://blog.csdn.net/jklinux/article/details/73848927

列线(输出模式)

配置GPIOD[28..31]MCU_TSI1_D[0..3])为输出模式,作为列线COL[3..0],用于matrix_keypad驱动程序。

//Modification: Set GPIOD[28..31] (MCU_TSI1_D[0..3]) to OUTPUT mode to work as COL[3..0] for matrix_keypad driver
#define PAD_GPIOD28     (PAD_MODE_OUT | PAD_FUNC_ALT0 | PAD_LEVEL_HIGH | PAD_PULL_UP  | PAD_STRENGTH_0)     // 0: GPIO          ,1: VIP1_VD[0]          ,2: MPEGTSI_TDATA1[0]   ,3: MCUS_ADDR[24]       =
#define PAD_GPIOD29     (PAD_MODE_OUT | PAD_FUNC_ALT0 | PAD_LEVEL_HIGH | PAD_PULL_UP  | PAD_STRENGTH_0)     // 0: GPIO          ,1: VIP1_VD[1]          ,2: MPEGTSI_TDATA1[1]   ,3:_                    =
#define PAD_GPIOD30     (PAD_MODE_OUT | PAD_FUNC_ALT0 | PAD_LEVEL_HIGH | PAD_PULL_UP  | PAD_STRENGTH_0)     // 0: GPIO          ,1: VIP1_VD[2]          ,2: MPEGTSI_TDATA1[2]   ,3:_                    =
#define PAD_GPIOD31     (PAD_MODE_OUT | PAD_FUNC_ALT0 | PAD_LEVEL_HIGH | PAD_PULL_UP  | PAD_STRENGTH_0)     // 0: GPIO          ,1: VIP1_VD[3]          ,2: MPEGTSI_TDATA1[3]   ,3:_                    =
//End-of-Modification: Set GPIOD[28..31] (MCU_TSI1_D[0..3]) to OUTPUT mode to work as COL[3..0] for matrix_keypad driver

行线(输入模式)

配置GPIOD[0..3]MCU_TSI1_D[4..7])为上拉输入模式,作为列线ROW[3..0],用于matrix_keypad驱动程序。

//Modification: Set pull-up for ROW[0..3] for matrix_keypad using GPIOE[3..0] (MCU_TSI1_D[7..4])
#define PAD_GPIOE0      (PAD_MODE_IN  | PAD_FUNC_ALT0 | PAD_LEVEL_LOW  | PAD_PULL_UP  | PAD_STRENGTH_0)     // 0: GPIO          1: VIP1_VD[4]           ,2: MPEGTSI_TDATA1[0]   ,3:_                    =
#define PAD_GPIOE1      (PAD_MODE_IN  | PAD_FUNC_ALT0 | PAD_LEVEL_LOW  | PAD_PULL_UP  | PAD_STRENGTH_0)     // 0: GPIO          1: VIP1_VD[5]           ,2: MPEGTSI_TDATA1[0]   ,3:_                    =
#define PAD_GPIOE2      (PAD_MODE_IN  | PAD_FUNC_ALT0 | PAD_LEVEL_LOW  | PAD_PULL_UP  | PAD_STRENGTH_0)     // 0: GPIO          1: VIP1_VD[6]           ,2: MPEGTSI_TDATA1[0]   ,3:_                    =
#define PAD_GPIOE3      (PAD_MODE_IN  | PAD_FUNC_ALT0 | PAD_LEVEL_LOW  | PAD_PULL_UP  | PAD_STRENGTH_0)     // 0: GPIO          1: VIP1_VD[7]           ,2: MPEGTSI_TDATA1[0]   ,3:_                    =
//End-of-Modification: Set pull-up for ROW[0..3] for matrix_keypad using GPIOE[3..0] (MCU_TSI1_D[7..4])

内核驱动程序添加

进入iTop-4418内核源码,打开菜单化配置界面:

cd kernel
export ARCH=arm
make menuconfig

定位到:

Device Drivers ---> Input device support ---> Keyboards

选中GPIO driven matrix keypad support项,保存并退出。

硬件信息添加

在平台初始化文件kernel/arch/arm/plat-s5p4418/topeet/device.c中添加相关结构体定义:

#ifdef CONFIG_KEYBOARD_MATRIX
/* 
 * Matrix Keypad Definitions for iTop-4418.
 * 
 * Include 'GPIO driven matrix keypad support' to enable the definition of CONFIG_KEYBOARD_MATRIX in:
 * MenuConfig ---> Device Drivers ---> Input device support ---> Keyboards
 * 
 * This file is merged into:
 * kernel/arch/arm/plat-s5p4418/topeet/device.c
 * 
 * Code adapted from SAMSUNG Exynos 4412's keypad definition. (%iTop4412Src%\arch\arm\mach-exynos\mach-itop4412.c : '#ifdef CONFIG_SAMSUNG_DEV_KEYPAD' line)
 * We set GPIOD[28..31] (MCU_TSI1_D[0..3]) to OUTPUT mode to work as COL[3..0] for matrix_keypad driver.
 * We set pull-up for ROW[0..3] for matrix_keypad using GPIOE[3..0] (MCU_TSI1_D[7..4]).
 * In iTop-4412:
 * -   CORE   -> KEYPAD
 * - KP_COL6  -> COL0
 * - KP_COL5  -> COL1
 * - KP_COL3  -> COL2
 * - KP_COL0  -> COL3
 * - KP_ROW13 -> ROW0
 * - KP_ROW7  -> ROW1
 * - KP_ROW6  -> ROW2
 * - KP_ROW8  -> ROW3
 * In iTop-4418:
 * -   CORE   -> KEYPAD
 * - GPIOD31  -> COL0
 * - GPIOD30  -> COL1
 * - GPIOD29  -> COL2
 * - GPIOD28  -> COL3
 * - GPIOE3   -> ROW0
 * - GPIOE2   -> ROW1
 * - GPIOE1   -> ROW2
 * - GPIOE0   -> ROW3
 * 
 * Ref. https://blog.csdn.net/jklinux/article/details/73848927
 * 
 * Add this code in nxp_board_devices_register():
 * //Modification: register matrix keypad for iTpp-4418
 * #ifdef CONFIG_KEYBOARD_MATRIX
 * printk("plat: add device matrix-keypad (for itop-4418)\n");
 * platform_device_register(&itop4418_matrix_keypad_device);
 * #endif
 * //End-of-Modification: register matrix keypad for iTpp-4418
 * 
 * Picsell Dois @ SEU-BME
 */
 
/* Linux header */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
/* Platform-related header files */
#include <mach/gpio.h>
#include <mach/platform.h>
#include <mach/soc.h>
 
/* Key definition */
static u32 arrKeyMapping[] = {
    //KEY(row, col, keycode)
    KEY( 3, 3, KEY_1), KEY( 3, 2, KEY_2), KEY( 3, 1, KEY_3), KEY( 3, 0, KEY_4),
    KEY( 2, 3, KEY_5), KEY( 2, 2, KEY_6), KEY( 2, 1, KEY_7), KEY( 2, 0, KEY_8),
    KEY( 1, 3, KEY_9), KEY( 1, 2, KEY_0), KEY( 1, 1, KEY_A), KEY( 1, 0, KEY_B),
    KEY( 0, 3, KEY_C), KEY( 0, 2, KEY_D), KEY( 0, 1, KEY_E), KEY( 0, 0, KEY_F)
};
 
static struct matrix_keymap_data mkdKeyMappingData = {
    .keymap = arrKeyMapping,
    .keymap_size = ARRAY_SIZE(arrKeyMapping), 
};
 
/* Row & Col definition */
static u32 arrRowGPIOs[] = {PAD_GPIO_E + 3, PAD_GPIO_E + 2, PAD_GPIO_E + 1, PAD_GPIO_E + 0}; //GPIO ports of Row line
static u32 arrColGPIOs[] = {PAD_GPIO_D + 31, PAD_GPIO_D + 30, PAD_GPIO_D + 29, PAD_GPIO_D + 28}; //GPIO ports of Col line
 
static struct matrix_keypad_platform_data mkpMatrixKeypadPlatformData = {
    .keymap_data = &mkdKeyMappingData,
    .row_gpios = arrRowGPIOs,
    .col_gpios = arrColGPIOs,
 
    .num_row_gpios = ARRAY_SIZE(arrRowGPIOs),
    .num_col_gpios = ARRAY_SIZE(arrColGPIOs),
 
    .col_scan_delay_us = 100,
    .debounce_ms = 10,  
 
    .active_low = 1,
    .no_autorepeat = 0,
};
 
/* Platform device definition */
struct platform_device itop4418_matrix_keypad_device = {
    .name = "matrix-keypad",
    .id = -1,
    .dev = {
        .platform_data = &mkpMatrixKeypadPlatformData,
    },
};
 
#endif // CONFIG_KEYBOARD_MATRIX

设备注册

kernel/arch/arm/plat-s5p4418/topeet/device.cnxp_board_devices_register()函数末尾添加平台设备注册代码:

//Modification: register matrix keypad for iTpp-4418
#ifdef CONFIG_KEYBOARD_MATRIX
printk("plat: add device matrix-keypad (for itop-4418)\n");
platform_device_register(&itop4418_matrix_keypad_device);
#endif
//End-of-Modification: register matrix keypad for iTpp-4418

使用设备(Qt/E)

查看引脚占用状况:

mount -t debugfs none /sys/kernel/debug
cat /sys/kernel/debug/gpio

应能观察到类似matrix_kbd_colmatrix_kbd_row的GPIO引脚占用。

检查输入事件对应关系:

cat /proc/bus/input/devices

应能观察到Name="matrix-keypad"的项,并记录其Handlers属性中的Event编号。这里假设为event0

编辑Qt初始化脚本,导出QWS_KEYBOARD变量,指向/dev/input/event0

export QWS_KEYBOARD="USB:/dev/input/event0"

参考:

https://blog.csdn.net/MyArrow/article/details/10582667

https://blog.csdn.net/qq_33205540/article/details/105950700

it
除非特别注明,本页内容采用以下授权方式: Creative Commons Attribution-ShareAlike 3.0 License