summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/gesture.c6
-rw-r--r--common/motion_sense.c198
-rw-r--r--include/motion_sense.h1
3 files changed, 137 insertions, 68 deletions
diff --git a/common/gesture.c b/common/gesture.c
index ed4443c741..6c37d34e0e 100644
--- a/common/gesture.c
+++ b/common/gesture.c
@@ -286,7 +286,11 @@ DECLARE_HOOK(HOOK_CHIPSET_RESUME, gesture_chipset_resume,
static void gesture_chipset_suspend(void)
{
- /* Set ODR to desired value */
+ /*
+ * Set ODR to desired value
+ * We assume EC rate set correctly: it works because the sensor used
+ * is never offlined/suspened.
+ */
sensor->drv->set_data_rate(sensor, TAP_ODR, 1);
/*
diff --git a/common/motion_sense.c b/common/motion_sense.c
index 629a523910..c4c615f219 100644
--- a/common/motion_sense.c
+++ b/common/motion_sense.c
@@ -40,10 +40,12 @@ static int accel_disp;
#endif
#define SENSOR_EC_RATE(_sensor) \
- ((_sensor)->active == SENSOR_ACTIVE_S0 ? \
+ (sensor_active == SENSOR_ACTIVE_S0 ? \
(_sensor)->runtime_config.ec_rate : \
(_sensor)->default_config.ec_rate)
+#define SENSOR_ACTIVE(_sensor) (sensor_active & (_sensor)->active_mask)
+
/* Minimal amount of time since last collection before triggering a new one */
#define SENSOR_EC_RATE_THRES(_sensor) \
(SENSOR_EC_RATE(_sensor) * 9 / 10)
@@ -56,6 +58,11 @@ static int accel_disp;
*/
static struct mutex g_sensor_mutex;
+/*
+ * Current power level (S0, S3, S5, ...)
+ */
+enum chipset_state_mask sensor_active;
+
#ifdef CONFIG_ACCEL_FIFO
struct queue motion_sense_fifo = QUEUE_NULL(CONFIG_ACCEL_FIFO,
struct ec_response_motion_sensor_data);
@@ -116,6 +123,7 @@ static void motion_sense_get_fifo_info(
*
* 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.
*/
@@ -132,73 +140,99 @@ int motion_sense_set_accel_interval(
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))
+ continue;
+
if (SENSOR_EC_RATE(sensor) < data)
data = SENSOR_EC_RATE(sensor);
}
- accel_interval = data;
+ 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.
+ */
+ task_wake(TASK_ID_MOTIONSENSE);
+ } else {
+ accel_interval = data;
+ }
+
return data;
}
-static void motion_sense_startup(void)
+static inline void motion_sense_init(struct motion_sensor_t *sensor)
+{
+ int ret, cnt = 3;
+
+ /* Initialize accelerometers. */
+ do {
+ ret = sensor->drv->init(sensor);
+ } while ((ret != EC_SUCCESS) && (--cnt > 0));
+
+ if (ret != EC_SUCCESS) {
+ sensor->state = SENSOR_INIT_ERROR;
+ } else {
+ timestamp_t ts = get_time();
+ sensor->state = SENSOR_INITIALIZED;
+ sensor->last_collection = ts.val;
+ }
+}
+
+/*
+ * motion_sense_switch_unused_sensor
+ *
+ * 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)
{
int i;
struct motion_sensor_t *sensor;
for (i = 0; i < motion_sensor_count; ++i) {
sensor = &motion_sensors[i];
- sensor->state = SENSOR_NOT_INITIALIZED;
- sensor->active = SENSOR_ACTIVE_S5;
-
- memcpy(&sensor->runtime_config, &sensor->default_config,
- sizeof(sensor->runtime_config));
+ if ((sensor->state == SENSOR_INITIALIZED) &&
+ !SENSOR_ACTIVE(sensor)) {
+ sensor->drv->set_data_rate(sensor, 0, 0);
+ sensor->state = SENSOR_NOT_INITIALIZED;
+ }
}
motion_sense_set_accel_interval(NULL, MAX_MOTION_SENSE_WAIT_TIME);
}
-DECLARE_HOOK(HOOK_INIT, motion_sense_startup,
- MOTION_SENSE_HOOK_PRIO);
static void motion_sense_shutdown(void)
{
int i;
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];
- sensor->active = SENSOR_ACTIVE_S5;
+ /* Forget about changes made by the AP */
memcpy(&sensor->runtime_config, &sensor->default_config,
sizeof(sensor->runtime_config));
- if ((sensor->state == SENSOR_INITIALIZED) &&
- !(sensor->active_mask & sensor->active)) {
- sensor->drv->set_data_rate(sensor, 0, 0);
- sensor->state = SENSOR_NOT_INITIALIZED;
- }
}
- motion_sense_set_accel_interval(NULL, MAX_MOTION_SENSE_WAIT_TIME);
}
DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, motion_sense_shutdown,
MOTION_SENSE_HOOK_PRIO);
static void motion_sense_suspend(void)
{
- int i;
- struct motion_sensor_t *sensor;
-
- for (i = 0; i < motion_sensor_count; i++) {
- sensor = &motion_sensors[i];
-
- /* if we are comming from S5, don't enter suspend */
- if (sensor->active == SENSOR_ACTIVE_S5)
- return;
-
- sensor->active = SENSOR_ACTIVE_S3;
+ /*
+ * If we are comming from S5, don't enter suspend:
+ * We will go in SO almost immediately.
+ */
+ if (sensor_active == SENSOR_ACTIVE_S5)
+ return;
- /* Saving power if the sensor is not active in S3 */
- if ((sensor->state == SENSOR_INITIALIZED) &&
- !(sensor->active_mask & sensor->active)) {
- sensor->drv->set_data_rate(sensor, 0, 0);
- sensor->state = SENSOR_NOT_INITIALIZED;
- }
- }
- motion_sense_set_accel_interval(NULL, MAX_MOTION_SENSE_WAIT_TIME);
+ sensor_active = SENSOR_ACTIVE_S3;
+ motion_sense_switch_unused_sensor();
}
DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, motion_sense_suspend,
MOTION_SENSE_HOOK_PRIO);
@@ -208,20 +242,48 @@ 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];
- sensor->active = SENSOR_ACTIVE_S0;
- if (sensor->state == SENSOR_INITIALIZED) {
- /* Put back the odr previously set. */
+ /* 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);
}
DECLARE_HOOK(HOOK_CHIPSET_RESUME, motion_sense_resume,
MOTION_SENSE_HOOK_PRIO);
+static void motion_sense_startup(void)
+{
+ int i;
+ struct motion_sensor_t *sensor;
+
+ sensor_active = SENSOR_ACTIVE_S5;
+ 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),
+ * but it may be necessary if the init sequence has changed.
+ */
+ if (chipset_in_state(SENSOR_ACTIVE_S0_S3))
+ motion_sense_suspend();
+ if (chipset_in_state(SENSOR_ACTIVE_S0))
+ motion_sense_resume();
+}
+DECLARE_HOOK(HOOK_INIT, motion_sense_startup,
+ MOTION_SENSE_HOOK_PRIO);
+
/* Write to LPC status byte to represent that accelerometers are present. */
static inline void set_present(uint8_t *lpc_status)
{
@@ -272,24 +334,6 @@ static inline void update_sense_data(uint8_t *lpc_status,
*lpc_status = EC_MEMMAP_ACC_STATUS_PRESENCE_BIT | *psample_id;
}
-static inline void motion_sense_init(struct motion_sensor_t *sensor)
-{
- int ret, cnt = 3;
-
- /* Initialize accelerometers. */
- do {
- ret = sensor->drv->init(sensor);
- } while ((ret != EC_SUCCESS) && (--cnt > 0));
-
- if (ret != EC_SUCCESS) {
- sensor->state = SENSOR_INIT_ERROR;
- } else {
- timestamp_t ts = get_time();
- sensor->state = SENSOR_INITIALIZED;
- sensor->last_collection = ts.val;
- }
-}
-
static int motion_sense_read(struct motion_sensor_t *sensor)
{
if (sensor->state != SENSOR_INITIALIZED)
@@ -374,7 +418,6 @@ void motion_sense_task(void)
lpc_data = (uint16_t *)host_get_memmap(EC_MEMMAP_ACC_DATA);
set_present(lpc_status);
- wait_us = accel_interval;
#ifdef CONFIG_ACCEL_FIFO
ts_last_int = get_time();
#endif
@@ -386,9 +429,13 @@ void motion_sense_task(void)
sensor = &motion_sensors[i];
/* if the sensor is active in the current power state */
- if (sensor->active & sensor->active_mask) {
- if (sensor->state == SENSOR_NOT_INITIALIZED)
- motion_sense_init(sensor);
+ if (SENSOR_ACTIVE(sensor) &&
+ (sensor->runtime_config.odr != 0)) {
+ if (sensor->state != SENSOR_INITIALIZED) {
+ CPRINTS("S%d active, not initalized",
+ sensor);
+ continue;
+ }
ts_begin_task = get_time();
ret = motion_sense_process(sensor, event,
@@ -459,7 +506,13 @@ void motion_sense_task(void)
fifo_flush_needed = 0;
ts_last_int = ts_end_task;
#ifdef CONFIG_MKBP_EVENT
- mkbp_send_event(EC_MKBP_EVENT_SENSOR_FIFO);
+ /*
+ * We don't currently support wake up sensor.
+ * When we do, add per sensor test to know
+ * when sending the event.
+ */
+ if (sensor_active == SENSOR_ACTIVE_S0)
+ mkbp_send_event(EC_MKBP_EVENT_SENSOR_FIFO);
#endif
}
#endif
@@ -502,9 +555,8 @@ static struct motion_sensor_t
sensor = &motion_sensors[host_id];
/* if sensor is powered and initialized, return match */
- if ((sensor->active & sensor->active_mask)
- && (sensor->state == SENSOR_INITIALIZED))
- return sensor;
+ if (SENSOR_ACTIVE(sensor) && (sensor->state == SENSOR_INITIALIZED))
+ return sensor;
/* If no match then the EC currently doesn't support ID received. */
return NULL;
@@ -626,6 +678,12 @@ static int host_cmd_motion_sense(struct host_cmd_handler_args *args)
out->sensor_odr.ret = data;
args->response_size = sizeof(out->sensor_odr);
+
+ /* If the sensor was suspended before, or now suspended, we have
+ * to recalculate the EC sampling rate */
+ motion_sense_set_accel_interval(
+ NULL, MAX_MOTION_SENSE_WAIT_TIME);
+
break;
case MOTIONSENSE_CMD_SENSOR_RANGE:
@@ -893,9 +951,15 @@ static int command_accel_data_rate(int argc, char **argv)
if (sensor->drv->set_data_rate(sensor, data, round)
== EC_ERROR_INVAL)
return EC_ERROR_PARAM2;
+ sensor->runtime_config.odr = data;
+ motion_sense_set_accel_interval(
+ NULL, MAX_MOTION_SENSE_WAIT_TIME);
} else {
sensor->drv->get_data_rate(sensor, &data);
ccprintf("Data rate for sensor %d: %d\n", id, data);
+ ccprintf("EC rate for sensor %d: %d\n", id,
+ SENSOR_EC_RATE(sensor));
+ ccprintf("Current EC rate: %d\n", accel_interval);
}
return EC_SUCCESS;
@@ -996,6 +1060,8 @@ static int command_display_accel_info(int argc, char **argv)
return EC_ERROR_PARAM2;
accel_interval = val * MSEC;
+ task_wake(TASK_ID_MOTIONSENSE);
+
}
return EC_SUCCESS;
diff --git a/include/motion_sense.h b/include/motion_sense.h
index 82a492719c..8233049565 100644
--- a/include/motion_sense.h
+++ b/include/motion_sense.h
@@ -80,7 +80,6 @@ struct motion_sensor_t {
/* state parameters */
enum sensor_state state;
- enum chipset_state_mask active;
vector_3_t raw_xyz;
vector_3_t xyz;