From cd2ced4d9a00bd123b6c6153f09124ea693fee31 Mon Sep 17 00:00:00 2001 From: DisruptiveNL Date: Sat, 25 Aug 2018 08:19:31 -0600 Subject: [PATCH] drivers/sensors and configs/nucleo-l476g: Add support for LSM303AGR and LSM6DSL sensors --- TODO | 4 +- configs/nucleo-l476rg/include/board.h | 12 + configs/nucleo-l476rg/src/Makefile | 12 + configs/nucleo-l476rg/src/nucleo-l476rg.h | 4 + configs/nucleo-l476rg/src/stm32_appinit.c | 36 +- configs/nucleo-l476rg/src/stm32_lsm303agr.c | 94 ++ configs/nucleo-l476rg/src/stm32_lsm6dsl.c | 100 ++ drivers/sensors/Kconfig | 26 + drivers/sensors/Make.defs | 8 + drivers/sensors/lsm303agr.c | 1287 ++++++++++++++++++ drivers/sensors/lsm6dsl.c | 1345 +++++++++++++++++++ include/nuttx/sensors/ioctl.h | 156 ++- include/nuttx/sensors/lsm303agr.h | 228 ++++ include/nuttx/sensors/lsm6dsl.h | 897 +++++++++++++ 14 files changed, 4129 insertions(+), 80 deletions(-) create mode 100644 configs/nucleo-l476rg/src/stm32_lsm303agr.c create mode 100644 configs/nucleo-l476rg/src/stm32_lsm6dsl.c create mode 100644 drivers/sensors/lsm303agr.c create mode 100644 drivers/sensors/lsm6dsl.c create mode 100644 include/nuttx/sensors/lsm303agr.h create mode 100644 include/nuttx/sensors/lsm6dsl.h diff --git a/TODO b/TODO index ef4d193a35f..60325f7ccbb 100644 --- a/TODO +++ b/TODO @@ -454,10 +454,10 @@ o SMP Title: CORTEX-A GIC SGI INTERRUPT MASKING Description: In the ARMv7-A GICv2 architecture, the inter-processor interrupts (SGIs) are non maskable and will occur even if - interrupts are disabled. This addes a lot of complexity + interrupts are disabled. This adde a lot of complexity to the ARMV7-A critical section design. - Masayuki Ishakawa has suggest the use of the GICv2 ICCMPR + Masayuki Ishakawa has suggested the use of the GICv2 ICCMPR register to control SGI interrupts. This register (much like the ARMv7-M BASEPRI register) can be used to mask interrupts by interrupt priority. Since SGIs may be assigned priorities diff --git a/configs/nucleo-l476rg/include/board.h b/configs/nucleo-l476rg/include/board.h index 6e7cb0aefb2..a9fa9bc1ac8 100644 --- a/configs/nucleo-l476rg/include/board.h +++ b/configs/nucleo-l476rg/include/board.h @@ -120,6 +120,18 @@ #define GPIO_USART2_RTS GPIO_USART2_RTS_2 #define GPIO_USART2_CTS GPIO_USART2_CTS_2 +/* USART3: + * RXD: PA10 CN9 pin 3, CN10 pin 33 + * PC5 CN5 pin 9, CN10 pin 6 + * PC11 CN7 pin 2 + * TXD: PA9 CN5 pin 1, CN10 pin 21 + * PC4 CN9 pin 3, CN10 pin 34 + * PC10 CN7 pin 1 + */ + +#define GPIO_USART3_RX GPIO_USART3_RX_3 /* PC11 */ +#define GPIO_USART3_TX GPIO_USART3_TX_3 /* PC10 */ + #define GPIO_UART4_RX GPIO_UART4_RX_1 /* PA1 */ #define GPIO_UART4_TX GPIO_UART4_TX_1 /* PA0 */ diff --git a/configs/nucleo-l476rg/src/Makefile b/configs/nucleo-l476rg/src/Makefile index a7c47f6cbf9..d06c4871429 100644 --- a/configs/nucleo-l476rg/src/Makefile +++ b/configs/nucleo-l476rg/src/Makefile @@ -81,6 +81,18 @@ ifeq ($(CONFIG_SENSORS_QENCODER),y) CSRCS += stm32_qencoder.c endif +ifeq ($(CONFIG_SENSORS_HTS221),y) +CSRCS += stm32_hts221.c +endif + +ifeq ($(CONFIG_SENSORS_LSM6DSL),y) +CSRCS += stm32_lsm6dsl.c +endif + +ifeq ($(CONFIG_SENSORS_LSM303AGR),y) +CSRCS += stm32_lsm303agr.c +endif + ifeq ($(CONFIG_PWM),y) CSRCS += stm32_pwm.c endif diff --git a/configs/nucleo-l476rg/src/nucleo-l476rg.h b/configs/nucleo-l476rg/src/nucleo-l476rg.h index aa06f948fb2..344235ac8eb 100644 --- a/configs/nucleo-l476rg/src/nucleo-l476rg.h +++ b/configs/nucleo-l476rg/src/nucleo-l476rg.h @@ -267,6 +267,10 @@ GPIO_OUTPUT_SET | GPIO_PORTB | GPIO_PIN1) #define GPIO_INT1 (GPIO_INPUT | GPIO_FLOAT | GPIO_PORTB | GPIO_PIN2) +#define GPIO_HTS221_INT (GPIO_INPUT | GPIO_FLOAT | GPIO_PORTA | GPIO_PIN10) +#define GPIO_LSM6DSL_INT1 (GPIO_INPUT | GPIO_FLOAT | GPIO_PORTB | GPIO_PIN4) +#define GPIO_LSM6DSL_INT2 (GPIO_INPUT | GPIO_FLOAT | GPIO_PORTB | GPIO_PIN5) + /************************************************************************************ * Public Data ************************************************************************************/ diff --git a/configs/nucleo-l476rg/src/stm32_appinit.c b/configs/nucleo-l476rg/src/stm32_appinit.c index 68c4385e28e..a1e04c5dc43 100644 --- a/configs/nucleo-l476rg/src/stm32_appinit.c +++ b/configs/nucleo-l476rg/src/stm32_appinit.c @@ -64,6 +64,12 @@ # include "stm32l4_rtc.h" #endif +#include "stm32l4_i2c.h" + +/**************************************************************************** + * Private Data + ***************************************************************************/ + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -204,10 +210,6 @@ int board_app_initialize(uintptr_t arg) } #endif -/* Initialize CAN and register the CAN driver. - * Added by: Ben vd Veen (DisruptiveNL) -- www.nuttx.nl - */ - #ifdef CONFIG_CAN ret = stm32l4_can_setup(); if (ret < 0) @@ -332,9 +334,29 @@ int board_app_initialize(uintptr_t arg) #endif #endif /* CONFIG_SENSORS_QENCODER */ -/* Initialize CAN and register the CAN driver. - * Added by: Ben vd Veen (DisruptiveNL) -- www.nuttx.nl - */ +#ifdef CONFIG_SENSORS_HTS221 + ret = stm32l4_hts221_initialize("/dev/hts221"); + if (ret < 0) + { + serr("ERROR: Failed to initialize HTC221 driver: %d\n", ret); + } +#endif + +#ifdef CONFIG_SENSORS_LSM6DSL + ret = stm32l4_lsm6dsl_initialize("/dev/lsm6dsl0"); + if (ret < 0) + { + serr("ERROR: Failed to initialize LSM6DSL driver: %d\n", ret); + } +#endif + +#ifdef CONFIG_SENSORS_LSM303AGR + ret = stm32l4_lsm303agr_initialize("/dev/lsm303mag0"); + if (ret < 0) + { + serr("ERROR: Failed to initialize LSM303AGR driver: %d\n", ret); + } +#endif #ifdef CONFIG_DEV_GPIO ret = stm32l4_gpio_initialize(); diff --git a/configs/nucleo-l476rg/src/stm32_lsm303agr.c b/configs/nucleo-l476rg/src/stm32_lsm303agr.c new file mode 100644 index 00000000000..eb8ad2c5b9d --- /dev/null +++ b/configs/nucleo-l476rg/src/stm32_lsm303agr.c @@ -0,0 +1,94 @@ +/***************************************************************************** + * configs/stm32l476rg/src/stm32_lsm303agr.c + * + * Copyright (C) 2018 Greg Nutt. All rights reserved. + * Author: Alan Carvalho de Assis + * + * 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 "stm32l4.h" +#include +#include + +/***************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_STM32L4_I2C1 +# error "LSM303AGR driver requires CONFIG_STM32L4_I2C1 to be enabled" +#endif + +/***************************************************************************** + * Public Functions + ****************************************************************************/ + +/***************************************************************************** + * Name: stm32_lsm303agr_initialize + * + * Description: + * Initialize I2C-based LSM303AGR. + ****************************************************************************/ + +int stm32l4_lsm303agr_initialize(char *devpath) +{ + FAR struct i2c_master_s *i2c; + int ret = OK; + + sninfo("INFO: Initializing LMS303AGR sensor over I2C\n"); + +#if defined(CONFIG_STM32L4_I2C1) + i2c = stm32l4_i2cbus_initialize(1); + if (i2c == NULL) + { + return -ENODEV; + } + + ret = lsm303agr_sensor_register("/dev/lsm303mag0", i2c, LSM303AGRMAGNETO_ADDR); + if (ret < 0) + { + snerr("ERROR: Failed to initialize LMS303AGR magneto driver %s\n", devpath); + return -ENODEV; + } + + sninfo("INFO: LMS303AGR sensor has been initialized successfully\n"); +#endif + + return ret; +} diff --git a/configs/nucleo-l476rg/src/stm32_lsm6dsl.c b/configs/nucleo-l476rg/src/stm32_lsm6dsl.c new file mode 100644 index 00000000000..5c2030dc333 --- /dev/null +++ b/configs/nucleo-l476rg/src/stm32_lsm6dsl.c @@ -0,0 +1,100 @@ +/***************************************************************************** + * configs/stm32l476rg/src/stm32_lsm6dsl.c + * + * Copyright (C) 2018 Greg Nutt. All rights reserved. + * Author: Alan Carvalho de Assis + * + * 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 "stm32l4.h" +#include +#include + +/***************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_STM32L4_I2C1 +# error "LSM6DSL driver requires CONFIG_STM32L4_I2C1 to be enabled" +#endif + +/***************************************************************************** + * Public Functions + ****************************************************************************/ + +/***************************************************************************** + * Name: stm32_lsm6dsl_initialize + * + * Description: + * Initialize I2C-based LSM6DSL. + ****************************************************************************/ + +int stm32l4_lsm6dsl_initialize(char *devpath) +{ + FAR struct i2c_master_s *i2c; + int ret = OK; + + sninfo("Initializing LMS6DSL!\n"); + + /* Configure the GPIO interrupt */ + + stm32l4_configgpio(GPIO_HTS221_INT); /* IS THE SAME AS HTS221 FOR IKS01_A2 SHIELD */ + +#if defined(CONFIG_STM32L4_I2C1) + i2c = stm32l4_i2cbus_initialize(1); + if (i2c == NULL) + { + return -ENODEV; + } + + sninfo("INFO: Initializing LMS6DSL accelero-gyro sensor over I2C%d\n", ret); + + ret = lsm6dsl_sensor_register("/dev/lsm6dsl0", i2c, LSM6DSLACCEL_ADDR1); + if (ret < 0) + { + snerr("ERROR: Failed to initialize LMS6DSL accelero-gyro driver %s\n", devpath); + return -ENODEV; + } + + sninfo("INFO: LMS6DSL sensor has been initialized successfully\n"); +#endif + + return ret; +} diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig index 02cce0600ae..5ecaa38c142 100644 --- a/drivers/sensors/Kconfig +++ b/drivers/sensors/Kconfig @@ -185,6 +185,32 @@ config SENSORS_LSM330SPI ---help--- Enable driver support for the STMicro LSM330 on SPI. +config SENSORS_LSM303AGR + bool "STMicro LSM303AGR support" + default n + select I2C + ---help--- + Enable driver support for the STMicro LSM303AGR. + +config LSM303AGR_I2C_FREQUENCY + int "LSM303AGR I2C frequency" + default 400000 + range 1 400000 + depends on SN_LSM303AGR + +config SENSORS_LSM6DSL + bool "STMicro LSM6DSL support" + default n + select I2C + ---help--- + Enable driver support for the STMicro LSM6DSL. + +config LSM6DSL_I2C_FREQUENCY + int "LSM6DSL I2C frequency" + default 400000 + range 1 400000 + depends on SN_LSM6DSL + config SENSORS_LSM9DS1 bool "STMicro LSM9DS1 support" default n diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs index e94e397bcc1..9fa30cc8b0b 100644 --- a/drivers/sensors/Make.defs +++ b/drivers/sensors/Make.defs @@ -69,6 +69,14 @@ ifeq ($(CONFIG_LIS331DL),y) CSRCS += lis331dl.c endif +ifeq ($(CONFIG_SENSORS_LSM303AGR),y) + CSRCS += lsm303agr.c +endif + +ifeq ($(CONFIG_SENSORS_LSM6DSL),y) + CSRCS += lsm6dsl.c +endif + ifeq ($(CONFIG_SENSORS_LSM9DS1),y) CSRCS += lsm9ds1.c endif diff --git a/drivers/sensors/lsm303agr.c b/drivers/sensors/lsm303agr.c new file mode 100644 index 00000000000..d3c0401217e --- /dev/null +++ b/drivers/sensors/lsm303agr.c @@ -0,0 +1,1287 @@ +/**************************************************************************** + * drivers/sensors/lsm303agr.c + * + * Copyright (C) 2018 Inc. All rights reserved. + * Author: Ben vd Veen + * Alias: DisruptiveNL + * + * Based on: + * + * Copyright (C) 2016 Omni Hoverboards Inc. All rights reserved. + * Author: Paul Alexander Patience + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 +#include + +#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_LSM303AGR) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_LSM303AGR_I2C_FREQUENCY +# define CONFIG_LSM303AGR_I2C_FREQUENCY 400000 +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* I2C Helpers */ + +static int lsm303agr_readreg8(FAR struct lsm303agr_dev_s *priv, + uint8_t regaddr, FAR uint8_t * regval); +static int lsm303agr_writereg8(FAR struct lsm303agr_dev_s *priv, + uint8_t regaddr, uint8_t regval); +static int lsm303agr_modifyreg8(FAR struct lsm303agr_dev_s *priv, + uint8_t regaddr, + uint8_t clearbits, uint8_t setbits); + +/* Other Helpers */ + +static int lsm303agr_find_minimum(int16_t a[], int n); +static int lsm303agr_find_maximum(int16_t a[], int n); +static bool lsm303agr_isbitset(int8_t b, int8_t n); + +/* Accelerometer Operations */ + +static int lsm303agr_sensor_config(FAR struct lsm303agr_dev_s *priv); +static int lsm303agr_sensor_start(FAR struct lsm303agr_dev_s *priv); +static int lsm303agr_sensor_stop(FAR struct lsm303agr_dev_s *priv); +static int lsm303agr_sensor_read(FAR struct lsm303agr_dev_s *priv, + FAR struct lsm303agr_sensor_data_s *sensor_data); +static int lsm303agr_selftest(FAR struct lsm303agr_dev_s *priv, + uint32_t mode); + +/* Character Driver Methods */ + +static int lsm303agr_open(FAR struct file *filep); +static int lsm303agr_close(FAR struct file *filep); +static ssize_t lsm303agr_read(FAR struct file *filep, + FAR char *buffer, size_t buflen); +static ssize_t lsm303agr_write(FAR struct file *filep, + FAR const char *buffer, size_t buflen); +static int lsm303agr_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); + +/* Common Register Function */ + +static int lsm303agr_register(FAR const char *devpath, + FAR struct i2c_master_s *i2c, + uint8_t addr, + FAR const struct lsm303agr_ops_s *ops, + uint8_t datareg, + struct lsm303agr_sensor_data_s sensor_data); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static double accelerofactor = 0; +static double magnetofactor = 0; + +static const struct file_operations g_fops = +{ + lsm303agr_open, + lsm303agr_close, + lsm303agr_read, + lsm303agr_write, + NULL, + lsm303agr_ioctl +#ifndef CONFIG_DISABLE_POLL + , NULL +#endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + , NULL +#endif +}; + +static const struct lsm303agr_ops_s g_lsm303agrsensor_ops = +{ + lsm303agr_sensor_config, + lsm303agr_sensor_start, + lsm303agr_sensor_stop, + lsm303agr_sensor_read, + lsm303agr_selftest +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lsm303agr_resetsensor + * + * Description: + * Reset sensor values + * + ****************************************************************************/ + +static void lsm303agr_resetsensor(FAR struct lsm303agr_dev_s *priv) +{ + priv->sensor_data.x_data = 0; + priv->sensor_data.y_data = 0; + priv->sensor_data.z_data = 0; + priv->sensor_data.temperature = 0; + priv->sensor_data.m_x_data = 0; + priv->sensor_data.m_y_data = 0; + priv->sensor_data.m_z_data = 0; + priv->sensor_data.timestamp = 0; +} + +/**************************************************************************** + * Name: lsm303agr_readreg8 + * + * Description: + * Read from an 8-bit register. + * + ****************************************************************************/ + +static int lsm303agr_readreg8(FAR struct lsm303agr_dev_s *priv, + uint8_t regaddr, FAR uint8_t * regval) +{ + struct i2c_config_s config; + int ret; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(regval != NULL); + + /* Set up the I2C configuration */ + + config.frequency = CONFIG_LSM303AGR_I2C_FREQUENCY; + config.address = priv->addr; + config.addrlen = 7; + + /* Write the register address */ + + ret = i2c_write(priv->i2c, &config, ®addr, sizeof(regaddr)); + if (ret < 0) + { + snerr("ERROR: i2c_write failed: %d\n", ret); + return ret; + } + + /* Restart and read 8 bits from the register */ + + ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval)); + if (ret < 0) + { + snerr("ERROR: i2c_read failed: %d\n", ret); + return ret; + } + + sninfo("addr: %02x value: %02x\n", regaddr, *regval); + return OK; +} + +/**************************************************************************** + * Name: lsm303agr_writereg8 + * + * Description: + * Write to an 8-bit register. + * + ****************************************************************************/ + +static int lsm303agr_writereg8(FAR struct lsm303agr_dev_s *priv, + uint8_t regaddr, uint8_t regval) +{ + struct i2c_config_s config; + uint8_t buffer[2]; + int ret; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + /* Set up a 2-byte message to send */ + + buffer[0] = regaddr; + buffer[1] = regval; + + /* Set up the I2C configuration */ + + config.frequency = CONFIG_LSM303AGR_I2C_FREQUENCY; + config.address = priv->addr; + config.addrlen = 7; + + /* Write the register address followed by the data (no RESTART) */ + + ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer)); + if (ret < 0) + { + snerr("ERROR: i2c_write failed: %d\n", ret); + return ret; + } + + sninfo("addr: %02x value: %02x\n", regaddr, regval); + return OK; +} + +/**************************************************************************** + * Name: lsm303agr_modifyreg8 + * + * Description: + * Modify an 8-bit register. + * + ****************************************************************************/ + +static int lsm303agr_modifyreg8(FAR struct lsm303agr_dev_s *priv, + uint8_t regaddr, + uint8_t clearbits, uint8_t setbits) +{ + int ret; + uint8_t regval; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + ret = lsm303agr_readreg8(priv, regaddr, ®val); + if (ret < 0) + { + snerr("ERROR: lsm303agr_readreg8 failed: %d\n", ret); + return ret; + } + + regval &= ~clearbits; + regval |= setbits; + + ret = lsm303agr_writereg8(priv, regaddr, regval); + if (ret < 0) + { + snerr("ERROR: lsm303agr_writereg8 failed: %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: lsm303agr_find_minimum + * + * Description: + * Find the minimum value in an array of numbers. + * + ****************************************************************************/ + +static int lsm303agr_find_minimum(int16_t a[], int n) +{ + int c; + int min; + int index; + + min = a[0]; + index = 0; + + for (c = 1; c < n; c++) + { + if (a[c] < min) + { + index = c; + min = a[c]; + } + } + + return index; +} + +/**************************************************************************** + * Name: lsm303agr_find_maximum + * + * Description: + * Find the maximum value in an array of numbers. + * + ****************************************************************************/ + +static int lsm303agr_find_maximum(int16_t am[], int n) +{ + int c; + int max = am[0]; + int index = 0; + + for (c = 1; c < n; c++) + { + if (am[c] > max) + { + index = c; + max = am[c]; + } + } + + return index; +} + +/**************************************************************************** + * Name: lsm303agr_sensor_config + * + * Description: + * Configure the accelerometer and gyroscope. + * + ****************************************************************************/ + +static int lsm303agr_sensor_config(FAR struct lsm303agr_dev_s *priv) +{ + int ret; + uint8_t regval; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + /* Get the device identification */ + + ret = lsm303agr_readreg8(priv, LSM303AGR_WHO_AM_I, ®val); + if (ret < 0) + { + snerr("ERROR: lsm303agr_readreg8 failed: %d\n", ret); + return ret; + } + + sninfo("WHO AM I check address regval: %02x reg: %d....\n", regval, ret); + + if (regval != LSM303AGR_WHO_AM_I_VALUE) + { + snerr("ERROR: Invalid device identification %02x\n", regval); + return -ENODEV; + } + + return OK; +} + +/**************************************************************************** + * Name: lsm303agr_isbitset + * + * Description: + * Check if bit it set from mask, not bit number. + * + ****************************************************************************/ + +static bool lsm303agr_isbitset(int8_t b, int8_t m) +{ + if ((b & m) != 0) + { + return true; + } + + return false; +} + +/**************************************************************************** + * Name: lsm303agr_sensor_start + * + * Description: + * Start the accelerometer. + * + ****************************************************************************/ + +static int lsm303agr_sensor_start(FAR struct lsm303agr_dev_s *priv) +{ + /* readreg8 is not necessary to modify. Clearbits can be 0x00 or 0xFF */ + + uint8_t value; + + /* Enable the accelerometer */ + + /* Reset values */ + + lsm303agr_resetsensor(priv); + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + sninfo("Starting...."); + + /* Accelerometer config registers Turn on the accelerometer: 833Hz, +- 16g */ + + lsm303agr_writereg8(priv, LSM303AGR_CTRL_REG1_A, 0x77); + lsm303agr_writereg8(priv, LSM303AGR_CTRL_REG4_A, 0xB0); + accelerofactor = 11.72; + + /* Gyro config registers Turn on the gyro: FS=2000dps, ODR=833Hz Not using + * modifyreg with empty value!!!! Then read value first!!! + * lsm303agr_modifyreg8(priv, lsm303agr_CTRL2_G, value, 0x7C); + */ + + lsm303agr_writereg8(priv, LSM303AGR_CFG_REG_A_M, 0x8C); + magnetofactor = 1.5; + + return OK; +} + +/**************************************************************************** + * Name: lsm303agr_sensor_stop + * + * Description: + * Stop the sensor. + * + ****************************************************************************/ + +static int lsm303agr_sensor_stop(FAR struct lsm303agr_dev_s *priv) +{ + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + /* Stop accelero: not implemented [datasheet] */ + + /* Stop magneto: not implemented [datasheet] */ + + return OK; +} + +/**************************************************************************** + * Name: lsm303agr_selftest + * + * Description: + * Selftesting the sensor. + * Mode 0 = selftest accelerometer and mode 1 = selftest magneto + * + ****************************************************************************/ + +static int lsm303agr_selftest(FAR struct lsm303agr_dev_s *priv, uint32_t mode) +{ + int samples = 5; + int i; + int i2; + int i3; + + uint8_t value; + int8_t lox = 0; + int8_t loxst = 0; + int8_t hix = 0; + int8_t hixst = 0; + int8_t loy = 0; + int8_t loyst = 0; + int8_t hiy = 0; + int8_t hiyst = 0; + int8_t loz = 0; + int8_t lozst = 0; + int8_t hiz = 0; + int8_t hizst = 0; + + int16_t OUTX_NOST[samples]; + int16_t OUTY_NOST[samples]; + int16_t OUTZ_NOST[samples]; + int16_t OUTX_ST[samples]; + int16_t OUTY_ST[samples]; + int16_t OUTZ_ST[samples]; + + int16_t AVR_OUTX_NOST[samples]; + int16_t AVR_OUTY_NOST[samples]; + int16_t AVR_OUTZ_NOST[samples]; + int16_t AVR_OUTX_ST[samples]; + int16_t AVR_OUTY_ST[samples]; + int16_t AVR_OUTZ_ST[samples]; + + int16_t avr_x = 0; + int16_t avr_y = 0; + int16_t avr_z = 0; + int16_t avr_xst = 0; + int16_t avr_yst = 0; + int16_t avr_zst = 0; + + int16_t min_x = 0; + int16_t min_y = 0; + int16_t min_z = 0; + int16_t max_x = 0; + int16_t max_y = 0; + int16_t max_z = 0; + + int16_t min_xst = 0; + int16_t min_yst = 0; + int16_t min_zst = 0; + int16_t max_xst = 0; + int16_t max_yst = 0; + int16_t max_zst = 0; + + int16_t ltemp; + int16_t htemp; + int16_t tempi; + int16_t temp = 0; + + int16_t raw_xst = 0; + int16_t raw_yst = 0; + int16_t raw_zst = 0; + + int16_t raw_x = 0; + int16_t raw_y = 0; + int16_t raw_z = 0; + + /* mode = 0 then add hex 0x06 to OUT registers */ + + int8_t registershift; + + /* Keep the device still during the self-test procedure. Setting registers + * Power up, wait for 100ms for stable output. + */ + + if (mode == 0) + { + registershift = 0x00; + lsm303agr_writereg8(priv, LSM303AGR_CTRL_REG2_A, 0x00); + lsm303agr_writereg8(priv, LSM303AGR_CTRL_REG3_A, 0x00); + lsm303agr_writereg8(priv, LSM303AGR_CTRL_REG4_A, 0x81); + lsm303agr_writereg8(priv, LSM303AGR_CTRL_REG1_A, 0x57); + accelerofactor = 1; + } + else + { + registershift = 0x40; + lsm303agr_writereg8(priv, LSM303AGR_CFG_REG_A_M, 0x8C); + lsm303agr_writereg8(priv, LSM303AGR_CFG_REG_B_M, 0x02); + lsm303agr_writereg8(priv, LSM303AGR_CFG_REG_C_M, 0x10); + magnetofactor = 1; + } + + nxsig_usleep(100000); /* 100ms */ + + /* Read the output registers after checking XLDA bit 5 times */ + + bool checkbit = false; + + /* Wait until first sample and data is available */ + + while (checkbit) + { + if (mode == 0) + { + lsm303agr_readreg8(priv, LSM303AGR_STATUS_REG_A, &value); + checkbit = lsm303agr_isbitset(value, LSM303AGR_STATUS_REG_A_ZYXDA); + } + else + { + lsm303agr_readreg8(priv, LSM303AGR_STATUS_REG_M, &value); + checkbit = lsm303agr_isbitset(value, LSM303AGR_STATUS_REG_M_ZYXDA); + } + } + + nxsig_usleep(100000); /* 100ms */ + + /* Read OUT registers Gyro is starting at 22h and Accelero at 28h */ + + lsm303agr_readreg8(priv, LSM303AGR_OUT_X_L_A + registershift, &lox); + lsm303agr_readreg8(priv, LSM303AGR_OUT_X_H_A + registershift, &hix); + + lsm303agr_readreg8(priv, LSM303AGR_OUT_Y_L_A + registershift, &loy); + lsm303agr_readreg8(priv, LSM303AGR_OUT_Y_H_A + registershift, &hiy); + + lsm303agr_readreg8(priv, LSM303AGR_OUT_Z_L_A + registershift, &loz); + lsm303agr_readreg8(priv, LSM303AGR_OUT_Z_H_A + registershift, &hiz); + + /* check XLDA 5 times */ + + for (i = 0; i < samples; i++) + { + if (mode == 0) + { + lsm303agr_readreg8(priv, LSM303AGR_STATUS_REG_A, &value); + checkbit = lsm303agr_isbitset(value, LSM303AGR_STATUS_REG_A_ZYXDA); + } + else + { + lsm303agr_readreg8(priv, LSM303AGR_STATUS_REG_M, &value); + checkbit = lsm303agr_isbitset(value, LSM303AGR_STATUS_REG_M_ZYXDA); + } + + /* Average the stored data on each axis * + * http://ozzmaker.com/accelerometer-to-g/ + */ + + lsm303agr_readreg8(priv, LSM303AGR_OUT_X_L_A + registershift, &lox); + lsm303agr_readreg8(priv, LSM303AGR_OUT_X_H_A + registershift, &hix); + raw_x = (int16_t) (((uint16_t) hix << 8U) | (uint16_t) lox); + + lsm303agr_readreg8(priv, LSM303AGR_OUT_Y_L_A + registershift, &loy); + lsm303agr_readreg8(priv, LSM303AGR_OUT_Y_H_A + registershift, &hiy); + raw_y = (int16_t) (((uint16_t) hiy << 8U) | (uint16_t) loy); + + lsm303agr_readreg8(priv, LSM303AGR_OUT_Z_L_A + registershift, &loz); + lsm303agr_readreg8(priv, LSM303AGR_OUT_Z_H_A + registershift, &hiz); + raw_z = (int16_t) (((uint16_t) hiz << 8U) | (uint16_t) loz); + + /* selftest only uses raw values */ + + OUTX_NOST[i] = raw_x; + OUTY_NOST[i] = raw_y; + OUTZ_NOST[i] = raw_z; + } + + /* Enable Selftest */ + + if (mode == 0) + { + lsm303agr_writereg8(priv, LSM303AGR_CTRL_REG4_A, 0x85); + } + else + { + lsm303agr_writereg8(priv, LSM303AGR_CFG_REG_C_M, 0x12); + } + + nxsig_usleep(100000); /* 100ms */ + + checkbit = false; + while (checkbit) + { + if (mode == 0) + { + lsm303agr_readreg8(priv, LSM303AGR_STATUS_REG_A, &value); + checkbit = lsm303agr_isbitset(value, LSM303AGR_STATUS_REG_A_ZYXDA); + } + else + { + lsm303agr_readreg8(priv, LSM303AGR_STATUS_REG_M, &value); + checkbit = lsm303agr_isbitset(value, LSM303AGR_STATUS_REG_M_ZYXDA); + } + } + + nxsig_usleep(100000); /* 100ms */ + + /* Now do all the ST values */ + + lsm303agr_readreg8(priv, LSM303AGR_OUT_X_L_A + registershift, &loxst); + lsm303agr_readreg8(priv, LSM303AGR_OUT_X_H_A + registershift, &hixst); + + lsm303agr_readreg8(priv, LSM303AGR_OUT_Y_L_A + registershift, &loyst); + lsm303agr_readreg8(priv, LSM303AGR_OUT_Y_H_A + registershift, &hiyst); + + lsm303agr_readreg8(priv, LSM303AGR_OUT_Z_L_A + registershift, &lozst); + lsm303agr_readreg8(priv, LSM303AGR_OUT_Z_H_A + registershift, &hizst); + + for (i2 = 0; i2 < samples; i2++) + { + if (mode == 0) + { + lsm303agr_readreg8(priv, LSM303AGR_STATUS_REG_A, &value); + checkbit = lsm303agr_isbitset(value, LSM303AGR_STATUS_REG_A_ZYXDA); + } + else + { + lsm303agr_readreg8(priv, LSM303AGR_STATUS_REG_M, &value); + checkbit = lsm303agr_isbitset(value, LSM303AGR_STATUS_REG_M_ZYXDA); + } + + nxsig_usleep(100000); /* 100ms */ + + lsm303agr_readreg8(priv, LSM303AGR_OUT_X_L_A + registershift, &loxst); + lsm303agr_readreg8(priv, LSM303AGR_OUT_X_H_A + registershift, &hixst); + raw_xst = (int16_t) (((uint16_t) hixst << 8U) | (uint16_t) loxst); + + lsm303agr_readreg8(priv, LSM303AGR_OUT_Y_L_A + registershift, &loyst); + lsm303agr_readreg8(priv, LSM303AGR_OUT_Y_H_A + registershift, &hiyst); + raw_yst = (int16_t) (((uint16_t) hiyst << 8U) | (uint16_t) loyst); + + lsm303agr_readreg8(priv, LSM303AGR_OUT_Z_L_A + registershift, &lozst); + lsm303agr_readreg8(priv, LSM303AGR_OUT_Z_H_A + registershift, &hizst); + raw_zst = (int16_t) (((uint16_t) hizst << 8U) | (uint16_t) lozst); + + /* Selftest only uses raw values */ + + OUTX_ST[i2] = raw_xst; + OUTY_ST[i2] = raw_yst; + OUTZ_ST[i2] = raw_zst; + } + + /* Average stored data on each axis */ + + for (i3 = 0; i3 < samples; i3++) + { + avr_x = avr_x + (int16_t) OUTX_NOST[i3]; + avr_y = avr_y + (int16_t) OUTY_NOST[i3]; + avr_z = avr_z + (int16_t) OUTZ_NOST[i3]; + + avr_xst = avr_xst + (int16_t) OUTX_ST[i3]; + avr_yst = avr_yst + (int16_t) OUTY_ST[i3]; + avr_zst = avr_zst + (int16_t) OUTZ_ST[i3]; + } + + avr_x = (int16_t) avr_x / samples; + avr_y = (int16_t) avr_y / samples; + avr_z = (int16_t) avr_z / samples; + + avr_xst = (int16_t) avr_xst / samples; + avr_yst = (int16_t) avr_yst / samples; + avr_zst = (int16_t) avr_zst / samples; + + min_x = OUTX_NOST[lsm303agr_find_minimum(OUTX_NOST, samples)]; + min_y = OUTY_NOST[lsm303agr_find_minimum(OUTY_NOST, samples)]; + min_z = OUTZ_NOST[lsm303agr_find_minimum(OUTZ_NOST, samples)]; + + max_x = OUTX_NOST[lsm303agr_find_maximum(OUTX_NOST, samples)]; + max_y = OUTY_NOST[lsm303agr_find_maximum(OUTY_NOST, samples)]; + max_z = OUTZ_NOST[lsm303agr_find_maximum(OUTZ_NOST, samples)]; + + min_xst = OUTX_ST[lsm303agr_find_minimum(OUTX_ST, samples)]; + min_yst = OUTY_ST[lsm303agr_find_minimum(OUTY_ST, samples)]; + min_zst = OUTZ_ST[lsm303agr_find_minimum(OUTZ_ST, samples)]; + + max_xst = OUTX_ST[lsm303agr_find_maximum(OUTX_ST, samples)]; + max_yst = OUTY_ST[lsm303agr_find_maximum(OUTY_ST, samples)]; + max_zst = OUTZ_ST[lsm303agr_find_maximum(OUTZ_ST, samples)]; + + sninfo("stdev_x: -%d %d +%d\n", avr_x - min_x, avr_x, max_x - avr_x); + sninfo("stdev_y: -%d %d +%d\n", avr_y - min_y, avr_y, max_y - avr_y); + sninfo("stdev_z: -%d %d +%d\n", avr_z - min_z, avr_z, max_z - avr_z); + + sninfo("stdev_xst: -%d %d +%d\n", avr_xst - min_xst, avr_xst, + max_xst - avr_xst); + sninfo("stdev_yst: -%d %d +%d\n", avr_yst - min_yst, avr_yst, + max_yst - avr_yst); + sninfo("stdev_zst: -%d %d +%d\n", avr_zst - min_zst, avr_zst, + max_zst - avr_zst); + + sninfo("avr_x: %d\n", avr_x); + sninfo("avr_y: %d\n", avr_y); + sninfo("avr_z: %d\n", avr_z); + sninfo("min_x: %d\n", min_x); + sninfo("max_x: %d\n", max_x); + sninfo("min_xst: %d\n", min_xst); + sninfo("max_xst: %d\n", max_xst); + + /* Validation */ + + if ((avr_x >= min_x && avr_x <= max_x) && + (avr_xst >= min_xst && avr_xst <= max_xst)) + { + sninfo("PASSED NOST AND ST FOR X!\n"); + } + else + { + sninfo("FAILED NOST AND ST FOR X!\n"); + sninfo("[ %d - %d ]", min_x, min_xst); + sninfo(" <=\n "); + sninfo("[ %d - %d ]", avr_x, avr_xst); + sninfo(" <=\n "); + sninfo("[ %d - %d ]", max_x, max_xst); + sninfo("\n"); + } + + if ((avr_y >= min_y && avr_y <= max_y) && + (avr_yst >= min_yst && avr_yst <= max_yst)) + { + sninfo("PASSED NOST AND ST FOR Y!\n"); + } + else + { + sninfo("FAILED NOST AND ST FOR Y!\n"); + sninfo("[ %d - %d ]", min_y, min_yst); + sninfo(" <=\n "); + sninfo("[ %d - %d ]", avr_y, avr_yst); + sninfo(" <=\n "); + sninfo("[ %d - %d ]", max_y, max_yst); + sninfo("\n"); + } + + if ((avr_z >= min_z && avr_z <= max_z) && + (avr_zst >= min_zst && avr_zst <= max_zst)) + { + sninfo("PASSED NOST AND ST FOR Z!\n"); + } + else + { + sninfo("FAILED NOST AND ST FOR Z!\n"); + sninfo("[ %d - %d ]", min_z, min_zst); + sninfo(" <=\n "); + sninfo("[ %d - %d ]", avr_z, avr_zst); + sninfo(" <=\n "); + sninfo("[ %d - %d ]", max_z, max_zst); + sninfo("\n"); + } + + sleep(2); + + /* Disable test */ + + switch (mode) + { + case 0: + { + sninfo("SELFTEST ACCELERO DISABLED\n"); + lsm303agr_writereg8(priv, LSM303AGR_CTRL_REG1_A, 0x00); + lsm303agr_writereg8(priv, LSM303AGR_CTRL_REG4_A, 0x01); + } + break; + + case 1: + { + sninfo("SELFTEST MAGNETO DISABLED\n"); + lsm303agr_writereg8(priv, LSM303AGR_CFG_REG_C_M, 0x10); + lsm303agr_writereg8(priv, LSM303AGR_CFG_REG_A_M, 0x83); + } + break; + + default: + break; + } + + return OK; +} + +/**************************************************************************** + * Name: lsm303agr_sensor_read + * + * Description: + * Read the sensor. + * A sensor in a steady state on a horizontal surface will + * measure 0 g on both the X-axis and Y-axis, whereas the Z-axis will + * measure 1 g. (page 30 datasheet). The X- and Y-axis have an offset + * of 40 mg/LSB + * + ****************************************************************************/ + +static int lsm303agr_sensor_read(FAR struct lsm303agr_dev_s *priv, + FAR struct lsm303agr_sensor_data_s *sensor_data) +{ + + int16_t lo = 0; + int16_t lox = 0; + int16_t loxg = 0; + int16_t hi = 0; + int16_t hix = 0; + int16_t hixg = 0; + int16_t loy = 0; + int16_t loyg = 0; + int16_t hiy = 0; + int16_t hiyg = 0; + int16_t loz = 0; + int16_t lozg = 0; + int16_t hiz = 0; + int16_t hizg = 0; + + int16_t templ = 0; + int16_t temph = 0; + + uint8_t status1 = 0; + uint8_t status2 = 0; + uint8_t status3 = 0; + uint8_t status4 = 0; + uint8_t value = 0; + + uint8_t tstamp0 = 0; + uint8_t tstamp1 = 0; + uint8_t tstamp2 = 0; + uint8_t tstamp3 = 0; + + uint32_t ts = 0; + + int16_t x_val = 0; + int16_t y_val = 0; + int16_t z_val = 0; + int16_t tempi = 0; + int16_t temp_val = 0; + + int16_t x_valg = 0; + int16_t y_valg = 0; + int16_t z_valg = 0; + + /* Magneto */ + + lsm303agr_readreg8(priv, LSM303AGR_OUTX_L_REG_M, &loxg); + lsm303agr_readreg8(priv, LSM303AGR_OUTX_H_REG_M, &hixg); + + lsm303agr_readreg8(priv, LSM303AGR_OUTY_L_REG_M, &loyg); + lsm303agr_readreg8(priv, LSM303AGR_OUTY_H_REG_M, &hiyg); + + lsm303agr_readreg8(priv, LSM303AGR_OUTZ_L_REG_M, &lozg); + lsm303agr_readreg8(priv, LSM303AGR_OUTZ_H_REG_M, &hizg); + + /* Temperature */ + + lsm303agr_readreg8(priv, LSM303AGR_OUT_TEMP_L_A, &templ); + lsm303agr_readreg8(priv, LSM303AGR_OUT_TEMP_H_A, &temph); + + tempi = (int16_t) ((((int16_t) temph << 8) | (int16_t) templ)); + + temp_val = (tempi / 256) + 25; /* TSen 256 LSB/°C */ + + sninfo("Data 16-bit TEMP--->: %d Celsius\n", temp_val); + + sensor_data->temperature = temp_val; + + x_valg = (int16_t) (((hixg) << 8) | loxg); + y_valg = (int16_t) (((hiyg) << 8) | loyg); + z_valg = (int16_t) (((hizg) << 8) | lozg); + + sninfo("Data 16-bit M_X--->: %d mguass\n", (short)(x_valg * magnetofactor)); + sninfo("Data 16-bit M_Y--->: %d mguass\n", (short)(y_valg * magnetofactor)); + sninfo("Data 16-bit M_Z--->: %d mguass\n", (short)(z_valg * magnetofactor)); + + sensor_data->m_x_data = x_valg; + sensor_data->m_y_data = y_valg; + sensor_data->m_z_data = z_valg; + + return OK; +} + +/**************************************************************************** + * Name: lsm303agr_open + * + * Description: + * This method is called when the device is opened. + * + ****************************************************************************/ + +static int lsm303agr_open(FAR struct file *filep) +{ + sninfo("Device LSM303AGR opened!!\r\n"); + return OK; +} + +/**************************************************************************** + * Name: lsm303agr_close + * + * Description: + * This method is called when the device is closed. + * + ****************************************************************************/ + +static int lsm303agr_close(FAR struct file *filep) +{ + return OK; +} + +/**************************************************************************** + * Name: lsm303agr_read + * + * Description: + * The standard read method. + * + ****************************************************************************/ + +static ssize_t lsm303agr_read(FAR struct file *filep, + FAR char *buffer, size_t buflen) +{ + FAR struct inode *inode; + FAR struct lsm303agr_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; + uint32_t merge = 0; + + /* Sanity check */ + + DEBUGASSERT(filep != NULL); + inode = filep->f_inode; + + DEBUGASSERT(inode != NULL); + priv = (FAR struct lsm303agr_dev_s *)inode->i_private; + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv->datareg == LSM303AGR_OUTX_L_A_SHIFT || + priv->datareg == LSM303AGR_OUTX_L_M_SHIFT); + 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 = lsm303agr_readreg8(priv, regaddr, &lo); + if (ret < 0) + { + snerr("ERROR: lsm303agr_readreg8 failed: %d\n", ret); + return (ssize_t) ret; + } + + regaddr++; + + /* Read the high byte */ + + ret = lsm303agr_readreg8(priv, regaddr, &hi); + if (ret < 0) + { + snerr("ERROR: lsm303agr_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; + + /* Collect entropy */ + + merge += data ^ (merge >> 16); + + /* 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); + } + } + } + + /* Feed sensor data to entropy pool */ + + add_sensor_randomness(merge); + + return nsamples * samplesize; +} + +/**************************************************************************** + * Name: lsm303agr_write + * + * Description: + * A dummy write method. + * + ****************************************************************************/ + +static ssize_t lsm303agr_write(FAR struct file *filep, + FAR const char *buffer, size_t buflen) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: lsm303agr_ioctl + * + * Description: + * The standard ioctl method. + * + ****************************************************************************/ + +static int lsm303agr_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode; + FAR struct lsm303agr_dev_s *priv; + int ret; + + /* Sanity check */ + + DEBUGASSERT(filep != NULL); + inode = filep->f_inode; + + DEBUGASSERT(inode != NULL); + priv = (FAR struct lsm303agr_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; + + case SNIOC_LSM303AGRSENSORREAD: + ret = priv->ops->sensor_read(priv, (FAR struct lsm303agr_sensor_data_s *) arg); + break; + + case SNIOC_START_SELFTEST: + ret = priv->ops->selftest(priv, (uint32_t) arg); + break; + + /* Unrecognized commands */ + + default: + snerr("ERROR: Unrecognized cmd: %d arg: %lu\n", cmd, arg); + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: lsm303agr_register + * + * Description: + * Register the LSM303AGR accelerometer, gyroscope device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register, e.g., "/dev/lsm303agr0", + * "/dev/gyro0" or "/dev/mag0". + * i2c - An I2C driver instance. + * addr - The I2C address of the LSM303AGR 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 lsm303agr_register(FAR const char *devpath, + FAR struct i2c_master_s *i2c, + uint8_t addr, + FAR const struct lsm303agr_ops_s *ops, + uint8_t datareg, + struct lsm303agr_sensor_data_s sensor_data) +{ + FAR struct lsm303agr_dev_s *priv; + int ret; + + /* Sanity check */ + + DEBUGASSERT(devpath != NULL); + DEBUGASSERT(i2c != NULL); + DEBUGASSERT(datareg == LSM303AGR_OUTX_L_A_SHIFT || + datareg == LSM303AGR_OUTX_L_M_SHIFT); + + /* Initialize the device's structure */ + + priv = (FAR struct lsm303agr_dev_s *)kmm_malloc(sizeof(*priv)); + if (priv == NULL) + { + snerr("ERROR: Failed to allocate instance\n"); + return -ENOMEM; + } + + priv->i2c = i2c; + priv->addr = addr; + priv->ops = ops; + priv->datareg = datareg; + priv->sensor_data = sensor_data; + + /* Configure the device */ + + ret = priv->ops->config(priv); + if (ret < 0) + { + snerr("ERROR: 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) + { + snerr("ERROR: Failed to register driver: %d\n", ret); + kmm_free(priv); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lsm303agr_sensor_register + * + * Description: + * Register the LSM303AGR accelerometer character device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register, e.g., "/dev/lsm303agr0". + * i2c - An I2C driver instance. + * addr - The I2C address of the LSM303AGR accelerometer. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ +int lsm303agr_sensor_register(FAR const char *devpath, + FAR struct i2c_master_s *i2c, uint8_t addr) +{ + struct lsm303agr_sensor_data_s sensor_data; + + DEBUGASSERT(addr == LSM303AGRACCELERO_ADDR || addr == LSM303AGRMAGNETO_ADDR); + + sninfo("Trying to register accel\n"); + + return lsm303agr_register(devpath, i2c, addr, &g_lsm303agrsensor_ops, + LSM303AGR_OUTX_L_A_SHIFT, sensor_data); +} + +#endif /* CONFIG_I2C && CONFIG_SENSORS_LSM303AGR */ diff --git a/drivers/sensors/lsm6dsl.c b/drivers/sensors/lsm6dsl.c new file mode 100644 index 00000000000..e235ea64378 --- /dev/null +++ b/drivers/sensors/lsm6dsl.c @@ -0,0 +1,1345 @@ +/**************************************************************************** + * drivers/sensors/lsm6dsl.c + * + * Copyright (C) 2018 Inc. All rights reserved. + * Author: Ben vd Veen + * Alias: DisruptiveNL + * + * Based on: + * + * Copyright (C) 2016 Omni Hoverboards Inc. All rights reserved. + * Author: Paul Alexander Patience + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 +#include + +#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_LSM6DSL) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_LSM6DSL_I2C_FREQUENCY +# define CONFIG_LSM6DSL_I2C_FREQUENCY 400000 +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* I2C Helpers */ + +static int lsm6dsl_readreg8(FAR struct lsm6dsl_dev_s *priv, + uint8_t regaddr, FAR uint8_t * regval); +static int lsm6dsl_writereg8(FAR struct lsm6dsl_dev_s *priv, + uint8_t regaddr, uint8_t regval); +static int lsm6dsl_modifyreg8(FAR struct lsm6dsl_dev_s *priv, + uint8_t regaddr, + uint8_t clearbits, uint8_t setbits); + +/* Other Helpers */ + +static int lsm6dsl_find_minimum(int16_t a[], int n); +static int lsm6dsl_find_maximum(int16_t a[], int n); +static bool lsm6dsl_isbitset(int8_t b, int8_t n); + +/* Accelerometer Operations */ + +static int lsm6dsl_sensor_config(FAR struct lsm6dsl_dev_s *priv); +static int lsm6dsl_sensor_start(FAR struct lsm6dsl_dev_s *priv); +static int lsm6dsl_sensor_stop(FAR struct lsm6dsl_dev_s *priv); +static int lsm6dsl_sensor_read(FAR struct lsm6dsl_dev_s *priv, + FAR struct lsm6dsl_sensor_data_s *sensor_data); +static int lsm6dsl_selftest(FAR struct lsm6dsl_dev_s *priv, uint32_t mode); + +/* Character Driver Methods */ + +static int lsm6dsl_open(FAR struct file *filep); +static int lsm6dsl_close(FAR struct file *filep); +static ssize_t lsm6dsl_read(FAR struct file *filep, + FAR char *buffer, size_t buflen); +static ssize_t lsm6dsl_write(FAR struct file *filep, + FAR const char *buffer, size_t buflen); +static int lsm6dsl_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); + +/* Common Register Function */ + +static int lsm6dsl_register(FAR const char *devpath, + FAR struct i2c_master_s *i2c, + uint8_t addr, + FAR const struct lsm6dsl_ops_s *ops, + uint8_t datareg, + struct lsm6dsl_sensor_data_s sensor_data); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static double accelerofactor = 0; +static double gyrofactor = 0; + +static const struct file_operations g_fops = +{ + lsm6dsl_open, + lsm6dsl_close, + lsm6dsl_read, + lsm6dsl_write, + NULL, + lsm6dsl_ioctl +#ifndef CONFIG_DISABLE_POLL + , NULL +#endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + , NULL +# endif +}; + +static const struct lsm6dsl_ops_s g_LSM6DSLsensor_ops = +{ + lsm6dsl_sensor_config, + lsm6dsl_sensor_start, + lsm6dsl_sensor_stop, + lsm6dsl_sensor_read, + lsm6dsl_selftest +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lsm6dsl_resetsensor + * + * Description: + * Reset sensor values + * + ****************************************************************************/ + +static void lsm6dsl_resetsensor(FAR struct lsm6dsl_dev_s *priv) +{ + priv->sensor_data.x_data = 0; + priv->sensor_data.y_data = 0; + priv->sensor_data.z_data = 0; + priv->sensor_data.temperature = 0; + priv->sensor_data.g_x_data = 0; + priv->sensor_data.g_y_data = 0; + priv->sensor_data.g_z_data = 0; + priv->sensor_data.timestamp = 0; +} + +/**************************************************************************** + * Name: lsm6dsl_readreg8 + * + * Description: + * Read from an 8-bit register. + * + ****************************************************************************/ + +static int lsm6dsl_readreg8(FAR struct lsm6dsl_dev_s *priv, + uint8_t regaddr, FAR uint8_t * regval) +{ + struct i2c_config_s config; + int ret; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(regval != NULL); + + /* Set up the I2C configuration */ + + config.frequency = CONFIG_LSM6DSL_I2C_FREQUENCY; + config.address = priv->addr; + config.addrlen = 7; + + /* Write the register address */ + + ret = i2c_write(priv->i2c, &config, ®addr, sizeof(regaddr)); + if (ret < 0) + { + snerr("ERROR: i2c_write failed: %d\n", ret); + return ret; + } + + /* Restart and read 8 bits from the register */ + + ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval)); + if (ret < 0) + { + snerr("ERROR: i2c_read failed: %d\n", ret); + return ret; + } + + sninfo("addr: %02x value: %02x\n", regaddr, *regval); + return OK; +} + +/**************************************************************************** + * Name: lsm6dsl_writereg8 + * + * Description: + * Write to an 8-bit register. + * + ****************************************************************************/ + +static int lsm6dsl_writereg8(FAR struct lsm6dsl_dev_s *priv, + uint8_t regaddr, uint8_t regval) +{ + struct i2c_config_s config; + uint8_t buffer[2]; + int ret; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + /* Set up a 2-byte message to send */ + + buffer[0] = regaddr; + buffer[1] = regval; + + /* Set up the I2C configuration */ + + config.frequency = CONFIG_LSM6DSL_I2C_FREQUENCY; + config.address = priv->addr; + config.addrlen = 7; + + /* Write the register address followed by the data (no RESTART) */ + + ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer)); + if (ret < 0) + { + snerr("ERROR: i2c_write failed: %d\n", ret); + return ret; + } + + sninfo("addr: %02x value: %02x\n", regaddr, regval); + return OK; +} + +/**************************************************************************** + * Name: lsm6dsl_modifyreg8 + * + * Description: + * Modify an 8-bit register. + * + ****************************************************************************/ + +static int lsm6dsl_modifyreg8(FAR struct lsm6dsl_dev_s *priv, + uint8_t regaddr, + uint8_t clearbits, uint8_t setbits) +{ + int ret; + uint8_t regval; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + ret = lsm6dsl_readreg8(priv, regaddr, ®val); + if (ret < 0) + { + snerr("ERROR: lsm6dsl_readreg8 failed: %d\n", ret); + return ret; + } + + regval &= ~clearbits; + regval |= setbits; + + ret = lsm6dsl_writereg8(priv, regaddr, regval); + if (ret < 0) + { + snerr("ERROR: lsm6dsl_writereg8 failed: %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: lsm6dsl_find_minimum + * + * Description: + * Find the minimum value in an array of numbers. + * + ****************************************************************************/ + +static int lsm6dsl_find_minimum(int16_t a[], int n) +{ + int c; + int min = a[0]; + int index = 0; + + for (c = 1; c < n; c++) + { + if (a[c] < min) + { + index = c; + min = a[c]; + } + } + + return index; +} + +/**************************************************************************** + * Name: lsm6dsl_find_maximum + * + * Description: + * Find the maximum value in an array of numbers. + * + ****************************************************************************/ + +static int lsm6dsl_find_maximum(int16_t am[], int n) +{ + int c; + int max = am[0]; + int index = 0; + + for (c = 1; c < n; c++) + { + if (am[c] > max) + { + index = c; + max = am[c]; + } + } + + return index; +} + +/**************************************************************************** + * Name: lsm6dsl_sensor_config + * + * Description: + * Configure the accelerometer and gyroscope. + * + ****************************************************************************/ + +static int lsm6dsl_sensor_config(FAR struct lsm6dsl_dev_s *priv) +{ + int ret; + uint8_t regval; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + /* Get the device identification */ + + ret = lsm6dsl_readreg8(priv, LSM6DSL_WHO_AM_I, ®val); + if (ret < 0) + { + snerr("ERROR: lsm6dsl_readreg8 failed: %d\n", ret); + return ret; + } + + if (regval != LSM6DSL_WHO_AM_I_VALUE) + { + snerr("ERROR: Invalid device identification %02x\n", regval); + return -ENODEV; + } + + return OK; +} + +/**************************************************************************** + * Name: lsm6dsl_isbitset + * + * Description: + * Check if bit it set from mask, not bit number. + * + ****************************************************************************/ + +static bool lsm6dsl_isbitset(int8_t b, int8_t m) +{ + if ((b & m) != 0) + { + return true; + } + + return false; +} + +/**************************************************************************** + * Name: lsm6dsl_sensor_start + * + * Description: + * Start the accelerometer. + * + ****************************************************************************/ + +static int lsm6dsl_sensor_start(FAR struct lsm6dsl_dev_s *priv) +{ + uint8_t value; + + /* Enable the accelerometer */ + + /* Reset values */ + + lsm6dsl_resetsensor(priv); + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + sninfo("Starting...."); + + /* Accelerometer config registers Turn on the accelerometer: 833Hz, +- 16g */ + + lsm6dsl_writereg8(priv, LSM6DSL_CTRL1_XL, 0x74); + accelerofactor = 0.488; + + /* Gyro config registers Turn on the gyro: FS=2000dps, ODR=833Hz Not using + * modifyreg with empty value!!!! Then read value first!!! + */ + + lsm6dsl_writereg8(priv, LSM6DSL_CTRL2_G, 0x7C); + gyrofactor = 70; + + lsm6dsl_writereg8(priv, LSM6DSL_CTRL6_C, 0x00); + + /* Timestamp registers */ + + lsm6dsl_writereg8(priv, LSM6DSL_CTRL10_C, 0x20); + + return OK; +} + +/**************************************************************************** + * Name: lsm6dsl_sensor_stop + * + * Description: + * Stop the accelerometer. + * + ****************************************************************************/ + +static int lsm6dsl_sensor_stop(FAR struct lsm6dsl_dev_s *priv) +{ + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + /* Stop accelerometer */ + + lsm6dsl_modifyreg8(priv, + LSM6DSL_CTRL1_XL_ODR_XL_SHIFT, + LSM6DSL_CTRL1_XL_ODR_XL_MASK, + LSM6DSL_CTRL1_XL_ODR_XL_POWER_DOWN); + + /* Stop gyro */ + + lsm6dsl_modifyreg8(priv, + LSM6DSL_CTRL2_G_ODR_G_SHIFT, + LSM6DSL_CTRL2_G_ODR_G_MASK, + LSM6DSL_CTRL2_G_ODR_G_POWER_DOWN); + + return OK; +} + +/**************************************************************************** + * Name: lsm6dsl_selftest + * + * Description: + * Selftesting the sensor. + * Mode 0 = selftest accelerometer and mode 1 = selftest gyro + * + ****************************************************************************/ + +static int lsm6dsl_selftest(FAR struct lsm6dsl_dev_s *priv, uint32_t mode) +{ + + int samples = 5; + int i; + int i2; + int i3; + + uint8_t value = 0; + int8_t lox = 0; + int8_t loxst = 0; + int8_t hix = 0; + int8_t hixst = 0; + int8_t loy = 0; + int8_t loyst = 0; + int8_t hiy = 0; + int8_t hiyst = 0; + int8_t loz = 0; + int8_t lozst = 0; + int8_t hiz = 0; + int8_t hizst = 0; + + int16_t OUTX_NOST[samples]; + int16_t OUTY_NOST[samples]; + int16_t OUTZ_NOST[samples]; + int16_t OUTX_ST[samples]; + int16_t OUTY_ST[samples]; + int16_t OUTZ_ST[samples]; + + int16_t AVR_OUTX_NOST[samples]; + int16_t AVR_OUTY_NOST[samples]; + int16_t AVR_OUTZ_NOST[samples]; + int16_t AVR_OUTX_ST[samples]; + int16_t AVR_OUTY_ST[samples]; + int16_t AVR_OUTZ_ST[samples]; + + int16_t avr_x = 0; + int16_t avr_y = 0; + int16_t avr_z = 0; + int16_t avr_xst = 0; + int16_t avr_yst = 0; + int16_t avr_zst = 0; + + int16_t min_x = 0; + int16_t min_y = 0; + int16_t min_z = 0; + int16_t max_x = 0; + int16_t max_y = 0; + int16_t max_z = 0; + + int16_t min_xst = 0; + int16_t min_yst = 0; + int16_t min_zst = 0; + int16_t max_xst = 0; + int16_t max_yst = 0; + int16_t max_zst = 0; + + int16_t ltemp = 0; + int16_t htemp = 0; + int16_t tempi = 0; + int16_t temp = 0; + + int16_t raw_x = 0; + int16_t raw_y = 0; + int16_t raw_z = 0; + + int16_t raw_xst = 0; + int16_t raw_yst = 0; + int16_t raw_zst = 0; + + /* mode = 0 then add hex 0x06 to OUT registers */ + + int8_t registershift; + + /* Keep the device still during the self-test procedure. Setting registers + * Power up, wait for 100ms for stable output. + */ + + if (mode == 0) + { + registershift = 0x06; + + /* Accelero ; power down gyro CTRL2_G 4g factor: 1000 for mg -> g value + * is in mg/LSB FS=4g,52Hz 4000mg=65535 + */ + + lsm6dsl_writereg8(priv, LSM6DSL_CTRL1_XL, 0x38); + lsm6dsl_writereg8(priv, LSM6DSL_CTRL2_G, 0x00); + lsm6dsl_writereg8(priv, LSM6DSL_CTRL3_C, 0x44); + accelerofactor = (0.122 / 1000); + } + else + { + registershift = 0x00; + + /* Gyro; power down accelero CTRL1_XL FS=2000dps,208Hz 2000dps=65535 */ + + lsm6dsl_writereg8(priv, LSM6DSL_CTRL1_XL, 0x00); + lsm6dsl_writereg8(priv, LSM6DSL_CTRL2_G, 0x5C); + lsm6dsl_writereg8(priv, LSM6DSL_CTRL3_C, 0x44); + gyrofactor = (70 / 1000); /* 2000dps */ + } + + lsm6dsl_writereg8(priv, LSM6DSL_CTRL4_C, 0x00); + lsm6dsl_writereg8(priv, LSM6DSL_CTRL5_C, 0x00); + lsm6dsl_writereg8(priv, LSM6DSL_CTRL6_C, 0x00); + lsm6dsl_writereg8(priv, LSM6DSL_CTRL7_G, 0x00); + lsm6dsl_writereg8(priv, LSM6DSL_CTRL8_XL, 0x00); + lsm6dsl_writereg8(priv, LSM6DSL_CTRL9_XL, 0x00); + lsm6dsl_writereg8(priv, LSM6DSL_CTRL10_C, 0x00); + + nxsig_usleep(100000); /* 100ms */ + + /* Read the output registers after checking XLDA bit 5 times */ + + bool checkbit = false; + + /* Wait until first sample and data is available */ + + while (checkbit) + { + lsm6dsl_readreg8(priv, LSM6DSL_STATUS_REG, &value); + if (mode == 0) + { + checkbit = lsm6dsl_isbitset(value, LSM6DSL_STATUS_REG_XLDA); + } + else + { + checkbit = lsm6dsl_isbitset(value, LSM6DSL_STATUS_REG_GDA); + } + } + + nxsig_usleep(100000); /* 100ms */ + + /* Read OUT registers Gyro is starting at 22h and Accelero at 28h */ + + lsm6dsl_readreg8(priv, LSM6DSL_OUTX_L_G + registershift, &lox); + lsm6dsl_readreg8(priv, LSM6DSL_OUTX_H_G + registershift, &hix); + + lsm6dsl_readreg8(priv, LSM6DSL_OUTY_L_G + registershift, &loy); + lsm6dsl_readreg8(priv, LSM6DSL_OUTY_H_G + registershift, &hiy); + + lsm6dsl_readreg8(priv, LSM6DSL_OUTZ_L_G + registershift, &loz); + lsm6dsl_readreg8(priv, LSM6DSL_OUTZ_H_G + registershift, &hiz); + + /* check XLDA 5 times */ + + for (i = 0; i < samples; i++) + { + lsm6dsl_readreg8(priv, LSM6DSL_STATUS_REG, &value); + if (mode == 0) + { + checkbit = lsm6dsl_isbitset(value, LSM6DSL_STATUS_REG_XLDA); + } + else + { + checkbit = lsm6dsl_isbitset(value, LSM6DSL_STATUS_REG_GDA); + } + + /* Average the stored data on each axis + * http://ozzmaker.com/accelerometer-to-g/ + */ + + lsm6dsl_readreg8(priv, LSM6DSL_OUTX_L_G + registershift, &lox); + lsm6dsl_readreg8(priv, LSM6DSL_OUTX_H_G + registershift, &hix); + raw_x = (int16_t) (((uint16_t) hix << 8U) | (uint16_t) lox); + + lsm6dsl_readreg8(priv, LSM6DSL_OUTY_L_G + registershift, &loy); + lsm6dsl_readreg8(priv, LSM6DSL_OUTY_H_G + registershift, &hiy); + raw_y = (int16_t) (((uint16_t) hiy << 8U) | (uint16_t) loy); + + lsm6dsl_readreg8(priv, LSM6DSL_OUTZ_L_G + registershift, &loz); + lsm6dsl_readreg8(priv, LSM6DSL_OUTZ_H_G + registershift, &hiz); + raw_z = (int16_t) (((uint16_t) hiz << 8U) | (uint16_t) loz); + + /* Selftest only uses raw values */ + + OUTX_NOST[i] = raw_x; + OUTY_NOST[i] = raw_y; + OUTZ_NOST[i] = raw_z; + } + + /* Enable Selftest */ + + if (mode == 0) + { + lsm6dsl_writereg8(priv, LSM6DSL_CTRL5_C, 0x01); + } + else + { + lsm6dsl_writereg8(priv, LSM6DSL_CTRL5_C, 0x04); + } + + nxsig_usleep(100000); /* 100ms */ + + checkbit = false; + while (checkbit) /* wait until first sample and data is + * available */ + { + lsm6dsl_readreg8(priv, LSM6DSL_STATUS_REG, &value); + if (mode == 0) + { + checkbit = lsm6dsl_isbitset(value, LSM6DSL_STATUS_REG_XLDA); + } + else + { + checkbit = lsm6dsl_isbitset(value, LSM6DSL_STATUS_REG_GDA); + } + } + + nxsig_usleep(100000); /* 100ms */ + + /* Now do all the ST values */ + + lsm6dsl_readreg8(priv, LSM6DSL_OUTX_L_G + registershift, &loxst); + lsm6dsl_readreg8(priv, LSM6DSL_OUTX_H_G + registershift, &hixst); + + lsm6dsl_readreg8(priv, LSM6DSL_OUTY_L_G + registershift, &loyst); + lsm6dsl_readreg8(priv, LSM6DSL_OUTY_H_G + registershift, &hiyst); + + lsm6dsl_readreg8(priv, LSM6DSL_OUTZ_L_G + registershift, &lozst); + lsm6dsl_readreg8(priv, LSM6DSL_OUTZ_H_G + registershift, &hizst); + + for (i2 = 0; i2 < samples; i2++) + { + lsm6dsl_readreg8(priv, LSM6DSL_STATUS_REG, &value); + if (mode == 0) + { + checkbit = lsm6dsl_isbitset(value, LSM6DSL_STATUS_REG_XLDA); + } + else + { + checkbit = lsm6dsl_isbitset(value, LSM6DSL_STATUS_REG_GDA); + } + + nxsig_usleep(100000); /* 100ms */ + + lsm6dsl_readreg8(priv, LSM6DSL_OUTX_L_G + registershift, &loxst); + lsm6dsl_readreg8(priv, LSM6DSL_OUTX_H_G + registershift, &hixst); + raw_xst = (int16_t) (((uint16_t) hixst << 8U) | (uint16_t) loxst); + + lsm6dsl_readreg8(priv, LSM6DSL_OUTY_L_G + registershift, &loyst); + lsm6dsl_readreg8(priv, LSM6DSL_OUTY_H_G + registershift, &hiyst); + raw_yst = (int16_t) (((uint16_t) hiyst << 8U) | (uint16_t) loyst); + + lsm6dsl_readreg8(priv, LSM6DSL_OUTZ_L_G + registershift, &lozst); + lsm6dsl_readreg8(priv, LSM6DSL_OUTZ_H_G + registershift, &hizst); + raw_zst = (int16_t) (((uint16_t) hizst << 8U) | (uint16_t) lozst); + + /* Selftest only uses raw values */ + + OUTX_ST[i2] = raw_xst; + OUTY_ST[i2] = raw_yst; + OUTZ_ST[i2] = raw_zst; + } + + /* Average stored data on each axis */ + + for (i3 = 0; i3 < samples; i3++) + { + avr_x = avr_x + (int16_t) OUTX_NOST[i3]; + avr_y = avr_y + (int16_t) OUTY_NOST[i3]; + avr_z = avr_z + (int16_t) OUTZ_NOST[i3]; + + avr_xst = avr_xst + (int16_t) OUTX_ST[i3]; + avr_yst = avr_yst + (int16_t) OUTY_ST[i3]; + avr_zst = avr_zst + (int16_t) OUTZ_ST[i3]; + } + + avr_x = (int16_t) avr_x / samples; + avr_y = (int16_t) avr_y / samples; + avr_z = (int16_t) avr_z / samples; + + avr_xst = (int16_t) avr_xst / samples; + avr_yst = (int16_t) avr_yst / samples; + avr_zst = (int16_t) avr_zst / samples; + + min_x = OUTX_NOST[lsm6dsl_find_minimum(OUTX_NOST, samples)]; + min_y = OUTY_NOST[lsm6dsl_find_minimum(OUTY_NOST, samples)]; + min_z = OUTZ_NOST[lsm6dsl_find_minimum(OUTZ_NOST, samples)]; + + max_x = OUTX_NOST[lsm6dsl_find_maximum(OUTX_NOST, samples)]; + max_y = OUTY_NOST[lsm6dsl_find_maximum(OUTY_NOST, samples)]; + max_z = OUTZ_NOST[lsm6dsl_find_maximum(OUTZ_NOST, samples)]; + + min_xst = OUTX_ST[lsm6dsl_find_minimum(OUTX_ST, samples)]; + min_yst = OUTY_ST[lsm6dsl_find_minimum(OUTY_ST, samples)]; + min_zst = OUTZ_ST[lsm6dsl_find_minimum(OUTZ_ST, samples)]; + + max_xst = OUTX_ST[lsm6dsl_find_maximum(OUTX_ST, samples)]; + max_yst = OUTY_ST[lsm6dsl_find_maximum(OUTY_ST, samples)]; + max_zst = OUTZ_ST[lsm6dsl_find_maximum(OUTZ_ST, samples)]; + + sninfo("stdev_x: -%d %d +%d\n", avr_x - min_x, avr_x, max_x - avr_x); + sninfo("stdev_y: -%d %d +%d\n", avr_y - min_y, avr_y, max_y - avr_y); + sninfo("stdev_z: -%d %d +%d\n", avr_z - min_z, avr_z, max_z - avr_z); + + sninfo("stdev_xst: -%d %d +%d\n", avr_xst - min_xst, avr_xst, + max_xst - avr_xst); + sninfo("stdev_yst: -%d %d +%d\n", avr_yst - min_yst, avr_yst, + max_yst - avr_yst); + sninfo("stdev_zst: -%d %d +%d\n", avr_zst - min_zst, avr_zst, + max_zst - avr_zst); + + sninfo("avr_x: %d\n", avr_x); + sninfo("avr_y: %d\n", avr_y); + sninfo("avr_z: %d\n", avr_z); + sninfo("min_x: %d\n", min_x); + sninfo("max_x: %d\n", max_x); + sninfo("min_xst: %d\n", min_xst); + sninfo("max_xst: %d\n", max_xst); + + /* Validation Question is placed at ST FAE because the equation in the + * datasheet is doubtful. + */ + + if ((avr_x >= min_x && avr_x <= max_x) && + (avr_xst >= min_xst && avr_xst <= max_xst)) + { + sninfo("PASSED NOST AND ST FOR X!\n"); + } + else + { + sninfo("FAILED NOST AND ST FOR X!\n"); + sninfo("[ %d - %d ]", min_x, min_xst); + sninfo(" <=\n "); + sninfo("[ %d - %d ]", avr_x, avr_xst); + sninfo(" <=\n "); + sninfo("[ %d - %d ]", max_x, max_xst); + sninfo("\n"); + } + + if ((avr_y >= min_y && avr_y <= max_y) && + (avr_yst >= min_yst && avr_yst <= max_yst)) + { + sninfo("PASSED NOST AND ST FOR Y!\n"); + } + else + { + sninfo("FAILED NOST AND ST FOR Y!\n"); + sninfo("[ %d - %d ]", min_y, min_yst); + sninfo(" <=\n "); + sninfo("[ %d - %d ]", avr_y, avr_yst); + sninfo(" <=\n "); + sninfo("[ %d - %d ]", max_y, max_yst); + sninfo("\n"); + } + + if ((avr_z >= min_z && avr_z <= max_z) && + (avr_zst >= min_zst && avr_zst <= max_zst)) + { + sninfo("PASSED NOST AND ST FOR Z!\n"); + } + else + { + sninfo("FAILED NOST AND ST FOR Z!\n"); + sninfo("[ %d - %d ]", min_z, min_zst); + sninfo(" <=\n "); + sninfo("[ %d - %d ]", avr_z, avr_zst); + sninfo(" <=\n "); + sninfo("[ %d - %d ]", max_z, max_zst); + sninfo("\n"); + } + + sleep(2); + + /* Disable test */ + + switch (mode) + { + case 0: + { + sninfo("SELFTEST ACCELERO DISABLED\n"); + lsm6dsl_writereg8(priv, LSM6DSL_CTRL1_XL, 0x00); + lsm6dsl_writereg8(priv, LSM6DSL_CTRL5_C, 0x00); + } + break; + case 1: + { + sninfo("SELFTEST GYRO DISABLED\n"); + lsm6dsl_writereg8(priv, LSM6DSL_CTRL2_G, 0x00); + lsm6dsl_writereg8(priv, LSM6DSL_CTRL5_C, 0x00); + } + break; + + default: + break; + } + + return OK; +} + +/**************************************************************************** + * Name: lsm6dsl_sensor_read + * + * Description: + * Read the sensor. + * A sensor in a steady state on a horizontal surface will + * measure 0 g on both the X-axis and Y-axis, whereas the Z-axis will + * measure 1 g. (page 30 datasheet). The X- and Y-axis have an offset + * of 40 mg/LSB + * + ****************************************************************************/ + +static int lsm6dsl_sensor_read(FAR struct lsm6dsl_dev_s *priv, + FAR struct lsm6dsl_sensor_data_s *sensor_data) +{ + + int16_t lo = 0; + int16_t lox = 0; + int16_t loxg = 0; + int16_t hi = 0; + int16_t hix = 0; + int16_t hixg = 0; + int16_t loy = 0; + int16_t loyg = 0; + int16_t hiy = 0; + int16_t hiyg = 0; + int16_t loz = 0; + int16_t lozg = 0; + int16_t hiz = 0; + int16_t hizg = 0; + + int16_t templ = 0; + int16_t temph = 0; + + uint8_t status1 = 0; + uint8_t status2 = 0; + uint8_t status3 = 0; + uint8_t status4 = 0; + uint8_t value = 0; + + uint8_t tstamp0 = 0; + uint8_t tstamp1 = 0; + uint8_t tstamp2 = 0; + uint8_t tstamp3 = 0; + uint32_t ts = 0; + + int16_t x_val = 0; + int16_t y_val = 0; + int16_t z_val = 0; + int16_t tempi = 0; + int16_t temp_val = 0; + + int16_t x_valg = 0; + int16_t y_valg = 0; + int16_t z_valg = 0; + + int16_t xf_val = 0; + int16_t yf_val = 0; + int16_t zf_val = 0; + + /* Accelerometer */ + + lsm6dsl_readreg8(priv, LSM6DSL_OUTX_L_XL, &lox); + lsm6dsl_readreg8(priv, LSM6DSL_OUTX_H_XL, &hix); + + lsm6dsl_readreg8(priv, LSM6DSL_OUTY_L_XL, &loy); + lsm6dsl_readreg8(priv, LSM6DSL_OUTY_H_XL, &hiy); + + lsm6dsl_readreg8(priv, LSM6DSL_OUTZ_L_XL, &loz); + lsm6dsl_readreg8(priv, LSM6DSL_OUTZ_H_XL, &hiz); + + /* Gyro */ + + lsm6dsl_readreg8(priv, LSM6DSL_OUTX_L_G, &loxg); + lsm6dsl_readreg8(priv, LSM6DSL_OUTX_H_G, &hixg); + + lsm6dsl_readreg8(priv, LSM6DSL_OUTY_L_G, &loyg); + lsm6dsl_readreg8(priv, LSM6DSL_OUTY_H_G, &hiyg); + + lsm6dsl_readreg8(priv, LSM6DSL_OUTZ_L_G, &lozg); + lsm6dsl_readreg8(priv, LSM6DSL_OUTZ_H_G, &hizg); + + /* Timestamp */ + + lsm6dsl_readreg8(priv, LSM6DSL_TIMESTAMP0_REG, &tstamp0); + lsm6dsl_readreg8(priv, LSM6DSL_TIMESTAMP1_REG, &tstamp1); + lsm6dsl_readreg8(priv, LSM6DSL_TIMESTAMP2_REG, &tstamp2); + + ts = (tstamp2 << 16) | (tstamp1 << 8) | tstamp0; + + /* Temperature */ + + lsm6dsl_readreg8(priv, LSM6DSL_OUT_TEMP_L, &templ); + lsm6dsl_readreg8(priv, LSM6DSL_OUT_TEMP_H, &temph); + + xf_val = (int16_t) ((hix << 8) | lox); + yf_val = (int16_t) ((hiy << 8) | loy); + zf_val = (int16_t) ((hiz << 8) | loz); + + tempi = (int16_t) ((((int16_t) temph << 8) | (int16_t) templ)); + + temp_val = (tempi / 256) + 25; + + sninfo("Data 16-bit XL_X--->: %d mg\n", (short)(xf_val * accelerofactor)); + sninfo("Data 16-bit XL_Y--->: %d mg\n", (short)(yf_val * accelerofactor)); + sninfo("Data 16-bit XL_Z--->: %d mg\n", (short)(zf_val * accelerofactor)); + sninfo("Data 16-bit TEMP--->: %d Celsius\n", temp_val); + + sensor_data->x_data = xf_val * accelerofactor; + sensor_data->y_data = yf_val * accelerofactor; + sensor_data->z_data = zf_val * accelerofactor; + sensor_data->temperature = temp_val; + sensor_data->timestamp = ts; + + x_valg = (int16_t) (((hixg) << 8) | loxg); + y_valg = (int16_t) (((hiyg) << 8) | loyg); + z_valg = (int16_t) (((hizg) << 8) | lozg); + + sninfo("Data 16-bit G_X--->: %d mdps\n", (short)(x_valg * gyrofactor)); + sninfo("Data 16-bit G_Y--->: %d mdps\n", (short)(y_valg * gyrofactor)); + sninfo("Data 16-bit G_Z--->: %d mdps\n", (short)(z_valg * gyrofactor)); + + sensor_data->g_x_data = x_valg * gyrofactor; + sensor_data->g_y_data = y_valg * gyrofactor; + sensor_data->g_z_data = z_valg * gyrofactor; + + return OK; +} + +/**************************************************************************** + * Name: lsm6dsl_open + * + * Description: + * This method is called when the device is opened. + * + ****************************************************************************/ + +static int lsm6dsl_open(FAR struct file *filep) +{ + sninfo("Device LSM6DSL opened!!\r\n"); + return OK; +} + +/**************************************************************************** + * Name: lsm6dsl_close + * + * Description: + * This method is called when the device is closed. + * + ****************************************************************************/ + +static int lsm6dsl_close(FAR struct file *filep) +{ + return OK; +} + +/**************************************************************************** + * Name: lsm6dsl_read + * + * Description: + * The standard read method. + * + ****************************************************************************/ + +static ssize_t lsm6dsl_read(FAR struct file *filep, + FAR char *buffer, size_t buflen) +{ + FAR struct inode *inode; + FAR struct lsm6dsl_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; + uint32_t merge = 0; + + /* Sanity check */ + + DEBUGASSERT(filep != NULL); + inode = filep->f_inode; + + DEBUGASSERT(inode != NULL); + priv = (FAR struct lsm6dsl_dev_s *)inode->i_private; + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv->datareg == LSM6DSL_OUTX_L_G_SHIFT || + priv->datareg == LSM6DSL_OUTX_L_XL_SHIFT); + 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 = lsm6dsl_readreg8(priv, regaddr, &lo); + if (ret < 0) + { + snerr("ERROR: lsm6dsl_readreg8 failed: %d\n", ret); + return (ssize_t) ret; + } + + regaddr++; + + /* Read the high byte */ + + ret = lsm6dsl_readreg8(priv, regaddr, &hi); + if (ret < 0) + { + snerr("ERROR: lsm6dsl_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; + + /* Collect entropy */ + + merge += data ^ (merge >> 16); + + /* 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); + } + } + } + + /* Feed sensor data to entropy pool */ + + add_sensor_randomness(merge); + + return nsamples * samplesize; +} + +/**************************************************************************** + * Name: lsm6dsl_write + * + * Description: + * A dummy write method. + * + ****************************************************************************/ + +static ssize_t lsm6dsl_write(FAR struct file *filep, + FAR const char *buffer, size_t buflen) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: lsm6dsl_ioctl + * + * Description: + * The standard ioctl method. + * + ****************************************************************************/ + +static int lsm6dsl_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode; + FAR struct lsm6dsl_dev_s *priv; + int ret; + + /* Sanity check */ + + DEBUGASSERT(filep != NULL); + inode = filep->f_inode; + + DEBUGASSERT(inode != NULL); + priv = (FAR struct lsm6dsl_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; + + case SNIOC_LSM6DSLSENSORREAD: + ret = priv->ops->sensor_read(priv, (FAR struct lsm6dsl_sensor_data_s *) arg); + break; + + case SNIOC_START_SELFTEST: + ret = priv->ops->selftest(priv, (uint32_t) arg); + break; + + /* Unrecognized commands */ + + default: + { + snerr("ERROR: Unrecognized cmd: %d arg: %lu\n", cmd, arg); + ret = -ENOTTY; + } + break; + } + + return ret; +} + +/**************************************************************************** + * Name: lsm6dsl_register + * + * Description: + * Register the LSM6DSL accelerometer, gyroscope device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register, e.g., "/dev/lsm6dsl0", + * "/dev/gyro0" or "/dev/mag0". + * i2c - An I2C driver instance. + * addr - The I2C address of the LSM6DSL 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 lsm6dsl_register(FAR const char *devpath, + FAR struct i2c_master_s *i2c, + uint8_t addr, + FAR const struct lsm6dsl_ops_s *ops, + uint8_t datareg, + struct lsm6dsl_sensor_data_s sensor_data) +{ + FAR struct lsm6dsl_dev_s *priv; + int ret; + + /* Sanity check */ + + DEBUGASSERT(devpath != NULL); + DEBUGASSERT(i2c != NULL); + DEBUGASSERT(datareg == LSM6DSL_OUTX_L_XL_SHIFT || + datareg == LSM6DSL_OUTX_L_G_SHIFT); + + /* Initialize the device's structure */ + + priv = (FAR struct lsm6dsl_dev_s *)kmm_malloc(sizeof(*priv)); + if (priv == NULL) + { + snerr("ERROR: Failed to allocate instance\n"); + return -ENOMEM; + } + + priv->i2c = i2c; + priv->addr = addr; + priv->ops = ops; + priv->datareg = datareg; + priv->sensor_data = sensor_data; + + /* Configure the device */ + + ret = priv->ops->config(priv); + if (ret < 0) + { + snerr("ERROR: 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) + { + snerr("ERROR: Failed to register driver: %d\n", ret); + kmm_free(priv); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lsm6dsl_sensor_register + * + * Description: + * Register the LSM6DSL accelerometer character device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register, e.g., "/dev/lsm6dsl0". + * i2c - An I2C driver instance. + * addr - The I2C address of the LSM6DSL accelerometer. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int lsm6dsl_sensor_register(FAR const char *devpath, + FAR struct i2c_master_s *i2c, uint8_t addr) +{ + struct lsm6dsl_sensor_data_s sensor_data; + + DEBUGASSERT(addr == LSM6DSLACCEL_ADDR0 || addr == LSM6DSLACCEL_ADDR1); + + sninfo("Trying to register accel\n"); + + return lsm6dsl_register(devpath, i2c, addr, &g_LSM6DSLsensor_ops, + LSM6DSL_OUTX_L_XL_SHIFT, sensor_data); +} + +#endif /* CONFIG_I2C && CONFIG_SENSORS_LSM6DSL */ diff --git a/include/nuttx/sensors/ioctl.h b/include/nuttx/sensors/ioctl.h index f8589e03647..d39a595b468 100644 --- a/include/nuttx/sensors/ioctl.h +++ b/include/nuttx/sensors/ioctl.h @@ -1,4 +1,4 @@ -/**************************************************************************** +/************************************************************************************ * include/nuttx/sensors/ioctl.h * * Copyright (C) 2016-2018 Gregory Nutt. All rights reserved. @@ -31,133 +31,147 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - ****************************************************************************/ + ************************************************************************************/ #ifndef __INCLUDE_NUTTX_SENSORS_IOCTL_H #define __INCLUDE_NUTTX_SENSORS_IOCTL_H -/**************************************************************************** +/************************************************************************************ * Included Files - ****************************************************************************/ + ************************************************************************************/ #include #include -/**************************************************************************** +/************************************************************************************ * Pre-processor Definitions - ****************************************************************************/ + ************************************************************************************/ /* IOCTL commands unique to the BH1750FVI */ -#define SNIOC_CHRM _SNIOC(0x0001) /* Contin. H-Res Mode Arg: None */ -#define SNIOC_CHRM2 _SNIOC(0x0002) /* Contin. H-Res Mode2 Arg: None */ -#define SNIOC_CLRM _SNIOC(0x0003) /* Contin. L-Res Mode Arg: None */ -#define SNIOC_OTHRM _SNIOC(0x0004) /* One Time H-Res Mode Arg: None */ -#define SNIOC_OTHRM2 _SNIOC(0x0005) /* One Time H-Res Mode2 Arg: None */ -#define SNIOC_OTLRM _SNIOC(0x0006) /* One Time L-Res Mode Arg: None */ -#define SNIOC_CHMEATIME _SNIOC(0x0007) /* Change Meas. Time Arg: uint8_t */ +#define SNIOC_CHRM _SNIOC(0x0001) /* Contin. H-Res Mode Arg: None */ +#define SNIOC_CHRM2 _SNIOC(0x0002) /* Contin. H-Res Mode2 Arg: None */ +#define SNIOC_CLRM _SNIOC(0x0003) /* Contin. L-Res Mode Arg: None */ +#define SNIOC_OTHRM _SNIOC(0x0004) /* One Time H-Res Mode Arg: None */ +#define SNIOC_OTHRM2 _SNIOC(0x0005) /* One Time H-Res Mode2 Arg: None */ +#define SNIOC_OTLRM _SNIOC(0x0006) /* One Time L-Res Mode Arg: None */ +#define SNIOC_CHMEATIME _SNIOC(0x0007) /* Change Meas. Time Arg: uint8_t */ /* IOCTL commands unique to the KXTJ9 */ -#define SNIOC_ENABLE _SNIOC(0x0008) /* Arg: None */ -#define SNIOC_DISABLE _SNIOC(0x0009) /* Arg: None */ -#define SNIOC_CONFIGURE _SNIOC(0x000a) /* Arg: enum kxtj9_odr_e value */ +#define SNIOC_ENABLE _SNIOC(0x0008) /* Arg: None */ +#define SNIOC_DISABLE _SNIOC(0x0009) /* Arg: None */ +#define SNIOC_CONFIGURE _SNIOC(0x000a) /* Arg: enum kxtj9_odr_e value */ /* IOCTL commands common to the LM75, LM92 (and compatible parts) */ -#define SNIOC_READCONF _SNIOC(0x000b) /* Arg: uint8_t* pointer */ -#define SNIOC_WRITECONF _SNIOC(0x000c) /* Arg: uint8_t value */ -#define SNIOC_SHUTDOWN _SNIOC(0x000d) /* Arg: None */ -#define SNIOC_POWERUP _SNIOC(0x000e) /* Arg: None */ -#define SNIOC_FAHRENHEIT _SNIOC(0x000f) /* Arg: None */ -#define SNIOC_CENTIGRADE _SNIOC(0x0010) /* Arg: None */ -#define SNIOC_READTHYS _SNIOC(0x0011) /* Arg: b16_t* pointer */ -#define SNIOC_WRITETHYS _SNIOC(0x0012) /* Arg: b16_t value */ +#define SNIOC_READCONF _SNIOC(0x000b) /* Arg: uint8_t* pointer */ +#define SNIOC_WRITECONF _SNIOC(0x000c) /* Arg: uint8_t value */ +#define SNIOC_SHUTDOWN _SNIOC(0x000d) /* Arg: None */ +#define SNIOC_POWERUP _SNIOC(0x000e) /* Arg: None */ +#define SNIOC_FAHRENHEIT _SNIOC(0x000f) /* Arg: None */ +#define SNIOC_CENTIGRADE _SNIOC(0x0010) /* Arg: None */ +#define SNIOC_READTHYS _SNIOC(0x0011) /* Arg: b16_t* pointer */ +#define SNIOC_WRITETHYS _SNIOC(0x0012) /* Arg: b16_t value */ /* IOCTL commands unique to the LM75 */ -#define SNIOC_READTOS _SNIOC(0x0013) /* Arg: b16_t* pointer */ -#define SNIOC_WRITETOS _SNIOC(0x0014) /* Arg: b16_t value */ +#define SNIOC_READTOS _SNIOC(0x0013) /* Arg: b16_t* pointer */ +#define SNIOC_WRITETOS _SNIOC(0x0014) /* Arg: b16_t value */ /* IOCTL commands unique to the LM92 */ -#define SNIOC_READTCRIT _SNIOC(0x0015) /* Arg: b16_t* pointer */ -#define SNIOC_WRITETCRIT _SNIOC(0x0016) /* Arg: b16_t value */ -#define SNIOC_READTLOW _SNIOC(0x0017) /* Arg: b16_t* pointer */ -#define SNIOC_WRITETLOW _SNIOC(0x0018) /* Arg: b16_t value */ -#define SNIOC_READTHIGH _SNIOC(0x0019) /* Arg: b16_t* pointer */ -#define SNIOC_WRITETHIGH _SNIOC(0x001a) /* Arg: b16_t value */ -#define SNIOC_READID _SNIOC(0x001b) /* Arg: uint16_t* pointer */ +#define SNIOC_READTCRIT _SNIOC(0x0015) /* Arg: b16_t* pointer */ +#define SNIOC_WRITETCRIT _SNIOC(0x0016) /* Arg: b16_t value */ +#define SNIOC_READTLOW _SNIOC(0x0017) /* Arg: b16_t* pointer */ +#define SNIOC_WRITETLOW _SNIOC(0x0018) /* Arg: b16_t value */ +#define SNIOC_READTHIGH _SNIOC(0x0019) /* Arg: b16_t* pointer */ +#define SNIOC_WRITETHIGH _SNIOC(0x001a) /* Arg: b16_t value */ +#define SNIOC_READID _SNIOC(0x001b) /* Arg: uint16_t* pointer */ /* IOCTL commands unique to the LSM9DS1 */ -#define SNIOC_START _SNIOC(0x001c) /* Arg: None */ -#define SNIOC_STOP _SNIOC(0x001d) /* Arg: None */ -#define SNIOC_SETSAMPLERATE _SNIOC(0x001e) /* Arg: uint32_t value */ -#define SNIOC_SETFULLSCALE _SNIOC(0x001f) /* Arg: uint32_t value */ +#define SNIOC_START _SNIOC(0x001c) /* Arg: None */ +#define SNIOC_STOP _SNIOC(0x001d) /* Arg: None */ +#define SNIOC_SETSAMPLERATE _SNIOC(0x001e) /* Arg: uint32_t value */ +#define SNIOC_SETFULLSCALE _SNIOC(0x001f) /* Arg: uint32_t value */ /* IOCTL commands unique to the MB7040 */ -#define SNIOC_MEASURE _SNIOC(0x0020) /* Arg: None */ -#define SNIOC_RANGE _SNIOC(0x0021) /* Arg: int32_t* pointer */ -#define SNIOC_CHANGEADDR _SNIOC(0x0022) /* Arg: uint8_t value */ +#define SNIOC_MEASURE _SNIOC(0x0020) /* Arg: None */ +#define SNIOC_RANGE _SNIOC(0x0021) /* Arg: int32_t* pointer */ +#define SNIOC_CHANGEADDR _SNIOC(0x0022) /* Arg: uint8_t value */ /* IOCTL commands unique to the MCP9844 */ -#define SNIOC_READTEMP _SNIOC(0x0023) /* Arg: mcp9844_temp_arg_s* pointer */ -#define SNIOC_SETRESOLUTION _SNIOC(0x0024) /* Arg: uint16_t value */ +#define SNIOC_READTEMP _SNIOC(0x0023) /* Arg: mcp9844_temp_arg_s* pointer */ +#define SNIOC_SETRESOLUTION _SNIOC(0x0024) /* Arg: uint16_t value */ /* IOCTL commands unique to the MS58XX */ -#define SNIOC_MEASURE _SNIOC(0x0025) /* Arg: None */ -#define SNIOC_TEMPERATURE _SNIOC(0x0026) /* Arg: int32_t* pointer */ -#define SNIOC_PRESSURE _SNIOC(0x0027) /* Arg: int32_t* pointer */ -#define SNIOC_RESET _SNIOC(0x0028) /* Arg: None */ -#define SNIOC_OVERSAMPLING _SNIOC(0x0029) /* Arg: uint16_t value */ +#define SNIOC_MEASURE _SNIOC(0x0025) /* Arg: None */ +#define SNIOC_TEMPERATURE _SNIOC(0x0026) /* Arg: int32_t* pointer */ +#define SNIOC_PRESSURE _SNIOC(0x0027) /* Arg: int32_t* pointer */ +#define SNIOC_RESET _SNIOC(0x0028) /* Arg: None */ +#define SNIOC_OVERSAMPLING _SNIOC(0x0029) /* Arg: uint16_t value */ /* IOCTL commands to the HTS221 & LPS25H */ -#define SNIOC_CFGR _SNIOC(0x002a) -#define SNIOC_GET_DEV_ID _SNIOC(0x002b) +#define SNIOC_CFGR _SNIOC(0x002a) +#define SNIOC_GET_DEV_ID _SNIOC(0x002b) /* IOCTL commands unique to the HTS221 */ -#define SNIOC_START_CONVERSION _SNIOC(0x002c) -#define SNIOC_CHECK_STATUS_REG _SNIOC(0x002d) -#define SNIOC_READ_RAW_DATA _SNIOC(0x002e) -#define SNIOC_READ_CONVERT_DATA _SNIOC(0x002f) -#define SNIOC_DUMP_REGS _SNIOC(0x0030) +#define SNIOC_START_CONVERSION _SNIOC(0x002c) +#define SNIOC_CHECK_STATUS_REG _SNIOC(0x002d) +#define SNIOC_READ_RAW_DATA _SNIOC(0x002e) +#define SNIOC_READ_CONVERT_DATA _SNIOC(0x002f) +#define SNIOC_DUMP_REGS _SNIOC(0x0030) /* IOCTL commands unique to the LPS25H */ -#define SNIOC_TEMPERATURE_OUT _SNIOC(0x0031) -#define SNIOC_PRESSURE_OUT _SNIOC(0x0032) -#define SNIOC_SENSOR_OFF _SNIOC(0x0033) +#define SNIOC_TEMPERATURE_OUT _SNIOC(0x0031) +#define SNIOC_PRESSURE_OUT _SNIOC(0x0032) +#define SNIOC_SENSOR_OFF _SNIOC(0x0033) /* IOCTL commands unique to the LIS2DH */ -#define SNIOC_WRITESETUP _SNIOC(0x0034) /* Arg: uint8_t value */ -#define SNIOC_WRITE_INT1THRESHOLD _SNIOC(0x0035) /* Arg: uint8_t value */ -#define SNIOC_WRITE_INT2THRESHOLD _SNIOC(0x0036) /* Arg: uint8_t value */ -#define SNIOC_RESET_HPFILTER _SNIOC(0x0037) /* Arg: uint8_t value */ -#define SNIOC_START_SELFTEST _SNIOC(0x0038) /* Arg: uint8_t value */ -#define SNIOC_WHO_AM_I _SNIOC(0x0039) -#define SNIOC_READ_TEMP _SNIOC(0x003a) /* Arg: int16_t value */ +#define SNIOC_WRITESETUP _SNIOC(0x0034) /* Arg: uint8_t value */ +#define SNIOC_WRITE_INT1THRESHOLD _SNIOC(0x0035) /* Arg: uint8_t value */ +#define SNIOC_WRITE_INT2THRESHOLD _SNIOC(0x0036) /* Arg: uint8_t value */ +#define SNIOC_RESET_HPFILTER _SNIOC(0x0037) /* Arg: uint8_t value */ +#define SNIOC_START_SELFTEST _SNIOC(0x0038) /* Arg: uint8_t value */ +#define SNIOC_WHO_AM_I _SNIOC(0x0039) +#define SNIOC_READ_TEMP _SNIOC(0x003a) /* Arg: int16_t value */ /* IOCTL commands unique to the MAX44009 */ -#define SNIOC_INIT _SNIOC(0x003b) -#define SNIOC_THRESHOLD _SNIOC(0x003c) +#define SNIOC_INIT _SNIOC(0x003b) +#define SNIOC_THRESHOLD _SNIOC(0x003c) /* IOCTL commands unique to LIS3DH */ -#define SNIOC_SET_POWER_MODE _SNIOC(0x003d) /* Arg: LIS3DH_POWER_xxx */ -#define SNIOC_SET_DATA_RATE _SNIOC(0x003e) /* Arg: LIS3DH_ODR_xxx */ -#define SNIOC_SET_DATA_FORMAT _SNIOC(0x003f) /* Arg: LIS3DH_FORMAT_xxx */ +#define SNIOC_SET_POWER_MODE _SNIOC(0x003d) /* Arg: LIS3DH_POWER_xxx */ +#define SNIOC_SET_DATA_RATE _SNIOC(0x003e) /* Arg: LIS3DH_ODR_xxx */ +#define SNIOC_SET_DATA_FORMAT _SNIOC(0x003f) /* Arg: LIS3DH_FORMAT_xxx */ /* IOCTL commands unique to T67XX */ -#define SNIOC_SPCALIB _SNIOC(0x0040) /* Arg: uint8_t value */ -#define SNIOC_ABCLOGIC _SNIOC(0x0041) /* Arg: uint8_t value */ +#define SNIOC_SPCALIB _SNIOC(0x0040) /* Arg: uint8_t value */ +#define SNIOC_ABCLOGIC _SNIOC(0x0041) /* Arg: uint8_t value */ + +/* IOCTL commands unique to the LSM6DSL */ + +#define SNIOC_START _SNIOC(0x0042) /* Arg: None */ +#define SNIOC_STOP _SNIOC(0x0043) /* Arg: None */ +#define SNIOC_LSM6DSLSENSORREAD _SNIOC(0x0046) /* Arg: file *filep, FAR char *buffer,size_t buflen */ +#define SNIOC_START_SELFTEST _SNIOC(0x0047) /* Arg: file *filep, FAR char *buffer,size_t mode */ + +/* IOCTL commands unique to the LSM303AGR */ + +#define SNIOC_START _SNIOC(0x0049) /* Arg: None */ +#define SNIOC_STOP _SNIOC(0x0050) /* Arg: None */ +#define SNIOC_LSM303AGRSENSORREAD _SNIOC(0x0051) /* Arg: file *filep, FAR char *buffer,size_t buflen */ +#define SNIOC_START_SELFTEST _SNIOC(0x0052) /* Arg: file *filep, FAR char *buffer,size_t mode */ #endif /* __INCLUDE_NUTTX_SENSORS_IOCTL_H */ diff --git a/include/nuttx/sensors/lsm303agr.h b/include/nuttx/sensors/lsm303agr.h new file mode 100644 index 00000000000..2bceb826036 --- /dev/null +++ b/include/nuttx/sensors/lsm303agr.h @@ -0,0 +1,228 @@ +/**************************************************************************** + * include/nuttx/sensors/lsm303agr.h [from the IKS01A2 MEMS board STM] + * + * 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_LSM303AGR +#define __INCLUDE_NUTTX_SENSORS_LSM303AGR + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_LSM303AGR) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* I2C Addresses ************************************************************/ + +/* https://github.com/RIOT-OS/RIOT/issues/7133 */ + +/* Accelerometer addresses */ + +#define LSM303AGRACCELERO_ADDR (0x32>>1) + +/* Magnetometer addresses */ + +#define LSM303AGRMAGNETO_ADDR (0x3C>>1) /* 7-bit */ + +/* Register Addresses *******************************************************/ + +/* Accelerometer and magnetometer registers */ + +#define LSM303AGR_STATUS_REG_AUX_A 0x07 +#define LSM303AGR_OUT_TEMP_L_A 0x0C +#define LSM303AGR_OUT_TEMP_H_A 0x0D +#define LSM303AGR_INT_COUNTER_REG_A 0x0E +#define LSM303AGR_WHO_AM_I 0x0F +#define LSM303AGR_WHO_AM_I_VALUE 0x00 +#define LSM303AGR_TEMP_CFG_REG_A 0x1F +#define LSM303AGR_CTRL_REG1_A 0x20 +#define LSM303AGR_CTRL_REG2_A 0x21 +#define LSM303AGR_CTRL_REG3_A 0x22 +#define LSM303AGR_CTRL_REG4_A 0x23 +#define LSM303AGR_CTRL_REG5_A 0x24 +#define LSM303AGR_CTRL_REG6_A 0x25 +#define LSM303AGR_REF_DATA_CAP_A 0x26 +#define LSM303AGR_STATUS_REG_A 0x27 + +#define LSM303AGR_STATUS_REG_A_SHIFT 0 +#define LSM303AGR_STATUS_REG_A_MASK (0 << LSM303AGR_STATUS_REG_A_SHIFT) +#define LSM303AGR_STATUS_REG_A_ZYXDA (1 << 3) +#define LSM303AGR_STATUS_REG_A_ZYXOR (1 << 7) + +#define LSM303AGR_OUT_X_L_A 0x28 +#define LSM303AGR_OUT_X_H_A 0x29 +#define LSM303AGR_OUT_Y_L_A 0x2A +#define LSM303AGR_OUT_Y_H_A 0x2B +#define LSM303AGR_OUT_Z_L_A 0x2C +#define LSM303AGR_OUT_Z_H_A 0x2D + +#define LSM303AGR_OUTX_L_A_SHIFT 0 +#define LSM303AGR_OUTX_L_A_MASK (255 << LSM303AGR_OUTX_L_A_SHIFT) + +#define LSM303AGR_FIFO_CTRL_REG_A 0x2E +#define LSM303AGR_FIFO_SRC_REG_A 0x2F +#define LSM303AGR_INT1_CFG_A 0x30 +#define LSM303AGR_INT1_SRC_A 0x3A +#define LSM303AGR_INT1_THS_A 0x32 +#define LSM303AGR_INT1_DURATION_A 0x33 +#define LSM303AGR_INT2_CFG_A 0x34 +#define LSM303AGR_INT2_SRC_A 0x35 +#define LSM303AGR_INT2_THS_A 0x36 +#define LSM303AGR_INT2_DURATION_A 0x37 +#define LSM303AGR_CLICK_CFG_A 0x38 +#define LSM303AGR_CLICK_SRC_A 0x39 +#define LSM303AGR_CLICK_THS_A 0x3A +#define LSM303AGR_TIME_LIMIT_A 0x3B +#define LSM303AGR_TIME_LATENCY_A 0x3C +#define LSM303AGR_TIME_WINDOW_A 0x3D +#define LSM303AGR_Act_THS_A 0x3E +#define LSM303AGR_Act_DUR_A 0x3F +#define LSM303AGR_OFFSET_X_REG_L_M 0x45 +#define LSM303AGR_OFFSET_X_REG_H_M 0x46 +#define LSM303AGR_OFFSET_Y_REG_L_M 0x47 +#define LSM303AGR_OFFSET_Y_REG_H_M 0x48 +#define LSM303AGR_OFFSET_Z_REG_L_M 0x49 +#define LSM303AGR_OFFSET_Z_REG_H_M 0x4A +#define LSM303AGR_WHO_AM_I_M 0x4F +#define LSM303AGR_CFG_REG_A_M 0x60 +#define LSM303AGR_CFG_REG_B_M 0x61 +#define LSM303AGR_CFG_REG_C_M 0x62 +#define LSM303AGR_INT_CTRL_REG_M 0x63 +#define LSM303AGR_INT_SOURCE_REG_M 0x64 +#define LSM303AGR_INT_THS_L_REG_M 0x65 +#define LSM303AGR_INT_THS_H_REG_M 0x66 +#define LSM303AGR_STATUS_REG_M 0x67 + +#define LSM303AGR_STATUS_REG_M_SHIFT 0 +#define LSM303AGR_STATUS_REG_M_MASK (0 << LSM303AGR_STATUS_REG_M_SHIFT) +#define LSM303AGR_STATUS_REG_M_ZYXDA (1 << 3) +#define LSM303AGR_STATUS_REG_M_ZYXOR (1 << 7) + +#define LSM303AGR_OUTX_L_REG_M 0x68 +#define LSM303AGR_OUTX_H_REG_M 0x69 +#define LSM303AGR_OUTY_L_REG_M 0x6A +#define LSM303AGR_OUTY_H_REG_M 0x6B +#define LSM303AGR_OUTZ_L_REG_M 0x6C +#define LSM303AGR_OUTZ_H_REG_M 0x6D + +#define LSM303AGR_OUTX_L_M_SHIFT 0 +#define LSM303AGR_OUTX_L_M_MASK (255 << LSM303AGR_OUTX_L_M_SHIFT) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct i2c_master_s; + +/* Container for sensor data */ + +struct lsm303agr_sensor_data_s +{ + int16_t x_data; + int16_t y_data; + int16_t z_data; + uint16_t temperature; + int16_t m_x_data; + int16_t m_y_data; + int16_t m_z_data; + uint16_t timestamp; +}; + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct lsm303agr_dev_s; +struct lsm303agr_ops_s +{ + CODE int (*config)(FAR struct lsm303agr_dev_s *priv); + CODE int (*start)(FAR struct lsm303agr_dev_s *priv); + CODE int (*stop)(FAR struct lsm303agr_dev_s *priv); + CODE int (*sensor_read)(FAR struct lsm303agr_dev_s *priv, + FAR struct lsm303agr_sensor_data_s *sensor_data); + CODE int (*selftest)(FAR struct lsm303agr_dev_s *priv, + uint32_t mode); +}; + +struct lsm303agr_dev_s +{ + FAR struct i2c_master_s *i2c; /* I2C interface */ + uint8_t addr; /* I2C address */ + + FAR const struct lsm303agr_ops_s *ops; + + uint8_t datareg; /* Output data register of X low byte */ + struct lsm303agr_sensor_data_s sensor_data; /* Sensor data container */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/**************************************************************************** + * Name: lsm303agr_sensor_register + * + * Description: + * Register the lsm303agr accelerometer character device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register, e.g., "/dev/sensor0". + * 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 lsm303agr_sensor_register(FAR const char *devpath, + FAR struct i2c_master_s *i2c,uint8_t addr); + +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_I2C && CONFIG_SENSORS_LSM303AGR */ +#endif /* __INCLUDE_NUTTX_SENSORS_LSM303AGR */ diff --git a/include/nuttx/sensors/lsm6dsl.h b/include/nuttx/sensors/lsm6dsl.h new file mode 100644 index 00000000000..c6ea7281696 --- /dev/null +++ b/include/nuttx/sensors/lsm6dsl.h @@ -0,0 +1,897 @@ +/**************************************************************************************************** + * include/nuttx/sensors/lsm6dsl.h [from the IKS01A2 MEMS board STM] + * + * 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_LSM6DSL +#define __INCLUDE_NUTTX_SENSORS_LSM6DSL + +/**************************************************************************************************** + * Included Files + ****************************************************************************************************/ + +#include +#include + +#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_LSM6DSL) + +/**************************************************************************************************** + * Pre-processor Definitions + ****************************************************************************************************/ + +/* I2C Addresses ************************************************************************************/ + +/* Accelerometer addresses */ + +#define LSM6DSLACCEL_ADDR0 (0xD4>>1) /*0x6a low */ +#define LSM6DSLACCEL_ADDR1 (0xD6>>1) /* 0x6B .. high */ + +/* Gyroscope addresses */ + +#define LSM6DSLGYRO_ADDR0 0xd4 +#define LSM6DSLGYRO_ADDR1 0xd6 + +/* Register Addresses *******************************************************************************/ + +/* Accelerometer and gyroscope registers */ + +#define LSM6DSL_FUNC_CFG_ACCESS 0x01 /* Enable embedded functions register (r/w).*/ +#define LSM6DSL_SENSOR_SYNC_TIME_FRAME 0x04 /* Sensor synchronization time frame register (r/w). */ +#define LSM6DSL_SENSOR_SYNC_RES_RATIO 0x05 /* Sensor synchronization resolution ratio (r/w) */ +#define LSM6DSL_FIFO_CTRL1 0x06 /* FIFO control register (r/w). */ +#define LSM6DSL_FIFO_CTRL2 0x07 /* FIFO control register (r/w). */ +#define LSM6DSL_FIFO_CTRL3 0x08 /* FIFO control register (r/w). */ +#define LSM6DSL_FIFO_CTRL4 0x09 /* FIFO control register (r/w). */ +#define LSM6DSL_FIFO_CTRL5 0x0A /* FIFO control register (r/w). */ +#define LSM6DSL_DRDY_PULSE_CFG_G 0x0B /* DataReady configuration register (r/w).*/ +#define LSM6DSL_INT1_CTRL 0x0D /* INT1 pad control register (r/w). */ +#define LSM6DSL_INT2_CTRL 0x0E /* INT2 pad control register (r/w). */ +#define LSM6DSL_WHO_AM_I 0x0F /* Who_AM_I register (r). This register is a read-only register. */ +#define LSM6DSL_WHO_AM_I_VALUE 0x6A +#define LSM6DSL_CTRL1_XL 0x10 /* Linear acceleration sensor control register 1 (r/w). */ +#define LSM6DSL_CTRL2_G 0x11 /* Angular rate sensor control register 2 (r/w). */ +#define LSM6DSL_CTRL3_C 0x12 /* Control register 3 (r/w). */ +#define LSM6DSL_CTRL4_C 0x13 /* Control register 4 (r/w).*/ +#define LSM6DSL_CTRL5_C 0x14 /* Control register 5 (r/w). */ +#define LSM6DSL_CTRL6_C 0x15 /* Angular rate sensor control register 6 (r/w). */ +#define LSM6DSL_CTRL7_G 0x16 /* Angular rate sensor control register 7 (r/w). */ +#define LSM6DSL_CTRL8_XL 0x17 /* Linear acceleration sensor control register 8 (r/w). */ +#define LSM6DSL_CTRL9_XL 0x18 /* Linear acceleration sensor control register 9 (r/w). */ +#define LSM6DSL_CTRL10_C 0x19 /* Control register 10 (r/w). */ +#define LSM6DSL_MASTER_CONFIG 0x1A /* Master configuration register (r/w). */ +#define LSM6DSL_WAKE_UP_SRC 0x1B /* Wake up interrupt source register (r). */ +#define LSM6DSL_TAP_SRC 0x1C /* Tap source register (r). */ +#define LSM6DSL_D6D_SRC 0x1D /* Portrait, landscape, face-up and face-down source register (r). */ +#define LSM6DSL_STATUS_REG 0x1E /* The STATUS_REG register is read by the SPI/I2C interface (r). */ +#define LSM6DSL_OUT_TEMP_L 0x20 /* Temperature data output register (r). */ +#define LSM6DSL_OUT_TEMP_H 0x21 /* Temperature data output register (r). */ +#define LSM6DSL_OUTX_L_G 0x22 /* Angular rate sensor pitch axis (X) angular rate output register (r). */ +#define LSM6DSL_OUTX_H_G 0x23 /* Angular rate sensor pitch axis (X) angular rate output register (r). */ +#define LSM6DSL_OUTY_L_G 0x24 /* Angular rate sensor roll axis (Y) angular rate output register (r). */ +#define LSM6DSL_OUTY_H_G 0x25 /* Angular rate sensor roll axis (Y) angular rate output register (r). */ +#define LSM6DSL_OUTZ_L_G 0x26 /* Angular rate sensor roll axis (Z) angular rate output register (r). */ +#define LSM6DSL_OUTZ_H_G 0x27 /* Angular rate sensor roll axis (Z) angular rate output register (r). */ +#define LSM6DSL_OUTX_L_XL 0x28 /* Linear acceleration sensor X-axis output register (r). */ +#define LSM6DSL_OUTX_H_XL 0x29 /* Linear acceleration sensor X-axis output register (r). */ +#define LSM6DSL_OUTY_L_XL 0x2A /* Linear acceleration sensor Y-axis output register (r). */ +#define LSM6DSL_OUTY_H_XL 0x2B /* Linear acceleration sensor Y-axis output register (r). */ +#define LSM6DSL_OUTZ_L_XL 0x2C /* Linear acceleration sensor Z-axis output register (r). */ +#define LSM6DSL_OUTZ_H_XL 0x2D /* Linear acceleration sensor Z-axis output register (r). */ +#define LSM6DSL_SENSORHUB1_REG 0x2E /* First byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB2_REG 0x2F /* Second byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB3_REG 0x30 /* Third byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB4_REG 0x31 /* Fourth byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB5_REG 0x32 /* Fifth byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB6_REG 0x33 /* Sixth byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB7_REG 0x34 /* Seventh byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB8_REG 0x35 /* Eighth byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB9_REG 0x36 /* Ninth byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB10_REG 0x37 /* Tenth byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB11_REG 0x38 /* Eleventh byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB12_REG 0x39 /* Twelfth byte associated to external sensors. */ +#define LSM6DSL_FIFO_STATUS1 0x3A /* FIFO status control register (r). */ +#define LSM6DSL_FIFO_STATUS2 0x3B /* FIFO status control register (r). */ +#define LSM6DSL_FIFO_STATUS3 0x3C /* FIFO status control register (r). */ +#define LSM6DSL_FIFO_STATUS4 0x3D /* FIFO status control register (r). */ +#define LSM6DSL_FIFO_DATA_OUT_L 0x3E /* FIFO data output register (r). */ +#define LSM6DSL_FIFO_DATA_OUT_H 0x3F /* FIFO data output register (r). */ +#define LSM6DSL_TIMESTAMP0_REG 0x40 /* Timestamp first (least significant) byte data output register (r). */ +#define LSM6DSL_TIMESTAMP1_REG 0x41 /* Timestamp second byte data output register (r). */ +#define LSM6DSL_TIMESTAMP2_REG 0x42 /* Timestamp third (most significant) byte data output register (r). */ +#define LSM6DSL_STEP_TIMESTAMP_L 0x49 /* Step counter timestamp information register (r). */ +#define LSM6DSL_STEP_TIMESTAMP_H 0x4A /* Step counter timestamp information register (r). */ +#define LSM6DSL_STEP_COUNTER_L 0x4B /* Step counter output register (r). */ +#define LSM6DSL_STEP_COUNTER_H 0x4C /* Step counter output register (r). */ +#define LSM6DSL_SENSORHUB13_REG 0x4D /* Thirteenth byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB14_REG 0x4E /* Fourteenth byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB15_REG 0x4F /* Fifteenth byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB16_REG 0x50 /* Sixteenth byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB17_REG 0x51 /* Seventeenth byte associated to external sensors. */ +#define LSM6DSL_SENSORHUB18_REG 0x52 /* Eighteenth byte associated to external sensors. */ +#define LSM6DSL_FUNC_SRC1 0x53 /* Significant motion, tilt, step detector, hard/soft-iron and sensor hub interrupt source register +(r). */ +#define LSM6DSL_FUNC_SRC2 0x54 /* Wrist tilt interrupt source register (r). */ +#define LSM6DSL_WRIST_TILT_IA 0x55 /* Wrist tilt interrupt source register (r). */ +#define LSM6DSL_TAP_CFG 0x58 /* Enables interrupt and inactivity functions, configuration of filtering and tap recognition +functions (r/w). */ +#define LSM6DSL_TAP_THS_6D 0x59 /* Portrait/landscape position and tap function threshold register (r/w). */ +#define LSM6DSL_INT_DUR2 0x5A /* Tap recognition function setting register (r/w). */ +#define LSM6DSL_WAKE_UP_THS 0x5B /* Single and double-tap function threshold register (r/w). */ +#define LSM6DSL_WAKE_UP_DUR 0x5C /* Free-fall, wakeup, timestamp and sleep mode functions duration setting register (r/w). */ +#define LSM6DSL_FREE_FALL 0x5D /* Free-fall function duration setting register (r/w). */ +#define LSM6DSL_MD1_CFG 0x5E /* Functions routing on INT1 register (r/w). */ +#define LSM6DSL_MD2_CFG 0x5F /* Functions routing on INT2 register (r/w). */ +#define LSM6DSL_MASTER_CMD_CODE 0x60 /* Master command code used for stamping for sensor sync. */ +#define LSM6DSL_SENS_SYNC_SPI_ERROR_CODE 0x61 /* Error code used for sensor synchronization. */ +#define LSM6DSL_OUT_MAG_RAW_X_L 0x66 /* External magnetometer raw data (r). */ +#define LSM6DSL_OUT_MAG_RAW_X_H 0x67 /* External magnetometer raw data (r). */ +#define LSM6DSL_OUT_MAG_RAW_Y_L 0x68 /* External magnetometer raw data (r). */ +#define LSM6DSL_OUT_MAG_RAW_Y_H 0x69 /* External magnetometer raw data (r). */ +#define LSM6DSL_OUT_MAG_RAW_Z_L 0x6A /* External magnetometer raw data (r). */ +#define LSM6DSL_OUT_MAG_RAW_Z_H 0x6B /* External magnetometer raw data (r). */ +#define LSM6DSL_X_OFS_USR 0x73 /* Accelerometer X-axis user offset correction (r/w). */ +#define LSM6DSL_Y_OFS_USR 0x74 /* Accelerometer Y-axis user offset correction (r/w). */ +#define LSM6DSL_Z_OFS_USR 0x75 /* Accelerometer Z-axis user offset correction (r/w). */ + +/* Embedded functions registers description - Bank A */ + +#define LSM6DSL_SLV0_ADD 0x02 /* I2C slave address of the first external sensor (Sensor1) register (r/w). */ +#define LSM6DSL_SLV0_SUBADD 0x03 /* Address of register on the first external sensor (Sensor1) register (r/w). */ +#define LSM6DSL_SLAVE0_CONFIG 0x04 /* First external sensor (Sensor1) configuration and sensor hub settings register (r/w). */ +#define LSM6DSL_SLV1_ADD 0x05 /* I2C slave address of the second external sensor (Sensor2) register (r/w). */ +#define LSM6DSL_SLV1_SUBADD 0x06 /* Address of register on the second external sensor (Sensor2) register (r/w). */ +#define LSM6DSL_SLAVE1_CONFIG 0x07 /* Second external sensor (Sensor2) configuration register (r/w). */ +#define LSM6DSL_SLV2_ADD 0x08 /* I2C slave address of the third external sensor (Sensor3) register (r/w). */ +#define LSM6DSL_SLV2_SUBADD 0x09 /* Address of register on the third external sensor (Sensor3) register (r/w). */ +#define LSM6DSL_SLAVE2_CONFIG 0x0A /* Third external sensor (Sensor3) configuration register (r/w). */ +#define LSM6DSL_SLV3_ADD 0x0B /* I2C slave address of the fourth external sensor (Sensor4) register (r/w). */ +#define LSM6DSL_SLV3_SUBADD 0x0C /* Address of register on the fourth external sensor (Sensor4) register (r/w). */ +#define LSM6DSL_SLAVE3_CONFIG 0x0D /* Fourth external sensor (Sensor4) configuration register (r/w). */ +#define LSM6DSL_DATAWRITE_SRC_MODE_SUB_SLV0 0x0E /* Data to be written into the slave device register (r/w). */ +#define LSM6DSL_CONFIG_PEDO_THS_MIN 0x0F +#define LSM6DSL_SM_THS 0x13 /* Significant motion configuration register (r/w). */ +#define LSM6DSL_PEDO_DEB_REG 0x14 +#define LSM6DSL_STEP_COUNT_DELTA 0x15 /* Time period register for step detection on delta time (r/w). */ +#define LSM6DSL_MAG_SI_XX 0x24 /* Soft-iron matrix correction register (r/w). */ +#define LSM6DSL_MAG_SI_XY 0x25 /* Soft-iron matrix correction register (r/w). */ +#define LSM6DSL_MAG_SI_XZ 0x26 /* Soft-iron matrix correction register (r/w). */ +#define LSM6DSL_MAG_SI_YX 0x27 /* Soft-iron matrix correction register (r/w). */ +#define LSM6DSL_MAG_SI_YY 0x28 /* Soft-iron matrix correction register (r/w). */ +#define LSM6DSL_MAG_SI_YZ 0x29 /* Soft-iron matrix correction register (r/w). */ +#define LSM6DSL_MAG_SI_ZX 0x2A /* Soft-iron matrix correction register (r/w). */ +#define LSM6DSL_MAG_SI_ZY 0x2B /* Soft-iron matrix correction register (r/w). */ +#define LSM6DSL_MAG_SI_ZZ 0x2C /* Soft-iron matrix correction register (r/w). */ +#define LSM6DSL_MAG_OFFX_L 0x2D /* Offset for X-axis hard-iron compensation register (r/w). */ +#define LSM6DSL_MAG_OFFX_H 0x2E /* Offset for X-axis hard-iron compensation register (r/w). */ +#define LSM6DSL_MAG_OFFY_L 0x2F /* Offset for Y-axis hard-iron compensation register (r/w). */ +#define LSM6DSL_MAG_OFFY_H 0x30 /* Offset for Y-axis hard-iron compensation register (r/w). */ +#define LSM6DSL_MAG_OFFZ_L 0x31 /* Offset for Z-axis hard-iron compensation register (r/w). */ +#define LSM6DSL_MAG_OFFZ_H 0x32 /* Offset for Z-axis hard-iron compensation register (r/w). */ + +/* Embedded functions registers description - Bank B */ + +#define LSM6DSL_A_WRIST_TILT_LAT 0x50 /* Absolute Wrist Tilt latency register (r/w). */ +#define LSM6DSL_A_WRIST_TILT_THS 0x54 /* Absolute Wrist Tilt threshold register (r/w). */ +#define LSM6DSL_A_WRIST_TILT_Mask 0x59 /* Absolute Wrist Tilt mask register (r/w). */ + +/**************************************************************************************************** + * Register Bit Definitions + * + * For this sensor it is choosen to not define each pin individually...its set bitwise like: + * 0b000[0]0000 with preferred hex value! Where [] is showing the [not defined in datasheet] bit. + * A complete definition is written below, just not all registers are validated!! + * + ****************************************************************************************************/ + +#define LSM6DSL_FUNC_CFG_ACCESS_FUNC_CFG_EN (1 << 5) +#define LSM6DSL_FUNC_CFG_ACCESS_FUNC_CFG_EN_B (1 << 7) + +#define LSM6DSL_SENSOR_SYNC_TIME_FRAME_TPH_SHIFT 0 +#define LSM6DSL_SENSOR_SYNC_TIME_FRAME_TPH_MASK (15 << LSM6DSL_SENSOR_SYNC_TIME_FRAME_TPH_SHIFT) + +#define LSM6DSL_SENSOR_SYNC_RES_RATIO_SHIFT 0 +#define LSM6DSL_SENSOR_SYNC_RES_RATIO_MASK (3 << LSM6DSL_SENSOR_SYNC_RES_RATIO_SHIFT) +#define LSM6DSL_SENSOR_SYNC_RES_RATIO_RR_2_11 (0 << LSM6DSL_SENSOR_SYNC_RES_RATIO_SHIFT) +#define LSM6DSL_SENSOR_SYNC_RES_RATIO_RR_2_12 (1 << LSM6DSL_SENSOR_SYNC_RES_RATIO_SHIFT) +#define LSM6DSL_SENSOR_SYNC_RES_RATIO_RR_2_13 (2 << LSM6DSL_SENSOR_SYNC_RES_RATIO_SHIFT) +#define LSM6DSL_SENSOR_SYNC_RES_RATIO_RR_2_14 (3 << LSM6DSL_SENSOR_SYNC_RES_RATIO_SHIFT) + +#define LSM6DSL_FIFO_CTRL1_SHIFT 0 +#define LSM6DSL_FIFO_CTRL1_MASK (255 << LSM6DSL_FIFO_CTRL1_SHIFT) + +#define LSM6DSL_FIFO_CTRL2_SHIFT 255 +#define LSM6DSL_FIFO_CTRL2_MASK (255 << LSM6DSL_FIFO_CTRL2_SHIFT) +#define LSM6DSL_FIFO_CTRL2_FTH_8 (1 << 0) +#define LSM6DSL_FIFO_CTRL2_FTH_9 (1 << 1) +#define LSM6DSL_FIFO_CTRL2_FTH_10 (1 << 2) +#define LSM6DSL_FIFO_CTRL2_FIFO_TEMP_EN (1 << 3) +#define LSM6DSL_FIFO_CTRL2_PEDO_FIFO_DRDY (1 << 6) +#define LSM6DSL_FIFO_CTRL2_PEDO_FIFO_EN (1 << 7) + +#define LSM6DSL_FIFO_CTRL3_DEC_FIFO_XL_SHIFT 0 +#define LSM6DSL_FIFO_CTRL3_DEC_FIFO_XL_MASK (3 << LSM6DSL_FIFO_CTRL3_DEC_FIFO_XL_SHIFT) +#define LSM6DSL_FIFO_CTRL3_DEC_FIFO_GYRO_SHIFT 3 +#define LSM6DSL_FIFO_CTRL3_DEC_FIFO_GYRO_MASK (3 << LSM6DSL_FIFO_CTRL3_DEC_FIFO_GYRO_SHIFT) + +#define LSM6DSL_FIFO_CTRL4_DEC_DS3_FIFO_SHIFT 0 +#define LSM6DSL_FIFO_CTRL4_DEC_DS3_FIFO_MASK (3 << LSM6DSL_FIFO_CTRL4_DEC_DS3_FIFO_SHIFT) +#define LSM6DSL_FIFO_CTRL4_DEC_DS4_FIFO_SHIFT 3 +#define LSM6DSL_FIFO_CTRL4_DEC_DS4_FIFO_MASK (3 << LSM6DSL_FIFO_CTRL4_DEC_DS4_FIFO_SHIFT) +#define LSM6DSL_FIFO_CTRL4_ONLY_HIGH_DATA (1 << 6)/* */ +#define LSM6DSL_FIFO_CTRL4_STOP_ON_FTH (1 << 7) /* .*/ + +#define LSM6DSL_FIFO_CTRL5_FIFO_MODE_SHIFT 0 +#define LSM6DSL_FIFO_CTRL5_FIFO_MODE_MASK (3 << LSM6DSL_FIFO_CTRL5_FIFO_MODE_SHIFT) +#define LSM6DSL_FIFO_CTRL5_FMODE_BYPASS (0 << LSM6DSL_FIFO_CTRL5_FIFO_MODE_SHIFT) +#define LSM6DSL_FIFO_CTRL5_FMODE_FIFO (1 << LSM6DSL_FIFO_CTRL5_FIFO_MODE_SHIFT) +#define LSM6DSL_FIFO_CTRL5_FMODE_CONT_FIFO (3 << LSM6DSL_FIFO_CTRL5_FIFO_MODE_SHIFT) +#define LSM6DSL_FIFO_CTRL5_FMODE_BYPASS_CONT (4 << LSM6DSL_FIFO_CTRL5_FIFO_MODE_SHIFT) +#define LSM6DSL_FIFO_CTRL5_FMODE_CONT (6 << LSM6DSL_FIFO_CTRL5_FIFO_MODE_SHIFT) +#define LSM6DSL_FIFO_CTRL5_ODR_FIFO_SHIFT 3 +#define LSM6DSL_FIFO_CTRL5_ODR_FIFO_MASK (15 << LSM6DSL_FIFO_CTRL5_ODR_FIFO_SHIFT) + +#define LSM6DSL_DRDY_PULSE_CFG_G_INT2_WRIST_TILT (1 << 0) +#define LSM6DSL_DRDY_PULSE_CFG_G_DRDY_PULSED (1 << 7) + +#define LSM6DSL_INT1_CTRL_INT1_DRDY_XL (1 << 0) +#define LSM6DSL_INT1_CTRL_INT1_DRDY_G (1 << 1) +#define LSM6DSL_INT1_CTRL_INT1_BOOT (1 << 2) +#define LSM6DSL_INT1_CTRL_INT1_FTH (1 << 3) +#define LSM6DSL_INT1_CTRL_INT1_FIFO_OVT (1 << 4) +#define LSM6DSL_INT1_CTRL_INT1_FULL_FLAG (1 << 5) +#define LSM6DSL_INT1_CTRL_INT1_SIGN_MOT (1 << 6) +#define LSM6DSL_INT1_CTRL_INT1_STEP_DETECTOR (1 << 7) + +#define LSM6DSL_INT2_CTRL_INT2_DRDY_XL (1 << 0) +#define LSM6DSL_INT2_CTRL_INT2_DRDY_G (1 << 1) +#define LSM6DSL_INT2_CTRL_INT2_DRDY_TEMP (1 << 2) +#define LSM6DSL_INT2_CTRL_INT2_FTH (1 << 3) +#define LSM6DSL_INT2_CTRL_INT2_FIFO_OVT (1 << 4) +#define LSM6DSL_INT2_CTRL_INT2_FULL_FLAG (1 << 5) +#define LSM6DSL_INT2_CTRL_INT2_STEP_COUNT_OV (1 << 6) +#define LSM6DSL_INT2_CTRL_INT2_STEP_DELTA (1 << 7) + +#define LSM6DSL_FIFO_CTRL5_ODR_FIFO_MASK (15 << LSM6DSL_FIFO_CTRL5_ODR_FIFO_SHIFT) + +#define LSM6DSL_CTRL1_XL_DRDY_XL (1 << 0) +#define LSM6DSL_CTRL1_XL_SHIFT 0 +#define LSM6DSL_CTRL1_XL_BW0_XL (1 << 0) +#define LSM6DSL_CTRL1_XL_LPF1_BW_SEL (1 << 1) +#define LSM6DSL_CTRL1_XL_FS_XL_SHIFT 2 +#define LSM6DSL_CTRL1_XL_FS_XL_MASK (3 << LSM6DSL_CTRL1_XL_FS_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_FS_XL_2G (0 << LSM6DSL_CTRL1_XL_FS_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_FS_XL_16G (1 << LSM6DSL_CTRL1_XL_FS_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_FS_XL_4G (2 << LSM6DSL_CTRL1_XL_FS_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_FS_XL_8G (3 << LSM6DSL_CTRL1_XL_FS_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_ODR_XL_SHIFT 4 +#define LSM6DSL_CTRL1_XL_ODR_XL_MASK (15 << LSM6DSL_CTRL1_XL_ODR_XL_SHIFT) + +#define LSM6DSL_CTRL1_XL_ODR_XL_POWER_DOWN (0 << LSM6DSL_CTRL1_XL_ODR_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_ODR_XL_1_6HZ_12_5HZ (11 << LSM6DSL_CTRL1_XL_ODR_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_ODR_XL_12_5HZ_12_5HZ (1 << LSM6DSL_CTRL1_XL_ODR_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_ODR_XL_26HZ_26HZ (2 << LSM6DSL_CTRL1_XL_ODR_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_ODR_XL_52HZ_52HZ (3 << LSM6DSL_CTRL1_XL_ODR_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_ODR_XL_104HZ_104HZ (4 << LSM6DSL_CTRL1_XL_ODR_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_ODR_XL_208HZ_208HZ (5 << LSM6DSL_CTRL1_XL_ODR_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_ODR_XL_416HZ_416HZ (6 << LSM6DSL_CTRL1_XL_ODR_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_ODR_XL_833HZ_833HZ (7 << LSM6DSL_CTRL1_XL_ODR_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_ODR_XL_1_6kHZ_1_6kHZ (8 << LSM6DSL_CTRL1_XL_ODR_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_ODR_XL_3_3kHz_3_3kHZ (9 << LSM6DSL_CTRL1_XL_ODR_XL_SHIFT) +#define LSM6DSL_CTRL1_XL_ODR_XL_6_6kHZ_6_6kHZ (10 << LSM6DSL_CTRL1_XL_ODR_XL_SHIFT) + +#define LSM6DSL_CTRL2_G_SHIFT 0 +#define LSM6DSL_CTRL2_G_FS_125 (1 << 1) +#define LSM6DSL_CTRL2_G_FS_G_SHIFT 2 +#define LSM6DSL_CTRL2_G_FS_G_MASK (3 << LSM6DSL_CTRL2_G_FS_G_SHIFT) +#define LSM6DSL_CTRL2_G_FS_G_250DPS (0 << LSM6DSL_CTRL2_G_FS_G_SHIFT) +#define LSM6DSL_CTRL2_G_FS_G_500DPS (1 << LSM6DSL_CTRL2_G_FS_G_SHIFT) +#define LSM6DSL_CTRL2_G_FS_G_1000DPS (2 << LSM6DSL_CTRL2_G_FS_G_SHIFT) +#define LSM6DSL_CTRL2_G_FS_G_2000DPS (3 << LSM6DSL_CTRL2_G_FS_G_SHIFT) +#define LSM6DSL_CTRL2_G_ODR_G_SHIFT 4 +#define LSM6DSL_CTRL2_G_ODR_G_MASK (15 << LSM6DSL_CTRL2_G_ODR_G_SHIFT) + +#define LSM6DSL_CTRL2_G_ODR_G_POWER_DOWN (0 << LSM6DSL_CTRL2_G_ODR_G_SHIFT) +#define LSM6DSL_CTRL2_G_ODR_G_1_6HZ_12_5HZ (11 << LSM6DSL_CTRL2_G_ODR_G_SHIFT) +#define LSM6DSL_CTRL2_G_ODR_G_12_5HZ_12_5HZ (1 << LSM6DSL_CTRL2_G_ODR_G_SHIFT) +#define LSM6DSL_CTRL2_G_ODR_G_26HZ_26HZ (2 << LSM6DSL_CTRL2_G_ODR_G_SHIFT) +#define LSM6DSL_CTRL2_G_ODR_G_52HZ_52HZ (3 << LSM6DSL_CTRL2_G_ODR_G_SHIFT) +#define LSM6DSL_CTRL2_G_ODR_G_104HZ_104HZ (4 << LSM6DSL_CTRL2_G_ODR_G_SHIFT) +#define LSM6DSL_CTRL2_G_ODR_G_208HZ_208HZ (5 << LSM6DSL_CTRL2_G_ODR_G_SHIFT) +#define LSM6DSL_CTRL2_G_ODR_G_416HZ_416HZ (6 << LSM6DSL_CTRL2_G_ODR_G_SHIFT) +#define LSM6DSL_CTRL2_G_ODR_G_833HZ_833HZ (7 << LSM6DSL_CTRL2_G_ODR_G_SHIFT) +#define LSM6DSL_CTRL2_G_ODR_G_1_6kHZ_1_6kHZ (8 << LSM6DSL_CTRL2_G_ODR_G_SHIFT) +#define LSM6DSL_CTRL2_G_ODR_G_3_3kHz_3_3kHZ (9 << LSM6DSL_CTRL2_G_ODR_G_SHIFT) +#define LSM6DSL_CTRL2_G_ODR_G_6_6kHZ_6_6kHZ (10 << LSM6DSL_CTRL2_G_ODR_G_SHIFT) + +#define LSM6DSL_CTRL3_C_SHIFT 0 +#define LSM6DSL_CTRL3_C_MASK (0 << LSM6DSL_CTRL3_C_SHIFT) +#define LSM6DSL_CTRL3_C_SW_RESET (1 << 0) +#define LSM6DSL_CTRL3_C_BLE (1 << 1) +#define LSM6DSL_CTRL3_C_IF_INC (1 << 2) +#define LSM6DSL_CTRL3_C_SIM (1 << 3) +#define LSM6DSL_CTRL3_C_PP_OD (1 << 4) +#define LSM6DSL_CTRL3_C_H_LACTIVE (1 << 5) +#define LSM6DSL_CTRL3_C_BDU (1 << 6) +#define LSM6DSL_CTRL3_C_BOOT (1 << 7) + +#define LSM6DSL_CTRL4_C_LPF1_SEL_G (1 << 1) +#define LSM6DSL_CTRL4_C_I2C_disable (1 << 2) +#define LSM6DSL_CTRL4_C_DRDY_MASK (1 << 3) +#define LSM6DSL_CTRL4_C_DEN_DRDY_INT1 (1 << 4) +#define LSM6DSL_CTRL4_C_INT2_on_INT1 (1 << 5) +#define LSM6DSL_CTRL4_C_SLEEP (1 << 6) +#define LSM6DSL_CTRL4_C_DEN_XL_EN (1 << 7) + +#define LSM6DSL_CTRL5_C_SHIFT 0 +#define LSM6DSL_CTRL5_C_ST_XL_MASK (3 << LSM6DSL_CTRL5_C_SHIFT) +#define LSM6DSL_CTRL5_C_ST_G_SHIFT 2 +#define LSM6DSL_CTRL5_C_ST_G_MASK (3 << LSM6DSL_CTRL5_C_ST_G_SHIFT) +#define LSM6DSL_CTRL5_C_DEN_LH (1 << 4) +#define LSM6DSL_CTRL5_C_ROUNDING_SHIFT 2 +#define LSM6DSL_CTRL5_C_ROUNDING_MASK (7 << LSM6DSL_CTRL5_C_ROUNDING_SHIFT) + +#define LSM6DSL_CTRL6_C_SHIFT 0 +#define LSM6DSL_CTRL6_C_FTYPE_MASK (3 << LSM6DSL_CTRL6_C_SHIFT) +#define LSM6DSL_CTRL6_C_USR_OFF_W (1 << 3) +#define LSM6DSL_CTRL6_C_XL_HM_MODE (1 << 4) +#define LSM6DSL_CTRL6_C_LVL2_EN (1 << 5) +#define LSM6DSL_CTRL6_C_LEL_EN (1 << 6) +#define LSM6DSL_CTRL6_C_TRIG_EN (1 << 7) + +#define LSM6DSL_CTRL7_G_SHIFT 0 +#define LSM6DSL_CTRL7_G_MASK (0 << LSM6DSL_CTRL7_G_SHIFT) +#define LSM6DSL_CTRL7_G_ROUNDING_STATUS (1 << 2) +#define LSM6DSL_CTRL7_G_HPM0_G (1 << 4) +#define LSM6DSL_CTRL7_G_HPM1_G (1 << 5) +#define LSM6DSL_CTRL7_G_HP_EN_G (1 << 6) +#define LSM6DSL_CTRL7_G_G_HM_MODE (1 << 7) + +#define LSM6DSL_CTRL8_XL_LOW_PASS_ON_6D (1 << 0) +#define LSM6DSL_CTRL8_XL_HP_SLOPE_XL_EN (1 << 2) +#define LSM6DSL_CTRL8_XL_INPUT_COMPOSITE (1 << 3) +#define LSM6DSL_CTRL8_XL_HP_REF_MODE (1 << 4) +#define LSM6DSL_CTRL8_XL_HPCF_XL_SHIFT 5 +#define LSM6DSL_CTRL8_XL_HPCF_XL_MASK (3 << LSM6DSL_CTRL8_XL_HPCF_XL_SHIFT) +#define LSM6DSL_CTRL8_XL_LPF2_XL_EN (1 << 7) + +#define LSM6DSL_CTRL9_XL_SOFT_EN (1 << 2) +#define LSM6DSL_CTRL9_XL_DEN_XL_G (1 << 4) +#define LSM6DSL_CTRL9_XL_DEN_Z (1 << 5) +#define LSM6DSL_CTRL9_XL_DEN_Y (1 << 6) +#define LSM6DSL_CTRL9_XL_DEN_X (1 << 7) + +#define LSM6DSL_CTRL10_C_SIGN_MOTION_EN (1 << 0) +#define LSM6DSL_CTRL10_C_PEDO_RST_STEP (1 << 1) +#define LSM6DSL_CTRL10_C_FUNC_EN (1 << 2) +#define LSM6DSL_CTRL10_C_TILT_EN (1 << 3) +#define LSM6DSL_CTRL10_C_PEDO_EN (1 << 4) +#define LSM6DSL_CTRL10_C_TIMER_EN (1 << 5) +#define LSM6DSL_CTRL10_C_WRIST_TILT_EN (1 << 7) + +#define LSM6DSL_MASTER_CONFIG_MASTER_ON (1 << 0) +#define LSM6DSL_MASTER_CONFIG_IRON_EN (1 << 1) +#define LSM6DSL_MASTER_CONFIG_PASS_THROUGH_MODE (1 << 2) +#define LSM6DSL_MASTER_CONFIG_PULL_UP_EN (1 << 3) +#define LSM6DSL_MASTER_CONFIG_START_CONFIG (1 << 4) +#define LSM6DSL_MASTER_CONFIG_DATA_VALID_SEL_FIFO (1 << 6) +#define LSM6DSL_MASTER_CONFIG_RDY_ON_INT1 (1 << 7) + +#define LSM6DSL_WAKE_UP_SRC_Z_WU (1 << 0) +#define LSM6DSL_WAKE_UP_SRC_Y_WU (1 << 1) +#define LSM6DSL_WAKE_UP_SRC_X_WU (1 << 2) +#define LSM6DSL_WAKE_UP_SRC_WU_IA (1 << 3) +#define LSM6DSL_WAKE_UP_SRC_SLEEP_STATE_IA (1 << 4) +#define LSM6DSL_WAKE_UP_SRC_FF_IA (1 << 5) + +#define LSM6DSL_TAP_SRC_Z_TAP (1 << 0) +#define LSM6DSL_TAP_SRC_Y_TAP (1 << 1) +#define LSM6DSL_TAP_SRC_X_TAP (1 << 2) +#define LSM6DSL_TAP_SRC_TAP_SIGN (1 << 3) +#define LSM6DSL_TAP_SRC_DOUBLE_TAP (1 << 4) +#define LSM6DSL_TAP_SRC_SINGLE_TAP (1 << 5) +#define LSM6DSL_TAP_SRC_TAP_IA (1 << 6) + +#define LSM6DSL_D6D_SRC_XL (1 << 0) +#define LSM6DSL_D6D_SRC_XH (1 << 1) +#define LSM6DSL_D6D_SRC_YL (1 << 2) +#define LSM6DSL_D6D_SRC_YH (1 << 3) +#define LSM6DSL_D6D_SRC_ZL (1 << 4) +#define LSM6DSL_D6D_SRC_ZH (1 << 5) +#define LSM6DSL_D6D_SRC_D6D_IA (1 << 6) +#define LSM6DSL_D6D_SRC_DEN_DRDY (1 << 7) + +#define LSM6DSL_STATUS_REG_SHIFT 0 +#define LSM6DSL_STATUS_REG_MASK (0 << LSM6DSL_STATUS_REG_SHIFT) +#define LSM6DSL_STATUS_REG_XLDA (1 << 0) +#define LSM6DSL_STATUS_REG_GDA (1 << 1) +#define LSM6DSL_STATUS_REG_TDA (1 << 2) + +#define LSM6DSL_CTRL5_C_SHIFT 0 +#define LSM6DSL_CTRL5_C_ST_XL_MASK (3 << LSM6DSL_CTRL5_C_SHIFT) + +#define LSM6DSL_OUT_TEMP_L_TEMP_SHIFT 0 +#define LSM6DSL_OUT_TEMP_L_TEMP_MASK (255 << LSM6DSL_OUT_TEMP_L_TEMP_SHIFT) +#define LSM6DSL_OUT_TEMP_H_TEMP_SHIFT 0 +#define LSM6DSL_OUT_TEMP_H_TEMP_MASK (255 << LSM6DSL_OUT_TEMP_H_TEMP_SHIFT) + +#define LSM6DSL_OUTX_L_G_SHIFT 0 +#define LSM6DSL_OUTX_L_G_MASK (255 << LSM6DSL_OUTX_L_G_SHIFT) + +#define LSM6DSL_OUTX_H_G_SHIFT 0 +#define LSM6DSL_OUTX_H_G_MASK (255 << LSM6DSL_OUTX_H_G_SHIFT) + +#define LSM6DSL_OUTY_L_G_SHIFT 0 +#define LSM6DSL_OUTY_L_G_MASK (255 << LSM6DSL_OUTY_L_G_SHIFT) + +#define LSM6DSL_OUTY_H_G_SHIFT 0 +#define LSM6DSL_OUTY_H_G_MASK (255 << LSM6DSL_OUTY_H_G_SHIFT) + +#define LSM6DSL_OUTZ_L_G_SHIFT 0 +#define LSM6DSL_OUTZ_L_G_MASK (255 << LSM6DSL_OUTZ_L_G_SHIFT) + +#define LSM6DSL_OUTZ_H_G_SHIFT 0 +#define LSM6DSL_OUTZ_H_G_MASK (255 << LSM6DSL_OUTZ_H_G_SHIFT) + +#define LSM6DSL_OUTX_L_XL_SHIFT 0 +#define LSM6DSL_OUTX_L_XL_MASK (255 << LSM6DSL_OUTX_L_XL_SHIFT) + +#define LSM6DSL_OUTX_H_XL_SHIFT 0 +#define LSM6DSL_OUTX_H_XL_MASK (255 << LSM6DSL_OUTX_H_XL_SHIFT) + +#define LSM6DSL_OUTY_L_XL_SHIFT 0 +#define LSM6DSL_OUTY_L_XL_MASK (255 << LSM6DSL_OUTY_L_XL_SHIFT) + +#define LSM6DSL_OUTY_H_XL_SHIFT 0 +#define LSM6DSL_OUTY_H_XL_MASK (255 << LSM6DSL_OUTY_H_XL_SHIFT) + +#define LSM6DSL_OUTZ_L_XL_SHIFT 0 +#define LSM6DSL_OUTZ_L_XL_MASK (255 << LSM6DSL_OUTZ_L_XL_SHIFT) + +#define LSM6DSL_OUTZ_H_XL_SHIFT 0 +#define LSM6DSL_OUTZ_H_XL_MASK (255 << LSM6DSL_OUTZ_H_XL_SHIFT) + +#define LSM6DSL_SENSORHUB1_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB1_REG_MASK (255 << LSM6DSL_SENSORHUB1_REG_SHIFT) + +#define LSM6DSL_SENSORHUB2_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB2_REG_MASK (255 << LSM6DSL_SENSORHUB2_REG_SHIFT) + +#define LSM6DSL_SENSORHUB3_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB3_REG_MASK (255 << LSM6DSL_SENSORHUB3_REG_SHIFT) + +#define LSM6DSL_SENSORHUB4_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB4_REG_MASK (255 << LSM6DSL_SENSORHUB4_REG_SHIFT) + +#define LSM6DSL_SENSORHUB5_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB5_REG_MASK (255 << LSM6DSL_SENSORHUB5_REG_SHIFT) + +#define LSM6DSL_SENSORHUB6_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB6_REG_MASK (255 << LSM6DSL_SENSORHUB6_REG_SHIFT) + +#define LSM6DSL_SENSORHUB7_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB7_REG_MASK (255 << LSM6DSL_SENSORHUB7_REG_SHIFT) + +#define LSM6DSL_SENSORHUB8_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB8_REG_MASK (255 << LSM6DSL_SENSORHUB8_REG_SHIFT) + +#define LSM6DSL_SENSORHUB9_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB9_REG_MASK (255 << LSM6DSL_SENSORHUB9_REG_SHIFT) + +#define LSM6DSL_SENSORHUB10_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB10_REG_MASK (255 << LSM6DSL_SENSORHUB10_REG_SHIFT) + +#define LSM6DSL_SENSORHUB11_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB11_REG_MASK (255 << LSM6DSL_SENSORHUB11_REG_SHIFT) + +#define LSM6DSL_SENSORHUB12_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB12_REG_MASK (255 << LSM6DSL_SENSORHUB12_REG_SHIFT) + +#define LSM6DSL_FIFO_STATUS1_SHIFT 0 +#define LSM6DSL_FIFO_STATUS1_MASK (255 << LSM6DSL_FIFO_STATUS1_SHIFT) + +#define LSM6DSL_FIFO_STATUS2_DIFF_FIFO_SHIFT 0 +#define LSM6DSL_FIFO_STATUS2_DIFF_FIFO_MASK (7 << LSM6DSL_FIFO_STATUS2_DIFF_FIFO_SHIFT) +#define LSM6DSL_FIFO_STATUS2_FIFO_EMPTY (1 << 1) +#define LSM6DSL_FIFO_STATUS2_FIFO_FULL_ART (1 << 1) +#define LSM6DSL_FIFO_STATUS2_OVER_RUN (1 << 2) +#define LSM6DSL_FIFO_STATUS2_WaterM (1 << 3) + +#define LSM6DSL_FIFO_STATUS3_SHIFT 0 +#define LSM6DSL_FIFO_STATUS3_MASK (255 << LSM6DSL_FIFO_STATUS3_SHIFT) + +#define LSM6DSL_FIFO_STATUS4_SHIFT 0 +#define LSM6DSL_FIFO_STATUS4_MASK (3 << LSM6DSL_FIFO_STATUS4_SHIFT) + +#define LSM6DSL_FIFO_DATA_OUT_L_SHIFT 0 +#define LSM6DSL_FIFO_DATA_OUT_L_MASK (255 << LSM6DSL_FIFO_DATA_OUT_L_SHIFT) + +#define LSM6DSL_FIFO_DATA_OUT_H_SHIFT 0 +#define LSM6DSL_FIFO_DATA_OUT_H_MASK (255 << LSM6DSL_FIFO_DATA_OUT_H_SHIFT) + +#define LSM6DSL_TIMESTAMP0_REG_SHIFT 0 +#define LSM6DSL_TIMESTAMP0_REG_MASK (255 << LSM6DSL_TIMESTAMP0_REG_SHIFT) + +#define LSM6DSL_TIMESTAMP1_REG_SHIFT 0 +#define LSM6DSL_TIMESTAMP1_REG_MASK (255 << LSM6DSL_TIMESTAMP1_REG_SHIFT) + +#define LSM6DSL_TIMESTAMP2_REG_SHIFT 0 +#define LSM6DSL_TIMESTAMP2_REG_MASK (255 << LSM6DSL_TIMESTAMP2_REG_SHIFT) + +#define LSM6DSL_STEP_TIMESTAMP_L_SHIFT 0 +#define LSM6DSL_STEP_TIMESTAMP_L_MASK (255 << LSM6DSL_STEP_TIMESTAMP_L_SHIFT) + +#define LSM6DSL_STEP_TIMESTAMP_H_SHIFT 0 +#define LSM6DSL_STEP_TIMESTAMP_H_MASK (255 << LSM6DSL_STEP_TIMESTAMP_H_SHIFT) + +#define LSM6DSL_STEP_COUNTER_L_SHIFT 0 +#define LSM6DSL_STEP_COUNTER_L_MASK (255 << LSM6DSL_STEP_COUNTER_L_SHIFT) + +#define LSM6DSL_SENSORHUB13_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB13_REG_MASK (255 << LSM6DSL_SENSORHUB13_REG_SHIFT) + +#define LSM6DSL_SENSORHUB14_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB14_REG_MASK (255 << LSM6DSL_SENSORHUB14_REG_SHIFT) + +#define LSM6DSL_SENSORHUB15_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB15_REG_MASK (255 << LSM6DSL_SENSORHUB15_REG_SHIFT) + +#define LSM6DSL_SENSORHUB16_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB16_REG_MASK (255 << LSM6DSL_SENSORHUB16_REG_SHIFT) + +#define LSM6DSL_SENSORHUB17_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB17_REG_MASK (255 << LSM6DSL_SENSORHUB17_REG_SHIFT) + +#define LSM6DSL_SENSORHUB18_REG_SHIFT 0 +#define LSM6DSL_SENSORHUB18_REG_MASK (255 << LSM6DSL_SENSORHUB18_REG_SHIFT) + +#define LSM6DSL_FUNC_SRC1_SENSORHUB_END_OP (1 << 0) +#define LSM6DSL_FUNC_SRC1_SI_END_OP (1 << 1) +#define LSM6DSL_FUNC_SRC1_HI_FAIL (1 << 2) +#define LSM6DSL_FUNC_SRC1_STEP_OVERFLOW (1 << 3) +#define LSM6DSL_FUNC_SRC1_STEP_DETECTED (1 << 4) +#define LSM6DSL_FUNC_SRC1_TILT_IA (1 << 5) +#define LSM6DSL_FUNC_SRC1_SIGN_MOTION_IA (1 << 6) +#define LSM6DSL_FUNC_SRC1_STEP_COUNT_DELTA_IA (1 << 7) + +#define LSM6DSL_FUNC_SRC2_WRIST_TILT_IA (1 << 0) +#define LSM6DSL_FUNC_SRC2_SLAVE0_NACK (1 << 3) +#define LSM6DSL_FUNC_SRC2_SLAVE1_NACK (1 << 4) +#define LSM6DSL_FUNC_SRC2_SLAVE2_NACK (1 << 5) +#define LSM6DSL_FUNC_SRC2_SLAVE3_NACK (1 << 6) + +#define LSM6DSL_WRIST_TILT_IA_SHIFT 2 +#define LSM6DSL_WRIST_TILT_IA_MASK (63 << LSM6DSL_WRIST_TILT_IA_SHIFT) + +#define LSM6DSL_TAP_CFG_LIR (1 << 0) +#define LSM6DSL_TAP_CFG_TAP_Z_EN (1 << 1) +#define LSM6DSL_TAP_CFG_TAP_Y_EN (1 << 2) +#define LSM6DSL_TAP_CFG_TAP_X_EN (1 << 3) +#define LSM6DSL_TAP_CFG_SLOPE_FDS (1 << 4) +#define LSM6DSL_TAP_CFG_INACT_EN_SHIFT 2 +#define LSM6DSL_TAP_CFG_INACT_EN_MASK (3 << LSM6DSL_TAP_CFG_INACT_EN_SHIFT) +#define LSM6DSL_TAP_CFG_INTERRUPTS_ENABLE (1 << 7) + +#define LSM6DSL_TAP_THS_6D_TAP_THS_SHIFT 0 +#define LSM6DSL_TAP_THS_6D_TAP_THS_MASK (31 << LSM6DSL_TAP_THS_6D_TAP_THS_SHIFT) +#define LSM6DSL_TAP_THS_6D_SIXD_THS_SHIFT 5 +#define LSM6DSL_TAP_THS_6D_SIXD_THS_MASK (3 << LSM6DSL_TAP_THS_6D_SIXD_THS_SHIFT) +#define LSM6DSL_TAP_THS_6D_SIXD_THS_80DEGR (0 << LSM6DSL_TAP_THS_6D_SIXD_THS_SHIFT) +#define LSM6DSL_TAP_THS_6D_SIXD_THS_70DEGR (1 << LSM6DSL_TAP_THS_6D_SIXD_THS_SHIFT) +#define LSM6DSL_TAP_THS_6D_SIXD_THS_60DEGR (2 << LSM6DSL_TAP_THS_6D_SIXD_THS_SHIFT) +#define LSM6DSL_TAP_THS_6D_SIXD_THS_50DEGR (3 << LSM6DSL_TAP_THS_6D_SIXD_THS_SHIFT) +#define LSM6DSL_TAP_THS_6D_D4D_EN (1 << 7) + +#define LSM6DSL_INT_DUR2_SHOCK_SHIFT 0 +#define LSM6DSL_INT_DUR2_SHOCK_MASK (3 << LSM6DSL_INT_DUR2_SHOCK_SHIFT) +#define LSM6DSL_INT_DUR2_QUIET_SHIFT 2 +#define LSM6DSL_INT_DUR2_QUIET_MASK (3 << LSM6DSL_INT_DUR2_QUIET_SHIFT) +#define LSM6DSL_INT_DUR2_DUR_SHIFT 4 +#define LSM6DSL_INT_DUR2_DUR_MASK (7 << LSM6DSL_INT_DUR2_QUIET_SHIFT) + +#define LSM6DSL_WAKE_UP_THS_WK_THS_SHIFT 0 +#define LSM6DSL_WAKE_UP_THS_WK_THS_MASK (31 << LSM6DSL_WAKE_UP_THS_WK_THS_SHIFT) +#define LSM6DSL_WAKE_UP_THS_SINGLE_DOUBLE_TAP4D_EN (1 << 7) + +#define LSM6DSL_WAKE_UP_DUR_SLEEP_DUR_SHIFT 0 +#define LSM6DSL_WAKE_UP_DUR_SLEEP_DUR_MASK (15 << LSM6DSL_WAKE_UP_DUR_SLEEP_DUR_SHIFT) +#define LSM6DSL_WAKE_UP_DUR_TIMER_HR (1 << 4) +#define LSM6DSL_WAKE_UP_DUR_WAKE_DUR_SHIFT 5 +#define LSM6DSL_WAKE_UP_DUR_WAKE_DUR_MASK (15 << LSM6DSL_WAKE_UP_DUR_WAKE_DUR_SHIFT) +#define LSM6DSL_WAKE_UP_DUR_FF_DUR5 (1 << 7) + +#define LSM6DSL_FREE_FALL_FF_THS_SHIFT 0 +#define LSM6DSL_FREE_FALL_FF_THS_MASK (7 << LSM6DSL_FREE_FALL_FF_THS_SHIFT) +#define LSM6DSL_FREE_FALL_FF_DUR_SHIFT 4 +#define LSM6DSL_FREE_FALL_FF_DUR_MASK (31 << LSM6DSL_FREE_FALL_FF_DUR_SHIFT) + +#define LSM6DSL_MD1_CFG_INT1_TIMER (1 << 0) +#define LSM6DSL_MD1_CFG_INT1_TILT (1 << 1) +#define LSM6DSL_MD1_CFG_INT1_6D (1 << 2) +#define LSM6DSL_MD1_CFG_INT1_DOUBLE_TAP (1 << 3) +#define LSM6DSL_MD1_CFG_INT1_FF (1 << 4) +#define LSM6DSL_MD1_CFG_INT1_WU (1 << 5) +#define LSM6DSL_MD1_CFG_INT1_SINGLE_TAP (1 << 6) +#define LSM6DSL_MD1_CFG_INT1_INACT_STATE (1 << 7) + +#define LSM6DSL_MD2_CFG_INT1_IRON (1 << 0) +#define LSM6DSL_MD2_CFG_INT1_TILT (1 << 1) +#define LSM6DSL_MD2_CFG_INT1_6D (1 << 2) +#define LSM6DSL_MD2_CFG_INT1_DOUBLE_TAP (1 << 3) +#define LSM6DSL_MD2_CFG_INT1_FF (1 << 4) +#define LSM6DSL_MD2_CFG_INT1_WU (1 << 5) +#define LSM6DSL_MD2_CFG_INT1_SINGLE_TAP (1 << 6) +#define LSM6DSL_MD2_CFG_INT1_INACT_STATE (1 << 7) + +#define LSM6DSL_MASTER_CMD_CODE_SHIFT 0 +#define LSM6DSL_MASTER_CMD_CODE_MASK (255 << LSM6DSL_MASTER_CMD_CODE_SHIFT) + +#define LSM6DSL_SENS_SYNC_SPI_ERROR_CODE_SHIFT 0 +#define LSM6DSL_SENS_SYNC_SPI_ERROR_CODE_MASK (255 << LSM6DSL_SENS_SYNC_SPI_ERROR_CODE_SHIFT) + +#define LSM6DSL_OUT_MAG_RAW_X_L_SHIFT 0 +#define LSM6DSL_OUT_MAG_RAW_X_L_MASK (255 << LSM6DSL_OUT_MAG_RAW_X_L_SHIFT) + +#define LSM6DSL_OUT_MAG_RAW_X_H_SHIFT 0 +#define LSM6DSL_OUT_MAG_RAW_X_H_MASK (255 << LSM6DSL_OUT_MAG_RAW_X_H_SHIFT) + +#define LSM6DSL_OUT_MAG_RAW_Y_L_SHIFT 0 +#define LSM6DSL_OUT_MAG_RAW_Y_L_MASK (255 << LSM6DSL_OUT_MAG_RAW_Y_L_SHIFT) + +#define LSM6DSL_OUT_MAG_RAW_Y_H_SHIFT 0 +#define LSM6DSL_OUT_MAG_RAW_Y_H_MASK (255 << LSM6DSL_OUT_MAG_RAW_Y_H_SHIFT) + +#define LSM6DSL_OUT_MAG_RAW_Z_L_SHIFT 0 +#define LSM6DSL_OUT_MAG_RAW_Z_L_MASK (255 << LSM6DSL_OUT_MAG_RAW_Z_L_SHIFT) + +#define LSM6DSL_OUT_MAG_RAW_Z_H_SHIFT 0 +#define LSM6DSL_OUT_MAG_RAW_Z_H_MASK (255 << LSM6DSL_OUT_MAG_RAW_Z_H_SHIFT) + +#define LSM6DSL_X_OFS_USR_SHIFT 0 +#define LSM6DSL_X_OFS_USR_MASK (255 << LSM6DSL_X_OFS_USR_SHIFT) + +#define LSM6DSL_Y_OFS_USR_SHIFT 0 +#define LSM6DSL_Y_OFS_USR_MASK (255 << LSM6DSL_Y_OFS_USR_SHIFT) + +#define LSM6DSL_Z_OFS_USR_SHIFT 0 +#define LSM6DSL_Z_OFS_USR_MASK (255 << LSM6DSL_Z_OFS_USR_SHIFT) + +/* Embedded functions registers description - Bank A */ + +#define LSM6DSL_SLV0_ADD_rw_0 (1 << 0) +#define LSM6DSL_SLV0_ADD_Slave0_add_SHIFT 1 +#define LSM6DSL_SLV0_ADD_Slave0_add_MASK (127 << LSM6DSL_SLV0_ADD_Slave0_add_SHIFT) + +#define LSM6DSL_SLV0_SUBADD_SHIFT 0 +#define LSM6DSL_SLV0_SUBADD_MASK (255 << LSM6DSL_SLV0_SUBADD_SHIFT) + +#define LSM6DSL_SLAVE0_CONFIG_Slave0_numop_SHIFT 0 +#define LSM6DSL_SLAVE0_CONFIG_Slave0_numop_MASK (7 << LSM6DSL_SLAVE0_CONFIG_Slave0_numop_SHIFT) +#define LSM6DSL_SLAVE0_CONFIG_Src_mode (1 << 3) +#define LSM6DSL_SLAVE0_CONFIG_Aux_sens_on_SHIFT 4 +#define LSM6DSL_SLAVE0_CONFIG_Aux_sens_on_MASK (3 << LSM6DSL_SLAVE0_CONFIG_Aux_sens_on_SHIFT) +#define LSM6DSL_SLAVE0_CONFIG_Slave0_rate_SHIFT 6 +#define LSM6DSL_SLAVE0_CONFIG_Slave0_rate_MASK (3 << LSM6DSL_SLAVE0_CONFIG_Slave0_rate_SHIFT) + +#define LSM6DSL_SLV1_ADD_r_1 (1 << 0) +#define LSM6DSL_SLV1_ADD_Slave1_add_SHIFT 1 +#define LSM6DSL_SLV1_ADD_Slave1_add_MASK (127 << LSM6DSL_SLV1_ADD_Slave1_add_SHIFT) + +#define LSM6DSL_SLV1_SUBADD_SHIFT 0 +#define LSM6DSL_SLV1_SUBADD_MASK (255 << LSM6DSL_SLV1_SUBADD_SHIFT) + +#define LSM6DSL_SLAVE1_CONFIG_Slave1_numop_SHIFT 0 +#define LSM6DSL_SLAVE1_CONFIG_Slave1_numop_MASK (7 << LSM6DSL_SLAVE1_CONFIG_Slave1_numop_SHIFT) +#define LSM6DSL_SLAVE1_CONFIG_write_once (1 << 5) +#define LSM6DSL_SLAVE1_CONFIG_Slave1_rate_SHIFT 6 +#define LSM6DSL_SLAVE1_CONFIG_Slave1_rate_MASK (3 << LSM6DSL_SLAVE1_CONFIG_Slave1_rate_SHIFT) + +#define LSM6DSL_SLV2_ADD_r_2 (1 << 0) +#define LSM6DSL_SLV2_ADD_Slave2_add_SHIFT 1 +#define LSM6DSL_SLV2_ADD_Slave2_add_MASK (127 << LSM6DSL_SLV2_ADD_Slave2_add_SHIFT) + +#define LSM6DSL_SLV2_SUBADD_SHIFT 0 +#define LSM6DSL_SLV2_SUBADD_MASK (255 << LSM6DSL_SLV2_SUBADD_SHIFT) + +#define LSM6DSL_SLAVE2_CONFIG_Slave2_numop_SHIFT 0 +#define LSM6DSL_SLAVE2_CONFIG_Slave2_numop_MASK (7 << LSM6DSL_SLAVE1_CONFIG_Slave1_numop_SHIFT) +#define LSM6DSL_SLAVE2_CONFIG_Slave2_rate_SHIFT 6 +#define LSM6DSL_SLAVE2_CONFIG_Slave2_rate_MASK (3 << LSM6DSL_SLAVE1_CONFIG_Slave1_rate_SHIFT) + +#define LSM6DSL_SLV3_ADD_r_3 (1 << 0) +#define LSM6DSL_SLV3_ADD_Slave3_add_SHIFT 1 +#define LSM6DSL_SLV3_ADD_Slave3_add_MASK (127 << LSM6DSL_SLV3_ADD_Slave3_add_SHIFT) + +#define LSM6DSL_SLV3_SUBADD_SHIFT 0 +#define LSM6DSL_SLV3_SUBADD_MASK (255 << LSM6DSL_SLV2_SUBADD_SHIFT) + +#define LSM6DSL_SLAVE3_CONFIG_Slave3_numop_SHIFT 0 +#define LSM6DSL_SLAVE3_CONFIG_Slave3_numop_MASK (7 << LSM6DSL_SLAVE1_CONFIG_Slave1_numop_SHIFT) +#define LSM6DSL_SLAVE3_CONFIG_Slave3_rate_SHIFT 6 +#define LSM6DSL_SLAVE3_CONFIG_Slave3_rate_MASK (3 << LSM6DSL_SLAVE1_CONFIG_Slave1_rate_SHIFT) + +#define LSM6DSL_DATAWRITE_SRC_MODE_SUB_SLV0_SHIFT 0 +#define LSM6DSL_DATAWRITE_SRC_MODE_SUB_SLV0_MASK (255 << LSM6DSL_DATAWRITE_SRC_MODE_SUB_SLV0_SHIFT) + +#define LSM6DSL_CONFIG_PEDO_THS_MIN_ths_min_SHIFT 0 +#define LSM6DSL_CONFIG_PEDO_THS_MIN_ths_min_MASK (31 << LSM6DSL_CONFIG_PEDO_THS_MIN_ths_min_SHIFT) +#define LSM6DSL_CONFIG_PEDO_THS_MIN_PEDO_FS (1 << 7> + +#define LSM6DSL_SM_THS_SHIFT 0 +#define LSM6DSL_SM_THS_MASK (255 << LSM6DSL_SM_THS_SHIFT) + +#define LSM6DSL_PEDO_DEB_REG_DEB_STEP_SHIFT 0 +#define LSM6DSL_PEDO_DEB_REG_DEB_STEP_MASK (7 << LSM6DSL_PEDO_DEB_REG_DEB_STEP_SHIFT) +#define LSM6DSL_PEDO_DEB_REG_DEB_TIME_SHIFT 3 +#define LSM6DSL_PEDO_DEB_REG_DEB_TIME_MASK (31 << LSM6DSL_PEDO_DEB_REG_DEB_TIME_SHIFT) + +#define LSM6DSL_STEP_COUNT_DELTA_SHIFT 0 +#define LSM6DSL_STEP_COUNT_DELTA_MASK (255 << LSM6DSL_STEP_COUNT_DELTA_SHIFT) + +#define LSM6DSL_MAG_SI_XX_SHIFT 0 +#define LSM6DSL_MAG_SI_XX_MASK (255 << LSM6DSL_MAG_SI_XX_SHIFT) + +#define LSM6DSL_MAG_SI_XY_SHIFT 0 +#define LSM6DSL_MAG_SI_XY_MASK (255 << LSM6DSL_MAG_SI_XY_SHIFT) + +#define LSM6DSL_MAG_SI_XZ_SHIFT 0 +#define LSM6DSL_MAG_SI_XZ_MASK (255 << LSM6DSL_MAG_SI_XZ_SHIFT) + +#define LSM6DSL_MAG_SI_YX_SHIFT 0 +#define LSM6DSL_MAG_SI_YX_MASK (255 << LSM6DSL_MAG_SI_YX_SHIFT) + +#define LSM6DSL_MAG_SI_YY_SHIFT 0 +#define LSM6DSL_MAG_SI_YY_MASK (255 << LSM6DSL_MAG_SI_YY_SHIFT) + +#define LSM6DSL_MAG_SI_YZ_SHIFT 0 +#define LSM6DSL_MAG_SI_YZ_MASK (255 << LSM6DSL_MAG_SI_YZ_SHIFT) + +#define LSM6DSL_MAG_SI_ZX_SHIFT 0 +#define LSM6DSL_MAG_SI_ZX_MASK (255 << LSM6DSL_MAG_SI_ZX_SHIFT) + +#define LSM6DSL_MAG_SI_ZY_SHIFT 0 +#define LSM6DSL_MAG_SI_ZY_MASK (255 << LSM6DSL_MAG_SI_ZY_SHIFT) + +#define LSM6DSL_MAG_SI_ZZ_SHIFT 0 +#define LSM6DSL_MAG_SI_ZZ_MASK (255 << LSM6DSL_MAG_SI_ZZ_SHIFT) + +#define LSM6DSL_MAG_OFFX_L_SHIFT 0 +#define LSM6DSL_MAG_OFFX_L_MASK (255 << LSM6DSL_MAG_OFFX_L_SHIFT) + +#define LSM6DSL_MAG_OFFX_H_SHIFT 0 +#define LSM6DSL_MAG_OFFX_H_MASK (255 << LSM6DSL_MAG_OFFX_H_SHIFT) + +#define LSM6DSL_MAG_OFFY_L_SHIFT 0 +#define LSM6DSL_MAG_OFFY_L_MASK (255 << LSM6DSL_MAG_OFFY_L_SHIFT) + +#define LSM6DSL_MAG_OFFY_H_SHIFT 0 +#define LSM6DSL_MAG_OFFY_H_MASK (255 << LSM6DSL_MAG_OFFY_H_SHIFT) + +#define LSM6DSL_MAG_OFFZ_L_SHIFT 0 +#define LSM6DSL_MAG_OFFZ_L_MASK (255 << LSM6DSL_MAG_OFFZ_L_SHIFT) + +#define LSM6DSL_MAG_OFFZ_H_SHIFT 0 +#define LSM6DSL_MAG_OFFZ_H_MASK (255 << LSM6DSL_MAG_OFFZ_H_SHIFT) + +/* Embedded functions registers description - Bank B */ + +#define LSM6DSL_A_WRIST_TILT_LAT_SHIFT 0 +#define LSM6DSL_A_WRIST_TILT_LAT_MASK (255 << LSM6DSL_A_WRIST_TILT_LAT_SHIFT) + +#define LSM6DSL_A_WRIST_TILT_THS_SHIFT 0 +#define LSM6DSL_A_WRIST_TILT_THS_MASK (255 << LSM6DSL_A_WRIST_TILT_THS_SHIFT) + +#define LSM6DSL_A_WRIST_TILT_Mask_SHIFT 2 +#define LSM6DSL_A_WRIST_TILT_Mask_MASK (63 << LSM6DSL_A_WRIST_TILT_Mask_SHIFT) + +/**************************************************************************************************** + * Public Types + ****************************************************************************************************/ + +struct i2c_master_s; + +/* Container for sensor data */ + +struct lsm6dsl_sensor_data_s +{ + int16_t x_data; + int16_t y_data; + int16_t z_data; + uint16_t temperature; + int16_t g_x_data; + int16_t g_y_data; + int16_t g_z_data; + uint16_t timestamp; +}; + +/**************************************************************************************************** + * Private Types + ****************************************************************************************************/ + +struct lsm6dsl_dev_s; +struct lsm6dsl_ops_s +{ + CODE int (*config)(FAR struct lsm6dsl_dev_s *priv); + CODE int (*start)(FAR struct lsm6dsl_dev_s *priv); + CODE int (*stop)(FAR struct lsm6dsl_dev_s *priv); + CODE int (*sensor_read)(FAR struct lsm6dsl_dev_s *priv, + FAR struct lsm6dsl_sensor_data_s *sensor_data); + CODE int (*selftest)(FAR struct lsm6dsl_dev_s *priv, + uint32_t mode); +}; + +struct lsm6dsl_dev_s +{ + FAR struct i2c_master_s *i2c; /* I2C interface */ + uint8_t addr; /* I2C address */ + + FAR const struct lsm6dsl_ops_s *ops; + + uint8_t datareg; /* Output data register of X low byte */ + struct lsm6dsl_sensor_data_s sensor_data; /* Sensor data container */ +}; + +/**************************************************************************************************** + * Public Function Prototypes + ****************************************************************************************************/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/**************************************************************************************************** + * Name: lsm6dslaccel_register + * + * Description: + * Register the LSM6DSL accelerometer character device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register, e.g., "/dev/sensor0". + * 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 lsm6dsl_sensor_register(FAR const char *devpath, + FAR struct i2c_master_s *i2c, + uint8_t addr); + +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_I2C && CONFIG_SENSORS_LSM9DS1 */ +#endif /* __INCLUDE_NUTTX_SENSORS_LSM9DS1 */