blob: 8fa53c6a6d88cffb06ee2275624b59c397f8d5bb [file] [log] [blame]
/* Copyright 2016 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* LSM6DSM (also LSM6DSL) Accel and Gyro driver for Chrome EC */
#ifndef __CROS_EC_ACCELGYRO_LSM6DSM_H
#define __CROS_EC_ACCELGYRO_LSM6DSM_H
#include "mag_bmm150.h"
#include "mag_cal.h"
#include "mag_lis2mdl.h"
#include "stm_mems_common.h"
/*
* 7-bit address is 110101xb. Where 'x' is determined
* by the voltage on the ADDR pin
*/
#define LSM6DSM_ADDR0_FLAGS 0x6a
#define LSM6DSM_ADDR1_FLAGS 0x6b
/* COMMON DEFINE FOR ACCEL-GYRO SENSORS */
#define LSM6DSM_EN_BIT 0x01
#define LSM6DSM_DIS_BIT 0x00
/* Access to embedded sensor hub register bank */
#define LSM6DSM_FUNC_CFG_ACC_ADDR 0x01
#define LSM6DSM_FUNC_CFG_EN 0x80
#define LSM6DSM_FUNC_CFG_EN_B 0x20
/* FIFO decimator registers and bitmask */
#define LSM6DSM_FIFO_CTRL1_ADDR 0x06
/* Output data rate registers and masks */
#define LSM6DSM_ODR_REG(_sensor) (LSM6DSM_CTRL1_ADDR + _sensor)
#define LSM6DSM_ODR_MASK 0xf0
#define LSM6DSM_FIFO_CTRL2_ADDR 0x07
#define LSM6DSM_FIFO_CTRL3_ADDR 0x08
#define LSM6DSM_FIFO_DEC_XL_OFF 0
#define LSM6DSM_FIFO_DEC_G_OFF 3
#define LSM6DSM_FIFO_CTRL4_ADDR 0x09
#define LSM6DSM_FIFO_DECIMATOR(_dec) \
(_dec < 8 ? _dec : (2 + __builtin_ctz(_dec)))
/* Hardware FIFO size in byte */
#define LSM6DSM_MAX_FIFO_SIZE 4096
#define LSM6DSM_MAX_FIFO_LENGTH (LSM6DSM_MAX_FIFO_SIZE / OUT_XYZ_SIZE)
#define LSM6DSM_FIFO_CTRL5_ADDR 0x0a
#define LSM6DSM_FIFO_CTRL5_ODR_OFF 3
#define LSM6DSM_FIFO_CTRL5_ODR_MASK (0xf << LSM6DSM_FIFO_CTRL5_ODR_OFF)
#define LSM6DSM_FIFO_CTRL5_MODE_MASK 0x07
#define LSM6DSM_INT1_CTRL 0x0d
#define LSM6DSM_INT_FIFO_TH 0x08
#define LSM6DSM_INT_FIFO_OVR 0x10
#define LSM6DSM_INT_FIFO_FULL 0x20
#define LSM6DSM_INT_SIGMO 0x40
/* Who Am I */
#define LSM6DSM_WHO_AM_I_REG 0x0f
/* LSM6DSM/LSM6DSL/LSM6DS3TR-C */
#define LSM6DSM_WHO_AM_I 0x6a
/* LSM6DS3 */
#define LSM6DS3_WHO_AM_I 0x69
#define LSM6DSM_CTRL1_ADDR 0x10
#define LSM6DSM_XL_ODR_MASK 0xf0
#define LSM6DSM_CTRL2_ADDR 0x11
#define LSM6DSM_CTRL3_ADDR 0x12
#define LSM6DSM_SW_RESET 0x01
#define LSM6DSM_IF_INC 0x04
#define LSM6DSM_PP_OD 0x10
#define LSM6DSM_H_L_ACTIVE 0x20
#define LSM6DSM_BDU 0x40
#define LSM6DSM_BOOT 0x80
#define LSM6DSM_CTRL4_ADDR 0x13
#define LSM6DSM_INT2_ON_INT1_MASK 0x20
#define LSM6DSM_CTRL6_ADDR 0x15
#define LSM6DSM_CTRL7_ADDR 0x16
#define LSM6DSM_CTRL10_ADDR 0x19
#define LSM6DSM_FUNC_EN_MASK 0x04
#define LSM6DSM_SIG_MOT_MASK 0x01
#define LSM6DSM_EMBED_FUNC_EN 0x04
#define LSM6DSM_SIG_MOT_EN 0x01
/* Controller mode configuration register */
#define LSM6DSM_CONTROLLER_CFG_ADDR 0x1a
#define LSM6DSM_PASSTROUGH_MASK 0x1f
#define LSM6DSM_EXT_TRIGGER_EN 0x10
#define LSM6DSM_PULLUP_EN 0x08
#define LSM6DSM_I2C_PASS_THRU_MODE 0x04
#define LSM6DSM_I2C_CONTROLLER_ON 0x01
#define LSM6DSM_TAP_SRC_ADDR 0x1c
#define LSM6DSM_STAP_DETECT 0x20
#define LSM6DSM_DTAP_DETECT 0x10
#define LSM6DSM_STATUS_REG 0x1e
#define LSM6DSM_OUT_TEMP_L_ADDR 0x20
#define LSM6DSM_GYRO_OUT_X_L_ADDR 0x22
#define LSM6DSM_ACCEL_OUT_X_L_ADDR 0x28
#define LSM6DSM_SENSORHUB1_REG 0x2e
#define LSM6DSM_FIFO_STS1_ADDR 0x3a
#define LSM6DSM_FIFO_STS2_ADDR 0x3b
#define LSM6DSM_FIFO_DIFF_MASK 0x0fff
#define LSM6DSM_FIFO_EMPTY 0x1000
#define LSM6DSM_FIFO_FULL 0x2000
#define LSM6DSM_FIFO_DATA_OVR 0x4000
#define LSM6DSM_FIFO_WATERMARK 0x8000
#define LSM6DSM_FIFO_NODECIM 0x01
/* Out data register */
#define LSM6DSM_FIFO_DATA_ADDR 0x3e
/* Registers value for supported FIFO mode */
#define LSM6DSM_FIFO_MODE_BYPASS_VAL 0x00
#define LSM6DSM_FIFO_MODE_CONTINUOUS_VAL 0x06
#define LSM6DSM_FUNC_SRC1_ADDR 0x53
#define LSM6DSM_SENSORHUB_END_OP 0x01
#define LSM6DSM_SIGN_MOTION_IA 0x40
#define LSM6DSM_LIR_ADDR 0x58
#define LSM6DSM_LIR_MASK 0x01
#define LSM6DSM_EN_INT 0x80
#define LSM6DSM_EN_TAP 0x0e
#define LSM6DSM_TAP_MASK 0x8e
#define LSM6DSM_TAP_THS_6D 0x59
#define LSM6DSM_D4D_EN_MASK 0x80
#define LSM6DSM_TAP_TH_MASK 0x1f
#define LSM6DSM_INT_DUR2_ADDR 0x5a
#define LSM6DSM_TAP_DUR_MASK 0xf0
#define LSM6DSM_TAP_QUIET_MASK 0x0c
#define LSM6DSM_WUP_THS_ADDR 0x5b
#define LSM6DSM_S_D_TAP_MASK 0x80
#define LSM6DSM_STAP_EN 0
#define LSM6DSM_DTAP_EN 1
#define LSM6DSM_MD1_CFG_ADDR 0x5e
#define LSM6DSM_INT1_STAP 0x40
#define LSM6DSM_INT1_DTAP 0x08
/* Register values for Sensor Hub Slave 0 / Bank A */
#define LSM6DSM_SLV0_ADD_ADDR 0x02
#define LSM6DSM_SLV0_ADDR_SHFT 1
#define LSM6DSM_SLV0_ADDR_MASK 0xfe
#define LSM6DSM_SLV0_RD_BIT 0x01
#define LSM6DSM_SLV0_SUBADD_ADDR 0x03
#define LSM6DSM_SLV0_CONFIG_ADDR 0x04
#define LSM6DSM_SLV0_SLV_RATE_SHFT 6
#define LSM6DSM_SLV0_SLV_RATE_MASK 0xc0
#define LSM6DSM_SLV0_AUX_SENS_SHFT 4
#define LSM6DSM_SLV0_AUX_SENS_MASK 0x30
#define LSM6DSM_SLV0_NUM_OPS_MASK 0x07
#define LSM6DSM_SLV1_CONFIG_ADDR 0x07
#define LSM6DSM_SLV0_WR_ONCE_MASK 0x20
#define LSM6DSM_DATA_WRITE_SUB_SLV0_ADDR 0x0e
/* Define device available in FIFO pattern */
enum dev_fifo {
FIFO_DEV_INVALID = -1,
FIFO_DEV_GYRO = 0,
FIFO_DEV_ACCEL,
FIFO_DEV_MAG,
};
#ifdef CONFIG_LSM6DSM_SEC_I2C
#define FIFO_DEV_NUM (FIFO_DEV_MAG + 1)
#else
#define FIFO_DEV_NUM (FIFO_DEV_ACCEL + 1)
#endif
struct fstatus {
uint16_t len;
uint16_t pattern;
};
/* Absolute maximum rate for acc and gyro sensors */
#define LSM6DSM_ODR_MIN_VAL 13000
#define LSM6DSM_ODR_MAX_VAL \
MOTION_MAX_SENSOR_FREQUENCY(416000, LSM6DSM_ODR_MIN_VAL)
/* ODR reg value from selected data rate in mHz */
#define LSM6DSM_ODR_TO_REG(_odr) (__fls(_odr / LSM6DSM_ODR_MIN_VAL) + 1)
/* normalized ODR value from selected data rate in mHz */
#define LSM6DSM_REG_TO_ODR(_reg) (LSM6DSM_ODR_MIN_VAL << (_reg - 1))
/* Full Scale range value and gain for Acc */
#define LSM6DSM_FS_LIST_NUM 4
#define LSM6DSM_ACCEL_FS_ADDR 0x10
#define LSM6DSM_ACCEL_FS_MASK 0x0c
#define LSM6DSM_ACCEL_FS_2G_VAL 0x00
#define LSM6DSM_ACCEL_FS_4G_VAL 0x02
#define LSM6DSM_ACCEL_FS_8G_VAL 0x03
#define LSM6DSM_ACCEL_FS_16G_VAL 0x01
#define LSM6DSM_ACCEL_FS_MAX_VAL 16
/* Accel Reg value from Full Scale */
#define LSM6DSM_ACCEL_FS_REG(_fs) \
(_fs == 2 ? LSM6DSM_ACCEL_FS_2G_VAL : \
_fs == 16 ? LSM6DSM_ACCEL_FS_16G_VAL : \
__fls(_fs))
/* Accel normalized FS value from Full Scale */
#define LSM6DSM_ACCEL_NORMALIZE_FS(_fs) (1 << __fls(_fs))
/* Full Scale range value and gain for Gyro */
#define LSM6DSM_GYRO_FS_ADDR 0x11
#define LSM6DSM_GYRO_FS_MASK 0x0c
/* Supported gyroscope ranges:
* name(dps) | register | gain(udps/LSB) | actual value(dps)
* 250 | 0 | 8750 | 286.72
* 500 | 1 | 17500 | 573.44
* 1000 | 2 | 35000 | 1146.88
* 2000 | 3 | 70000 | 2293.76
*/
#define LSM6DSM_GYRO_FS_MIN_VAL_MDPS ((8750 << 15) / 1000)
#define LSM6DSM_GYRO_FS_MAX_REG_VAL 3
/* Gyro Reg value for Full Scale selection */
#define LSM6DSM_GYRO_FS_REG(_fs) \
__fls(MAX(1, (_fs * 1000) / LSM6DSM_GYRO_FS_MIN_VAL_MDPS))
/* Gyro normalized FS value from Full Scale register */
#define LSM6DSM_GYRO_NORMALIZE_FS(_reg) \
((LSM6DSM_GYRO_FS_MIN_VAL_MDPS << (_reg)) / 1000)
/* FS register address/mask for Acc/Gyro sensors */
#define LSM6DSM_RANGE_REG(_sensor) (LSM6DSM_ACCEL_FS_ADDR + (_sensor))
#define LSM6DSM_RANGE_MASK 0x0c
/* Status register bitmask for Acc/Gyro data ready */
enum lsm6dsm_status {
LSM6DSM_STS_DOWN = 0x00,
LSM6DSM_STS_XLDA_UP = 0x01,
LSM6DSM_STS_GDA_UP = 0x02
};
#define LSM6DSM_STS_XLDA_MASK 0x01
#define LSM6DSM_STS_GDA_MASK 0x02
/* Sensor resolution in number of bits: fixed 16 bit */
#define LSM6DSM_RESOLUTION 16
extern const struct accelgyro_drv lsm6dsm_drv;
void lsm6dsm_interrupt(enum gpio_signal signal);
struct lsm6dsm_fifo_data {
/*
* FIFO data order is based on the ODR of each sensors.
* For example Acc @ 52 Hz, Gyro @ 26 Hz Mag @ 13 Hz in FIFO we have
* for each pattern this data samples:
* ________ _______ _______ _______ ________ _______ _______
* | Gyro_0 | Acc_0 | Mag_0 | Acc_1 | Gyro_1 | Acc_2 | Acc_3 |
* |________|_______|_______|_______|________|_______|_______|
*
* Total samples for each pattern: 2 Gyro, 4 Acc, 1 Mag
*/
/* Calculated samples in a pattern, based on ODR. */
int samples_in_pattern[FIFO_DEV_NUM];
/* Sum of all samples_in_pattern. */
int total_samples_in_pattern;
};
/**
* Structure used to hold fifo state. This struct should only be used if
* CONFIG_ACCEL_FIFO is defined.
*/
struct lsm6dsm_accel_fifo_state {
struct lsm6dsm_fifo_data config;
struct lsm6dsm_fifo_data current;
int next_in_pattern;
/*
* After an ODR change, the sensor filters need settling time; discard
* initial samples with incorrect values
*/
unsigned int samples_to_discard[FIFO_DEV_NUM];
};
/*
* lsm6dsm_data is used for accel gyro and the sensor connect to a LSM6DSM.
*
* +---- lsm6dsm_data ------------------------------------------------+
* | +--- stprivate_data ---+ |
* | | | ST common data for accelerometer |
* | +----------------------+ |
* | +--- stprivate_data ---+ |
* | | | ST common data for gyroscope |
* | +----------------------+ |
* | +--- stprivate_data ---+ |
* | | | ST common data for LIS2MDL magnetomer |
* | +----------------------+ (optional) |
* | |
* | Fifo Information |
* | |
* | +----- Magnetometer information -----------------------------+ |
* | | +--- mag_cal_t ------+ | |
* | | | | Data for online calibration | |
* | | +--------------------+ | |
* | | Other privata data | |
* | +------------------------------------------------------------+ |
* +------------------------------------------------------------------+
*
* In motion_sensors array, use LSM6DSM_ST_DATA to point drv_data
* to the right st_data structure.
*/
struct lsm6dsm_data {
#ifdef CONFIG_MAG_LSM6DSM_LIS2MDL
/* LIS2MDL uses st_mems_common and needs stprivate_data */
struct stprivate_data st_data[3];
#else
/* BMM150 doesn't use st_mems_common; no stprivate_data */
struct stprivate_data st_data[2];
#endif
struct lsm6dsm_accel_fifo_state *accel_fifo_state;
#if defined(CONFIG_LSM6DSM_SEC_I2C) && defined(CONFIG_MAG_CALIBRATE)
union {
#ifdef CONFIG_MAG_LSM6DSM_BMM150
struct bmm150_private_data compass;
#endif
#ifdef CONFIG_MAG_LSM6DSM_LIS2MDL
struct lis2mdl_private_data compass;
#endif
struct mag_cal_t cal;
};
#endif /* CONFIG_MAG_CALIBRATE */
};
#ifdef CONFIG_ACCEL_FIFO
#define LSM6DSM_ACCEL_FIFO_STATE (&((struct lsm6dsm_accel_fifo_state){}))
#else
#define LSM6DSM_ACCEL_FIFO_STATE NULL
#endif
#define LSM6DSM_DATA \
((struct lsm6dsm_data){ \
.accel_fifo_state = LSM6DSM_ACCEL_FIFO_STATE, \
})
/*
* Note: The specific number of samples to discard depends on the filters
* configured for the chip, as well as the ODR being set. For most of our
* allowed ODRs, 5 should suffice.
* See: ST's LSM6DSM application notes (AN4987) Tables 17 and 19 for details
*/
#define LSM6DSM_DISCARD_SAMPLES 5
#define LSM6DSM_ST_DATA(g, type) (&(&(g))->st_data[(type)])
#define LSM6DSM_MAIN_SENSOR(_s) ((_s) - (_s)->type)
#define LSM6DSM_GET_DATA(_s) \
((struct lsm6dsm_data *)(LSM6DSM_MAIN_SENSOR(_s))->drv_data)
#if defined(CONFIG_LSM6DSM_SEC_I2C) && defined(CONFIG_MAG_CALIBRATE)
#define LIS2MDL_CAL(_s) (&LSM6DSM_GET_DATA(_s)->cal)
#endif
int lsm6dsm_set_data_rate(const struct motion_sensor_t *s, int rate, int rnd);
#if defined(CONFIG_ZEPHYR)
/* Get the motion sensor ID of the LSM6DSM sensor that generates the
* interrupt. The interrupt is converted to the event and transferred to
* motion sense task that actually handles the interrupt.
*
* Here we use an alias (lsm6dsm_int) to get the motion sensor ID. This alias
* MUST be defined for this driver to work.
* aliases {
* lsm6dsm-int = &lid_accel;
* };
*/
#if DT_NODE_EXISTS(DT_ALIAS(lsm6dsm_int))
#define CONFIG_ACCEL_LSM6DSM_INT_EVENT \
TASK_EVENT_MOTION_SENSOR_INTERRUPT(SENSOR_ID(DT_ALIAS(lsm6dsm_int)))
#endif
#endif
#endif /* __CROS_EC_ACCELGYRO_LSM6DSM_H */