summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGwendal Grignou <gwendal@chromium.org>2015-08-30 20:55:40 -0700
committerchrome-bot <chrome-bot@chromium.org>2015-09-21 01:13:54 -0700
commit8139114897c2eab41fd71e66368d861f9e5db2ba (patch)
tree80088b7be806602ecf0f3f337e8f7f70f03a03e2
parent1d8fcfcd0d1b93d04ea5adcb980ffac38bd3d140 (diff)
downloadchrome-ec-8139114897c2eab41fd71e66368d861f9e5db2ba.tar.gz
driver: bmi160: Add Significant motion support.
Add support for significant motion. BRANCH=smaug BUG=b:23570481 TEST=On Ryu, check significant motion (not still) is detected. Change-Id: I5760a1ba3624490a0297de82371b1d15f05df5dc Signed-off-by: Gwendal Grignou <gwendal@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/296214
-rw-r--r--driver/accelgyro_bmi160.c94
-rw-r--r--driver/accelgyro_bmi160.h22
2 files changed, 116 insertions, 0 deletions
diff --git a/driver/accelgyro_bmi160.c b/driver/accelgyro_bmi160.c
index cbbb78f7cb..325398f011 100644
--- a/driver/accelgyro_bmi160.c
+++ b/driver/accelgyro_bmi160.c
@@ -628,6 +628,81 @@ void normalize(const struct motion_sensor_t *s, vector_3_t v, uint8_t *data)
rotate(v, *s->rot_standard_ref, v);
}
+/*
+ * Manage gesture recognition.
+ * Defined even if host interface is not defined, to enable double tap even
+ * when the host does not deal with gesture.
+ */
+int manage_activity(struct motion_sensor_t *s,
+ enum motionsensor_activity activity,
+ int enable,
+ struct ec_motion_sense_activity *param)
+{
+ int ret;
+ struct bmi160_drv_data_t *data = BMI160_GET_DATA(s);
+
+ switch (activity) {
+#ifdef CONFIG_GESTURE_SIGMO
+ case MOTIONSENSE_ACTIVITY_SIG_MOTION: {
+ int tmp;
+ /* Set double tap interrupt and fifo*/
+ ret = raw_read8(s->addr, BMI160_INT_EN_0, &tmp);
+ if (ret)
+ return ret;
+ if (enable) {
+ /* We should use paramters from caller */
+ raw_write8(s->addr, BMI160_INT_MOTION_3,
+ BMI160_MOTION_PROOF_TIME(
+ CONFIG_GESTURE_SIGMO_PROOF_MS) <<
+ BMI160_MOTION_PROOF_OFF |
+ BMI160_MOTION_SKIP_TIME(
+ CONFIG_GESTURE_SIGMO_SKIP_MS) <<
+ BMI160_MOTION_SKIP_OFF |
+ BMI160_MOTION_SIG_MOT_SEL);
+ raw_write8(s->addr, BMI160_INT_MOTION_1,
+ BMI160_MOTION_TH(s,
+ CONFIG_GESTURE_SIGMO_THRES_MG));
+ tmp |= BMI160_INT_ANYMO_X_EN |
+ BMI160_INT_ANYMO_Y_EN |
+ BMI160_INT_ANYMO_Z_EN;
+ } else {
+ tmp &= ~(BMI160_INT_ANYMO_X_EN |
+ BMI160_INT_ANYMO_Y_EN |
+ BMI160_INT_ANYMO_Z_EN);
+ }
+ ret = raw_write8(s->addr, BMI160_INT_EN_0, tmp);
+ if (ret)
+ ret = EC_RES_UNAVAILABLE;
+ break;
+ }
+#endif
+ default:
+ ret = EC_RES_INVALID_PARAM;
+ }
+ if (ret == EC_RES_SUCCESS) {
+ if (enable) {
+ data->enabled_activities |= 1 << activity;
+ data->disabled_activities &= ~(1 << activity);
+ } else {
+ data->enabled_activities &= ~(1 << activity);
+ data->disabled_activities |= 1 << activity;
+ }
+ }
+ return ret;
+}
+
+#ifdef CONFIG_GESTURE_HOST_DETECTION
+int list_activities(struct motion_sensor_t *s,
+ uint32_t *enabled,
+ uint32_t *disabled)
+{
+ struct bmi160_drv_data_t *data = BMI160_GET_DATA(s);
+ *enabled = data->enabled_activities;
+ *disabled = data->disabled_activities;
+ return EC_RES_SUCCESS;
+}
+#endif
+
#ifdef CONFIG_ACCEL_INTERRUPTS
/**
* bmi160_interrupt - called when the sensor activate the interrupt line.
@@ -668,6 +743,9 @@ static int config_interrupt(const struct motion_sensor_t *s)
/* Map activity interrupt to int 1 */
tmp = 0;
+#ifdef CONFIG_GESTURE_SIGMO
+ tmp |= BMI160_INT_ANYMOTION;
+#endif
#ifdef CONFIG_GESTURE_SENSOR_BATTERY_TAP
tmp |= BMI160_INT_D_TAP;
#endif
@@ -721,6 +799,10 @@ static int irq_handler(struct motion_sensor_t *s, uint32_t *event)
if (interrupt & BMI160_D_TAP_INT)
*event |= CONFIG_GESTURE_TAP_EVENT;
#endif
+#ifdef CONFIG_GESTURE_SIGMO
+ if (interrupt & BMI160_SIGMOT_INT)
+ *event |= CONFIG_GESTURE_SIGMO_EVENT;
+#endif
/*
* No need to read the FIFO here, motion sense task is
* doing it on every interrupt.
@@ -963,6 +1045,14 @@ static int init(const struct motion_sensor_t *s)
data->flags &= ~(BMI160_FLAG_SEC_I2C_ENABLED |
(BMI160_FIFO_ALL_MASK <<
BMI160_FIFO_FLAG_OFFSET));
+#ifdef CONFIG_GESTURE_HOST_DETECTION
+ data->enabled_activities = 0;
+ data->disabled_activities = 0;
+#ifdef CONFIG_GESTURE_SIGMO
+ data->disabled_activities |=
+ 1 << MOTIONSENSE_ACTIVITY_SIG_MOTION;
+#endif
+#endif
/* To avoid gyro wakeup */
raw_write8(s->addr, BMI160_PMU_TRIGGER, 0);
}
@@ -1073,6 +1163,10 @@ const struct accelgyro_drv bmi160_drv = {
#ifdef CONFIG_ACCEL_FIFO
.load_fifo = load_fifo,
#endif
+#ifdef CONFIG_GESTURE_HOST_DETECTION
+ .manage_activity = manage_activity,
+ .list_activities = list_activities,
+#endif
};
struct bmi160_drv_data_t g_bmi160_data = {
diff --git a/driver/accelgyro_bmi160.h b/driver/accelgyro_bmi160.h
index 0d6103a14c..ee44f9262e 100644
--- a/driver/accelgyro_bmi160.h
+++ b/driver/accelgyro_bmi160.h
@@ -296,8 +296,28 @@ enum fifo_header {
#define BMI160_INT_MOTION_0 0x5f
#define BMI160_INT_MOTION_1 0x60
+/*
+ * The formula is defined in 2.11.25 (any motion interrupt [1]).
+ *
+ * if we want threshold at a (in mg), the register should be x, where
+ * x * 7.81mg = a, assuming a range of 4G, which is
+ * x * 4 * 1.953 = a so
+ * x = a * 1000 / range * 1953
+ */
+#define BMI160_MOTION_TH(_s, _mg) \
+ (MIN(((_mg) * 1000) / ((_s)->drv->get_range(_s) * 1953), 0xff))
#define BMI160_INT_MOTION_2 0x61
#define BMI160_INT_MOTION_3 0x62
+#define BMI160_MOTION_NO_MOT_SEL (1 << 0)
+#define BMI160_MOTION_SIG_MOT_SEL (1 << 1)
+#define BMI160_MOTION_SKIP_OFF 2
+#define BMI160_MOTION_SKIP_MASK 0x3
+#define BMI160_MOTION_SKIP_TIME(_ms) \
+ (MIN(__fls((_ms) / 1500), BMI160_MOTION_SKIP_MASK))
+#define BMI160_MOTION_PROOF_OFF 4
+#define BMI160_MOTION_PROOF_MASK 0x3
+#define BMI160_MOTION_PROOF_TIME(_ms) \
+ (MIN(__fls((_ms) / 250), BMI160_MOTION_PROOF_MASK))
#define BMI160_INT_TAP_0 0x63
#define BMI160_INT_TAP_1 0x64
@@ -409,6 +429,8 @@ enum bmi160_running_mode {
struct bmi160_drv_data_t {
struct accelgyro_saved_data_t saved_data[3];
uint8_t flags;
+ uint8_t enabled_activities;
+ uint8_t disabled_activities;
#ifdef CONFIG_MAG_BMI160_BMM150
struct bmm150_comp_registers comp_regs;
#endif