summaryrefslogtreecommitdiff
path: root/driver/accelgyro_bmi160.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/accelgyro_bmi160.c')
-rw-r--r--driver/accelgyro_bmi160.c780
1 files changed, 0 insertions, 780 deletions
diff --git a/driver/accelgyro_bmi160.c b/driver/accelgyro_bmi160.c
deleted file mode 100644
index f92f61d181..0000000000
--- a/driver/accelgyro_bmi160.c
+++ /dev/null
@@ -1,780 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/**
- * BMI160 accelerometer and gyro module for Chrome EC
- * 3D digital accelerometer & 3D digital gyroscope
- */
-
-#include "accelgyro.h"
-#include "common.h"
-#include "console.h"
-#include "accelgyro_bmi_common.h"
-#include "accelgyro_bmi160.h"
-#include "mag_bmm150.h"
-#include "hwtimer.h"
-#include "i2c.h"
-#include "math_util.h"
-#include "motion_orientation.h"
-#include "motion_sense_fifo.h"
-#include "spi.h"
-#include "task.h"
-#include "timer.h"
-#include "util.h"
-
-#define CPUTS(outstr) cputs(CC_ACCEL, outstr)
-#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args)
-
-#if defined(CONFIG_ZEPHYR) && defined(CONFIG_ACCEL_INTERRUPTS)
-/* Get the motion sensor ID of the BMI160 sensor that generates the interrupt.
- * The interrupt is converted to the event and transferred to motion sense task
- * that actually handles the interrupt.
- *
- * Here we use an alias (bmi160_int) to get the motion sensor ID. This alias
- * MUST be defined for this driver to work.
- * aliases {
- * bmi160-int = &base_accel;
- * };
- */
-#if DT_NODE_EXISTS(DT_ALIAS(bmi160_int))
-#define CONFIG_ACCELGYRO_BMI160_INT_EVENT \
- TASK_EVENT_MOTION_SENSOR_INTERRUPT(SENSOR_ID(DT_ALIAS(bmi160_int)))
-#endif
-#endif
-
-STATIC_IF(CONFIG_BMI_ORIENTATION_SENSOR) void irq_set_orientation(
- struct motion_sensor_t *s,
- int interrupt);
-
-STATIC_IF(CONFIG_ACCEL_FIFO) volatile uint32_t last_interrupt_timestamp;
-
-static int wakeup_time[] = {
- [MOTIONSENSE_TYPE_ACCEL] = 4,
- [MOTIONSENSE_TYPE_GYRO] = 80,
- [MOTIONSENSE_TYPE_MAG] = 1
-};
-
-/**
- * Control access to the compass on the secondary i2c interface:
- * enable values are:
- * 1: manual access, we can issue i2c to the compass
- * 0: data access: BMI160 gather data periodically from the compass.
- */
-static __maybe_unused int bmi160_sec_access_ctrl(
- const int port,
- const uint16_t i2c_spi_addr_flags,
- const int enable)
-{
- int mag_if_ctrl;
- bmi_read8(port, i2c_spi_addr_flags,
- BMI160_MAG_IF_1, &mag_if_ctrl);
- if (enable) {
- mag_if_ctrl |= BMI160_MAG_MANUAL_EN;
- mag_if_ctrl &= ~BMI160_MAG_READ_BURST_MASK;
- mag_if_ctrl |= BMI160_MAG_READ_BURST_1;
- } else {
- mag_if_ctrl &= ~BMI160_MAG_MANUAL_EN;
- mag_if_ctrl &= ~BMI160_MAG_READ_BURST_MASK;
- mag_if_ctrl |= BMI160_MAG_READ_BURST_8;
- }
- return bmi_write8(port, i2c_spi_addr_flags,
- BMI160_MAG_IF_1, mag_if_ctrl);
-}
-
-/**
- * Read register from compass.
- * Assuming we are in manual access mode, read compass i2c register.
- */
-int bmi160_sec_raw_read8(const int port,
- const uint16_t i2c_spi_addr_flags,
- const uint8_t reg, int *data_ptr)
-{
- /* Only read 1 bytes */
- bmi_write8(port, i2c_spi_addr_flags,
- BMI160_MAG_I2C_READ_ADDR, reg);
- return bmi_read8(port, i2c_spi_addr_flags,
- BMI160_MAG_I2C_READ_DATA, data_ptr);
-}
-
-/**
- * Write register from compass.
- * Assuming we are in manual access mode, write to compass i2c register.
- */
-int bmi160_sec_raw_write8(const int port,
- const uint16_t i2c_spi_addr_flags,
- const uint8_t reg, int data)
-{
- bmi_write8(port, i2c_spi_addr_flags,
- BMI160_MAG_I2C_WRITE_DATA, data);
- return bmi_write8(port, i2c_spi_addr_flags,
- BMI160_MAG_I2C_WRITE_ADDR, reg);
-}
-
-static int set_data_rate(const struct motion_sensor_t *s,
- int rate,
- int rnd)
-{
- int ret, normalized_rate;
- uint8_t reg_val;
- struct accelgyro_saved_data_t *data = BMI_GET_SAVED_DATA(s);
-
- if (rate == 0) {
- /* FIFO stop collecting events */
- if (IS_ENABLED(CONFIG_ACCEL_FIFO))
- bmi_enable_fifo(s, 0);
-
- /* go to suspend mode */
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_REG,
- BMI160_CMD_MODE_SUSPEND(s->type));
- msleep(3);
- data->odr = 0;
- if (IS_ENABLED(CONFIG_MAG_BMI_BMM150) &&
- (s->type == MOTIONSENSE_TYPE_MAG)) {
- struct mag_cal_t *moc = BMM150_CAL(s);
-
- moc->batch_size = 0;
- }
-
- return ret;
- } else if (data->odr == 0) {
- /* back from suspend mode. */
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_REG,
- BMI160_CMD_MODE_NORMAL(s->type));
- msleep(wakeup_time[s->type]);
- }
-
- ret = bmi_get_normalized_rate(s, rate, rnd, &normalized_rate, &reg_val);
- if (ret)
- return ret;
-
- /*
- * Lock accel resource to prevent another task from attempting
- * to write accel parameters until we are done.
- */
- mutex_lock(s->mutex);
-
- ret = bmi_set_reg8(s, BMI_CONF_REG(s->type),
- reg_val, BMI_ODR_MASK);
- if (ret != EC_SUCCESS)
- goto accel_cleanup;
-
- /* Now that we have set the odr, update the driver's value. */
- data->odr = normalized_rate;
-
- if (IS_ENABLED(CONFIG_MAG_BMI_BMM150) &&
- (s->type == MOTIONSENSE_TYPE_MAG)) {
- struct mag_cal_t *moc = BMM150_CAL(s);
-
- /* Reset the calibration */
- init_mag_cal(moc);
- /*
- * We need at least MIN_BATCH_SIZE amd we must have collected
- * for at least MIN_BATCH_WINDOW_US.
- * Given odr is in mHz, multiply by 1000x
- */
- moc->batch_size = MAX(
- MAG_CAL_MIN_BATCH_SIZE,
- (data->odr * 1000) / (MAG_CAL_MIN_BATCH_WINDOW_US));
- CPRINTS("Batch size: %d", moc->batch_size);
- }
-
- /*
- * FIFO start collecting events.
- * They will be discarded if AP does not want them.
- */
- if (IS_ENABLED(CONFIG_ACCEL_FIFO))
- bmi_enable_fifo(s, 1);
-
-accel_cleanup:
- mutex_unlock(s->mutex);
- return ret;
-}
-
-static int set_offset(const struct motion_sensor_t *s,
- const int16_t *offset,
- int16_t temp)
-{
- int ret, val98;
- intv3_t v = { offset[X], offset[Y], offset[Z] };
-
- rotate_inv(v, *s->rot_standard_ref, v);
-
- ret = bmi_read8(s->port, s->i2c_spi_addr_flags,
- BMI160_OFFSET_EN_GYR98, &val98);
- if (ret != 0)
- return ret;
-
- switch (s->type) {
- case MOTIONSENSE_TYPE_ACCEL:
- ret = bmi_set_accel_offset(s, v);
- if (ret != EC_SUCCESS)
- return ret;
-
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_OFFSET_EN_GYR98,
- val98 | BMI160_OFFSET_ACC_EN);
- break;
- case MOTIONSENSE_TYPE_GYRO:
- ret = bmi_set_gyro_offset(s, v, &val98);
- if (ret != EC_SUCCESS)
- return ret;
-
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_OFFSET_EN_GYR98,
- val98 | BMI160_OFFSET_GYRO_EN);
- break;
-#ifdef CONFIG_MAG_BMI_BMM150
- case MOTIONSENSE_TYPE_MAG:
- ret = bmm150_set_offset(s, v);
- break;
-#endif /* defined(CONFIG_MAG_BMI_BMM150) */
- default:
- ret = EC_RES_INVALID_PARAM;
- }
- return ret;
-}
-
-static int perform_calib(struct motion_sensor_t *s, int enable)
-{
- int ret, val, en_flag, status, rate, range = s->current_range;
- timestamp_t deadline, timeout;
-
- if (!enable)
- return EC_SUCCESS;
-
- rate = bmi_get_data_rate(s);
- /*
- * Temporary set frequency to 100Hz to get enough data in a short
- * period of time.
- */
- ret = set_data_rate(s, 100000, 0);
- if (ret != EC_SUCCESS)
- goto end_perform_calib;
-
- switch (s->type) {
- case MOTIONSENSE_TYPE_ACCEL:
- /* We assume the device is laying flat for calibration */
- if (s->rot_standard_ref == NULL ||
- (*s->rot_standard_ref)[2][2] > INT_TO_FP(0))
- val = BMI160_FOC_ACC_PLUS_1G;
- else
- val = BMI160_FOC_ACC_MINUS_1G;
- val = (BMI160_FOC_ACC_0G << BMI160_FOC_ACC_X_OFFSET) |
- (BMI160_FOC_ACC_0G << BMI160_FOC_ACC_Y_OFFSET) |
- (val << BMI160_FOC_ACC_Z_OFFSET);
- en_flag = BMI160_OFFSET_ACC_EN;
- /*
- * Temporary set range to minimum to run calibration with
- * full sensitivity
- */
- bmi_set_range(s, 2, 0);
- /* Timeout for accelerometer calibration */
- timeout.val = 400 * MSEC;
- break;
- case MOTIONSENSE_TYPE_GYRO:
- val = BMI160_FOC_GYRO_EN;
- en_flag = BMI160_OFFSET_GYRO_EN;
- /*
- * Temporary set range to minimum to run calibration with
- * full sensitivity
- */
- bmi_set_range(s, 125, 0);
- /* Timeout for gyroscope calibration */
- timeout.val = 800 * MSEC;
- break;
- default:
- /* Not supported on Magnetometer */
- ret = EC_RES_INVALID_PARAM;
- goto end_perform_calib;
- }
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_FOC_CONF, val);
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_REG, BMI160_CMD_START_FOC);
- deadline.val = get_time().val + timeout.val;
- do {
- if (timestamp_expired(deadline, NULL)) {
- ret = EC_RES_TIMEOUT;
- goto end_perform_calib;
- }
- msleep(50);
- ret = bmi_read8(s->port, s->i2c_spi_addr_flags,
- BMI160_STATUS, &status);
- if (ret != EC_SUCCESS)
- goto end_perform_calib;
- } while ((status & BMI160_FOC_RDY) == 0);
-
- /* Calibration is successful, and loaded, use the result */
- ret = bmi_enable_reg8(s, BMI160_OFFSET_EN_GYR98, en_flag, 1);
-end_perform_calib:
- bmi_set_range(s, range, 0);
- set_data_rate(s, rate, 0);
- return ret;
-}
-
-/*
- * Manage gesture recognition.
- * Defined even if host interface is not defined, to enable double tap even
- * when the host does not deal with gesture.
- */
-#ifdef CONFIG_GESTURE_HOST_DETECTION
-static int manage_activity(const struct motion_sensor_t *s,
- enum motionsensor_activity activity,
- int enable,
- const struct ec_motion_sense_activity *param)
-{
- int ret;
- struct bmi_drv_data_t *data = BMI_GET_DATA(s);
-
- switch (activity) {
-#ifdef CONFIG_GESTURE_SIGMO
- case MOTIONSENSE_ACTIVITY_SIG_MOTION: {
- if (enable) {
- /* We should use parameters from caller */
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- 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);
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_INT_MOTION_1,
- BMI160_MOTION_TH(s,
- CONFIG_GESTURE_SIGMO_THRES_MG));
- }
- ret = bmi_enable_reg8(s, BMI160_INT_EN_0,
- BMI160_INT_ANYMO_X_EN |
- BMI160_INT_ANYMO_Y_EN |
- BMI160_INT_ANYMO_Z_EN,
- enable);
- if (ret)
- ret = EC_RES_UNAVAILABLE;
- break;
- }
-#endif
-#ifdef CONFIG_GESTURE_SENSOR_DOUBLE_TAP
- case MOTIONSENSE_ACTIVITY_DOUBLE_TAP: {
- /* Set double tap interrupt */
- ret = bmi_enable_reg8(s, BMI160_INT_EN_0,
- BMI160_INT_D_TAP_EN,
- enable);
- 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 &= ~BIT(activity);
- } else {
- data->enabled_activities &= ~BIT(activity);
- data->disabled_activities |= 1 << activity;
- }
- }
- return ret;
-}
-#endif
-
-static __maybe_unused int config_interrupt(const struct motion_sensor_t *s)
-{
- int ret, tmp;
-
- if (s->type != MOTIONSENSE_TYPE_ACCEL)
- return EC_SUCCESS;
-
- mutex_lock(s->mutex);
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_REG, BMI160_CMD_FIFO_FLUSH);
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_REG, BMI160_CMD_INT_RESET);
-
- if (IS_ENABLED(CONFIG_GESTURE_SENSOR_DOUBLE_TAP)) {
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_INT_TAP_0,
- BMI160_TAP_DUR(s, CONFIG_GESTURE_TAP_MAX_INTERSTICE_T));
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_INT_TAP_1,
- BMI160_TAP_TH(s, CONFIG_GESTURE_TAP_THRES_MG));
- }
- /* only use orientation sensor on the lid sensor */
- if (IS_ENABLED(CONFIG_BMI_ORIENTATION_SENSOR) &&
- (s->location == MOTIONSENSE_LOC_LID)) {
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_INT_ORIENT_0,
- BMI160_INT_ORIENT_0_INIT_VAL);
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_INT_ORIENT_1,
- BMI160_INT_ORIENT_1_INIT_VAL);
- }
-
- if (IS_ENABLED(CONFIG_ACCELGYRO_BMI160_INT2_OUTPUT)) {
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_INT_LATCH, BMI160_LATCH_5MS);
- } else {
- /* Also, configure int2 as an external input. */
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_INT_LATCH,
- BMI160_INT2_INPUT_EN | BMI160_LATCH_5MS);
- }
-
- /* configure int1 as an interrupt */
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_INT_OUT_CTRL,
- BMI160_INT_CTRL(1, OUTPUT_EN));
-
- /* Map activity interrupt to int 1 */
- tmp = 0;
- if (IS_ENABLED(CONFIG_GESTURE_SIGMO)) {
- tmp |= BMI160_INT_ANYMOTION;
- } else if (IS_ENABLED(CONFIG_GESTURE_SENSOR_DOUBLE_TAP)) {
- tmp |= BMI160_INT_D_TAP;
- } else if (IS_ENABLED(CONFIG_BMI_ORIENTATION_SENSOR) &&
- (s->location == MOTIONSENSE_LOC_LID)) {
- /* enable orientation interrupt for lid sensor only */
- tmp |= BMI160_INT_ORIENT;
- }
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_INT_MAP_REG(1), tmp);
-
- if (IS_ENABLED(CONFIG_ACCEL_FIFO)) {
- /* map fifo water mark to int 1 */
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_INT_FIFO_MAP,
- BMI160_INT_MAP(1, FWM) |
- BMI160_INT_MAP(1, FFULL));
-
- /*
- * Configure fifo watermark to int whenever there's any data in
- * there
- */
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_FIFO_CONFIG_0, 1);
- if (IS_ENABLED(CONFIG_ACCELGYRO_BMI160_INT2_OUTPUT))
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_FIFO_CONFIG_1,
- BMI160_FIFO_HEADER_EN);
- else
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_FIFO_CONFIG_1,
- BMI160_FIFO_TAG_INT2_EN |
- BMI160_FIFO_HEADER_EN);
-
- /* Set fifo*/
- bmi_enable_reg8(s, BMI160_INT_EN_1,
- BMI160_INT_FWM_EN | BMI160_INT_FFUL_EN, 1);
- }
- mutex_unlock(s->mutex);
- return ret;
-}
-
-#ifdef CONFIG_ACCEL_INTERRUPTS
-#ifdef CONFIG_BMI_ORIENTATION_SENSOR
-static void irq_set_orientation(struct motion_sensor_t *s,
- int interrupt)
-{
- int shifted_masked_orientation =
- (interrupt >> 24) & BMI160_ORIENT_XY_MASK;
- if (BMI_GET_DATA(s)->raw_orientation != shifted_masked_orientation) {
- enum motionsensor_orientation orientation =
- MOTIONSENSE_ORIENTATION_UNKNOWN;
-
- BMI_GET_DATA(s)->raw_orientation =
- shifted_masked_orientation;
-
- switch (shifted_masked_orientation) {
- case BMI160_ORIENT_PORTRAIT:
- orientation = MOTIONSENSE_ORIENTATION_PORTRAIT;
- break;
- case BMI160_ORIENT_PORTRAIT_INVERT:
- orientation =
- MOTIONSENSE_ORIENTATION_UPSIDE_DOWN_PORTRAIT;
- break;
- case BMI160_ORIENT_LANDSCAPE:
- orientation = MOTIONSENSE_ORIENTATION_LANDSCAPE;
- break;
- case BMI160_ORIENT_LANDSCAPE_INVERT:
- orientation =
- MOTIONSENSE_ORIENTATION_UPSIDE_DOWN_LANDSCAPE;
- break;
- default:
- break;
- }
- orientation = motion_orientation_remap(s, orientation);
- *motion_orientation_ptr(s) = orientation;
- }
-}
-#endif /* CONFIG_BMI_ORIENTATION_SENSOR */
-
-/**
- * bmi160_interrupt - called when the sensor activates the interrupt line.
- *
- * This is a "top half" interrupt handler, it just asks motion sense ask
- * to schedule the "bottom half", ->irq_handler().
- */
-void bmi160_interrupt(enum gpio_signal signal)
-{
- if (IS_ENABLED(CONFIG_ACCEL_FIFO))
- last_interrupt_timestamp = __hw_clock_source_read();
-
- task_set_event(TASK_ID_MOTIONSENSE, CONFIG_ACCELGYRO_BMI160_INT_EVENT);
-}
-
-/**
- * irq_handler - bottom half of the interrupt stack.
- * Ran from the motion_sense task, finds the events that raised the interrupt.
- *
- * For now, we just print out. We should set a bitmask motion sense code will
- * act upon.
- */
-static int irq_handler(struct motion_sensor_t *s,
- uint32_t *event)
-{
- uint32_t interrupt;
- int8_t has_read_fifo = 0;
- int rv;
-
- if ((s->type != MOTIONSENSE_TYPE_ACCEL) ||
- (!(*event & CONFIG_ACCELGYRO_BMI160_INT_EVENT)))
- return EC_ERROR_NOT_HANDLED;
-
- do {
- rv = bmi_read16(s->port, s->i2c_spi_addr_flags,
- BMI160_INT_STATUS_0, &interrupt);
- /*
- * Bail out of this loop there was an error reading the register
- */
- if (rv)
- return rv;
-
- if (IS_ENABLED(CONFIG_GESTURE_SENSOR_DOUBLE_TAP) &&
- (interrupt & BMI160_D_TAP_INT))
- *event |= TASK_EVENT_MOTION_ACTIVITY_INTERRUPT(
- MOTIONSENSE_ACTIVITY_DOUBLE_TAP);
- if (IS_ENABLED(CONFIG_GESTURE_SIGMO) &&
- (interrupt & BMI160_SIGMOT_INT))
- *event |= TASK_EVENT_MOTION_ACTIVITY_INTERRUPT(
- MOTIONSENSE_ACTIVITY_SIG_MOTION);
- if (IS_ENABLED(CONFIG_ACCEL_FIFO) &&
- (interrupt & (BMI160_FWM_INT | BMI160_FFULL_INT))) {
- bmi_load_fifo(s, last_interrupt_timestamp);
- has_read_fifo = 1;
- }
- if (IS_ENABLED(CONFIG_BMI_ORIENTATION_SENSOR))
- irq_set_orientation(s, interrupt);
- } while (interrupt != 0);
-
- if (IS_ENABLED(CONFIG_ACCEL_FIFO) && has_read_fifo)
- motion_sense_fifo_commit_data();
-
- return EC_SUCCESS;
-}
-#endif /* CONFIG_ACCEL_INTERRUPTS */
-
-static int init(struct motion_sensor_t *s)
-{
- int ret = 0, tmp, i;
- struct accelgyro_saved_data_t *saved_data = BMI_GET_SAVED_DATA(s);
-
- ret = bmi_read8(s->port, s->i2c_spi_addr_flags,
- BMI160_CHIP_ID, &tmp);
- if (ret)
- return EC_ERROR_UNKNOWN;
-
- if (tmp != BMI160_CHIP_ID_MAJOR && tmp != BMI168_CHIP_ID_MAJOR) {
- /* The device may be lock on paging mode. Try to unlock it. */
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B0);
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B1);
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B2);
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_EXT_MODE_ADDR, BMI160_CMD_PAGING_EN);
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_EXT_MODE_ADDR, 0);
- return EC_ERROR_ACCESS_DENIED;
- }
-
-
- if (s->type == MOTIONSENSE_TYPE_ACCEL) {
- struct bmi_drv_data_t *data = BMI_GET_DATA(s);
-
- /* Reset the chip to be in a good state */
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_REG, BMI160_CMD_SOFT_RESET);
- msleep(1);
- data->flags &= ~(BMI_FLAG_SEC_I2C_ENABLED |
- (BMI_FIFO_ALL_MASK <<
- BMI_FIFO_FLAG_OFFSET));
- if (IS_ENABLED(CONFIG_GESTURE_HOST_DETECTION)) {
- data->enabled_activities = 0;
- data->disabled_activities = 0;
- if (IS_ENABLED(CONFIG_GESTURE_SIGMO))
- data->disabled_activities |=
- BIT(MOTIONSENSE_ACTIVITY_SIG_MOTION);
- if (IS_ENABLED(CONFIG_GESTURE_SENSOR_DOUBLE_TAP))
- data->disabled_activities |=
- BIT(MOTIONSENSE_ACTIVITY_DOUBLE_TAP);
- }
- /* To avoid gyro wakeup */
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_PMU_TRIGGER, 0);
- }
-
-#ifdef CONFIG_BMI_SEC_I2C
- if (s->type == MOTIONSENSE_TYPE_MAG) {
- struct bmi_drv_data_t *data = BMI_GET_DATA(s);
-
- /*
- * To be able to configure the real magnetometer, we must set
- * the BMI160 magnetometer part (a pass through) in normal mode.
- */
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_REG, BMI160_CMD_MODE_NORMAL(s->type));
- msleep(wakeup_time[s->type]);
-
- if ((data->flags & BMI_FLAG_SEC_I2C_ENABLED) == 0) {
- int ext_page_reg;
- /* Enable secondary interface */
- /*
- * This is not part of the normal configuration but from
- * code on Bosh github repo:
- * https://github.com/BoschSensortec/BMI160_driver
- *
- * Magic command sequences
- */
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B0);
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B1);
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B2);
-
- /*
- * Change the register page to target mode, to change
- * the internal pull ups of the secondary interface.
- */
- bmi_enable_reg8(s, BMI160_CMD_EXT_MODE_ADDR,
- BMI160_CMD_TARGET_PAGE, 1);
- bmi_enable_reg8(s, BMI160_CMD_EXT_MODE_ADDR,
- BMI160_CMD_PAGING_EN, 1);
- bmi_enable_reg8(s, BMI160_COM_C_TRIM_ADDR,
- BMI160_COM_C_TRIM, 1);
- bmi_enable_reg8(s, BMI160_CMD_EXT_MODE_ADDR,
- BMI160_CMD_TARGET_PAGE, 0);
- bmi_read8(s->port, s->i2c_spi_addr_flags,
- BMI160_CMD_EXT_MODE_ADDR, &ext_page_reg);
-
- /* Set the i2c address of the compass */
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_MAG_IF_0,
- I2C_STRIP_FLAGS(
- CONFIG_ACCELGYRO_SEC_ADDR_FLAGS)
- << 1);
-
- /* Enable the secondary interface as I2C */
- ret = bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_IF_CONF,
- BMI160_IF_MODE_AUTO_I2C <<
- BMI160_IF_MODE_OFF);
- data->flags |= BMI_FLAG_SEC_I2C_ENABLED;
- }
-
-
- bmi160_sec_access_ctrl(s->port, s->i2c_spi_addr_flags, 1);
-
- ret = bmm150_init(s);
- if (ret)
- /* Leave the compass open for tinkering. */
- return ret;
-
- /* Leave the address for reading the data */
- bmi_write8(s->port, s->i2c_spi_addr_flags,
- BMI160_MAG_I2C_READ_ADDR, BMM150_BASE_DATA);
- /*
- * Put back the secondary interface in normal mode.
- * BMI160 will poll based on the configure ODR.
- */
- bmi160_sec_access_ctrl(s->port, s->i2c_spi_addr_flags, 0);
-
- /*
- * Clean interrupt event that may have occurred while the
- * BMI160 was in management mode.
- */
- task_set_event(TASK_ID_MOTIONSENSE,
- CONFIG_ACCELGYRO_BMI160_INT_EVENT);
- }
-#endif
-
- for (i = X; i <= Z; i++)
- saved_data->scale[i] = MOTION_SENSE_DEFAULT_SCALE;
- /*
- * The sensor is in Suspend mode at init,
- * so set data rate to 0.
- */
- saved_data->odr = 0;
-
- if (IS_ENABLED(CONFIG_ACCEL_INTERRUPTS) &&
- (s->type == MOTIONSENSE_TYPE_ACCEL))
- ret = config_interrupt(s);
-
- return sensor_init_done(s);
-}
-
-const struct accelgyro_drv bmi160_drv = {
- .init = init,
- .read = bmi_read,
- .set_range = bmi_set_range,
- .get_resolution = bmi_get_resolution,
- .set_data_rate = set_data_rate,
- .get_data_rate = bmi_get_data_rate,
- .set_offset = set_offset,
- .get_scale = bmi_get_scale,
- .set_scale = bmi_set_scale,
- .get_offset = bmi_get_offset,
- .perform_calib = perform_calib,
- .read_temp = bmi_read_temp,
-#ifdef CONFIG_ACCEL_INTERRUPTS
- .irq_handler = irq_handler,
-#endif
-#ifdef CONFIG_GESTURE_HOST_DETECTION
- .manage_activity = manage_activity,
- .list_activities = bmi_list_activities,
-#endif
-#ifdef CONFIG_BODY_DETECTION
- .get_rms_noise = bmi_get_rms_noise,
-#endif
-};
-
-#ifdef CONFIG_CMD_I2C_STRESS_TEST_ACCEL
-struct i2c_stress_test_dev bmi160_i2c_stress_test_dev = {
- .reg_info = {
- .read_reg = BMI160_CHIP_ID,
- .read_val = BMI160_CHIP_ID_MAJOR,
- .write_reg = BMI160_PMU_TRIGGER,
- },
- .i2c_read = &bmi_read8,
- .i2c_write = &bmi_write8,
-};
-#endif /* CONFIG_CMD_I2C_STRESS_TEST_ACCEL */
-
-/*
- * TODO(chingkang): Replace bmi160_get_sensor_temp in some board config to
- * bmi_get_sensor_temp. Then, remove this definition.
- */
-int bmi160_get_sensor_temp(int idx, int *temp_ptr)
-{
- return bmi_get_sensor_temp(idx, temp_ptr);
-}