diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig index 993cc412544..dc57cc69ba8 100644 --- a/drivers/sensors/Kconfig +++ b/drivers/sensors/Kconfig @@ -24,6 +24,13 @@ config LIS331DL select I2C select I2C_TRANSFER +config SN_LSM9DS1 + bool "STMicro LSM9DS1 support" + default n + depends on I2C + ---help--- + Enable driver support for the STMicro LSM9DS1. + config MB7040 bool "MaxBotix MB7040 Sonar support" default n diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs index e4d38ca0758..902194a95ea 100644 --- a/drivers/sensors/Make.defs +++ b/drivers/sensors/Make.defs @@ -53,6 +53,10 @@ ifeq ($(CONFIG_LIS331DL),y) CSRCS += lis331dl.c endif +ifeq ($(CONFIG_SN_LSM9DS1),y) + CSRCS += lsm9ds1.c +endif + ifeq ($(CONFIG_ADXL345_I2C),y) CSRCS += adxl345_i2c.c endif diff --git a/drivers/sensors/lsm9ds1.c b/drivers/sensors/lsm9ds1.c new file mode 100644 index 00000000000..ba6e07784bf --- /dev/null +++ b/drivers/sensors/lsm9ds1.c @@ -0,0 +1,1554 @@ +/**************************************************************************** + * drivers/sensors/lsm9ds1.c + * + * Copyright (C) 2016 Omni Hoverboards Inc. All rights reserved. + * Author: Paul Alexander Patience + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#if defined(CONFIG_I2C) && defined(CONFIG_SN_LSM9DS1) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Register Addresses *******************************************************/ +/* Accelerometer and gyroscope registers */ + +#define LSM9DS1_ACT_THS 0x04 /* Inactivity threshold */ +#define LSM9DS1_ACT_DUR 0x05 /* Inactivity duration */ +#define LSM9DS1_INT_GEN_CFG_XL 0x06 /* Accelerometer interrupt configuration */ +#define LSM9DS1_INT_GEN_THS_X_XL 0x07 /* Accelerometer X interrupt threshold */ +#define LSM9DS1_INT_GEN_THS_Y_XL 0x08 /* Accelerometer Y interrupt threshold */ +#define LSM9DS1_INT_GEN_THS_Z_XL 0x09 /* Accelerometer Z interrupt threshold */ +#define LSM9DS1_INT_GEN_DUR_XL 0x0a /* Accelerometer interrupt duration */ +#define LSM9DS1_REFERENCE_G 0x0b /* Gyroscope reference value for high-pass filter */ +#define LSM9DS1_INT1_CTRL 0x0c /* INT1_A/G pin control */ +#define LSM9DS1_INT2_CTRL 0x0d /* INT2_A/G pin control */ +#define LSM9DS1_WHO_AM_I 0x0f /* Accelerometer and gyroscope device identification */ +#define LSM9DS1_CTRL_REG1_G 0x10 /* Gyroscope control register 1 */ +#define LSM9DS1_CTRL_REG2_G 0x11 /* Gyroscope control register 2 */ +#define LSM9DS1_CTRL_REG3_G 0x12 /* Gyroscope control register 3 */ +#define LSM9DS1_ORIENT_CFG_G 0x13 /* Gyroscope sign and orientation */ +#define LSM9DS1_INT_GEN_SRC_G 0x14 /* Gyroscope interrupt source */ +#define LSM9DS1_OUT_TEMP_L 0x15 /* Temperature low byte */ +#define LSM9DS1_OUT_TEMP_H 0x16 /* Temperature high byte */ +#define LSM9DS1_STATUS_REG 0x17 /* Status register */ +#define LSM9DS1_OUT_X_L_G 0x18 /* Gyroscope pitch (X) low byte */ +#define LSM9DS1_OUT_X_H_G 0x19 /* Gyroscope pitch (X) high byte */ +#define LSM9DS1_OUT_Y_L_G 0x1a /* Gyroscope roll (Y) low byte */ +#define LSM9DS1_OUT_Y_H_G 0x1b /* Gyroscope roll (Y) high byte */ +#define LSM9DS1_OUT_Z_L_G 0x1c /* Gyroscope yaw (Z) low byte */ +#define LSM9DS1_OUT_Z_H_G 0x1d /* Gyroscope yaw (Z) high byte */ +#define LSM9DS1_CTRL_REG4 0x1e /* Control register 4 */ +#define LSM9DS1_CTRL_REG5_XL 0x1f /* Accelerometer control register 5 */ +#define LSM9DS1_CTRL_REG6_XL 0x20 /* Accelerometer control register 6 */ +#define LSM9DS1_CTRL_REG7_XL 0x21 /* Accelerometer control register 7 */ +#define LSM9DS1_CTRL_REG8 0x22 /* Control register 8 */ +#define LSM9DS1_CTRL_REG9 0x23 /* Control register 9 */ +#define LSM9DS1_CTRL_REG10 0x24 /* Control register 10 */ +#define LSM9DS1_INT_GEN_SRC_XL 0x26 /* Accelerometer interrupt source */ +#define LSM9DS1_STATUS_REG2 0x27 /* Status register 2 */ +#define LSM9DS1_OUT_X_L_XL 0x28 /* Accelerometer X low byte */ +#define LSM9DS1_OUT_X_H_XL 0x29 /* Accelerometer X high byte */ +#define LSM9DS1_OUT_Y_L_XL 0x2a /* Accelerometer Y low byte */ +#define LSM9DS1_OUT_Y_H_XL 0x2b /* Accelerometer Y high byte */ +#define LSM9DS1_OUT_Z_L_XL 0x2c /* Accelerometer Z low byte */ +#define LSM9DS1_OUT_Z_H_XL 0x2d /* Accelerometer Z high byte */ +#define LSM9DS1_FIFO_CTRL 0x2e /* FIFO control register */ +#define LSM9DS1_FIFO_SRC 0x2f /* FIFO status control register */ +#define LSM9DS1_INT_GEN_CFG_G 0x30 /* Gyroscope interrupt configuration */ +#define LSM9DS1_INT_GEN_THS_XH_G 0x31 /* Gyroscope pitch (X) interrupt threshold high byte */ +#define LSM9DS1_INT_GEN_THS_XL_G 0x32 /* Gyroscope pitch (X) interrupt threshold low byte */ +#define LSM9DS1_INT_GEN_THS_YH_G 0x33 /* Gyroscope roll (Y) interrupt threshold high byte */ +#define LSM9DS1_INT_GEN_THS_YL_G 0x34 /* Gyroscope roll (Y) interrupt threshold low byte */ +#define LSM9DS1_INT_GEN_THS_ZH_G 0x35 /* Gyroscope yaw (Z) interrupt threshold high byte */ +#define LSM9DS1_INT_GEN_THS_ZL_G 0x36 /* Gyroscope yaw (Z) interrupt threshold low byte */ +#define LSM9DS1_INT_GEN_DUR_G 0x37 /* Gyroscope interrupt duration */ + +/* Magnetometer registers */ + +#define LSM9DS1_OFFSET_X_REG_L_M 0x05 /* X low byte offset */ +#define LSM9DS1_OFFSET_X_REG_H_M 0x06 /* X high byte offset */ +#define LSM9DS1_OFFSET_Y_REG_L_M 0x07 /* Y low byte offset */ +#define LSM9DS1_OFFSET_Y_REG_H_M 0x08 /* Y high byte offset */ +#define LSM9DS1_OFFSET_Z_REG_L_M 0x09 /* Z low byte offset */ +#define LSM9DS1_OFFSET_Z_REG_H_M 0x0a /* Z high byte offset */ +#define LSM9DS1_WHO_AM_I_M 0x0f /* Device identification */ +#define LSM9DS1_CTRL_REG1_M 0x20 /* Control register 1 */ +#define LSM9DS1_CTRL_REG2_M 0x21 /* Control register 2 */ +#define LSM9DS1_CTRL_REG3_M 0x22 /* Control register 3 */ +#define LSM9DS1_CTRL_REG4_M 0x23 /* Control register 4 */ +#define LSM9DS1_CTRL_REG5_M 0x24 /* Control register 5 */ +#define LSM9DS1_STATUS_REG_M 0x27 /* Status register */ +#define LSM9DS1_OUT_X_L_M 0x28 /* X low byte */ +#define LSM9DS1_OUT_X_H_M 0x29 /* X high byte */ +#define LSM9DS1_OUT_Y_L_M 0x2a /* Y low byte */ +#define LSM9DS1_OUT_Y_H_M 0x2b /* Y high byte */ +#define LSM9DS1_OUT_Z_L_M 0x2c /* Z low byte */ +#define LSM9DS1_OUT_Z_H_M 0x2d /* Z high byte */ +#define LSM9DS1_INT_CFG_M 0x30 /* Interrupt configuration */ +#define LSM9DS1_INT_SRC_M 0x31 /* Interrupt source */ +#define LSM9DS1_INT_THS_L_M 0x32 /* Interrupt threshold low byte */ +#define LSM9DS1_INT_THS_H_M 0x33 /* Interrupt threshold high byte */ + +/* Register Bit Definitions *************************************************/ +/* Inactivity threshold register */ + +#define LSM9DS1_ACT_THS_ACT_THS_SHIFT 0 /* Inactivity threshold */ +#define LSM9DS1_ACT_THS_ACT_THS_MASK (127 << LSM9DS1_ACT_THS_ACT_THS_SHIFT) +#define LSM9DS1_ACT_THS_SLEEP_ON_INACT_EN (1 << 7) /* Gyroscope operating mode during inactivity */ + +/* Accelerometer interrupt configuration register */ + +#define LSM9DS1_INT_GEN_CFG_XL_XLIE_XL (1 << 0) /* X-axis low byte interrupt enable */ +#define LSM9DS1_INT_GEN_CFG_XL_XHIE_XL (1 << 1) /* X-axis high byte interrupt enable */ +#define LSM9DS1_INT_GEN_CFG_XL_YLIE_XL (1 << 2) /* Y-axis low byte interrupt enable */ +#define LSM9DS1_INT_GEN_CFG_XL_YHIE_XL (1 << 3) /* Y-axis high byte interrupt enable */ +#define LSM9DS1_INT_GEN_CFG_XL_ZLIE_XL (1 << 4) /* Z-axis low byte interrupt enable */ +#define LSM9DS1_INT_GEN_CFG_XL_ZHIE_XL (1 << 5) /* Z-axis high byte interrupt enable */ +#define LSM9DS1_INT_GEN_CFG_XL_6D (1 << 6) /* 6-direction detection function for interrupt */ +#define LSM9DS1_INT_GEN_CFG_XL_AOI_XL (1 << 7) /* AND/OR combination of interrupt events */ + +/* Accelerometer interrupt duration register */ + +#define LSM9DS1_INT_GEN_DUR_XL_DUR_XL_SHIFT 0 /* Enter/exit interrupt duration */ +#define LSM9DS1_INT_GEN_DUR_XL_DUR_XL_MASK (127 << LSM9DS1_INT_GEN_DUR_XL_DUR_XL_SHIFT) +#define LSM9DS1_INT_GEN_DUR_XL_WAIT_XL (1 << 7) /* Wait function enabled on duration counter */ + +/* INT1_A/G pin control register */ + +#define LSM9DS1_INT1_CTRL_INT1_DRDY_XL (1 << 0) /* Accelerometer data ready */ +#define LSM9DS1_INT1_CTRL_INT1_DRDY_G (1 << 1) /* Gyroscope data ready */ +#define LSM9DS1_INT1_CTRL_INT1_BOOT (1 << 2) /* Boot status available */ +#define LSM9DS1_INT1_CTRL_INT1_FTH (1 << 3) /* FIFO threshold interrupt */ +#define LSM9DS1_INT1_CTRL_INT1_OVR (1 << 4) /* Overrun interrupt */ +#define LSM9DS1_INT1_CTRL_INT1_FSS5 (1 << 5) /* FSS5 interrupt */ +#define LSM9DS1_INT1_CTRL_INT1_IG_XL (1 << 6) /* Accelerometer interrupt enable */ +#define LSM9DS1_INT1_CTRL_INT1_IG_G (1 << 7) /* Gyroscope interrupt enable */ + +/* INT2_A/G pin control register */ + +#define LSM9DS1_INT2_CTRL_INT2_DRDY_XL (1 << 0) /* Accelerometer data ready */ +#define LSM9DS1_INT2_CTRL_INT2_DRDY_G (1 << 1) /* Gyroscope data ready */ +#define LSM9DS1_INT2_CTRL_INT2_DRDY_TEMP (1 << 2) /* Temperature data ready */ +#define LSM9DS1_INT2_CTRL_INT2_FTH (1 << 3) /* FIFO threshold interrupt */ +#define LSM9DS1_INT2_CTRL_INT2_OVR (1 << 4) /* Overrun interrupt */ +#define LSM9DS1_INT2_CTRL_INT2_FSS5 (1 << 5) /* FSS5 interrupt */ +#define LSM9DS1_INT2_CTRL_INT2_INACT (1 << 7) /* Inactivity interrupt output signal */ + +/* Device identification register */ + +#define LSM9DS1_WHO_AM_I_VALUE 0x68 + +/* Gyroscope control register 1 */ + +#define LSM9DS1_CTRL_REG1_G_BW_G_SHIFT 0 /* Gyroscope bandwidth selection */ +#define LSM9DS1_CTRL_REG1_G_BW_G_MASK (3 << LSM9DS1_CTRL_REG1_G_BW_G_SHIFT) +#define LSM9DS1_CTRL_REG1_G_FS_G_SHIFT 3 /* Gyroscope full-scale selection */ +#define LSM9DS1_CTRL_REG1_G_FS_G_MASK (3 << LSM9DS1_CTRL_REG1_G_FS_G_SHIFT) +# define LSM9DS1_CTRL_REG1_G_FS_G_245DPS (0 << LSM9DS1_CTRL_REG1_G_FS_G_SHIFT) /* 245 dps */ +# define LSM9DS1_CTRL_REG1_G_FS_G_500DPS (1 << LSM9DS1_CTRL_REG1_G_FS_G_SHIFT) /* 500 dps */ +# define LSM9DS1_CTRL_REG1_G_FS_G_2000DPS (3 << LSM9DS1_CTRL_REG1_G_FS_G_SHIFT) /* 2000 dps */ +#define LSM9DS1_CTRL_REG1_G_ODR_G_SHIFT 5 /* Gyroscope bandwidth selection */ +#define LSM9DS1_CTRL_REG1_G_ODR_G_MASK (7 << LSM9DS1_CTRL_REG1_G_ODR_G_SHIFT) +# define LSM9DS1_CTRL_REG1_G_ODR_G_POWERDOWN (0 << LSM9DS1_CTRL_REG1_G_ODR_G_SHIFT) /* Power-down mode */ +# define LSM9DS1_CTRL_REG1_G_ODR_G_14p9HZ (1 << LSM9DS1_CTRL_REG1_G_ODR_G_SHIFT) /* 14.9 Hz */ +# define LSM9DS1_CTRL_REG1_G_ODR_G_59p5HZ (2 << LSM9DS1_CTRL_REG1_G_ODR_G_SHIFT) /* 59.5 Hz */ +# define LSM9DS1_CTRL_REG1_G_ODR_G_119HZ (3 << LSM9DS1_CTRL_REG1_G_ODR_G_SHIFT) /* 119 Hz */ +# define LSM9DS1_CTRL_REG1_G_ODR_G_238HZ (4 << LSM9DS1_CTRL_REG1_G_ODR_G_SHIFT) /* 238 Hz */ +# define LSM9DS1_CTRL_REG1_G_ODR_G_476HZ (5 << LSM9DS1_CTRL_REG1_G_ODR_G_SHIFT) /* 476 Hz */ +# define LSM9DS1_CTRL_REG1_G_ODR_G_952HZ (6 << LSM9DS1_CTRL_REG1_G_ODR_G_SHIFT) /* 952 Hz */ + +/* Gyroscope control register 2 */ + +#define LSM9DS1_CTRL_REG2_G_OUT_SEL_SHIFT 0 /* Out selection configuration */ +#define LSM9DS1_CTRL_REG2_G_OUT_SEL_MASK (3 << LSM9DS1_CTRL_REG2_G_OUT_SEL_SHIFT) +#define LSM9DS1_CTRL_REG2_G_INT_SEL_SHIFT 2 /* INT selection configuration */ +#define LSM9DS1_CTRL_REG2_G_INT_SEL_MASK (3 << LSM9DS1_CTRL_REG2_G_INT_SEL_SHIFT) + +/* Gyroscope control register 3 */ + +#define LSM9DS1_CTRL_REG3_G_HPCF_G_SHIFT 0 /* Gyroscope high-pass filter cutoff frequency selection */ +#define LSM9DS1_CTRL_REG3_G_HPCF_G_MASK (15 << LSM9DS1_CTRL_REG3_G_HPCF_G_SHIFT) +#define LSM9DS1_CTRL_REG3_G_HP_EN (1 << 6) /* High-pass filter enable */ +#define LSM9DS1_CTRL_REG3_G_LP_MODE (1 << 7) /* Low-power mode enable */ + +/* Gyroscope sign and orientation register */ + +#define LSM9DS1_ORIENT_CFG_G_ORIENT_SHIFT 0 /* Directional user orientation selection */ +#define LSM9DS1_ORIENT_CFG_G_ORIENT_MASK (3 << LSM9DS1_ORIENT_CFG_G_ORIENT_SHIFT) +#define LSM9DS1_ORIENT_CFG_G_SIGNZ_G (1 << 3) /* Yaw axis (Z) angular rate sign */ +#define LSM9DS1_ORIENT_CFG_G_SIGNY_G (1 << 4) /* Roll axis (Y) angular rate sign */ +#define LSM9DS1_ORIENT_CFG_G_SIGNX_G (1 << 5) /* Pitch axis (X) angular rate sign */ + +/* Gyroscope interrupt source register */ + +#define LSM9DS1_INT_GEN_SRC_G_XL_G (1 << 0) /* Pitch (X) low */ +#define LSM9DS1_INT_GEN_SRC_G_XH_G (1 << 1) /* Pitch (X) high */ +#define LSM9DS1_INT_GEN_SRC_G_YL_G (1 << 2) /* Roll (Y) low */ +#define LSM9DS1_INT_GEN_SRC_G_YH_G (1 << 3) /* Roll (Y) high */ +#define LSM9DS1_INT_GEN_SRC_G_ZL_G (1 << 4) /* Yaw (Z) low */ +#define LSM9DS1_INT_GEN_SRC_G_ZH_G (1 << 5) /* Yaw (Z) high */ +#define LSM9DS1_INT_GEN_SRC_G_IA_G (1 << 6) /* Interrupt active */ + +/* Status register */ + +#define LSM9DS1_STATUS_REG_XLDA (1 << 0) /* Accelerometer new data available */ +#define LSM9DS1_STATUS_REG_GDA (1 << 1) /* Gyroscope new data available */ +#define LSM9DS1_STATUS_REG_TDA (1 << 2) /* Temperature sensor new data available */ +#define LSM9DS1_STATUS_REG_BOOT_STATUS (1 << 3) /* Boot running flag signal */ +#define LSM9DS1_STATUS_REG_INACT (1 << 4) /* Inactivity interrupt output signal */ +#define LSM9DS1_STATUS_REG_IG_G (1 << 5) /* Gyroscope interrupt output signal */ +#define LSM9DS1_STATUS_REG_IG_XL (1 << 6) /* Accelerometer interrupt output signal */ + +/* Control register 4 */ + +#define LSM9DS1_CTRL_REG4_4D_XL1 (1 << 0) /* 4D option enabled on interrupt */ +#define LSM9DS1_CTRL_REG4_LIR_XL1 (1 << 1) /* Latched interrupt */ +#define LSM9DS1_CTRL_REG4_XEN_G (1 << 3) /* Gyroscope's pitch axis (X) output enable */ +#define LSM9DS1_CTRL_REG4_YEN_G (1 << 4) /* Gyroscope's roll axis (Y) output enable */ +#define LSM9DS1_CTRL_REG4_ZEN_G (1 << 5) /* Gyroscope's yaw axis (Z) output enable */ + +/* Accelerometer control register 5 */ + +#define LSM9DS1_CTRL_REG5_XL_XEN_XL (1 << 3) /* Accelerometer's X-axis output enable */ +#define LSM9DS1_CTRL_REG5_XL_YEN_XL (1 << 4) /* Accelerometer's Y-axis output enable */ +#define LSM9DS1_CTRL_REG5_XL_ZEN_XL (1 << 5) /* Accelerometer's Z-axis output enable */ +#define LSM9DS1_CTRL_REG5_XL_DEC_SHIFT 6 /* Decimation of acceleration data on OUT REG and FIFO */ +#define LSM9DS1_CTRL_REG5_XL_DEC_MASK (3 << LSM9DS1_CTRL_REG5_XL_DEC_SHIFT) +# define LSM9DS1_CTRL_REG5_XL_DEC_NODEC (0 << LSM9DS1_CTRL_REG5_XL_DEC_SHIFT) /* No decimation */ +# define LSM9DS1_CTRL_REG5_XL_DEC_2SAMPLES (1 << LSM9DS1_CTRL_REG5_XL_DEC_SHIFT) /* Update every 2 samples */ +# define LSM9DS1_CTRL_REG5_XL_DEC_4SAMPLES (2 << LSM9DS1_CTRL_REG5_XL_DEC_SHIFT) /* Update every 4 samples */ +# define LSM9DS1_CTRL_REG5_XL_DEC_8SAMPLES (3 << LSM9DS1_CTRL_REG5_XL_DEC_SHIFT) /* Update every 8 samples */ + +/* Accelerometer control register 6 */ + +#define LSM9DS1_CTRL_REG6_XL_BW_XL_SHIFT 0 /* Anti-aliasing filter bandwidth selection */ +#define LSM9DS1_CTRL_REG6_XL_BW_XL_MASK (3 << LSM9DS1_CTRL_REG6_XL_BW_XL_SHIFT) +# define LSM9DS1_CTRL_REG6_XL_BW_XL_408HZ (0 << LSM9DS1_CTRL_REG6_XL_BW_XL_SHIFT) /* 408 Hz */ +# define LSM9DS1_CTRL_REG6_XL_BW_XL_211HZ (1 << LSM9DS1_CTRL_REG6_XL_BW_XL_SHIFT) /* 211 Hz */ +# define LSM9DS1_CTRL_REG6_XL_BW_XL_105HZ (2 << LSM9DS1_CTRL_REG6_XL_BW_XL_SHIFT) /* 105 Hz */ +# define LSM9DS1_CTRL_REG6_XL_BW_XL_50HZ (3 << LSM9DS1_CTRL_REG6_XL_BW_XL_SHIFT) /* 50 Hz */ +#define LSM9DS1_CTRL_REG6_XL_BW_SCAL_ODR (1 << 2) /* Bandwidth selection */ +#define LSM9DS1_CTRL_REG6_XL_FS_XL_SHIFT 3 /* Accelerometer full-scale selection */ +#define LSM9DS1_CTRL_REG6_XL_FS_XL_MASK (3 << LSM9DS1_CTRL_REG6_XL_FS_XL_SHIFT) +# define LSM9DS1_CTRL_REG6_XL_FS_XL_2G (0 << LSM9DS1_CTRL_REG6_XL_FS_XL_SHIFT) /* +/- 2 g */ +# define LSM9DS1_CTRL_REG6_XL_FS_XL_16G (1 << LSM9DS1_CTRL_REG6_XL_FS_XL_SHIFT) /* +/- 16 g */ +# define LSM9DS1_CTRL_REG6_XL_FS_XL_4G (2 << LSM9DS1_CTRL_REG6_XL_FS_XL_SHIFT) /* +/- 4 g */ +# define LSM9DS1_CTRL_REG6_XL_FS_XL_8G (3 << LSM9DS1_CTRL_REG6_XL_FS_XL_SHIFT) /* +/- 8 g */ +#define LSM9DS1_CTRL_REG6_XL_ODR_XL_SHIFT 5 /* Output data rate and power mode selection */ +#define LSM9DS1_CTRL_REG6_XL_ODR_XL_MASK (7 << LSM9DS1_CTRL_REG6_XL_ODR_XL_SHIFT) +# define LSM9DS1_CTRL_REG6_XL_ODR_XL_POWERDOWN (0 << LSM9DS1_CTRL_REG6_XL_ODR_XL_SHIFT) /* Power-down mode */ +# define LSM9DS1_CTRL_REG6_XL_ODR_XL_10HZ (1 << LSM9DS1_CTRL_REG6_XL_ODR_XL_SHIFT) /* 10 Hz */ +# define LSM9DS1_CTRL_REG6_XL_ODR_XL_50HZ (2 << LSM9DS1_CTRL_REG6_XL_ODR_XL_SHIFT) /* 50 Hz */ +# define LSM9DS1_CTRL_REG6_XL_ODR_XL_119HZ (3 << LSM9DS1_CTRL_REG6_XL_ODR_XL_SHIFT) /* 119 Hz */ +# define LSM9DS1_CTRL_REG6_XL_ODR_XL_238HZ (4 << LSM9DS1_CTRL_REG6_XL_ODR_XL_SHIFT) /* 238 Hz */ +# define LSM9DS1_CTRL_REG6_XL_ODR_XL_476HZ (5 << LSM9DS1_CTRL_REG6_XL_ODR_XL_SHIFT) /* 476 Hz */ +# define LSM9DS1_CTRL_REG6_XL_ODR_XL_952HZ (6 << LSM9DS1_CTRL_REG6_XL_ODR_XL_SHIFT) /* 952 Hz */ + +/* Accelerometer control register 7 */ + +#define LSM9DS1_CTRL_REG7_XL_HPIS1 (1 << 0) /* High-pass filter enabled */ +#define LSM9DS1_CTRL_REG7_XL_FDS (1 << 2) /* Filtered data selection */ +#define LSM9DS1_CTRL_REG7_XL_DCF_SHIFT 5 /* Accelerometer digital filter cutoff frequency selection */ +#define LSM9DS1_CTRL_REG7_XL_DCF_MASK (3 << LSM9DS1_CTRL_REG7_XL_DCF_SHIFT) +# define LSM9DS1_CTRL_REG7_XL_DCF_ODR_DIV50 (0 << LSM9DS1_CTRL_REG7_XL_DCF_SHIFT) +# define LSM9DS1_CTRL_REG7_XL_DCF_ODR_DIV100 (1 << LSM9DS1_CTRL_REG7_XL_DCF_SHIFT) +# define LSM9DS1_CTRL_REG7_XL_DCF_ODR_DIV9 (2 << LSM9DS1_CTRL_REG7_XL_DCF_SHIFT) +# define LSM9DS1_CTRL_REG7_XL_DCF_ODR_DIV400 (3 << LSM9DS1_CTRL_REG7_XL_DCF_SHIFT) +#define LSM9DS1_CTRL_REG7_XL_HR (1 << 7) /* High resolution mode enable */ + +/* Control register 8 */ + +#define LSM9DS1_CTRL_REG8_SW_RESET (1 << 0) /* Software reset */ +#define LSM9DS1_CTRL_REG8_BLE (1 << 1) /* Big/little endian data selection */ +#define LSM9DS1_CTRL_REG8_IF_ADD_INC (1 << 2) /* Register address automatically incremented during a multibyte access */ +#define LSM9DS1_CTRL_REG8_SIM (1 << 3) /* SPI serial interface mode selection */ +#define LSM9DS1_CTRL_REG8_PP_OD (1 << 4) /* Push-pull/open-drain selection on the INT1_A/G and INT2_A/G pins */ +#define LSM9DS1_CTRL_REG8_H_LACTIVE (1 << 5) /* Interrupt activation level */ +#define LSM9DS1_CTRL_REG8_BDU (1 << 6) /* Block data update */ +#define LSM9DS1_CTRL_REG8_BOOT (1 << 7) /* Reboot memory content */ + +/* Control register 9 */ + +#define LSM9DS1_CTRL_REG9_STOP_ON_FTH (1 << 0) /* Enable FIFO threshold level use */ +#define LSM9DS1_CTRL_REG9_FIFO_EN (1 << 1) /* FIFO memory enable */ +#define LSM9DS1_CTRL_REG9_I2C_DISABLE (1 << 2) /* Disable I2C interface */ +#define LSM9DS1_CTRL_REG9_DRDY_MASK_BIT (1 << 3) /* Data available enable bit */ +#define LSM9DS1_CTRL_REG9_FIFO_TEMP_EN (1 << 4) /* Temperature data storage in FIFO enable */ +#define LSM9DS1_CTRL_REG9_SLEEP_G (1 << 6) /* Gyroscope sleep mode enable */ + +/* Control register 10 */ + +#define LSM9DS1_CTRL_REG10_ST_XL (1 << 0) /* Linear acceleration sensor self-test enable */ +#define LSM9DS1_CTRL_REG10_ST_G (1 << 2) /* Angular rate sensor self-test enable */ + +/* Accelerometer interrupt source register */ + +#define LSM9DS1_INT_GEN_SRC_XL_XL_XL (1 << 0) /* Accelerometer's X low event */ +#define LSM9DS1_INT_GEN_SRC_XL_XH_XL (1 << 1) /* Accelerometer's X high event */ +#define LSM9DS1_INT_GEN_SRC_XL_YL_XL (1 << 2) /* Accelerometer's Y low event */ +#define LSM9DS1_INT_GEN_SRC_XL_YH_XL (1 << 3) /* Accelerometer's Y high event */ +#define LSM9DS1_INT_GEN_SRC_XL_ZL_XL (1 << 4) /* Accelerometer's Z low event */ +#define LSM9DS1_INT_GEN_SRC_XL_ZH_XL (1 << 5) /* Accelerometer's Z high event */ +#define LSM9DS1_INT_GEN_SRC_XL_IA_XL (1 << 6) /* Interrupt active */ + +/* Status register 2 */ + +#define LSM9DS1_STATUS_REG2_XLDA (1 << 0) /* Accelerometer new data available */ +#define LSM9DS1_STATUS_REG2_GDA (1 << 1) /* Gyroscope new data available */ +#define LSM9DS1_STATUS_REG2_TDA (1 << 2) /* Temperature sensor new data available */ +#define LSM9DS1_STATUS_REG2_BOOT_STATUS (1 << 3) /* Boot running flag signal */ +#define LSM9DS1_STATUS_REG2_INACT (1 << 4) /* Inactivity interrupt output signal */ +#define LSM9DS1_STATUS_REG2_IG_G (1 << 5) /* Gyroscope interrupt output signal */ +#define LSM9DS1_STATUS_REG2_IG_XL (1 << 6) /* Accelerometer interrupt output signal */ + +/* FIFO control register */ + +#define LSM9DS1_FIFO_CTRL_FTH_SHIFT 0 /* FIFO threshold level setting */ +#define LSM9DS1_FIFO_CTRL_FTH_MASK (31 << LSM9DS1_FIFO_CTRL_FTH_SHIFT) +#define LSM9DS1_FIFO_CTRL_FMODE_SHIFT 5 /* FIFO mode selection bits */ +#define LSM9DS1_FIFO_CTRL_FMODE_MASK (7 << LSM9DS1_FIFO_CTRL_FMODE_SHIFT) +# define LSM9DS1_FIFO_CTRL_FMODE_BYPASS (0 << LSM9DS1_FIFO_CTRL_FMODE_SHIFT) /* Bypass mode */ +# define LSM9DS1_FIFO_CTRL_FMODE_FIFO (1 << LSM9DS1_FIFO_CTRL_FMODE_SHIFT) /* FIFO mode */ +# define LSM9DS1_FIFO_CTRL_FMODE_CONT_FIFO (3 << LSM9DS1_FIFO_CTRL_FMODE_SHIFT) /* Continuous-to-FIFO mode */ +# define LSM9DS1_FIFO_CTRL_FMODE_BYPASS_CONT (4 << LSM9DS1_FIFO_CTRL_FMODE_SHIFT) /* Bypass-to-continuous mode */ +# define LSM9DS1_FIFO_CTRL_FMODE_CONT (5 << LSM9DS1_FIFO_CTRL_FMODE_SHIFT) /* Continuous mode */ + +/* FIFO status control register */ + +#define LSM9DS1_FIFO_SRC_FSS_SHIFT 0 /* Number of unread samples stored into FIFO */ +#define LSM9DS1_FIFO_SRC_FSS_MASK (63 << LSM9DS1_FIFO_SRC_FSS_SHIFT) +#define LSM9DS1_FIFO_SRC_OVRN (1 << 6) /* FIFO overrun status */ +#define LSM9DS1_FIFO_SRC_FTH (1 << 7) /* FIFO threshold status */ + +/* Gyroscope interrupt configuration register */ + +#define LSM9DS1_INT_GEN_CFG_G_XLIE_G (1 << 0) /* Pitch (X) axis low event interrupt enable */ +#define LSM9DS1_INT_GEN_CFG_G_XHIE_G (1 << 1) /* Pitch (X) axis high event interrupt enable */ +#define LSM9DS1_INT_GEN_CFG_G_YLIE_G (1 << 2) /* Roll (Y) axis low event interrupt enable */ +#define LSM9DS1_INT_GEN_CFG_G_YHIE_G (1 << 3) /* Roll (Y) axis high event interrupt enable */ +#define LSM9DS1_INT_GEN_CFG_G_ZLIE_G (1 << 4) /* Yaw (Z) axis low event interrupt enable */ +#define LSM9DS1_INT_GEN_CFG_G_ZHIE_G (1 << 5) /* Yaw (Z) axis high event interrupt enable */ +#define LSM9DS1_INT_GEN_CFG_G_LIR_G (1 << 6) /* Latch interrupt request */ +#define LSM9DS1_INT_GEN_CFG_G_AOI_G (1 << 7) /* AND/OR combination of interrupt events */ + +/* Gyroscope interrupt threshold registers */ + +#define LSM9DS1_INT_GEN_THS_XH_G_THS_XH_G_SHIFT 0 /* X interrupt threshold high byte */ +#define LSM9DS1_INT_GEN_THS_XH_G_THS_XH_G_MASK (127 << LSM9DS1_INT_GEN_THS_XH_G_THS_XH_G_SHIFT) +#define LSM9DS1_INT_GEN_THS_XH_G_DCRM_G (1 << 7) /* Decrement or reset counter mode selection */ + +/* Gyroscope interrupt duration register */ + +#define LSM9DS1_INT_GEN_DUR_G_DUR_G_SHIFT 0 /* Enter/exit interrupt duration */ +#define LSM9DS1_INT_GEN_DUR_G_DUR_G_MASK (127 << LSM9DS1_INT_GEN_DUR_G_DUR_G_SHIFT) +#define LSM9DS1_INT_GEN_DUR_G_WAIT_G (1 << 7) /* Exit from interrupt wait function enable */ + +/* Device identification register */ + +#define LSM9DS1_WHO_AM_I_M_VALUE 0x3d + +/* Magnetometer control register 1 */ + +#define LSM9DS1_CTRL_REG1_M_ST (1 << 0) /* Self-test enable */ +#define LSM9DS1_CTRL_REG1_M_FAST_ODR (1 << 1) /* Enable data rates higher than 80 Hz */ +#define LSM9DS1_CTRL_REG1_M_DO_SHIFT 2 /* Output data rate selection */ +#define LSM9DS1_CTRL_REG1_M_DO_MASK (7 << LSM9DS1_CTRL_REG1_M_DO_SHIFT) +# define LSM9DS1_CTRL_REG1_M_DO_0p625HZ (0 << LSM9DS1_CTRL_REG1_M_DO_SHIFT) /* 0.625 Hz */ +# define LSM9DS1_CTRL_REG1_M_DO_1p25HZ (1 << LSM9DS1_CTRL_REG1_M_DO_SHIFT) /* 1.25 Hz */ +# define LSM9DS1_CTRL_REG1_M_DO_2p5HZ (2 << LSM9DS1_CTRL_REG1_M_DO_SHIFT) /* 2.5 Hz */ +# define LSM9DS1_CTRL_REG1_M_DO_5HZ (3 << LSM9DS1_CTRL_REG1_M_DO_SHIFT) /* 5 Hz */ +# define LSM9DS1_CTRL_REG1_M_DO_10HZ (4 << LSM9DS1_CTRL_REG1_M_DO_SHIFT) /* 10 Hz */ +# define LSM9DS1_CTRL_REG1_M_DO_20HZ (5 << LSM9DS1_CTRL_REG1_M_DO_SHIFT) /* 20 Hz */ +# define LSM9DS1_CTRL_REG1_M_DO_40HZ (6 << LSM9DS1_CTRL_REG1_M_DO_SHIFT) /* 40 Hz */ +# define LSM9DS1_CTRL_REG1_M_DO_80HZ (7 << LSM9DS1_CTRL_REG1_M_DO_SHIFT) /* 80 Hz */ +#define LSM9DS1_CTRL_REG1_M_OM_SHIFT 5 /* X and Y axes operative mode selection */ +#define LSM9DS1_CTRL_REG1_M_OM_MASK (3 << LSM9DS1_CTRL_REG1_M_OM_SHIFT) +# define LSM9DS1_CTRL_REG1_M_OM_LOW (0 << LSM9DS1_CTRL_REG1_M_OM_SHIFT) /* Low-power mode */ +# define LSM9DS1_CTRL_REG1_M_OM_MEDIUM (1 << LSM9DS1_CTRL_REG1_M_OM_SHIFT) /* Medium-performance mode */ +# define LSM9DS1_CTRL_REG1_M_OM_HIGH (2 << LSM9DS1_CTRL_REG1_M_OM_SHIFT) /* High-performance mode */ +# define LSM9DS1_CTRL_REG1_M_OM_ULTRAHIGH (3 << LSM9DS1_CTRL_REG1_M_OM_SHIFT) /* Ultra-high performance mode */ +#define LSM9DS1_CTRL_REG1_M_TEMP_COMP (1 << 7) /* Temperature compensation enable */ + +/* Magnetometer control register 2 */ + +#define LSM9DS1_CTRL_REG2_M_SOFT_RST (1 << 2) /* Configuration register and user register reset */ +#define LSM9DS1_CTRL_REG2_M_REBOOT (1 << 3) /* Reboot memory content */ +#define LSM9DS1_CTRL_REG2_M_FS_SHIFT 5 /* Full-scale configuration */ +#define LSM9DS1_CTRL_REG2_M_FS_MASK (3 << LSM9DS1_CTRL_REG2_M_FS_SHIFT) +# define LSM9DS1_CTRL_REG2_M_FS_4GAUSS (0 << LSM9DS1_CTRL_REG2_M_FS_SHIFT) /* +/- 4 gauss */ +# define LSM9DS1_CTRL_REG2_M_FS_8GAUSS (1 << LSM9DS1_CTRL_REG2_M_FS_SHIFT) /* +/- 8 gauss */ +# define LSM9DS1_CTRL_REG2_M_FS_12GAUSS (2 << LSM9DS1_CTRL_REG2_M_FS_SHIFT) /* +/- 12 gauss */ +# define LSM9DS1_CTRL_REG2_M_FS_16GAUSS (3 << LSM9DS1_CTRL_REG2_M_FS_SHIFT) /* +/- 16 gauss */ + +/* Magnetometer control register 3 */ + +#define LSM9DS1_CTRL_REG3_M_MD_SHIFT 0 /* Operating mode selection */ +#define LSM9DS1_CTRL_REG3_M_MD_MASK (3 << LSM9DS1_CTRL_REG3_M_MD_SHIFT) +# define LSM9DS1_CTRL_REG3_M_MD_CONT (0 << LSM9DS1_CTRL_REG3_M_MD_SHIFT) /* Continuous-conversion mode */ +# define LSM9DS1_CTRL_REG3_M_MD_SINGLE (1 << LSM9DS1_CTRL_REG3_M_MD_SHIFT) /* Single-conversion mode */ +# define LSM9DS1_CTRL_REG3_M_MD_POWERDOWN (2 << LSM9DS1_CTRL_REG3_M_MD_SHIFT) /* Power-down mode */ +# define LSM9DS1_CTRL_REG3_M_MD_POWERDOWN2 (3 << LSM9DS1_CTRL_REG3_M_MD_SHIFT) /* Power-down mode */ +#define LSM9DS1_CTRL_REG3_M_SIM (1 << 2) /* SPI serial interface mode selection */ +#define LSM9DS1_CTRL_REG3_M_LP (1 << 5) /* Low-power mode configuration */ +#define LSM9DS1_CTRL_REG3_M_I2C_DISABLE (1 << 7) /* Disable I2C interface */ + +/* Magnetometer control register 4 */ + +#define LSM9DS1_CTRL_REG4_M_BLE (1 << 1) /* Big/little endian data selection */ +#define LSM9DS1_CTRL_REG4_M_OMZ_SHIFT 2 /* Z-axis operative mode selection */ +#define LSM9DS1_CTRL_REG4_M_OMZ_MASK (3 << LSM9DS1_CTRL_REG4_M_OMZ_SHIFT) +# define LSM9DS1_CTRL_REG4_M_OMZ_LOW (0 << LSM9DS1_CTRL_REG4_M_OMZ_SHIFT) /* Low-power mode */ +# define LSM9DS1_CTRL_REG4_M_OMZ_MEDIUM (1 << LSM9DS1_CTRL_REG4_M_OMZ_SHIFT) /* Medium-performance mode */ +# define LSM9DS1_CTRL_REG4_M_OMZ_HIGH (2 << LSM9DS1_CTRL_REG4_M_OMZ_SHIFT) /* High-performance mode */ +# define LSM9DS1_CTRL_REG4_M_OMZ_ULTRAHIGH (3 << LSM9DS1_CTRL_REG4_M_OMZ_SHIFT) /* Ultra-high performance mode */ + +/* Magnetometer control register 5 */ + +#define LSM9DS1_CTRL_REG5_M_BDU (1 << 6) /* Block data update */ +#define LSM9DS1_CTRL_REG5_M_FAST_READ (1 << 7) /* Fast read enable */ + +/* Magnetometer status register */ + +#define LSM9DS1_STATUS_REG_M_XDA (1 << 0) /* X-axis new data available */ +#define LSM9DS1_STATUS_REG_M_YDA (1 << 1) /* Y-axis new data available */ +#define LSM9DS1_STATUS_REG_M_ZDA (1 << 2) /* Z-axis new data available */ +#define LSM9DS1_STATUS_REG_M_ZYXDA (1 << 3) /* X, Y and Z-axis new data available */ +#define LSM9DS1_STATUS_REG_M_XOR (1 << 4) /* X-axis data overrun */ +#define LSM9DS1_STATUS_REG_M_YOR (1 << 5) /* Y-axis data overrun */ +#define LSM9DS1_STATUS_REG_M_ZOR (1 << 6) /* Z-axis data overrun */ +#define LSM9DS1_STATUS_REG_M_ZYXOR (1 << 7) /* X, Y and Z-axis data overrun */ + +/* Magnetometer interrupt configuration register */ + +#define LSM9DS1_INT_CFG_M_IEN (1 << 0) /* Interrupt enable on the INT_M pin */ +#define LSM9DS1_INT_CFG_M_IEL (1 << 1) /* Latch interrupt request */ +#define LSM9DS1_INT_CFG_M_IEA (1 << 2) /* Interrupt active configuration on INT_MAG */ +#define LSM9DS1_INT_CFG_M_ZIEN (1 << 5) /* Z-axis interrupt enable */ +#define LSM9DS1_INT_CFG_M_YIEN (1 << 6) /* Y-axis interrupt enable */ +#define LSM9DS1_INT_CFG_M_XIEN (1 << 7) /* X-axis interrupt enable */ + +/* Magnetometer interrupt source register */ + +#define LSM9DS1_INT_SRC_M_INT (1 << 0) /* Interrupt occurred */ +#define LSM9DS1_INT_SRC_M_MROI (1 << 1) /* Internal measurement range overflow */ +#define LSM9DS1_INT_SRC_M_NTH_Z (1 << 2) /* Value on Z-axis exceeds threshold on negative side */ +#define LSM9DS1_INT_SRC_M_NTH_Y (1 << 3) /* Value on Y-axis exceeds threshold on negative side */ +#define LSM9DS1_INT_SRC_M_NTH_X (1 << 4) /* Value on X-axis exceeds threshold on negative side */ +#define LSM9DS1_INT_SRC_M_PTH_Z (1 << 5) /* Value on Z-axis exceeds threshold on positive side */ +#define LSM9DS1_INT_SRC_M_PTH_Y (1 << 6) /* Value on Y-axis exceeds threshold on positive side */ +#define LSM9DS1_INT_SRC_M_PTH_X (1 << 7) /* Value on X-axis exceeds threshold on positive side */ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct lsm9ds1_dev_s; +struct lsm9ds1_ops_s +{ + CODE int (*config)(FAR struct lsm9ds1_dev_s *priv); + CODE int (*start)(FAR struct lsm9ds1_dev_s *priv); + CODE int (*stop)(FAR struct lsm9ds1_dev_s *priv); + CODE int (*setsamplerate)(FAR struct lsm9ds1_dev_s *priv, + uint32_t samplerate); + CODE int (*setfullscale)(FAR struct lsm9ds1_dev_s *priv, + uint32_t fullscale); +}; + +struct lsm9ds1_dev_s +{ + FAR struct i2c_dev_s *i2c; /* I2C interface */ + uint8_t addr; /* I2C address */ + + FAR const struct lsm9ds1_ops_s *ops; + + uint32_t samplerate; /* Output data rate */ + uint8_t datareg; /* Output data register of X low byte */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ +/* I2C Helpers */ + +static int lsm9ds1_readreg8(FAR struct lsm9ds1_dev_s *priv, uint8_t regaddr, + FAR uint8_t *regval); +static int lsm9ds1_writereg8(FAR struct lsm9ds1_dev_s *priv, uint8_t regaddr, + uint8_t regval); +static int lsm9ds1_modifyreg8(FAR struct lsm9ds1_dev_s *priv, + uint8_t regaddr, uint8_t clearbits, + uint8_t setbits); + +/* Other Helpers */ + +static uint32_t lsm9ds1_midpoint(uint32_t a, uint32_t b); + +/* Accelerometer Operations */ + +static int lsm9ds1accelgyro_config(FAR struct lsm9ds1_dev_s *priv); +static int lsm9ds1accel_start(FAR struct lsm9ds1_dev_s *priv); +static int lsm9ds1accel_stop(FAR struct lsm9ds1_dev_s *priv); +static int lsm9ds1accelgyro_setsamplerate(FAR struct lsm9ds1_dev_s *priv, + uint32_t samplerate); +static int lsm9ds1accel_setfullscale(FAR struct lsm9ds1_dev_s *priv, + uint32_t fullscale); + +/* Gyroscope Operations */ + +static int lsm9ds1gyro_start(FAR struct lsm9ds1_dev_s *priv); +static int lsm9ds1gyro_stop(FAR struct lsm9ds1_dev_s *priv); +static int lsm9ds1gyro_setfullscale(FAR struct lsm9ds1_dev_s *priv, + uint32_t fullscale); + +/* Magnetometer Operations */ + +static int lsm9ds1mag_config(FAR struct lsm9ds1_dev_s *priv); +static int lsm9ds1mag_start(FAR struct lsm9ds1_dev_s *priv); +static int lsm9ds1mag_stop(FAR struct lsm9ds1_dev_s *priv); +static int lsm9ds1mag_setfullscale(FAR struct lsm9ds1_dev_s *priv, + uint32_t fullscale); +static int lsm9ds1mag_setsamplerate(FAR struct lsm9ds1_dev_s *priv, + uint32_t samplerate); + +/* Character Driver Methods */ + +static int lsm9ds1_open(FAR struct file *filep); +static int lsm9ds1_close(FAR struct file *filep); +static ssize_t lsm9ds1_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static ssize_t lsm9ds1_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen); +static int lsm9ds1_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); + +/* Common Register Function */ + +static int lsm9ds1_register(FAR const char *devpath, + FAR struct i2c_dev_s *i2c, uint8_t addr, + FAR const struct lsm9ds1_ops_s *ops, + uint8_t datareg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_fops = +{ + lsm9ds1_open, + lsm9ds1_close, + lsm9ds1_read, + lsm9ds1_write, + NULL, + lsm9ds1_ioctl, +#ifndef CONFIG_DISABLE_POLL + NULL, +#endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + NULL, +#endif +}; + +static const struct lsm9ds1_ops_s g_lsm9ds1accel_ops = +{ + lsm9ds1accelgyro_config, + lsm9ds1accel_start, + lsm9ds1accel_stop, + lsm9ds1accelgyro_setsamplerate, + lsm9ds1accel_setfullscale, +}; + +static const struct lsm9ds1_ops_s g_lsm9ds1gyro_ops = +{ + lsm9ds1accelgyro_config, + lsm9ds1gyro_start, + lsm9ds1gyro_stop, + lsm9ds1accelgyro_setsamplerate, + lsm9ds1gyro_setfullscale, +}; + +static const struct lsm9ds1_ops_s g_lsm9ds1mag_ops = +{ + lsm9ds1mag_config, + lsm9ds1mag_start, + lsm9ds1mag_stop, + lsm9ds1mag_setsamplerate, + lsm9ds1mag_setfullscale, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lsm9ds1_readreg8 + * + * Description: + * Read from an 8-bit register. + * + ****************************************************************************/ + +static int lsm9ds1_readreg8(FAR struct lsm9ds1_dev_s *priv, uint8_t regaddr, + FAR uint8_t *regval) +{ + int ret; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(regval != NULL); + + /* Write the register address */ + + I2C_SETADDRESS(priv->i2c, priv->addr, 7); + ret = I2C_WRITE(priv->i2c, ®addr, sizeof(regaddr)); + if (ret < 0) + { + sndbg("I2C_WRITE failed: %d\n", ret); + return ret; + } + + /* Restart and read 8 bits from the register */ + + ret = I2C_READ(priv->i2c, regval, sizeof(*regval)); + if (ret < 0) + { + sndbg("I2C_READ failed: %d\n", ret); + return ret; + } + + snvdbg("addr: %02x value: %02x\n", regaddr, *regval); + return OK; +} + +/**************************************************************************** + * Name: lsm9ds1_writereg8 + * + * Description: + * Write to an 8-bit register. + * + ****************************************************************************/ + +static int lsm9ds1_writereg8(FAR struct lsm9ds1_dev_s *priv, uint8_t regaddr, + uint8_t regval) +{ + int ret; + uint8_t buffer[2]; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + /* Set up a 2-byte message to send */ + + buffer[0] = regaddr; + buffer[1] = regval; + + /* Write the register address followed by the data (no RESTART) */ + + I2C_SETADDRESS(priv->i2c, priv->addr, 7); + ret = I2C_WRITE(priv->i2c, buffer, sizeof(buffer)); + if (ret < 0) + { + sndbg("I2C_WRITE failed: %d\n", ret); + return ret; + } + + snvdbg("addr: %02x value: %02x\n", regaddr, regval); + return OK; +} + +/**************************************************************************** + * Name: lsm9ds1_modifyreg8 + * + * Description: + * Modify an 8-bit register. + * + ****************************************************************************/ + +static int lsm9ds1_modifyreg8(FAR struct lsm9ds1_dev_s *priv, uint8_t regaddr, + uint8_t clearbits, uint8_t setbits) +{ + int ret; + uint8_t regval; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + ret = lsm9ds1_readreg8(priv, regaddr, ®val); + if (ret < 0) + { + sndbg("lsm9ds1_readreg8 failed: %d\n", ret); + return ret; + } + + regval &= ~clearbits; + regval |= setbits; + + ret = lsm9ds1_writereg8(priv, regaddr, regval); + if (ret < 0) + { + sndbg("lsm9ds1_writereg8 failed: %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: lsm9ds1_midpoint + * + * Description: + * Find the midpoint between two numbers. + * + ****************************************************************************/ + +static uint32_t lsm9ds1_midpoint(uint32_t a, uint32_t b) +{ + return (uint32_t)(((uint64_t)a + (uint64_t)b + (uint64_t)1) / (uint64_t)2); +} + +/**************************************************************************** + * Name: lsm9ds1accelgyro_config + * + * Description: + * Configure the accelerometer and gyroscope. + * + ****************************************************************************/ + +static int lsm9ds1accelgyro_config(FAR struct lsm9ds1_dev_s *priv) +{ + int ret; + uint8_t regval; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + /* Get the device identification */ + + ret = lsm9ds1_readreg8(priv, LSM9DS1_WHO_AM_I, ®val); + if (ret < 0) + { + sndbg("lsm9ds1_readreg8 failed: %d\n", ret); + return ret; + } + + if (regval != LSM9DS1_WHO_AM_I_VALUE) + { + sndbg("Invalid device identification %02x\n", regval); + return -ENODEV; + } + + return OK; +} + +/**************************************************************************** + * Name: lsm9ds1accel_start + * + * Description: + * Start the accelerometer. + * + ****************************************************************************/ + +static int lsm9ds1accel_start(FAR struct lsm9ds1_dev_s *priv) +{ + uint8_t setbits; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + if (priv->samplerate < lsm9ds1_midpoint(10, 50)) + { + setbits = LSM9DS1_CTRL_REG6_XL_ODR_XL_10HZ; + } + else if (priv->samplerate < lsm9ds1_midpoint(50, 119)) + { + setbits = LSM9DS1_CTRL_REG6_XL_ODR_XL_50HZ; + } + else if (priv->samplerate < lsm9ds1_midpoint(119, 238)) + { + setbits = LSM9DS1_CTRL_REG6_XL_ODR_XL_119HZ; + } + else if (priv->samplerate < lsm9ds1_midpoint(238, 476)) + { + setbits = LSM9DS1_CTRL_REG6_XL_ODR_XL_238HZ; + } + else if (priv->samplerate < lsm9ds1_midpoint(476, 952)) + { + setbits = LSM9DS1_CTRL_REG6_XL_ODR_XL_476HZ; + } + else + { + setbits = LSM9DS1_CTRL_REG6_XL_ODR_XL_952HZ; + } + + return lsm9ds1_modifyreg8(priv, LSM9DS1_CTRL_REG6_XL, + LSM9DS1_CTRL_REG6_XL_ODR_XL_MASK, setbits); +} + +/**************************************************************************** + * Name: lsm9ds1accel_stop + * + * Description: + * Stop the accelerometer. + * + ****************************************************************************/ + +static int lsm9ds1accel_stop(FAR struct lsm9ds1_dev_s *priv) +{ + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + return lsm9ds1_modifyreg8(priv, LSM9DS1_CTRL_REG6_XL, + LSM9DS1_CTRL_REG6_XL_ODR_XL_MASK, + LSM9DS1_CTRL_REG6_XL_ODR_XL_POWERDOWN); +} + +/**************************************************************************** + * Name: lsm9ds1accelgyro_setsamplerate + * + * Description: + * Set the accelerometer or gyroscope's sample rate. + * + ****************************************************************************/ + +static int lsm9ds1accelgyro_setsamplerate(FAR struct lsm9ds1_dev_s *priv, + uint32_t samplerate) +{ + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + priv->samplerate = samplerate; + return OK; +} + +/**************************************************************************** + * Name: lsm9ds1accel_setfullscale + * + * Description: + * Set the accelerometer's full-scale range. + * + ****************************************************************************/ + +static int lsm9ds1accel_setfullscale(FAR struct lsm9ds1_dev_s *priv, + uint32_t fullscale) +{ + uint8_t setbits; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + if (fullscale < lsm9ds1_midpoint(2, 4)) + { + setbits = LSM9DS1_CTRL_REG6_XL_FS_XL_2G; + } + else if (fullscale < lsm9ds1_midpoint(4, 8)) + { + setbits = LSM9DS1_CTRL_REG6_XL_FS_XL_4G; + } + else if (fullscale < lsm9ds1_midpoint(8, 16)) + { + setbits = LSM9DS1_CTRL_REG6_XL_FS_XL_8G; + } + else + { + setbits = LSM9DS1_CTRL_REG6_XL_FS_XL_16G; + } + + return lsm9ds1_modifyreg8(priv, LSM9DS1_CTRL_REG6_XL, + LSM9DS1_CTRL_REG6_XL_FS_XL_MASK, setbits); +} + +/**************************************************************************** + * Name: lsm9ds1gyro_start + * + * Description: + * Start the gyroscope. + * + ****************************************************************************/ + +static int lsm9ds1gyro_start(FAR struct lsm9ds1_dev_s *priv) +{ + uint8_t setbits; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + if (priv->samplerate < lsm9ds1_midpoint(14, 59)) + { + setbits = LSM9DS1_CTRL_REG1_G_ODR_G_14p9HZ; + } + else if (priv->samplerate < lsm9ds1_midpoint(59, 119)) + { + setbits = LSM9DS1_CTRL_REG1_G_ODR_G_59p5HZ; + } + else if (priv->samplerate < lsm9ds1_midpoint(119, 238)) + { + setbits = LSM9DS1_CTRL_REG1_G_ODR_G_119HZ; + } + else if (priv->samplerate < lsm9ds1_midpoint(238, 476)) + { + setbits = LSM9DS1_CTRL_REG1_G_ODR_G_238HZ; + } + else if (priv->samplerate < lsm9ds1_midpoint(476, 952)) + { + setbits = LSM9DS1_CTRL_REG1_G_ODR_G_476HZ; + } + else + { + setbits = LSM9DS1_CTRL_REG1_G_ODR_G_952HZ; + } + + return lsm9ds1_modifyreg8(priv, LSM9DS1_CTRL_REG1_G, + LSM9DS1_CTRL_REG1_G_ODR_G_MASK, setbits); +} + +/**************************************************************************** + * Name: lsm9ds1gyro_stop + * + * Description: + * Stop the gyroscope. + * + ****************************************************************************/ + +static int lsm9ds1gyro_stop(FAR struct lsm9ds1_dev_s *priv) +{ + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + return lsm9ds1_modifyreg8(priv, LSM9DS1_CTRL_REG1_G, + LSM9DS1_CTRL_REG1_G_ODR_G_MASK, + LSM9DS1_CTRL_REG1_G_ODR_G_POWERDOWN); +} + +/**************************************************************************** + * Name: lsm9ds1gyro_setfullscale + * + * Description: + * Set the gyroscope's full-scale range. + * + ****************************************************************************/ + +static int lsm9ds1gyro_setfullscale(FAR struct lsm9ds1_dev_s *priv, + uint32_t fullscale) +{ + uint8_t setbits; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + if (fullscale < lsm9ds1_midpoint(245, 500)) + { + setbits = LSM9DS1_CTRL_REG1_G_FS_G_245DPS; + } + else if (fullscale < lsm9ds1_midpoint(500, 2000)) + { + setbits = LSM9DS1_CTRL_REG1_G_FS_G_500DPS; + } + else + { + setbits = LSM9DS1_CTRL_REG1_G_FS_G_2000DPS; + } + + return lsm9ds1_modifyreg8(priv, LSM9DS1_CTRL_REG1_G, + LSM9DS1_CTRL_REG1_G_FS_G_MASK, setbits); +} + +/**************************************************************************** + * Name: lsm9ds1mag_config + * + * Description: + * Configure the magnetometer. + * + ****************************************************************************/ + +static int lsm9ds1mag_config(FAR struct lsm9ds1_dev_s *priv) +{ + int ret; + uint8_t regval; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + /* Get the device identification */ + + ret = lsm9ds1_readreg8(priv, LSM9DS1_WHO_AM_I_M, ®val); + if (ret < 0) + { + sndbg("lsm9ds1_readreg8 failed: %d\n", ret); + return ret; + } + + if (regval != LSM9DS1_WHO_AM_I_M_VALUE) + { + sndbg("Invalid device identification %02x\n", regval); + return -ENODEV; + } + + return OK; +} + +/**************************************************************************** + * Name: lsm9ds1mag_start + * + * Description: + * Start the magnetometer. + * + ****************************************************************************/ + +static int lsm9ds1mag_start(FAR struct lsm9ds1_dev_s *priv) +{ + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + return lsm9ds1_modifyreg8(priv, LSM9DS1_CTRL_REG3_M, + LSM9DS1_CTRL_REG3_M_MD_MASK, + LSM9DS1_CTRL_REG3_M_MD_CONT); +} + +/**************************************************************************** + * Name: lsm9ds1mag_stop + * + * Description: + * Stop the magnetometer. + * + ****************************************************************************/ + +static int lsm9ds1mag_stop(FAR struct lsm9ds1_dev_s *priv) +{ + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + return lsm9ds1_modifyreg8(priv, LSM9DS1_CTRL_REG3_M, + LSM9DS1_CTRL_REG3_M_MD_MASK, + LSM9DS1_CTRL_REG3_M_MD_POWERDOWN2); +} + +/**************************************************************************** + * Name: lsm9ds1mag_setfullscale + * + * Description: + * Set the magnetometer's full-scale range. + * + ****************************************************************************/ + +static int lsm9ds1mag_setfullscale(FAR struct lsm9ds1_dev_s *priv, + uint32_t fullscale) +{ + uint8_t setbits; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + if (fullscale < lsm9ds1_midpoint(4, 8)) + { + setbits = LSM9DS1_CTRL_REG2_M_FS_4GAUSS; + } + else if (fullscale < lsm9ds1_midpoint(8, 12)) + { + setbits = LSM9DS1_CTRL_REG2_M_FS_8GAUSS; + } + else if (fullscale < lsm9ds1_midpoint(12, 16)) + { + setbits = LSM9DS1_CTRL_REG2_M_FS_12GAUSS; + } + else + { + setbits = LSM9DS1_CTRL_REG2_M_FS_16GAUSS; + } + + return lsm9ds1_modifyreg8(priv, LSM9DS1_CTRL_REG2_M, + LSM9DS1_CTRL_REG2_M_FS_MASK, setbits); +} + +/**************************************************************************** + * Name: lsm9ds1mag_setsamplerate + * + * Description: + * Set the magnetometer's sample rate. + * + ****************************************************************************/ + +static int lsm9ds1mag_setsamplerate(FAR struct lsm9ds1_dev_s *priv, + uint32_t samplerate) +{ + uint8_t setbits; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + /* The magnetometer can change its sample rate without exiting + * power-down mode, so we don't need to save the value for later, + * unlike the accelerometer and gyroscope. + */ + + if (samplerate < lsm9ds1_midpoint(0, 1)) + { + setbits = LSM9DS1_CTRL_REG1_M_DO_0p625HZ; + } + else if (samplerate < lsm9ds1_midpoint(1, 2)) + { + setbits = LSM9DS1_CTRL_REG1_M_DO_1p25HZ; + } + else if (samplerate < lsm9ds1_midpoint(2, 5)) + { + setbits = LSM9DS1_CTRL_REG1_M_DO_2p5HZ; + } + else if (samplerate < lsm9ds1_midpoint(5, 10)) + { + setbits = LSM9DS1_CTRL_REG1_M_DO_5HZ; + } + else if (samplerate < lsm9ds1_midpoint(10, 20)) + { + setbits = LSM9DS1_CTRL_REG1_M_DO_10HZ; + } + else if (samplerate < lsm9ds1_midpoint(20, 40)) + { + setbits = LSM9DS1_CTRL_REG1_M_DO_20HZ; + } + else if (samplerate < lsm9ds1_midpoint(40, 80)) + { + setbits = LSM9DS1_CTRL_REG1_M_DO_40HZ; + } + else + { + setbits = LSM9DS1_CTRL_REG1_M_DO_80HZ; + } + + return lsm9ds1_modifyreg8(priv, LSM9DS1_CTRL_REG1_M, + LSM9DS1_CTRL_REG1_M_DO_MASK, setbits); +} + +/**************************************************************************** + * Name: lsm9ds1_open + * + * Description: + * This method is called when the device is opened. + * + ****************************************************************************/ + +static int lsm9ds1_open(FAR struct file *filep) +{ + return OK; +} + +/**************************************************************************** + * Name: lsm9ds1_close + * + * Description: + * This method is called when the device is closed. + * + ****************************************************************************/ + +static int lsm9ds1_close(FAR struct file *filep) +{ + return OK; +} + +/**************************************************************************** + * Name: lsm9ds1_read + * + * Description: + * The standard read method. + * + ****************************************************************************/ + +static ssize_t lsm9ds1_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR struct inode *inode; + FAR struct lsm9ds1_dev_s *priv; + int ret; + size_t i; + size_t j; + size_t samplesize; + size_t nsamples; + uint16_t data; + FAR int16_t *ptr; + uint8_t regaddr; + uint8_t lo; + uint8_t hi; + + /* Sanity check */ + + DEBUGASSERT(filep != NULL); + inode = filep->f_inode; + + DEBUGASSERT(inode != NULL); + priv = (FAR struct lsm9ds1_dev_s *)inode->i_private; + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv->datareg == LSM9DS1_OUT_X_L_G || + priv->datareg == LSM9DS1_OUT_X_L_XL || + priv->datareg == LSM9DS1_OUT_X_L_M); + DEBUGASSERT(buffer != NULL); + + samplesize = 3 * sizeof(*ptr); + nsamples = buflen / samplesize; + ptr = (FAR int16_t *)buffer; + + /* Get the requested number of samples */ + + for (i = 0; i < nsamples; i++) + { + /* Reset the register address to the X low byte register */ + + regaddr = priv->datareg; + + /* Read the X, Y and Z data */ + + for (j = 0; j < 3; j++) + { + /* Read the low byte */ + + ret = lsm9ds1_readreg8(priv, regaddr, &lo); + if (ret < 0) + { + sndbg("lsm9ds1_readreg8 failed: %d\n", ret); + return (ssize_t)ret; + } + + regaddr++; + + /* Read the high byte */ + + ret = lsm9ds1_readreg8(priv, regaddr, &hi); + if (ret < 0) + { + sndbg("lsm9ds1_readreg8 failed: %d\n", ret); + return (ssize_t)ret; + } + + regaddr++; + + /* The data is 16 bits in two's complement representation */ + + data = ((uint16_t)hi << 8) | (uint16_t)lo; + + /* The value is positive */ + + if (data < 0x8000) + { + ptr[j] = (int16_t)data; + } + + /* The value is negative, so find its absolute value by taking the + * two's complement + */ + + else if (data > 0x8000) + { + data = ~data + 1; + ptr[j] = -(int16_t)data; + } + + /* The value is negative and can't be represented as a positive + * int16_t value + */ + + else + { + ptr[j] = (int16_t)(-32768); + } + } + } + + return nsamples * samplesize; +} + +/**************************************************************************** + * Name: lsm9ds1_write + * + * Description: + * A dummy write method. + * + ****************************************************************************/ + +static ssize_t lsm9ds1_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: lsm9ds1_ioctl + * + * Description: + * The standard ioctl method. + * + ****************************************************************************/ + +static int lsm9ds1_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode; + FAR struct lsm9ds1_dev_s *priv; + int ret; + + /* Sanity check */ + + DEBUGASSERT(filep != NULL); + inode = filep->f_inode; + + DEBUGASSERT(inode != NULL); + priv = (FAR struct lsm9ds1_dev_s *)inode->i_private; + + DEBUGASSERT(priv != NULL); + + /* Handle ioctl commands */ + + switch (cmd) + { + /* Start converting. Arg: None. */ + + case SNIOC_START: + ret = priv->ops->start(priv); + break; + + /* Stop converting. Arg: None. */ + + case SNIOC_STOP: + ret = priv->ops->stop(priv); + break; + + /* Set the sample rate. Arg: uint32_t value. */ + + case SNIOC_SETSAMPLERATE: + ret = priv->ops->setsamplerate(priv, (uint32_t)arg); + sndbg("sample rate: %08x ret: %d\n", (uint32_t)arg, ret); + break; + + /* Set the full-scale range. Arg: uint32_t value. */ + + case SNIOC_SETFULLSCALE: + ret = priv->ops->setfullscale(priv, (uint32_t)arg); + sndbg("full-scale range: %08x ret: %d\n", (uint32_t)arg, ret); + break; + + /* Unrecognized commands */ + + default: + sndbg("Unrecognized cmd: %d arg: %lu\n", cmd, arg); + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: lsm9ds1_register + * + * Description: + * Register the LSM9DS1 accelerometer, gyroscope or magnetometer character + * device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register, e.g., "/dev/accel0", + * "/dev/gyro0" or "/dev/mag0". + * i2c - An I2C driver instance. + * addr - The I2C address of the LSM9DS1 accelerometer, gyroscope or + * magnetometer. + * ops - The device operations structure. + * datareg - The register address of the low byte of the X-coordinate data. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int lsm9ds1_register(FAR const char *devpath, + FAR struct i2c_dev_s *i2c, uint8_t addr, + FAR const struct lsm9ds1_ops_s *ops, + uint8_t datareg) +{ + FAR struct lsm9ds1_dev_s *priv; + int ret; + + /* Sanity check */ + + DEBUGASSERT(devpath != NULL); + DEBUGASSERT(i2c != NULL); + DEBUGASSERT(datareg == LSM9DS1_OUT_X_L_XL || + datareg == LSM9DS1_OUT_X_L_G || + datareg == LSM9DS1_OUT_X_L_M); + + /* Initialize the device's structure */ + + priv = (FAR struct lsm9ds1_dev_s *)kmm_malloc(sizeof(*priv)); + if (priv == NULL) + { + sndbg("Failed to allocate instance\n"); + return -ENOMEM; + } + + priv->i2c = i2c; + priv->addr = addr; + priv->ops = ops; + priv->samplerate = 0; + priv->datareg = datareg; + + /* Configure the device */ + + ret = priv->ops->config(priv); + if (ret < 0) + { + sndbg("Failed to configure device: %d\n", ret); + kmm_free(priv); + return ret; + } + + /* Register the character driver */ + + ret = register_driver(devpath, &g_fops, 0666, priv); + if (ret < 0) + { + sndbg("Failed to register driver: %d\n", ret); + kmm_free(priv); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lsm9ds1accel_register + * + * Description: + * Register the LSM9DS1 accelerometer character device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register, e.g., "/dev/accel0". + * i2c - An I2C driver instance. + * addr - The I2C address of the LSM9DS1 accelerometer. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int lsm9ds1accel_register(FAR const char *devpath, FAR struct i2c_dev_s *i2c, + uint8_t addr) +{ + /* Sanity check */ + + DEBUGASSERT(addr == LSM9DS1ACCEL_ADDR0 || addr == LSM9DS1ACCEL_ADDR1); + + return lsm9ds1_register(devpath, i2c, addr, &g_lsm9ds1accel_ops, + LSM9DS1_OUT_X_L_XL); +} + +/**************************************************************************** + * Name: lsm9ds1gyro_register + * + * Description: + * Register the LSM9DS1 gyroscope character device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register, e.g., "/dev/gyro0". + * i2c - An I2C driver instance. + * addr - The I2C address of the LSM9DS1 gyroscope. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int lsm9ds1gyro_register(FAR const char *devpath, FAR struct i2c_dev_s *i2c, + uint8_t addr) +{ + /* Sanity check */ + + DEBUGASSERT(addr == LSM9DS1GYRO_ADDR0 || addr == LSM9DS1GYRO_ADDR1); + + return lsm9ds1_register(devpath, i2c, addr, &g_lsm9ds1gyro_ops, + LSM9DS1_OUT_X_L_G); +} + +/**************************************************************************** + * Name: lsm9ds1mag_register + * + * Description: + * Register the LSM9DS1 magnetometer character device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register, e.g., "/dev/mag0". + * i2c - An I2C driver instance. + * addr - The I2C address of the LSM9DS1 magnetometer. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int lsm9ds1mag_register(FAR const char *devpath, FAR struct i2c_dev_s *i2c, + uint8_t addr) +{ + /* Sanity check */ + + DEBUGASSERT(addr == LSM9DS1MAG_ADDR0 || addr == LSM9DS1MAG_ADDR1); + + return lsm9ds1_register(devpath, i2c, addr, &g_lsm9ds1mag_ops, + LSM9DS1_OUT_X_L_M); +} + +#endif /* CONFIG_I2C && CONFIG_SN_LSM9DS1 */ diff --git a/include/nuttx/sensors/lsm9ds1.h b/include/nuttx/sensors/lsm9ds1.h new file mode 100644 index 00000000000..d69ca9e808a --- /dev/null +++ b/include/nuttx/sensors/lsm9ds1.h @@ -0,0 +1,151 @@ +/**************************************************************************** + * include/nuttx/sensors/lsm9ds1.h + * + * Copyright (C) 2016 Omni Hoverboards Inc. All rights reserved. + * Author: Paul Alexander Patience + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_SENSORS_LSM9DS1 +#define __INCLUDE_NUTTX_SENSORS_LSM9DS1 + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#if defined(CONFIG_I2C) && defined(CONFIG_SN_LSM9DS1) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* IOCTL Commands ***********************************************************/ + +#define SNIOC_START _SNIOC(0x0001) /* Arg: None */ +#define SNIOC_STOP _SNIOC(0x0002) /* Arg: None */ +#define SNIOC_SETSAMPLERATE _SNIOC(0x0003) /* Arg: uint32_t value */ +#define SNIOC_SETFULLSCALE _SNIOC(0x0004) /* Arg: uint32_t value */ + +/* I2C Addresses ************************************************************/ +/* Accelerometer addresses */ + +#define LSM9DS1ACCEL_ADDR0 0x6a +#define LSM9DS1ACCEL_ADDR1 0x6b + +/* Gyroscope addresses */ + +#define LSM9DS1GYRO_ADDR0 LSM9DS1ACCEL_ADDR0 +#define LSM9DS1GYRO_ADDR1 LSM9DS1ACCEL_ADDR1 + +/* Magnetometer addresses */ + +#define LSM9DS1MAG_ADDR0 0x1c +#define LSM9DS1MAG_ADDR1 0x1e + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct i2c_dev_s; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/**************************************************************************** + * Name: lsm9ds1accel_register + * + * Description: + * Register the LSM9DS1 accelerometer character device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register, e.g., "/dev/accel0". + * i2c - An I2C driver instance. + * addr - The I2C address of the LSM9DS1 accelerometer. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int lsm9ds1accel_register(FAR const char *devpath, FAR struct i2c_dev_s *i2c, + uint8_t addr); + +/**************************************************************************** + * Name: lsm9ds1gyro_register + * + * Description: + * Register the LSM9DS1 gyroscope character device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register, e.g., "/dev/gyro0". + * i2c - An I2C driver instance. + * addr - The I2C address of the LSM9DS1 gyroscope. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int lsm9ds1gyro_register(FAR const char *devpath, FAR struct i2c_dev_s *i2c, + uint8_t addr); + +/**************************************************************************** + * Name: lsm9ds1mag_register + * + * Description: + * Register the LSM9DS1 magnetometer character device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register, e.g., "/dev/mag0". + * i2c - An I2C driver instance. + * addr - The I2C address of the LSM9DS1 magnetometer. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int lsm9ds1mag_register(FAR const char *devpath, FAR struct i2c_dev_s *i2c, + uint8_t addr); + +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_I2C && CONFIG_SN_LSM9DS1 */ +#endif /* __INCLUDE_NUTTX_SENSORS_LSM9DS1 */