summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFurquan Shaikh <furquan@google.com>2018-11-27 19:44:19 -0800
committerchrome-bot <chrome-bot@chromium.org>2018-11-29 04:31:50 -0800
commit7b3088705a977cabc736405f291b39510763aa44 (patch)
tree9e2ae837c479640e4a1f848f0bbf7290a8df819f
parentba1f417b824cae748474a3a210d75f109f8a8473 (diff)
downloadchrome-ec-7b3088705a977cabc736405f291b39510763aa44.tar.gz
motion_lid: Allow host to configure tablet mode detection threshold
This change adds support for host to configure the tablet mode threshold angle and hysteresis degree using a new motionsense command MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE. Additionally, the EC sets a new feature bit to indicate support for this refined tablet mode detection. This feature bit can be used by kernel to expose an inclinometer device which can eventually help remove the redundant lid angle calculation in Chrome. BUG=b:120050761 BRANCH=octopus TEST=make -j buildall. Additionally, verified that tablet mode lid angle can be configured by host using ectool. Also, feature flag is correctly set to indicate support for this feature. Change-Id: I51bd160bbfae02d899bdf63096618c13eb5800e8 Signed-off-by: Furquan Shaikh <furquan@google.com> Reviewed-on: https://chromium-review.googlesource.com/1351518 Commit-Ready: Furquan Shaikh <furquan@chromium.org> Tested-by: Furquan Shaikh <furquan@chromium.org> Reviewed-by: Jett Rink <jettrink@chromium.org>
-rw-r--r--common/ec_features.c3
-rw-r--r--common/motion_lid.c70
-rw-r--r--include/ec_commands.h40
-rw-r--r--util/ectool.c47
4 files changed, 154 insertions, 6 deletions
diff --git a/common/ec_features.c b/common/ec_features.c
index ec483ad47f..b0f5876e92 100644
--- a/common/ec_features.c
+++ b/common/ec_features.c
@@ -128,6 +128,9 @@ uint32_t get_feature_flags1(void)
#ifdef CONFIG_ACCEL_FIFO
| EC_FEATURE_MASK_1(EC_FEATURE_MOTION_SENSE_TIGHT_TIMESTAMPS)
#endif
+#if defined(CONFIG_LID_ANGLE) && defined(CONFIG_TABLET_MODE)
+ | EC_FEATURE_MASK_1(EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS)
+#endif
;
#ifdef CONFIG_EC_FEATURE_BOARD_OVERRIDE
result = board_override_feature_flags1(result);
diff --git a/common/motion_lid.c b/common/motion_lid.c
index d737046c53..db7b076afa 100644
--- a/common/motion_lid.c
+++ b/common/motion_lid.c
@@ -135,8 +135,8 @@ __attribute__((weak)) int board_is_lid_angle_tablet_mode(void)
* - when lid is closed while the hinge is perpendicular to the floor, we will
* stay in tablet mode.
*
- * Tablet mode is defined as the lid angle being greater than 180 degree. We use
- * 2 threshold to calculate tablet mode:
+ * Tablet mode is defined as the lid angle being greater than 180 degree(by
+ * default). We use 2 threshold to calculate tablet mode:
* tablet_mode:
* 1 | +-----<----+----------
* | \/ /\
@@ -144,9 +144,26 @@ __attribute__((weak)) int board_is_lid_angle_tablet_mode(void)
* 0 |------------------>----+
* +------------+----------+----------+ lid angle
* 0 160 200 360
+ *
+ * Host can configure the threshold to be different than default of 180 +/- 20
+ * by using MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE.
*/
-#define TABLET_ZONE_LID_ANGLE FLOAT_TO_FP(200)
-#define LAPTOP_ZONE_LID_ANGLE FLOAT_TO_FP(160)
+
+#define DEFAULT_TABLET_MODE_ANG (180)
+#define DEFAULT_TABLET_MODE_HYS (20)
+
+#define TABLET_ZONE_ANGLE(a, h) ((a) + (h))
+#define LAPTOP_ZONE_ANGLE(a, h) ((a) - (h))
+
+static fp_t tablet_zone_lid_angle =
+ FLOAT_TO_FP(TABLET_ZONE_ANGLE(DEFAULT_TABLET_MODE_ANG,
+ DEFAULT_TABLET_MODE_HYS));
+static fp_t laptop_zone_lid_angle =
+ FLOAT_TO_FP(LAPTOP_ZONE_ANGLE(DEFAULT_TABLET_MODE_ANG,
+ DEFAULT_TABLET_MODE_HYS));
+
+static int tablet_mode_lid_ang = DEFAULT_TABLET_MODE_ANG;
+static int tablet_mode_hys_deg = DEFAULT_TABLET_MODE_HYS;
/*
* We will change our tablet mode status when we are "convinced" that it has
@@ -165,9 +182,9 @@ static void motion_lid_set_tablet_mode(int reliable)
int new_mode = current_mode;
if (reliable) {
- if (last_lid_angle_fp > TABLET_ZONE_LID_ANGLE)
+ if (last_lid_angle_fp > tablet_zone_lid_angle)
new_mode = 1;
- else if (last_lid_angle_fp < LAPTOP_ZONE_LID_ANGLE)
+ else if (last_lid_angle_fp < laptop_zone_lid_angle)
new_mode = 0;
/* Only change tablet mode if we're sure. */
@@ -195,6 +212,24 @@ static void motion_lid_set_tablet_mode(int reliable)
tablet_mode_debounce_cnt = TABLET_MODE_DEBOUNCE_COUNT;
}
+static int lid_angle_set_tablet_mode_threshold(int ang, int hys)
+{
+ if ((ang == EC_MOTION_SENSE_NO_VALUE) ||
+ (hys == EC_MOTION_SENSE_NO_VALUE))
+ return EC_RES_SUCCESS;
+
+ if ((ang < 0) || (hys < 0) || (ang < hys) || ((ang + hys) > 360))
+ return EC_RES_INVALID_PARAM;
+
+ tablet_mode_lid_ang = ang;
+ tablet_mode_hys_deg = hys;
+
+ tablet_zone_lid_angle = INT_TO_FP(TABLET_ZONE_ANGLE(ang, hys));
+ laptop_zone_lid_angle = INT_TO_FP(LAPTOP_ZONE_ANGLE(ang, hys));
+
+ return EC_RES_SUCCESS;
+}
+
#endif /* CONFIG_TABLET_MODE */
#if defined(CONFIG_DPTF_MULTI_PROFILE) && \
@@ -534,6 +569,29 @@ int host_cmd_motion_lid(struct host_cmd_handler_args *args)
#endif
break;
+ case MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE:
+ {
+#ifdef CONFIG_TABLET_MODE
+ int ret;
+ ret = lid_angle_set_tablet_mode_threshold(
+ in->tablet_mode_threshold.lid_ang,
+ in->tablet_mode_threshold.hys_deg);
+
+ if (ret != EC_RES_SUCCESS)
+ return ret;
+
+ out->tablet_mode_threshold.lid_ang =
+ tablet_mode_lid_ang;
+ out->tablet_mode_threshold.hys_deg =
+ tablet_mode_hys_deg;
+
+ args->response_size =
+ sizeof(out->tablet_mode_threshold);
+#else
+ return EC_RES_INVALID_PARAM;
+#endif
+ }
+ break;
default:
return EC_RES_INVALID_PARAM;
}
diff --git a/include/ec_commands.h b/include/ec_commands.h
index 1fbf2617c5..34d6bb7038 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -1330,6 +1330,12 @@ enum ec_feature_code {
EC_FEATURE_CEC = 35,
/* EC supports tight sensor timestamping. */
EC_FEATURE_MOTION_SENSE_TIGHT_TIMESTAMPS = 36,
+ /*
+ * EC supports tablet mode detection aligned to Chrome and allows
+ * setting of threshold by host command using
+ * MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE.
+ */
+ EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS = 37,
};
#define EC_FEATURE_MASK_0(event_code) (1UL << (event_code % 32))
@@ -2359,6 +2365,9 @@ enum motionsense_command {
*/
MOTIONSENSE_CMD_SPOOF = 16,
+ /* Set lid angle for tablet mode detection. */
+ MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE = 17,
+
/* Number of motionsense sub-commands. */
MOTIONSENSE_NUM_CMDS
};
@@ -2629,6 +2638,24 @@ struct ec_params_motion_sense {
/* Individual component values to spoof. */
int16_t components[3];
} spoof;
+
+ /* Used for MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE. */
+ struct __ec_todo_unpacked {
+ /*
+ * Lid angle threshold for switching between tablet and
+ * clamshell mode.
+ */
+ int16_t lid_ang;
+
+ /*
+ * Hysteresis degree to prevent fluctuations between
+ * clamshell and tablet mode if lid angle keeps
+ * changing around the threshold. Lid motion driver will
+ * use lid_ang + hys_deg to trigger tablet mode and
+ * lid_ang - hys_deg to trigger clamshell mode.
+ */
+ int16_t hys_deg;
+ } tablet_mode_threshold;
};
} __ec_todo_packed;
@@ -2724,6 +2751,19 @@ struct ec_response_motion_sense {
*/
uint16_t value;
} lid_angle;
+
+ /* Used for MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE. */
+ struct __ec_todo_unpacked {
+ /*
+ * Lid angle threshold for switching between tablet and
+ * clamshell mode.
+ */
+ uint16_t lid_ang;
+
+ /* Hysteresis degree. */
+ uint16_t hys_deg;
+ } tablet_mode_threshold;
+
};
} __ec_todo_packed;
diff --git a/util/ectool.c b/util/ectool.c
index 1c5cb1cc59..03b0ecca17 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -643,6 +643,8 @@ static const char * const ec_feature_names[] = {
[EC_FEATURE_CEC] = "Consumer Electronics Control",
[EC_FEATURE_MOTION_SENSE_TIGHT_TIMESTAMPS] =
"Tight timestamp for sensors events",
+ [EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS] =
+ "Refined tablet mode hysteresis",
};
int cmd_inventory(int argc, char *argv[])
@@ -4098,6 +4100,7 @@ static const struct {
{ ST_CMD_SIZE, ST_RSP_SIZE(lid_angle) },
ST_BOTH_SIZES(fifo_int_enable),
ST_BOTH_SIZES(spoof),
+ ST_BOTH_SIZES(tablet_mode_threshold),
};
BUILD_ASSERT(ARRAY_SIZE(ms_command_sizes) == MOTIONSENSE_NUM_CMDS);
@@ -4132,6 +4135,8 @@ static int ms_help(const char *cmd)
printf(" %s lid_angle - print lid angle\n", cmd);
printf(" %s spoof -- NUM [0/1] [X Y Z] - enable/disable spoofing\n",
cmd);
+ printf(" %s tablet_mode_angle ANG HYS - set/get tablet mode angle\n",
+ cmd);
return 0;
}
@@ -4471,6 +4476,48 @@ static int cmd_motionsense(int argc, char **argv)
return 0;
}
+ if (argc < 5 && !strcasecmp(argv[1], "tablet_mode_angle")) {
+ param.cmd = MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE;
+ /*
+ * EC_MOTION_SENSE_NO_VALUE indicates to the EC that host is
+ * attempting to only read the current values.
+ */
+ param.tablet_mode_threshold.lid_ang = EC_MOTION_SENSE_NO_VALUE;
+ param.tablet_mode_threshold.hys_deg = EC_MOTION_SENSE_NO_VALUE;
+
+ if (argc == 4) {
+ param.tablet_mode_threshold.lid_ang = strtol(argv[2],
+ &e, 0);
+
+ if (e && *e) {
+ fprintf(stderr, "Bad %s arg.\n", argv[2]);
+ return -1;
+ }
+
+ param.tablet_mode_threshold.hys_deg = strtol(argv[3],
+ &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad %s arg.\n", argv[3]);
+ return -1;
+ }
+ } else if (argc != 2) {
+ return ms_help(argv[0]);
+ }
+
+ rv = ec_command(EC_CMD_MOTION_SENSE_CMD, 2,
+ &param, ms_command_sizes[param.cmd].outsize,
+ resp, ms_command_sizes[param.cmd].insize);
+
+ if (rv < 0)
+ return rv;
+
+ printf("tablet_mode_angle=%d hys=%d\n",
+ resp->tablet_mode_threshold.lid_ang,
+ resp->tablet_mode_threshold.hys_deg);
+
+ return 0;
+ }
+
if (argc == 2 && !strcasecmp(argv[1], "fifo_info")) {
int sensor_count;