summaryrefslogtreecommitdiff
path: root/driver/accelgyro_lsm6dso.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/accelgyro_lsm6dso.c')
-rw-r--r--driver/accelgyro_lsm6dso.c490
1 files changed, 0 insertions, 490 deletions
diff --git a/driver/accelgyro_lsm6dso.c b/driver/accelgyro_lsm6dso.c
deleted file mode 100644
index fbce687f2c..0000000000
--- a/driver/accelgyro_lsm6dso.c
+++ /dev/null
@@ -1,490 +0,0 @@
-/* Copyright 2019 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.
- */
-
-/**
- * LSM6DSO Accel and Gyro module for Chrome EC
- * 3D digital accelerometer & 3D digital gyroscope
- *
- * For any details on driver implementation please
- * Refer to AN5192 Application Note on www.st.com
- */
-
-#include "driver/accelgyro_lsm6dso.h"
-#include "hooks.h"
-#include "hwtimer.h"
-#include "math_util.h"
-#include "motion_sense_fifo.h"
-#include "task.h"
-#include "timer.h"
-
-#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args)
-
-STATIC_IF(CONFIG_ACCEL_FIFO) volatile uint32_t last_interrupt_timestamp;
-STATIC_IF(CONFIG_ACCEL_INTERRUPTS) int config_interrupt(
- const struct motion_sensor_t *s);
-
-/*
- * When ODR change, the sensor filters need settling time;
- * Add a counter to discard a well known number of data with
- * incorrect values.
- */
-static uint32_t samples_to_discard[LSM6DSO_FIFO_DEV_NUM];
-
-/**
- * @return output data base register for sensor
- */
-static inline int get_xyz_reg(enum motionsensor_type type)
-{
- return LSM6DSO_ACCEL_OUT_X_L_ADDR -
- (LSM6DSO_ACCEL_OUT_X_L_ADDR - LSM6DSO_GYRO_OUT_X_L_ADDR) * type;
-}
-
-#ifdef CONFIG_ACCEL_INTERRUPTS
-/**
- * Configure interrupt int 1 to fire handler for:
- *
- * FIFO threshold on watermark (1 sample)
- *
- * @s: Motion sensor pointer
- */
-static int config_interrupt(const struct motion_sensor_t *s)
-{
- int ret = EC_SUCCESS;
- int int1_ctrl_val;
-
- if (!IS_ENABLED(CONFIG_ACCEL_FIFO))
- return ret;
-
- ret = st_raw_read8(s->port, s->i2c_spi_addr_flags, LSM6DSO_INT1_CTRL,
- &int1_ctrl_val);
- if (ret != EC_SUCCESS)
- return ret;
-
- /*
- * Configure FIFO threshold to 1 sample: interrupt on watermark
- * will be generated every time a new data sample will be stored
- * in FIFO. The interrupr on watermark is cleared only when the
- * number or samples still present in FIFO exceeds the
- * configured threshold.
- */
- ret = st_raw_write8(s->port, s->i2c_spi_addr_flags,
- LSM6DSO_FIFO_CTRL1_ADDR, 1);
- if (ret != EC_SUCCESS)
- return ret;
-
- int1_ctrl_val |= LSM6DSO_INT_FIFO_TH | LSM6DSO_INT_FIFO_OVR |
- LSM6DSO_INT_FIFO_FULL;
-
- ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, LSM6DSO_INT1_CTRL,
- int1_ctrl_val);
-
- return ret;
-}
-
-/**
- * fifo_disable - set fifo mode to LSM6DSO_FIFO_MODE_BYPASS_VAL
- * @s: Motion sensor pointer: must be MOTIONSENSE_TYPE_ACCEL.
- */
-static int fifo_disable(const struct motion_sensor_t *s)
-{
- return st_raw_write8(s->port, s->i2c_spi_addr_flags,
- LSM6DSO_FIFO_CTRL4_ADDR,
- LSM6DSO_FIFO_MODE_BYPASS_VAL);
-}
-
-/**
- * set_fifo_params - Configure internal FIFO parameters
- *
- * Configure FIFO decimator to have every time the right pattern
- * with acc/gyro
- */
-static int fifo_enable(const struct motion_sensor_t *s)
-{
- return st_raw_write8(s->port, s->i2c_spi_addr_flags,
- LSM6DSO_FIFO_CTRL4_ADDR,
- LSM6DSO_FIFO_MODE_CONTINUOUS_VAL);
-}
-
-/**
- * push_fifo_data - Scan data pattern and push upside
- */
-static void push_fifo_data(struct motion_sensor_t *main_s, uint8_t *fifo,
- uint32_t saved_ts)
-{
- struct ec_response_motion_sensor_data vect;
- struct motion_sensor_t *sensor;
- uint8_t tag;
- int id;
- int *axis;
- uint8_t *ptr;
- uint8_t ag_maps[] = {
- MOTIONSENSE_TYPE_GYRO,
- MOTIONSENSE_TYPE_ACCEL,
- };
-
- /*
- * FIFO pattern is as follow (i.e. Acc/Gyro @ same ODR)
- * ________ ____________ _______ ____________
- * | TAG_XL | Acc[x,y,z] | TAG_G | Gyr[x,y,z] |
- * |________|____________|_______|____________|
- * |<-------- 1 -------->|<-------- 2 ------->| (FIFO Threshold)
- *
- * First byte is tag, next data.
- * Data pattern len is fixed for each sample.
- * FIFO threshold is related to sample data (7 byte).
- */
- ptr = fifo + LSM6DSO_TAG_SIZE;
- tag = (*fifo >> 3) - LSM6DSO_GYRO_TAG;
- id = ag_maps[tag];
-
- /* Discard samples every ODR changes. */
- if (samples_to_discard[id] > 0) {
- samples_to_discard[id]--;
- return;
- }
-
- sensor = main_s + id;
- axis = sensor->raw_xyz;
-
- /* Apply precision, sensitivity and rotation. */
- st_normalize(sensor, axis, ptr);
- vect.data[X] = axis[X];
- vect.data[Y] = axis[Y];
- vect.data[Z] = axis[Z];
-
- vect.flags = 0;
- vect.sensor_num = sensor - motion_sensors;
- motion_sense_fifo_stage_data(&vect, sensor, 3, saved_ts);
-}
-
-static inline int load_fifo(struct motion_sensor_t *main_s,
- const uint16_t fifo_len,
- uint32_t saved_ts)
-{
- uint8_t fifo[LSM6DSO_FIFO_SAMPLE_SIZE];
- int i, err;
-
- for (i = 0; i < fifo_len; i++) {
- err = st_raw_read_n_noinc(main_s->port,
- main_s->i2c_spi_addr_flags,
- LSM6DSO_FIFO_DATA_ADDR_TAG,
- fifo, LSM6DSO_FIFO_SAMPLE_SIZE);
- if (err != EC_SUCCESS)
- return err;
-
- push_fifo_data(main_s, fifo, saved_ts);
- }
-
- return EC_SUCCESS;
-}
-
-/**
- * accelgyro_config_fifo - update mode and ODR for FIFO decimator
- */
-static int accelgyro_config_fifo(const struct motion_sensor_t *s)
-{
- int err;
- struct stprivate_data *data = LSM6DSO_GET_DATA(s);
- uint8_t reg_val;
- uint8_t fifo_odr_mask;
-
- /* Changing in ODR must stop FIFO. */
- err = fifo_disable(s);
- if (err != EC_SUCCESS)
- return err;
-
- /*
- * If ODR changes restore to default discard samples number
- * the counter related to this sensor.
- */
- samples_to_discard[s->type] = LSM6DSO_DISCARD_SAMPLES;
-
- fifo_odr_mask = LSM6DSO_FIFO_ODR_MASK(s);
- reg_val = LSM6DSO_ODR_TO_REG(data->base.odr);
- err = st_write_data_with_mask(s, LSM6DSO_FIFO_CTRL3_ADDR,
- fifo_odr_mask, reg_val);
- if (err != EC_SUCCESS)
- return err;
-
- return fifo_enable(s);
-}
-
-/**
- * lsm6dso_interrupt - interrupt from int1 pin of sensor
- */
-void lsm6dso_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_ACCEL_LSM6DSO_INT_EVENT);
-}
-
-/**
- * irq_handler - bottom half of the interrupt task sheduled by consumer
- */
-static int irq_handler(struct motion_sensor_t *s, uint32_t *event)
-{
- int ret = EC_SUCCESS, fifo_len = 0;
- struct lsm6dso_fstatus fsts;
- bool has_read_fifo = false;
-
- if ((s->type != MOTIONSENSE_TYPE_ACCEL) ||
- (!(*event & CONFIG_ACCEL_LSM6DSO_INT_EVENT)))
- return EC_ERROR_NOT_HANDLED;
-
- if (!IS_ENABLED(CONFIG_ACCEL_FIFO))
- return EC_SUCCESS;
-
- do {
- /* Read how many data patterns on FIFO to read. */
- ret = st_raw_read_n_noinc(s->port, s->i2c_spi_addr_flags,
- LSM6DSO_FIFO_STS1_ADDR,
- (uint8_t *)&fsts, sizeof(fsts));
- if (ret != EC_SUCCESS)
- break;
-
- if (fsts.len & (LSM6DSO_FIFO_DATA_OVR | LSM6DSO_FIFO_FULL))
- CPRINTS("%s FIFO Overrun: %04x", s->name, fsts.len);
-
- fifo_len = fsts.len & LSM6DSO_FIFO_DIFF_MASK;
- if (fifo_len) {
- ret = load_fifo(s, fifo_len, last_interrupt_timestamp);
- has_read_fifo = true;
- }
- } while (fifo_len != 0 && ret == EC_SUCCESS);
-
- if (ret == EC_SUCCESS && has_read_fifo)
- motion_sense_fifo_commit_data();
-
- return ret;
-}
-#endif /* CONFIG_ACCEL_INTERRUPTS */
-
-/**
- * set_range - set full scale range
- * @s: Motion sensor pointer
- * @range: Range
- * @rnd: Round up/down flag
- * Note: Range is sensitivity/gain for speed purpose
- */
-static int set_range(struct motion_sensor_t *s, int range, int rnd)
-{
- int err;
- uint8_t ctrl_reg, reg_val;
- int newrange = range;
-
- ctrl_reg = LSM6DSO_RANGE_REG(s->type);
- if (s->type == MOTIONSENSE_TYPE_ACCEL) {
- /* Adjust and check rounded value for Acc. */
- if (rnd && (newrange < LSM6DSO_ACCEL_NORMALIZE_FS(newrange)))
- newrange *= 2;
-
- if (newrange > LSM6DSO_ACCEL_FS_MAX_VAL)
- newrange = LSM6DSO_ACCEL_FS_MAX_VAL;
-
- reg_val = lsm6dso_accel_fs_reg(newrange);
- } else {
- /* Adjust and check rounded value for Gyro. */
- reg_val = LSM6DSO_GYRO_FS_REG(range);
- if (rnd && (range > LSM6DSO_GYRO_NORMALIZE_FS(reg_val)))
- reg_val++;
-
- if (reg_val > LSM6DSO_GYRO_FS_MAX_REG_VAL)
- reg_val = LSM6DSO_GYRO_FS_MAX_REG_VAL;
-
- newrange = LSM6DSO_GYRO_NORMALIZE_FS(reg_val);
- }
-
- mutex_lock(s->mutex);
- err = st_write_data_with_mask(s, ctrl_reg, LSM6DSO_RANGE_MASK,
- reg_val);
- if (err == EC_SUCCESS)
- s->current_range = newrange;
-
- mutex_unlock(s->mutex);
-
- return EC_SUCCESS;
-}
-
-/**
- * set_data_rate set sensor data rate
- * @s: Motion sensor pointer
- * @range: Rate (mHz)
- * @rnd: Round up/down flag
- */
-static int set_data_rate(const struct motion_sensor_t *s, int rate, int rnd)
-{
- int ret, normalized_rate = 0;
- struct stprivate_data *data = LSM6DSO_GET_DATA(s);
- uint8_t ctrl_reg, reg_val = 0;
-
- ctrl_reg = LSM6DSO_ODR_REG(s->type);
- if (rate > 0) {
- reg_val = LSM6DSO_ODR_TO_REG(rate);
- normalized_rate = LSM6DSO_REG_TO_ODR(reg_val);
-
- if (rnd && (normalized_rate < rate)) {
- reg_val++;
- normalized_rate = LSM6DSO_REG_TO_ODR(reg_val);
- }
-
- if (normalized_rate < LSM6DSO_ODR_MIN_VAL ||
- normalized_rate > LSM6DSO_ODR_MAX_VAL)
- return EC_RES_INVALID_PARAM;
- }
-
- mutex_lock(s->mutex);
- ret = st_write_data_with_mask(s, ctrl_reg, LSM6DSO_ODR_MASK, reg_val);
- if (ret == EC_SUCCESS) {
- data->base.odr = normalized_rate;
- if (IS_ENABLED(CONFIG_ACCEL_FIFO))
- accelgyro_config_fifo(s);
- }
-
- mutex_unlock(s->mutex);
-
- return ret;
-}
-
-static int is_data_ready(const struct motion_sensor_t *s, int *ready)
-{
- int ret, tmp;
-
- ret = st_raw_read8(s->port, s->i2c_spi_addr_flags,
- LSM6DSO_STATUS_REG, &tmp);
- if (ret != EC_SUCCESS) {
- CPRINTS("%s type:0x%X RS Error", s->name, s->type);
-
- return ret;
- }
-
- if (MOTIONSENSE_TYPE_ACCEL == s->type)
- *ready = (LSM6DSO_STS_XLDA_UP == (tmp & LSM6DSO_STS_XLDA_MASK));
- else
- *ready = (LSM6DSO_STS_GDA_UP == (tmp & LSM6DSO_STS_GDA_MASK));
-
- return EC_SUCCESS;
-}
-
-/*
- * Is not very efficient to collect the data in read: better have an interrupt
- * and collect in FIFO, even if it has one item: we don't have to check if the
- * sensor is ready (minimize I2C access).
- */
-static int read(const struct motion_sensor_t *s, intv3_t v)
-{
- uint8_t raw[OUT_XYZ_SIZE];
- uint8_t xyz_reg;
- int ret, tmp = 0;
-
- ret = is_data_ready(s, &tmp);
- 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 (!tmp) {
- if (v != s->raw_xyz)
- memcpy(v, s->raw_xyz, sizeof(s->raw_xyz));
-
- return EC_SUCCESS;
- }
-
- xyz_reg = get_xyz_reg(s->type);
-
- /* Read data bytes starting at xyz_reg. */
- ret = st_raw_read_n_noinc(s->port, s->i2c_spi_addr_flags,
- xyz_reg, raw, OUT_XYZ_SIZE);
- if (ret != EC_SUCCESS)
- return ret;
-
- /* Apply precision, sensitivity and rotation vector. */
- st_normalize(s, v, raw);
-
- return EC_SUCCESS;
-}
-
-static int init(struct motion_sensor_t *s)
-{
- int ret = 0, tmp;
- struct stprivate_data *data = LSM6DSO_GET_DATA(s);
-
- ret = st_raw_read8(s->port, s->i2c_spi_addr_flags,
- LSM6DSO_WHO_AM_I_REG, &tmp);
- if (ret != EC_SUCCESS)
- return EC_ERROR_UNKNOWN;
-
- if (tmp != LSM6DSO_WHO_AM_I)
- return EC_ERROR_ACCESS_DENIED;
-
- /*
- * This sensor can be powered through an EC reboot, so the state of the
- * sensor is unknown here so reset it
- * LSM6DSO supports both Acc & Gyro features
- * Board will see two virtual sensor devices: Acc & Gyro
- * Requirement: Acc need be init before Gyro
- */
- if (s->type == MOTIONSENSE_TYPE_ACCEL) {
- mutex_lock(s->mutex);
-
- /* Software reset. */
- ret = st_raw_write8(s->port, s->i2c_spi_addr_flags,
- LSM6DSO_CTRL3_ADDR, LSM6DSO_SW_RESET);
- if (ret != EC_SUCCESS)
- goto err_unlock;
-
- /*
- * Output data not updated until have been read.
- * Require interrupt to be active low.
- */
- ret = st_raw_write8(s->port, s->i2c_spi_addr_flags,
- LSM6DSO_CTRL3_ADDR,
- LSM6DSO_BDU | LSM6DSO_IF_INC
- | LSM6DSO_H_L_ACTIVE);
- if (ret != EC_SUCCESS)
- goto err_unlock;
-
- if (IS_ENABLED(CONFIG_ACCEL_FIFO)) {
- ret = fifo_disable(s);
- if (ret != EC_SUCCESS)
- goto err_unlock;
- }
-
- if (IS_ENABLED(CONFIG_ACCEL_INTERRUPTS))
- ret = config_interrupt(s);
- if (ret != EC_SUCCESS)
- goto err_unlock;
-
- mutex_unlock(s->mutex);
- }
-
- /* Set default resolution common to Acc and Gyro. */
- data->resol = LSM6DSO_RESOLUTION;
- return sensor_init_done(s);
-
-err_unlock:
- mutex_unlock(s->mutex);
- CPRINTS("%s: MS Init type:0x%X Error", s->name, s->type);
-
- return ret;
-}
-
-const struct accelgyro_drv lsm6dso_drv = {
- .init = init,
- .read = read,
- .set_range = set_range,
- .get_resolution = st_get_resolution,
- .set_data_rate = set_data_rate,
- .get_data_rate = st_get_data_rate,
- .set_offset = st_set_offset,
- .get_offset = st_get_offset,
-#ifdef CONFIG_ACCEL_INTERRUPTS
- .irq_handler = irq_handler,
-#endif /* CONFIG_ACCEL_INTERRUPTS */
-};