diff options
-rw-r--r-- | common/ec_features.c | 3 | ||||
-rw-r--r-- | common/motion_lid.c | 70 | ||||
-rw-r--r-- | include/ec_commands.h | 40 | ||||
-rw-r--r-- | util/ectool.c | 47 |
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, + ¶m, 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; |