diff options
-rw-r--r-- | board/ryu/board.c | 137 | ||||
-rw-r--r-- | common/motion_sense.c | 296 | ||||
-rw-r--r-- | driver/accel_kxcj9.c | 10 | ||||
-rw-r--r-- | driver/accelgyro_bmi160.c | 20 | ||||
-rw-r--r-- | driver/accelgyro_bmi160.h | 2 | ||||
-rw-r--r-- | driver/accelgyro_lsm6ds0.c | 17 | ||||
-rw-r--r-- | driver/accelgyro_lsm6ds0.h | 4 | ||||
-rw-r--r-- | driver/als_si114x.c | 2 | ||||
-rw-r--r-- | include/accelgyro.h | 6 | ||||
-rw-r--r-- | include/motion_sense.h | 58 | ||||
-rw-r--r-- | test/motion_lid.c | 93 |
11 files changed, 427 insertions, 218 deletions
diff --git a/board/ryu/board.c b/board/ryu/board.c index c38a9823da..53d3d2efd3 100644 --- a/board/ryu/board.c +++ b/board/ryu/board.c @@ -287,12 +287,29 @@ struct motion_sensor_t motion_sensors[] = { .drv_data = &g_bmi160_data, .addr = BMI160_ADDR0, .rot_standard_ref = &accelgyro_standard_ref, - .default_config = { - /* 100Hz is fast enough for double tap detection */ - .odr = 100000, - .range = 8, /* g */ - .ec_rate = SUSPEND_SAMPLING_INTERVAL, - } + .default_range = 8, /* g, use hifi requirements */ + .config = { + /* AP: by default shutdown all sensors */ + [SENSOR_CONFIG_AP] = { + .odr = 0, + .ec_rate = 0, + }, + /* EC does not need accel in S0 */ + [SENSOR_CONFIG_EC_S0] = { + .odr = 0, + .ec_rate = 0, + }, + /* Used for double tap */ + [SENSOR_CONFIG_EC_S3] = { + .odr = 100000, + /* Interrupt driven, no polling */ + .ec_rate = 0, + }, + [SENSOR_CONFIG_EC_S5] = { + .odr = 100000, + .ec_rate = 0, + }, + }, }, {.name = "Gyro", @@ -304,12 +321,29 @@ struct motion_sensor_t motion_sensors[] = { .mutex = &g_mutex, .drv_data = &g_bmi160_data, .addr = BMI160_ADDR0, + .default_range = 1000, /* dps, use hifi requirement */ .rot_standard_ref = &accelgyro_standard_ref, - .default_config = { - .odr = 0, - .range = 1000, /* dps */ - .ec_rate = MAX_MOTION_SENSE_WAIT_TIME, - } + .config = { + /* AP: by default shutdown all sensors */ + [SENSOR_CONFIG_AP] = { + .odr = 0, + .ec_rate = 0, + }, + /* EC does not need accel in S0 */ + [SENSOR_CONFIG_EC_S0] = { + .odr = 0, + .ec_rate = 0, + }, + /* Unused */ + [SENSOR_CONFIG_EC_S3] = { + .odr = 0, + .ec_rate = 0, + }, + [SENSOR_CONFIG_EC_S5] = { + .odr = 0, + .ec_rate = 0, + }, + }, }, {.name = "Mag", @@ -322,11 +356,28 @@ struct motion_sensor_t motion_sensors[] = { .drv_data = &g_bmi160_data, .addr = BMI160_ADDR0, .rot_standard_ref = &mag_standard_ref, - .default_config = { - .odr = 0, - .range = 1 << 11, /* 16LSB / uT */ - .ec_rate = MAX_MOTION_SENSE_WAIT_TIME, - } + .default_range = 1 << 11, /* 16LSB / uT, fixed */ + .config = { + /* AP: by default shutdown all sensors */ + [SENSOR_CONFIG_AP] = { + .odr = 0, + .ec_rate = 0, + }, + /* EC does not need accel in S0 */ + [SENSOR_CONFIG_EC_S0] = { + .odr = 0, + .ec_rate = 0, + }, + /* Unused */ + [SENSOR_CONFIG_EC_S3] = { + .odr = 0, + .ec_rate = 0, + }, + [SENSOR_CONFIG_EC_S5] = { + .odr = 0, + .ec_rate = 0, + }, + }, }, {.name = "Light", .active_mask = SENSOR_ACTIVE_S0_S3_S5, @@ -338,11 +389,28 @@ struct motion_sensor_t motion_sensors[] = { .drv_data = &g_si114x_data, .addr = SI114X_ADDR, .rot_standard_ref = NULL, - .default_config = { - .odr = 0, - .range = 9000, /* 90%: int = 0 - frac = 9000/10000 */ - .ec_rate = 1000 * MSEC, - } + .default_range = 9000, /* 90%: int = 0 - frac = 9000/10000 */ + .config = { + /* AP: by default shutdown all sensors */ + [SENSOR_CONFIG_AP] = { + .odr = 0, + .ec_rate = 0, + }, + /* EC to use to set led brightness */ + [SENSOR_CONFIG_EC_S0] = { + .odr = 1000, + .ec_rate = 1000, + }, + [SENSOR_CONFIG_EC_S3] = { + .odr = 1000, + /* Interrupt driven, for double tap */ + .ec_rate = 0, + }, + [SENSOR_CONFIG_EC_S5] = { + .odr = 1000, + .ec_rate = 0, + }, + }, }, {.name = "Proxi", .active_mask = SENSOR_ACTIVE_S0_S3_S5, @@ -354,11 +422,28 @@ struct motion_sensor_t motion_sensors[] = { .drv_data = &g_si114x_data, .addr = SI114X_ADDR, .rot_standard_ref = NULL, - .default_config = { - .odr = 0, - .range = 1 << 16, /* 100% fuzzy unit */ - .ec_rate = 1000 * MSEC, - } + .default_range = 1 << 16, /* 100% fuzzy unit */ + .config = { + /* AP: by default shutdown all sensors */ + [SENSOR_CONFIG_AP] = { + .odr = 0, + .ec_rate = 0, + }, + /* EC does not need accel in S0 */ + [SENSOR_CONFIG_EC_S0] = { + .odr = 0, + .ec_rate = 0, + }, + /* Unused */ + [SENSOR_CONFIG_EC_S3] = { + .odr = 0, + .ec_rate = 0, + }, + [SENSOR_CONFIG_EC_S5] = { + .odr = 0, + .ec_rate = 0, + }, + }, }, }; const unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors); diff --git a/common/motion_sense.c b/common/motion_sense.c index b5de3480ff..f2650fbc52 100644 --- a/common/motion_sense.c +++ b/common/motion_sense.c @@ -39,11 +39,6 @@ unsigned accel_interval; static int accel_disp; #endif -#define SENSOR_EC_RATE(_sensor) \ - (sensor_active == SENSOR_ACTIVE_S0 ? \ - (_sensor)->runtime_config.ec_rate : \ - (_sensor)->default_config.ec_rate) - #define SENSOR_ACTIVE(_sensor) (sensor_active & (_sensor)->active_mask) /* @@ -71,7 +66,8 @@ void motion_sense_fifo_add_unit(struct ec_response_motion_sensor_data *data, struct ec_response_motion_sensor_data vector; int i; - data->sensor_num = (sensor - motion_sensors); + data->sensor_num = sensor - motion_sensors; + mutex_lock(&g_sensor_mutex); if (queue_space(&motion_sense_fifo) == 0) { queue_remove_unit(&motion_sense_fifo, &vector); @@ -83,10 +79,29 @@ void motion_sense_fifo_add_unit(struct ec_response_motion_sensor_data *data, for (i = 0; i < valid_data; i++) sensor->xyz[i] = data->data[i]; mutex_unlock(&g_sensor_mutex); + + if (valid_data) { + int ap_odr = sensor->config[SENSOR_CONFIG_AP].odr & + ~ROUND_UP_FLAG; + int rate = INT_TO_FP(sensor->drv->get_data_rate(sensor)); + + /* If the AP does not want sensor info, skip */ + if (ap_odr == 0) + return; + + /* Skip if EC is oversampling */ + if (sensor->oversampling < 0) { + sensor->oversampling += fp_div(INT_TO_FP(1000), rate); + return; + } + sensor->oversampling += fp_div(INT_TO_FP(1000), rate) - + fp_div(INT_TO_FP(1000), INT_TO_FP(ap_odr)); + } + queue_add_unit(&motion_sense_fifo, data); } -static inline void motion_sense_insert_flush(struct motion_sensor_t *sensor) +static void motion_sense_insert_flush(struct motion_sensor_t *sensor) { struct ec_response_motion_sensor_data vector; vector.flags = MOTIONSENSE_SENSOR_FLAG_FLUSH | @@ -95,7 +110,7 @@ static inline void motion_sense_insert_flush(struct motion_sensor_t *sensor) motion_sense_fifo_add_unit(&vector, sensor, 0); } -static inline void motion_sense_insert_timestamp(void) +static void motion_sense_insert_timestamp(void) { struct ec_response_motion_sensor_data vector; vector.flags = MOTIONSENSE_SENSOR_FLAG_TIMESTAMP; @@ -130,53 +145,111 @@ static inline int motion_sensor_time_to_read(const timestamp_t *ts, sensor->last_collection + 950000000 / rate); } +static enum sensor_config motion_sense_get_ec_config(void) +{ + switch (sensor_active) { + case SENSOR_ACTIVE_S0: + return SENSOR_CONFIG_EC_S0; + case SENSOR_ACTIVE_S3: + return SENSOR_CONFIG_EC_S3; + case SENSOR_ACTIVE_S5: + return SENSOR_CONFIG_EC_S5; + default: + CPRINTS("get_ec_config: Invalid active state: %x", + sensor_active); + return SENSOR_CONFIG_MAX; + } +} +/* motion_sense_set_data_rate + * + * Set the sensor data rate. It is altered when the AP change the data + * rate or when the power state changes. + */ +int motion_sense_set_data_rate(struct motion_sensor_t *sensor) +{ + int roundup = 0, ec_odr = 0, odr = 0; + enum sensor_config config_id; + + /* We assume the sensor is initalized */ + + /* Check the AP setting first. */ + if (sensor_active != SENSOR_ACTIVE_S5) + odr = sensor->config[SENSOR_CONFIG_AP].odr & ~ROUND_UP_FLAG; + + /* check if the EC set the sensor ODR at a higher frequency */ + config_id = motion_sense_get_ec_config(); + ec_odr = sensor->config[config_id].odr & ~ROUND_UP_FLAG; + if (ec_odr > odr) + odr = ec_odr; + else + config_id = SENSOR_CONFIG_AP; + roundup = !!(sensor->config[config_id].odr & ROUND_UP_FLAG); + CPRINTS("%s ODR: %d - roundup %d from config %d", + sensor->name, odr, roundup, config_id); + return sensor->drv->set_data_rate(sensor, odr, roundup); +} + +/* motion_sense_ec_rate + * + * Calculate the sensor ec rate. It will be use to set the motion task polling + * rate. + * + * Return the EC rate, in us. + */ +static int motion_sense_ec_rate(struct motion_sensor_t *sensor) +{ + int ec_rate = 0, ec_rate_from_cfg; + enum sensor_config config_id = SENSOR_CONFIG_AP; + + /* Check the AP setting first. */ + if (sensor_active != SENSOR_ACTIVE_S5) + ec_rate = sensor->config[SENSOR_CONFIG_AP].ec_rate; + + config_id = motion_sense_get_ec_config(); + ec_rate_from_cfg = sensor->config[config_id].ec_rate; + if ((ec_rate == 0 && ec_rate_from_cfg != 0) || + (ec_rate_from_cfg != 0 && ec_rate_from_cfg < ec_rate)) + ec_rate = ec_rate_from_cfg; + return ec_rate * MSEC; +} + /* * motion_sense_set_accel_interval * * Set the wake up interval for the motion sense thread. * It is set to the highest frequency one of the sensors need to be polled at. * - * driving_sensor: In S0, indicates which sensor has its EC sampling rate - * changed. In S3, it is hard coded, so in S3 driving_sensor should be NULL. - * data: The new ec sampling rate for this sensor. - * * Note: Not static to be tested. */ -int motion_sense_set_accel_interval( - struct motion_sensor_t *driving_sensor, - unsigned data) +int motion_sense_set_accel_interval(void) { - int i; + int i, sensor_ec_rate, ec_rate, wake_up = 0; struct motion_sensor_t *sensor; - if (driving_sensor) - driving_sensor->runtime_config.ec_rate = data; - - for (i = 0; i < motion_sensor_count; ++i) { + for (i = 0, ec_rate = 0; i < motion_sensor_count; ++i) { sensor = &motion_sensors[i]; - if (sensor == driving_sensor) - continue; /* * If the sensor is sleeping, no need to check it periodicaly. */ - if ((sensor->runtime_config.odr == 0) || - (sensor->state != SENSOR_INITIALIZED)) + if ((sensor->state != SENSOR_INITIALIZED) || + (sensor->drv->get_data_rate(sensor) == 0)) continue; - if (SENSOR_EC_RATE(sensor) < data) - data = SENSOR_EC_RATE(sensor); + sensor_ec_rate = motion_sense_ec_rate(sensor); + if ((ec_rate == 0 && sensor_ec_rate != 0) || + (sensor_ec_rate != 0 && sensor_ec_rate < ec_rate)) + ec_rate = sensor_ec_rate; } - if (accel_interval > data) { - accel_interval = data; - /* - * Wake up the motion sense task: we want to sensor task to take - * in account the new period right away. - */ + /* + * Wake up the motion sense task: we want to sensor task to take + * in account the new period right away. + */ + if (accel_interval == 0 || + (ec_rate > 0 && accel_interval > ec_rate)) + wake_up = 1; + accel_interval = ec_rate; + if (wake_up) task_wake(TASK_ID_MOTIONSENSE); - } else { - accel_interval = data; - } - - return data; + return accel_interval; } static inline void motion_sense_init(struct motion_sensor_t *sensor) @@ -194,29 +267,36 @@ static inline void motion_sense_init(struct motion_sensor_t *sensor) timestamp_t ts = get_time(); sensor->state = SENSOR_INITIALIZED; sensor->last_collection = ts.le.lo; + sensor->oversampling = 0; + motion_sense_set_data_rate(sensor); } } /* - * motion_sense_switch_unused_sensor + * motion_sense_switch_sensor_rate * * Suspend all sensors that are not needed. * Mark them as unitialized, they wll lose power and * need to be initialized again. */ -static void motion_sense_switch_unused_sensor(void) +static void motion_sense_switch_sensor_rate(void) { int i; struct motion_sensor_t *sensor; for (i = 0; i < motion_sensor_count; ++i) { sensor = &motion_sensors[i]; - if ((sensor->state == SENSOR_INITIALIZED) && - !SENSOR_ACTIVE(sensor)) { - sensor->drv->set_data_rate(sensor, 0, 0); - sensor->state = SENSOR_NOT_INITIALIZED; + if (SENSOR_ACTIVE(sensor)) { + /* Initialize or just back the odr previously set. */ + if (sensor->state == SENSOR_INITIALIZED) + motion_sense_set_data_rate(sensor); + else + motion_sense_init(sensor); + } else { + if (sensor->state == SENSOR_INITIALIZED) + sensor->state = SENSOR_NOT_INITIALIZED; } } - motion_sense_set_accel_interval(NULL, MAX_MOTION_SENSE_WAIT_TIME); + motion_sense_set_accel_interval(); } static void motion_sense_shutdown(void) @@ -225,14 +305,16 @@ static void motion_sense_shutdown(void) struct motion_sensor_t *sensor; sensor_active = SENSOR_ACTIVE_S5; - motion_sense_switch_unused_sensor(); for (i = 0; i < motion_sensor_count; i++) { sensor = &motion_sensors[i]; /* Forget about changes made by the AP */ - memcpy(&sensor->runtime_config, &sensor->default_config, - sizeof(sensor->runtime_config)); + sensor->config[SENSOR_CONFIG_AP].odr = 0; + sensor->config[SENSOR_CONFIG_AP].ec_rate = 0; + sensor->drv->set_range(sensor, sensor->default_range, 0); + } + motion_sense_switch_sensor_rate(); } DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, motion_sense_shutdown, MOTION_SENSE_HOOK_PRIO); @@ -247,27 +329,15 @@ static void motion_sense_suspend(void) return; sensor_active = SENSOR_ACTIVE_S3; - motion_sense_switch_unused_sensor(); + motion_sense_switch_sensor_rate(); } DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, motion_sense_suspend, MOTION_SENSE_HOOK_PRIO); static void motion_sense_resume(void) { - int i; - struct motion_sensor_t *sensor; - sensor_active = SENSOR_ACTIVE_S0; - for (i = 0; i < motion_sensor_count; i++) { - sensor = &motion_sensors[i]; - /* Initialize or just back the odr previously set. */ - if (sensor->state == SENSOR_INITIALIZED) - sensor->drv->set_data_rate(sensor, - sensor->runtime_config.odr, 1); - else - motion_sense_init(sensor); - } - motion_sense_set_accel_interval(NULL, MAX_MOTION_SENSE_WAIT_TIME); + motion_sense_switch_sensor_rate(); } DECLARE_HOOK(HOOK_CHIPSET_RESUME, motion_sense_resume, MOTION_SENSE_HOOK_PRIO); @@ -281,11 +351,7 @@ static void motion_sense_startup(void) for (i = 0; i < motion_sensor_count; ++i) { sensor = &motion_sensors[i]; sensor->state = SENSOR_NOT_INITIALIZED; - - memcpy(&sensor->runtime_config, &sensor->default_config, - sizeof(sensor->runtime_config)); } - motion_sense_set_accel_interval(NULL, MAX_MOTION_SENSE_WAIT_TIME); /* If the AP is already in S0, call the resume hook now. * We may initialize the sensor 2 times (once in RO, anoter time in RW), @@ -357,7 +423,7 @@ static int motion_sense_read(struct motion_sensor_t *sensor) if (sensor->state != SENSOR_INITIALIZED) return EC_ERROR_UNKNOWN; - if (sensor->runtime_config.odr == 0) + if (sensor->drv->get_data_rate(sensor) == 0) return EC_ERROR_NOT_POWERED; /* Read all raw X,Y,Z accelerations. */ @@ -466,7 +532,6 @@ void motion_sense_task(void) /* if the sensor is active in the current power state */ if (SENSOR_ACTIVE(sensor)) { if (sensor->state != SENSOR_INITIALIZED) { - CPRINTS("S%d active not initalized", i); continue; } @@ -524,7 +589,8 @@ void motion_sense_task(void) if (fifo_flush_needed || event & TASK_EVENT_MOTION_ODR_CHANGE || queue_space(&motion_sense_fifo) < CONFIG_ACCEL_FIFO_THRES || - (ts_end_task.val - ts_last_int.val) > accel_interval) { + (accel_interval > 0 && + (ts_end_task.val - ts_last_int.val) > accel_interval)) { if (!fifo_flush_needed) motion_sense_insert_timestamp(); fifo_flush_needed = 0; @@ -540,16 +606,24 @@ void motion_sense_task(void) #endif } #endif - /* Delay appropriately to keep sampling time consistent. */ - wait_us = accel_interval - - (ts_end_task.val - ts_begin_task.val); + if (accel_interval > 0) { + /* + * Delay appropriately to keep sampling time + * consistent. + */ + wait_us = accel_interval - + (ts_end_task.val - ts_begin_task.val); + + /* + * Guarantee some minimum delay to allow other lower + * priority tasks to run. + */ + if (wait_us < MIN_MOTION_SENSE_WAIT_TIME) + wait_us = MIN_MOTION_SENSE_WAIT_TIME; + } else { + wait_us = -1; + } - /* - * Guarantee some minimum delay to allow other lower priority - * tasks to run. - */ - if (wait_us < MIN_MOTION_SENSE_WAIT_TIME) - wait_us = MIN_MOTION_SENSE_WAIT_TIME; } while ((event = task_wait_event(wait_us))); } @@ -591,7 +665,7 @@ static int host_cmd_motion_sense(struct host_cmd_handler_args *args) const struct ec_params_motion_sense *in = args->params; struct ec_response_motion_sense *out = args->response; struct motion_sensor_t *sensor; - int i, data, ret = EC_RES_INVALID_PARAM, reported; + int i, ret = EC_RES_INVALID_PARAM, reported; switch (in->cmd) { case MOTIONSENSE_CMD_DUMP: @@ -657,14 +731,18 @@ static int host_cmd_motion_sense(struct host_cmd_handler_args *args) * has a value. */ if (in->ec_rate.data != EC_MOTION_SENSE_NO_VALUE) { + if (in->ec_rate.data == 0) + sensor->config[SENSOR_CONFIG_AP].ec_rate = 0; + else + sensor->config[SENSOR_CONFIG_AP].ec_rate = + MAX(in->ec_rate.data, + MIN_MOTION_SENSE_WAIT_TIME / MSEC); + /* Bound the new sampling rate. */ - motion_sense_set_accel_interval( - sensor, - MAX(in->ec_rate.data * MSEC, - MIN_MOTION_SENSE_WAIT_TIME)); + motion_sense_set_accel_interval(); } - out->ec_rate.ret = sensor->runtime_config.ec_rate / MSEC; + out->ec_rate.ret = motion_sense_ec_rate(sensor) / MSEC; args->response_size = sizeof(out->ec_rate); break; @@ -678,14 +756,14 @@ static int host_cmd_motion_sense(struct host_cmd_handler_args *args) /* Set new data rate if the data arg has a value. */ if (in->sensor_odr.data != EC_MOTION_SENSE_NO_VALUE) { - if (sensor->drv->set_data_rate(sensor, - in->sensor_odr.data, - in->sensor_odr.roundup) - != EC_SUCCESS) { - CPRINTS("MS bad sensor rate %d", - in->sensor_odr.data); + sensor->config[SENSOR_CONFIG_AP].odr = + in->sensor_odr.data | + (in->sensor_odr.roundup ? ROUND_UP_FLAG : 0); + + ret = motion_sense_set_data_rate(sensor); + if (ret != EC_SUCCESS) return EC_RES_INVALID_PARAM; - } + /* * To be sure timestamps are calculated properly, * Send an event to have a timestamp inserted in the @@ -698,16 +776,10 @@ static int host_cmd_motion_sense(struct host_cmd_handler_args *args) * suspended, we have to recalculate the EC sampling * rate */ - motion_sense_set_accel_interval( - NULL, MAX_MOTION_SENSE_WAIT_TIME); - + motion_sense_set_accel_interval(); } - data = sensor->drv->get_data_rate(sensor); - - /* Save configuration parameter: ODR */ - sensor->runtime_config.odr = data; - out->sensor_odr.ret = data; + out->sensor_odr.ret = sensor->drv->get_data_rate(sensor); args->response_size = sizeof(out->sensor_odr); @@ -726,18 +798,11 @@ static int host_cmd_motion_sense(struct host_cmd_handler_args *args) in->sensor_range.data, in->sensor_range.roundup) != EC_SUCCESS) { - CPRINTS("MS bad sensor range %d", - in->sensor_range.data); return EC_RES_INVALID_PARAM; } } - data = sensor->drv->get_range(sensor); - - /* Save configuration parameter: range */ - sensor->runtime_config.range = data; - - out->sensor_range.ret = data; + out->sensor_range.ret = sensor->drv->get_range(sensor); args->response_size = sizeof(out->sensor_range); break; @@ -832,8 +897,6 @@ static int host_cmd_motion_sense(struct host_cmd_handler_args *args) if (ret == EC_RES_INVALID_PARAM) ret = host_cmd_motion_lid(args); #endif - if (ret == EC_RES_INVALID_PARAM) - CPRINTS("MS bad cmd 0x%x", in->cmd); return ret; } @@ -945,8 +1008,9 @@ DECLARE_CONSOLE_COMMAND(accelres, command_accelresolution, static int command_accel_data_rate(int argc, char **argv) { char *e; - int id, data, round = 1; + int id, data, round = 1, ret; struct motion_sensor_t *sensor; + enum sensor_config config_id; if (argc < 2 || argc > 4) return EC_ERROR_PARAM_COUNT; @@ -975,17 +1039,19 @@ static int command_accel_data_rate(int argc, char **argv) * Write new data rate, if it returns invalid arg, then * return a parameter error. */ - if (sensor->drv->set_data_rate(sensor, data, round) == - EC_ERROR_INVAL) + config_id = motion_sense_get_ec_config(); + sensor->config[config_id].odr = + data | (round ? ROUND_UP_FLAG : 0); + ret = motion_sense_set_data_rate(sensor); + if (ret) return EC_ERROR_PARAM2; - sensor->runtime_config.odr = data; - motion_sense_set_accel_interval( - NULL, MAX_MOTION_SENSE_WAIT_TIME); + /* Sensor might be out of suspend, check the ec_rate */ + motion_sense_set_accel_interval(); } else { ccprintf("Data rate for sensor %d: %d\n", id, sensor->drv->get_data_rate(sensor)); ccprintf("EC rate for sensor %d: %d\n", id, - SENSOR_EC_RATE(sensor)); + motion_sense_ec_rate(sensor)); ccprintf("Current EC rate: %d\n", accel_interval); } diff --git a/driver/accel_kxcj9.c b/driver/accel_kxcj9.c index b893d71c51..dd0cf49115 100644 --- a/driver/accel_kxcj9.c +++ b/driver/accel_kxcj9.c @@ -511,7 +511,7 @@ static int init(const struct motion_sensor_t *s) } } while (1); - ret = set_range(s, s->runtime_config.range, 1); + ret = set_range(s, s->default_range, 1); if (ret != EC_SUCCESS) return ret; @@ -519,15 +519,11 @@ static int init(const struct motion_sensor_t *s) if (ret != EC_SUCCESS) return ret; - ret = set_data_rate(s, s->runtime_config.odr, 1); - if (ret != EC_SUCCESS) - return ret; - #ifdef CONFIG_ACCEL_INTERRUPTS config_interrupt(s); #endif - CPRINTF("[%T %s: Done Init type:0x%X range:%d rate:%d]\n", - s->name, s->type, get_range(s), get_data_rate(s)); + CPRINTF("[%T %s: Done Init type:0x%X range:%d]\n", + s->name, s->type, get_range(s)); return ret; } diff --git a/driver/accelgyro_bmi160.c b/driver/accelgyro_bmi160.c index 0960131926..3044fe1c66 100644 --- a/driver/accelgyro_bmi160.c +++ b/driver/accelgyro_bmi160.c @@ -304,7 +304,7 @@ static int set_range(const struct motion_sensor_t *s, int ret, range_tbl_size; uint8_t reg_val, ctrl_reg; const struct accel_param_pair *ranges; - struct motion_data_t *data = BMI160_GET_SAVED_DATA(s); + struct accelgyro_saved_data_t *data = BMI160_GET_SAVED_DATA(s); if (s->type == MOTIONSENSE_TYPE_MAG) { data->range = range; @@ -325,7 +325,7 @@ static int set_range(const struct motion_sensor_t *s, static int get_range(const struct motion_sensor_t *s) { - struct motion_data_t *data = BMI160_GET_SAVED_DATA(s); + struct accelgyro_saved_data_t *data = BMI160_GET_SAVED_DATA(s); return data->range; } @@ -349,7 +349,7 @@ static int set_data_rate(const struct motion_sensor_t *s, { int ret, val, normalized_rate; uint8_t ctrl_reg, reg_val; - struct motion_data_t *data = BMI160_GET_SAVED_DATA(s); + struct accelgyro_saved_data_t *data = BMI160_GET_SAVED_DATA(s); if (rate == 0) { #ifdef CONFIG_ACCEL_FIFO @@ -429,8 +429,9 @@ static int set_data_rate(const struct motion_sensor_t *s, data->odr = normalized_rate; #ifdef CONFIG_ACCEL_FIFO - /* FIFO start collecting events */ - enable_fifo(s, 1); + /* FIFO start collecting events if AP wants them */ + if (s->config[SENSOR_CONFIG_AP].odr != 0) + enable_fifo(s, 1); #endif accel_cleanup: @@ -440,7 +441,7 @@ accel_cleanup: static int get_data_rate(const struct motion_sensor_t *s) { - struct motion_data_t *data = BMI160_GET_SAVED_DATA(s); + struct accelgyro_saved_data_t *data = BMI160_GET_SAVED_DATA(s); return data->odr; } @@ -1015,11 +1016,10 @@ static int init(const struct motion_sensor_t *s) if (s->type == MOTIONSENSE_TYPE_ACCEL) ret = config_interrupt(s); #endif - set_data_rate(s, s->runtime_config.odr, 0); - set_range(s, s->runtime_config.range, 0); + set_range(s, s->default_range, 0); - CPRINTF("[%T %s: MS Done Init type:0x%X range:%d odr:%d]\n", - s->name, s->type, get_range(s), get_data_rate(s)); + CPRINTF("[%T %s: MS Done Init type:0x%X range:%d]\n", + s->name, s->type, get_range(s)); return ret; } diff --git a/driver/accelgyro_bmi160.h b/driver/accelgyro_bmi160.h index fd2de42a4b..069e49b265 100644 --- a/driver/accelgyro_bmi160.h +++ b/driver/accelgyro_bmi160.h @@ -405,7 +405,7 @@ enum bmi160_running_mode { #define BMI160_FIFO_ALL_MASK 7 struct bmi160_drv_data_t { - struct motion_data_t saved_data[3]; + struct accelgyro_saved_data_t saved_data[3]; uint8_t flags; #ifdef CONFIG_MAG_BMI160_BMM150 struct bmm150_comp_registers comp_regs; diff --git a/driver/accelgyro_lsm6ds0.c b/driver/accelgyro_lsm6ds0.c index dee3e7d622..62996825ac 100644 --- a/driver/accelgyro_lsm6ds0.c +++ b/driver/accelgyro_lsm6ds0.c @@ -426,29 +426,20 @@ static int init(const struct motion_sensor_t *s) if (ret) return EC_ERROR_UNKNOWN; - ret = set_range(s, s->runtime_config.range, 1); - if (ret) - return EC_ERROR_UNKNOWN; - - ret = set_data_rate(s, s->runtime_config.odr, 1); + ret = set_range(s, s->default_range, 1); if (ret) return EC_ERROR_UNKNOWN; } if (MOTIONSENSE_TYPE_GYRO == s->type) { /* Config GYRO Range */ - ret = set_range(s, s->runtime_config.range, 1); - if (ret) - return EC_ERROR_UNKNOWN; - - /* Config ACCEL & GYRO ODR */ - ret = set_data_rate(s, s->runtime_config.odr, 1); + ret = set_range(s, s->default_range, 1); if (ret) return EC_ERROR_UNKNOWN; } - CPRINTF("[%T %s: MS Done Init type:0x%X range:%d odr:%d]\n", - s->name, s->type, get_range(s), get_data_rate(s)); + CPRINTF("[%T %s: MS Done Init type:0x%X range:%d]\n", + s->name, s->type, get_range(s)); return ret; } diff --git a/driver/accelgyro_lsm6ds0.h b/driver/accelgyro_lsm6ds0.h index 82b675db09..481f39aa10 100644 --- a/driver/accelgyro_lsm6ds0.h +++ b/driver/accelgyro_lsm6ds0.h @@ -8,7 +8,7 @@ #ifndef __CROS_EC_ACCELGYRO_LSM6DS0_H #define __CROS_EC_ACCELGYRO_LSM6DS0_H -#include "motion_sense.h" +#include "accelgyro.h" #include "task.h" /* @@ -119,7 +119,7 @@ enum lsm6ds0_bdu { extern const struct accelgyro_drv lsm6ds0_drv; struct lsm6ds0_data { - struct motion_data_t base; + struct accelgyro_saved_data_t base; int16_t offset[3]; }; diff --git a/driver/als_si114x.c b/driver/als_si114x.c index c7a3d0374a..3be0c68d67 100644 --- a/driver/als_si114x.c +++ b/driver/als_si114x.c @@ -487,7 +487,7 @@ static int init(const struct motion_sensor_t *s) resol = 5; } - set_range(s, s->runtime_config.range, 0); + set_range(s, s->default_range, 0); /* * Sensor is most likely behind a glass. * Max out the gain to get correct measurement diff --git a/include/accelgyro.h b/include/accelgyro.h index c65e624bf4..46ab68d855 100644 --- a/include/accelgyro.h +++ b/include/accelgyro.h @@ -120,4 +120,10 @@ struct accelgyro_drv { #endif }; +/* Used to save sensor information */ +struct accelgyro_saved_data_t { + int odr; + int range; +}; + #endif /* __CROS_EC_ACCELGYRO_H */ diff --git a/include/motion_sense.h b/include/motion_sense.h index cbe311fdf6..6541893d67 100644 --- a/include/motion_sense.h +++ b/include/motion_sense.h @@ -22,6 +22,14 @@ enum sensor_state { SENSOR_INIT_ERROR = 2 }; +enum sensor_config { + SENSOR_CONFIG_AP, /* Configuration requested/for the AP */ + SENSOR_CONFIG_EC_S0, /* Configuration from the EC while device in S0 */ + SENSOR_CONFIG_EC_S3, /* from the EC when device sleep */ + SENSOR_CONFIG_EC_S5, /* from the EC when device powered off */ + SENSOR_CONFIG_MAX, +}; + #define SENSOR_ACTIVE_S5 CHIPSET_STATE_SOFT_OFF #define SENSOR_ACTIVE_S3 CHIPSET_STATE_SUSPEND #define SENSOR_ACTIVE_S0 CHIPSET_STATE_ON @@ -47,17 +55,21 @@ enum sensor_state { #define MIN_MOTION_SENSE_WAIT_TIME (3 * MSEC) #define MAX_MOTION_SENSE_WAIT_TIME (60000 * MSEC) +#define ROUND_UP_FLAG (1 << 31) + struct motion_data_t { - /* data rate the sensor will measure, in mHz */ - int odr; - /* range of measurement in SI */ - int range; + /* + * data rate the sensor will measure, in mHz: 0 suspended. + * MSB is used to know if we are rounding up. + * */ + unsigned odr; /* delay between collection by EC, in ms. * For non FIFO sensor, should be nead 1e6/odr to * collect events. * For sensor with FIFO, can be much longer. + * 0: no collection. */ - unsigned ec_rate; + unsigned short ec_rate; }; struct motion_sensor_t { @@ -74,11 +86,29 @@ struct motion_sensor_t { uint8_t addr; const matrix_3x3_t *rot_standard_ref; - /* Default configuration parameters, RO only */ - struct motion_data_t default_config; + /* + * default_range: set by default by the EC. + * The host can change it, but rarely does. + */ + int default_range; - /* Run-Time configuration parameters */ - struct motion_data_t runtime_config; + /* + * There are 4 configuration parameters to deal with different + * configuration + * + * Power | S0 | S3 | S5 + * --------+-------------------+-------------------+----------------- + * From AP | <------- SENSOR_CONFIG_AP ----------> | + * | Use for normal | While sleeping | Always disabled + * | operation: game, | iFor Activity | + * | screen rotatopm | Recognition | + * --------+-------------------+-------------------+------------------ + * From EC |SENSOR_CONFIG_EC_S0|SENSOR_CONFIG_EC_S3|SENSOR_CONFIG_EC_S5 + * | Background | Gesture Recognition (Double tap, ...) + * | Activity: compass,| + * | ambient light)| + */ + struct motion_data_t config[SENSOR_CONFIG_MAX]; /* state parameters */ enum sensor_state state; @@ -89,6 +119,11 @@ struct motion_sensor_t { uint32_t flush_pending; /* + * Allow EC to request an higher frequency for the sensors than the AP. + */ + fp_t oversampling; + + /* * How many vector events are lost in the FIFO since last time * FIFO info has been transmitted. */ @@ -109,10 +144,9 @@ extern struct motion_sensor_t motion_sensors[]; extern const unsigned motion_sensor_count; /* For testing purposes: export the sampling interval. */ +extern enum chipset_state_mask sensor_active; extern unsigned accel_interval; -int motion_sense_set_accel_interval( - struct motion_sensor_t *driving_sensor, - unsigned data); +int motion_sense_set_accel_interval(void); /* * Priority of the motion sense resume/suspend hooks, to be sure associated diff --git a/test/motion_lid.c b/test/motion_lid.c index d204ec4ab0..964bd9f026 100644 --- a/test/motion_lid.c +++ b/test/motion_lid.c @@ -24,7 +24,7 @@ * Period in us for the motion task period. * The task will read the vectors at that interval */ -#define TEST_LID_EC_RATE (SUSPEND_SAMPLING_INTERVAL / 10) +#define TEST_LID_EC_RATE (10) /* * Time in ms to wait for the task to read the vectors. @@ -51,10 +51,9 @@ static int accel_set_range(const struct motion_sensor_t *s, return EC_SUCCESS; } -static int accel_get_range(const struct motion_sensor_t *s, - int * const range) +static int accel_get_range(const struct motion_sensor_t *s) { - return EC_SUCCESS; + return 0; } static int accel_set_resolution(const struct motion_sensor_t *s, @@ -64,23 +63,24 @@ static int accel_set_resolution(const struct motion_sensor_t *s, return EC_SUCCESS; } -static int accel_get_resolution(const struct motion_sensor_t *s, - int * const res) +static int accel_get_resolution(const struct motion_sensor_t *s) { - return EC_SUCCESS; + return 0; } +int test_data_rate[2] = { 0 }; + static int accel_set_data_rate(const struct motion_sensor_t *s, const int rate, const int rnd) { + test_data_rate[s - motion_sensors] = rate | (rnd ? ROUND_UP_FLAG : 0); return EC_SUCCESS; } -static int accel_get_data_rate(const struct motion_sensor_t *s, - int * const rate) +static int accel_get_data_rate(const struct motion_sensor_t *s) { - return EC_SUCCESS; + return test_data_rate[s - motion_sensors]; } const struct accelgyro_drv test_motion_sense = { @@ -117,11 +117,28 @@ struct motion_sensor_t motion_sensors[] = { .drv_data = NULL, .addr = 0, .rot_standard_ref = &base_standard_ref, - .default_config = { - .odr = 119000, - .range = 2, - .ec_rate = SUSPEND_SAMPLING_INTERVAL, - } + .default_range = 2, /* g, enough for laptop. */ + .config = { + /* AP: by default shutdown all sensors */ + [SENSOR_CONFIG_AP] = { + .odr = 0, + .ec_rate = 0, + }, + /* EC use accel for angle detection */ + [SENSOR_CONFIG_EC_S0] = { + .odr = 119000 | ROUND_UP_FLAG, + .ec_rate = TEST_LID_EC_RATE + }, + /* Used for double tap */ + [SENSOR_CONFIG_EC_S3] = { + .odr = 119000 | ROUND_UP_FLAG, + .ec_rate = TEST_LID_EC_RATE * 100, + }, + [SENSOR_CONFIG_EC_S5] = { + .odr = 0, + .ec_rate = 0, + }, + }, }, {.name = "lid", .active_mask = SENSOR_ACTIVE_S0, @@ -133,11 +150,28 @@ struct motion_sensor_t motion_sensors[] = { .drv_data = NULL, .addr = 0, .rot_standard_ref = &lid_standard_ref, - .default_config = { - .odr = 119000, - .range = 2, - .ec_rate = SUSPEND_SAMPLING_INTERVAL, - } + .default_range = 2, /* g, enough for laptop. */ + .config = { + /* AP: by default shutdown all sensors */ + [SENSOR_CONFIG_AP] = { + .odr = 0, + .ec_rate = 0, + }, + /* EC use accel for angle detection */ + [SENSOR_CONFIG_EC_S0] = { + .odr = 119000 | ROUND_UP_FLAG, + .ec_rate = TEST_LID_EC_RATE, + }, + /* Used for double tap */ + [SENSOR_CONFIG_EC_S3] = { + .odr = 119000 | ROUND_UP_FLAG, + .ec_rate = TEST_LID_EC_RATE * 100, + }, + [SENSOR_CONFIG_EC_S5] = { + .odr = 0, + .ec_rate = 0, + }, + }, }, }; const unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors); @@ -163,19 +197,16 @@ static int test_lid_angle(void) struct motion_sensor_t *lid = &motion_sensors[1]; /* Go to S3 state */ - TEST_ASSERT(accel_interval == SUSPEND_SAMPLING_INTERVAL); - TEST_ASSERT(motion_sensors[0].active == SENSOR_ACTIVE_S5); + TEST_ASSERT(sensor_active == SENSOR_ACTIVE_S5); + TEST_ASSERT(accel_get_data_rate(lid) == 0); + TEST_ASSERT(accel_interval == 0); /* Go to S0 state */ hook_notify(HOOK_CHIPSET_RESUME); - TEST_ASSERT(accel_interval == SUSPEND_SAMPLING_INTERVAL); - TEST_ASSERT(motion_sensors[0].active == SENSOR_ACTIVE_S0); - - motion_sense_set_accel_interval(base, TEST_LID_EC_RATE); - TEST_ASSERT(accel_interval == TEST_LID_EC_RATE); - - motion_sense_set_accel_interval(lid, TEST_LID_EC_RATE); - TEST_ASSERT(accel_interval == TEST_LID_EC_RATE); + msleep(1000); + TEST_ASSERT(sensor_active == SENSOR_ACTIVE_S0); + TEST_ASSERT(accel_get_data_rate(lid) == (119000 | ROUND_UP_FLAG)); + TEST_ASSERT(accel_interval == TEST_LID_EC_RATE * MSEC); /* * Set the base accelerometer as if it were sitting flat on a desk @@ -191,7 +222,7 @@ static int test_lid_angle(void) task_wake(TASK_ID_MOTIONSENSE); /* wait for the EC sampling period to expire */ - msleep(TEST_LID_EC_RATE/MSEC); + msleep(TEST_LID_EC_RATE); task_wake(TASK_ID_MOTIONSENSE); wait_for_valid_sample(); |