avionic design with actual uboot and tooling
submodule of avionic design uboot bootloader and with included tools to get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
237
u-boot/drivers/input/cros_ec_keyb.c
Normal file
237
u-boot/drivers/input/cros_ec_keyb.c
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Chromium OS Matrix Keyboard
|
||||
*
|
||||
* Copyright (c) 2012 The Chromium OS Authors.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cros_ec.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <input.h>
|
||||
#include <keyboard.h>
|
||||
#include <key_matrix.h>
|
||||
#include <stdio_dev.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
enum {
|
||||
KBC_MAX_KEYS = 8, /* Maximum keys held down at once */
|
||||
KBC_REPEAT_RATE_MS = 30,
|
||||
KBC_REPEAT_DELAY_MS = 240,
|
||||
};
|
||||
|
||||
struct cros_ec_keyb_priv {
|
||||
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 */
|
||||
int ghost_filter; /* 1 to enable ghost filter, else 0 */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check the keyboard controller and return a list of key matrix positions
|
||||
* for which a key is pressed
|
||||
*
|
||||
* @param dev Keyboard device
|
||||
* @param keys List of keys that we have detected
|
||||
* @param max_count Maximum number of keys to return
|
||||
* @param samep Set to true if this scan repeats the last, else false
|
||||
* @return number of pressed keys, 0 for none, -EIO on error
|
||||
*/
|
||||
static int check_for_keys(struct udevice *dev, struct key_matrix_key *keys,
|
||||
int max_count, bool *samep)
|
||||
{
|
||||
struct cros_ec_keyb_priv *priv = dev_get_priv(dev);
|
||||
struct key_matrix_key *key;
|
||||
static struct mbkp_keyscan last_scan;
|
||||
static bool last_scan_valid;
|
||||
struct mbkp_keyscan scan;
|
||||
unsigned int row, col, bit, data;
|
||||
int num_keys;
|
||||
|
||||
if (cros_ec_scan_keyboard(dev->parent, &scan)) {
|
||||
debug("%s: keyboard scan failed\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
*samep = last_scan_valid && !memcmp(&last_scan, &scan, sizeof(scan));
|
||||
|
||||
/*
|
||||
* This is a bit odd. The EC has no way to tell us that it has run
|
||||
* out of key scans. It just returns the same scan over and over
|
||||
* again. So the only way to detect that we have run out is to detect
|
||||
* that this scan is the same as the last.
|
||||
*/
|
||||
last_scan_valid = true;
|
||||
memcpy(&last_scan, &scan, sizeof(last_scan));
|
||||
|
||||
for (col = num_keys = bit = 0; col < priv->matrix.num_cols;
|
||||
col++) {
|
||||
for (row = 0; row < priv->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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
struct udevice *dev = input->dev;
|
||||
struct cros_ec_keyb_priv *priv = dev_get_priv(dev);
|
||||
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;
|
||||
bool same = false;
|
||||
|
||||
/*
|
||||
* 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(dev->parent);
|
||||
if (irq_pending) {
|
||||
num_keys = check_for_keys(dev, keys, KBC_MAX_KEYS,
|
||||
&same);
|
||||
if (num_keys < 0)
|
||||
return 0;
|
||||
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(&priv->matrix, keys,
|
||||
num_keys, keycodes, KBC_MAX_KEYS);
|
||||
sent = input_send_keycodes(input, keycodes, num_keycodes);
|
||||
|
||||
/*
|
||||
* For those ECs without an interrupt, stop scanning when we
|
||||
* see that the scan is the same as last time.
|
||||
*/
|
||||
if ((irq_pending < 0) && same)
|
||||
break;
|
||||
} 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 cros_ec_keyb_priv *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, "keypad,num-rows", 0);
|
||||
config->key_cols = fdtdec_get_int(blob, node, "keypad,num-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->ghost_filter = fdtdec_get_bool(blob, node,
|
||||
"google,needs-ghost-filter");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_ec_kbd_probe(struct udevice *dev)
|
||||
{
|
||||
struct cros_ec_keyb_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;
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node = dev->of_offset;
|
||||
int ret;
|
||||
|
||||
if (cros_ec_keyb_decode_fdt(blob, node, priv))
|
||||
return -1;
|
||||
input_set_delays(input, KBC_REPEAT_DELAY_MS, KBC_REPEAT_RATE_MS);
|
||||
ret = key_matrix_init(&priv->matrix, priv->key_rows, priv->key_cols,
|
||||
priv->ghost_filter);
|
||||
if (ret) {
|
||||
debug("%s: cannot init key matrix\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
ret = key_matrix_decode_fdt(&priv->matrix, gd->fdt_blob, node);
|
||||
if (ret) {
|
||||
debug("%s: Could not decode key matrix from fdt\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
debug("%s: Matrix keyboard %dx%d ready\n", __func__, priv->key_rows,
|
||||
priv->key_cols);
|
||||
|
||||
priv->input = input;
|
||||
input->dev = dev;
|
||||
input_add_tables(input, false);
|
||||
input->read_keys = cros_ec_kbc_check;
|
||||
strcpy(sdev->name, "cros-ec-keyb");
|
||||
|
||||
/* Register the device. cros_ec_init_keyboard() will be called soon */
|
||||
return input_stdio_register(sdev);
|
||||
}
|
||||
|
||||
static const struct keyboard_ops cros_ec_kbd_ops = {
|
||||
};
|
||||
|
||||
static const struct udevice_id cros_ec_kbd_ids[] = {
|
||||
{ .compatible = "google,cros-ec-keyb" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(cros_ec_kbd) = {
|
||||
.name = "cros_ec_kbd",
|
||||
.id = UCLASS_KEYBOARD,
|
||||
.of_match = cros_ec_kbd_ids,
|
||||
.probe = cros_ec_kbd_probe,
|
||||
.ops = &cros_ec_kbd_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct cros_ec_keyb_priv),
|
||||
};
|
||||
Reference in New Issue
Block a user