diff options
author | Ching-Kang Yen <chingkang@chromium.org> | 2020-03-31 19:10:36 +0800 |
---|---|---|
committer | Ching-Kang Yen <chingkang@chromium.org> | 2020-04-23 13:42:42 +0000 |
commit | 86be30f5c4220112c6303c176f12096151285515 (patch) | |
tree | cfeeb602160484cfd88b29ddaaf741ac1e09d9e8 | |
parent | 246044881c894aac0f552e5218b8207f74d105f7 (diff) | |
download | chrome-ec-86be30f5c4220112c6303c176f12096151285515.tar.gz |
driver: Add BMI common code
Add accelgyro_bmi_common.(c/h) for the code shared among the BMI.
BRANCH=None
BUG=b:146144827
TEST=make -j4 BOARD=ampton
Then, flash the ec.bin into DUT, check sensor data is available on DUT
by "ectool motionsense".
TEST=make buildall -j
Change-Id: Ia56ffb0896943b08640b3d6ca96324ac5e7d93a0
Signed-off-by: Ching-Kang Yen <chingkang@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2130146
Reviewed-by: Gwendal Grignou <gwendal@chromium.org>
-rw-r--r-- | driver/accelgyro_bmi160.c | 995 | ||||
-rw-r--r-- | driver/accelgyro_bmi160.h | 90 | ||||
-rw-r--r-- | driver/accelgyro_bmi_common.c | 837 | ||||
-rw-r--r-- | driver/accelgyro_bmi_common.h | 327 | ||||
-rw-r--r-- | driver/build.mk | 4 | ||||
-rw-r--r-- | driver/mag_bmm150.c | 4 | ||||
-rw-r--r-- | driver/mag_bmm150.h | 17 | ||||
-rw-r--r-- | driver/mag_lis2mdl.c | 2 | ||||
-rw-r--r-- | driver/mag_lis2mdl.h | 2 | ||||
-rw-r--r-- | include/config.h | 44 |
10 files changed, 1346 insertions, 976 deletions
diff --git a/driver/accelgyro_bmi160.c b/driver/accelgyro_bmi160.c index 2c29295988..7beaa0de04 100644 --- a/driver/accelgyro_bmi160.c +++ b/driver/accelgyro_bmi160.c @@ -11,9 +11,9 @@ #include "accelgyro.h" #include "common.h" #include "console.h" +#include "driver/accelgyro_bmi_common.h" #include "driver/accelgyro_bmi160.h" #include "driver/mag_bmm150.h" -#include "hooks.h" #include "hwtimer.h" #include "i2c.h" #include "math_util.h" @@ -29,223 +29,13 @@ STATIC_IF(CONFIG_ACCEL_FIFO) volatile uint32_t last_interrupt_timestamp; -/* - * Struct for pairing an engineering value with the register value for a - * parameter. - */ -struct accel_param_pair { - int val; /* Value in engineering units. */ - int reg_val; /* Corresponding register value. */ -}; - -/* List of range values in +/-G's and their associated register values. */ -static const struct accel_param_pair g_ranges[] = { - {2, BMI160_GSEL_2G}, - {4, BMI160_GSEL_4G}, - {8, BMI160_GSEL_8G}, - {16, BMI160_GSEL_16G} -}; - -/* - * List of angular rate range values in +/-dps's - * and their associated register values. - */ -const struct accel_param_pair dps_ranges[] = { - {125, BMI160_DPS_SEL_125}, - {250, BMI160_DPS_SEL_250}, - {500, BMI160_DPS_SEL_500}, - {1000, BMI160_DPS_SEL_1000}, - {2000, BMI160_DPS_SEL_2000} -}; - static int wakeup_time[] = { [MOTIONSENSE_TYPE_ACCEL] = 4, [MOTIONSENSE_TYPE_GYRO] = 80, [MOTIONSENSE_TYPE_MAG] = 1 }; -static inline const struct accel_param_pair *get_range_table( - enum motionsensor_type type, int *psize) -{ - if (MOTIONSENSE_TYPE_ACCEL == type) { - if (psize) - *psize = ARRAY_SIZE(g_ranges); - return g_ranges; - } else { - if (psize) - *psize = ARRAY_SIZE(dps_ranges); - return dps_ranges; - } -} - -static inline int get_xyz_reg(enum motionsensor_type type) -{ - switch (type) { - case MOTIONSENSE_TYPE_ACCEL: - return BMI160_ACC_X_L_G; - case MOTIONSENSE_TYPE_GYRO: - return BMI160_GYR_X_L_G; - case MOTIONSENSE_TYPE_MAG: - return BMI160_MAG_X_L_G; - default: - return -1; - } -} - -/** - * @return reg value that matches the given engineering value passed in. - * The round_up flag is used to specify whether to round up or down. - * Note, this function always returns a valid reg value. If the request is - * outside the range of values, it returns the closest valid reg value. - */ -static int get_reg_val(const int eng_val, const int round_up, - const struct accel_param_pair *pairs, const int size) -{ - int i; - - for (i = 0; i < size - 1; i++) { - if (eng_val <= pairs[i].val) - break; - - if (eng_val < pairs[i+1].val) { - if (round_up) - i += 1; - break; - } - } - return pairs[i].reg_val; -} - -/** - * @return engineering value that matches the given reg val - */ -static int get_engineering_val(const int reg_val, - const struct accel_param_pair *pairs, const int size) -{ - int i; - - for (i = 0; i < size; i++) { - if (reg_val == pairs[i].reg_val) - break; - } - return pairs[i].val; -} - -#ifdef CONFIG_SPI_ACCEL_PORT -static inline int spi_raw_read(const int addr, const uint8_t reg, - uint8_t *data, const int len) -{ - uint8_t cmd = 0x80 | reg; - - return spi_transaction(&spi_devices[addr], &cmd, 1, data, len); -} -#endif -/** - * Read 8bit register from accelerometer. - */ -static int raw_read8(const int port, - const uint16_t i2c_spi_addr_flags, - const int reg, int *data_ptr) -{ - int rv = -EC_ERROR_PARAM1; - - if (SLAVE_IS_SPI(i2c_spi_addr_flags)) { -#ifdef CONFIG_SPI_ACCEL_PORT - uint8_t val; - rv = spi_raw_read(SLAVE_GET_SPI_ADDR(i2c_spi_addr_flags), - reg, &val, 1); - if (rv == EC_SUCCESS) - *data_ptr = val; -#endif - } else { -#ifdef I2C_PORT_ACCEL - rv = i2c_read8(port, i2c_spi_addr_flags, - reg, data_ptr); -#endif - } - return rv; -} - -/** - * Write 8bit register from accelerometer. - */ -static int raw_write8(const int port, - const uint16_t i2c_spi_addr_flags, - const int reg, int data) -{ - int rv = -EC_ERROR_PARAM1; - - if (SLAVE_IS_SPI(i2c_spi_addr_flags)) { -#ifdef CONFIG_SPI_ACCEL_PORT - uint8_t cmd[2] = { reg, data }; - rv = spi_transaction( - &spi_devices[SLAVE_GET_SPI_ADDR(i2c_spi_addr_flags)], - cmd, 2, NULL, 0); -#endif - } else { -#ifdef I2C_PORT_ACCEL - rv = i2c_write8(port, i2c_spi_addr_flags, - reg, data); -#endif - } - /* - * From Bosch: BMI160 needs a delay of 450us after each write if it - * is in suspend mode, otherwise the operation may be ignored by - * the sensor. Given we are only doing write during init, add - * the delay inconditionally. - */ - msleep(1); - return rv; -} - -#ifdef CONFIG_ACCEL_INTERRUPTS -/** - * Read 32bit register from accelerometer. - */ -static int raw_read32(const int port, - const uint16_t i2c_spi_addr_flags, - const uint8_t reg, int *data_ptr) -{ - int rv = -EC_ERROR_PARAM1; - if (SLAVE_IS_SPI(i2c_spi_addr_flags)) { -#ifdef CONFIG_SPI_ACCEL_PORT - rv = spi_raw_read(SLAVE_GET_SPI_ADDR(i2c_spi_addr_flags), - reg, (uint8_t *)data_ptr, 4); -#endif - } else { -#ifdef I2C_PORT_ACCEL - rv = i2c_read32(port, i2c_spi_addr_flags, - reg, data_ptr); -#endif - } - return rv; -} -#endif /* defined(CONFIG_ACCEL_INTERRUPTS) */ - -/** - * Read n bytes from accelerometer. - */ -static int raw_read_n(const int port, - const uint16_t i2c_spi_addr_flags, - const uint8_t reg, uint8_t *data_ptr, const int len) -{ - int rv = -EC_ERROR_PARAM1; - - if (SLAVE_IS_SPI(i2c_spi_addr_flags)) { -#ifdef CONFIG_SPI_ACCEL_PORT - rv = spi_raw_read(SLAVE_GET_SPI_ADDR(i2c_spi_addr_flags), - reg, data_ptr, len); -#endif - } else { -#ifdef I2C_PORT_ACCEL - rv = i2c_read_block(port, i2c_spi_addr_flags, - reg, data_ptr, len); -#endif - } - return rv; -} - -#ifdef CONFIG_BMI160_SEC_I2C +#ifdef CONFIG_BMI_SEC_I2C /** * Control access to the compass on the secondary i2c interface: * enable values are: @@ -257,7 +47,7 @@ static int bmi160_sec_access_ctrl(const int port, const int enable) { int mag_if_ctrl; - raw_read8(port, i2c_spi_addr_flags, + bmi_read8(port, i2c_spi_addr_flags, BMI160_MAG_IF_1, &mag_if_ctrl); if (enable) { mag_if_ctrl |= BMI160_MAG_MANUAL_EN; @@ -268,7 +58,7 @@ static int bmi160_sec_access_ctrl(const int port, mag_if_ctrl &= ~BMI160_MAG_READ_BURST_MASK; mag_if_ctrl |= BMI160_MAG_READ_BURST_8; } - return raw_write8(port, i2c_spi_addr_flags, + return bmi_write8(port, i2c_spi_addr_flags, BMI160_MAG_IF_1, mag_if_ctrl); } @@ -281,9 +71,9 @@ int bmi160_sec_raw_read8(const int port, const uint8_t reg, int *data_ptr) { /* Only read 1 bytes */ - raw_write8(port, i2c_spi_addr_flags, + bmi_write8(port, i2c_spi_addr_flags, BMI160_MAG_I2C_READ_ADDR, reg); - return raw_read8(port, i2c_spi_addr_flags, + return bmi_read8(port, i2c_spi_addr_flags, BMI160_MAG_I2C_READ_DATA, data_ptr); } @@ -295,145 +85,51 @@ int bmi160_sec_raw_write8(const int port, const uint16_t i2c_spi_addr_flags, const uint8_t reg, int data) { - raw_write8(port, i2c_spi_addr_flags, + bmi_write8(port, i2c_spi_addr_flags, BMI160_MAG_I2C_WRITE_DATA, data); - return raw_write8(port, i2c_spi_addr_flags, + return bmi_write8(port, i2c_spi_addr_flags, BMI160_MAG_I2C_WRITE_ADDR, reg); } #endif -static int enable_fifo(const struct motion_sensor_t *s, int enable) -{ - struct bmi160_drv_data_t *data = BMI160_GET_DATA(s); - int ret, val; - - if (enable) { - /* FIFO start collecting events */ - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - BMI160_FIFO_CONFIG_1, &val); - val |= BMI160_FIFO_SENSOR_EN(s->type); - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - BMI160_FIFO_CONFIG_1, val); - if (ret == EC_SUCCESS) - data->flags |= 1 << (s->type + BMI160_FIFO_FLAG_OFFSET); - - } else { - /* FIFO stop collecting events */ - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - BMI160_FIFO_CONFIG_1, &val); - val &= ~BMI160_FIFO_SENSOR_EN(s->type); - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - BMI160_FIFO_CONFIG_1, val); - if (ret == EC_SUCCESS) - data->flags &= - ~(1 << (s->type + BMI160_FIFO_FLAG_OFFSET)); - } - return ret; -} - -static int set_range(const struct motion_sensor_t *s, - int range, - int rnd) -{ - int ret, range_tbl_size; - uint8_t reg_val, ctrl_reg; - const struct accel_param_pair *ranges; - struct accelgyro_saved_data_t *data = BMI160_GET_SAVED_DATA(s); - - if (s->type == MOTIONSENSE_TYPE_MAG) { - data->range = range; - return EC_SUCCESS; - } - - ctrl_reg = BMI160_RANGE_REG(s->type); - ranges = get_range_table(s->type, &range_tbl_size); - reg_val = get_reg_val(range, rnd, ranges, range_tbl_size); - - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - ctrl_reg, reg_val); - /* Now that we have set the range, update the driver's value. */ - if (ret == EC_SUCCESS) - data->range = get_engineering_val(reg_val, ranges, - range_tbl_size); - return ret; -} - -static int get_range(const struct motion_sensor_t *s) -{ - struct accelgyro_saved_data_t *data = BMI160_GET_SAVED_DATA(s); - - return data->range; -} - -static int get_resolution(const struct motion_sensor_t *s) -{ - return BMI160_RESOLUTION; -} - static int set_data_rate(const struct motion_sensor_t *s, int rate, int rnd) { - int ret, val, normalized_rate; - uint8_t ctrl_reg, reg_val; - struct accelgyro_saved_data_t *data = BMI160_GET_SAVED_DATA(s); -#ifdef CONFIG_MAG_BMI160_BMM150 + int ret, normalized_rate; + uint8_t reg_val; + struct accelgyro_saved_data_t *data = BMI_GET_SAVED_DATA(s); +#ifdef CONFIG_MAG_BMI_BMM150 struct mag_cal_t *moc = BMM150_CAL(s); #endif if (rate == 0) { /* FIFO stop collecting events */ if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - enable_fifo(s, 0); + bmi_enable_fifo(s, 0); /* go to suspend mode */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_CMD_REG, BMI160_CMD_MODE_SUSPEND(s->type)); msleep(3); data->odr = 0; -#ifdef CONFIG_MAG_BMI160_BMM150 +#ifdef CONFIG_MAG_BMI_BMM150 if (s->type == MOTIONSENSE_TYPE_MAG) moc->batch_size = 0; #endif return ret; } else if (data->odr == 0) { /* back from suspend mode. */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_CMD_REG, BMI160_CMD_MODE_NORMAL(s->type)); msleep(wakeup_time[s->type]); } - ctrl_reg = BMI160_CONF_REG(s->type); - reg_val = BMI160_ODR_TO_REG(rate); - normalized_rate = BMI160_REG_TO_ODR(reg_val); - if (rnd && (normalized_rate < rate)) { - reg_val++; - normalized_rate = BMI160_REG_TO_ODR(reg_val); - } - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - if (normalized_rate > BMI160_ACCEL_MAX_FREQ || - normalized_rate < BMI160_ACCEL_MIN_FREQ) - return EC_RES_INVALID_PARAM; - break; - case MOTIONSENSE_TYPE_GYRO: - if (normalized_rate > BMI160_GYRO_MAX_FREQ || - normalized_rate < BMI160_GYRO_MIN_FREQ) - return EC_RES_INVALID_PARAM; - break; -#ifdef CONFIG_MAG_BMI160_BMM150 - case MOTIONSENSE_TYPE_MAG: - /* We use the regular preset we can go about 100Hz */ - if (reg_val > BMI160_ODR_100HZ || reg_val < BMI160_ODR_0_78HZ) - return EC_RES_INVALID_PARAM; - break; -#endif - - default: - return EC_RES_INVALID_PARAM; - } + ret = bmi_get_normalized_rate(s, rate, rnd, &normalized_rate, ®_val); + if (ret) + return ret; /* * Lock accel resource to prevent another task from attempting @@ -441,19 +137,15 @@ static int set_data_rate(const struct motion_sensor_t *s, */ mutex_lock(s->mutex); - ret = raw_read8(s->port, s->i2c_spi_addr_flags, ctrl_reg, &val); - if (ret != EC_SUCCESS) - goto accel_cleanup; - - val = (val & ~BMI160_ODR_MASK) | reg_val; - ret = raw_write8(s->port, s->i2c_spi_addr_flags, ctrl_reg, val); + 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; -#ifdef CONFIG_MAG_BMI160_BMM150 +#ifdef CONFIG_MAG_BMI_BMM150 if (s->type == MOTIONSENSE_TYPE_MAG) { /* Reset the calibration */ init_mag_cal(moc); @@ -474,170 +166,51 @@ static int set_data_rate(const struct motion_sensor_t *s, * They will be discarded if AP does not want them. */ if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - enable_fifo(s, 1); + bmi_enable_fifo(s, 1); accel_cleanup: mutex_unlock(s->mutex); return ret; } -static int get_data_rate(const struct motion_sensor_t *s) -{ - struct accelgyro_saved_data_t *data = BMI160_GET_SAVED_DATA(s); - - return data->odr; -} -static int get_offset(const struct motion_sensor_t *s, - int16_t *offset, - int16_t *temp) -{ - int i, val, val98; - intv3_t v; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - /* - * The offset of the accelerometer off_acc_[xyz] is a 8 bit - * two-complement number in units of 3.9 mg independent of the - * range selected for the accelerometer. - */ - for (i = X; i <= Z; i++) { - raw_read8(s->port, s->i2c_spi_addr_flags, - BMI160_OFFSET_ACC70 + i, &val); - if (val > 0x7f) - val = -256 + val; - v[i] = round_divide( - (int64_t)val * BMI160_OFFSET_ACC_MULTI_MG, - BMI160_OFFSET_ACC_DIV_MG); - - } - break; - case MOTIONSENSE_TYPE_GYRO: - /* Read the MSB first */ - raw_read8(s->port, s->i2c_spi_addr_flags, - BMI160_OFFSET_EN_GYR98, &val98); - /* - * The offset of the gyroscope off_gyr_[xyz] is a 10 bit - * two-complement number in units of 0.061 °/s. - * Therefore a maximum range that can be compensated is - * -31.25 °/s to +31.25 °/s - */ - for (i = X; i <= Z; i++) { - raw_read8(s->port, s->i2c_spi_addr_flags, - BMI160_OFFSET_GYR70 + i, &val); - val |= ((val98 >> (2 * i)) & 0x3) << 8; - if (val > 0x1ff) - val = -1024 + val; - v[i] = round_divide( - (int64_t)val * BMI160_OFFSET_GYRO_MULTI_MDS, - BMI160_OFFSET_GYRO_DIV_MDS); - } - break; -#ifdef CONFIG_MAG_BMI160_BMM150 - case MOTIONSENSE_TYPE_MAG: - bmm150_get_offset(s, v); - break; -#endif /* defined(CONFIG_MAG_BMI160_BMM150) */ - default: - for (i = X; i <= Z; i++) - v[i] = 0; - } - rotate(v, *s->rot_standard_ref, v); - offset[X] = v[X]; - offset[Y] = v[Y]; - offset[Z] = v[Z]; - /* Saving temperature at calibration not supported yet */ - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - static int set_offset(const struct motion_sensor_t *s, const int16_t *offset, int16_t temp) { - int ret, i, val, val98; + int ret, val98; intv3_t v = { offset[X], offset[Y], offset[Z] }; rotate_inv(v, *s->rot_standard_ref, v); - ret = raw_read8(s->port, s->i2c_spi_addr_flags, + 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: - for (i = X; i <= Z; i++) { - val = round_divide( - (int64_t)v[i] * BMI160_OFFSET_ACC_DIV_MG, - BMI160_OFFSET_ACC_MULTI_MG); - if (val > 127) - val = 127; - if (val < -128) - val = -128; - if (val < 0) - val = 256 + val; - raw_write8(s->port, s->i2c_spi_addr_flags, - BMI160_OFFSET_ACC70 + i, val); - } - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + bmi_set_accel_offset(s, v); + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_OFFSET_EN_GYR98, val98 | BMI160_OFFSET_ACC_EN); break; case MOTIONSENSE_TYPE_GYRO: - for (i = X; i <= Z; i++) { - val = round_divide( - (int64_t)v[i] * BMI160_OFFSET_GYRO_DIV_MDS, - BMI160_OFFSET_GYRO_MULTI_MDS); - if (val > 511) - val = 511; - if (val < -512) - val = -512; - if (val < 0) - val = 1024 + val; - raw_write8(s->port, s->i2c_spi_addr_flags, - BMI160_OFFSET_GYR70 + i, val & 0xFF); - val98 &= ~(0x3 << (2 * i)); - val98 |= (val >> 8) << (2 * i); - } - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + bmi_set_gyro_offset(s, v, &val98); + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_OFFSET_EN_GYR98, val98 | BMI160_OFFSET_GYRO_EN); break; -#ifdef CONFIG_MAG_BMI160_BMM150 +#ifdef CONFIG_MAG_BMI_BMM150 case MOTIONSENSE_TYPE_MAG: ret = bmm150_set_offset(s, v); break; -#endif /* defined(CONFIG_MAG_BMI160) */ +#endif /* defined(CONFIG_MAG_BMI_BMM150) */ default: ret = EC_RES_INVALID_PARAM; } return ret; } -int set_scale(const struct motion_sensor_t *s, - const uint16_t *scale, int16_t temp) -{ - struct accelgyro_saved_data_t *data = BMI160_GET_SAVED_DATA(s); - - data->scale[X] = scale[X]; - data->scale[Y] = scale[Y]; - data->scale[Z] = scale[Z]; - return EC_SUCCESS; -} - -int get_scale(const struct motion_sensor_t *s, - uint16_t *scale, int16_t *temp) -{ - struct accelgyro_saved_data_t *data = BMI160_GET_SAVED_DATA(s); - - scale[X] = data->scale[X]; - scale[Y] = data->scale[Y]; - scale[Z] = data->scale[Z]; - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - static int perform_calib(const struct motion_sensor_t *s, int enable) { int ret, val, en_flag, status, rate; @@ -646,7 +219,7 @@ static int perform_calib(const struct motion_sensor_t *s, int enable) if (!enable) return EC_SUCCESS; - rate = get_data_rate(s); + rate = bmi_get_data_rate(s); /* * Temporary set frequency to 100Hz to get enough data in a short * period of time. @@ -675,9 +248,9 @@ static int perform_calib(const struct motion_sensor_t *s, int enable) ret = EC_RES_INVALID_PARAM; goto end_perform_calib; } - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_FOC_CONF, val); - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_CMD_REG, BMI160_CMD_START_FOC); deadline.val = get_time().val + 400 * MSEC; do { @@ -686,47 +259,19 @@ static int perform_calib(const struct motion_sensor_t *s, int enable) goto end_perform_calib; } msleep(50); - ret = raw_read8(s->port, s->i2c_spi_addr_flags, + 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 = raw_read8(s->port, s->i2c_spi_addr_flags, - BMI160_OFFSET_EN_GYR98, &val); - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - BMI160_OFFSET_EN_GYR98, val | en_flag); + ret = bmi_enable_reg8(s, BMI160_OFFSET_EN_GYR98, en_flag, 1); end_perform_calib: set_data_rate(s, rate, 0); return ret; } -void normalize(const struct motion_sensor_t *s, intv3_t v, uint8_t *input) -{ - int i; - struct accelgyro_saved_data_t *data = BMI160_GET_SAVED_DATA(s); - -#ifdef CONFIG_MAG_BMI160_BMM150 - if (s->type == MOTIONSENSE_TYPE_MAG) - bmm150_normalize(s, v, input); - else -#endif -#ifdef CONFIG_MAG_BMI160_LIS2MDL - if (s->type == MOTIONSENSE_TYPE_MAG) - lis2mdl_normalize(s, v, data); - else -#endif - { - v[0] = ((int16_t)((input[1] << 8) | input[0])); - v[1] = ((int16_t)((input[3] << 8) | input[2])); - v[2] = ((int16_t)((input[5] << 8) | input[4])); - } - rotate(v, *s->rot_standard_ref, v); - for (i = X; i <= Z; i++) - v[i] = SENSOR_APPLY_SCALE(v[i], data->scale[i]); -} - /* * Manage gesture recognition. * Defined even if host interface is not defined, to enable double tap even @@ -738,18 +283,14 @@ int manage_activity(const struct motion_sensor_t *s, const struct ec_motion_sense_activity *param) { int ret; - struct bmi160_drv_data_t *data = BMI160_GET_DATA(s); + struct bmi_drv_data_t *data = BMI_GET_DATA(s); switch (activity) { #ifdef CONFIG_GESTURE_SIGMO case MOTIONSENSE_ACTIVITY_SIG_MOTION: { - int tmp; - ret = raw_read8(s->port, s->addr, BMI160_INT_EN_0, &tmp); - if (ret) - return ret; if (enable) { /* We should use parameters from caller */ - raw_write8(s->port, s->i2c_spi_addr_flags, + bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_INT_MOTION_3, BMI160_MOTION_PROOF_TIME( CONFIG_GESTURE_SIGMO_PROOF_MS) << @@ -758,20 +299,16 @@ int manage_activity(const struct motion_sensor_t *s, CONFIG_GESTURE_SIGMO_SKIP_MS) << BMI160_MOTION_SKIP_OFF | BMI160_MOTION_SIG_MOT_SEL); - raw_write8(s->port, s->i2c_spi_addr_flags, + bmi_write8(s->port, s->i2c_spi_addr_flags, 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->port, s->i2c_spi_addr_flags, - BMI160_INT_EN_0, tmp); + 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; @@ -779,18 +316,10 @@ int manage_activity(const struct motion_sensor_t *s, #endif #ifdef CONFIG_GESTURE_SENSOR_DOUBLE_TAP case MOTIONSENSE_ACTIVITY_DOUBLE_TAP: { - int tmp; /* Set double tap interrupt */ - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - BMI160_INT_EN_0, &tmp); - if (ret) - return ret; - if (enable) - tmp |= BMI160_INT_D_TAP_EN; - else - tmp &= ~BMI160_INT_D_TAP_EN; - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - BMI160_INT_EN_0, tmp); + ret = bmi_enable_reg8(s, BMI160_INT_EN_0, + BMI160_INT_D_TAP_EN, + enable); if (ret) ret = EC_RES_UNAVAILABLE; break; @@ -816,7 +345,7 @@ int list_activities(const struct motion_sensor_t *s, uint32_t *enabled, uint32_t *disabled) { - struct bmi160_drv_data_t *data = BMI160_GET_DATA(s); + struct bmi_drv_data_t *data = BMI_GET_DATA(s); *enabled = data->enabled_activities; *disabled = data->disabled_activities; return EC_RES_SUCCESS; @@ -825,216 +354,6 @@ int list_activities(const struct motion_sensor_t *s, #ifdef CONFIG_ACCEL_INTERRUPTS -enum fifo_state { - FIFO_HEADER, - FIFO_DATA_SKIP, - FIFO_DATA_TIME, - FIFO_DATA_CONFIG, -}; - - -#define BMI160_FIFO_BUFFER 64 -static uint8_t bmi160_buffer[BMI160_FIFO_BUFFER]; -/* - * Decode the header from the fifo. - * Return 0 if we need further processing. - * Sensor mutex must be held during processing, to protect the fifos. - * - * @s: base sensor - * @hdr: the header to decode - * @bp: current pointer in the buffer, updated when processing the header. - * @ep: pointer to the end of the valid data in the buffer. - */ -static int bmi160_decode_header(struct motion_sensor_t *accel, - enum fifo_header hdr, uint32_t last_ts, - uint8_t **bp, uint8_t *ep) -{ - if ((hdr & BMI160_FH_MODE_MASK) == BMI160_EMPTY && - (hdr & BMI160_FH_PARM_MASK) != 0) { - int i, size = 0; - /* Check if there is enough space for the data frame */ - for (i = MOTIONSENSE_TYPE_MAG; i >= MOTIONSENSE_TYPE_ACCEL; - i--) { - if (hdr & (1 << (i + BMI160_FH_PARM_OFFSET))) - size += (i == MOTIONSENSE_TYPE_MAG ? 8 : 6); - } - if (*bp + size > ep) { - /* frame is not complete, it will be retransmitted. */ - *bp = ep; - return 1; - } - for (i = MOTIONSENSE_TYPE_MAG; i >= MOTIONSENSE_TYPE_ACCEL; - i--) { - struct motion_sensor_t *s = accel + i; - - if (hdr & (1 << (i + BMI160_FH_PARM_OFFSET))) { - struct ec_response_motion_sensor_data vector; - int *v = s->raw_xyz; - vector.flags = 0; - normalize(s, v, *bp); - if (IS_ENABLED(CONFIG_ACCEL_SPOOF_MODE) && - s->flags & MOTIONSENSE_FLAG_IN_SPOOF_MODE) - v = s->spoof_xyz; - vector.data[X] = v[X]; - vector.data[Y] = v[Y]; - vector.data[Z] = v[Z]; - vector.sensor_num = s - motion_sensors; - motion_sense_fifo_stage_data(&vector, s, 3, - last_ts); - *bp += (i == MOTIONSENSE_TYPE_MAG ? 8 : 6); - } - } - return 1; - } else { - return 0; - } -} - -/** - * Retrieve hardware FIFO from sensor, - * - put data in Sensor Hub fifo. - * - update sensor raw_xyz vector with the last information. - * We put raw data in hub fifo and process data from there. - * @s Pointer to sensor data. - * - * Read only up to bmi160_buffer. If more reads are needed, we will be called - * again by the interrupt routine. - * - * NOTE: If a new driver supports this function, be sure to add a check - * for spoof_mode in order to load the sensor stack with the spoofed - * data. See accelgyro_bmi160.c::load_fifo for an example. - */ -static int load_fifo(struct motion_sensor_t *s, uint32_t last_ts) -{ - struct bmi160_drv_data_t *data = BMI160_GET_DATA(s); - uint16_t length; - enum fifo_state state = FIFO_HEADER; - uint8_t *bp = bmi160_buffer; - uint8_t *ep; - uint32_t beginning; - - - if (s->type != MOTIONSENSE_TYPE_ACCEL) - return EC_SUCCESS; - - if (!(data->flags & - (BMI160_FIFO_ALL_MASK << BMI160_FIFO_FLAG_OFFSET))) { - /* - * The FIFO was disabled while we were processing it. - * - * Flush potential left over: - * When sensor is resumed, we won't read old data. - */ - raw_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_REG, BMI160_CMD_FIFO_FLUSH); - return EC_SUCCESS; - } - - raw_read_n(s->port, s->i2c_spi_addr_flags, - BMI160_FIFO_LENGTH_0, - (uint8_t *)&length, sizeof(length)); - length &= BMI160_FIFO_LENGTH_MASK; - - /* - * We have not requested timestamp, no extra frame to read. - * if we have too much to read, read the whole buffer. - */ - if (length == 0) { - CPRINTS("unexpected empty FIFO"); - return EC_SUCCESS; - } - - /* Add one byte to get an empty FIFO frame.*/ - length++; - - if (length > sizeof(bmi160_buffer)) - CPRINTS("unexpected large FIFO: %d", length); - length = MIN(length, sizeof(bmi160_buffer)); - - - raw_read_n(s->port, s->i2c_spi_addr_flags, - BMI160_FIFO_DATA, bmi160_buffer, length); - beginning = *(uint32_t *)bmi160_buffer; - ep = bmi160_buffer + length; - /* - * FIFO is invalid when reading while the sensors are all - * suspended. - * Instead of returning the empty frame, it can return a - * pattern that looks like a valid header: 84 or 40. - * If we see those, assume the sensors have been disabled - * while this thread was running. - */ - if (beginning == 0x84848484 || - (beginning & 0xdcdcdcdc) == 0x40404040) { - CPRINTS("Suspended FIFO: accel ODR/rate: %d/%d: 0x%08x", - BASE_ODR(s->config[SENSOR_CONFIG_AP].odr), - get_data_rate(s), - beginning); - return EC_SUCCESS; - } - - while (bp < ep) { - switch (state) { - case FIFO_HEADER: { - enum fifo_header hdr = *bp++; - - if (bmi160_decode_header(s, hdr, last_ts, &bp, ep)) - continue; - /* Other cases */ - hdr &= 0xdc; - switch (hdr) { - case BMI160_EMPTY: - return EC_SUCCESS; - case BMI160_SKIP: - state = FIFO_DATA_SKIP; - break; - case BMI160_TIME: - state = FIFO_DATA_TIME; - break; - case BMI160_CONFIG: - state = FIFO_DATA_CONFIG; - break; - default: - CPRINTS("Unknown header: 0x%02x @ %zd", - hdr, bp - bmi160_buffer); - raw_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_REG, - BMI160_CMD_FIFO_FLUSH); - return EC_ERROR_NOT_HANDLED; - } - break; - } - case FIFO_DATA_SKIP: - CPRINTS("@ %zd - %d, skipped %d frames", - bp - bmi160_buffer, length, *bp); - bp++; - state = FIFO_HEADER; - break; - case FIFO_DATA_CONFIG: - CPRINTS("@ %zd - %d, config change: 0x%02x", - bp - bmi160_buffer, length, *bp); - bp++; - state = FIFO_HEADER; - break; - case FIFO_DATA_TIME: - if (bp + 3 > ep) { - bp = ep; - continue; - } - /* We are not requesting timestamp */ - CPRINTS("timestamp %d", (bp[2] << 16) | - (bp[1] << 8) | bp[0]); - state = FIFO_HEADER; - bp += 3; - break; - default: - CPRINTS("Unknown data: 0x%02x", *bp++); - state = FIFO_HEADER; - } - } - return EC_SUCCESS; -} - /** * bmi160_interrupt - called when the sensor activates the interrupt line. * @@ -1059,43 +378,43 @@ static int config_interrupt(const struct motion_sensor_t *s) return EC_SUCCESS; mutex_lock(s->mutex); - raw_write8(s->port, s->i2c_spi_addr_flags, + bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_CMD_REG, BMI160_CMD_FIFO_FLUSH); - raw_write8(s->port, s->i2c_spi_addr_flags, + bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_CMD_REG, BMI160_CMD_INT_RESET); #ifdef CONFIG_GESTURE_SENSOR_DOUBLE_TAP - raw_write8(s->port, s->i2c_spi_addr_flags, + bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_INT_TAP_0, BMI160_TAP_DUR(s, CONFIG_GESTURE_TAP_MAX_INTERSTICE_T)); - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_INT_TAP_1, BMI160_TAP_TH(s, CONFIG_GESTURE_TAP_THRES_MG)); #endif -#ifdef CONFIG_BMI160_ORIENTATION_SENSOR +#ifdef CONFIG_BMI_ORIENTATION_SENSOR /* only use orientation sensor on the lid sensor */ if (s->location == MOTIONSENSE_LOC_LID) { - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_INT_ORIENT_0, BMI160_INT_ORIENT_0_INIT_VAL); - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_INT_ORIENT_1, BMI160_INT_ORIENT_1_INIT_VAL); } #endif #ifdef CONFIG_ACCELGYRO_BMI160_INT2_OUTPUT - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + 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 = raw_write8(s->port, s->i2c_spi_addr_flags, + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_INT_LATCH, BMI160_INT2_INPUT_EN | BMI160_LATCH_5MS); #endif /* configure int1 as an interrupt */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_INT_OUT_CTRL, BMI160_INT_CTRL(1, OUTPUT_EN)); @@ -1107,17 +426,17 @@ static int config_interrupt(const struct motion_sensor_t *s) #ifdef CONFIG_GESTURE_SENSOR_DOUBLE_TAP tmp |= BMI160_INT_D_TAP; #endif -#ifdef CONFIG_BMI160_ORIENTATION_SENSOR +#ifdef CONFIG_BMI_ORIENTATION_SENSOR /* enable orientation interrupt for lid sensor only */ if (s->location == MOTIONSENSE_LOC_LID) tmp |= BMI160_INT_ORIENT; #endif - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + 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 = raw_write8(s->port, s->i2c_spi_addr_flags, + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_INT_FIFO_MAP, BMI160_INT_MAP(1, FWM) | BMI160_INT_MAP(1, FFULL)); @@ -1126,41 +445,38 @@ static int config_interrupt(const struct motion_sensor_t *s) * Configure fifo watermark to int whenever there's any data in * there */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_FIFO_CONFIG_0, 1); #ifdef CONFIG_ACCELGYRO_BMI160_INT2_OUTPUT - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_FIFO_CONFIG_1, BMI160_FIFO_HEADER_EN); #else - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_FIFO_CONFIG_1, BMI160_FIFO_TAG_INT2_EN | BMI160_FIFO_HEADER_EN); #endif /* Set fifo*/ - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - BMI160_INT_EN_1, &tmp); - tmp |= BMI160_INT_FWM_EN | BMI160_INT_FFUL_EN; - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - BMI160_INT_EN_1, tmp); + 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_BMI160_ORIENTATION_SENSOR +#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 (BMI160_GET_DATA(s)->raw_orientation != shifted_masked_orientation) { + if (BMI_GET_DATA(s)->raw_orientation != shifted_masked_orientation) { enum motionsensor_orientation orientation = MOTIONSENSE_ORIENTATION_UNKNOWN; - BMI160_GET_DATA(s)->raw_orientation = + BMI_GET_DATA(s)->raw_orientation = shifted_masked_orientation; switch (shifted_masked_orientation) { @@ -1204,7 +520,7 @@ static int irq_handler(struct motion_sensor_t *s, uint32_t *event) return EC_ERROR_NOT_HANDLED; do { - rv = raw_read32(s->port, s->i2c_spi_addr_flags, + rv = bmi_read32(s->port, s->i2c_spi_addr_flags, BMI160_INT_STATUS_0, &interrupt); /* * Bail out of this loop there was an error reading the register @@ -1213,21 +529,23 @@ static int irq_handler(struct motion_sensor_t *s, uint32_t *event) return rv; #ifdef CONFIG_GESTURE_SENSOR_DOUBLE_TAP - if (interrupt & BMI160_D_TAP_INT) + if (interrupt & BMI160_D_TAP_INT) { *event |= TASK_EVENT_MOTION_ACTIVITY_INTERRUPT( MOTIONSENSE_ACTIVITY_DOUBLE_TAP); + } #endif #ifdef CONFIG_GESTURE_SIGMO - if (interrupt & BMI160_SIGMOT_INT) + if (interrupt & BMI160_SIGMOT_INT) { *event |= TASK_EVENT_MOTION_ACTIVITY_INTERRUPT( MOTIONSENSE_ACTIVITY_SIG_MOTION); + } #endif if (IS_ENABLED(CONFIG_ACCEL_FIFO) && interrupt & (BMI160_FWM_INT | BMI160_FFULL_INT)) { - load_fifo(s, last_interrupt_timestamp); + bmi_load_fifo(s, last_interrupt_timestamp); has_read_fifo = 1; } -#ifdef CONFIG_BMI160_ORIENTATION_SENSOR +#ifdef CONFIG_BMI_ORIENTATION_SENSOR irq_set_orientation(s, interrupt); #endif } while (interrupt != 0); @@ -1239,81 +557,42 @@ static int irq_handler(struct motion_sensor_t *s, uint32_t *event) } #endif /* CONFIG_ACCEL_INTERRUPTS */ - -static int read(const struct motion_sensor_t *s, intv3_t v) -{ - uint8_t data[6]; - int ret, status = 0; - - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - BMI160_STATUS, &status); - if (ret != EC_SUCCESS) - return ret; - - /* - * If sensor data is not ready, return the previous read data. - * Note: return success so that motion senor task can read again - * to get the latest updated sensor data quickly. - */ - if (!(status & BMI160_DRDY_MASK(s->type))) { - if (v != s->raw_xyz) - memcpy(v, s->raw_xyz, sizeof(s->raw_xyz)); - return EC_SUCCESS; - } - - /* Read 6 bytes starting at xyz_reg */ - ret = raw_read_n(s->port, s->i2c_spi_addr_flags, - get_xyz_reg(s->type), data, 6); - - if (ret != EC_SUCCESS) { - CPRINTS("%s: type:0x%X RD XYZ Error %d", s->name, s->type, ret); - return ret; - } - normalize(s, v, data); - return EC_SUCCESS; -} - -static int read_temp(const struct motion_sensor_t *s, int *temp_ptr) -{ - return bmi160_get_sensor_temp(s - motion_sensors, temp_ptr); -} - static int init(const struct motion_sensor_t *s) { int ret = 0, tmp, i; - struct accelgyro_saved_data_t *saved_data = BMI160_GET_SAVED_DATA(s); + struct accelgyro_saved_data_t *saved_data = BMI_GET_SAVED_DATA(s); - ret = raw_read8(s->port, s->i2c_spi_addr_flags, + 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. */ - raw_write8(s->port, s->i2c_spi_addr_flags, + bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B0); - raw_write8(s->port, s->i2c_spi_addr_flags, + bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B1); - raw_write8(s->port, s->i2c_spi_addr_flags, + bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B2); - raw_write8(s->port, s->i2c_spi_addr_flags, + bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_CMD_EXT_MODE_ADDR, BMI160_CMD_PAGING_EN); - raw_write8(s->port, s->i2c_spi_addr_flags, + 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 bmi160_drv_data_t *data = BMI160_GET_DATA(s); + struct bmi_drv_data_t *data = BMI_GET_DATA(s); /* Reset the chip to be in a good state */ - raw_write8(s->port, s->i2c_spi_addr_flags, + bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_CMD_REG, BMI160_CMD_SOFT_RESET); msleep(1); - data->flags &= ~(BMI160_FLAG_SEC_I2C_ENABLED | - (BMI160_FIFO_ALL_MASK << - BMI160_FIFO_FLAG_OFFSET)); + data->flags &= ~(BMI_FLAG_SEC_I2C_ENABLED | + (BMI_FIFO_ALL_MASK << + BMI_FIFO_FLAG_OFFSET)); #ifdef CONFIG_GESTURE_HOST_DETECTION data->enabled_activities = 0; data->disabled_activities = 0; @@ -1327,24 +606,24 @@ static int init(const struct motion_sensor_t *s) #endif #endif /* To avoid gyro wakeup */ - raw_write8(s->port, s->i2c_spi_addr_flags, + bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_PMU_TRIGGER, 0); } -#ifdef CONFIG_BMI160_SEC_I2C +#ifdef CONFIG_BMI_SEC_I2C if (s->type == MOTIONSENSE_TYPE_MAG) { - struct bmi160_drv_data_t *data = BMI160_GET_DATA(s); + 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. */ - raw_write8(s->port, s->i2c_spi_addr_flags, + 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 & BMI160_FLAG_SEC_I2C_ENABLED) == 0) { - int ext_page_reg, pullup_reg; + 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 @@ -1353,53 +632,41 @@ static int init(const struct motion_sensor_t *s) * * Magic command sequences */ - raw_write8(s->port, s->i2c_spi_addr_flags, + bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B0); - raw_write8(s->port, s->i2c_spi_addr_flags, + bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B1); - raw_write8(s->port, s->i2c_spi_addr_flags, + 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. */ - raw_read8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_EXT_MODE_ADDR, &ext_page_reg); - raw_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_EXT_MODE_ADDR, - ext_page_reg | BMI160_CMD_TARGET_PAGE); - raw_read8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_EXT_MODE_ADDR, &ext_page_reg); - raw_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_EXT_MODE_ADDR, - ext_page_reg | BMI160_CMD_PAGING_EN); - raw_read8(s->port, s->i2c_spi_addr_flags, - BMI160_COM_C_TRIM_ADDR, &pullup_reg); - raw_write8(s->port, s->i2c_spi_addr_flags, - BMI160_COM_C_TRIM_ADDR, - pullup_reg | BMI160_COM_C_TRIM); - raw_read8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_EXT_MODE_ADDR, &ext_page_reg); - raw_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_EXT_MODE_ADDR, - ext_page_reg & ~BMI160_CMD_TARGET_PAGE); - raw_read8(s->port, s->i2c_spi_addr_flags, + 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 = raw_write8(s->port, s->i2c_spi_addr_flags, + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_MAG_IF_0, I2C_GET_ADDR( CONFIG_ACCELGYRO_SEC_ADDR_FLAGS) << 1); /* Enable the secondary interface as I2C */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, BMI160_IF_CONF, BMI160_IF_MODE_AUTO_I2C << BMI160_IF_MODE_OFF); - data->flags |= BMI160_FLAG_SEC_I2C_ENABLED; + data->flags |= BMI_FLAG_SEC_I2C_ENABLED; } @@ -1411,7 +678,7 @@ static int init(const struct motion_sensor_t *s) return ret; /* Leave the address for reading the data */ - raw_write8(s->port, s->i2c_spi_addr_flags, + 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. @@ -1435,7 +702,7 @@ static int init(const struct motion_sensor_t *s) * so set data rate to 0. */ saved_data->odr = 0; - set_range(s, s->default_range, 0); + bmi_set_range(s, s->default_range, 0); if (s->type == MOTIONSENSE_TYPE_ACCEL) { #ifdef CONFIG_ACCEL_INTERRUPTS @@ -1448,18 +715,18 @@ static int init(const struct motion_sensor_t *s) const struct accelgyro_drv bmi160_drv = { .init = init, - .read = read, - .set_range = set_range, - .get_range = get_range, - .get_resolution = get_resolution, + .read = bmi_read, + .set_range = bmi_set_range, + .get_range = bmi_get_range, + .get_resolution = bmi_get_resolution, .set_data_rate = set_data_rate, - .get_data_rate = get_data_rate, + .get_data_rate = bmi_get_data_rate, .set_offset = set_offset, - .get_scale = get_scale, - .set_scale = set_scale, - .get_offset = get_offset, + .get_scale = bmi_get_scale, + .set_scale = bmi_set_scale, + .get_offset = bmi_get_offset, .perform_calib = perform_calib, - .read_temp = read_temp, + .read_temp = bmi_read_temp, #ifdef CONFIG_ACCEL_INTERRUPTS .irq_handler = irq_handler, #endif @@ -1476,24 +743,16 @@ struct i2c_stress_test_dev bmi160_i2c_stress_test_dev = { .read_val = BMI160_CHIP_ID_MAJOR, .write_reg = BMI160_PMU_TRIGGER, }, - .i2c_read = &raw_read8, - .i2c_write = &raw_write8, + .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) { - struct motion_sensor_t *s = &motion_sensors[idx]; - int16_t temp; - int ret; - - ret = raw_read_n(s->port, s->i2c_spi_addr_flags, - BMI160_TEMPERATURE_0, - (uint8_t *)&temp, sizeof(temp)); - - if (ret || temp == BMI160_INVALID_TEMP) - return EC_ERROR_NOT_POWERED; - - *temp_ptr = C_TO_K(23 + ((temp + 256) >> 9)); - return 0; + return bmi_get_sensor_temp(idx, temp_ptr); } diff --git a/driver/accelgyro_bmi160.h b/driver/accelgyro_bmi160.h index 42f46adab7..c1b4b47359 100644 --- a/driver/accelgyro_bmi160.h +++ b/driver/accelgyro_bmi160.h @@ -22,7 +22,6 @@ /* I2C addresses */ #define BMI160_ADDR0_FLAGS 0x68 -#define BMI160_ADDR1_FLAGS 0x69 #define BMI160_CHIP_ID 0x00 #define BMI160_CHIP_ID_MAJOR 0xd1 @@ -126,28 +125,14 @@ #define BMI160_TEMPERATURE_0 0x20 #define BMI160_TEMPERATURE_1 0x21 -#define BMI160_INVALID_TEMP 0x8000 #define BMI160_FIFO_LENGTH_0 0x22 #define BMI160_FIFO_LENGTH_1 0x23 #define BMI160_FIFO_LENGTH_MASK (BIT(11) - 1) #define BMI160_FIFO_DATA 0x24 -enum fifo_header { - BMI160_EMPTY = 0x80, - BMI160_SKIP = 0x40, - BMI160_TIME = 0x44, - BMI160_CONFIG = 0x48 -}; - -#define BMI160_FH_MODE_MASK 0xc0 -#define BMI160_FH_PARM_OFFSET 2 -#define BMI160_FH_PARM_MASK (0x7 << BMI160_FH_PARM_OFFSET) -#define BMI160_FH_EXT_MASK 0x03 - #define BMI160_ACC_CONF 0x40 -#define BMI160_ODR_MASK 0x0F #define BMI160_ACC_BW_OFFSET 4 #define BMI160_ACC_BW_MASK (0x7 << BMI160_ACC_BW_OFFSET) @@ -168,23 +153,8 @@ enum fifo_header { #define BMI160_DPS_SEL_250 0x03 #define BMI160_DPS_SEL_125 0x04 - #define BMI160_MAG_CONF 0x44 -/* odr = 100 / (1 << (8 - reg)) ,within limit */ -#define BMI160_ODR_0_78HZ 0x01 -#define BMI160_ODR_100HZ 0x08 - -#define BMI160_REG_TO_ODR(_regval) \ - ((_regval) < BMI160_ODR_100HZ ? 100000 / (1 << (8 - (_regval))) : \ - 100000 * (1 << ((_regval) - 8))) -#define BMI160_ODR_TO_REG(_odr) \ - ((_odr) < 100000 ? (__builtin_clz(100000 / ((_odr) + 1)) - 24) : \ - (39 - __builtin_clz((_odr) / 100000))) - -#define BMI160_CONF_REG(_sensor) (0x40 + 2 * (_sensor)) -#define BMI160_RANGE_REG(_sensor) (0x41 + 2 * (_sensor)) - #define BMI160_FIFO_DOWNS 0x45 #define BMI160_FIFO_CONFIG_0 0x46 #define BMI160_FIFO_CONFIG_1 0x47 @@ -361,11 +331,7 @@ enum fifo_header { #define BMI160_SELF_TEST 0x6d #define BMI160_OFFSET_ACC70 0x71 -#define BMI160_OFFSET_ACC_MULTI_MG (3900 * 1024) -#define BMI160_OFFSET_ACC_DIV_MG 1000000 #define BMI160_OFFSET_GYR70 0x74 -#define BMI160_OFFSET_GYRO_MULTI_MDS (61 * 1024) -#define BMI160_OFFSET_GYRO_DIV_MDS 1000 #define BMI160_OFFSET_EN_GYR98 0x77 #define BMI160_OFFSET_ACC_EN BIT(6) #define BMI160_OFFSET_GYRO_EN BIT(7) @@ -403,8 +369,6 @@ enum fifo_header { #define BMI160_COM_C_TRIM_ADDR 0x85 #define BMI160_COM_C_TRIM (3 << 4) - - #define BMI160_CMD_TGT_PAGE 0 #define BMI160_CMD_TGT_PAGE_COM 1 #define BMI160_CMD_TGT_PAGE_ACC 2 @@ -415,9 +379,10 @@ enum fifo_header { #define BMI160_FF_DATA_LEN_GYR 6 #define BMI160_FF_DATA_LEN_MAG 8 -/* Sensor resolution in number of bits. This sensor has fixed resolution. */ -#define BMI160_RESOLUTION 16 - +/* + * TODO(chingkang): Replace following in some board config to + * bmi version. Then, remove this definition(s). + */ /* Min and Max sampling frequency in mHz */ #define BMI160_ACCEL_MIN_FREQ 12500 #define BMI160_ACCEL_MAX_FREQ MOTION_MAX_SENSOR_FREQUENCY(1600000, 100000) @@ -426,31 +391,19 @@ enum fifo_header { extern const struct accelgyro_drv bmi160_drv; -enum bmi160_running_mode { - STANDARD_UI_9DOF_FIFO = 0, - STANDARD_UI_IMU_FIFO = 1, - STANDARD_UI_IMU = 2, - STANDARD_UI_ADVANCEPOWERSAVE = 3, - ACCEL_PEDOMETER = 4, - APPLICATION_HEAD_TRACKING = 5, - APPLICATION_NAVIGATION = 6, - APPLICATION_REMOTE_CONTROL = 7, - APPLICATION_INDOOR_NAVIGATION = 8, -}; - -#define BMI160_FLAG_SEC_I2C_ENABLED BIT(0) -#define BMI160_FIFO_FLAG_OFFSET 4 -#define BMI160_FIFO_ALL_MASK 7 - +/* + * TODO(chingkang): Replace bmi160_drv_data_t in some board config to + * bmi_drv_data_t. Then, remove this definition. + */ 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 +#ifdef CONFIG_MAG_BMI_BMM150 struct bmm150_private_data compass; #endif -#ifdef CONFIG_BMI160_ORIENTATION_SENSOR +#ifdef CONFIG_BMI_ORIENTATION_SENSOR uint8_t raw_orientation; enum motionsensor_orientation orientation; enum motionsensor_orientation last_orientation; @@ -458,30 +411,9 @@ struct bmi160_drv_data_t { }; -#define BMI160_GET_DATA(_s) \ - ((struct bmi160_drv_data_t *)(_s)->drv_data) -#define BMI160_GET_SAVED_DATA(_s) \ - (&BMI160_GET_DATA(_s)->saved_data[(_s)->type]) - -#ifdef CONFIG_BMI160_ORIENTATION_SENSOR -#define ORIENTATION_CHANGED(_sensor) \ - (BMI160_GET_DATA(_sensor)->orientation != \ - BMI160_GET_DATA(_sensor)->last_orientation) - -#define GET_ORIENTATION(_sensor) \ - (BMI160_GET_DATA(_sensor)->orientation) - -#define SET_ORIENTATION(_sensor, _val) \ - (BMI160_GET_DATA(_sensor)->orientation = _val) - -#define SET_ORIENTATION_UPDATED(_sensor) \ - (BMI160_GET_DATA(_sensor)->last_orientation = \ - BMI160_GET_DATA(_sensor)->orientation) -#endif - void bmi160_interrupt(enum gpio_signal signal); -#ifdef CONFIG_BMI160_SEC_I2C +#ifdef CONFIG_BMI_SEC_I2C /* Functions to access the secondary device through the accel/gyro. */ int bmi160_sec_raw_read8(const int port, const uint16_t addr_flags, const uint8_t reg, int *data_ptr); diff --git a/driver/accelgyro_bmi_common.c b/driver/accelgyro_bmi_common.c new file mode 100644 index 0000000000..87ad203170 --- /dev/null +++ b/driver/accelgyro_bmi_common.c @@ -0,0 +1,837 @@ +/* Copyright 2020 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. + */ + +/** + * BMI accelerometer and gyro module for Chrome EC + * 3D digital accelerometer & 3D digital gyroscope + */ + + +#include "accelgyro.h" +#include "console.h" +#include "driver/accelgyro_bmi_common.h" +#include "i2c.h" +#include "math_util.h" +#include "motion_sense_fifo.h" +#include "spi.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) + +/* List of range values in +/-G's and their associated register values. */ +const struct bmi_accel_param_pair g_ranges[4] = { + {2, BMI160_GSEL_2G}, + {4, BMI160_GSEL_4G}, + {8, BMI160_GSEL_8G}, + {16, BMI160_GSEL_16G}, +}; + +/* + * List of angular rate range values in +/-dps's + * and their associated register values. + */ +const struct bmi_accel_param_pair dps_ranges[5] = { + {125, BMI160_DPS_SEL_125}, + {250, BMI160_DPS_SEL_250}, + {500, BMI160_DPS_SEL_500}, + {1000, BMI160_DPS_SEL_1000}, + {2000, BMI160_DPS_SEL_2000}, +}; + +int bmi_get_xyz_reg(const struct motion_sensor_t *s) +{ + switch (s->type) { + case MOTIONSENSE_TYPE_ACCEL: + return BMI_ACC_DATA; + case MOTIONSENSE_TYPE_GYRO: + return BMI_GYR_DATA; + case MOTIONSENSE_TYPE_MAG: + return BMI_AUX_DATA; + default: + return -1; + } +} + +const struct bmi_accel_param_pair *bmi_get_range_table( + const struct motion_sensor_t *s, int *psize) +{ + if (s->type == MOTIONSENSE_TYPE_ACCEL) { + if (psize) + *psize = ARRAY_SIZE(g_ranges); + return g_ranges; + } + if (psize) + *psize = ARRAY_SIZE(dps_ranges); + return dps_ranges; +} + +/** + * @return reg value that matches the given engineering value passed in. + * The round_up flag is used to specify whether to round up or down. + * Note, this function always returns a valid reg value. If the request is + * outside the range of values, it returns the closest valid reg value. + */ +int bmi_get_reg_val(const int eng_val, const int round_up, + const struct bmi_accel_param_pair *pairs, + const int size) +{ + int i; + + for (i = 0; i < size - 1; i++) { + if (eng_val <= pairs[i].val) + break; + + if (eng_val < pairs[i+1].val) { + if (round_up) + i += 1; + break; + } + } + return pairs[i].reg_val; +} + +/** + * @return engineering value that matches the given reg val + */ +int bmi_get_engineering_val(const int reg_val, + const struct bmi_accel_param_pair *pairs, + const int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (reg_val == pairs[i].reg_val) + break; + } + return pairs[i].val; +} + +#ifdef CONFIG_SPI_ACCEL_PORT +int bmi_spi_raw_read(const int addr, const uint8_t reg, + uint8_t *data, const int len) +{ + uint8_t cmd = 0x80 | reg; + + return spi_transaction(&spi_devices[addr], &cmd, 1, data, len); +} +#endif + +/** + * Read 8bit register from accelerometer. + */ +int bmi_read8(const int port, const uint16_t i2c_spi_addr_flags, + const int reg, int *data_ptr) +{ + int rv = -EC_ERROR_PARAM1; + + if (SLAVE_IS_SPI(i2c_spi_addr_flags)) { +#ifdef CONFIG_SPI_ACCEL_PORT + uint8_t val; + + rv = bmi_spi_raw_read(SLAVE_GET_SPI_ADDR(i2c_spi_addr_flags), + reg, &val, 1); + if (rv == EC_SUCCESS) + *data_ptr = val; +#endif + } else { +#ifdef I2C_PORT_ACCEL + rv = i2c_read8(port, i2c_spi_addr_flags, + reg, data_ptr); +#endif + } + return rv; +} + +/** + * Write 8bit register from accelerometer. + */ +int bmi_write8(const int port, const uint16_t i2c_spi_addr_flags, + const int reg, int data) +{ + int rv = -EC_ERROR_PARAM1; + + if (SLAVE_IS_SPI(i2c_spi_addr_flags)) { +#ifdef CONFIG_SPI_ACCEL_PORT + uint8_t cmd[2] = { reg, data }; + + rv = spi_transaction( + &spi_devices[SLAVE_GET_SPI_ADDR(i2c_spi_addr_flags)], + cmd, 2, NULL, 0); +#endif + } else { +#ifdef I2C_PORT_ACCEL + rv = i2c_write8(port, i2c_spi_addr_flags, + reg, data); +#endif + } + /* + * From Bosch: BMI needs a delay of 450us after each write if it + * is in suspend mode, otherwise the operation may be ignored by + * the sensor. Given we are only doing write during init, add + * the delay unconditionally. + */ + msleep(1); + return rv; +} + +/** + * Read 16bit register from accelerometer. + */ +int bmi_read16(const int port, const uint16_t i2c_spi_addr_flags, + const uint8_t reg, int *data_ptr) +{ + int rv = -EC_ERROR_PARAM1; + + if (SLAVE_IS_SPI(i2c_spi_addr_flags)) { +#ifdef CONFIG_SPI_ACCEL_PORT + rv = bmi_spi_raw_read(SLAVE_GET_SPI_ADDR(i2c_spi_addr_flags), + reg, (uint8_t *)data_ptr, 2); +#endif + } else { +#ifdef I2C_PORT_ACCEL + rv = i2c_read16(port, i2c_spi_addr_flags, + reg, data_ptr); +#endif + } + return rv; +} + +/** + * Write 16bit register from accelerometer. + */ +int bmi_write16(const int port, const uint16_t i2c_spi_addr_flags, + const int reg, int data) +{ + int rv = -EC_ERROR_PARAM1; + + if (SLAVE_IS_SPI(i2c_spi_addr_flags)) { +#ifdef CONFIG_SPI_ACCEL_PORT + CPRINTS("%s() spi part is not implemented", __func__); +#endif + } else { +#ifdef I2C_PORT_ACCEL + rv = i2c_write16(port, i2c_spi_addr_flags, + reg, data); +#endif + } + /* + * From Bosch: BMI needs a delay of 450us after each write if it + * is in suspend mode, otherwise the operation may be ignored by + * the sensor. Given we are only doing write during init, add + * the delay unconditionally. + */ + msleep(1); + return rv; +} + +/** + * Read 32bit register from accelerometer. + */ +int bmi_read32(const int port, const uint16_t i2c_spi_addr_flags, + const uint8_t reg, int *data_ptr) +{ + int rv = -EC_ERROR_PARAM1; + + if (SLAVE_IS_SPI(i2c_spi_addr_flags)) { +#ifdef CONFIG_SPI_ACCEL_PORT + rv = bmi_spi_raw_read(SLAVE_GET_SPI_ADDR(i2c_spi_addr_flags), + reg, (uint8_t *)data_ptr, 4); +#endif + } else { +#ifdef I2C_PORT_ACCEL + rv = i2c_read32(port, i2c_spi_addr_flags, + reg, data_ptr); +#endif + } + return rv; +} + +/** + * Read n bytes from accelerometer. + */ +int bmi_read_n(const int port, const uint16_t i2c_spi_addr_flags, + const uint8_t reg, uint8_t *data_ptr, const int len) +{ + int rv = -EC_ERROR_PARAM1; + + if (SLAVE_IS_SPI(i2c_spi_addr_flags)) { +#ifdef CONFIG_SPI_ACCEL_PORT + rv = bmi_spi_raw_read(SLAVE_GET_SPI_ADDR(i2c_spi_addr_flags), + reg, data_ptr, len); +#endif + } else { +#ifdef I2C_PORT_ACCEL + rv = i2c_read_block(port, i2c_spi_addr_flags, + reg, data_ptr, len); +#endif + } + return rv; +} + +/** + * Write n bytes from accelerometer. + */ +int bmi_write_n(const int port, const uint16_t i2c_spi_addr_flags, + const uint8_t reg, const uint8_t *data_ptr, const int len) +{ + int rv = -EC_ERROR_PARAM1; + + if (SLAVE_IS_SPI(i2c_spi_addr_flags)) { +#ifdef CONFIG_SPI_ACCEL_PORT + CPRINTS("%s() spi part is not implemented", __func__); +#endif + } else { +#ifdef I2C_PORT_ACCEL + rv = i2c_write_block(port, i2c_spi_addr_flags, + reg, data_ptr, len); +#endif + } + /* + * From Bosch: BMI needs a delay of 450us after each write if it + * is in suspend mode, otherwise the operation may be ignored by + * the sensor. Given we are only doing write during init, add + * the delay unconditionally. + */ + msleep(1); + return rv; +} +/* + * Enable/Disable specific bit set of a 8-bit reg. + */ +int bmi_enable_reg8(const struct motion_sensor_t *s, + int reg, uint8_t bits, int enable) +{ + if (enable) + return bmi_set_reg8(s, reg, bits, 0); + return bmi_set_reg8(s, reg, 0, bits); +} + +/* + * Set specific bit set to certain value of a 8-bit reg. + */ +int bmi_set_reg8(const struct motion_sensor_t *s, + int reg, uint8_t bits, int mask) +{ + int ret, val; + + ret = bmi_read8(s->port, s->i2c_spi_addr_flags, reg, &val); + if (ret) + return ret; + val = (val & ~mask) | bits; + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, reg, val); + return ret; +} + +void bmi_normalize(const struct motion_sensor_t *s, intv3_t v, uint8_t *input) +{ + int i; + struct accelgyro_saved_data_t *data = BMI_GET_SAVED_DATA(s); + +#ifdef CONFIG_MAG_BMI_BMM150 + if (s->type == MOTIONSENSE_TYPE_MAG) + bmm150_normalize(s, v, input); + else +#endif +#ifdef CONFIG_MAG_BMI_LIS2MDL + if (s->type == MOTIONSENSE_TYPE_MAG) + lis2mdl_normalize(s, v, data); + else +#endif + { + v[0] = ((int16_t)((input[1] << 8) | input[0])); + v[1] = ((int16_t)((input[3] << 8) | input[2])); + v[2] = ((int16_t)((input[5] << 8) | input[4])); + } + rotate(v, *s->rot_standard_ref, v); + for (i = X; i <= Z; i++) + v[i] = SENSOR_APPLY_SCALE(v[i], data->scale[i]); +} + +int bmi_decode_header(struct motion_sensor_t *accel, + enum fifo_header hdr, uint32_t last_ts, + uint8_t **bp, uint8_t *ep) +{ + if ((hdr & BMI_FH_MODE_MASK) == BMI_FH_EMPTY && + (hdr & BMI_FH_PARM_MASK) != 0) { + int i, size = 0; + /* Check if there is enough space for the data frame */ + for (i = MOTIONSENSE_TYPE_MAG; i >= MOTIONSENSE_TYPE_ACCEL; + i--) { + if (hdr & (1 << (i + BMI_FH_PARM_OFFSET))) + size += (i == MOTIONSENSE_TYPE_MAG ? 8 : 6); + } + if (*bp + size > ep) { + /* frame is not complete, it will be retransmitted. */ + *bp = ep; + return 1; + } + for (i = MOTIONSENSE_TYPE_MAG; i >= MOTIONSENSE_TYPE_ACCEL; + i--) { + struct motion_sensor_t *s = accel + i; + + if (hdr & (1 << (i + BMI_FH_PARM_OFFSET))) { + struct ec_response_motion_sensor_data vector; + int *v = s->raw_xyz; + + vector.flags = 0; + bmi_normalize(s, v, *bp); + if (IS_ENABLED(CONFIG_ACCEL_SPOOF_MODE) && + s->flags & + MOTIONSENSE_FLAG_IN_SPOOF_MODE) + v = s->spoof_xyz; + vector.data[X] = v[X]; + vector.data[Y] = v[Y]; + vector.data[Z] = v[Z]; + vector.sensor_num = s - motion_sensors; + motion_sense_fifo_stage_data(&vector, s, 3, + last_ts); + *bp += (i == MOTIONSENSE_TYPE_MAG ? 8 : 6); + } + } + + return 1; + } else { + return 0; + } +} + +enum fifo_state { + FIFO_HEADER, + FIFO_DATA_SKIP, + FIFO_DATA_TIME, + FIFO_DATA_CONFIG, +}; + +#define BMI_FIFO_BUFFER 64 +static uint8_t bmi_buffer[BMI_FIFO_BUFFER]; + +int bmi_load_fifo(struct motion_sensor_t *s, uint32_t last_ts) +{ + struct bmi_drv_data_t *data = BMI_GET_DATA(s); + uint16_t length; + enum fifo_state state = FIFO_HEADER; + uint8_t *bp = bmi_buffer; + uint8_t *ep; + uint32_t beginning; + + + if (s->type != MOTIONSENSE_TYPE_ACCEL) + return EC_SUCCESS; + + if (!(data->flags & + (BMI_FIFO_ALL_MASK << BMI_FIFO_FLAG_OFFSET))) { + /* + * The FIFO was disabled while we were processing it. + * + * Flush potential left over: + * When sensor is resumed, we won't read old data. + */ + bmi_write8(s->port, s->i2c_spi_addr_flags, + BMI_CMD_REG, BMI_CMD_FIFO_FLUSH); + return EC_SUCCESS; + } + + bmi_read_n(s->port, s->i2c_spi_addr_flags, + BMI_FIFO_LENGTH_0, + (uint8_t *)&length, sizeof(length)); + length &= BMI_FIFO_LENGTH_MASK; + + /* + * We have not requested timestamp, no extra frame to read. + * if we have too much to read, read the whole buffer. + */ + if (length == 0) { + CPRINTS("unexpected empty FIFO"); + return EC_SUCCESS; + } + + /* Add one byte to get an empty FIFO frame.*/ + length++; + + if (length > sizeof(bmi_buffer)) + CPRINTS("unexpected large FIFO: %d", length); + length = MIN(length, sizeof(bmi_buffer)); + + bmi_read_n(s->port, s->i2c_spi_addr_flags, + BMI_FIFO_DATA, bmi_buffer, length); + beginning = *(uint32_t *)bmi_buffer; + ep = bmi_buffer + length; + /* + * FIFO is invalid when reading while the sensors are all + * suspended. + * Instead of returning the empty frame, it can return a + * pattern that looks like a valid header: 84 or 40. + * If we see those, assume the sensors have been disabled + * while this thread was running. + */ + if (beginning == 0x84848484 || + (beginning & 0xdcdcdcdc) == 0x40404040) { + CPRINTS("Suspended FIFO: accel ODR/rate: %d/%d: 0x%08x", + BASE_ODR(s->config[SENSOR_CONFIG_AP].odr), + BMI_GET_SAVED_DATA(s)->odr, + beginning); + return EC_SUCCESS; + } + + + while (bp < ep) { + switch (state) { + case FIFO_HEADER: { + enum fifo_header hdr = *bp++; + + if (bmi_decode_header(s, hdr, last_ts, &bp, ep)) + continue; + /* Other cases */ + hdr &= 0xdc; + switch (hdr) { + case BMI_FH_EMPTY: + return EC_SUCCESS; + case BMI_FH_SKIP: + state = FIFO_DATA_SKIP; + break; + case BMI_FH_TIME: + state = FIFO_DATA_TIME; + break; + case BMI_FH_CONFIG: + state = FIFO_DATA_CONFIG; + break; + default: + CPRINTS("Unknown header: 0x%02x @ %zd", + hdr, bp - bmi_buffer); + bmi_write8(s->port, s->i2c_spi_addr_flags, + BMI_CMD_REG, + BMI_CMD_FIFO_FLUSH); + return EC_ERROR_NOT_HANDLED; + } + break; + } + case FIFO_DATA_SKIP: + CPRINTS("@ %zd - %d, skipped %d frames", + bp - bmi_buffer, length, *bp); + bp++; + state = FIFO_HEADER; + break; + case FIFO_DATA_CONFIG: + CPRINTS("@ %zd - %d, config change: 0x%02x", + bp - bmi_buffer, length, *bp); + bp++; + state = FIFO_HEADER; + break; + case FIFO_DATA_TIME: + if (bp + 3 > ep) { + bp = ep; + continue; + } + /* We are not requesting timestamp */ + CPRINTS("timestamp %d", (bp[2] << 16) | + (bp[1] << 8) | bp[0]); + state = FIFO_HEADER; + bp += 3; + break; + default: + CPRINTS("Unknown data: 0x%02x", *bp++); + state = FIFO_HEADER; + } + } + + return EC_SUCCESS; +} + +int bmi_set_range(const struct motion_sensor_t *s, int range, int rnd) +{ + int ret, range_tbl_size; + uint8_t reg_val, ctrl_reg; + const struct bmi_accel_param_pair *ranges; + struct accelgyro_saved_data_t *data = BMI_GET_SAVED_DATA(s); + + if (s->type == MOTIONSENSE_TYPE_MAG) { + data->range = range; + return EC_SUCCESS; + } + + ctrl_reg = BMI_RANGE_REG(s->type); + ranges = bmi_get_range_table(s, &range_tbl_size); + reg_val = bmi_get_reg_val(range, rnd, ranges, range_tbl_size); + + ret = bmi_write8(s->port, s->i2c_spi_addr_flags, + ctrl_reg, reg_val); + /* Now that we have set the range, update the driver's value. */ + if (ret == EC_SUCCESS) + data->range = bmi_get_engineering_val(reg_val, ranges, + range_tbl_size); + return ret; +} + +int bmi_get_range(const struct motion_sensor_t *s) +{ + struct accelgyro_saved_data_t *data = BMI_GET_SAVED_DATA(s); + + return data->range; +} + +int bmi_get_data_rate(const struct motion_sensor_t *s) +{ + struct accelgyro_saved_data_t *data = BMI_GET_SAVED_DATA(s); + + return data->odr; +} + +int bmi_get_offset(const struct motion_sensor_t *s, + int16_t *offset, int16_t *temp) +{ + int i; + intv3_t v; + + switch (s->type) { + case MOTIONSENSE_TYPE_ACCEL: + /* + * The offset of the accelerometer off_acc_[xyz] is a 8 bit + * two-complement number in units of 3.9 mg independent of the + * range selected for the accelerometer. + */ + bmi_accel_get_offset(s, v); + break; + case MOTIONSENSE_TYPE_GYRO: + /* + * The offset of the gyroscope off_gyr_[xyz] is a 10 bit + * two-complement number in units of 0.061 °/s. + * Therefore a maximum range that can be compensated is + * -31.25 °/s to +31.25 °/s + */ + bmi_gyro_get_offset(s, v); + break; +#ifdef CONFIG_MAG_BMI_BMM150 + case MOTIONSENSE_TYPE_MAG: + bmm150_get_offset(s, v); + break; +#endif /* defined(CONFIG_MAG_BMI_BMM150) */ + default: + for (i = X; i <= Z; i++) + v[i] = 0; + } + rotate(v, *s->rot_standard_ref, v); + offset[X] = v[X]; + offset[Y] = v[Y]; + offset[Z] = v[Z]; + /* Saving temperature at calibration not supported yet */ + *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; + return EC_SUCCESS; +} + +int bmi_get_resolution(const struct motion_sensor_t *s) +{ + return BMI_RESOLUTION; +} + +int bmi_set_scale(const struct motion_sensor_t *s, + const uint16_t *scale, int16_t temp) +{ + struct accelgyro_saved_data_t *data = BMI_GET_SAVED_DATA(s); + + data->scale[X] = scale[X]; + data->scale[Y] = scale[Y]; + data->scale[Z] = scale[Z]; + return EC_SUCCESS; +} + +int bmi_get_scale(const struct motion_sensor_t *s, + uint16_t *scale, int16_t *temp) +{ + struct accelgyro_saved_data_t *data = BMI_GET_SAVED_DATA(s); + + scale[X] = data->scale[X]; + scale[Y] = data->scale[Y]; + scale[Z] = data->scale[Z]; + *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; + return EC_SUCCESS; +} + +int bmi_enable_fifo(const struct motion_sensor_t *s, int enable) +{ + struct bmi_drv_data_t *data = BMI_GET_DATA(s); + int ret; + + /* FIFO start/stop collecting events */ + ret = bmi_enable_reg8(s, BMI_FIFO_CONFIG_1, + BMI_FIFO_SENSOR_EN(s->type), enable); + if (ret) + return ret; + + if (enable) + data->flags |= 1 << (s->type + BMI_FIFO_FLAG_OFFSET); + else + data->flags &= ~(1 << (s->type + BMI_FIFO_FLAG_OFFSET)); + + return ret; +} + +int bmi_read(const struct motion_sensor_t *s, intv3_t v) +{ + uint8_t data[6]; + int ret, status = 0; + + ret = bmi_read8(s->port, s->i2c_spi_addr_flags, + BMI_STATUS, &status); + if (ret != EC_SUCCESS) + return ret; + + /* + * If sensor data is not ready, return the previous read data. + * Note: return success so that motion senor task can read again + * to get the latest updated sensor data quickly. + */ + if (!(status & BMI_DRDY_MASK(s->type))) { + if (v != s->raw_xyz) + memcpy(v, s->raw_xyz, sizeof(s->raw_xyz)); + return EC_SUCCESS; + } + + /* Read 6 bytes starting at xyz_reg */ + ret = bmi_read_n(s->port, s->i2c_spi_addr_flags, + bmi_get_xyz_reg(s), data, 6); + + if (ret != EC_SUCCESS) { + CPRINTS("%s: type:0x%X RD XYZ Error %d", s->name, s->type, ret); + return ret; + } + bmi_normalize(s, v, data); + return EC_SUCCESS; +} + +int bmi_read_temp(const struct motion_sensor_t *s, int *temp_ptr) +{ + return bmi_get_sensor_temp(s - motion_sensors, temp_ptr); +} + +int bmi_get_sensor_temp(int idx, int *temp_ptr) +{ + struct motion_sensor_t *s = &motion_sensors[idx]; + int16_t temp; + int ret; + + ret = bmi_read_n(s->port, s->i2c_spi_addr_flags, + BMI_TEMPERATURE_0, + (uint8_t *)&temp, sizeof(temp)); + + if (ret || temp == BMI_INVALID_TEMP) + return EC_ERROR_NOT_POWERED; + + *temp_ptr = C_TO_K(23 + ((temp + 256) >> 9)); + return 0; +} + +int bmi_get_normalized_rate(const struct motion_sensor_t *s, int rate, int rnd, + int *normalized_rate_ptr, uint8_t *reg_val_ptr) +{ + *reg_val_ptr = BMI_ODR_TO_REG(rate); + *normalized_rate_ptr = BMI_REG_TO_ODR(*reg_val_ptr); + if (rnd && (*normalized_rate_ptr < rate)) { + (*reg_val_ptr)++; + *normalized_rate_ptr = BMI_REG_TO_ODR(*reg_val_ptr); + } + + switch (s->type) { + case MOTIONSENSE_TYPE_ACCEL: + if (*normalized_rate_ptr > BMI_ACCEL_MAX_FREQ || + *normalized_rate_ptr < BMI_ACCEL_MIN_FREQ) + return EC_RES_INVALID_PARAM; + break; + case MOTIONSENSE_TYPE_GYRO: + if (*normalized_rate_ptr > BMI_GYRO_MAX_FREQ || + *normalized_rate_ptr < BMI_GYRO_MIN_FREQ) + return EC_RES_INVALID_PARAM; + break; +#ifdef CONFIG_MAG_BMI_BMM150 + case MOTIONSENSE_TYPE_MAG: + /* We use the regular preset we can go about 100Hz */ + if (*reg_val_ptr > BMI_ODR_100HZ || + *reg_val_ptr < BMI_ODR_0_78HZ) + return EC_RES_INVALID_PARAM; + break; +#endif + + default: + return EC_RES_INVALID_PARAM; + } + return EC_SUCCESS; +} + +void bmi_accel_get_offset(const struct motion_sensor_t *accel, intv3_t v) +{ + int i, val; + + for (i = X; i <= Z; i++) { + bmi_read8(accel->port, accel->i2c_spi_addr_flags, + BMI_OFFSET_ACC70 + i, &val); + if (val > 0x7f) + val = -256 + val; + v[i] = round_divide( + (int64_t)val * BMI_OFFSET_ACC_MULTI_MG, + BMI_OFFSET_ACC_DIV_MG); + + } +} + +void bmi_gyro_get_offset(const struct motion_sensor_t *gyro, intv3_t v) +{ + int i, val, val98; + + /* Read the MSB first */ + bmi_read8(gyro->port, gyro->i2c_spi_addr_flags, + BMI_OFFSET_EN_GYR98, &val98); + for (i = X; i <= Z; i++) { + bmi_read8(gyro->port, gyro->i2c_spi_addr_flags, + BMI_OFFSET_GYR70 + i, &val); + val |= ((val98 >> (2 * i)) & 0x3) << 8; + if (val > 0x1ff) + val = -1024 + val; + v[i] = round_divide( + (int64_t)val * BMI_OFFSET_GYRO_MULTI_MDS, + BMI_OFFSET_GYRO_DIV_MDS); + } +} + +void bmi_set_accel_offset(const struct motion_sensor_t *accel, intv3_t v) +{ + int i, val; + + for (i = X; i <= Z; ++i) { + val = round_divide( + (int64_t)v[i] * BMI_OFFSET_ACC_DIV_MG, + BMI_OFFSET_ACC_MULTI_MG); + if (val > 127) + val = 127; + if (val < -128) + val = -128; + if (val < 0) + val = 256 + val; + bmi_write8(accel->port, accel->i2c_spi_addr_flags, + BMI_OFFSET_ACC70 + i, val); + } +} + +void bmi_set_gyro_offset(const struct motion_sensor_t *gyro, intv3_t v, + int *val98_ptr) +{ + int i, val; + + for (i = X; i <= Z; i++) { + val = round_divide( + (int64_t)v[i] * BMI_OFFSET_GYRO_DIV_MDS, + BMI_OFFSET_GYRO_MULTI_MDS); + if (val > 511) + val = 511; + if (val < -512) + val = -512; + if (val < 0) + val = 1024 + val; + bmi_write8(gyro->port, gyro->i2c_spi_addr_flags, + BMI_OFFSET_GYR70 + i, val & 0xFF); + *val98_ptr &= ~(0x3 << (2 * i)); + *val98_ptr |= (val >> 8) << (2 * i); + } +} + diff --git a/driver/accelgyro_bmi_common.h b/driver/accelgyro_bmi_common.h new file mode 100644 index 0000000000..cf7f0d06cb --- /dev/null +++ b/driver/accelgyro_bmi_common.h @@ -0,0 +1,327 @@ +/* Copyright 2020 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. + */ +/* BMI accelerometer and gyro common definitions for Chrome EC */ + +#ifndef __CROS_EC_ACCELGYRO_BMI_COMMON_H +#define __CROS_EC_ACCELGYRO_BMI_COMMON_H + +#include "accelgyro.h" +#include "driver/accelgyro_bmi160.h" +#include "mag_bmm150.h" + +#define BMI_CONF_REG(_sensor) (0x40 + 2 * (_sensor)) +#define BMI_RANGE_REG(_sensor) (0x41 + 2 * (_sensor)) + +#define BMI_ODR_MASK 0x0F +/* odr = 100 / (1 << (8 - reg)) , within limit */ +#define BMI_ODR_0_78HZ 0x01 +#define BMI_ODR_100HZ 0x08 + +#define BMI_REG_TO_ODR(_regval) \ + ((_regval) < BMI_ODR_100HZ ? 100000 / (1 << (8 - (_regval))) : \ + 100000 * (1 << ((_regval) - 8))) +#define BMI_ODR_TO_REG(_odr) \ + ((_odr) < 100000 ? (__builtin_clz(100000 / ((_odr) + 1)) - 24) : \ + (39 - __builtin_clz((_odr) / 100000))) + +enum fifo_header { + BMI_FH_EMPTY = 0x80, + BMI_FH_SKIP = 0x40, + BMI_FH_TIME = 0x44, + BMI_FH_CONFIG = 0x48 +}; + +#define BMI_FH_MODE_MASK 0xc0 +#define BMI_FH_PARM_OFFSET 2 +#define BMI_FH_PARM_MASK (0x7 << BMI_FH_PARM_OFFSET) +#define BMI_FH_EXT_MASK 0x03 + +/* Sensor resolution in number of bits. This sensor has fixed resolution. */ +#define BMI_RESOLUTION 16 +/* Min and Max sampling frequency in mHz */ +#define BMI_ACCEL_MIN_FREQ 12500 +#define BMI_ACCEL_MAX_FREQ MOTION_MAX_SENSOR_FREQUENCY(1600000, 100000) +#define BMI_GYRO_MIN_FREQ 25000 +#define BMI_GYRO_MAX_FREQ MOTION_MAX_SENSOR_FREQUENCY(3200000, 100000) + +enum bmi_running_mode { + STANDARD_UI_9DOF_FIFO = 0, + STANDARD_UI_IMU_FIFO = 1, + STANDARD_UI_IMU = 2, + STANDARD_UI_ADVANCEPOWERSAVE = 3, + ACCEL_PEDOMETER = 4, + APPLICATION_HEAD_TRACKING = 5, + APPLICATION_NAVIGATION = 6, + APPLICATION_REMOTE_CONTROL = 7, + APPLICATION_INDOOR_NAVIGATION = 8, +}; + +#define BMI_FLAG_SEC_I2C_ENABLED BIT(0) +#define BMI_FIFO_FLAG_OFFSET 4 +#define BMI_FIFO_ALL_MASK 7 + +struct bmi_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_BMI_BMM150 + struct bmm150_private_data compass; +#endif +#ifdef CONFIG_BMI_ORIENTATION_SENSOR + uint8_t raw_orientation; + enum motionsensor_orientation orientation; + enum motionsensor_orientation last_orientation; +#endif + +}; + +#define BMI_GET_DATA(_s) \ + ((struct bmi_drv_data_t *)(_s)->drv_data) +#define BMI_GET_SAVED_DATA(_s) \ + (&BMI_GET_DATA(_s)->saved_data[(_s)->type]) + +#ifdef CONFIG_BMI_ORIENTATION_SENSOR +#define ORIENTATION_CHANGED(_sensor) \ + (BMI_GET_DATA(_sensor)->orientation != \ + BMI_GET_DATA(_sensor)->last_orientation) + +#define GET_ORIENTATION(_sensor) \ + (BMI_GET_DATA(_sensor)->orientation) + +#define SET_ORIENTATION(_sensor, _val) \ + (BMI_GET_DATA(_sensor)->orientation = _val) + +#define SET_ORIENTATION_UPDATED(_sensor) \ + (BMI_GET_DATA(_sensor)->last_orientation = \ + BMI_GET_DATA(_sensor)->orientation) +#endif + +#define BMI_ACC_DATA BMI160_ACC_X_L_G +#define BMI_GYR_DATA BMI160_GYR_X_L_G +#define BMI_AUX_DATA BMI160_MAG_X_L_G + +#define BMI_FIFO_CONFIG_0 BMI160_FIFO_CONFIG_0 +#define BMI_FIFO_CONFIG_1 BMI160_FIFO_CONFIG_1 +#define BMI_FIFO_SENSOR_EN(_sensor) BMI160_FIFO_SENSOR_EN(_sensor) + +#define BMI_TEMPERATURE_0 BMI160_TEMPERATURE_0 +#define BMI_INVALID_TEMP 0x8000 + +#define BMI_STATUS BMI160_STATUS +#define BMI_DRDY_OFF(_sensor) (7 - (_sensor)) +#define BMI_DRDY_MASK(_sensor) (1 << BMI160_DRDY_OFF(_sensor)) + +#define BMI_OFFSET_ACC70 BMI160_OFFSET_ACC70 +#define BMI_OFFSET_GYR70 BMI160_OFFSET_GYR70 +/* + * There is some bits in this register that differ between BMI160 and BMI260 + * Only use this macro for gyro offset 9:8 (BMI_OFFSET_EN_GYR98 5:0). + */ +#define BMI_OFFSET_EN_GYR98 BMI160_OFFSET_EN_GYR98 +#define BMI_OFFSET_GYR98_MASK (BIT(6) - 1) +#define BMI_OFFSET_ACC_MULTI_MG (3900 * 1024) +#define BMI_OFFSET_ACC_DIV_MG 1000000 +#define BMI_OFFSET_GYRO_MULTI_MDS (61 * 1024) +#define BMI_OFFSET_GYRO_DIV_MDS 1000 + +#define BMI_FIFO_LENGTH_0 BMI160_FIFO_LENGTH_0 +#define BMI_FIFO_LENGTH_MASK BMI160_FIFO_LENGTH_MASK +#define BMI_FIFO_DATA BMI160_FIFO_DATA + +#define BMI_CMD_REG BMI160_CMD_REG +#define BMI_CMD_FIFO_FLUSH 0xb0 + + + +/* + * Struct for pairing an engineering value with the register value for a + * parameter. + */ +struct bmi_accel_param_pair { + int val; /* Value in engineering units. */ + int reg_val; /* Corresponding register value. */ +}; + +int bmi_get_xyz_reg(const struct motion_sensor_t *s); + +/** + * @param type Accel/Gyro + * @param psize Size of the table + * + * @return Range table of the type. + */ +const struct bmi_accel_param_pair *bmi_get_range_table( + const struct motion_sensor_t *s, int *psize); + +/** + * @return reg value that matches the given engineering value passed in. + * The round_up flag is used to specify whether to round up or down. + * Note, this function always returns a valid reg value. If the request is + * outside the range of values, it returns the closest valid reg value. + */ +int bmi_get_reg_val(const int eng_val, const int round_up, + const struct bmi_accel_param_pair *pairs, + const int size); + +/** + * @return engineering value that matches the given reg val + */ +int bmi_get_engineering_val(const int reg_val, + const struct bmi_accel_param_pair *pairs, + const int size); + +#ifdef CONFIG_SPI_ACCEL_PORT +int bmi_spi_raw_read(const int addr, const uint8_t reg, + uint8_t *data, const int len); +#endif + +/** + * Read 8bit register from accelerometer. + */ +int bmi_read8(const int port, const uint16_t i2c_spi_addr_flags, + const int reg, int *data_ptr); + +/** + * Write 8bit register from accelerometer. + */ +int bmi_write8(const int port, const uint16_t i2c_spi_addr_flags, + const int reg, int data); + +/** + * Read 16bit register from accelerometer. + */ +int bmi_read16(const int port, const uint16_t i2c_spi_addr_flags, + const uint8_t reg, int *data_ptr); + +/** + * Write 16bit register from accelerometer. + */ +int bmi_write16(const int port, const uint16_t i2c_spi_addr_flags, + const int reg, int data); + +/** + * Read 32bit register from accelerometer. + */ +int bmi_read32(const int port, const uint16_t i2c_spi_addr_flags, + const uint8_t reg, int *data_ptr); + +/** + * Read n bytes from accelerometer. + */ +int bmi_read_n(const int port, const uint16_t i2c_spi_addr_flags, + const uint8_t reg, uint8_t *data_ptr, const int len); + +/** + * Write n bytes from accelerometer. + */ +int bmi_write_n(const int port, const uint16_t i2c_spi_addr_flags, + const uint8_t reg, const uint8_t *data_ptr, const int len); + +/* + * Enable/Disable specific bit set of a 8-bit reg. + */ +int bmi_enable_reg8(const struct motion_sensor_t *s, + int reg, uint8_t bits, int enable); + +/* + * Set specific bit set to certain value of a 8-bit reg. + */ +int bmi_set_reg8(const struct motion_sensor_t *s, int reg, + uint8_t bits, int mask); + +/* + * @s: base sensor. + * @v: output vector. + * @input: 6-bits array input. + */ +void bmi_normalize(const struct motion_sensor_t *s, intv3_t v, uint8_t *input); + +/* + * Decode the header from the fifo. + * Return 0 if we need further processing. + * Sensor mutex must be held during processing, to protect the fifos. + * + * @accel: base sensor + * @hdr: the header to decode + * @last_ts: the last timestamp of fifo interrupt. + * @bp: current pointer in the buffer, updated when processing the header. + * @ep: pointer to the end of the valid data in the buffer. + */ +int bmi_decode_header(struct motion_sensor_t *accel, + enum fifo_header hdr, uint32_t last_ts, + uint8_t **bp, uint8_t *ep); +/** + * Retrieve hardware FIFO from sensor, + * - put data in Sensor Hub fifo. + * - update sensor raw_xyz vector with the last information. + * We put raw data in hub fifo and process data from there. + * @s: Pointer to sensor data. + * @last_ts: The last timestamp of fifo interrupt. + * + * Read only up to bmi_buffer. If more reads are needed, we will be called + * again by the interrupt routine. + * + * NOTE: If a new driver supports this function, be sure to add a check + * for spoof_mode in order to load the sensor stack with the spoofed + * data. See accelgyro_bmi260.c::load_fifo for an example. + */ +int bmi_load_fifo(struct motion_sensor_t *s, uint32_t last_ts); + +int bmi_set_range(const struct motion_sensor_t *s, int range, int rnd); + +int bmi_get_range(const struct motion_sensor_t *s); + +int bmi_get_data_rate(const struct motion_sensor_t *s); + + +int bmi_get_offset(const struct motion_sensor_t *s, + int16_t *offset, int16_t *temp); + +int bmi_get_resolution(const struct motion_sensor_t *s); + +int bmi_set_scale(const struct motion_sensor_t *s, + const uint16_t *scale, int16_t temp); + +int bmi_get_scale(const struct motion_sensor_t *s, + uint16_t *scale, int16_t *temp); + +/* Start/Stop the FIFO collecting events */ +int bmi_enable_fifo(const struct motion_sensor_t *s, int enable); + +/* Read the xyz data of accel/gyro */ +int bmi_read(const struct motion_sensor_t *s, intv3_t v); + +/* Read temperature of sensor s */ +int bmi_read_temp(const struct motion_sensor_t *s, int *temp_ptr); + +/* Read temperature of sensor idx */ +int bmi_get_sensor_temp(int idx, int *temp_ptr); + +/* + * Get the normalized rate according to input rate and input rnd + * @rate: input rate + * @rnd: round up + * @normalized_rate_ptr: normalized rate pointer for output + * @reg_val_ptr: pointer to the actual register value of normalized rate for + * output. + */ +int bmi_get_normalized_rate(const struct motion_sensor_t *s, int rate, int rnd, + int *normalized_rate_ptr, uint8_t *reg_val_ptr); + +/* Get the accelerometer offset */ +void bmi_accel_get_offset(const struct motion_sensor_t *accel, intv3_t v); + +/* Get the gyroscope offset */ +void bmi_gyro_get_offset(const struct motion_sensor_t *gyro, intv3_t v); + +/* Set the accelerometer offset */ +void bmi_set_accel_offset(const struct motion_sensor_t *accel, intv3_t v); + +/* Set the gyroscope offset */ +void bmi_set_gyro_offset(const struct motion_sensor_t *gyro, intv3_t v, + int *val98_ptr); + +#endif /* __CROS_EC_ACCELGYRO_BMI_COMMON_H */ diff --git a/driver/build.mk b/driver/build.mk index d8acfc2d01..a4d80d429b 100644 --- a/driver/build.mk +++ b/driver/build.mk @@ -14,8 +14,8 @@ driver-$(CONFIG_ACCEL_BMA255)+=accel_bma2x2.o driver-$(CONFIG_ACCEL_KXCJ9)+=accel_kionix.o driver-$(CONFIG_ACCEL_KX022)+=accel_kionix.o driver-$(CONFIG_ACCELGYRO_LSM6DS0)+=accelgyro_lsm6ds0.o -driver-$(CONFIG_ACCELGYRO_BMI160)+=accelgyro_bmi160.o -driver-$(CONFIG_MAG_BMI160_BMM150)+=mag_bmm150.o +driver-$(CONFIG_ACCELGYRO_BMI160)+=accelgyro_bmi160.o accelgyro_bmi_common.o +driver-$(CONFIG_MAG_BMI_BMM150)+=mag_bmm150.o driver-$(CONFIG_ACCELGYRO_LSM6DSM)+=accelgyro_lsm6dsm.o stm_mems_common.o driver-$(CONFIG_ACCELGYRO_LSM6DSO)+=accelgyro_lsm6dso.o stm_mems_common.o driver-$(CONFIG_ACCEL_LIS2D_COMMON)+=accel_lis2dh.o stm_mems_common.o diff --git a/driver/mag_bmm150.c b/driver/mag_bmm150.c index 7490de3f38..2289a730f9 100644 --- a/driver/mag_bmm150.c +++ b/driver/mag_bmm150.c @@ -17,8 +17,8 @@ #include "timer.h" #include "util.h" -#ifdef CONFIG_MAG_BMI160_BMM150 -#include "driver/accelgyro_bmi160.h" +#ifdef CONFIG_MAG_BMI_BMM150 +#include "driver/accelgyro_bmi_common.h" #define raw_mag_read8 bmi160_sec_raw_read8 #define raw_mag_write8 bmi160_sec_raw_write8 #else diff --git a/driver/mag_bmm150.h b/driver/mag_bmm150.h index 79c77e66d7..f97d2a8882 100644 --- a/driver/mag_bmm150.h +++ b/driver/mag_bmm150.h @@ -112,20 +112,21 @@ struct bmm150_private_data { struct mag_cal_t cal; struct bmm150_comp_registers comp; }; + +#ifdef CONFIG_MAG_BMI_BMM150 +#include "accelgyro_bmi_common.h" + #define BMM150_COMP_REG(_s) \ - (&BMI160_GET_DATA(_s)->compass.comp) + (&BMI_GET_DATA(_s)->compass.comp) #define BMM150_CAL(_s) \ - (&BMI160_GET_DATA(_s)->compass.cal) - -#ifdef CONFIG_MAG_BMI160_BMM150 -#include "accelgyro_bmi160.h" + (&BMI_GET_DATA(_s)->compass.cal) /* - * Behind a BMI160, the BMM150 is in forced mode. Be sure to choose a frequency - * comptible with BMI160. + * Behind a BMI, the BMM150 is in forced mode. Be sure to choose a frequency + * compatible with BMI. */ #define BMM150_MAG_MAX_FREQ(_preset) \ - BMI160_REG_TO_ODR(BMI160_ODR_TO_REG(__BMM150_MAG_MAX_FREQ(_preset))) + BMI_REG_TO_ODR(BMI_ODR_TO_REG(__BMM150_MAG_MAX_FREQ(_preset))) #else #define BMM150_MAG_MAX_FREQ(_preset) __BMM150_MAG_MAX_FREQ(_preset) #endif diff --git a/driver/mag_lis2mdl.c b/driver/mag_lis2mdl.c index 1f05800c08..a9a00cc7c9 100644 --- a/driver/mag_lis2mdl.c +++ b/driver/mag_lis2mdl.c @@ -33,7 +33,7 @@ void lis2mdl_normalize(const struct motion_sensor_t *s, struct mag_cal_t *cal = LIS2MDL_CAL(s); int i; -#ifdef CONFIG_MAG_BMI160_LIS2MDL +#ifdef CONFIG_MAG_BMI_LIS2MDL struct lis2mdl_private_data *private = LIS2MDL_DATA(s); intv3_t hn1; diff --git a/driver/mag_lis2mdl.h b/driver/mag_lis2mdl.h index fb50b9712a..a7c47ec00e 100644 --- a/driver/mag_lis2mdl.h +++ b/driver/mag_lis2mdl.h @@ -62,7 +62,7 @@ struct lis2mdl_private_data { #ifndef CONFIG_LSM6DSM_SEC_I2C struct stprivate_data data; #endif -#ifdef CONFIG_MAG_BMI160_LIS2MDL +#ifdef CONFIG_MAG_BMI_LIS2MDL intv3_t hn; /* last sample for offset compensation */ int hn_valid; #endif diff --git a/include/config.h b/include/config.h index 984204f5dc..2665ae5e01 100644 --- a/include/config.h +++ b/include/config.h @@ -133,14 +133,16 @@ #undef CONFIG_MAG_LIS2MDL #undef CONFIG_MAG_BMM150 -/* Presence of a Bosh Sensortec BMM150 magnetometer behind a BMI160. */ +/* Presence of a Bosh Sensortec BMM150 magnetometer behind a BMIxxx. */ #undef CONFIG_MAG_BMI160_BMM150 +#undef CONFIG_MAG_BMI_BMM150 /* Presence of a Bosh Sensortec BMM150 magnetometer behind a LSM6DSM. */ #undef CONFIG_MAG_LSM6DSM_BMM150 -/* Presence of a ST LIS2MDL magnetometer behind a BMI160. */ +/* Presence of a ST LIS2MDL magnetometer behind a BMIxxx. */ #undef CONFIG_MAG_BMI160_LIS2MDL +#undef CONFIG_MAG_BMI_LIS2MDL /* Presence of a ST LIS2MDL magnetometer behind a LSM6DSM. */ #undef CONFIG_MAG_LSM6DSM_LIS2MDL @@ -148,14 +150,14 @@ /* Specify barometer attached */ #undef CONFIG_BARO_BMP280 -/* When set, it indicates a secondary sensor is attached behind a BMI160. */ -#undef CONFIG_BMI160_SEC_I2C +/* When set, it indicates a secondary sensor is attached behind a BMIxxx. */ +#undef CONFIG_BMI_SEC_I2C /* When set, it indicates a secondary sensor is attached behind a LSM6DSM/L. */ #undef CONFIG_LSM6DSM_SEC_I2C -/* Support for BMI160 hardware orientation sensor */ -#undef CONFIG_BMI160_ORIENTATION_SENSOR +/* Support for BMIxxx hardware orientation sensor */ +#undef CONFIG_BMI_ORIENTATION_SENSOR /* Support for KIONIX KX022 hardware orientation sensor */ #undef CONFIG_KX022_ORIENTATION_SENSOR @@ -164,7 +166,7 @@ #undef CONFIG_ACCELGYRO_SEC_ADDR_FLAGS /* - * Define if either CONFIG_BMI160_ORIENTATION_SUPPORT or + * Define if either CONFIG_BMI_ORIENTATION_SUPPORT or * CONFIG_KX022_ORIENTATION_SUPPORT is set. */ #undef CONFIG_ORIENTATION_SENSOR @@ -188,7 +190,7 @@ */ #undef CONFIG_ACCEL_STD_REF_FRAME_OLD -/* Set when INT2 is an ouptut */ +/* Set when INT2 is an output */ #undef CONFIG_ACCELGYRO_BMI160_INT2_OUTPUT /* Specify type of Gyrometers attached. */ @@ -4542,6 +4544,18 @@ #include "board.h" /* + * Define BMI macro when BMI160 is defined + * TODO(chingkang): replace all BMI160 macro by BMI. + */ +#ifdef CONFIG_MAG_BMI160_BMM150 +#define CONFIG_MAG_BMI_BMM150 +#endif + +#ifdef CONFIG_MAG_BMI160_LIS2MDL +#define CONFIG_MAG_BMI_LIS2MDL +#endif + +/* * Define CONFIG_HOST_ESPI_VW_POWER_SIGNAL if any power signals from the host * are configured as virtual wires. */ @@ -4749,7 +4763,7 @@ /******************************************************************************/ /* Set generic orientation config if a specific orientation config is set. */ #if defined(CONFIG_KX022_ORIENTATION_SENSOR) || \ - defined(CONFIG_BMI160_ORIENTATION_SENSOR) + defined(CONFIG_BMI_ORIENTATION_SENSOR) #ifndef CONFIG_ACCEL_FIFO #error CONFIG_ACCEL_FIFO must be defined to use hw orientation sensor support #endif @@ -5125,10 +5139,10 @@ CONFIG_EC_MAX_SENSOR_FREQ_DEFAULT_MILLIHZ #endif -/* Enable BMI160 secondary port if needed. */ -#if defined(CONFIG_MAG_BMI160_BMM150) || \ - defined(CONFIG_MAG_BMI160_LIS2MDL) -#define CONFIG_BMI160_SEC_I2C +/* Enable BMI secondary port if needed. */ +#if defined(CONFIG_MAG_BMI_BMM150) || \ + defined(CONFIG_MAG_BMI_LIS2MDL) +#define CONFIG_BMI_SEC_I2C #endif /* Enable LSM2MDL secondary port if needed. */ @@ -5138,7 +5152,7 @@ #endif /* Load LIS2MDL driver if needed */ -#if defined(CONFIG_MAG_BMI160_LIS2MDL) || \ +#if defined(CONFIG_MAG_BMI_LIS2MDL) || \ defined(CONFIG_MAG_LSM6DSM_LIS2MDL) #define CONFIG_MAG_LIS2MDL #ifndef CONFIG_ACCELGYRO_SEC_ADDR_FLAGS @@ -5147,7 +5161,7 @@ #endif /* Load BMM150 driver if needed */ -#if defined(CONFIG_MAG_BMI160_BMM150) || \ +#if defined(CONFIG_MAG_BMI_BMM150) || \ defined(CONFIG_MAG_LSM6DSM_BMM150) #define CONFIG_MAG_BMM150 #ifndef CONFIG_ACCELGYRO_SEC_ADDR_FLAGS |