Hi Hung-ying, On Mon, Mar 18, 2013 at 9:22 AM, Hung-ying Tyan <ty...@chromium.org> wrote: > This patch adds the driver for keyboard that's controlled by ChromeOS EC. > > Signed-off-by: Randall Spangler <rspang...@chromium.org> > Signed-off-by: Simon Glass <s...@chromium.org> > Signed-off-by: Vincent Palatin <vpala...@chromium.org> > Signed-off-by: Hung-ying Tyan <ty...@chromium.org> > > --- > Changes in v2: > - Wrapped lines to comply with the 80-char rule. > > README | 5 + > drivers/input/Makefile | 1 + > drivers/input/cros_ec_keyb.c | 264 > +++++++++++++++++++++++++++++++++++++++++++ > include/fdtdec.h | 1 + > lib/fdtdec.c | 1 + > 5 files changed, 272 insertions(+) > create mode 100644 drivers/input/cros_ec_keyb.c > > diff --git a/README b/README > index 42544ce..769d1bf 100644 > --- a/README > +++ b/README > @@ -1371,6 +1371,11 @@ CBFS (Coreboot Filesystem) support > Export function i8042_kbd_init, i8042_tstc and i8042_getc > for cfb_console. Supports cursor blinking. > > + CONFIG_CROS_EC_KEYB > + Enables a Chrome OS keyboard using the CROS_EC interface. > + This uses CROS_EC to communicate with a second microcontroller > + which provides key scans on request. > + > - Video support: > CONFIG_VIDEO > > diff --git a/drivers/input/Makefile b/drivers/input/Makefile > index 0805e86..4331190 100644 > --- a/drivers/input/Makefile > +++ b/drivers/input/Makefile > @@ -27,6 +27,7 @@ LIB := $(obj)libinput.o > > COBJS-$(CONFIG_I8042_KBD) += i8042.o > COBJS-$(CONFIG_TEGRA_KEYBOARD) += tegra-kbc.o > +COBJS-$(CONFIG_CROS_EC_KEYB) += cros_ec_keyb.o > ifdef CONFIG_PS2KBD > COBJS-y += keyboard.o pc_keyb.o > COBJS-$(CONFIG_PS2MULT) += ps2mult.o ps2ser.o > diff --git a/drivers/input/cros_ec_keyb.c b/drivers/input/cros_ec_keyb.c > new file mode 100644 > index 0000000..21fab15 > --- /dev/null > +++ b/drivers/input/cros_ec_keyb.c > @@ -0,0 +1,264 @@ > +/* > + * Chromium OS Matrix Keyboard > + * > + * Copyright (c) 2012 The Chromium OS Authors. > + * 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 <fdtdec.h> > +#include <input.h> > +#include <key_matrix.h> > +#include <cros_ec.h>
Please put this after common.h so it is in alphabetical order. > +#include <stdio_dev.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +enum { > + KBC_MAX_KEYS = 8, /* Maximum keys held down at once */ > +}; > + > +static struct keyb { > + struct cros_ec_dev *dev; /* The CROS_EC device */ > + struct input_config input; /* The input layer */ > + struct key_matrix matrix; /* The key matrix layer */ > + int key_rows; /* Number of keyboard rows */ > + int key_cols; /* Number of keyboard columns */ > + unsigned int repeat_delay_ms; /* Time before autorepeat starts */ > + unsigned int repeat_rate_ms; /* Autorepeat rate in ms */ > + int ghost_filter; /* 1 to enable ghost filter, else 0 */ > + int inited; /* 1 if keyboard is ready */ > +} config; > + > + > +/** > + * Check the keyboard controller and return a list of key matrix positions > + * for which a key is pressed > + * > + * @param config Keyboard config > + * @param keys List of keys that we have detected > + * @param max_count Maximum number of keys to return > + * @return number of pressed keys, 0 for none > + */ > +static int check_for_keys(struct keyb *config, > + struct key_matrix_key *keys, int max_count) > +{ > + struct key_matrix_key *key; > + struct mbkp_keyscan scan; > + unsigned int row, col, bit, data; > + int num_keys; > + > + if (cros_ec_scan_keyboard(config->dev, &scan)) { > + debug("%s: keyboard scan failed\n", __func__); > + return -1; > + } > + > + /* TODO(sjg@chromium,org): Should perhaps optimize this algorithm */ I think we can remove this TODO now. > + for (col = num_keys = bit = 0; col < config->matrix.num_cols; > + col++) { > + for (row = 0; row < config->matrix.num_rows; row++) { > + unsigned int mask = 1 << (bit & 7); > + > + data = scan.data[bit / 8]; > + if ((data & mask) && num_keys < max_count) { > + key = keys + num_keys++; > + key->row = row; > + key->col = col; > + key->valid = 1; > + } > + bit++; > + } > + } > + > + return num_keys; > +} > + > +/** > + * 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 config.inited ? input_tstc(&config.input) : 0; > +} > + > +/** > + * Read a 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 config.inited ? input_getc(&config.input) : 0; > +} > + > +/** > + * Check the 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 cros_ec_kbc_check(struct input_config *input) > +{ > + static struct key_matrix_key last_keys[KBC_MAX_KEYS]; > + static int last_num_keys; > + struct key_matrix_key keys[KBC_MAX_KEYS]; > + int keycodes[KBC_MAX_KEYS]; > + int num_keys, num_keycodes; > + int irq_pending, sent; > + > + /* > + * crosbug.com/p/13864 You can remove this bug reference as it is not relevant. > + * > + * Loop until the EC has no more keyscan records, or we have > + * received at least one character. This means we know that tstc() > + * will always return non-zero if keys have been pressed. > + * > + * Without this loop, a key release (which generates no new ascii > + * characters) will cause us to exit this function, and just tstc() > + * may return 0 before all keys have been read from the EC. > + */ > + do { > + irq_pending = cros_ec_interrupt_pending(config.dev); > + if (irq_pending) { > + num_keys = check_for_keys(&config, keys, > KBC_MAX_KEYS); > + last_num_keys = num_keys; > + memcpy(last_keys, keys, sizeof(keys)); > + } else { > + /* > + * EC doesn't want to be asked, so use keys from last > + * time. > + */ > + num_keys = last_num_keys; > + memcpy(keys, last_keys, sizeof(keys)); > + } > + > + if (num_keys < 0) > + return -1; > + num_keycodes = key_matrix_decode(&config.matrix, keys, > + num_keys, keycodes, KBC_MAX_KEYS); > + sent = input_send_keycodes(input, keycodes, num_keycodes); > + } while (irq_pending && !sent); > + > + return 1; > +} > + > +/** > + * Decode MBKP keyboard details from the device tree > + * > + * @param blob Device tree blob > + * @param node Node to decode from > + * @param config Configuration data read from fdt > + * @return 0 if ok, -1 on error > + */ > +static int cros_ec_keyb_decode_fdt(const void *blob, int node, > + struct keyb *config) > +{ > + /* > + * Get keyboard rows and columns - at present we are limited to > + * 8 columns by the protocol (one byte per row scan) > + */ > + config->key_rows = fdtdec_get_int(blob, node, "google,key-rows", 0); > + config->key_cols = fdtdec_get_int(blob, node, "google,key-columns", > 0); > + if (!config->key_rows || !config->key_cols || > + config->key_rows * config->key_cols / 8 > + > CROS_EC_KEYSCAN_COLS) { > + debug("%s: Invalid key matrix size %d x %d\n", __func__, > + config->key_rows, config->key_cols); > + return -1; > + } > + config->repeat_delay_ms = fdtdec_get_int(blob, node, > + "google,repeat-delay-ms", 0); > + config->repeat_rate_ms = fdtdec_get_int(blob, node, > + "google,repeat-rate-ms", 0); > + config->ghost_filter = fdtdec_get_bool(blob, node, > + "google,ghost-filter"); > + return 0; > +} > + > +/** > + * Set up the keyboard. This is called by the stdio device handler. > + * > + * We want to do this init when the keyboard is actually used rather than > + * at start-up, since keyboard input may not currently be selected. > + * > + * @return 0 if ok, -1 on error > + */ > +static int cros_ec_init_keyboard(void) > +{ > + const void *blob = gd->fdt_blob; > + int node; > + > + config.dev = board_get_cros_ec_dev(); > + if (!config.dev) { > + debug("%s: no cros_ec device: cannot init keyboard\n", > + __func__); > + return -1; > + } > + node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC_KEYB); > + if (node < 0) { > + debug("%s: Node not found\n", __func__); > + return -1; > + } > + if (cros_ec_keyb_decode_fdt(blob, node, &config)) > + return -1; > + input_set_delays(&config.input, config.repeat_delay_ms, > + config.repeat_rate_ms); > + if (key_matrix_init(&config.matrix, config.key_rows, > + config.key_cols, config.ghost_filter)) { > + debug("%s: cannot init key matrix\n", __func__); > + return -1; > + } > + if (key_matrix_decode_fdt(&config.matrix, gd->fdt_blob, node)) { > + debug("%s: Could not decode key matrix from fdt\n", __func__); > + return -1; > + } > + config.inited = 1; > + debug("%s: Matrix keyboard %dx%d ready\n", __func__, config.key_rows, > + config.key_cols); > + > + return 0; > +} > + > +int drv_keyboard_init(void) > +{ > + struct stdio_dev dev; > + > + if (input_init(&config.input, 0)) { > + debug("%s: Cannot set up input\n", __func__); > + return -1; > + } > + config.input.read_keys = cros_ec_kbc_check; > + > + memset(&dev, '\0', sizeof(dev)); > + strcpy(dev.name, "cros-ec-keyb"); > + dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; > + dev.getc = kbd_getc; > + dev.tstc = kbd_tstc; > + dev.start = cros_ec_init_keyboard; > + > + /* Register the device. cros_ec_init_keyboard() will be called soon */ > + return input_stdio_register(&dev); > +} > diff --git a/include/fdtdec.h b/include/fdtdec.h > index 0f4bbaa..0eaabe1 100644 > --- a/include/fdtdec.h > +++ b/include/fdtdec.h > @@ -79,6 +79,7 @@ enum fdt_compat_id { > COMPAT_WOLFSON_WM8994_CODEC, /* Wolfson WM8994 Sound Codec */ > COMPAT_SAMSUNG_EXYNOS_SPI, /* Exynos SPI */ > COMPAT_GOOGLE_CROS_EC, /* Google CROS_EC Protocol */ > + COMPAT_GOOGLE_CROS_EC_KEYB, /* Google CROS_EC Keyboard */ > COMPAT_SAMSUNG_EXYNOS_EHCI, /* Exynos EHCI controller */ > COMPAT_SAMSUNG_EXYNOS_USB_PHY, /* Exynos phy controller for usb2.0 */ > COMPAT_MAXIM_MAX77686_PMIC, /* MAX77686 PMIC */ > diff --git a/lib/fdtdec.c b/lib/fdtdec.c > index 24cd6f9..df60bee 100644 > --- a/lib/fdtdec.c > +++ b/lib/fdtdec.c > @@ -54,6 +54,7 @@ static const char * const compat_names[COMPAT_COUNT] = { > COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"), > COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"), > COMPAT(GOOGLE_CROS_EC, "google,cros-ec"), > + COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"), > COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"), > COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"), > COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"), > -- > 1.8.1.3 > Otherwise looks good to me. Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot