cros_ec: Support systems with no EC interrupt
authorSimon Glass <sjg@chromium.org>
Thu, 27 Feb 2014 20:26:05 +0000 (13:26 -0700)
committerSimon Glass <sjg@chromium.org>
Tue, 18 Mar 2014 02:05:46 +0000 (20:05 -0600)
Some systems do not have an EC interrupt. Rather than assuming that the
interrupt is always present, and hanging forever waiting for more input,
handle the missing interrupt. This works by reading key scans only until
we get an identical one. This means the EC keyscan FIFO is empty.

Tested-by: Che-Liang Chiou <clchiou@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
drivers/input/cros_ec_keyb.c

index e8dac237a995c0f492d3299921cc6f4fbbaf0f80..a2501e02063e0abb4689c1d1994696751875c4d9 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <common.h>
 #include <cros_ec.h>
+#include <errno.h>
 #include <fdtdec.h>
 #include <input.h>
 #include <key_matrix.h>
@@ -39,20 +40,34 @@ static struct keyb {
  * @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
+ * @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 keyb *config,
-                          struct key_matrix_key *keys, int max_count)
+                          struct key_matrix_key *keys, int max_count,
+                          bool *samep)
 {
        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(config->dev, &scan)) {
                debug("%s: keyboard scan failed\n", __func__);
-               return -1;
+               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 < config->matrix.num_cols;
                        col++) {
@@ -112,6 +127,7 @@ int cros_ec_kbc_check(struct input_config *input)
        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
@@ -125,7 +141,10 @@ int cros_ec_kbc_check(struct input_config *input)
        do {
                irq_pending = cros_ec_interrupt_pending(config.dev);
                if (irq_pending) {
-                       num_keys = check_for_keys(&config, keys, KBC_MAX_KEYS);
+                       num_keys = check_for_keys(&config, keys, KBC_MAX_KEYS,
+                                                 &same);
+                       if (num_keys < 0)
+                               return 0;
                        last_num_keys = num_keys;
                        memcpy(last_keys, keys, sizeof(keys));
                } else {
@@ -142,6 +161,13 @@ int cros_ec_kbc_check(struct input_config *input)
                num_keycodes = key_matrix_decode(&config.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;