summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGwendal Grignou <gwendal@chromium.org>2015-08-25 18:52:19 -0700
committerchrome-bot <chrome-bot@chromium.org>2015-08-29 01:34:14 -0700
commit4e7e1bb796190e658ea2de8d4e391efa59b0d643 (patch)
treec6927e9226f1853ce2602cc71d6399f7ad210860
parent398bd9a0178c0120a2dbf3f58419d6a5360dfb3d (diff)
downloadchrome-ec-4e7e1bb796190e658ea2de8d4e391efa59b0d643.tar.gz
motion_sense: Add more complex EC/AP sensor rate support.
Add config settings for ODR and EC rate per requestor and per power state (1 for the AP, 3 for the EC). This way we can finely set ec rate and ODR depending on usage. On chromeos, AP is not setting frequency, so EC sets for different power state. On some platform, sensors can now be suspended in S3/S5. Allow EC oversampling when AP is only looking for a few samples. It is useful for double tap detection where high accelerator ODR is required. BRANCH=ryu TEST=Tested on Ryu BUG=chromium:513458 Change-Id: Ic3888a749699f07b10c5da3bc07204afd4de70da Signed-off-by: Gwendal Grignou <gwendal@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/295637
-rw-r--r--board/ryu/board.c137
-rw-r--r--common/motion_sense.c296
-rw-r--r--driver/accel_kxcj9.c10
-rw-r--r--driver/accelgyro_bmi160.c20
-rw-r--r--driver/accelgyro_bmi160.h2
-rw-r--r--driver/accelgyro_lsm6ds0.c17
-rw-r--r--driver/accelgyro_lsm6ds0.h4
-rw-r--r--driver/als_si114x.c2
-rw-r--r--include/accelgyro.h6
-rw-r--r--include/motion_sense.h58
-rw-r--r--test/motion_lid.c93
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();