diff options
Diffstat (limited to 'driver/accelgyro_bmi160.c')
-rw-r--r-- | driver/accelgyro_bmi160.c | 780 |
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, ®_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); -} |