Signed-off-by: Andrey Danin <danind...@mail.ru> CC: Stephen Warren <swar...@nvidia.com> CC: Marc Dietrich <marvi...@gmx.de> CC: Julian Andres Klode <j...@jak-linux.org> CC: ac...@lists.launchpad.net --- Changes for v2: - fixed incorrect keys handling in nvec-keyboard driver
.../include/asm/arch-tegra/tegra_nvec_keyboard.h | 304 ++++++++++++++++++++ drivers/input/Makefile | 3 + drivers/input/tegra-nvec-kbc.c | 215 ++++++++++++++ include/configs/tegra-common-post.h | 2 + 4 files changed, 524 insertions(+) create mode 100644 arch/arm/include/asm/arch-tegra/tegra_nvec_keyboard.h create mode 100644 drivers/input/tegra-nvec-kbc.c diff --git a/arch/arm/include/asm/arch-tegra/tegra_nvec_keyboard.h b/arch/arm/include/asm/arch-tegra/tegra_nvec_keyboard.h new file mode 100644 index 0000000..5f789f4 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra/tegra_nvec_keyboard.h @@ -0,0 +1,304 @@ +/* + * (C) Copyright 2014 + * Andrey Danin <danind...@mail.ru> + * (C) Copyright 2009 + * NVIDIA Corporation. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _TEGRA_NVEC_KEYBOARD_H_ +#define _TEGRA_NVEC_KEYBOARD_H_ + +#include <linux/input.h> + + +/* Keytables */ + +static unsigned short code_tab_102us[] = { + /* 0x00 */ + KEY_GRAVE, + KEY_ESC, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_0, + KEY_MINUS, + KEY_EQUAL, + KEY_BACKSPACE, + KEY_TAB, + /* 0x10 */ + KEY_Q, + KEY_W, + KEY_E, + KEY_R, + KEY_T, + KEY_Y, + KEY_U, + KEY_I, + KEY_O, + KEY_P, + KEY_LEFTBRACE, + KEY_RIGHTBRACE, + KEY_ENTER, + KEY_LEFTCTRL, + KEY_A, + KEY_S, + /* 0x20 */ + KEY_D, + KEY_F, + KEY_G, + KEY_H, + KEY_J, + KEY_K, + KEY_L, + KEY_SEMICOLON, + KEY_APOSTROPHE, + KEY_GRAVE, + KEY_LEFTSHIFT, + KEY_BACKSLASH, + KEY_Z, + KEY_X, + KEY_C, + KEY_V, + /* 0x30 */ + KEY_B, + KEY_N, + KEY_M, + KEY_COMMA, + KEY_DOT, + KEY_SLASH, + KEY_RIGHTSHIFT, + KEY_KPASTERISK, + KEY_LEFTALT, + KEY_SPACE, + KEY_CAPSLOCK, + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + /* 0x40 */ + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_FN, + /* VK_SCROLL */ + 0, + KEY_KP7, + KEY_KP8, + KEY_KP9, + KEY_KPMINUS, + KEY_KP4, + KEY_KP5, + KEY_KP6, + KEY_KPPLUS, + KEY_KP1, + /* 0x50 */ + KEY_KP2, + KEY_KP3, + KEY_KP0, + KEY_KPDOT, + /* VK_SNAPSHOT */ + 0, /* KEY_MENU, */ + KEY_POWER, + /* VK_OEM_102 */ + KEY_102ND, + KEY_F11, + KEY_F12, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x60 */ + 0, + 0, + 0, + 0, /* KEY_SEARCH, */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x70 */ + 0, + 0, + 0, + KEY_KP5, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + KEY_KP9, +}; + +static unsigned short extcode_tab_us102[] = { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x10 */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* VK_MEDIA_NEXT_TRACK */ + 0, + 0, + 0, + /* VK_RETURN */ + 0, + KEY_RIGHTCTRL, + 0, + 0, + /* 0x20 */ + KEY_MUTE, + /* VK_LAUNCH_APP1 */ + 0, + /* VK_MEDIA_PLAY_PAUSE */ + 0, + 0, + /* VK_MEDIA_STOP */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x30 */ + KEY_VOLUMEUP, + 0, + /* VK_BROWSER_HOME */ + 0, + 0, + 0, + /* VK_DIVIDE */ + KEY_KPSLASH, + 0, + /* VK_SNAPSHOT */ + KEY_SYSRQ, + /* VK_RMENU */ + KEY_RIGHTALT, + /* VK_OEM_NV_BACKLIGHT_UP */ + 0, + /* VK_OEM_NV_BACKLIGHT_DN */ + 0, + /* VK_OEM_NV_BACKLIGHT_AUTOTOGGLE */ + 0, + /* VK_OEM_NV_POWER_INFO */ + 0, + /* VK_OEM_NV_WIFI_TOGGLE */ + 0, + /* VK_OEM_NV_DISPLAY_SELECT */ + 0, + /* VK_OEM_NV_AIRPLANE_TOGGLE */ + 0, + /* 0x40 */ + 0, + KEY_LEFT, + 0, + 0, + 0, + 0, + 0, /* KEY_CANCEL, */ + KEY_HOME, + KEY_UP, + KEY_PAGEUP, + 0, + KEY_LEFT, + 0, + KEY_RIGHT, + 0, + KEY_END, + /* 0x50 */ + KEY_DOWN, + KEY_PAGEDOWN, + KEY_INSERT, + KEY_DELETE, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + KEY_LEFTMETA, + 0, + KEY_ESC, + KEY_KPMINUS, + 0, + 0, + 0, + 0, + 0, + 0, + /* VK_BROWSER_SEARCH */ + 0, + /* VK_BROWSER_FAVORITES */ + 0, + /* VK_BROWSER_REFRESH */ + 0, + /* VK_BROWSER_STOP */ + 0, + /* VK_BROWSER_FORWARD */ + 0, + /* VK_BROWSER_BACK */ + 0, + /* VK_LAUNCH_APP2 */ + 0, + /* VK_LAUNCH_MAIL */ + 0, + /* VK_LAUNCH_MEDIA_SELECT */ + 0, +}; + +static unsigned short *code_tabs[] = { code_tab_102us, extcode_tab_us102 }; + + +#endif /* _TEGRA_NVEC_KEYBOARD_H_ */ diff --git a/drivers/input/Makefile b/drivers/input/Makefile index a8e9be2..38c576f 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -7,6 +7,9 @@ obj-$(CONFIG_I8042_KBD) += i8042.o obj-$(CONFIG_TEGRA_KEYBOARD) += tegra-kbc.o +ifdef CONFIG_SYS_I2C_TEGRA_NVEC +obj-$(CONFIG_TEGRA_NVEC_KEYBOARD) += tegra-nvec-kbc.o +endif obj-$(CONFIG_CROS_EC_KEYB) += cros_ec_keyb.o ifdef CONFIG_PS2KBD obj-y += keyboard.o pc_keyb.o diff --git a/drivers/input/tegra-nvec-kbc.c b/drivers/input/tegra-nvec-kbc.c new file mode 100644 index 0000000..f5832b1 --- /dev/null +++ b/drivers/input/tegra-nvec-kbc.c @@ -0,0 +1,215 @@ +/* + * (C) Copyright 2014 + * Andrey Danin <danind...@mail.ru> + * (C) Copyright 2011 + * NVIDIA Corporation <www.nvidia.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <input.h> +#include <asm/arch-tegra/tegra_nvec.h> +#include <asm/arch-tegra/tegra_nvec_keyboard.h> + + +enum { + KBC_MAX_KPENT = 8, + KBC_REPEAT_RATE_MS = 30, + KBC_REPEAT_DELAY_MS = 240, +}; + +/* keyboard config/state */ +static struct keyb { + int registered; + struct input_config input; /* The input layer */ + int pressed_keys[KBC_MAX_KPENT]; + int pressed_keys_cnt; +} config; + + +/* 0 - pressed, other - released */ +char keys[256]; + + +/* nvec commands */ +static char enable_kbd[] = { NVEC_KBD, ENABLE_KBD }; +static char reset_kbd[] = { NVEC_PS2, MOUSE_SEND_CMD, MOUSE_RESET, 3 }; +static char clear_leds[] = { NVEC_KBD, SET_LEDS, 0 }; + + +/** + * Check the tegra nvec keyboard, and send any keys that are pressed. + * + * This is called by input_tstc() and input_getc() when they need more + * characters + * + * @param input Input configuration + * @return 1, to indicate that we have something to look at + */ +int tegra_nvec_kbc_check(struct input_config *input) +{ + int i; + + nvec_read_events(); + + config.pressed_keys_cnt = 0; + /* TODO Optimization required */ + for (i = 0; i < sizeof(keys); ++i) { + if (keys[i] == 0 && config.pressed_keys_cnt < KBC_MAX_KPENT) { + config.pressed_keys[config.pressed_keys_cnt] = i; + ++config.pressed_keys_cnt; + } + } + + input_send_keycodes(input, + config.pressed_keys, + config.pressed_keys_cnt); + + return config.pressed_keys_cnt; +} + + +/** + * Test if keys are available to be read + * + * @return 0 if no keys available, 1 if keys are available + */ +static int kbd_tstc(void) +{ + /* Just get input to do this for us */ + return input_tstc(&config.input); +} + + +/** + * Read a key + * + * TODO: U-Boot wants 0 for no key, but Ctrl-@ is a valid key... + * + * @return ASCII key code, or 0 if no key, or -1 if error + */ +static int kbd_getc(void) +{ + /* Just get input to do this for us */ + return input_getc(&config.input); +} + + +int tegra_nvec_process_keyboard_msg(const unsigned char *msg) +{ + int code, state; + int event_type; + int _size; + int key; + + + event_type = nvec_msg_event_type(msg); + if (event_type != NVEC_KEYBOARD) + return -1; + + _size = (msg[0] & (3 << 5)) >> 5; + + if (_size == NVEC_VAR_SIZE) { + debug("Skip unsupported msg (size: %d)\n", _size); + return -1; + } + + if (_size == NVEC_3BYTES) + msg++; + + code = msg[1] & 0x7f; + state = msg[1] & 0x80; + + key = code_tabs[_size][code]; + keys[key] = state; + + return 0; +} + + +int tegra_nvec_enable_kbd_events(void) +{ + if (nvec_do_request(reset_kbd, 4)) { + error("NVEC: failed to reset keyboard\n"); + return -1; + } + if (nvec_do_request(clear_leds, 3)) { + error("NVEC: failed to clear leds\n"); + return -1; + } + if (nvec_do_request(enable_kbd, 2)) { + error("NVEC: failed to enable keyboard\n"); + return -1; + } + + debug("NVEC: keyboard initialization finished\n"); + + return 0; +} + + +static int tegra_nvec_kbc_start(void) +{ + if (config.registered) + return 0; + + struct nvec_periph nvec_keyboard; + memset(&nvec_keyboard, 0, sizeof(nvec_keyboard)); + nvec_keyboard.start = tegra_nvec_enable_kbd_events; + nvec_keyboard.process_msg = tegra_nvec_process_keyboard_msg; + + if (nvec_register_periph(NVEC_KEYBOARD, &nvec_keyboard)) { + error("NVEC: failed to register keyboard perephirial device"); + return -1; + } + + config.registered = 1; + + return 0; +} + + +int drv_keyboard_init(void) +{ + struct stdio_dev dev; + int error; +#ifdef CONFIG_CONSOLE_MUX + char *stdinname = getenv("stdin"); +#endif + + memset(keys, 1, sizeof(keys)); + + config.registered = 0; + + if (input_init(&config.input, 0)) { + printf("nvec kbc: cannot set up input\n"); + return -1; + } + input_set_delays(&config.input, KBC_REPEAT_DELAY_MS, + KBC_REPEAT_RATE_MS); + config.input.read_keys = tegra_nvec_kbc_check; + + memset(&dev, '\0', sizeof(dev)); + strcpy(dev.name, "tegra-nvec-kbc"); + dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; + dev.getc = kbd_getc; + dev.tstc = kbd_tstc; + dev.start = tegra_nvec_kbc_start; + + /* Register the device. tegra_nvec_kbc_start() will be called soon */ + error = input_stdio_register(&dev); + if (error) { + printf("nvec kbc: failed to register stdio device, %d\n", + error); + return error; + } +#ifdef CONFIG_CONSOLE_MUX + error = iomux_doenv(stdin, stdinname); + if (error) { + printf("nvec kbc: iomux_doenv failed, %d\n", error); + return error; + } +#endif + return 0; +} diff --git a/include/configs/tegra-common-post.h b/include/configs/tegra-common-post.h index e1a3bbc..efc0ef9 100644 --- a/include/configs/tegra-common-post.h +++ b/include/configs/tegra-common-post.h @@ -106,6 +106,8 @@ #ifdef CONFIG_TEGRA_KEYBOARD #define STDIN_KBD_KBC ",tegra-kbc" +#elif defined(CONFIG_TEGRA_NVEC_KEYBOARD) +#define STDIN_KBD_KBC ",tegra-nvec-kbc" #else #define STDIN_KBD_KBC "" #endif -- 1.7.9.5 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot