summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;