diff options
-rw-r--r-- | arch/arm/mach-tegra/Kconfig | 1 | ||||
-rw-r--r-- | drivers/input/tegra-kbc.c | 243 | ||||
-rw-r--r-- | include/fdtdec.h | 1 | ||||
-rw-r--r-- | lib/fdtdec.c | 1 |
4 files changed, 112 insertions, 134 deletions
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index a5b7e0d..de2454e 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -12,6 +12,7 @@ config TEGRA_ARMV7_COMMON select DM_I2C select DM_SPI select DM_GPIO + select DM_KEYBOARD choice prompt "Tegra SoC select" diff --git a/drivers/input/tegra-kbc.c b/drivers/input/tegra-kbc.c index 818ed8c..a7137f1 100644 --- a/drivers/input/tegra-kbc.c +++ b/drivers/input/tegra-kbc.c @@ -6,8 +6,10 @@ */ #include <common.h> +#include <dm.h> #include <fdtdec.h> #include <input.h> +#include <keyboard.h> #include <key_matrix.h> #include <stdio_dev.h> #include <tegra-kbc.h> @@ -40,14 +42,13 @@ enum { }; /* keyboard controller config and state */ -static struct keyb { - struct input_config input; /* The input layer */ +struct tegra_kbd_priv { + struct input_config *input; /* The input layer */ struct key_matrix matrix; /* The key matrix layer */ struct kbc_tegra *kbc; /* tegra keyboard controller */ unsigned char inited; /* 1 if keyboard has been inited */ unsigned char first_scan; /* 1 if this is our first key scan */ - unsigned char created; /* 1 if driver has been created */ /* * After init we must wait a short time before polling the keyboard. @@ -58,17 +59,17 @@ static struct keyb { unsigned int start_time_ms; /* Time that we inited (in ms) */ unsigned int last_poll_ms; /* Time we should last polled */ unsigned int next_repeat_ms; /* Next time we repeat a key */ -} config; +}; /** * reads the keyboard fifo for current keypresses * - * @param config Keyboard config + * @param priv Keyboard private data * @param fifo Place to put fifo results * @param max_keycodes Maximum number of key codes to put in the fifo * @return number of items put into fifo */ -static int tegra_kbc_find_keys(struct keyb *config, int *fifo, +static int tegra_kbc_find_keys(struct tegra_kbd_priv *priv, int *fifo, int max_keycodes) { struct key_matrix_key keys[KBC_MAX_KPENT], *key; @@ -78,7 +79,7 @@ static int tegra_kbc_find_keys(struct keyb *config, int *fifo, for (key = keys, i = 0; i < KBC_MAX_KPENT; i++, key++) { /* Get next word */ if (!(i & 3)) - kp_ent = readl(&config->kbc->kp_ent[i / 4]); + kp_ent = readl(&priv->kbc->kp_ent[i / 4]); key->valid = (kp_ent & KBC_KPENT_VALID) != 0; key->row = (kp_ent >> 3) & 0xf; @@ -87,7 +88,7 @@ static int tegra_kbc_find_keys(struct keyb *config, int *fifo, /* Shift to get next entry */ kp_ent >>= 8; } - return key_matrix_decode(&config->matrix, keys, KBC_MAX_KPENT, fifo, + return key_matrix_decode(&priv->matrix, keys, KBC_MAX_KPENT, fifo, max_keycodes); } @@ -106,10 +107,10 @@ static int tegra_kbc_find_keys(struct keyb *config, int *fifo, * Note: if fifo_cnt is 0, we will tell the input layer that no keys are * pressed. * - * @param config Keyboard config + * @param priv Keyboard private data * @param fifo_cnt Number of entries in the keyboard fifo */ -static void process_fifo(struct keyb *config, int fifo_cnt) +static void process_fifo(struct tegra_kbd_priv *priv, int fifo_cnt) { int fifo[KBC_MAX_KPENT]; int cnt = 0; @@ -117,9 +118,9 @@ static void process_fifo(struct keyb *config, int fifo_cnt) /* Always call input_send_keycodes() at least once */ do { if (fifo_cnt) - cnt = tegra_kbc_find_keys(config, fifo, KBC_MAX_KPENT); + cnt = tegra_kbc_find_keys(priv, fifo, KBC_MAX_KPENT); - input_send_keycodes(&config->input, fifo, cnt); + input_send_keycodes(priv->input, fifo, cnt); } while (--fifo_cnt > 0); } @@ -127,24 +128,24 @@ static void process_fifo(struct keyb *config, int fifo_cnt) * Check the keyboard controller and emit ASCII characters for any keys that * are pressed. * - * @param config Keyboard config + * @param priv Keyboard private data */ -static void check_for_keys(struct keyb *config) +static void check_for_keys(struct tegra_kbd_priv *priv) { int fifo_cnt; - if (!config->first_scan && - get_timer(config->last_poll_ms) < KBC_REPEAT_RATE_MS) + if (!priv->first_scan && + get_timer(priv->last_poll_ms) < KBC_REPEAT_RATE_MS) return; - config->last_poll_ms = get_timer(0); - config->first_scan = 0; + priv->last_poll_ms = get_timer(0); + priv->first_scan = 0; /* * Once we get here we know the keyboard has been scanned. So if there * scan waiting for us, we know that nothing is held down. */ - fifo_cnt = (readl(&config->kbc->interrupt) >> 4) & 0xf; - process_fifo(config, fifo_cnt); + fifo_cnt = (readl(&priv->kbc->interrupt) >> 4) & 0xf; + process_fifo(priv, fifo_cnt); } /** @@ -153,22 +154,22 @@ static void check_for_keys(struct keyb *config) * Wkup mode to Continous polling mode and the repoll time. We can * deduct the time that's already elapsed. * - * @param config Keyboard config + * @param priv Keyboard private data */ -static void kbd_wait_for_fifo_init(struct keyb *config) +static void kbd_wait_for_fifo_init(struct tegra_kbd_priv *priv) { - if (!config->inited) { + if (!priv->inited) { unsigned long elapsed_time; long delay_ms; - elapsed_time = get_timer(config->start_time_ms); - delay_ms = config->init_dly_ms - elapsed_time; + elapsed_time = get_timer(priv->start_time_ms); + delay_ms = priv->init_dly_ms - elapsed_time; if (delay_ms > 0) { udelay(delay_ms * 1000); debug("%s: delay %ldms\n", __func__, delay_ms); } - config->inited = 1; + priv->inited = 1; } } @@ -183,38 +184,16 @@ static void kbd_wait_for_fifo_init(struct keyb *config) */ static int tegra_kbc_check(struct input_config *input) { - kbd_wait_for_fifo_init(&config); - check_for_keys(&config); - - return 1; -} + struct tegra_kbd_priv *priv = dev_get_priv(input->dev); -/** - * Test if keys are available to be read - * - * @return 0 if no keys available, 1 if keys are available - */ -static int kbd_tstc(struct stdio_dev *dev) -{ - /* Just get input to do this for us */ - return input_tstc(&config.input); -} + kbd_wait_for_fifo_init(priv); + check_for_keys(priv); -/** - * 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(struct stdio_dev *dev) -{ - /* Just get input to do this for us */ - return input_getc(&config.input); + return 1; } /* configures keyboard GPIO registers to use the rows and columns */ -static void config_kbc_gpio(struct kbc_tegra *kbc) +static void config_kbc_gpio(struct tegra_kbd_priv *priv, struct kbc_tegra *kbc) { int i; @@ -233,10 +212,10 @@ static void config_kbc_gpio(struct kbc_tegra *kbc) row_cfg &= ~r_mask; col_cfg &= ~c_mask; - if (i < config.matrix.num_rows) { + if (i < priv->matrix.num_rows) { row_cfg |= ((i << 1) | 1) << r_shift; } else { - col_cfg |= (((i - config.matrix.num_rows) << 1) | 1) + col_cfg |= (((i - priv->matrix.num_rows) << 1) | 1) << c_shift; } @@ -248,9 +227,9 @@ static void config_kbc_gpio(struct kbc_tegra *kbc) /** * Start up the keyboard device */ -static void tegra_kbc_open(void) +static void tegra_kbc_open(struct tegra_kbd_priv *priv) { - struct kbc_tegra *kbc = config.kbc; + struct kbc_tegra *kbc = priv->kbc; unsigned int scan_period; u32 val; @@ -265,16 +244,32 @@ static void tegra_kbc_open(void) * Before reading from the keyboard we must wait for the init_dly * plus the rpt_delay, plus 2ms for the row scan time. */ - config.init_dly_ms = scan_period * 2 + 2; + priv->init_dly_ms = scan_period * 2 + 2; val = KBC_DEBOUNCE_COUNT << KBC_DEBOUNCE_CNT_SHIFT; val |= 1 << KBC_FIFO_TH_CNT_SHIFT; /* fifo interrupt threshold */ val |= KBC_CONTROL_KBC_EN; /* enable */ writel(val, &kbc->control); - config.start_time_ms = get_timer(0); - config.last_poll_ms = config.next_repeat_ms = get_timer(0); - config.first_scan = 1; + priv->start_time_ms = get_timer(0); + priv->last_poll_ms = get_timer(0); + priv->next_repeat_ms = priv->last_poll_ms; + priv->first_scan = 1; +} + +static int tegra_kbd_start(struct udevice *dev) +{ + struct tegra_kbd_priv *priv = dev_get_priv(dev); + + /* Set up pin mux and enable the clock */ + funcmux_select(PERIPH_ID_KBC, FUNCMUX_DEFAULT); + clock_enable(PERIPH_ID_KBC); + config_kbc_gpio(priv, priv->kbc); + + tegra_kbc_open(priv); + debug("%s: Tegra keyboard ready\n", __func__); + + return 0; } /** @@ -289,89 +284,73 @@ static void tegra_kbc_open(void) * * @return 0 if ok, -ve on error */ -static int init_tegra_keyboard(struct stdio_dev *dev) +static int tegra_kbd_probe(struct udevice *dev) { - /* check if already created */ - if (config.created) - return 0; - -#if CONFIG_IS_ENABLED(OF_CONTROL) - int node; - - node = fdtdec_next_compatible(gd->fdt_blob, 0, - COMPAT_NVIDIA_TEGRA20_KBC); - if (node < 0) { - debug("%s: cannot locate keyboard node\n", __func__); - return node; - } - config.kbc = (struct kbc_tegra *)fdtdec_get_addr(gd->fdt_blob, - node, "reg"); - if ((fdt_addr_t)config.kbc == FDT_ADDR_T_NONE) { + struct tegra_kbd_priv *priv = dev_get_priv(dev); + struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev); + struct stdio_dev *sdev = &uc_priv->sdev; + struct input_config *input = &uc_priv->input; + int node = dev->of_offset; + int ret; + + priv->kbc = (struct kbc_tegra *)dev_get_addr(dev); + if ((fdt_addr_t)priv->kbc == FDT_ADDR_T_NONE) { debug("%s: No keyboard register found\n", __func__); - return -1; + return -EINVAL; } - input_set_delays(&config.input, KBC_REPEAT_DELAY_MS, - KBC_REPEAT_RATE_MS); + input_set_delays(input, KBC_REPEAT_DELAY_MS, KBC_REPEAT_RATE_MS); /* Decode the keyboard matrix information (16 rows, 8 columns) */ - if (key_matrix_init(&config.matrix, 16, 8, 1)) { - debug("%s: Could not init key matrix\n", __func__); - return -1; + ret = key_matrix_init(&priv->matrix, 16, 8, 1); + if (ret) { + debug("%s: Could not init key matrix: %d\n", __func__, ret); + return ret; } - if (key_matrix_decode_fdt(&config.matrix, gd->fdt_blob, node)) { - debug("%s: Could not decode key matrix from fdt\n", __func__); - return -1; + ret = key_matrix_decode_fdt(&priv->matrix, gd->fdt_blob, node); + if (ret) { + debug("%s: Could not decode key matrix from fdt: %d\n", + __func__, ret); + return ret; } - if (config.matrix.fn_keycode) { - if (input_add_table(&config.input, KEY_FN, -1, - config.matrix.fn_keycode, - config.matrix.key_count)) - return -1; + if (priv->matrix.fn_keycode) { + ret = input_add_table(input, KEY_FN, -1, + priv->matrix.fn_keycode, + priv->matrix.key_count); + if (ret) { + debug("%s: input_add_table() failed\n", __func__); + return ret; + } } -#else -#error "Tegra keyboard driver requires FDT definitions" -#endif - - /* Set up pin mux and enable the clock */ - funcmux_select(PERIPH_ID_KBC, FUNCMUX_DEFAULT); - clock_enable(PERIPH_ID_KBC); - config_kbc_gpio(config.kbc); - tegra_kbc_open(); - config.created = 1; - debug("%s: Tegra keyboard ready\n", __func__); + /* Register the device. init_tegra_keyboard() will be called soon */ + priv->input = input; + input->dev = dev; + input->read_keys = tegra_kbc_check; + input_add_tables(input); + strcpy(sdev->name, "tegra-kbc"); + ret = input_stdio_register(sdev); + if (ret) { + debug("%s: input_stdio_register() failed\n", __func__); + return ret; + } return 0; } -int drv_keyboard_init(void) -{ - struct stdio_dev dev; - char *stdinname = getenv("stdin"); - int error; - - if (input_init(&config.input, 0)) { - debug("%s: Cannot set up input\n", __func__); - return -1; - } - config.input.read_keys = tegra_kbc_check; - input_add_tables(input); +static const struct keyboard_ops tegra_kbd_ops = { + .start = tegra_kbd_start, +}; - memset(&dev, '\0', sizeof(dev)); - strcpy(dev.name, "tegra-kbc"); - dev.flags = DEV_FLAGS_INPUT; - dev.getc = kbd_getc; - dev.tstc = kbd_tstc; - dev.start = init_tegra_keyboard; +static const struct udevice_id tegra_kbd_ids[] = { + { .compatible = "nvidia,tegra20-kbc" }, + { } +}; - /* Register the device. init_tegra_keyboard() will be called soon */ - error = input_stdio_register(&dev); - if (error) - return error; -#ifdef CONFIG_CONSOLE_MUX - error = iomux_doenv(stdin, stdinname); - if (error) - return error; -#endif - return 0; -} +U_BOOT_DRIVER(tegra_kbd) = { + .name = "tegra_kbd", + .id = UCLASS_KEYBOARD, + .of_match = tegra_kbd_ids, + .probe = tegra_kbd_probe, + .ops = &tegra_kbd_ops, + .priv_auto_alloc_size = sizeof(struct tegra_kbd_priv), +}; diff --git a/include/fdtdec.h b/include/fdtdec.h index 3a6ff1f..79826d7 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -118,7 +118,6 @@ enum fdt_compat_id { COMPAT_UNKNOWN, COMPAT_NVIDIA_TEGRA20_EMC, /* Tegra20 memory controller */ COMPAT_NVIDIA_TEGRA20_EMC_TABLE, /* Tegra20 memory timing table */ - COMPAT_NVIDIA_TEGRA20_KBC, /* Tegra20 Keyboard */ COMPAT_NVIDIA_TEGRA20_NAND, /* Tegra2 NAND controller */ COMPAT_NVIDIA_TEGRA20_PWM, /* Tegra 2 PWM controller */ COMPAT_NVIDIA_TEGRA124_DC, /* Tegra 124 Display controller */ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index f1849bc..e0e6bb4 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -24,7 +24,6 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(UNKNOWN, "<none>"), COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"), COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"), - COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"), COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"), COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"), COMPAT(NVIDIA_TEGRA124_DC, "nvidia,tegra124-dc"), |