| /* |
| * (C) Copyright 2011 |
| * NVIDIA Corporation <www.nvidia.com> |
| * |
| * See file CREDITS for list of people who contributed to this |
| * project. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation; either version 2 of |
| * the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| * MA 02111-1307 USA |
| */ |
| |
| #include <common.h> |
| #include <malloc.h> |
| #include <stdio_dev.h> |
| #include <asm/io.h> |
| #include <asm/arch/clock.h> |
| #include <asm/arch/pinmux.h> |
| #include <tegra-kbc.h> |
| #include <fdt_decode.h> |
| |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| #define DEVNAME "tegra-kbc" |
| |
| enum { |
| KBC_MAX_GPIO = 24, |
| KBC_MAX_KPENT = 8, |
| }; |
| |
| #define KBC_MAX_KEY (KBC_MAX_ROW * KBC_MAX_COL) |
| |
| /* KBC row scan time and delay for beginning the row scan. */ |
| #define KBC_ROW_SCAN_TIME 16 |
| #define KBC_ROW_SCAN_DLY 5 |
| |
| /* uses a 32KHz clock so a cycle = 1/32Khz */ |
| #define KBC_CYCLE_IN_USEC DIV_ROUND_UP(1000, 32) |
| |
| #define KBC_FIFO_TH_CNT_SHIFT(cnt) (cnt << 14) |
| #define KBC_DEBOUNCE_CNT_SHIFT(cnt) (cnt << 4) |
| #define KBC_CONTROL_FIFO_CNT_INT_EN (1 << 3) |
| #define KBC_CONTROL_KBC_EN (1 << 0) |
| #define KBC_INT_FIFO_CNT_INT_STATUS (1 << 2) |
| #define KBC_KPENT_VALID (1 << 7) |
| |
| #define KBC_RPT_DLY 20 |
| #define KBC_RPT_RATE 4 |
| |
| /* kbc globals */ |
| static unsigned int kbc_repoll_time; |
| static unsigned int kbc_init_dly; |
| static unsigned long kbc_start_time; |
| |
| /* |
| * Use a simple FIFO to convert some keys into escape sequences and to handle |
| * testc vs getc. The FIFO length must be a power of two. Currently, four |
| * characters is the smallest power of two that is large enough to contain all |
| * generated escape sequences. |
| */ |
| #define KBC_FIFO_LENGTH (1 << 2) |
| |
| static int kbc_fifo[KBC_FIFO_LENGTH]; |
| static int kbc_fifo_read; |
| static int kbc_fifo_write; |
| |
| /* These are key maps for each modifier: each has KBC_KEY_COUNT entries */ |
| u8 *kbc_plain_keycode; |
| u8 *kbc_fn_keycode; |
| u8 *kbc_shift_keycode; |
| u8 *kbc_ctrl_keycode; |
| |
| #ifdef CONFIG_OF_CONTROL |
| struct fdt_kbc config; /* Our keyboard config */ |
| #if (FDT_KBC_KEY_COUNT) != (KBC_KEY_COUNT) |
| #error definition mismatch |
| #endif |
| #endif |
| |
| static int tegra_kbc_keycode(int r, int c, int modifier) |
| { |
| int entry = r * KBC_MAX_COL + c; |
| |
| if (modifier == KEY_FN) |
| return kbc_fn_keycode[entry]; |
| |
| /* Put ctrl keys ahead of shift */ |
| else if ((modifier == KEY_LEFT_CTRL || modifier == KEY_RIGHT_CTRL) |
| && kbc_ctrl_keycode) |
| return kbc_ctrl_keycode[entry]; |
| else if (modifier == KEY_SHIFT) |
| return kbc_shift_keycode[entry]; |
| else |
| return kbc_plain_keycode[entry]; |
| } |
| |
| /* determines if current keypress configuration can cause key ghosting */ |
| static int is_ghost_key_config(int *rows_val, int *cols_val, int valid) |
| { |
| int i, j, key_in_same_col = 0, key_in_same_row = 0; |
| |
| /* |
| * Matrix keyboard designs are prone to keyboard ghosting. |
| * Ghosting occurs if there are 3 keys such that - |
| * any 2 of the 3 keys share a row, and any 2 of them share a column. |
| */ |
| for (i = 0; i < valid; i++) { |
| /* |
| * Find 2 keys such that one key is in the same row |
| * and the other is in the same column as the i-th key. |
| */ |
| for (j = i + 1; j < valid; j++) { |
| if (cols_val[j] == cols_val[i]) |
| key_in_same_col = 1; |
| if (rows_val[j] == rows_val[i]) |
| key_in_same_row = 1; |
| } |
| } |
| |
| if (key_in_same_col && key_in_same_row) |
| return 1; |
| else |
| return 0; |
| } |
| |
| /* reads the keyboard fifo for current keypresses. */ |
| static int tegra_kbc_find_keys(int *fifo) |
| { |
| struct kbc_tegra *kbc = (struct kbc_tegra *)TEGRA_KBC_BASE; |
| int rows_val[KBC_MAX_KPENT], cols_val[KBC_MAX_KPENT]; |
| u32 kp_ent_val[(KBC_MAX_KPENT + 3) / 4]; |
| u32 *kp_ents = kp_ent_val; |
| u32 kp_ent = 0; |
| int i, j, k, valid = 0; |
| int modifier = 0; |
| |
| for (i = 0; i < ARRAY_SIZE(kp_ent_val); i++) |
| kp_ent_val[i] = readl(&kbc->kp_ent[i]); |
| |
| valid = 0; |
| for (i = 0; i < KBC_MAX_KPENT; i++) { |
| if (!(i&3)) |
| kp_ent = *kp_ents++; |
| |
| if (kp_ent & KBC_KPENT_VALID) { |
| cols_val[valid] = kp_ent & 0x7; |
| rows_val[valid++] = (kp_ent >> 3) & 0xf; |
| } |
| kp_ent >>= 8; |
| } |
| for (i = 0; i < valid; i++) { |
| k = tegra_kbc_keycode(rows_val[i], cols_val[i], 0); |
| if (KEY_IS_MODIFIER(k)) { |
| modifier = k; |
| break; |
| } |
| } |
| |
| /* For a ghost key config, ignore the keypresses for this iteration. */ |
| if ((valid >= 3) && is_ghost_key_config(rows_val, cols_val, valid)) |
| return KBC_MAX_KPENT + 1; |
| |
| j = 0; |
| for (i = 0; i < valid; i++) { |
| k = tegra_kbc_keycode(rows_val[i], cols_val[i], modifier); |
| /* Key modifiers (Fn and Shift) will not be part of the fifo */ |
| if (k && (k != -1)) |
| fifo[j++] = k; |
| } |
| |
| return j; |
| } |
| |
| /* processes all the keypresses in fifo and returns a single key */ |
| static int tegra_kbc_get_single_char(u32 fifo_cnt) |
| { |
| int i, cnt, j; |
| int fifo[KBC_MAX_KPENT] = {0}; |
| static int prev_fifo[KBC_MAX_KPENT]; |
| static int prev_cnt; |
| static int prev_key; |
| char key = 0; |
| |
| if (fifo_cnt) { |
| do { |
| cnt = tegra_kbc_find_keys(fifo); |
| /* If this is a ghost key combination report no change. */ |
| key = prev_key; |
| if (cnt <= KBC_MAX_KPENT) { |
| int prev_key_in_fifo = 0; |
| /* |
| * If multiple keys are pressed such that it |
| * results in * 2 or more unmodified keys, we |
| * will determine the newest key and report |
| * that to the upper layer. |
| */ |
| for (i = 0; i < cnt; i++) { |
| for (j = 0; j < prev_cnt; j++) { |
| if (fifo[i] == prev_fifo[j]) |
| break; |
| } |
| /* Found a new key. */ |
| if (j == prev_cnt) { |
| key = fifo[i]; |
| break; |
| } |
| if (prev_key == fifo[i]) |
| prev_key_in_fifo = 1; |
| } |
| /* |
| * Keys were released and FIFO does not contain |
| * the previous reported key. So report a null |
| * key. |
| */ |
| if (i == cnt && !prev_key_in_fifo) |
| key = 0; |
| |
| for (i = 0; i < cnt; i++) |
| prev_fifo[i] = fifo[i]; |
| prev_cnt = cnt; |
| prev_key = key; |
| } |
| } while (!key && --fifo_cnt); |
| } else { |
| prev_cnt = 0; |
| prev_key = 0; |
| } |
| udelay((fifo_cnt == 1) ? kbc_repoll_time : 1000); |
| |
| return key; |
| } |
| |
| /* manages keyboard hardware registers on keypresses and returns a key.*/ |
| static unsigned char tegra_kbc_get_char(void) |
| { |
| struct kbc_tegra *kbc = (struct kbc_tegra *)TEGRA_KBC_BASE; |
| u32 val, ctl; |
| char key = 0; |
| |
| /* |
| * Until all keys are released, defer further processing to |
| * the polling loop. |
| */ |
| ctl = readl(&kbc->control); |
| ctl &= ~KBC_CONTROL_FIFO_CNT_INT_EN; |
| writel(ctl, &kbc->control); |
| |
| /* |
| * Quickly bail out & reenable interrupts if the interrupt source |
| * wasn't fifo count threshold |
| */ |
| val = readl(&kbc->interrupt); |
| writel(val, &kbc->interrupt); |
| |
| if (val & KBC_INT_FIFO_CNT_INT_STATUS) |
| key = tegra_kbc_get_single_char((val >> 4) & 0xf); |
| |
| ctl |= KBC_CONTROL_FIFO_CNT_INT_EN; |
| writel(ctl, &kbc->control); |
| |
| return key; |
| } |
| |
| /* handles key repeat delay and key repeat rate.*/ |
| static int kbd_fetch_char(int test) |
| { |
| unsigned char key; |
| static unsigned char prev_key; |
| static unsigned int rpt_dly = KBC_RPT_DLY; |
| |
| do { |
| key = tegra_kbc_get_char(); |
| if (!key) { |
| prev_key = 0; |
| if (test) |
| break; |
| else |
| continue; |
| } |
| |
| /* This logic takes care of the repeat rate */ |
| if ((key != prev_key) || !(rpt_dly--)) |
| break; |
| } while (1); |
| |
| if (key == prev_key) { |
| rpt_dly = KBC_RPT_RATE; |
| } else { |
| rpt_dly = KBC_RPT_DLY; |
| prev_key = key; |
| } |
| |
| return key; |
| } |
| |
| /* |
| * Return true if there are no characters in the FIFO. |
| */ |
| static int kbd_fifo_empty(void) |
| { |
| return kbc_fifo_read == kbc_fifo_write; |
| } |
| |
| /* |
| * Return number of characters of free space in the FIFO. |
| */ |
| static int kbd_fifo_free_space(void) |
| { |
| return KBC_FIFO_LENGTH - (kbc_fifo_write - kbc_fifo_read); |
| } |
| |
| /* |
| * Insert a character into the FIFO. Calling this function when the FIFO is |
| * full will overwrite the oldest character in the FIFO. |
| */ |
| static void kbd_fifo_insert(int key) |
| { |
| int index = kbc_fifo_write & (KBC_FIFO_LENGTH - 1); |
| |
| assert(kbd_fifo_free_space() > 0); |
| |
| kbc_fifo[index] = key; |
| |
| kbc_fifo_write++; |
| } |
| |
| /* |
| * Remove a character from the FIFO, it is an error to call this function when |
| * the FIFO is empty. |
| */ |
| static int kbd_fifo_remove(void) |
| { |
| int index = kbc_fifo_read & (KBC_FIFO_LENGTH - 1); |
| int key = kbc_fifo[index]; |
| |
| assert(!kbd_fifo_empty()); |
| |
| kbc_fifo_read++; |
| |
| return key; |
| } |
| |
| /* |
| * Given a keycode, convert it to the sequence of characters that U-Boot expects |
| * to recieve from its input devices and insert the characters into the FIFO. |
| * If the keycode is 0, ignore it. Currently this function will only ever add |
| * at most three characters to the FIFO, so it is always safe to call when the |
| * FIFO is empty. |
| */ |
| static void kbd_fifo_refill(int key) |
| { |
| switch (key) |
| { |
| /* |
| * We need to deal with a zero keycode value here because the |
| * testc call can call us with zero if no key is pressed. |
| */ |
| case 0x00: |
| break; |
| |
| /* |
| * Generate escape sequences for arrow keys. Additional escape |
| * sequences can be added to the switch statements, but it may |
| * be better in the future t0 use the top bit of the keycode to |
| * indicate a key that generates an escape sequence. Then the |
| * outer switch could turn into an "if (key & 0x80)". |
| */ |
| case 0x1C: |
| case 0x1D: |
| case 0x1E: |
| case 0x1F: |
| kbd_fifo_insert(0x1B); /* Escape */ |
| kbd_fifo_insert('['); |
| |
| switch (key) |
| { |
| case 0x1C: kbd_fifo_insert('D'); break; |
| case 0x1D: kbd_fifo_insert('C'); break; |
| case 0x1E: kbd_fifo_insert('A'); break; |
| case 0x1F: kbd_fifo_insert('B'); break; |
| } |
| break; |
| |
| /* |
| * All other keycodes can be treated as characters as is and |
| * are inserted into the FIFO directly. |
| */ |
| default: |
| kbd_fifo_insert(key); |
| break; |
| } |
| } |
| |
| static void kbd_wait_for_fifo_init(void) |
| { |
| unsigned long elapsed_time; |
| long delay; |
| static unsigned int kbc_initialized; |
| |
| if (kbc_initialized) |
| return; |
| /* |
| * In order to detect keys pressed on boot, wait for the hardware to |
| * complete scanning the keys. This includes time to transition from |
| * Wkup mode to Continous polling mode and the repoll time. We can |
| * deduct the time thats already elapsed. |
| */ |
| elapsed_time = timer_get_us() - kbc_start_time; |
| delay = kbc_init_dly + kbc_repoll_time - elapsed_time; |
| if (delay > 0) |
| udelay(delay); |
| |
| kbc_initialized = 1; |
| } |
| |
| static int kbd_testc(void) |
| { |
| kbd_wait_for_fifo_init(); |
| |
| if (kbd_fifo_empty()) |
| kbd_fifo_refill(kbd_fetch_char(1)); |
| |
| return !kbd_fifo_empty(); |
| } |
| |
| static int kbd_getc(void) |
| { |
| if (kbd_fifo_empty()) |
| kbd_fifo_refill(kbd_fetch_char(0)); |
| |
| return kbd_fifo_remove(); |
| } |
| |
| /* configures keyboard GPIO registers to use the rows and columns */ |
| static void config_kbc(void) |
| { |
| struct kbc_tegra *kbc = (struct kbc_tegra *)TEGRA_KBC_BASE; |
| int i; |
| |
| for (i = 0; i < KBC_MAX_GPIO; i++) { |
| u32 row_cfg, col_cfg; |
| u32 r_shift = 5 * (i % 6); |
| u32 c_shift = 4 * (i % 8); |
| u32 r_mask = 0x1f << r_shift; |
| u32 c_mask = 0xf << c_shift; |
| u32 r_offs = i / 6; |
| u32 c_offs = i / 8; |
| |
| row_cfg = readl(&kbc->row_cfg[r_offs]); |
| col_cfg = readl(&kbc->col_cfg[c_offs]); |
| |
| row_cfg &= ~r_mask; |
| col_cfg &= ~c_mask; |
| |
| if (i < KBC_MAX_ROW) |
| row_cfg |= ((i << 1) | 1) << r_shift; |
| else |
| col_cfg |= (((i - KBC_MAX_ROW) << 1) | 1) << c_shift; |
| |
| writel(row_cfg, &kbc->row_cfg[r_offs]); |
| writel(col_cfg, &kbc->col_cfg[c_offs]); |
| } |
| } |
| |
| static int tegra_kbc_open(void) |
| { |
| struct kbc_tegra *kbc = (struct kbc_tegra *)TEGRA_KBC_BASE; |
| unsigned int scan_time_rows, debounce_cnt, rpt_cnt; |
| u32 val = 0; |
| |
| config_kbc(); |
| |
| /* |
| * The time delay between two consecutive reads of the FIFO is |
| * the sum of the repeat time and the time taken for scanning |
| * the rows. There is an additional delay before the row scanning |
| * starts. The repoll delay is computed in microseconds. |
| */ |
| rpt_cnt = 5 * DIV_ROUND_UP(1000, KBC_CYCLE_IN_USEC); |
| debounce_cnt = 2; |
| scan_time_rows = (KBC_ROW_SCAN_TIME + debounce_cnt) * KBC_MAX_ROW; |
| kbc_repoll_time = KBC_ROW_SCAN_DLY + scan_time_rows + rpt_cnt; |
| kbc_repoll_time = kbc_repoll_time * KBC_CYCLE_IN_USEC; |
| |
| writel(rpt_cnt, &kbc->rpt_dly); |
| |
| val = KBC_DEBOUNCE_CNT_SHIFT(debounce_cnt); |
| val |= KBC_FIFO_TH_CNT_SHIFT(1); /* set fifo interrupt threshold to 1 */ |
| val |= KBC_CONTROL_FIFO_CNT_INT_EN; /* interrupt on FIFO threshold */ |
| val |= KBC_CONTROL_KBC_EN; /* enable */ |
| |
| writel(val, &kbc->control); |
| |
| kbc_init_dly = readl(&kbc->init_dly) * KBC_CYCLE_IN_USEC; |
| kbc_start_time = timer_get_us(); |
| |
| return 0; |
| } |
| |
| void config_kbc_pinmux(void) |
| { |
| enum pmux_pingrp pingrp[] = {PINGRP_KBCA, PINGRP_KBCB, PINGRP_KBCC, |
| PINGRP_KBCD, PINGRP_KBCE, PINGRP_KBCF}; |
| int i; |
| |
| for (i = 0; i < (sizeof(pingrp)/sizeof(pingrp[0])); i++) { |
| pinmux_tristate_disable(pingrp[i]); |
| pinmux_set_func(pingrp[i], PMUX_FUNC_KBC); |
| pinmux_set_pullupdown(pingrp[i], PMUX_PULL_UP); |
| } |
| } |
| |
| int drv_keyboard_init(void) |
| { |
| int error; |
| struct stdio_dev kbddev; |
| char *stdinname; |
| |
| #ifdef CONFIG_OF_CONTROL |
| int node; |
| |
| node = fdt_decode_next_compatible(gd->blob, 0, |
| COMPAT_NVIDIA_TEGRA250_KBC); |
| if (node < 0) |
| return node; |
| if (fdt_decode_kbc(gd->blob, node, &config)) |
| return -1; |
| |
| kbc_plain_keycode = config.plain_keycode; |
| kbc_shift_keycode = config.shift_keycode; |
| kbc_fn_keycode = config.fn_keycode; |
| kbc_ctrl_keycode = config.ctrl_keycode; |
| #else |
| kbc_plain_keycode = board_keyboard_config.plain_keycode; |
| kbc_shift_keycode = board_keyboard_config.shift_keycode; |
| kbc_fn_keycode = board_keyboard_config.fn_keycode; |
| #endif |
| |
| config_kbc_pinmux(); |
| |
| /* |
| * All of the Tegra board use the same clock configuration for now. |
| * This can be moved to the board specific configuration if that |
| * changes. |
| */ |
| clock_enable(PERIPH_ID_KBC); |
| |
| stdinname = getenv("stdin"); |
| memset(&kbddev, 0, sizeof(kbddev)); |
| strcpy(kbddev.name, DEVNAME); |
| kbddev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; |
| kbddev.putc = NULL; |
| kbddev.puts = NULL; |
| kbddev.getc = kbd_getc; |
| kbddev.tstc = kbd_testc; |
| kbddev.start = tegra_kbc_open; |
| |
| error = stdio_register(&kbddev); |
| if (!error) { |
| /* check if this is the standard input device */ |
| if (strcmp(stdinname, DEVNAME) == 0) { |
| /* reassign the console */ |
| if (OVERWRITE_CONSOLE) |
| return 1; |
| |
| error = console_assign(stdin, DEVNAME); |
| if (!error) |
| return 0; |
| else |
| return error; |
| } |
| return 1; |
| } |
| |
| return error; |
| } |