summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2014-03-14 09:27:31 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-03-25 22:25:58 +0000
commit311abbd8896a927b7c4a4b2a226060a5ed64b044 (patch)
tree6022002aa844376f925a0c4eaa3748dee40046e9
parentb0b57a581e8ed3e818a195f7d6f9695ed90287ee (diff)
downloadchrome-ec-311abbd8896a927b7c4a4b2a226060a5ed64b044.tar.gz
rambi: glimmer: Disable key scanning in suspend when lid is open
Added ability to disable the keyboard to wake from suspend when the lid is outside a certain angle range. This has been added to glimmer by defining CONFIG_LID_ANGLE_KEY_SCAN in its board.h. Also modified the lid angle calculation to include a reliability flag which can be used to tell when the hinge aligns too closely with gravity and the lid angle value is unreliable. BUG=none BRANCH=rambi TEST=Tested on a glimmer: In S3, verified that when the lid is open past ~180 deg, the keyboard does not wake the machine. Also verified that if you align hinge with gravity, the keyboard enabled/disabled status remains the same (since we can't actually trust the lid angle value). Change-Id: If1a1592d259902d38941936961854b81b3a75b95 Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/190061
-rw-r--r--board/glimmer/board.h13
-rw-r--r--common/build.mk1
-rw-r--r--common/console_output.c1
-rw-r--r--common/keyboard_scan.c15
-rw-r--r--common/lid_angle.c81
-rw-r--r--common/motion_sense.c55
-rw-r--r--include/config.h11
-rw-r--r--include/console.h1
-rw-r--r--include/keyboard_scan.h5
-rw-r--r--include/lid_angle.h20
-rw-r--r--include/motion_sense.h3
-rw-r--r--test/motion_sense.c6
12 files changed, 193 insertions, 19 deletions
diff --git a/board/glimmer/board.h b/board/glimmer/board.h
index 0354674518..c134b50f80 100644
--- a/board/glimmer/board.h
+++ b/board/glimmer/board.h
@@ -34,6 +34,7 @@
#define CONFIG_KEYBOARD_IRQ_GPIO GPIO_KBD_IRQ_L
#define CONFIG_KEYBOARD_PROTOCOL_8042
#define CONFIG_LED_COMMON
+#define CONFIG_LID_ANGLE_KEY_SCAN
#define CONFIG_LOW_POWER_IDLE
#undef CONFIG_PECI
#define CONFIG_POWER_BUTTON
@@ -78,6 +79,18 @@
#define WIRELESS_GPIO_WWAN GPIO_PP3300_LTE_EN
#define WIRELESS_GPIO_WLAN_POWER GPIO_PP3300_WLAN_EN
+/*
+ * Macros to be used in suspend to determine the state of key scanning
+ * based on measured lid angle. Note that the angle input is bound [-180, 180]
+ * where 0 degrees is lid closed/lid fully open. Also note that the key scan
+ * enable state will only change if recent readings are all within range,
+ * therefore it is recommended to leave a deadband where the lid angle doesn't
+ * fit into either range. Also note, if lid is closed, key scanning is
+ * automatically disabled.
+ */
+#define LID_IN_RANGE_TO_ACCEPT_KEYS(ang) ((ang) >= 15 || (ang) <= -173)
+#define LID_IN_RANGE_TO_IGNORE_KEYS(ang) ((ang) <= 12 && (ang) >= -170)
+
/* GPIO signal definitions. */
enum gpio_signal {
/* Inputs with interrupt handlers are first for efficiency */
diff --git a/common/build.mk b/common/build.mk
index 921a07f20c..e4695804b7 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -45,6 +45,7 @@ common-$(CONFIG_KEYBOARD_PROTOCOL_8042)+=keyboard_8042.o
common-$(CONFIG_KEYBOARD_PROTOCOL_MKBP)+=keyboard_mkbp.o
common-$(CONFIG_KEYBOARD_TEST)+=keyboard_test.o
common-$(CONFIG_LED_COMMON)+=led_common.o
+common-$(CONFIG_LID_ANGLE_KEY_SCAN)+=lid_angle.o
common-$(CONFIG_LID_SWITCH)+=lid_switch.o
common-$(CONFIG_LPC)+=port80.o
common-$(CONFIG_ONEWIRE)+=onewire.o
diff --git a/common/console_output.c b/common/console_output.c
index b9db75c7fd..2b52da66cf 100644
--- a/common/console_output.c
+++ b/common/console_output.c
@@ -43,6 +43,7 @@ static const char * const channel_names[] = {
"i2c",
"keyboard",
"keyscan",
+ "lidangle",
"lightbar",
"lpc",
"motionsense",
diff --git a/common/keyboard_scan.c b/common/keyboard_scan.c
index 8af50de209..da918bbc8b 100644
--- a/common/keyboard_scan.c
+++ b/common/keyboard_scan.c
@@ -93,7 +93,7 @@ static int enable_scanning = 1; /* Must init to 1 for scanning at boot */
/* Constantly incrementing counter of the number of times we polled */
static volatile int kbd_polls;
-static int is_scanning_enabled(void)
+int keyboard_scan_is_enabled(void)
{
#ifdef CONFIG_LID_SWITCH
/* Scanning is never enabled when lid is closed */
@@ -201,7 +201,7 @@ static int read_matrix(uint8_t *state)
for (c = 0; c < KEYBOARD_COLS; c++) {
/*
* Stop if scanning becomes disabled. Check enable_cscanning
- * instead of is_scanning_enabled() so that we can scan the
+ * instead of keyboard_scan_is_enabled() so that we can scan the
* matrix at boot time before the lid switch is readable.
*/
if (!enable_scanning)
@@ -404,7 +404,7 @@ static int check_keys_changed(uint8_t *state)
#ifdef CONFIG_KEYBOARD_PROTOCOL_8042
/* Inform keyboard module if scanning is enabled */
- if (is_scanning_enabled())
+ if (keyboard_scan_is_enabled())
keyboard_state_changed(i, c, new_mask ? 1 : 0);
#endif
}
@@ -567,7 +567,7 @@ void keyboard_scan_task(void)
while (1) {
/* Enable all outputs */
CPRINTF("[%T KB wait]\n");
- if (is_scanning_enabled())
+ if (keyboard_scan_is_enabled())
keyboard_raw_drive_column(KEYBOARD_COLUMN_ALL);
keyboard_raw_enable_interrupt(1);
@@ -579,9 +579,10 @@ void keyboard_scan_task(void)
* user pressing a key and enable_interrupt()
* starting to pay attention to edges.
*/
- if (!keyboard_raw_read_rows() || !is_scanning_enabled())
+ if (!keyboard_raw_read_rows() ||
+ !keyboard_scan_is_enabled())
task_wait_event(-1);
- } while (!is_scanning_enabled());
+ } while (!keyboard_scan_is_enabled());
/* Enter polling mode */
CPRINTF("[%T KB poll]\n");
@@ -589,7 +590,7 @@ void keyboard_scan_task(void)
keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE);
/* Busy polling keyboard state. */
- while (is_scanning_enabled()) {
+ while (keyboard_scan_is_enabled()) {
start = get_time();
/* Check for keys down */
diff --git a/common/lid_angle.c b/common/lid_angle.c
new file mode 100644
index 0000000000..e7a3139ebb
--- /dev/null
+++ b/common/lid_angle.c
@@ -0,0 +1,81 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Lid angle module for Chrome EC */
+
+#include "chipset.h"
+#include "common.h"
+#include "console.h"
+#include "keyboard_scan.h"
+#include "lid_angle.h"
+#include "lid_switch.h"
+#include "motion_sense.h"
+
+/* Console output macros */
+#define CPUTS(outstr) cputs(CC_LIDANGLE, outstr)
+#define CPRINTF(format, args...) cprintf(CC_LIDANGLE, format, ## args)
+
+/*
+ * Define the number of previous lid angle measurements to keep for determining
+ * whether to enable or disable key scanning. Note, that in order to change
+ * the state of key scanning, all stored measurements of the lid angle buffer
+ * must be in the specified range.
+ */
+#define KEY_SCAN_LID_ANGLE_BUFFER_SIZE 4
+
+void lidangle_keyscan_update(float lid_ang)
+{
+ static float lidangle_buffer[KEY_SCAN_LID_ANGLE_BUFFER_SIZE];
+ static int index;
+
+ int i;
+ int keys_accept = 1, keys_ignore = 1;
+
+ /* Record most recent lid angle in circular buffer. */
+ lidangle_buffer[index] = lid_ang;
+ index = (index == KEY_SCAN_LID_ANGLE_BUFFER_SIZE-1) ? 0 : index+1;
+
+#ifdef CONFIG_LID_SWITCH
+ /*
+ * If lid is closed, don't need to check if keyboard scanning should
+ * be enabled.
+ */
+ if (!lid_is_open())
+ return;
+#endif
+
+ if (chipset_in_state(CHIPSET_STATE_SUSPEND)) {
+ for (i = 0; i < KEY_SCAN_LID_ANGLE_BUFFER_SIZE; i++) {
+ /*
+ * If any lid angle samples are unreliable, then
+ * don't change keyboard scanning state.
+ */
+ if (lidangle_buffer[i] == LID_ANGLE_UNRELIABLE)
+ return;
+
+ /*
+ * Force all elements of the lid angle buffer to be
+ * in range of one of the conditions in order to change
+ * to the corresponding key scanning state.
+ */
+ if (!LID_IN_RANGE_TO_ACCEPT_KEYS(lidangle_buffer[i]))
+ keys_accept = 0;
+ if (!LID_IN_RANGE_TO_IGNORE_KEYS(lidangle_buffer[i]))
+ keys_ignore = 0;
+ }
+
+ /* Enable or disable keyboard scanning if necessary. */
+ if (keys_accept && !keyboard_scan_is_enabled()) {
+ CPRINTF("[%T Enabling keyboard scan, lid ang at %d]\n",
+ (int)lidangle_buffer[index]);
+ keyboard_scan_enable(1);
+ } else if (keys_ignore && !keys_accept &&
+ keyboard_scan_is_enabled()) {
+ CPRINTF("[%T Disabling keyboard scan, lid ang at %d]\n",
+ (int)lidangle_buffer[index]);
+ keyboard_scan_enable(0);
+ }
+ }
+}
diff --git a/common/motion_sense.c b/common/motion_sense.c
index 651215ef34..5dad6db1cf 100644
--- a/common/motion_sense.c
+++ b/common/motion_sense.c
@@ -10,6 +10,7 @@
#include "console.h"
#include "hooks.h"
#include "host_command.h"
+#include "lid_angle.h"
#include "math_util.h"
#include "motion_sense.h"
#include "timer.h"
@@ -27,11 +28,20 @@
static vector_3_t acc_lid_raw, acc_lid, acc_base;
static vector_3_t acc_lid_host, acc_base_host;
static float lid_angle_deg;
+static int lid_angle_is_reliable;
/* Accelerometer polling intervals based on chipset state. */
#define ACCEL_INTERVAL_AP_ON_MS 10
#define ACCEL_INTERVAL_AP_SUSPEND_MS 100
+/*
+ * Angle threshold for how close the hinge aligns with gravity before
+ * considering the lid angle calculation unreliable. For computational
+ * efficiency, value is given unit-less, so if you want the threshold to be
+ * at 15 degrees, the value would be cos(15 deg) = 0.96593.
+ */
+#define HINGE_ALIGNED_WITH_GRAVITY_THRESHOLD 0.96593F
+
/* Sampling interval for measuring acceleration and calculating lid angle. */
static int accel_interval_ms = ACCEL_INTERVAL_AP_SUSPEND_MS;
@@ -50,12 +60,20 @@ const struct accel_orientation * const p_acc_orient = &acc_orient;
/**
* Calculate the lid angle using two acceleration vectors, one recorded in
* the base and one in the lid.
+ *
+ * @param base Base accel vector
+ * @param lid Lid accel vector
+ * @param lid_angle Pointer to location to store lid angle result
+ *
+ * @return flag representing if resulting lid angle calculation is reliable.
*/
-static float calculate_lid_angle(vector_3_t base, vector_3_t lid)
+static int calculate_lid_angle(vector_3_t base, vector_3_t lid,
+ float *lid_angle)
{
vector_3_t v;
float ang_lid_to_base, ang_lid_90, ang_lid_270;
float lid_to_base, base_to_hinge;
+ int reliable = 1;
/*
* The angle between lid and base is:
@@ -66,11 +84,21 @@ static float calculate_lid_angle(vector_3_t base, vector_3_t lid)
*/
lid_to_base = cosine_of_angle_diff(base, lid);
base_to_hinge = cosine_of_angle_diff(base, p_acc_orient->hinge_axis);
+
+ /*
+ * If hinge aligns too closely with gravity, then result may be
+ * unreliable.
+ */
+ if (ABS(base_to_hinge) > HINGE_ALIGNED_WITH_GRAVITY_THRESHOLD)
+ reliable = 0;
+
base_to_hinge = SQ(base_to_hinge);
/* Check divide by 0. */
- if (ABS(1.0F - base_to_hinge) < 0.01F)
- return 0.0;
+ if (ABS(1.0F - base_to_hinge) < 0.01F) {
+ *lid_angle = 0.0;
+ return 0;
+ }
ang_lid_to_base = arc_cos(
(lid_to_base - base_to_hinge) / (1 - base_to_hinge));
@@ -101,12 +129,16 @@ static float calculate_lid_angle(vector_3_t base, vector_3_t lid)
if (ang_lid_270 > ang_lid_90)
ang_lid_to_base = -ang_lid_to_base;
- return ang_lid_to_base;
+ *lid_angle = ang_lid_to_base;
+ return reliable;
}
int motion_get_lid_angle(void)
{
- return (int)lid_angle_deg;
+ if (lid_angle_is_reliable)
+ return (int)lid_angle_deg;
+ else
+ return (int)LID_ANGLE_UNRELIABLE;
}
#ifdef CONFIG_ACCEL_CALIBRATE
@@ -178,7 +210,8 @@ void motion_sense_task(void)
rotate(acc_lid_raw, &p_acc_orient->rot_align, &acc_lid);
/* Calculate angle of lid. */
- lid_angle_deg = calculate_lid_angle(acc_base, acc_lid);
+ lid_angle_is_reliable = calculate_lid_angle(acc_base, acc_lid,
+ &lid_angle_deg);
/* TODO(crosbug.com/p/25597): Add filter to smooth lid angle. */
@@ -201,7 +234,7 @@ void motion_sense_task(void)
* Copy sensor data to shared memory. Note that this code
* assumes little endian, which is what the host expects.
*/
- lpc_data[0] = (int)lid_angle_deg;
+ lpc_data[0] = motion_get_lid_angle();
lpc_data[1] = acc_base_host[X];
lpc_data[2] = acc_base_host[Y];
lpc_data[3] = acc_base_host[Z];
@@ -217,14 +250,18 @@ void motion_sense_task(void)
EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK;
*lpc_status = EC_MEMMAP_ACC_STATUS_PRESENCE_BIT | sample_id;
+#ifdef CONFIG_LID_ANGLE_KEY_SCAN
+ lidangle_keyscan_update(motion_get_lid_angle());
+#endif
#ifdef CONFIG_CMD_LID_ANGLE
if (accel_disp) {
CPRINTF("[%T ACC base=%-5d, %-5d, %-5d lid=%-5d, "
- "%-5d, %-5d a=%-6.1d]\n",
+ "%-5d, %-5d a=%-6.1d r=%d]\n",
acc_base[X], acc_base[Y], acc_base[Z],
acc_lid[X], acc_lid[Y], acc_lid[Z],
- (int)(10*lid_angle_deg));
+ (int)(10*lid_angle_deg),
+ lid_angle_is_reliable);
}
#endif
diff --git a/include/config.h b/include/config.h
index aed9085202..048033d793 100644
--- a/include/config.h
+++ b/include/config.h
@@ -534,6 +534,17 @@
#undef CONFIG_LED_DRIVER_LP5562 /* LP5562, on I2C interface */
/*
+ * Allows using the lid angle measurement to determine if key scanning should
+ * be enabled or disabled when chipset is suspended.
+ *
+ * Any board that defines this must also define two macros:
+ * LID_IN_RANGE_TO_ACCEPT_KEYS(angle), LID_IN_RANGE_TO_IGNORE_KEYS(angle).
+ * These macros should return true if the given angle argument is in range
+ * to accept or ignore key presses.
+ */
+#undef CONFIG_LID_ANGLE_KEY_SCAN
+
+/*
* Compile lid switch support.
*
* This is enabled by default because all boards other than reference boards
diff --git a/include/console.h b/include/console.h
index 8106e54f56..a6cce1fa8c 100644
--- a/include/console.h
+++ b/include/console.h
@@ -39,6 +39,7 @@ enum console_channel {
CC_I2C,
CC_KEYBOARD,
CC_KEYSCAN,
+ CC_LIDANGLE,
CC_LIGHTBAR,
CC_LPC,
CC_MOTION_SENSE,
diff --git a/include/keyboard_scan.h b/include/keyboard_scan.h
index bc956cc685..8359cbd174 100644
--- a/include/keyboard_scan.h
+++ b/include/keyboard_scan.h
@@ -84,6 +84,11 @@ void keyboard_scan_enable(int enable);
static inline void keyboard_scan_enable(int enable) { }
#endif
+/**
+ * Returns if keyboard matrix scanning is enabled/disabled.
+ */
+int keyboard_scan_is_enabled(void);
+
#ifdef CONFIG_KEYBOARD_SUPPRESS_NOISE
/**
* Indicate to audio codec that a key has been pressed.
diff --git a/include/lid_angle.h b/include/lid_angle.h
new file mode 100644
index 0000000000..bd60b90907
--- /dev/null
+++ b/include/lid_angle.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Lid angle module for Chrome EC */
+
+#ifndef __CROS_EC_LID_ANGLE_H
+#define __CROS_EC_LID_ANGLE_H
+
+/**
+ * Update the lid angle module with the most recent lid angle calculation. Then
+ * use the lid angle history to enable/disable keyboard scanning when chipset
+ * is suspended.
+ *
+ * @lid_ang Lid angle.
+ */
+void lidangle_keyscan_update(float lid_ang);
+
+#endif /* __CROS_EC_LID_ANGLE_H */
diff --git a/include/motion_sense.h b/include/motion_sense.h
index 08aefbcc0b..d0c2774254 100644
--- a/include/motion_sense.h
+++ b/include/motion_sense.h
@@ -11,6 +11,9 @@
#include "gpio.h"
#include "math_util.h"
+/* Anything outside of lid angle range [-180, 180] should work. */
+#define LID_ANGLE_UNRELIABLE 500.0F
+
/**
* This structure defines all of the data needed to specify the orientation
* of the base and lid accelerometers in order to calculate the lid angle.
diff --git a/test/motion_sense.c b/test/motion_sense.c
index 1a5d808044..c332f962c5 100644
--- a/test/motion_sense.c
+++ b/test/motion_sense.c
@@ -70,15 +70,15 @@ static int test_lid_angle(void)
TEST_ASSERT(motion_get_lid_angle() == -135);
/*
- * Align base with hinge and make sure it returns 0 for angle. In this
- * test it doesn't matter what the lid acceleration vector is.
+ * Align base with hinge and make sure it returns unreliable for angle.
+ * In this test it doesn't matter what the lid acceleration vector is.
*/
mock_x_acc[ACCEL_BASE] = 0;
mock_y_acc[ACCEL_BASE] = 1000;
mock_z_acc[ACCEL_BASE] = 0;
task_wake(TASK_ID_MOTIONSENSE);
msleep(5);
- TEST_ASSERT(motion_get_lid_angle() == 0);
+ TEST_ASSERT(motion_get_lid_angle() == LID_ANGLE_UNRELIABLE);
/*
* Use all three axes and set lid to negative base and make sure