[U-Boot] [PATCH v2 4/6] ARM: tegra: nvec: add keyboard support
Andrey Danin
danindrey at mail.ru
Sun Apr 27 03:14:28 CEST 2014
Signed-off-by: Andrey Danin <danindrey at mail.ru>
CC: Stephen Warren <swarren at nvidia.com>
CC: Marc Dietrich <marvin24 at gmx.de>
CC: Julian Andres Klode <jak at jak-linux.org>
CC: ac100 at 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 <danindrey at 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 <danindrey at 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
More information about the U-Boot
mailing list