summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2015-11-11 10:05:46 -0700
committerSimon Glass <sjg@chromium.org>2015-11-19 20:13:41 -0700
commit011d89d6066592a67253df81905ace358968dacc (patch)
tree235e6b27e160d8f030c81a36dc185ca628b6aad4 /drivers/input
parentdcbf825714e27a4c39edcc36c7623b37bc40040a (diff)
i8042: Handle a duplicate power-on-reset response
Sometimes we seem to get 0xaa twice which causes the config read to fail. This causes chromebook_link to fail to set up the keyboard. Add a check for this and read the config again when detected. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/i8042.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/drivers/input/i8042.c b/drivers/input/i8042.c
index e5e2926670..661d7fd86c 100644
--- a/drivers/input/i8042.c
+++ b/drivers/input/i8042.c
@@ -15,13 +15,20 @@
#include <keyboard.h>
#include <asm/io.h>
+DECLARE_GLOBAL_DATA_PTR;
+
/* defines */
#define in8(p) inb(p)
#define out8(p, v) outb(v, p)
+enum {
+ QUIRK_DUP_POR = 1 << 0,
+};
+
/* locals */
struct i8042_kbd_priv {
bool extended; /* true if an extended keycode is expected next */
+ int quirks; /* quirks that we support */
};
static unsigned char ext_key_map[] = {
@@ -113,7 +120,7 @@ static int kbd_cmd_write(int cmd, int data)
return kbd_write(I8042_DATA_REG, data);
}
-static int kbd_reset(void)
+static int kbd_reset(int quirk)
{
int config;
@@ -132,6 +139,10 @@ static int kbd_reset(void)
if (config == -1)
goto err;
+ /* Sometimes get a second byte */
+ else if ((quirk & QUIRK_DUP_POR) && config == KBD_POR)
+ config = kbd_cmd_read(CMD_RD_CONFIG);
+
config |= CONFIG_AT_TRANS;
config &= ~(CONFIG_KIRQ_EN | CONFIG_MIRQ_EN);
if (kbd_cmd_write(CMD_WR_CONFIG, config))
@@ -246,6 +257,7 @@ static int i8042_kbd_check(struct input_config *input)
static int i8042_start(struct udevice *dev)
{
struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct i8042_kbd_priv *priv = dev_get_priv(dev);
struct input_config *input = &uc_priv->input;
int keymap, try;
char *penv;
@@ -264,7 +276,7 @@ static int i8042_start(struct udevice *dev)
keymap = KBD_GER;
}
- for (try = 0; kbd_reset() != 0; try++) {
+ for (try = 0; kbd_reset(priv->quirks) != 0; try++) {
if (try >= KBD_RESET_TRIES)
return -1;
}
@@ -294,10 +306,15 @@ static int i8042_start(struct udevice *dev)
static int i8042_kbd_probe(struct udevice *dev)
{
struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct i8042_kbd_priv *priv = dev_get_priv(dev);
struct stdio_dev *sdev = &uc_priv->sdev;
struct input_config *input = &uc_priv->input;
int ret;
+ if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset,
+ "intel,duplicate-por"))
+ priv->quirks |= QUIRK_DUP_POR;
+
/* Register the device. i8042_start() will be called soon */
input->dev = dev;
input->read_keys = i8042_kbd_check;