You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by GitBox <gi...@apache.org> on 2018/04/18 21:43:03 UTC
[GitHub] vrahane closed pull request #1018: Sensors/BMA2XX - New PR from PR
#699 comments
vrahane closed pull request #1018: Sensors/BMA2XX - New PR from PR #699 comments
URL: https://github.com/apache/mynewt-core/pull/1018
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/apps/sensors_test/src/main.c b/apps/sensors_test/src/main.c
index 87c08eb48..0f270bda9 100644
--- a/apps/sensors_test/src/main.c
+++ b/apps/sensors_test/src/main.c
@@ -44,6 +44,9 @@
#if MYNEWT_VAL(BMA253_CLI)
#include <bma253/bma253.h>
#endif
+#if MYNEWT_VAL(BMA2XX_CLI)
+#include <bma2xx/bma2xx.h>
+#endif
#if MYNEWT_VAL(BME280_CLI)
#include <bme280/bme280.h>
#endif
@@ -421,6 +424,9 @@ sensors_dev_shell_init(void)
#if MYNEWT_VAL(BMA253_CLI)
bma253_shell_init();
#endif
+#if MYNEWT_VAL(BMA2XX_CLI)
+ bma2xx_shell_init();
+#endif
#if MYNEWT_VAL(BME280_CLI)
bme280_shell_init();
diff --git a/apps/sensors_test/syscfg.yml b/apps/sensors_test/syscfg.yml
index 997235b97..87a449bb6 100644
--- a/apps/sensors_test/syscfg.yml
+++ b/apps/sensors_test/syscfg.yml
@@ -46,6 +46,7 @@ syscfg.vals:
BNO055_CLI: 0
TCS34725_CLI: 0
BME280_CLI: 0
+ BMA2XX_CLI: 0
# Setup Sensor BLE OIC GATT Server
SENSOR_OIC: 1
diff --git a/hw/bsp/bmd300eval/src/hal_bsp.c b/hw/bsp/bmd300eval/src/hal_bsp.c
index cb9550d21..af16b2bfe 100644
--- a/hw/bsp/bmd300eval/src/hal_bsp.c
+++ b/hw/bsp/bmd300eval/src/hal_bsp.c
@@ -27,6 +27,7 @@
#include "hal/hal_system.h"
#include "hal/hal_flash.h"
#include "hal/hal_spi.h"
+#include "hal/hal_i2c.h"
#include "mcu/nrf52_hal.h"
#if MYNEWT_VAL(UART_0) || MYNEWT_VAL(UART_1)
#include "uart/uart.h"
@@ -88,6 +89,14 @@ static const struct nrf52_hal_spi_cfg os_bsp_spi0s_cfg = {
};
#endif
+#if MYNEWT_VAL(I2C_0)
+static const struct nrf52_hal_i2c_cfg hal_i2c_cfg = {
+ .scl_pin = MYNEWT_VAL(I2C_0_PIN_CLK),
+ .sda_pin = MYNEWT_VAL(I2C_0_PIN_SDA),
+ .i2c_frequency = 400 /* 400 kHz */
+};
+#endif
+
#if MYNEWT_VAL(ADC_0)
static struct adc_dev os_bsp_adc0;
static struct nrf52_adc_dev_cfg os_bsp_adc0_config = {
@@ -273,6 +282,11 @@ hal_bsp_init(void)
assert(rc == 0);
#endif
+#if MYNEWT_VAL(I2C_0)
+ rc = hal_i2c_init(0, (void *)&hal_i2c_cfg);
+ assert(rc == 0);
+#endif
+
#if MYNEWT_VAL(UART_0)
rc = os_dev_create((struct os_dev *) &os_bsp_uart0, "uart0",
OS_DEV_INIT_PRIMARY, 0, uart_hal_init, (void *)&os_bsp_uart0_cfg);
diff --git a/hw/bsp/bmd300eval/syscfg.yml b/hw/bsp/bmd300eval/syscfg.yml
index ba2435dbc..4d5ceadde 100644
--- a/hw/bsp/bmd300eval/syscfg.yml
+++ b/hw/bsp/bmd300eval/syscfg.yml
@@ -73,6 +73,13 @@ syscfg.defs:
description: 'SS pin for SPI_0_SLAVE'
value: 22
+ I2C_0_PIN_CLK:
+ description: 'Pin Number for I2C Clock'
+ value: 15
+ I2C_0_PIN_SDA:
+ description: 'Pin Number for I2C SDA'
+ value: 14
+
TIMER_0:
description: 'NRF52 Timer 0'
value: 1
diff --git a/hw/drivers/sensors/bma2xx/README.md b/hw/drivers/sensors/bma2xx/README.md
new file mode 100644
index 000000000..4fdd76e7a
--- /dev/null
+++ b/hw/drivers/sensors/bma2xx/README.md
@@ -0,0 +1,189 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+-->
+
+<img src="http://mynewt.apache.org/img/logo.svg" width="250" alt="Apache Mynewt">
+
+## Table of Contents
+- [Overview](#overview)
+- [Usage](#usage)
+- [Wrap-up](#wrap)
+
+## Overview<a name=overview></a>
+
+The goal of the mynewt BMA2XX sensor driver is to allow a common interface
+across the family of [Bosch BMA200 series accelerometers](https://www.bosch-sensortec.com/bst/products/motion/accelerometers/overview_accelerometers).
+Fortunately, the line of sensors have very similar functionality, and share
+the same registers mappings and interrupt engine. The main differences are
+that each sensor has different bit-depth (14, 12, 10bit) and chip ids.
+
+The BMA2XX is based off the functionality of the mynewt BMA253 driver, but
+now includes SPI and I2C support and will support the following models:
+
+* BMA280 - Supported
+* BMA255 - (Coming soon)
+* BMA253 - Supported
+* BMA250E - (Coming soon)
+* BMA22E - (Coming soon)
+* BMA220 - (Coming soon)
+
+
+Bosch-Sensortech has also published a [generic driver](https://github.com/BoschSensortec/BMA2x2_driver)
+for reference
+
+## Usage<a name=usage></a>
+
+The BMA2XX driver is designed as an (offboard sensor) and is instantiated from
+ the sensor creator. It also has shell support and defines a "bma2xx" command
+ option. To test it out let's walk through a simple sensor_test application.
+
+NOTE: Stay tuned for
+
+### Create Target
+First let's create a new target and base it off the sensor_test app. We will
+ also enable the shell, the driver and indicate if we are SPI or I2C.
+~~~~
+> newt target create bma2xx_sensor_test
+Target targets/bma2xx_sensor_test successfully created
+~~~~
+~~~~
+> newt target set bma2xx_sensor_test app=@apache-mynewt-core/apps/sensors_test bsp=@apache-mynewt-core/hw/bsp/bmd300eval build_profile=debug
+Target targets/bma2xx_sensor_test successfully set target.app to @apache-mynewt-core/apps/sensors_test
+Target targets/bma2xx_sensor_test successfully set target.bsp to @apache-mynewt-core/hw/bsp/bmd300eval
+Target targets/bma2xx_sensor_test successfully set target.build_profile to debug
+~~~~
+~~~~
+> newt target set bma2xx_sensor_test syscfg=BMA2XX_OFB=1:SPI_0_MASTER=1:BMA2XX_CLI=1:SHELL_TASK=1
+Target targets/bma2xx_sensor_test successfully set target.syscfg to BMA2XX_OFB=1:SPI_0_MASTER=1:BMA2XX_CLI=1:SHELL_TASK=1
+~~~~
+
+### Set Model in Config
+As mentioned earlier the BMA2XX driver is supported in the sensor creator,
+and comes with a set of default settings. The key attribute that needs to be
+ set is the specific model (eg. BMA280, BMA253, etc) so that chip_ids and
+ resolution of accelerometer values are correct. This is found in
+ [sensor_creator.c](https://github.com/apache/mynewt-core/blob/master/hw/sensor/creator/src/sensor_creator.c)
+in the config_bma2xx_sensor() function, and we will indicate that the BMA280
+is present.
+~~~~
+int
+config_bma2xx_sensor(void)
+{
+ struct os_dev * dev;
+ struct bma2xx_cfg cfg;
+ int rc;
+
+ dev = os_dev_open("bma2xx_0", OS_TIMEOUT_NEVER, NULL);
+ assert(dev != NULL);
+
+ // set the model attribute to one of the following enums
+ // enum bma2xx_model {
+ // BMA2XX_BMA280 = 0,
+ // BMA2XX_BMA253 = 1,
+ // };
+ //
+ cfg.model = BMA2XX_BMA280;
+
+
+ .
+ .
+ .
+}
+~~~~
+
+### Set Pins
+Don't forgot to update your SPI/I2C pins the appropriate BSP configs and
+sensor_creator.c file. We will not cover how to do that here.
+
+### Load App
+Now it's time to build, and load the app to the target bsp. We will assume
+the bootloader is already built and installed. See [this tutorial](https://mynewt.apache.org/latest/os/tutorials/sensors/sensor_thingy_lis2dh12_onb/)
+for more instructions.
+Using the "newt run" command (build, load, gdb) we get the following:
+
+~~~~
+> newt run bma2xx_sensor_test 0.0.0.1
+ .
+ .
+ .
+at repos/apache-mynewt-core/hw/mcu/nordic/nrf52xxx/src/hal_os_tick.c:165
+165 if (ticks > 0) {
+Resetting target
+0x000000dc in ?? ()
+(gdb) c
+Continuing.
+~~~~
+
+
+### Read Data
+Now that the app is loaded and running in a gdb session let's interact with the
+shell to read some data. Below is output from uart session with the BSP.
+Please note the command available under the "bma2xx" command option.
+~~~~
+help
+
+009897 help
+009897 stat
+009898 config
+009899 log
+009900 flash
+009901 i2c_scan
+009902 tasks
+009903 mpool
+009904 date
+009905 sensor
+009906 bma2xx
+009907
+009908 compat> bma2xx
+
+010864 self-test <default|strict>
+010864 offset-compensation <x={0g|-1g|+1g}> <y={0g|-1g|+1g}> <z={0g|-1g|+1g}>
+010866 query-offsets
+010867 write-offsets
+010868 stream-read <num-reads>
+010868 current-temp
+010869 current-orient
+010870 wait-for-orient
+010870 wait-for-high-g
+010871 wait-for-low-g
+010872 wait-for-tap <double|single>
+010872 power-settings <normal|deep-suspend|suspend|standby|lpm1|lpm2>
+ <0.5ms|1ms|2ms|4ms|6ms|10ms|25ms|50ms|100ms|500ms|1s>
+010876 compat> bma2xx stream-read 10
+
+012040 x = 0.009516000 y = 0.017324000 z = 1.004791975
+012041 x = 0.011224000 y = 0.021715998 z = 0.998936000
+012042 x = 0.012932000 y = 0.021472000 z = 0.997716032
+012044 x = 0.019032000 y = 0.019763998 z = 1.001863956
+012045 x = 0.016592000 y = 0.017811998 z = 0.996495936
+012046 x = 0.017080000 y = 0.016348001 z = 1.001132011
+012048 x = 0.016104000 y = 0.011224000 z = 0.993323968
+012049 x = 0.017324000 y = 0.015372000 z = 1.006255984
+012051 x = 0.015616000 y = 0.015616000 z = 0.994544000
+012052 x = 0.014884000 y = 0.018056000 z = 0.999668032
+012065 compat>
+~~~~
+
+## Wrap-Up
+As shown in the example above, in one package your app can support the family
+ of Bosch BMA200 sensors with minimal configuration. Also, using the "newt
+ size" command the package runs ~13k in debug mode In the coming weeks the
+ intent is complete support of the rest of the sensors, and provide more in
+ depth tutorials that exercise the sensor API.
diff --git a/hw/drivers/sensors/bma2xx/include/bma2xx/bma2xx.h b/hw/drivers/sensors/bma2xx/include/bma2xx/bma2xx.h
new file mode 100644
index 000000000..cac395928
--- /dev/null
+++ b/hw/drivers/sensors/bma2xx/include/bma2xx/bma2xx.h
@@ -0,0 +1,464 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * resarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef __BMA2XX_H__
+#define __BMA2XX_H__
+
+#include "os/os.h"
+#include "os/os_dev.h"
+#include "sensor/sensor.h"
+#include "sensor/accel.h"
+#include "sensor/temperature.h"
+
+#ifdef __cplusplus
+#extern "C" {
+#endif
+
+/* XXX use some better defaults. For now it is min */
+#define BMA2XX_LOW_G_DELAY_MS_DEFAULT 2
+#define BMA2XX_HIGH_G_DELAY_MS_DEFAULT 2
+
+/* Supported device models. */
+enum bma2xx_model {
+ BMA2XX_BMA280 = 0,
+ BMA2XX_BMA253 = 1,
+};
+
+/* Range of acceleration measurements */
+enum bma2xx_g_range {
+ BMA2XX_G_RANGE_2 = 0,
+ BMA2XX_G_RANGE_4 = 1,
+ BMA2XX_G_RANGE_8 = 2,
+ BMA2XX_G_RANGE_16 = 3,
+};
+
+/* How often acceleration measurements are taken */
+enum bma2xx_filter_bandwidth {
+ BMA2XX_FILTER_BANDWIDTH_7_81_HZ = 0,
+ BMA2XX_FILTER_BANDWIDTH_15_63_HZ = 1,
+ BMA2XX_FILTER_BANDWIDTH_31_25_HZ = 2,
+ BMA2XX_FILTER_BANDWIDTH_62_5_HZ = 3,
+ BMA2XX_FILTER_BANDWIDTH_125_HZ = 4,
+ BMA2XX_FILTER_BANDWIDTH_250_HZ = 5,
+ BMA2XX_FILTER_BANDWIDTH_500_HZ = 6,
+ BMA2XX_FILTER_BANDWIDTH_1000_HZ = 7,
+ BMA2XX_FILTER_BANDWIDTH_ODR_MAX = 8,
+};
+
+/* Quiet time after a double/single tap */
+enum bma2xx_tap_quiet {
+ BMA2XX_TAP_QUIET_20_MS = 0,
+ BMA2XX_TAP_QUIET_30_MS = 1,
+};
+
+/* Settling time after a double/single tap */
+enum bma2xx_tap_shock {
+ BMA2XX_TAP_SHOCK_50_MS = 0,
+ BMA2XX_TAP_SHOCK_75_MS = 1,
+};
+
+/* How long to wait for the next tap in a double tap scenario */
+enum bma2xx_d_tap_window {
+ BMA2XX_D_TAP_WINDOW_50_MS = 0,
+ BMA2XX_D_TAP_WINDOW_100_MS = 1,
+ BMA2XX_D_TAP_WINDOW_150_MS = 2,
+ BMA2XX_D_TAP_WINDOW_200_MS = 3,
+ BMA2XX_D_TAP_WINDOW_250_MS = 4,
+ BMA2XX_D_TAP_WINDOW_375_MS = 5,
+ BMA2XX_D_TAP_WINDOW_500_MS = 6,
+ BMA2XX_D_TAP_WINDOW_700_MS = 7,
+};
+
+/* How many samples to use after a wake up from a low power mode to determine
+ * whether a tap occurred */
+enum bma2xx_tap_wake_samples {
+ BMA2XX_TAP_WAKE_SAMPLES_2 = 0,
+ BMA2XX_TAP_WAKE_SAMPLES_4 = 1,
+ BMA2XX_TAP_WAKE_SAMPLES_8 = 2,
+ BMA2XX_TAP_WAKE_SAMPLES_16 = 3,
+};
+
+/* Block generation of orientation events based on given criteria */
+enum bma2xx_orient_blocking {
+ BMA2XX_ORIENT_BLOCKING_NONE = 0,
+ BMA2XX_ORIENT_BLOCKING_ACCEL_ONLY = 1,
+ BMA2XX_ORIENT_BLOCKING_ACCEL_AND_SLOPE = 2,
+ BMA2XX_ORIENT_BLOCKING_ACCEL_AND_SLOPE_AND_STABLE = 3,
+};
+
+/* Orientation mode configuration, used to determine thresholds for
+ * transitions between different orientations */
+enum bma2xx_orient_mode {
+ BMA2XX_ORIENT_MODE_SYMMETRICAL = 0,
+ BMA2XX_ORIENT_MODE_HIGH_ASYMMETRICAL = 1,
+ BMA2XX_ORIENT_MODE_LOW_ASYMMETRICAL = 2,
+};
+
+/* Power mode for the device */
+enum bma2xx_power_mode {
+ BMA2XX_POWER_MODE_NORMAL = 0,
+ BMA2XX_POWER_MODE_DEEP_SUSPEND = 1,
+ BMA2XX_POWER_MODE_SUSPEND = 2,
+ BMA2XX_POWER_MODE_STANDBY = 3,
+ BMA2XX_POWER_MODE_LPM_1 = 4,
+ BMA2XX_POWER_MODE_LPM_2 = 5,
+};
+
+/* Duration of sleep whenever the device is in a power mode that alternates
+ * between wake and sleep (LPM 1 & 2) */
+enum bma2xx_sleep_duration {
+ BMA2XX_SLEEP_DURATION_0_5_MS = 0,
+ BMA2XX_SLEEP_DURATION_1_MS = 1,
+ BMA2XX_SLEEP_DURATION_2_MS = 2,
+ BMA2XX_SLEEP_DURATION_4_MS = 3,
+ BMA2XX_SLEEP_DURATION_6_MS = 4,
+ BMA2XX_SLEEP_DURATION_10_MS = 5,
+ BMA2XX_SLEEP_DURATION_25_MS = 6,
+ BMA2XX_SLEEP_DURATION_50_MS = 7,
+ BMA2XX_SLEEP_DURATION_100_MS = 8,
+ BMA2XX_SLEEP_DURATION_500_MS = 9,
+ BMA2XX_SLEEP_DURATION_1_S = 10,
+};
+
+/* Default configuration values to use with the device */
+struct bma2xx_cfg {
+ /* device model within BMA2XX family */
+ enum bma2xx_model model;
+ /* Accelerometer configuration */
+ enum bma2xx_g_range g_range;
+ enum bma2xx_filter_bandwidth filter_bandwidth;
+ /* Whether to use data that has not been filtered at all */
+ bool use_unfiltered_data;
+ /* Low-g event configuration */
+ uint16_t low_g_delay_ms;
+ float low_g_thresh_g;
+ float low_g_hyster_g;
+ /* High-g event configuration */
+ float high_g_hyster_g;
+ uint16_t high_g_delay_ms;
+ float high_g_thresh_g;
+ /* Tap (double & single) event configuration */
+ enum bma2xx_tap_quiet tap_quiet;
+ enum bma2xx_tap_shock tap_shock;
+ enum bma2xx_d_tap_window d_tap_window;
+ enum bma2xx_tap_wake_samples tap_wake_samples;
+ float tap_thresh_g;
+ /* Orientation event configuration */
+ float orient_hyster_g;
+ enum bma2xx_orient_blocking orient_blocking;
+ enum bma2xx_orient_mode orient_mode;
+ bool orient_signal_ud;
+ /* Offsets for acceleration measurements, by axis */
+ float offset_x_g;
+ float offset_y_g;
+ float offset_z_g;
+ /* Power management configuration */
+ enum bma2xx_power_mode power_mode;
+ enum bma2xx_sleep_duration sleep_duration;
+ /* Applicable sensor types supported */
+ sensor_type_t sensor_mask;
+};
+
+/* Used to track interrupt state to wake any present waiters */
+struct bma2xx_int {
+ /* Synchronize access to this structure */
+ os_sr_t lock;
+ /* Sleep waiting for an interrupt to occur */
+ struct os_sem wait;
+ /* Is the interrupt currently active */
+ bool active;
+ /* Is there a waiter currently sleeping */
+ bool asleep;
+ /* Configured interrupts */
+ struct sensor_int *ints;
+};
+
+/* Device private data */
+struct bma2xx_private_driver_data {
+ struct bma2xx_int * interrupt;
+ struct sensor_notify_ev_ctx notify_ctx;
+ struct sensor_read_ev_ctx read_ctx;
+ uint8_t registered_mask;
+
+ uint8_t int_num;
+ uint8_t int_route;
+ uint8_t int_ref_cnt;
+};
+
+/* The device itself */
+struct bma2xx {
+ /* Underlying OS device */
+ struct os_dev dev;
+ /* The sensor infrastructure */
+ struct sensor sensor;
+ /* Default configuration values */
+ struct bma2xx_cfg cfg;
+ /* Active interrupt state */
+ struct bma2xx_int intr;
+ /* Active power mode, could be different from default configured
+ * power mode if a function that requires a higher power mode is
+ * currently running. */
+ enum bma2xx_power_mode power;
+
+ /* Private driver data */
+ struct bma2xx_private_driver_data pdd;
+};
+
+/* Offset compensation is performed to target this given value, by axis */
+enum bma2xx_offset_comp_target {
+ BMA2XX_OFFSET_COMP_TARGET_0_G = 0,
+ BMA2XX_OFFSET_COMP_TARGET_NEG_1_G = 1,
+ BMA2XX_OFFSET_COMP_TARGET_POS_1_G = 2,
+};
+
+/* The device's X/Y orientation, in form of rotation */
+enum bma2xx_orient_xy {
+ BMA2XX_ORIENT_XY_PORTRAIT_UPRIGHT = 0,
+ BMA2XX_ORIENT_XY_PORTRAIT_UPSIDE_DOWN = 1,
+ BMA2XX_ORIENT_XY_LANDSCAPE_LEFT = 2,
+ BMA2XX_ORIENT_XY_LANDSCAPE_RIGHT = 3,
+};
+
+/* The device's full orientation */
+struct bma2xx_orient_xyz {
+ /* The X/Y orientation */
+ enum bma2xx_orient_xy orient_xy;
+ /* Is device facing upward or downward */
+ bool downward_z;
+};
+
+/* Type of tap event to look for */
+enum bma2xx_tap_type {
+ BMA2XX_TAP_TYPE_DOUBLE = 0,
+ BMA2XX_TAP_TYPE_SINGLE = 1,
+};
+
+/**
+ * Perform a self test of the device and report on its health.
+ *
+ * @param The device object.
+ * @param Multiplier on the high amplitude self test minimums; 1.0 for default.
+ * @param Multiplier on the low amplitude self test minimums; 0.0 for default.
+ * @param The result of the self-test: false if passed, true if failed.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma2xx_self_test(struct bma2xx * bma2xx,
+ float delta_high_mult,
+ float delta_low_mult,
+ bool * self_test_fail);
+
+/**
+ * Perform an offset compensation and use the resulting offsets.
+ *
+ * @param The device object.
+ * @param The correct target value for the X axis.
+ * @param The correct target value for the Y axis.
+ * @param The correct target value for the Z axis.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma2xx_offset_compensation(struct bma2xx * bma2xx,
+ enum bma2xx_offset_comp_target target_x,
+ enum bma2xx_offset_comp_target target_y,
+ enum bma2xx_offset_comp_target target_z);
+
+/**
+ * Return the current compensation offsets in use.
+ *
+ * @param The device object.
+ * @param The offset for the X axis, filled in by this function.
+ * @param The offset for the Y axis, filled in by this function.
+ * @param The offset for the Z axis, filled in by this function.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma2xx_query_offsets(struct bma2xx * bma2xx,
+ float * offset_x_g,
+ float * offset_y_g,
+ float * offset_z_g);
+
+/**
+ * Store and use the provided compensation offsets.
+ *
+ * @param The device object.
+ * @param The offset for the X axis.
+ * @param The offset for the Y axis.
+ * @param the offset for the Z axis.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma2xx_write_offsets(struct bma2xx * bma2xx,
+ float offset_x_g,
+ float offset_y_g,
+ float offset_z_g);
+
+/**
+ * Callback for handling accelerometer sensor data.
+ *
+ * @param The opaque pointer passed in to the stream read function.
+ * @param The accelerometer data provided by the sensor.
+ *
+ * @return true to stop streaming data, false to continue.
+ */
+typedef bool
+(*bma2xx_stream_read_func_t)(void *,
+ struct sensor_accel_data *);
+
+/**
+ * Provide a continuous stream of accelerometer readings.
+ *
+ * @param The device object.
+ * @param The function pointer to invoke for each accelerometer reading.
+ * @param The opaque pointer that will be passed in to the function.
+ * @param If non-zero, how long the stream should run in milliseconds.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma2xx_stream_read(struct bma2xx * bma2xx,
+ bma2xx_stream_read_func_t read_func,
+ void * read_arg,
+ uint32_t time_ms);
+
+/**
+ * Get the current temperature at the device.
+ *
+ * @param The device object.
+ * @param The current temperature in celsius, filled in by this function.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma2xx_current_temp(struct bma2xx * bma2xx,
+ float * temp_c);
+
+/**
+ * Get the current device orientation.
+ *
+ * @param The device object.
+ * @param The current orientation, filled in by this function.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma2xx_current_orient(struct bma2xx * bma2xx,
+ struct bma2xx_orient_xyz * orient_xyz);
+
+/**
+ * Block until the device orientation changes.
+ *
+ * @param The device object.
+ * @param The new orientation, filled in by this function.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma2xx_wait_for_orient(struct bma2xx * bma2xx,
+ struct bma2xx_orient_xyz * orient_xyz);
+
+/**
+ * Block until a high-g event occurs.
+ *
+ * @param The device object.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma2xx_wait_for_high_g(struct bma2xx * bma2xx);
+
+/**
+ * Block until a low-g event occurs.
+ *
+ * @param The device object.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma2xx_wait_for_low_g(struct bma2xx * bma2xx);
+
+/**
+ * Block until a single or double tap event occurs.
+ *
+ * @param The device object.
+ * @param The type of tap event to look for.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma2xx_wait_for_tap(struct bma2xx * bma2xx,
+ enum bma2xx_tap_type tap_type);
+
+/**
+ * Change the default power settings.
+ *
+ * @param The device object.
+ * @param The new power mode, which the device resides in unless a different
+ * and more aggressive power mode is required to satisfy a running API
+ * function.
+ * @param The new sleep duration, used whenever device is in LPM_1/2 mode
+ * either due to default power mode or due to being in a temporarily
+ * overridden power mode.
+ */
+int
+bma2xx_power_settings(struct bma2xx * bma2xx,
+ enum bma2xx_power_mode power_mode,
+ enum bma2xx_sleep_duration sleep_duration);
+
+/**
+ * Configure the sensor.
+ *
+ * @param ptr to sensor driver
+ * @param ptr to sensor driver config
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma2xx_config(struct bma2xx * bma2xx, struct bma2xx_cfg * cfg);
+
+/**
+ * Expects to be called back through os_dev_create().
+ *
+ * @param ptr to the device object associated with this accelerometer
+ * @param argument passed to OS device init
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma2xx_init(struct os_dev * dev, void * arg);
+
+#if MYNEWT_VAL(BMA2XX_CLI)
+/**
+ * Initialize the BMA2XX shell extensions.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma2xx_shell_init(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw/drivers/sensors/bma2xx/pkg.yml b/hw/drivers/sensors/bma2xx/pkg.yml
new file mode 100644
index 000000000..aaf26ad38
--- /dev/null
+++ b/hw/drivers/sensors/bma2xx/pkg.yml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: hw/drivers/sensors/bma2xx
+pkg.description: Driver for the Bosch BMA2xx line of accelerometers. Supports BMA253, BMA280
+pkg.keywords:
+ - bma2xx
+ - i2c
+ - spi
+ - sensor
+
+pkg.deps:
+ - "@apache-mynewt-core/kernel/os"
+ - "@apache-mynewt-core/hw/hal"
+ - "@apache-mynewt-core/hw/sensor"
+
+pkg.req_apis:
+ - stats
+ - log
+
+pkg.deps.BMA2XX_CLI:
+ - "@apache-mynewt-core/util/parse"
diff --git a/hw/drivers/sensors/bma2xx/src/bma2xx.c b/hw/drivers/sensors/bma2xx/src/bma2xx.c
new file mode 100644
index 000000000..f8a1f1e18
--- /dev/null
+++ b/hw/drivers/sensors/bma2xx/src/bma2xx.c
@@ -0,0 +1,4941 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * resarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+
+
+#include "bma2xx/bma2xx.h"
+#include "bma2xx_priv.h"
+#include "defs/error.h"
+#include "hal/hal_gpio.h"
+#include "hal/hal_i2c.h"
+#include "hal/hal_spi.h"
+
+#if MYNEWT_VAL(BMA2XX_LOG)
+#include "log/log.h"
+#endif
+
+#if MYNEWT_VAL(BMA2XX_LOG)
+static struct log bma2xx_log;
+#define LOG_MODULE_BMA2XX (200)
+#define BMA2XX_ERROR(...) LOG_ERROR(&bma2xx_log, LOG_MODULE_BMA2XX, __VA_ARGS__)
+#define BMA2XX_INFO(...) LOG_INFO(&bma2xx_log, LOG_MODULE_BMA2XX, __VA_ARGS__)
+#else
+#define BMA2XX_ERROR(...)
+#define BMA2XX_INFO(...)
+#endif
+
+#define BMA2XX_NOTIFY_MASK 0x01
+#define BMA2XX_READ_MASK 0x02
+
+#if MYNEWT_VAL(SPI_0_MASTER) || MYNEWT_VAL(SPI_1_MASTER)
+static struct hal_spi_settings spi_bma2xx_settings = {
+ .data_order = HAL_SPI_MSB_FIRST,
+ .data_mode = HAL_SPI_MODE0,
+ .baudrate = 4000,
+ .word_size = HAL_SPI_WORD_SIZE_8BIT,
+};
+#endif
+
+static void
+delay_msec(uint32_t delay)
+{
+ delay = (delay * OS_TICKS_PER_SEC) / 1000 + 1;
+ os_time_delay(delay);
+}
+
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+static void
+init_interrupt(struct bma2xx_int * interrupt, struct sensor_int *ints)
+{
+ os_error_t error;
+
+ error = os_sem_init(&interrupt->wait, 0);
+ assert(error == OS_OK);
+
+ interrupt->active = false;
+ interrupt->asleep = false;
+ interrupt->ints = ints;
+}
+
+static void
+undo_interrupt(struct bma2xx_int * interrupt)
+{
+ OS_ENTER_CRITICAL(interrupt->lock);
+ interrupt->active = false;
+ interrupt->asleep = false;
+ OS_EXIT_CRITICAL(interrupt->lock);
+}
+
+static void
+wait_interrupt(struct bma2xx_int * interrupt, enum bma2xx_int_num int_num)
+{
+ bool wait;
+
+ OS_ENTER_CRITICAL(interrupt->lock);
+
+ /* Check if we did not missed interrupt */
+ if (hal_gpio_read(interrupt->ints[int_num].host_pin) ==
+ interrupt->ints[int_num].active) {
+ OS_EXIT_CRITICAL(interrupt->lock);
+ return;
+ }
+
+ if (interrupt->active) {
+ interrupt->active = false;
+ wait = false;
+ } else {
+ interrupt->asleep = true;
+ wait = true;
+ }
+ OS_EXIT_CRITICAL(interrupt->lock);
+
+ if (wait) {
+ os_error_t error;
+
+ error = os_sem_pend(&interrupt->wait, -1);
+ assert(error == OS_OK);
+ }
+}
+
+static void
+wake_interrupt(struct bma2xx_int * interrupt)
+{
+ bool wake;
+
+ OS_ENTER_CRITICAL(interrupt->lock);
+ if (interrupt->asleep) {
+ interrupt->asleep = false;
+ wake = true;
+ } else {
+ interrupt->active = true;
+ wake = false;
+ }
+ OS_EXIT_CRITICAL(interrupt->lock);
+
+ if (wake) {
+ os_error_t error;
+
+ error = os_sem_release(&interrupt->wait);
+ assert(error == OS_OK);
+ }
+}
+
+static void
+interrupt_handler(void * arg)
+{
+ struct sensor *sensor = arg;
+ struct bma2xx *bma2xx;
+
+ bma2xx = (struct bma2xx *)SENSOR_GET_DEVICE(sensor);
+
+ if (bma2xx->pdd.interrupt) {
+ wake_interrupt(bma2xx->pdd.interrupt);
+ }
+
+ sensor_mgr_put_interrupt_evt(sensor);
+}
+#endif
+
+/**
+ * Read multiple length data over SPI
+ *
+ * @param register address
+ * @param variable length payload
+ * @param length of the payload to read
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+spi_readlen(const struct sensor_itf * itf, uint8_t addr, uint8_t *payload,
+ uint8_t len)
+{
+ int i;
+ uint16_t retval;
+ int rc;
+
+ rc = 0;
+
+ /* Select the device */
+ hal_gpio_write(itf->si_cs_pin, 0);
+
+ /* Send the address */
+ retval = hal_spi_tx_val(itf->si_num, addr | BMA2XX_SPI_READ_CMD_BIT);
+ if (retval == 0xFFFF) {
+ rc = SYS_EINVAL;
+ BMA2XX_ERROR("SPI_%u register write failed addr:0x%02X\n",
+ itf->si_num, addr);
+ goto err;
+ }
+
+ for (i = 0; i < len; i++) {
+ /* Read data */
+ retval = hal_spi_tx_val(itf->si_num, 0);
+ if (retval == 0xFFFF) {
+ rc = SYS_EINVAL;
+ BMA2XX_ERROR("SPI_%u read failed addr:0x%02X\n",
+ itf->si_num, addr);
+ goto err;
+ }
+ payload[i] = retval;
+ }
+
+ rc = 0;
+
+ err:
+ /* De-select the device */
+ hal_gpio_write(itf->si_cs_pin, 1);
+
+ return rc;
+}
+
+/**
+ * Write multiple length data SPI
+ *
+ * @param register address
+ * @param variable length payload
+ * @param length of the payload to write
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+spi_writereg(const struct sensor_itf * itf, uint8_t addr, uint8_t payload,
+ uint8_t len)
+{
+ int i;
+ int rc;
+
+ /* Select the device */
+ hal_gpio_write(itf->si_cs_pin, 0);
+
+ /* Send the address */
+ rc = hal_spi_tx_val(itf->si_num, addr);
+ if (rc == 0xFFFF) {
+ rc = SYS_EINVAL;
+ BMA2XX_ERROR("SPI_%u register write failed addr:0x%02X\n",
+ itf->si_num, addr);
+ goto err;
+ }
+
+ for (i = 0; i < len; i++) {
+ /* Read data */
+ rc = hal_spi_tx_val(itf->si_num, payload);
+ if (rc == 0xFFFF) {
+ rc = SYS_EINVAL;
+ BMA2XX_ERROR("SPI_%u write failed addr:0x%02X:0x%02X\n",
+ itf->si_num, addr);
+ goto err;
+ }
+ }
+
+
+ rc = 0;
+
+ err:
+ /* De-select the device */
+ hal_gpio_write(itf->si_cs_pin, 1);
+
+ os_time_delay((OS_TICKS_PER_SEC * 30)/1000 + 1);
+
+ return rc;
+}
+
+int
+i2c_readlen(const struct sensor_itf * itf, uint8_t addr, uint8_t *payload,
+ uint8_t len)
+{
+ struct hal_i2c_master_data oper;
+ int rc;
+
+ oper.address = itf->si_addr;
+ oper.len = 1;
+ oper.buffer = &addr;
+
+ rc = hal_i2c_master_write(itf->si_num, &oper,
+ OS_TICKS_PER_SEC / 10, 1);
+ if (rc != 0) {
+ BMA2XX_ERROR("I2C access failed at address 0x%02X\n",
+ addr);
+ return rc;
+ }
+
+ oper.address = itf->si_addr;
+ oper.len = len;
+ oper.buffer = payload;
+
+ rc = hal_i2c_master_read(itf->si_num, &oper,
+ OS_TICKS_PER_SEC / 10, 1);
+ if (rc != 0) {
+ BMA2XX_ERROR("I2C read failed at address 0x%02X length %u\n",
+ addr, len);
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+i2c_writereg(const struct sensor_itf * itf, uint8_t addr, uint8_t data)
+{
+ uint8_t tuple[2];
+ struct hal_i2c_master_data oper;
+ int rc;
+
+ tuple[0] = addr;
+ tuple[1] = data;
+
+ oper.address = itf->si_addr;
+ oper.len = 2;
+ oper.buffer = tuple;
+
+ rc = hal_i2c_master_write(itf->si_num, &oper,
+ OS_TICKS_PER_SEC / 10, 1);
+ if (rc != 0) {
+ BMA2XX_ERROR("I2C write failed at address 0x%02X single byte\n",
+ addr);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int
+get_register(const struct bma2xx * bma2xx,
+ uint8_t addr,
+ uint8_t * data)
+{
+ int rc;
+ const struct sensor_itf * itf;
+ itf = SENSOR_GET_ITF(&bma2xx->sensor);
+
+ if (itf->si_type == SENSOR_ITF_SPI) {
+ rc = spi_readlen(itf, addr, data, 1);
+ } else if (itf->si_type == SENSOR_ITF_I2C){
+ rc = i2c_readlen(itf, addr, data, 1);
+ } else {
+ rc = SYS_EINVAL;
+ }
+
+ return rc;
+}
+
+static int
+get_registers(const struct bma2xx * bma2xx,
+ uint8_t addr,
+ uint8_t * data,
+ uint8_t size)
+{
+ int rc;
+ const struct sensor_itf * itf;
+ itf = SENSOR_GET_ITF(&bma2xx->sensor);
+
+ if (itf->si_type == SENSOR_ITF_SPI) {
+ rc = spi_readlen(itf, addr, data, size);
+ } else if (itf->si_type == SENSOR_ITF_I2C){
+ rc = i2c_readlen(itf, addr, data, size);
+ } else {
+ rc = SYS_EINVAL;
+ }
+
+ return rc;
+}
+
+static int
+set_register(const struct bma2xx * bma2xx,
+ uint8_t addr,
+ uint8_t data)
+{
+ int rc;
+ const struct sensor_itf * itf;
+
+ itf = SENSOR_GET_ITF(&bma2xx->sensor);
+
+ if (itf->si_type == SENSOR_ITF_SPI) {
+ rc = spi_writereg(itf, addr, data, 1);
+ } else if (itf->si_type == SENSOR_ITF_I2C){
+ rc = i2c_writereg(itf, addr, data);
+ } else {
+ rc = SYS_EINVAL;
+ }
+
+ switch (bma2xx->power) {
+ case BMA2XX_POWER_MODE_SUSPEND:
+ case BMA2XX_POWER_MODE_LPM_1:
+ delay_msec(1);
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+int
+bma2xx_get_chip_id(const struct bma2xx * bma2xx,
+ uint8_t * chip_id)
+{
+ return get_register(bma2xx, REG_ADDR_BGW_CHIPID, chip_id);
+}
+
+static void
+compute_accel_data(struct accel_data * accel_data,
+ enum bma2xx_model model,
+ const uint8_t * raw_data,
+ float accel_scale)
+{
+ int16_t raw_accel;
+ uint8_t model_shift = 0;
+
+ switch (model) {
+ case BMA2XX_BMA280:
+ model_shift = BMA280_ACCEL_BIT_SHIFT;
+ break;
+ case BMA2XX_BMA253:
+ model_shift = BMA253_ACCEL_BIT_SHIFT;
+ break;
+ default:
+ break;
+ }
+
+ raw_accel = (int16_t)(raw_data[0] & 0xFC) | (int16_t)(raw_data[1] << 8);
+ raw_accel >>= model_shift;
+
+ accel_data->accel_g = (float)raw_accel * accel_scale;
+ accel_data->new_data = raw_data[0] & 0x01;
+}
+
+static int
+get_accel_scale(enum bma2xx_model model,
+ enum bma2xx_g_range g_range,
+ float *accel_scale)
+{
+ switch (g_range) {
+ case BMA2XX_G_RANGE_2:
+ switch(model){
+ case BMA2XX_BMA280:
+ *accel_scale = BMA280_G_SCALE_2;
+ break;
+ case BMA2XX_BMA253:
+ *accel_scale = BMA253_G_SCALE_2;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+ break;
+ case BMA2XX_G_RANGE_4:
+ switch(model){
+ case BMA2XX_BMA280:
+ *accel_scale = BMA280_G_SCALE_4;
+ break;
+ case BMA2XX_BMA253:
+ *accel_scale = BMA253_G_SCALE_4;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+ break;
+ case BMA2XX_G_RANGE_8:
+ switch(model){
+ case BMA2XX_BMA280:
+ *accel_scale = BMA280_G_SCALE_8;
+ break;
+ case BMA2XX_BMA253:
+ *accel_scale = BMA253_G_SCALE_8;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+ break;
+ case BMA2XX_G_RANGE_16:
+ switch(model){
+ case BMA2XX_BMA280:
+ *accel_scale = BMA280_G_SCALE_16;
+ break;
+ case BMA2XX_BMA253:
+ *accel_scale = BMA253_G_SCALE_16;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_get_accel(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ enum axis axis,
+ struct accel_data * accel_data)
+{
+ float accel_scale;
+ uint8_t base_addr;
+ uint8_t data[2];
+ int rc;
+
+ rc = get_accel_scale(bma2xx->cfg.model, g_range, &accel_scale);
+ if (rc != 0){
+ return rc;
+ }
+
+ switch (axis) {
+ case AXIS_X:
+ base_addr = REG_ADDR_ACCD_X_LSB;
+ break;
+ case AXIS_Y:
+ base_addr = REG_ADDR_ACCD_Y_LSB;
+ break;
+ case AXIS_Z:
+ base_addr = REG_ADDR_ACCD_Z_LSB;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ rc = get_registers(bma2xx, base_addr,
+ data, sizeof(data) / sizeof(*data));
+ if (rc != 0) {
+ return rc;
+ }
+
+ compute_accel_data(accel_data, bma2xx->cfg.model, data, accel_scale);
+
+ return 0;
+}
+
+int
+bma2xx_get_temp(const struct bma2xx * bma2xx,
+ float * temp_c)
+{
+ uint8_t data;
+ int rc;
+
+ rc = get_register(bma2xx, REG_ADDR_ACCD_TEMP, &data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ *temp_c = (float)(int8_t)data * 0.5 + 23.0;
+
+ return 0;
+}
+
+static void
+quad_to_axis_trigger(struct axis_trigger * axis_trigger,
+ uint8_t quad_bits,
+ const char * name_bits)
+{
+ axis_trigger->sign = (quad_bits >> 3) & 0x01;
+ switch (quad_bits & 0x07) {
+ default:
+ BMA2XX_ERROR("unknown %s quad bits 0x%02X\n",
+ name_bits, quad_bits);
+ case 0x00:
+ axis_trigger->axis = -1;
+ axis_trigger->axis_known = false;
+ break;
+ case 0x01:
+ axis_trigger->axis = AXIS_X;
+ axis_trigger->axis_known = true;
+ break;
+ case 0x02:
+ axis_trigger->axis = AXIS_Y;
+ axis_trigger->axis_known = true;
+ break;
+ case 0x03:
+ axis_trigger->axis = AXIS_Z;
+ axis_trigger->axis_known = true;
+ break;
+ }
+}
+
+int
+bma2xx_get_int_status(const struct bma2xx * bma2xx,
+ struct int_status * int_status)
+{
+ uint8_t data[4];
+ int rc;
+
+ rc = get_registers(bma2xx, REG_ADDR_INT_STATUS_0,
+ data, sizeof(data) / sizeof(*data));
+ if (rc != 0) {
+ return rc;
+ }
+
+ int_status->flat_int_active = data[0] & 0x80;
+ int_status->orient_int_active = data[0] & 0x40;
+ int_status->s_tap_int_active = data[0] & 0x20;
+ int_status->d_tap_int_active = data[0] & 0x10;
+ int_status->slow_no_mot_int_active = data[0] & 0x08;
+ int_status->slope_int_active = data[0] & 0x04;
+ int_status->high_g_int_active = data[0] & 0x02;
+ int_status->low_g_int_active = data[0] & 0x01;
+ int_status->data_int_active = data[1] & 0x80;
+ int_status->fifo_wmark_int_active = data[1] & 0x40;
+ int_status->fifo_full_int_active = data[1] & 0x20;
+ quad_to_axis_trigger(&int_status->tap_trigger,
+ (data[2] >> 4) & 0x0F, "tap");
+ quad_to_axis_trigger(&int_status->slope_trigger,
+ (data[2] >> 0) & 0x0F, "slope");
+ int_status->device_is_flat = data[3] & 0x80;
+ int_status->device_is_down = data[3] & 0x40;
+ int_status->device_orientation = (data[3] >> 4) & 0x03;
+ quad_to_axis_trigger(&int_status->high_g_trigger,
+ (data[3] >> 0) & 0x0F, "high_g");
+
+ return 0;
+}
+
+int
+bma2xx_get_fifo_status(const struct bma2xx * bma2xx,
+ bool * overrun,
+ uint8_t * frame_counter)
+{
+ uint8_t data;
+ int rc;
+
+ rc = get_register(bma2xx, REG_ADDR_FIFO_STATUS, &data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ *overrun = data & 0x80;
+ *frame_counter = data & 0x7F;
+
+ return 0;
+}
+
+int
+bma2xx_get_g_range(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range * g_range)
+{
+ uint8_t data;
+ int rc;
+
+ rc = get_register(bma2xx, REG_ADDR_PMU_RANGE, &data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ switch (data & 0x0F) {
+ default:
+ BMA2XX_ERROR("unknown PMU_RANGE reg value 0x%02X\n", data);
+ *g_range = BMA2XX_G_RANGE_16;
+ break;
+ case 0x03:
+ *g_range = BMA2XX_G_RANGE_2;
+ break;
+ case 0x05:
+ *g_range = BMA2XX_G_RANGE_4;
+ break;
+ case 0x08:
+ *g_range = BMA2XX_G_RANGE_8;
+ break;
+ case 0x0C:
+ *g_range = BMA2XX_G_RANGE_16;
+ break;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_set_g_range(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range)
+{
+ uint8_t data;
+
+ switch (g_range) {
+ case BMA2XX_G_RANGE_2:
+ data = 0x03;
+ break;
+ case BMA2XX_G_RANGE_4:
+ data = 0x05;
+ break;
+ case BMA2XX_G_RANGE_8:
+ data = 0x08;
+ break;
+ case BMA2XX_G_RANGE_16:
+ data = 0x0C;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ return set_register(bma2xx, REG_ADDR_PMU_RANGE, data);
+}
+
+int
+bma2xx_get_filter_bandwidth(const struct bma2xx * bma2xx,
+ enum bma2xx_filter_bandwidth * filter_bandwidth)
+{
+ uint8_t data;
+ int rc;
+
+ rc = get_register(bma2xx, REG_ADDR_PMU_BW, &data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ switch (data & 0x1F) {
+ case 0x00 ... 0x08:
+ *filter_bandwidth = BMA2XX_FILTER_BANDWIDTH_7_81_HZ;
+ break;
+ case 0x09:
+ *filter_bandwidth = BMA2XX_FILTER_BANDWIDTH_15_63_HZ;
+ break;
+ case 0x0A:
+ *filter_bandwidth = BMA2XX_FILTER_BANDWIDTH_31_25_HZ;
+ break;
+ case 0x0B:
+ *filter_bandwidth = BMA2XX_FILTER_BANDWIDTH_62_5_HZ;
+ break;
+ case 0x0C:
+ *filter_bandwidth = BMA2XX_FILTER_BANDWIDTH_125_HZ;
+ break;
+ case 0x0D:
+ *filter_bandwidth = BMA2XX_FILTER_BANDWIDTH_250_HZ;
+ break;
+ case 0x0E:
+ *filter_bandwidth = BMA2XX_FILTER_BANDWIDTH_500_HZ;
+ break;
+ case 0x0F ... 0x1F:
+ *filter_bandwidth = BMA2XX_FILTER_BANDWIDTH_1000_HZ;
+ break;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_set_filter_bandwidth(const struct bma2xx * bma2xx,
+ enum bma2xx_filter_bandwidth filter_bandwidth)
+{
+ uint8_t data;
+
+ switch (filter_bandwidth) {
+ case BMA2XX_FILTER_BANDWIDTH_7_81_HZ:
+ data = 0x08;
+ break;
+ case BMA2XX_FILTER_BANDWIDTH_15_63_HZ:
+ data = 0x09;
+ break;
+ case BMA2XX_FILTER_BANDWIDTH_31_25_HZ:
+ data = 0x0A;
+ break;
+ case BMA2XX_FILTER_BANDWIDTH_62_5_HZ:
+ data = 0x0B;
+ break;
+ case BMA2XX_FILTER_BANDWIDTH_125_HZ:
+ data = 0x0C;
+ break;
+ case BMA2XX_FILTER_BANDWIDTH_250_HZ:
+ data = 0x0D;
+ break;
+ case BMA2XX_FILTER_BANDWIDTH_500_HZ:
+ data = 0x0E;
+ break;
+ case BMA2XX_FILTER_BANDWIDTH_1000_HZ:
+ switch( bma2xx->cfg.model) {
+ case BMA2XX_BMA253:
+ data = 0x0F;
+ break;
+ case BMA2XX_BMA280:
+ return SYS_EINVAL;
+ default:
+ return SYS_EINVAL;
+ }
+ break;
+ case BMA2XX_FILTER_BANDWIDTH_ODR_MAX:
+ switch( bma2xx->cfg.model) {
+ case BMA2XX_BMA253:
+ return SYS_EINVAL;
+ case BMA2XX_BMA280:
+ data = 0x0F;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ return set_register(bma2xx, REG_ADDR_PMU_BW, data);
+}
+
+int
+bma2xx_get_power_settings(const struct bma2xx * bma2xx,
+ struct power_settings * power_settings)
+{
+ uint8_t data[2];
+ int rc;
+
+ rc = get_registers(bma2xx, REG_ADDR_PMU_LPW,
+ data, sizeof(data) / sizeof(*data));
+ if (rc != 0) {
+ return rc;
+ }
+
+ switch ((data[0] >> 5) & 0x07) {
+ default:
+ BMA2XX_ERROR("unknown PMU_LPW reg value 0x%02X\n", data[0]);
+ power_settings->power_mode = BMA2XX_POWER_MODE_NORMAL;
+ break;
+ case 0x00:
+ power_settings->power_mode = BMA2XX_POWER_MODE_NORMAL;
+ break;
+ case 0x01:
+ power_settings->power_mode = BMA2XX_POWER_MODE_DEEP_SUSPEND;
+ break;
+ case 0x02:
+ if ((data[1] & 0x40) == 0) {
+ power_settings->power_mode = BMA2XX_POWER_MODE_LPM_1;
+ } else {
+ power_settings->power_mode = BMA2XX_POWER_MODE_LPM_2;
+ }
+ break;
+ case 0x04:
+ if ((data[1] & 0x40) == 0) {
+ power_settings->power_mode = BMA2XX_POWER_MODE_SUSPEND;
+ } else {
+ power_settings->power_mode = BMA2XX_POWER_MODE_STANDBY;
+ }
+ break;
+ }
+
+ switch ((data[0] >> 1) & 0x0F) {
+ case 0x00 ... 0x05:
+ power_settings->sleep_duration = BMA2XX_SLEEP_DURATION_0_5_MS;
+ break;
+ case 0x06:
+ power_settings->sleep_duration = BMA2XX_SLEEP_DURATION_1_MS;
+ break;
+ case 0x07:
+ power_settings->sleep_duration = BMA2XX_SLEEP_DURATION_2_MS;
+ break;
+ case 0x08:
+ power_settings->sleep_duration = BMA2XX_SLEEP_DURATION_4_MS;
+ break;
+ case 0x09:
+ power_settings->sleep_duration = BMA2XX_SLEEP_DURATION_6_MS;
+ break;
+ case 0x0A:
+ power_settings->sleep_duration = BMA2XX_SLEEP_DURATION_10_MS;
+ break;
+ case 0x0B:
+ power_settings->sleep_duration = BMA2XX_SLEEP_DURATION_25_MS;
+ break;
+ case 0x0C:
+ power_settings->sleep_duration = BMA2XX_SLEEP_DURATION_50_MS;
+ break;
+ case 0x0D:
+ power_settings->sleep_duration = BMA2XX_SLEEP_DURATION_100_MS;
+ break;
+ case 0x0E:
+ power_settings->sleep_duration = BMA2XX_SLEEP_DURATION_500_MS;
+ break;
+ case 0x0F:
+ power_settings->sleep_duration = BMA2XX_SLEEP_DURATION_1_S;
+ break;
+ }
+
+ if ((data[1] & 0x20) != 0) {
+ power_settings->sleep_timer = SLEEP_TIMER_EQUIDISTANT_SAMPLING;
+ } else {
+ power_settings->sleep_timer = SLEEP_TIMER_EVENT_DRIVEN;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_set_power_settings(const struct bma2xx * bma2xx,
+ const struct power_settings * power_settings)
+{
+ uint8_t data[2];
+ int rc;
+
+ data[0] = 0;
+ data[1] = 0;
+
+ switch (power_settings->power_mode) {
+ case BMA2XX_POWER_MODE_NORMAL:
+ data[0] |= 0x00 << 5;
+ break;
+ case BMA2XX_POWER_MODE_DEEP_SUSPEND:
+ data[0] |= 0x01 << 5;
+ break;
+ case BMA2XX_POWER_MODE_SUSPEND:
+ data[0] |= 0x04 << 5;
+ data[1] |= 0x00 << 6;
+ break;
+ case BMA2XX_POWER_MODE_STANDBY:
+ data[0] |= 0x04 << 5;
+ data[1] |= 0x01 << 6;
+ break;
+ case BMA2XX_POWER_MODE_LPM_1:
+ data[0] |= 0x02 << 5;
+ data[1] |= 0x00 << 6;
+ break;
+ case BMA2XX_POWER_MODE_LPM_2:
+ data[0] |= 0x02 << 5;
+ data[1] |= 0x01 << 6;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ switch (power_settings->sleep_duration) {
+ case BMA2XX_SLEEP_DURATION_0_5_MS:
+ data[0] |= 0x05 << 1;
+ break;
+ case BMA2XX_SLEEP_DURATION_1_MS:
+ data[0] |= 0x06 << 1;
+ break;
+ case BMA2XX_SLEEP_DURATION_2_MS:
+ data[0] |= 0x07 << 1;
+ break;
+ case BMA2XX_SLEEP_DURATION_4_MS:
+ data[0] |= 0x08 << 1;
+ break;
+ case BMA2XX_SLEEP_DURATION_6_MS:
+ data[0] |= 0x09 << 1;
+ break;
+ case BMA2XX_SLEEP_DURATION_10_MS:
+ data[0] |= 0x0A << 1;
+ break;
+ case BMA2XX_SLEEP_DURATION_25_MS:
+ data[0] |= 0x0B << 1;
+ break;
+ case BMA2XX_SLEEP_DURATION_50_MS:
+ data[0] |= 0x0C << 1;
+ break;
+ case BMA2XX_SLEEP_DURATION_100_MS:
+ data[0] |= 0x0D << 1;
+ break;
+ case BMA2XX_SLEEP_DURATION_500_MS:
+ data[0] |= 0x0E << 1;
+ break;
+ case BMA2XX_SLEEP_DURATION_1_S:
+ data[0] |= 0x0F << 1;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ switch (power_settings->sleep_timer) {
+ case SLEEP_TIMER_EVENT_DRIVEN:
+ data[1] |= 0x00 << 5;
+ break;
+ case SLEEP_TIMER_EQUIDISTANT_SAMPLING:
+ data[1] |= 0x01 << 5;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ rc = set_register(bma2xx, REG_ADDR_PMU_LOW_POWER, data[1]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_PMU_LPW, data[0]);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_get_data_acquisition(const struct bma2xx * bma2xx,
+ bool * unfiltered_reg_data,
+ bool * disable_reg_shadow)
+{
+ uint8_t data;
+ int rc;
+
+ rc = get_register(bma2xx, REG_ADDR_ACCD_HBW, &data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ *unfiltered_reg_data = data & 0x80;
+ *disable_reg_shadow = data & 0x40;
+
+ return 0;
+}
+
+int
+bma2xx_set_data_acquisition(const struct bma2xx * bma2xx,
+ bool unfiltered_reg_data,
+ bool disable_reg_shadow)
+{
+ uint8_t data;
+
+ data = (unfiltered_reg_data << 7) |
+ (disable_reg_shadow << 6);
+
+ return set_register(bma2xx, REG_ADDR_ACCD_HBW, data);
+}
+
+int
+bma2xx_set_softreset(const struct bma2xx * bma2xx)
+{
+ int rc;
+
+ rc = set_register(bma2xx, REG_ADDR_BGW_SOFTRESET, REG_VALUE_SOFT_RESET);
+ if (rc != 0) {
+ return rc;
+ }
+
+ delay_msec(2);
+
+ return 0;
+}
+
+int
+bma2xx_get_int_enable(const struct bma2xx * bma2xx,
+ struct int_enable * int_enable)
+{
+ uint8_t data[3];
+ int rc;
+
+ rc = get_registers(bma2xx, REG_ADDR_INT_EN_0,
+ data, sizeof(data) / sizeof(*data));
+ if (rc != 0) {
+ return rc;
+ }
+
+ int_enable->flat_int_enable = data[0] & 0x80;
+ int_enable->orient_int_enable = data[0] & 0x40;
+ int_enable->s_tap_int_enable = data[0] & 0x20;
+ int_enable->d_tap_int_enable = data[0] & 0x10;
+ int_enable->slope_z_int_enable = data[0] & 0x04;
+ int_enable->slope_y_int_enable = data[0] & 0x02;
+ int_enable->slope_x_int_enable = data[0] & 0x01;
+ int_enable->fifo_wmark_int_enable = data[1] & 0x40;
+ int_enable->fifo_full_int_enable = data[1] & 0x20;
+ int_enable->data_int_enable = data[1] & 0x10;
+ int_enable->low_g_int_enable = data[1] & 0x08;
+ int_enable->high_g_z_int_enable = data[1] & 0x04;
+ int_enable->high_g_y_int_enable = data[1] & 0x02;
+ int_enable->high_g_x_int_enable = data[1] & 0x01;
+ int_enable->no_motion_select = data[2] & 0x08;
+ int_enable->slow_no_mot_z_int_enable = data[2] & 0x04;
+ int_enable->slow_no_mot_y_int_enable = data[2] & 0x02;
+ int_enable->slow_no_mot_x_int_enable = data[2] & 0x01;
+
+ return 0;
+}
+
+int
+bma2xx_set_int_enable(const struct bma2xx * bma2xx,
+ const struct int_enable * int_enable)
+{
+ uint8_t data[3];
+ int rc;
+
+ data[0] = (int_enable->flat_int_enable << 7) |
+ (int_enable->orient_int_enable << 6) |
+ (int_enable->s_tap_int_enable << 5) |
+ (int_enable->d_tap_int_enable << 4) |
+ (int_enable->slope_z_int_enable << 2) |
+ (int_enable->slope_y_int_enable << 1) |
+ (int_enable->slope_x_int_enable << 0);
+
+ data[1] = (int_enable->fifo_wmark_int_enable << 6) |
+ (int_enable->fifo_full_int_enable << 5) |
+ (int_enable->data_int_enable << 4) |
+ (int_enable->low_g_int_enable << 3) |
+ (int_enable->high_g_z_int_enable << 2) |
+ (int_enable->high_g_y_int_enable << 1) |
+ (int_enable->high_g_x_int_enable << 0);
+
+ data[2] = (int_enable->no_motion_select << 3) |
+ (int_enable->slow_no_mot_z_int_enable << 2) |
+ (int_enable->slow_no_mot_y_int_enable << 1) |
+ (int_enable->slow_no_mot_x_int_enable << 0);
+
+ rc = set_register(bma2xx, REG_ADDR_INT_EN_0, data[0]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_INT_EN_1, data[1]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_INT_EN_2, data[2]);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_get_int_routes(const struct bma2xx * bma2xx,
+ struct int_routes * int_routes)
+{
+ uint8_t data[3];
+ int rc;
+
+ rc = get_registers(bma2xx, REG_ADDR_INT_MAP_0,
+ data, sizeof(data) / sizeof(*data));
+ if (rc != 0) {
+ return rc;
+ }
+
+ int_routes->flat_int_route = INT_ROUTE_NONE;
+ if ((data[0] & 0x80) != 0) {
+ int_routes->flat_int_route |= INT_ROUTE_PIN_1;
+ }
+ if ((data[2] & 0x80) != 0) {
+ int_routes->flat_int_route |= INT_ROUTE_PIN_2;
+ }
+
+ int_routes->orient_int_route = INT_ROUTE_NONE;
+ if ((data[0] & 0x40) != 0) {
+ int_routes->orient_int_route |= INT_ROUTE_PIN_1;
+ }
+ if ((data[2] & 0x40) != 0) {
+ int_routes->orient_int_route |= INT_ROUTE_PIN_2;
+ }
+
+ int_routes->s_tap_int_route = INT_ROUTE_NONE;
+ if ((data[0] & 0x20) != 0) {
+ int_routes->s_tap_int_route |= INT_ROUTE_PIN_1;
+ }
+ if ((data[2] & 0x20) != 0) {
+ int_routes->s_tap_int_route |= INT_ROUTE_PIN_2;
+ }
+
+ int_routes->d_tap_int_route = INT_ROUTE_NONE;
+ if ((data[0] & 0x10) != 0) {
+ int_routes->d_tap_int_route |= INT_ROUTE_PIN_1;
+ }
+ if ((data[2] & 0x10) != 0) {
+ int_routes->d_tap_int_route |= INT_ROUTE_PIN_2;
+ }
+
+ int_routes->slow_no_mot_int_route = INT_ROUTE_NONE;
+ if ((data[0] & 0x08) != 0) {
+ int_routes->slow_no_mot_int_route |= INT_ROUTE_PIN_1;
+ }
+ if ((data[2] & 0x08) != 0) {
+ int_routes->slow_no_mot_int_route |= INT_ROUTE_PIN_2;
+ }
+
+ int_routes->slope_int_route = INT_ROUTE_NONE;
+ if ((data[0] & 0x04) != 0) {
+ int_routes->slope_int_route |= INT_ROUTE_PIN_1;
+ }
+ if ((data[2] & 0x04) != 0) {
+ int_routes->slope_int_route |= INT_ROUTE_PIN_2;
+ }
+
+ int_routes->high_g_int_route = INT_ROUTE_NONE;
+ if ((data[0] & 0x02) != 0) {
+ int_routes->high_g_int_route |= INT_ROUTE_PIN_1;
+ }
+ if ((data[2] & 0x02) != 0) {
+ int_routes->high_g_int_route |= INT_ROUTE_PIN_2;
+ }
+
+ int_routes->low_g_int_route = INT_ROUTE_NONE;
+ if ((data[0] & 0x01) != 0) {
+ int_routes->low_g_int_route |= INT_ROUTE_PIN_1;
+ }
+ if ((data[2] & 0x01) != 0) {
+ int_routes->low_g_int_route |= INT_ROUTE_PIN_2;
+ }
+
+ int_routes->fifo_wmark_int_route = INT_ROUTE_NONE;
+ if ((data[1] & 0x02) != 0) {
+ int_routes->fifo_wmark_int_route |= INT_ROUTE_PIN_1;
+ }
+ if ((data[1] & 0x40) != 0) {
+ int_routes->fifo_wmark_int_route |= INT_ROUTE_PIN_2;
+ }
+
+ int_routes->fifo_full_int_route = INT_ROUTE_NONE;
+ if ((data[1] & 0x04) != 0) {
+ int_routes->fifo_full_int_route |= INT_ROUTE_PIN_1;
+ }
+ if ((data[1] & 0x20) != 0) {
+ int_routes->fifo_full_int_route |= INT_ROUTE_PIN_2;
+ }
+
+ int_routes->data_int_route = INT_ROUTE_NONE;
+ if ((data[1] & 0x01) != 0) {
+ int_routes->data_int_route |= INT_ROUTE_PIN_1;
+ }
+ if ((data[1] & 0x80) != 0) {
+ int_routes->data_int_route |= INT_ROUTE_PIN_2;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_set_int_routes(const struct bma2xx * bma2xx,
+ const struct int_routes * int_routes)
+{
+ uint8_t data[3];
+ int rc;
+
+ data[0] = (((int_routes->flat_int_route & INT_ROUTE_PIN_1) != 0) << 7) |
+ (((int_routes->orient_int_route & INT_ROUTE_PIN_1) != 0) << 6) |
+ (((int_routes->s_tap_int_route & INT_ROUTE_PIN_1) != 0) << 5) |
+ (((int_routes->d_tap_int_route & INT_ROUTE_PIN_1) != 0) << 4) |
+ (((int_routes->slow_no_mot_int_route & INT_ROUTE_PIN_1) != 0) << 3) |
+ (((int_routes->slope_int_route & INT_ROUTE_PIN_1) != 0) << 2) |
+ (((int_routes->high_g_int_route & INT_ROUTE_PIN_1) != 0) << 1) |
+ (((int_routes->low_g_int_route & INT_ROUTE_PIN_1) != 0) << 0);
+
+ data[1] = (((int_routes->data_int_route & INT_ROUTE_PIN_2) != 0) << 7) |
+ (((int_routes->fifo_wmark_int_route & INT_ROUTE_PIN_2) != 0) << 6) |
+ (((int_routes->fifo_full_int_route & INT_ROUTE_PIN_2) != 0) << 5) |
+ (((int_routes->fifo_full_int_route & INT_ROUTE_PIN_1) != 0) << 2) |
+ (((int_routes->fifo_wmark_int_route & INT_ROUTE_PIN_1) != 0) << 1) |
+ (((int_routes->data_int_route & INT_ROUTE_PIN_1) != 0) << 0);
+
+ data[2] = (((int_routes->flat_int_route & INT_ROUTE_PIN_2) != 0) << 7) |
+ (((int_routes->orient_int_route & INT_ROUTE_PIN_2) != 0) << 6) |
+ (((int_routes->s_tap_int_route & INT_ROUTE_PIN_2) != 0) << 5) |
+ (((int_routes->d_tap_int_route & INT_ROUTE_PIN_2) != 0) << 4) |
+ (((int_routes->slow_no_mot_int_route & INT_ROUTE_PIN_2) != 0) << 3) |
+ (((int_routes->slope_int_route & INT_ROUTE_PIN_2) != 0) << 2) |
+ (((int_routes->high_g_int_route & INT_ROUTE_PIN_2) != 0) << 1) |
+ (((int_routes->low_g_int_route & INT_ROUTE_PIN_2) != 0) << 0);
+
+ rc = set_register(bma2xx, REG_ADDR_INT_MAP_0, data[0]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_INT_MAP_1, data[1]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_INT_MAP_2, data[2]);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_get_int_filters(const struct bma2xx * bma2xx,
+ struct int_filters * int_filters)
+{
+ uint8_t data;
+ int rc;
+
+ rc = get_register(bma2xx, REG_ADDR_INT_SRC, &data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ int_filters->unfiltered_data_int = data & 0x20;
+ int_filters->unfiltered_tap_int = data & 0x10;
+ int_filters->unfiltered_slow_no_mot_int = data & 0x08;
+ int_filters->unfiltered_slope_int = data & 0x04;
+ int_filters->unfiltered_high_g_int = data & 0x02;
+ int_filters->unfiltered_low_g_int = data & 0x01;
+
+ return 0;
+}
+
+int
+bma2xx_set_int_filters(const struct bma2xx * bma2xx,
+ const struct int_filters * int_filters)
+{
+ uint8_t data;
+
+ data = (int_filters->unfiltered_data_int << 5) |
+ (int_filters->unfiltered_tap_int << 4) |
+ (int_filters->unfiltered_slow_no_mot_int << 3) |
+ (int_filters->unfiltered_slope_int << 2) |
+ (int_filters->unfiltered_high_g_int << 1) |
+ (int_filters->unfiltered_low_g_int << 0);
+
+ return set_register(bma2xx, REG_ADDR_INT_SRC, data);
+}
+
+int
+bma2xx_get_int_pin_electrical(const struct bma2xx * bma2xx,
+ struct int_pin_electrical * electrical)
+{
+ uint8_t data;
+ int rc;
+
+ rc = get_register(bma2xx, REG_ADDR_INT_OUT_CTRL, &data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ if ((data & 0x02) != 0) {
+ electrical->pin1_output = INT_PIN_OUTPUT_OPEN_DRAIN;
+ } else {
+ electrical->pin1_output = INT_PIN_OUTPUT_PUSH_PULL;
+ }
+ if ((data & 0x01) != 0) {
+ electrical->pin1_active = INT_PIN_ACTIVE_HIGH;
+ } else {
+ electrical->pin1_active = INT_PIN_ACTIVE_LOW;
+ }
+ if ((data & 0x08) != 0) {
+ electrical->pin2_output = INT_PIN_OUTPUT_OPEN_DRAIN;
+ } else {
+ electrical->pin2_output = INT_PIN_OUTPUT_PUSH_PULL;
+ }
+ if ((data & 0x04) != 0) {
+ electrical->pin2_active = INT_PIN_ACTIVE_HIGH;
+ } else {
+ electrical->pin2_active = INT_PIN_ACTIVE_LOW;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_set_int_pin_electrical(const struct bma2xx * bma2xx,
+ const struct int_pin_electrical * electrical)
+{
+ uint8_t data;
+
+ data = 0;
+
+ switch (electrical->pin1_output) {
+ case INT_PIN_OUTPUT_OPEN_DRAIN:
+ data |= 0x02;
+ break;
+ case INT_PIN_OUTPUT_PUSH_PULL:
+ data |= 0x00;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ switch (electrical->pin1_active) {
+ case INT_PIN_ACTIVE_HIGH:
+ data |= 0x01;
+ break;
+ case INT_PIN_ACTIVE_LOW:
+ data |= 0x00;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ switch (electrical->pin2_output) {
+ case INT_PIN_OUTPUT_OPEN_DRAIN:
+ data |= 0x08;
+ break;
+ case INT_PIN_OUTPUT_PUSH_PULL:
+ data |= 0x00;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ switch (electrical->pin2_active) {
+ case INT_PIN_ACTIVE_HIGH:
+ data |= 0x04;
+ break;
+ case INT_PIN_ACTIVE_LOW:
+ data |= 0x00;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ return set_register(bma2xx, REG_ADDR_INT_OUT_CTRL, data);
+}
+
+int
+bma2xx_get_int_latch(const struct bma2xx * bma2xx,
+ enum int_latch * int_latch)
+{
+ uint8_t data;
+ int rc;
+
+ rc = get_register(bma2xx, REG_ADDR_INT_RST_LATCH, &data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ switch (data & 0x0F) {
+ case 0x00:
+ *int_latch = INT_LATCH_NON_LATCHED;
+ break;
+ case 0x01:
+ *int_latch = INT_LATCH_TEMPORARY_250_MS;
+ break;
+ case 0x02:
+ *int_latch = INT_LATCH_TEMPORARY_500_MS;
+ break;
+ case 0x03:
+ *int_latch = INT_LATCH_TEMPORARY_1_S;
+ break;
+ case 0x04:
+ *int_latch = INT_LATCH_TEMPORARY_2_S;
+ break;
+ case 0x05:
+ *int_latch = INT_LATCH_TEMPORARY_4_S;
+ break;
+ case 0x06:
+ *int_latch = INT_LATCH_TEMPORARY_8_S;
+ break;
+ case 0x07:
+ *int_latch = INT_LATCH_LATCHED;
+ break;
+ case 0x08:
+ *int_latch = INT_LATCH_NON_LATCHED;
+ break;
+ case 0x09:
+ *int_latch = INT_LATCH_TEMPORARY_250_US;
+ break;
+ case 0x0A:
+ *int_latch = INT_LATCH_TEMPORARY_500_US;
+ break;
+ case 0x0B:
+ *int_latch = INT_LATCH_TEMPORARY_1_MS;
+ break;
+ case 0x0C:
+ *int_latch = INT_LATCH_TEMPORARY_12_5_MS;
+ break;
+ case 0x0D:
+ *int_latch = INT_LATCH_TEMPORARY_25_MS;
+ break;
+ case 0x0E:
+ *int_latch = INT_LATCH_TEMPORARY_50_MS;
+ break;
+ case 0x0F:
+ *int_latch = INT_LATCH_LATCHED;
+ break;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_set_int_latch(const struct bma2xx * bma2xx,
+ bool reset_ints,
+ enum int_latch int_latch)
+{
+ uint8_t data;
+
+ data = 0;
+ data |= reset_ints << 7;
+
+ switch (int_latch) {
+ case INT_LATCH_NON_LATCHED:
+ data |= 0x00;
+ break;
+ case INT_LATCH_LATCHED:
+ data |= 0x0F;
+ break;
+ case INT_LATCH_TEMPORARY_250_US:
+ data |= 0x09;
+ break;
+ case INT_LATCH_TEMPORARY_500_US:
+ data |= 0x0A;
+ break;
+ case INT_LATCH_TEMPORARY_1_MS:
+ data |= 0x0B;
+ break;
+ case INT_LATCH_TEMPORARY_12_5_MS:
+ data |= 0x0C;
+ break;
+ case INT_LATCH_TEMPORARY_25_MS:
+ data |= 0x0D;
+ break;
+ case INT_LATCH_TEMPORARY_50_MS:
+ data |= 0x0E;
+ break;
+ case INT_LATCH_TEMPORARY_250_MS:
+ data |= 0x01;
+ break;
+ case INT_LATCH_TEMPORARY_500_MS:
+ data |= 0x02;
+ break;
+ case INT_LATCH_TEMPORARY_1_S:
+ data |= 0x03;
+ break;
+ case INT_LATCH_TEMPORARY_2_S:
+ data |= 0x04;
+ break;
+ case INT_LATCH_TEMPORARY_4_S:
+ data |= 0x05;
+ break;
+ case INT_LATCH_TEMPORARY_8_S:
+ data |= 0x06;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ return set_register(bma2xx, REG_ADDR_INT_RST_LATCH, data);
+}
+
+int
+bma2xx_get_low_g_int_cfg(const struct bma2xx * bma2xx,
+ struct low_g_int_cfg * low_g_int_cfg)
+{
+ uint8_t data[3];
+ int rc;
+
+ rc = get_registers(bma2xx, REG_ADDR_INT_0,
+ data, sizeof(data) / sizeof(*data));
+ if (rc != 0) {
+ return rc;
+ }
+
+ low_g_int_cfg->delay_ms = (data[0] + 1) << 1;
+ low_g_int_cfg->thresh_g = (float)data[1] * 0.00781;
+ low_g_int_cfg->hyster_g = (float)(data[2] & 0x03) * 0.125;
+ low_g_int_cfg->axis_summing = data[2] & 0x04;
+
+ return 0;
+}
+
+int
+bma2xx_set_low_g_int_cfg(const struct bma2xx * bma2xx,
+ const struct low_g_int_cfg * low_g_int_cfg)
+{
+ uint8_t data[3];
+ int rc;
+
+ if (low_g_int_cfg->delay_ms < 2 ||
+ low_g_int_cfg->delay_ms > 512) {
+ return SYS_EINVAL;
+ }
+ if (low_g_int_cfg->thresh_g < 0.0 ||
+ low_g_int_cfg->thresh_g > 1.992) {
+ return SYS_EINVAL;
+ }
+ if (low_g_int_cfg->hyster_g < 0.0 ||
+ low_g_int_cfg->hyster_g > 0.375) {
+ return SYS_EINVAL;
+ }
+
+ data[0] = (low_g_int_cfg->delay_ms >> 1) - 1;
+ data[1] = low_g_int_cfg->thresh_g / 0.00781;
+ data[2] = (low_g_int_cfg->axis_summing << 2) |
+ (((uint8_t)(low_g_int_cfg->hyster_g / 0.125) & 0x03) << 0);
+
+ rc = set_register(bma2xx, REG_ADDR_INT_0, data[0]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_INT_1, data[1]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_INT_2, data[2]);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_get_high_g_int_cfg(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ struct high_g_int_cfg * high_g_int_cfg)
+{
+ float hyster_scale;
+ float thresh_scale;
+ uint8_t data[3];
+ int rc;
+
+ switch (g_range) {
+ case BMA2XX_G_RANGE_2:
+ hyster_scale = 0.125;
+ thresh_scale = 0.00781;
+ break;
+ case BMA2XX_G_RANGE_4:
+ hyster_scale = 0.25;
+ thresh_scale = 0.01563;
+ break;
+ case BMA2XX_G_RANGE_8:
+ hyster_scale = 0.5;
+ thresh_scale = 0.03125;
+ break;
+ case BMA2XX_G_RANGE_16:
+ hyster_scale = 1.0;
+ thresh_scale = 0.0625;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ rc = get_registers(bma2xx, REG_ADDR_INT_2,
+ data, sizeof(data) / sizeof(*data));
+ if (rc != 0) {
+ return rc;
+ }
+
+ high_g_int_cfg->hyster_g = (float)((data[0] >> 6) & 0x03) * hyster_scale;
+ high_g_int_cfg->delay_ms = (data[1] + 1) << 1;
+ high_g_int_cfg->thresh_g = (float)data[2] * thresh_scale;
+
+ return 0;
+}
+
+int
+bma2xx_set_high_g_int_cfg(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ const struct high_g_int_cfg * high_g_int_cfg)
+{
+ float hyster_scale;
+ float thresh_scale;
+ uint8_t data[3];
+ int rc;
+
+ switch (g_range) {
+ case BMA2XX_G_RANGE_2:
+ hyster_scale = 0.125;
+ thresh_scale = 0.00781;
+ break;
+ case BMA2XX_G_RANGE_4:
+ hyster_scale = 0.25;
+ thresh_scale = 0.01563;
+ break;
+ case BMA2XX_G_RANGE_8:
+ hyster_scale = 0.5;
+ thresh_scale = 0.03125;
+ break;
+ case BMA2XX_G_RANGE_16:
+ hyster_scale = 1.0;
+ thresh_scale = 0.0625;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ if (high_g_int_cfg->hyster_g < 0.0 ||
+ high_g_int_cfg->hyster_g > hyster_scale * 3.0) {
+ return SYS_EINVAL;
+ }
+ if (high_g_int_cfg->delay_ms < 2 ||
+ high_g_int_cfg->delay_ms > 512) {
+ return SYS_EINVAL;
+ }
+ if (high_g_int_cfg->thresh_g < 0.0 ||
+ high_g_int_cfg->thresh_g > thresh_scale * 255.0) {
+ return SYS_EINVAL;
+ }
+
+ data[0] = ((uint8_t)(high_g_int_cfg->hyster_g / hyster_scale) & 0x03) << 6;
+ data[1] = (high_g_int_cfg->delay_ms >> 1) - 1;
+ data[2] = high_g_int_cfg->thresh_g / thresh_scale;
+
+ rc = set_register(bma2xx, REG_ADDR_INT_2, data[0]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_INT_3, data[1]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_INT_4, data[2]);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_get_slow_no_mot_int_cfg(const struct bma2xx * bma2xx,
+ bool no_motion_select,
+ enum bma2xx_g_range g_range,
+ struct slow_no_mot_int_cfg * slow_no_mot_int_cfg)
+{
+ float thresh_scale;
+ uint8_t data[2];
+ int rc;
+
+ switch (g_range) {
+ case BMA2XX_G_RANGE_2:
+ thresh_scale = 0.00391;
+ break;
+ case BMA2XX_G_RANGE_4:
+ thresh_scale = 0.00781;
+ break;
+ case BMA2XX_G_RANGE_8:
+ thresh_scale = 0.01563;
+ break;
+ case BMA2XX_G_RANGE_16:
+ thresh_scale = 0.03125;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ rc = get_register(bma2xx, REG_ADDR_INT_5, data + 0);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = get_register(bma2xx, REG_ADDR_INT_7, data + 1);
+ if (rc != 0) {
+ return rc;
+ }
+
+ if (no_motion_select) {
+ if ((data[0] & 0x80) == 0) {
+ if ((data[0] & 0x40) == 0) {
+ slow_no_mot_int_cfg->duration_p_or_s =
+ ((data[0] >> 2) & 0x0F) + 1;
+ } else {
+ slow_no_mot_int_cfg->duration_p_or_s =
+ (((data[0] >> 2) & 0x0F) << 2) + 20;
+ }
+ } else {
+ slow_no_mot_int_cfg->duration_p_or_s =
+ (((data[0] >> 2) & 0x1F) << 3) + 88;
+ }
+ } else {
+ slow_no_mot_int_cfg->duration_p_or_s =
+ ((data[0] >> 2) & 0x03) + 1;
+ }
+ slow_no_mot_int_cfg->thresh_g = (float)data[1] * thresh_scale;
+
+ return 0;
+}
+
+int
+bma2xx_set_slow_no_mot_int_cfg(const struct bma2xx * bma2xx,
+ bool no_motion_select,
+ enum bma2xx_g_range g_range,
+ const struct slow_no_mot_int_cfg * slow_no_mot_int_cfg)
+{
+ float thresh_scale;
+ uint8_t data[2];
+ uint16_t duration;
+ int rc;
+
+ switch (g_range) {
+ case BMA2XX_G_RANGE_2:
+ thresh_scale = 0.00391;
+ break;
+ case BMA2XX_G_RANGE_4:
+ thresh_scale = 0.00781;
+ break;
+ case BMA2XX_G_RANGE_8:
+ thresh_scale = 0.01563;
+ break;
+ case BMA2XX_G_RANGE_16:
+ thresh_scale = 0.03125;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ if (no_motion_select) {
+ if (slow_no_mot_int_cfg->duration_p_or_s < 1 ||
+ slow_no_mot_int_cfg->duration_p_or_s > 336) {
+ return SYS_EINVAL;
+ }
+ } else {
+ if (slow_no_mot_int_cfg->duration_p_or_s < 1 ||
+ slow_no_mot_int_cfg->duration_p_or_s > 4) {
+ return SYS_EINVAL;
+ }
+ }
+ if (slow_no_mot_int_cfg->thresh_g < 0.0 ||
+ slow_no_mot_int_cfg->thresh_g > thresh_scale * 255.0) {
+ return SYS_EINVAL;
+ }
+
+ duration = slow_no_mot_int_cfg->duration_p_or_s;
+ if (no_motion_select) {
+ if (duration > 80) {
+ if (duration < 88) {
+ duration = 88;
+ }
+ data[0] = (((duration - 88) >> 3) << 2) | 0x80;
+ } else if (duration > 16) {
+ if (duration < 20) {
+ duration = 20;
+ }
+ data[0] = (((duration - 20) >> 2) << 2) | 0x40;
+ } else {
+ data[0] = (duration - 1) << 2;
+ }
+ } else {
+ data[0] = (duration - 1) << 2;
+ }
+ data[1] = slow_no_mot_int_cfg->thresh_g / thresh_scale;
+
+ rc = set_register(bma2xx, REG_ADDR_INT_5, data[0]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_INT_7, data[1]);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_get_slope_int_cfg(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ struct slope_int_cfg * slope_int_cfg)
+{
+ float thresh_scale;
+ uint8_t data[2];
+ int rc;
+
+ switch (g_range) {
+ case BMA2XX_G_RANGE_2:
+ thresh_scale = 0.00391;
+ break;
+ case BMA2XX_G_RANGE_4:
+ thresh_scale = 0.00781;
+ break;
+ case BMA2XX_G_RANGE_8:
+ thresh_scale = 0.01563;
+ break;
+ case BMA2XX_G_RANGE_16:
+ thresh_scale = 0.03125;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ rc = get_registers(bma2xx, REG_ADDR_INT_5,
+ data, sizeof(data) / sizeof(*data));
+ if (rc != 0) {
+ return rc;
+ }
+
+ slope_int_cfg->duration_p = (data[0] & 0x03) + 1;
+ slope_int_cfg->thresh_g = (float)data[1] * thresh_scale;
+
+ return 0;
+}
+
+int
+bma2xx_set_slope_int_cfg(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ const struct slope_int_cfg * slope_int_cfg)
+{
+ float thresh_scale;
+ uint8_t data[2];
+ int rc;
+
+ switch (g_range) {
+ case BMA2XX_G_RANGE_2:
+ thresh_scale = 0.00391;
+ break;
+ case BMA2XX_G_RANGE_4:
+ thresh_scale = 0.00781;
+ break;
+ case BMA2XX_G_RANGE_8:
+ thresh_scale = 0.01563;
+ break;
+ case BMA2XX_G_RANGE_16:
+ thresh_scale = 0.03125;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ if (slope_int_cfg->duration_p < 1 ||
+ slope_int_cfg->duration_p > 4) {
+ return SYS_EINVAL;
+ }
+ if (slope_int_cfg->thresh_g < 0.0 ||
+ slope_int_cfg->thresh_g > thresh_scale * 255.0) {
+ return SYS_EINVAL;
+ }
+
+ data[0] = (slope_int_cfg->duration_p - 1) & 0x03;
+ data[1] = slope_int_cfg->thresh_g / thresh_scale;
+
+ rc = set_register(bma2xx, REG_ADDR_INT_5, data[0]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_INT_6, data[1]);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_get_tap_int_cfg(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ struct tap_int_cfg * tap_int_cfg)
+{
+ float thresh_scale;
+ uint8_t data[2];
+ int rc;
+
+ switch (g_range) {
+ case BMA2XX_G_RANGE_2:
+ thresh_scale = 0.0625;
+ break;
+ case BMA2XX_G_RANGE_4:
+ thresh_scale = 0.125;
+ break;
+ case BMA2XX_G_RANGE_8:
+ thresh_scale = 0.25;
+ break;
+ case BMA2XX_G_RANGE_16:
+ thresh_scale = 0.5;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ rc = get_registers(bma2xx, REG_ADDR_INT_8,
+ data, sizeof(data) / sizeof(*data));
+ if (rc != 0) {
+ return rc;
+ }
+
+ if ((data[0] & 0x80) == 0) {
+ tap_int_cfg->tap_quiet = BMA2XX_TAP_QUIET_30_MS;
+ } else {
+ tap_int_cfg->tap_quiet = BMA2XX_TAP_QUIET_20_MS;
+ }
+ if ((data[0] & 0x40) == 0) {
+ tap_int_cfg->tap_shock = BMA2XX_TAP_SHOCK_50_MS;
+ } else {
+ tap_int_cfg->tap_shock = BMA2XX_TAP_SHOCK_75_MS;
+ }
+
+ switch (data[0] & 0x07) {
+ case 0x00:
+ tap_int_cfg->d_tap_window = BMA2XX_D_TAP_WINDOW_50_MS;
+ break;
+ case 0x01:
+ tap_int_cfg->d_tap_window = BMA2XX_D_TAP_WINDOW_100_MS;
+ break;
+ case 0x02:
+ tap_int_cfg->d_tap_window = BMA2XX_D_TAP_WINDOW_150_MS;
+ break;
+ case 0x03:
+ tap_int_cfg->d_tap_window = BMA2XX_D_TAP_WINDOW_200_MS;
+ break;
+ case 0x04:
+ tap_int_cfg->d_tap_window = BMA2XX_D_TAP_WINDOW_250_MS;
+ break;
+ case 0x05:
+ tap_int_cfg->d_tap_window = BMA2XX_D_TAP_WINDOW_375_MS;
+ break;
+ case 0x06:
+ tap_int_cfg->d_tap_window = BMA2XX_D_TAP_WINDOW_500_MS;
+ break;
+ case 0x07:
+ tap_int_cfg->d_tap_window = BMA2XX_D_TAP_WINDOW_700_MS;
+ break;
+ }
+
+ switch ((data[1] >> 6) & 0x03) {
+ case 0x00:
+ tap_int_cfg->tap_wake_samples = BMA2XX_TAP_WAKE_SAMPLES_2;
+ break;
+ case 0x01:
+ tap_int_cfg->tap_wake_samples = BMA2XX_TAP_WAKE_SAMPLES_4;
+ break;
+ case 0x02:
+ tap_int_cfg->tap_wake_samples = BMA2XX_TAP_WAKE_SAMPLES_8;
+ break;
+ case 0x03:
+ tap_int_cfg->tap_wake_samples = BMA2XX_TAP_WAKE_SAMPLES_16;
+ break;
+ }
+
+ tap_int_cfg->thresh_g = (float)(data[1] & 0x1F) * thresh_scale;
+
+ return 0;
+}
+
+int
+bma2xx_set_tap_int_cfg(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ const struct tap_int_cfg * tap_int_cfg)
+{
+ float thresh_scale;
+ uint8_t data[2];
+ int rc;
+
+ switch (g_range) {
+ case BMA2XX_G_RANGE_2:
+ thresh_scale = 0.0625;
+ break;
+ case BMA2XX_G_RANGE_4:
+ thresh_scale = 0.125;
+ break;
+ case BMA2XX_G_RANGE_8:
+ thresh_scale = 0.25;
+ break;
+ case BMA2XX_G_RANGE_16:
+ thresh_scale = 0.5;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ if (tap_int_cfg->thresh_g < 0.0 ||
+ tap_int_cfg->thresh_g > thresh_scale * 31.0) {
+ return SYS_EINVAL;
+ }
+
+ data[0] = 0;
+ data[1] = 0;
+
+ switch (tap_int_cfg->tap_quiet) {
+ case BMA2XX_TAP_QUIET_20_MS:
+ data[0] |= 0x80;
+ break;
+ case BMA2XX_TAP_QUIET_30_MS:
+ data[0] |= 0x00;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ switch (tap_int_cfg->tap_shock) {
+ case BMA2XX_TAP_SHOCK_50_MS:
+ data[0] |= 0x00;
+ break;
+ case BMA2XX_TAP_SHOCK_75_MS:
+ data[0] |= 0x40;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ switch (tap_int_cfg->d_tap_window) {
+ case BMA2XX_D_TAP_WINDOW_50_MS:
+ data[0] |= 0x00;
+ break;
+ case BMA2XX_D_TAP_WINDOW_100_MS:
+ data[0] |= 0x01;
+ break;
+ case BMA2XX_D_TAP_WINDOW_150_MS:
+ data[0] |= 0x02;
+ break;
+ case BMA2XX_D_TAP_WINDOW_200_MS:
+ data[0] |= 0x03;
+ break;
+ case BMA2XX_D_TAP_WINDOW_250_MS:
+ data[0] |= 0x04;
+ break;
+ case BMA2XX_D_TAP_WINDOW_375_MS:
+ data[0] |= 0x05;
+ break;
+ case BMA2XX_D_TAP_WINDOW_500_MS:
+ data[0] |= 0x06;
+ break;
+ case BMA2XX_D_TAP_WINDOW_700_MS:
+ data[0] |= 0x07;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ switch (tap_int_cfg->tap_wake_samples) {
+ case BMA2XX_TAP_WAKE_SAMPLES_2:
+ data[1] |= 0x00 << 6;
+ break;
+ case BMA2XX_TAP_WAKE_SAMPLES_4:
+ data[1] |= 0x01 << 6;
+ break;
+ case BMA2XX_TAP_WAKE_SAMPLES_8:
+ data[1] |= 0x02 << 6;
+ break;
+ case BMA2XX_TAP_WAKE_SAMPLES_16:
+ data[1] |= 0x03 << 6;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ data[1] |= (uint8_t)(tap_int_cfg->thresh_g / thresh_scale) & 0x1F;
+
+ rc = set_register(bma2xx, REG_ADDR_INT_8, data[0]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_INT_9, data[1]);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_get_orient_int_cfg(const struct bma2xx * bma2xx,
+ struct orient_int_cfg * orient_int_cfg)
+{
+ uint8_t data[2];
+ int rc;
+
+ rc = get_registers(bma2xx, REG_ADDR_INT_A,
+ data, sizeof(data) / sizeof(*data));
+ if (rc != 0) {
+ return rc;
+ }
+
+ orient_int_cfg->hyster_g = (float)((data[0] >> 4) & 0x07) * 0.0625;
+
+ switch ((data[0] >> 2) & 0x03) {
+ case 0x00:
+ orient_int_cfg->orient_blocking =
+ BMA2XX_ORIENT_BLOCKING_NONE;
+ break;
+ case 0x01:
+ orient_int_cfg->orient_blocking =
+ BMA2XX_ORIENT_BLOCKING_ACCEL_ONLY;
+ break;
+ case 0x02:
+ orient_int_cfg->orient_blocking =
+ BMA2XX_ORIENT_BLOCKING_ACCEL_AND_SLOPE;
+ break;
+ case 0x03:
+ orient_int_cfg->orient_blocking =
+ BMA2XX_ORIENT_BLOCKING_ACCEL_AND_SLOPE_AND_STABLE;
+ break;
+ }
+
+ switch (data[0] & 0x03) {
+ case 0x00:
+ orient_int_cfg->orient_mode =
+ BMA2XX_ORIENT_MODE_SYMMETRICAL;
+ break;
+ case 0x01:
+ orient_int_cfg->orient_mode =
+ BMA2XX_ORIENT_MODE_HIGH_ASYMMETRICAL;
+ break;
+ case 0x02:
+ orient_int_cfg->orient_mode =
+ BMA2XX_ORIENT_MODE_LOW_ASYMMETRICAL;
+ break;
+ case 0x03:
+ orient_int_cfg->orient_mode =
+ BMA2XX_ORIENT_MODE_SYMMETRICAL;
+ break;
+ }
+
+ orient_int_cfg->signal_up_dn = data[1] & 0x40;
+ orient_int_cfg->blocking_angle = data[1] & 0x3F;
+
+ return 0;
+}
+
+int
+bma2xx_set_orient_int_cfg(const struct bma2xx * bma2xx,
+ const struct orient_int_cfg * orient_int_cfg)
+{
+ uint8_t data[2];
+ int rc;
+
+ if (orient_int_cfg->hyster_g < 0.0 ||
+ orient_int_cfg->hyster_g > (0.0625 * 7.0)) {
+ return SYS_EINVAL;
+ }
+ if (orient_int_cfg->blocking_angle > 0x3F) {
+ return SYS_EINVAL;
+ }
+
+ data[0] = (uint8_t)(orient_int_cfg->hyster_g / 0.0625) << 4;
+
+ switch (orient_int_cfg->orient_blocking) {
+ case BMA2XX_ORIENT_BLOCKING_NONE:
+ data[0] |= 0x00 << 2;
+ break;
+ case BMA2XX_ORIENT_BLOCKING_ACCEL_ONLY:
+ data[0] |= 0x01 << 2;
+ break;
+ case BMA2XX_ORIENT_BLOCKING_ACCEL_AND_SLOPE:
+ data[0] |= 0x02 << 2;
+ break;
+ case BMA2XX_ORIENT_BLOCKING_ACCEL_AND_SLOPE_AND_STABLE:
+ data[0] |= 0x03 << 2;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ switch (orient_int_cfg->orient_mode) {
+ case BMA2XX_ORIENT_MODE_SYMMETRICAL:
+ data[0] |= 0x00;
+ break;
+ case BMA2XX_ORIENT_MODE_HIGH_ASYMMETRICAL:
+ data[0] |= 0x01;
+ break;
+ case BMA2XX_ORIENT_MODE_LOW_ASYMMETRICAL:
+ data[0] |= 0x02;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ data[1] = (orient_int_cfg->signal_up_dn << 6) |
+ ((orient_int_cfg->blocking_angle & 0x3F) << 0);
+
+ rc = set_register(bma2xx, REG_ADDR_INT_A, data[0]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_INT_B, data[1]);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_get_flat_int_cfg(const struct bma2xx * bma2xx,
+ struct flat_int_cfg * flat_int_cfg)
+{
+ uint8_t data[2];
+ int rc;
+
+ rc = get_registers(bma2xx, REG_ADDR_INT_C,
+ data, sizeof(data) / sizeof(*data));
+ if (rc != 0) {
+ return rc;
+ }
+
+ flat_int_cfg->flat_angle = data[0] & 0x3F;
+
+ switch ((data[1] >> 4) & 0x03) {
+ case 0x00:
+ flat_int_cfg->flat_hold = FLAT_HOLD_0_MS;
+ break;
+ case 0x01:
+ flat_int_cfg->flat_hold = FLAT_HOLD_512_MS;
+ break;
+ case 0x02:
+ flat_int_cfg->flat_hold = FLAT_HOLD_1024_MS;
+ break;
+ case 0x03:
+ flat_int_cfg->flat_hold = FLAT_HOLD_2048_MS;
+ break;
+ }
+
+ flat_int_cfg->flat_hyster = data[1] & 0x07;
+ flat_int_cfg->hyster_enable = (data[1] & 0x07) != 0x00;
+
+ return 0;
+}
+
+int
+bma2xx_set_flat_int_cfg(const struct bma2xx * bma2xx,
+ const struct flat_int_cfg * flat_int_cfg)
+{
+ uint8_t data[2];
+ int rc;
+
+ if (flat_int_cfg->flat_angle > 0x3F) {
+ return SYS_EINVAL;
+ }
+ if (flat_int_cfg->flat_hyster == 0x00 &&
+ flat_int_cfg->hyster_enable) {
+ return SYS_EINVAL;
+ }
+
+ data[0] = flat_int_cfg->flat_angle & 0x3F;
+ data[1] = 0;
+
+ switch (flat_int_cfg->flat_hold) {
+ case FLAT_HOLD_0_MS:
+ data[1] |= 0x00 << 4;
+ break;
+ case FLAT_HOLD_512_MS:
+ data[1] |= 0x01 << 4;
+ break;
+ case FLAT_HOLD_1024_MS:
+ data[1] |= 0x02 << 4;
+ break;
+ case FLAT_HOLD_2048_MS:
+ data[1] |= 0x03 << 4;
+ break;
+ }
+
+ if (flat_int_cfg->hyster_enable) {
+ data[1] |= flat_int_cfg->flat_hyster & 0x07;
+ }
+
+ rc = set_register(bma2xx, REG_ADDR_INT_C, data[0]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_INT_D, data[1]);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_get_fifo_wmark_level(const struct bma2xx * bma2xx,
+ uint8_t * wmark_level)
+{
+ uint8_t data;
+ int rc;
+
+ rc = get_register(bma2xx, REG_ADDR_FIFO_CONFIG_0, &data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ *wmark_level = data & 0x3F;
+
+ return 0;
+}
+
+int
+bma2xx_set_fifo_wmark_level(const struct bma2xx * bma2xx,
+ uint8_t wmark_level)
+{
+ uint8_t data;
+
+ if (wmark_level > 32) {
+ return SYS_EINVAL;
+ }
+
+ data = wmark_level & 0x3F;
+
+ return set_register(bma2xx, REG_ADDR_FIFO_CONFIG_0, data);
+}
+
+int
+bma2xx_get_self_test_cfg(const struct bma2xx * bma2xx,
+ struct self_test_cfg * self_test_cfg)
+{
+ uint8_t data;
+ int rc;
+
+ rc = get_register(bma2xx, REG_ADDR_PMU_SELF_TEST, &data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ if ((data & 0x10) == 0) {
+ self_test_cfg->self_test_ampl = SELF_TEST_AMPL_LOW;
+ } else {
+ self_test_cfg->self_test_ampl = SELF_TEST_AMPL_HIGH;
+ }
+ if ((data & 0x04) == 0) {
+ self_test_cfg->self_test_sign = SELF_TEST_SIGN_NEGATIVE;
+ } else {
+ self_test_cfg->self_test_sign = SELF_TEST_SIGN_POSITIVE;
+ }
+
+ switch (data & 0x03) {
+ case 0x00:
+ self_test_cfg->self_test_axis = -1;
+ self_test_cfg->self_test_enabled = false;
+ break;
+ case 0x01:
+ self_test_cfg->self_test_axis = AXIS_X;
+ self_test_cfg->self_test_enabled = true;
+ break;
+ case 0x02:
+ self_test_cfg->self_test_axis = AXIS_Y;
+ self_test_cfg->self_test_enabled = true;
+ break;
+ case 0x03:
+ self_test_cfg->self_test_axis = AXIS_Z;
+ self_test_cfg->self_test_enabled = true;
+ break;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_set_self_test_cfg(const struct bma2xx * bma2xx,
+ const struct self_test_cfg * self_test_cfg)
+{
+ uint8_t data;
+
+ data = 0;
+
+ switch (self_test_cfg->self_test_ampl) {
+ case SELF_TEST_AMPL_HIGH:
+ data |= 0x10;
+ break;
+ case SELF_TEST_AMPL_LOW:
+ data |= 0x00;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ switch (self_test_cfg->self_test_sign) {
+ case SELF_TEST_SIGN_NEGATIVE:
+ data |= 0x00;
+ break;
+ case SELF_TEST_SIGN_POSITIVE:
+ data |= 0x04;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ if (self_test_cfg->self_test_enabled) {
+ switch (self_test_cfg->self_test_axis) {
+ case AXIS_X:
+ data |= 0x01;
+ break;
+ case AXIS_Y:
+ data |= 0x02;
+ break;
+ case AXIS_Z:
+ data |= 0x03;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+ }
+
+ return set_register(bma2xx, REG_ADDR_PMU_SELF_TEST, data);
+}
+
+int
+bma2xx_get_nvm_control(const struct bma2xx * bma2xx,
+ uint8_t * remaining_cycles,
+ bool * load_from_nvm,
+ bool * nvm_is_ready,
+ bool * nvm_unlocked)
+{
+ uint8_t data;
+ int rc;
+
+ rc = get_register(bma2xx, REG_ADDR_TRIM_NVM_CTRL, &data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ *remaining_cycles = (data >> 4) & 0x0F;
+ *load_from_nvm = data & 0x08;
+ *nvm_is_ready = data & 0x04;
+ *nvm_unlocked = data & 0x01;
+
+ return 0;
+}
+
+int
+bma2xx_set_nvm_control(const struct bma2xx * bma2xx,
+ bool load_from_nvm,
+ bool store_into_nvm,
+ bool nvm_unlocked)
+{
+ uint8_t data;
+
+ data = (load_from_nvm << 3) |
+ (store_into_nvm << 1) |
+ (nvm_unlocked << 0);
+
+ return set_register(bma2xx, REG_ADDR_TRIM_NVM_CTRL, data);
+}
+
+int
+bma2xx_get_i2c_watchdog(const struct bma2xx * bma2xx,
+ enum i2c_watchdog * i2c_watchdog)
+{
+ uint8_t data;
+ int rc;
+
+ rc = get_register(bma2xx, REG_ADDR_BGW_SPI3_WDT, &data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ if ((data & 0x04) != 0) {
+ if ((data & 0x02) != 0) {
+ *i2c_watchdog = I2C_WATCHDOG_50_MS;
+ } else {
+ *i2c_watchdog = I2C_WATCHDOG_1_MS;
+ }
+ } else {
+ *i2c_watchdog = I2C_WATCHDOG_DISABLED;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_set_i2c_watchdog(const struct bma2xx * bma2xx,
+ enum i2c_watchdog i2c_watchdog)
+{
+ uint8_t data;
+
+ switch (i2c_watchdog) {
+ case I2C_WATCHDOG_DISABLED:
+ data = 0x00;
+ break;
+ case I2C_WATCHDOG_1_MS:
+ data = 0x04;
+ break;
+ case I2C_WATCHDOG_50_MS:
+ data = 0x06;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ return set_register(bma2xx, REG_ADDR_BGW_SPI3_WDT, data);
+}
+
+int
+bma2xx_get_fast_ofc_cfg(const struct bma2xx * bma2xx,
+ bool * fast_ofc_ready,
+ enum bma2xx_offset_comp_target * ofc_target_z,
+ enum bma2xx_offset_comp_target * ofc_target_y,
+ enum bma2xx_offset_comp_target * ofc_target_x)
+{
+ uint8_t data[2];
+ int rc;
+
+ rc = get_registers(bma2xx, REG_ADDR_OFC_CTRL,
+ data, sizeof(data) / sizeof(*data));
+ if (rc != 0) {
+ return rc;
+ }
+
+ *fast_ofc_ready = data[0] & 0x10;
+
+ switch ((data[1] >> 5) & 0x03) {
+ case 0x00:
+ *ofc_target_z = BMA2XX_OFFSET_COMP_TARGET_0_G;
+ break;
+ case 0x01:
+ *ofc_target_z = BMA2XX_OFFSET_COMP_TARGET_POS_1_G;
+ break;
+ case 0x02:
+ *ofc_target_z = BMA2XX_OFFSET_COMP_TARGET_NEG_1_G;
+ break;
+ case 0x03:
+ *ofc_target_z = BMA2XX_OFFSET_COMP_TARGET_0_G;
+ break;
+ }
+
+ switch ((data[1] >> 3) & 0x03) {
+ case 0x00:
+ *ofc_target_y = BMA2XX_OFFSET_COMP_TARGET_0_G;
+ break;
+ case 0x01:
+ *ofc_target_y = BMA2XX_OFFSET_COMP_TARGET_POS_1_G;
+ break;
+ case 0x02:
+ *ofc_target_y = BMA2XX_OFFSET_COMP_TARGET_NEG_1_G;
+ break;
+ case 0x03:
+ *ofc_target_y = BMA2XX_OFFSET_COMP_TARGET_0_G;
+ break;
+ }
+
+ switch ((data[1] >> 1) & 0x03) {
+ case 0x00:
+ *ofc_target_x = BMA2XX_OFFSET_COMP_TARGET_0_G;
+ break;
+ case 0x01:
+ *ofc_target_x = BMA2XX_OFFSET_COMP_TARGET_POS_1_G;
+ break;
+ case 0x02:
+ *ofc_target_x = BMA2XX_OFFSET_COMP_TARGET_NEG_1_G;
+ break;
+ case 0x03:
+ *ofc_target_x = BMA2XX_OFFSET_COMP_TARGET_0_G;
+ break;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_set_fast_ofc_cfg(const struct bma2xx * bma2xx,
+ enum axis fast_ofc_axis,
+ enum bma2xx_offset_comp_target fast_ofc_target,
+ bool trigger_fast_ofc)
+{
+ uint8_t data[2];
+ uint8_t axis_value;
+ uint8_t axis_shift;
+ int rc;
+
+ data[0] = 0;
+ data[1] = 0;
+
+ switch (fast_ofc_axis) {
+ case AXIS_X:
+ axis_value = 0x01;
+ axis_shift = 1;
+ break;
+ case AXIS_Y:
+ axis_value = 0x02;
+ axis_shift = 3;
+ break;
+ case AXIS_Z:
+ axis_value = 0x03;
+ axis_shift = 5;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ switch (fast_ofc_target) {
+ case BMA2XX_OFFSET_COMP_TARGET_0_G:
+ data[1] |= 0x00 << axis_shift;
+ break;
+ case BMA2XX_OFFSET_COMP_TARGET_NEG_1_G:
+ data[1] |= 0x02 << axis_shift;
+ break;
+ case BMA2XX_OFFSET_COMP_TARGET_POS_1_G:
+ data[1] |= 0x01 << axis_shift;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ if (trigger_fast_ofc) {
+ data[0] |= axis_value << 5;
+ }
+
+ rc = set_register(bma2xx, REG_ADDR_OFC_SETTING, data[1]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_OFC_CTRL, data[0]);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_get_slow_ofc_cfg(const struct bma2xx * bma2xx,
+ struct slow_ofc_cfg * slow_ofc_cfg)
+{
+ uint8_t data[2];
+ int rc;
+
+ rc = get_registers(bma2xx, REG_ADDR_OFC_CTRL,
+ data, sizeof(data) / sizeof(*data));
+ if (rc != 0) {
+ return rc;
+ }
+
+ slow_ofc_cfg->ofc_z_enabled = data[0] & 0x04;
+ slow_ofc_cfg->ofc_y_enabled = data[0] & 0x02;
+ slow_ofc_cfg->ofc_x_enabled = data[0] & 0x01;
+ slow_ofc_cfg->high_bw_cut_off = data[1] & 0x01;
+
+ return 0;
+}
+
+int
+bma2xx_set_slow_ofc_cfg(const struct bma2xx * bma2xx,
+ const struct slow_ofc_cfg * slow_ofc_cfg)
+{
+ uint8_t data[2];
+ int rc;
+
+ data[0] = (slow_ofc_cfg->ofc_z_enabled << 2) |
+ (slow_ofc_cfg->ofc_y_enabled << 1) |
+ (slow_ofc_cfg->ofc_x_enabled << 0);
+ data[1] = slow_ofc_cfg->high_bw_cut_off << 0;
+
+ rc = set_register(bma2xx, REG_ADDR_OFC_SETTING, data[1]);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = set_register(bma2xx, REG_ADDR_OFC_CTRL, data[0]);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_set_ofc_reset(const struct bma2xx * bma2xx)
+{
+ return set_register(bma2xx, REG_ADDR_OFC_CTRL, 0x80);
+}
+
+int
+bma2xx_get_ofc_offset(const struct bma2xx * bma2xx,
+ enum axis axis,
+ float * offset_g)
+{
+ uint8_t reg_addr;
+ uint8_t data;
+ int rc;
+
+ switch (axis) {
+ case AXIS_X:
+ reg_addr = REG_ADDR_OFC_OFFSET_X;
+ break;
+ case AXIS_Y:
+ reg_addr = REG_ADDR_OFC_OFFSET_Y;
+ break;
+ case AXIS_Z:
+ reg_addr = REG_ADDR_OFC_OFFSET_Z;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ rc = get_register(bma2xx, reg_addr, &data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ *offset_g = (float)(int8_t)data * 0.00781;
+
+ return 0;
+}
+
+int
+bma2xx_set_ofc_offset(const struct bma2xx * bma2xx,
+ enum axis axis,
+ float offset_g)
+{
+ uint8_t reg_addr;
+ uint8_t data;
+
+ switch (axis) {
+ case AXIS_X:
+ reg_addr = REG_ADDR_OFC_OFFSET_X;
+ break;
+ case AXIS_Y:
+ reg_addr = REG_ADDR_OFC_OFFSET_Y;
+ break;
+ case AXIS_Z:
+ reg_addr = REG_ADDR_OFC_OFFSET_Z;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ data = (int8_t)(offset_g / 0.00781);
+
+ return set_register(bma2xx, reg_addr, data);
+}
+
+int
+bma2xx_get_saved_data(const struct bma2xx * bma2xx,
+ enum saved_data_addr saved_data_addr,
+ uint8_t * saved_data_val)
+{
+ uint8_t reg_addr;
+
+ switch (saved_data_addr) {
+ case SAVED_DATA_ADDR_0:
+ reg_addr = REG_ADDR_TRIM_GP0;
+ break;
+ case SAVED_DATA_ADDR_1:
+ reg_addr = REG_ADDR_TRIM_GP1;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ return get_register(bma2xx, reg_addr, saved_data_val);
+}
+
+int
+bma2xx_set_saved_data(const struct bma2xx * bma2xx,
+ enum saved_data_addr saved_data_addr,
+ uint8_t saved_data_val)
+{
+ uint8_t reg_addr;
+
+ switch (saved_data_addr) {
+ case SAVED_DATA_ADDR_0:
+ reg_addr = REG_ADDR_TRIM_GP0;
+ break;
+ case SAVED_DATA_ADDR_1:
+ reg_addr = REG_ADDR_TRIM_GP1;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ return set_register(bma2xx, reg_addr, saved_data_val);
+}
+
+int
+bma2xx_get_fifo_cfg(const struct bma2xx * bma2xx,
+ struct fifo_cfg * fifo_cfg)
+{
+ uint8_t data;
+ int rc;
+
+ rc = get_register(bma2xx, REG_ADDR_FIFO_CONFIG_1, &data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ switch ((data >> 6) & 0x03) {
+ case 0x03:
+ BMA2XX_ERROR("unknown FIFO_CONFIG_1 reg value 0x%02X\n", data);
+ case 0x00:
+ fifo_cfg->fifo_mode = FIFO_MODE_BYPASS;
+ break;
+ case 0x01:
+ fifo_cfg->fifo_mode = FIFO_MODE_FIFO;
+ break;
+ case 0x02:
+ fifo_cfg->fifo_mode = FIFO_MODE_STREAM;
+ break;
+ }
+
+ switch ((data >> 0) & 0x03) {
+ case 0x00:
+ fifo_cfg->fifo_data = FIFO_DATA_X_AND_Y_AND_Z;
+ break;
+ case 0x01:
+ fifo_cfg->fifo_data = FIFO_DATA_X_ONLY;
+ break;
+ case 0x02:
+ fifo_cfg->fifo_data = FIFO_DATA_Y_ONLY;
+ break;
+ case 0x03:
+ fifo_cfg->fifo_data = FIFO_DATA_Z_ONLY;
+ break;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_set_fifo_cfg(const struct bma2xx * bma2xx,
+ const struct fifo_cfg * fifo_cfg)
+{
+ uint8_t data;
+
+ data = 0;
+
+ switch (fifo_cfg->fifo_mode) {
+ case FIFO_MODE_BYPASS:
+ data |= 0x00 << 6;
+ break;
+ case FIFO_MODE_FIFO:
+ data |= 0x01 << 6;
+ break;
+ case FIFO_MODE_STREAM:
+ data |= 0x02 << 6;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ switch (fifo_cfg->fifo_data) {
+ case FIFO_DATA_X_AND_Y_AND_Z:
+ data |= 0x00 << 0;
+ break;
+ case FIFO_DATA_X_ONLY:
+ data |= 0x01 << 0;
+ break;
+ case FIFO_DATA_Y_ONLY:
+ data |= 0x02 << 0;
+ break;
+ case FIFO_DATA_Z_ONLY:
+ data |= 0x03 << 0;
+ break;
+ }
+
+ return set_register(bma2xx, REG_ADDR_FIFO_CONFIG_1, data);
+}
+
+int
+bma2xx_get_fifo(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ enum fifo_data fifo_data,
+ struct accel_data * accel_data)
+{
+ float accel_scale;
+ uint8_t size, iter;
+ uint8_t data[AXIS_ALL << 1];
+ int rc;
+
+ rc = get_accel_scale(bma2xx->cfg.model, g_range, &accel_scale);
+ if (rc != 0){
+ return SYS_EINVAL;
+ }
+
+ switch (fifo_data) {
+ case FIFO_DATA_X_AND_Y_AND_Z:
+ size = AXIS_ALL << 1;
+ break;
+ case FIFO_DATA_X_ONLY:
+ case FIFO_DATA_Y_ONLY:
+ case FIFO_DATA_Z_ONLY:
+ size = 1 << 1;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ rc = get_registers(bma2xx, REG_ADDR_FIFO_DATA, data, size);
+ if (rc != 0) {
+ return rc;
+ }
+
+ for (iter = 0; iter < size; iter += 2) {
+ compute_accel_data(accel_data + (iter >> 1),
+ bma2xx->cfg.model,
+ data + iter,
+ accel_scale);
+ }
+
+ return 0;
+}
+
+static int
+reset_and_recfg(struct bma2xx * bma2xx)
+{
+ const struct bma2xx_cfg * cfg;
+ int rc;
+ enum int_route int_route;
+ struct int_routes int_routes;
+ struct int_filters int_filters;
+ struct int_pin_electrical int_pin_electrical;
+ struct low_g_int_cfg low_g_int_cfg;
+ struct high_g_int_cfg high_g_int_cfg;
+ struct tap_int_cfg tap_int_cfg;
+ struct orient_int_cfg orient_int_cfg;
+ enum i2c_watchdog i2c_watchdog;
+ struct fifo_cfg fifo_cfg;
+ struct bma2xx_private_driver_data *pdd;
+
+ cfg = &bma2xx->cfg;
+ pdd = &bma2xx->pdd;
+
+ bma2xx->power = BMA2XX_POWER_MODE_NORMAL;
+
+ rc = bma2xx_set_softreset(bma2xx);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_set_g_range(bma2xx, cfg->g_range);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_set_filter_bandwidth(bma2xx, cfg->filter_bandwidth);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_set_data_acquisition(bma2xx,
+ cfg->use_unfiltered_data,
+ false);
+ if (rc != 0) {
+ return rc;
+ }
+
+ int_route = INT_ROUTE_NONE;
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+ int_route = pdd->int_route;
+#endif
+
+ int_routes.flat_int_route = INT_ROUTE_NONE;
+ int_routes.orient_int_route = int_route;
+ int_routes.s_tap_int_route = INT_ROUTE_NONE;
+ int_routes.d_tap_int_route = INT_ROUTE_NONE;
+ int_routes.slow_no_mot_int_route = INT_ROUTE_NONE;
+ int_routes.slope_int_route = INT_ROUTE_NONE;
+ int_routes.high_g_int_route = int_route;
+ int_routes.low_g_int_route = int_route;
+ int_routes.fifo_wmark_int_route = INT_ROUTE_NONE;
+ int_routes.fifo_full_int_route = INT_ROUTE_NONE;
+ int_routes.data_int_route = int_route;
+
+ rc = bma2xx_set_int_routes(bma2xx, &int_routes);
+ if (rc != 0) {
+ return rc;
+ }
+
+ int_filters.unfiltered_data_int = cfg->use_unfiltered_data;
+ int_filters.unfiltered_tap_int = cfg->use_unfiltered_data;
+ int_filters.unfiltered_slow_no_mot_int = cfg->use_unfiltered_data;
+ int_filters.unfiltered_slope_int = cfg->use_unfiltered_data;
+ int_filters.unfiltered_high_g_int = cfg->use_unfiltered_data;
+ int_filters.unfiltered_low_g_int = cfg->use_unfiltered_data;
+
+ rc = bma2xx_set_int_filters(bma2xx, &int_filters);
+ if (rc != 0) {
+ return rc;
+ }
+
+#if MYNEWT_VAL(BMA2XX_INT_CFG_OUTPUT)
+ int_pin_electrical.pin1_output = INT_PIN_OUTPUT_OPEN_DRAIN;
+ int_pin_electrical.pin2_output = INT_PIN_OUTPUT_OPEN_DRAIN;
+#else
+ int_pin_electrical.pin1_output = INT_PIN_OUTPUT_PUSH_PULL;
+ int_pin_electrical.pin2_output = INT_PIN_OUTPUT_PUSH_PULL;
+#endif
+#if MYNEWT_VAL(BMA2XX_INT_CFG_ACTIVE)
+ int_pin_electrical.pin1_active = INT_PIN_ACTIVE_HIGH;
+ int_pin_electrical.pin2_active = INT_PIN_ACTIVE_HIGH;
+#else
+ int_pin_electrical.pin1_active = INT_PIN_ACTIVE_LOW;
+ int_pin_electrical.pin2_active = INT_PIN_ACTIVE_LOW;
+#endif
+
+ rc = bma2xx_set_int_pin_electrical(bma2xx, &int_pin_electrical);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_set_int_latch(bma2xx, false, INT_LATCH_NON_LATCHED);
+ if (rc != 0) {
+ return rc;
+ }
+
+ low_g_int_cfg.delay_ms = cfg->low_g_delay_ms;
+ low_g_int_cfg.thresh_g = cfg->low_g_thresh_g;
+ low_g_int_cfg.hyster_g = cfg->low_g_hyster_g;
+ low_g_int_cfg.axis_summing = false;
+
+ rc = bma2xx_set_low_g_int_cfg(bma2xx, &low_g_int_cfg);
+ if (rc != 0) {
+ return rc;
+ }
+
+ high_g_int_cfg.hyster_g = cfg->high_g_hyster_g;
+ high_g_int_cfg.delay_ms = cfg->high_g_delay_ms;
+ high_g_int_cfg.thresh_g = cfg->high_g_thresh_g;
+
+ rc = bma2xx_set_high_g_int_cfg(bma2xx, cfg->g_range, &high_g_int_cfg);
+ if (rc != 0) {
+ return rc;
+ }
+
+ tap_int_cfg.tap_quiet = cfg->tap_quiet;
+ tap_int_cfg.tap_shock = cfg->tap_shock;
+ tap_int_cfg.d_tap_window = cfg->d_tap_window;
+ tap_int_cfg.tap_wake_samples = cfg->tap_wake_samples;
+ tap_int_cfg.thresh_g = cfg->tap_thresh_g;
+
+ rc = bma2xx_set_tap_int_cfg(bma2xx, cfg->g_range, &tap_int_cfg);
+ if (rc != 0) {
+ return rc;
+ }
+
+ orient_int_cfg.hyster_g = cfg->orient_hyster_g;
+ orient_int_cfg.orient_blocking = cfg->orient_blocking;
+ orient_int_cfg.orient_mode = cfg->orient_mode;
+ orient_int_cfg.signal_up_dn = cfg->orient_signal_ud;
+ orient_int_cfg.blocking_angle = 0x08;
+
+ rc = bma2xx_set_orient_int_cfg(bma2xx, &orient_int_cfg);
+ if (rc != 0) {
+ return rc;
+ }
+
+#if MYNEWT_VAL(BMA2XX_I2C_WDT)
+ i2c_watchdog = I2C_WATCHDOG_50_MS;
+#else
+ i2c_watchdog = I2C_WATCHDOG_DISABLED;
+#endif
+
+ rc = bma2xx_set_i2c_watchdog(bma2xx, i2c_watchdog);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_set_ofc_offset(bma2xx, AXIS_X, cfg->offset_x_g);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_set_ofc_offset(bma2xx, AXIS_Y, cfg->offset_y_g);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_set_ofc_offset(bma2xx, AXIS_Z, cfg->offset_z_g);
+ if (rc != 0) {
+ return rc;
+ }
+
+ fifo_cfg.fifo_mode = FIFO_MODE_BYPASS;
+ fifo_cfg.fifo_data = FIFO_DATA_X_AND_Y_AND_Z;
+
+ rc = bma2xx_set_fifo_cfg(bma2xx, &fifo_cfg);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+static int
+change_power(struct bma2xx * bma2xx,
+ enum bma2xx_power_mode target)
+{
+ const struct bma2xx_cfg * cfg;
+ int rc;
+ bool step1_move;
+ bool step2_move;
+ enum bma2xx_power_mode step1_mode;
+ enum bma2xx_power_mode step2_mode;
+ struct power_settings power_settings;
+
+ cfg = &bma2xx->cfg;
+
+ if (bma2xx->power == BMA2XX_POWER_MODE_DEEP_SUSPEND) {
+ rc = reset_and_recfg(bma2xx);
+ if (rc != 0) {
+ return rc;
+ }
+ }
+
+ step1_move = false;
+ switch (bma2xx->power) {
+ case BMA2XX_POWER_MODE_SUSPEND:
+ case BMA2XX_POWER_MODE_LPM_1:
+ switch (target) {
+ case BMA2XX_POWER_MODE_STANDBY:
+ case BMA2XX_POWER_MODE_LPM_2:
+ step1_mode = BMA2XX_POWER_MODE_NORMAL;
+ step1_move = true;
+ break;
+ default:
+ break;
+ }
+ break;
+ case BMA2XX_POWER_MODE_STANDBY:
+ case BMA2XX_POWER_MODE_LPM_2:
+ switch (target) {
+ case BMA2XX_POWER_MODE_SUSPEND:
+ case BMA2XX_POWER_MODE_LPM_1:
+ step1_mode = BMA2XX_POWER_MODE_NORMAL;
+ step1_move = true;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (bma2xx->power != target) {
+ step2_mode = target;
+ step2_move = true;
+ } else {
+ step2_move = false;
+ }
+
+ if (step1_move) {
+ power_settings.power_mode = step1_mode;
+ power_settings.sleep_duration = cfg->sleep_duration;
+ power_settings.sleep_timer = SLEEP_TIMER_EVENT_DRIVEN;
+
+ rc = bma2xx_set_power_settings(bma2xx, &power_settings);
+ if (rc != 0) {
+ return rc;
+ }
+
+ bma2xx->power = step1_mode;
+ }
+
+ if (step2_move) {
+ power_settings.power_mode = step2_mode;
+ power_settings.sleep_duration = cfg->sleep_duration;
+ power_settings.sleep_timer = SLEEP_TIMER_EVENT_DRIVEN;
+
+ rc = bma2xx_set_power_settings(bma2xx, &power_settings);
+ if (rc != 0) {
+ return rc;
+ }
+
+ bma2xx->power = step2_mode;
+ }
+
+ return 0;
+}
+
+static int
+interim_power(struct bma2xx * bma2xx,
+ const enum bma2xx_power_mode * reqs,
+ uint8_t size)
+{
+ uint8_t i;
+
+ if (size == 0) {
+ return SYS_EINVAL;
+ }
+
+ for (i = 0; i < size; i++) {
+ if (reqs[i] == bma2xx->power) {
+ return 0;
+ }
+ }
+
+ return change_power(bma2xx, reqs[0]);
+}
+
+static int
+default_power(struct bma2xx * bma2xx)
+{
+ const struct bma2xx_cfg * cfg;
+
+ cfg = &bma2xx->cfg;
+
+ if (cfg->power_mode == bma2xx->power) {
+ return 0;
+ }
+
+ return change_power(bma2xx, cfg->power_mode);
+}
+
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+static int
+init_intpin(struct bma2xx * bma2xx,
+ hal_gpio_irq_handler_t handler,
+ void * arg)
+{
+ struct bma2xx_private_driver_data *pdd = &bma2xx->pdd;
+ hal_gpio_irq_trig_t trig;
+ int pin = -1;
+ int rc;
+ int i;
+
+ for (i = 0; i < MYNEWT_VAL(SENSOR_MAX_INTERRUPTS_PINS); i++){
+ pin = bma2xx->sensor.s_itf.si_ints[i].host_pin;
+ if (pin > 0) {
+ break;
+ }
+ }
+
+ if (pin < 0) {
+ BMA2XX_ERROR("Interrupt pin not configured\n");
+ return SYS_EINVAL;
+ }
+
+ pdd->int_num = i;
+ if (bma2xx->sensor.s_itf.si_ints[pdd->int_num].active) {
+ trig = HAL_GPIO_TRIG_RISING;
+ } else {
+ trig = HAL_GPIO_TRIG_FALLING;
+ }
+
+ if (bma2xx->sensor.s_itf.si_ints[pdd->int_num].device_pin == 1) {
+ pdd->int_route = INT_ROUTE_PIN_1;
+ } else if (bma2xx->sensor.s_itf.si_ints[pdd->int_num].device_pin == 2) {
+ pdd->int_route = INT_ROUTE_PIN_2;
+ } else {
+ BMA2XX_ERROR("Route not configured\n");
+ return SYS_EINVAL;
+ }
+
+ rc = hal_gpio_irq_init(pin,
+ handler,
+ arg,
+ trig,
+ HAL_GPIO_PULL_NONE);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+static void
+enable_intpin(struct bma2xx * bma2xx)
+{
+ struct bma2xx_private_driver_data *pdd = &bma2xx->pdd;
+ enum bma2xx_int_num int_num = pdd->int_num;
+
+ pdd->int_ref_cnt++;
+
+ if (pdd->int_ref_cnt == 1) {
+ hal_gpio_irq_enable(bma2xx->sensor.s_itf.si_ints[int_num].host_pin);
+ }
+}
+
+static void
+disable_intpin(struct bma2xx * bma2xx)
+{
+ struct bma2xx_private_driver_data *pdd = &bma2xx->pdd;
+ enum bma2xx_int_num int_num = pdd->int_num;
+
+ if (pdd->int_ref_cnt == 0) {
+ return;
+ }
+
+ pdd->int_ref_cnt--;
+
+ if (pdd->int_ref_cnt == 0) {
+ hal_gpio_irq_disable(bma2xx->sensor.s_itf.si_ints[int_num].host_pin);
+ }
+}
+#endif
+
+static int
+self_test_enable(const struct bma2xx * bma2xx,
+ enum self_test_ampl ampl,
+ enum self_test_sign sign,
+ enum axis axis)
+{
+ struct self_test_cfg self_test_cfg;
+
+ self_test_cfg.self_test_ampl = ampl;
+ self_test_cfg.self_test_sign = sign;
+ self_test_cfg.self_test_axis = axis;
+ self_test_cfg.self_test_enabled = true;
+
+ return bma2xx_set_self_test_cfg(bma2xx, &self_test_cfg);
+}
+
+static int
+self_test_disable(const struct bma2xx * bma2xx)
+{
+ struct self_test_cfg self_test_cfg;
+
+ self_test_cfg.self_test_ampl = SELF_TEST_AMPL_LOW;
+ self_test_cfg.self_test_sign = SELF_TEST_SIGN_NEGATIVE;
+ self_test_cfg.self_test_axis = -1;
+ self_test_cfg.self_test_enabled = false;
+
+ return bma2xx_set_self_test_cfg(bma2xx, &self_test_cfg);
+}
+
+static int
+self_test_nudge(const struct bma2xx * bma2xx,
+ enum self_test_ampl ampl,
+ enum self_test_sign sign,
+ enum axis axis,
+ enum bma2xx_g_range g_range,
+ struct accel_data * accel_data)
+{
+ int rc;
+
+ rc = self_test_enable(bma2xx, ampl, sign, axis);
+ if (rc != 0) {
+ return rc;
+ }
+
+ delay_msec(50);
+
+ rc = bma2xx_get_accel(bma2xx, g_range, axis, accel_data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = self_test_disable(bma2xx);
+ if (rc != 0) {
+ return rc;
+ }
+
+ delay_msec(50);
+
+ return 0;
+}
+
+static int
+self_test_axis(const struct bma2xx * bma2xx,
+ enum axis axis,
+ enum bma2xx_g_range g_range,
+ float * delta_hi_g,
+ float * delta_lo_g)
+{
+ struct accel_data accel_neg_hi;
+ struct accel_data accel_neg_lo;
+ struct accel_data accel_pos_hi;
+ struct accel_data accel_pos_lo;
+ int rc;
+
+ rc = self_test_nudge(bma2xx,
+ SELF_TEST_AMPL_HIGH,
+ SELF_TEST_SIGN_NEGATIVE,
+ axis,
+ g_range,
+ &accel_neg_hi);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = self_test_nudge(bma2xx,
+ SELF_TEST_AMPL_LOW,
+ SELF_TEST_SIGN_NEGATIVE,
+ axis,
+ g_range,
+ &accel_neg_lo);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = self_test_nudge(bma2xx,
+ SELF_TEST_AMPL_HIGH,
+ SELF_TEST_SIGN_POSITIVE,
+ axis,
+ g_range,
+ &accel_pos_hi);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = self_test_nudge(bma2xx,
+ SELF_TEST_AMPL_LOW,
+ SELF_TEST_SIGN_POSITIVE,
+ axis,
+ g_range,
+ &accel_pos_lo);
+ if (rc != 0) {
+ return rc;
+ }
+
+ *delta_hi_g = accel_pos_hi.accel_g - accel_neg_hi.accel_g;
+ *delta_lo_g = accel_pos_lo.accel_g - accel_neg_lo.accel_g;
+
+ return 0;
+}
+
+int
+bma2xx_self_test(struct bma2xx * bma2xx,
+ float delta_high_mult,
+ float delta_low_mult,
+ bool * self_test_fail)
+{
+ const struct bma2xx_cfg * cfg;
+ enum bma2xx_power_mode request_power;
+ int rc;
+ float delta_hi_x_g;
+ float delta_lo_x_g;
+ float delta_hi_y_g;
+ float delta_lo_y_g;
+ float delta_hi_z_g;
+ float delta_lo_z_g;
+ bool fail;
+
+ cfg = &bma2xx->cfg;
+
+ request_power = BMA2XX_POWER_MODE_NORMAL;
+
+ rc = interim_power(bma2xx, &request_power, 1);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_set_g_range(bma2xx, BMA2XX_G_RANGE_8);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = self_test_axis(bma2xx,
+ AXIS_X,
+ BMA2XX_G_RANGE_8,
+ &delta_hi_x_g,
+ &delta_lo_x_g);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = self_test_axis(bma2xx,
+ AXIS_Y,
+ BMA2XX_G_RANGE_8,
+ &delta_hi_y_g,
+ &delta_lo_y_g);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = self_test_axis(bma2xx,
+ AXIS_Z,
+ BMA2XX_G_RANGE_8,
+ &delta_hi_z_g,
+ &delta_lo_z_g);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = self_test_disable(bma2xx);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_set_g_range(bma2xx, cfg->g_range);
+ if (rc != 0) {
+ return rc;
+ }
+
+ delay_msec(50);
+
+ rc = default_power(bma2xx);
+ if (rc != 0) {
+ return rc;
+ }
+
+ fail = false;
+ if (delta_hi_x_g < delta_high_mult * 0.8) {
+ fail = true;
+ }
+ if (delta_lo_x_g < delta_low_mult * 0.8) {
+ fail = true;
+ }
+ if (delta_hi_y_g < delta_high_mult * 0.8) {
+ fail = true;
+ }
+ if (delta_lo_y_g < delta_low_mult * 0.8) {
+ fail = true;
+ }
+ if (delta_hi_z_g < delta_high_mult * 0.4) {
+ fail = true;
+ }
+ if (delta_lo_z_g < delta_low_mult * 0.4) {
+ fail = true;
+ }
+
+ *self_test_fail = fail;
+
+ return 0;
+}
+
+static int
+axis_offset_compensation(const struct bma2xx * bma2xx,
+ enum axis axis,
+ enum bma2xx_offset_comp_target target)
+{
+ int rc;
+ bool ready;
+ enum bma2xx_offset_comp_target target_z;
+ enum bma2xx_offset_comp_target target_y;
+ enum bma2xx_offset_comp_target target_x;
+ uint32_t count;
+
+ rc = bma2xx_get_fast_ofc_cfg(bma2xx,
+ &ready,
+ &target_z,
+ &target_y,
+ &target_x);
+ if (rc != 0) {
+ return rc;
+ }
+
+ if (!ready) {
+ BMA2XX_ERROR("offset compensation already in progress\n");
+ return SYS_ETIMEOUT;
+ }
+
+ rc = bma2xx_set_fast_ofc_cfg(bma2xx, axis, target, true);
+ if (rc != 0) {
+ return rc;
+ }
+
+ for (count = 1000; count != 0; count--) {
+ rc = bma2xx_get_fast_ofc_cfg(bma2xx,
+ &ready,
+ &target_z,
+ &target_y,
+ &target_x);
+ if (rc != 0) {
+ return rc;
+ }
+
+ if (ready) {
+ break;
+ }
+ }
+
+ if (count == 0) {
+ BMA2XX_ERROR("offset compensation did not complete\n");
+ return SYS_ETIMEOUT;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_offset_compensation(struct bma2xx * bma2xx,
+ enum bma2xx_offset_comp_target target_x,
+ enum bma2xx_offset_comp_target target_y,
+ enum bma2xx_offset_comp_target target_z)
+{
+ const struct bma2xx_cfg * cfg;
+ enum bma2xx_power_mode request_power;
+ int rc;
+
+ cfg = &bma2xx->cfg;
+
+ request_power = BMA2XX_POWER_MODE_NORMAL;
+
+ rc = interim_power(bma2xx, &request_power, 1);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_set_g_range(bma2xx, BMA2XX_G_RANGE_2);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = axis_offset_compensation(bma2xx, AXIS_X, target_x);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = axis_offset_compensation(bma2xx, AXIS_Y, target_y);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = axis_offset_compensation(bma2xx, AXIS_Z, target_z);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_get_ofc_offset(bma2xx, AXIS_X, &bma2xx->cfg.offset_x_g);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = bma2xx_get_ofc_offset(bma2xx, AXIS_Y, &bma2xx->cfg.offset_y_g);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = bma2xx_get_ofc_offset(bma2xx, AXIS_Z, &bma2xx->cfg.offset_z_g);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_set_g_range(bma2xx, cfg->g_range);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = default_power(bma2xx);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_query_offsets(struct bma2xx * bma2xx,
+ float * offset_x_g,
+ float * offset_y_g,
+ float * offset_z_g)
+{
+ const struct bma2xx_cfg * cfg;
+ enum bma2xx_power_mode request_power[5];
+ int rc;
+ float val_offset_x_g;
+ float val_offset_y_g;
+ float val_offset_z_g;
+ bool mismatch;
+
+ cfg = &bma2xx->cfg;
+
+ request_power[0] = BMA2XX_POWER_MODE_SUSPEND;
+ request_power[1] = BMA2XX_POWER_MODE_STANDBY;
+ request_power[2] = BMA2XX_POWER_MODE_LPM_1;
+ request_power[3] = BMA2XX_POWER_MODE_LPM_2;
+ request_power[4] = BMA2XX_POWER_MODE_NORMAL;
+
+ rc = interim_power(bma2xx,
+ request_power,
+ sizeof(request_power) / sizeof(*request_power));
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_get_ofc_offset(bma2xx, AXIS_X, &val_offset_x_g);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = bma2xx_get_ofc_offset(bma2xx, AXIS_Y, &val_offset_y_g);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = bma2xx_get_ofc_offset(bma2xx, AXIS_Z, &val_offset_z_g);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = default_power(bma2xx);
+ if (rc != 0) {
+ return rc;
+ }
+
+ mismatch = false;
+ if (cfg->offset_x_g != val_offset_x_g) {
+ BMA2XX_ERROR("X compensation offset value mismatch\n");
+ mismatch = true;
+ }
+ if (cfg->offset_y_g != val_offset_y_g) {
+ BMA2XX_ERROR("Y compensation offset value mismatch\n");
+ mismatch = true;
+ }
+ if (cfg->offset_z_g != val_offset_z_g) {
+ BMA2XX_ERROR("Z compensation offset value mismatch\n");
+ mismatch = true;
+ }
+
+ if (mismatch) {
+ return SYS_EINVAL;
+ }
+
+ *offset_x_g = val_offset_x_g;
+ *offset_y_g = val_offset_y_g;
+ *offset_z_g = val_offset_z_g;
+
+ return 0;
+}
+
+int
+bma2xx_write_offsets(struct bma2xx * bma2xx,
+ float offset_x_g,
+ float offset_y_g,
+ float offset_z_g)
+{
+ struct bma2xx_cfg * cfg;
+ enum bma2xx_power_mode request_power[5];
+ int rc;
+
+ cfg = &bma2xx->cfg;
+
+ request_power[0] = BMA2XX_POWER_MODE_SUSPEND;
+ request_power[1] = BMA2XX_POWER_MODE_STANDBY;
+ request_power[2] = BMA2XX_POWER_MODE_LPM_1;
+ request_power[3] = BMA2XX_POWER_MODE_LPM_2;
+ request_power[4] = BMA2XX_POWER_MODE_NORMAL;
+
+ rc = interim_power(bma2xx,
+ request_power,
+ sizeof(request_power) / sizeof(*request_power));
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_set_ofc_offset(bma2xx, AXIS_X, offset_x_g);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = bma2xx_set_ofc_offset(bma2xx, AXIS_Y, offset_y_g);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = bma2xx_set_ofc_offset(bma2xx, AXIS_Z, offset_z_g);
+ if (rc != 0) {
+ return rc;
+ }
+
+ cfg->offset_x_g = offset_x_g;
+ cfg->offset_y_g = offset_y_g;
+ cfg->offset_z_g = offset_z_g;
+
+ return 0;
+}
+
+int
+bma2xx_stream_read(struct bma2xx * bma2xx,
+ bma2xx_stream_read_func_t read_func,
+ void * read_arg,
+ uint32_t time_ms)
+{
+ const struct bma2xx_cfg * cfg;
+ int rc;
+ enum bma2xx_power_mode request_power;
+ struct int_enable int_enable_org;
+ struct int_enable int_enable = { 0 };
+ os_time_t time_ticks;
+ os_time_t stop_ticks;
+ struct accel_data accel_data[AXIS_ALL];
+ struct sensor_accel_data sad;
+ struct bma2xx_private_driver_data *pdd;
+
+ cfg = &bma2xx->cfg;
+ pdd = &bma2xx->pdd;
+
+ stop_ticks = 0;
+
+ request_power = BMA2XX_POWER_MODE_NORMAL;
+
+ rc = interim_power(bma2xx, &request_power, 1);
+ if (rc != 0) {
+ return rc;
+ }
+
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+ undo_interrupt(&bma2xx->intr);
+
+ if (pdd->interrupt) {
+ return SYS_EBUSY;
+ }
+ pdd->interrupt = &bma2xx->intr;
+ enable_intpin(bma2xx);
+#endif
+
+ rc = bma2xx_get_int_enable(bma2xx, &int_enable_org);
+ if (rc != 0) {
+ goto done;
+ }
+
+ /* Leave tap configured as it is since it is on int2*/
+ int_enable.s_tap_int_enable = int_enable_org.s_tap_int_enable;
+ int_enable.d_tap_int_enable = int_enable_org.d_tap_int_enable;
+ int_enable.data_int_enable = true;
+
+ rc = bma2xx_set_int_enable(bma2xx, &int_enable);
+ if (rc != 0) {
+ goto done;
+ }
+
+ if (time_ms != 0) {
+ rc = os_time_ms_to_ticks(time_ms, &time_ticks);
+ if (rc != 0) {
+ goto done;
+ }
+ stop_ticks = os_time_get() + time_ticks;
+ }
+
+ for (;;) {
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+ wait_interrupt(&bma2xx->intr, pdd->int_num);
+#else
+ switch (cfg->filter_bandwidth) {
+ case BMA2XX_FILTER_BANDWIDTH_7_81_HZ:
+ delay_msec(128);
+ break;
+ case BMA2XX_FILTER_BANDWIDTH_15_63_HZ:
+ delay_msec(64);
+ break;
+ case BMA2XX_FILTER_BANDWIDTH_31_25_HZ:
+ delay_msec(32);
+ break;
+ case BMA2XX_FILTER_BANDWIDTH_62_5_HZ:
+ delay_msec(16);
+ break;
+ case BMA2XX_FILTER_BANDWIDTH_125_HZ:
+ delay_msec(8);
+ break;
+ case BMA2XX_FILTER_BANDWIDTH_250_HZ:
+ delay_msec(4);
+ break;
+ case BMA2XX_FILTER_BANDWIDTH_500_HZ:
+ delay_msec(2);
+ break;
+ case BMA2XX_FILTER_BANDWIDTH_1000_HZ:
+ case BMA2XX_FILTER_BANDWIDTH_ODR_MAX:
+ delay_msec(1);
+ break;
+ default:
+ delay_msec(1000);
+ break;
+ }
+#endif
+
+ rc = bma2xx_get_fifo(bma2xx,
+ cfg->g_range,
+ FIFO_DATA_X_AND_Y_AND_Z,
+ accel_data);
+ if (rc != 0) {
+ goto done;
+ }
+
+ sad.sad_x = accel_data[AXIS_X].accel_g;
+ sad.sad_y = accel_data[AXIS_Y].accel_g;
+ sad.sad_z = accel_data[AXIS_Z].accel_g;
+ sad.sad_x_is_valid = 1;
+ sad.sad_y_is_valid = 1;
+ sad.sad_z_is_valid = 1;
+
+ if (read_func(read_arg, &sad)) {
+ break;
+ }
+
+ if (time_ms != 0 && OS_TIME_TICK_GT(os_time_get(), stop_ticks)) {
+ break;
+ }
+ }
+
+ rc = bma2xx_set_int_enable(bma2xx, &int_enable_org);
+ if (rc != 0) {
+ goto done;
+ }
+
+ rc = default_power(bma2xx);
+ if (rc != 0) {
+ goto done;
+ }
+
+done:
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+ pdd->interrupt = NULL;
+ disable_intpin(bma2xx);
+#endif
+
+ return rc;
+}
+
+int
+bma2xx_current_temp(struct bma2xx * bma2xx,
+ float * temp_c)
+{
+ enum bma2xx_power_mode request_power[3];
+ int rc;
+
+ request_power[0] = BMA2XX_POWER_MODE_LPM_1;
+ request_power[1] = BMA2XX_POWER_MODE_LPM_2;
+ request_power[2] = BMA2XX_POWER_MODE_NORMAL;
+
+ rc = interim_power(bma2xx,
+ request_power,
+ sizeof(request_power) / sizeof(*request_power));
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_get_temp(bma2xx, temp_c);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = default_power(bma2xx);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_current_orient(struct bma2xx * bma2xx,
+ struct bma2xx_orient_xyz * orient_xyz)
+{
+ enum bma2xx_power_mode request_power[3];
+ int rc;
+ struct int_enable int_enable_org;
+ struct int_enable int_enable = { 0 };
+ struct int_status int_status;
+
+ request_power[0] = BMA2XX_POWER_MODE_LPM_1;
+ request_power[1] = BMA2XX_POWER_MODE_LPM_2;
+ request_power[2] = BMA2XX_POWER_MODE_NORMAL;
+
+ rc = interim_power(bma2xx,
+ request_power,
+ sizeof(request_power) / sizeof(*request_power));
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_get_int_enable(bma2xx, &int_enable_org);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* Leave tap configured as it is since it is on int2*/
+ int_enable.s_tap_int_enable = int_enable_org.s_tap_int_enable;
+ int_enable.d_tap_int_enable = int_enable_org.d_tap_int_enable;
+
+ int_enable.orient_int_enable = true;
+
+ rc = bma2xx_set_int_enable(bma2xx, &int_enable);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_get_int_status(bma2xx, &int_status);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* Back to original interrupts */
+ rc = bma2xx_set_int_enable(bma2xx, &int_enable_org);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = default_power(bma2xx);
+ if (rc != 0) {
+ return rc;
+ }
+
+ orient_xyz->orient_xy = int_status.device_orientation;
+ orient_xyz->downward_z = int_status.device_is_down;
+
+ return 0;
+}
+
+int
+bma2xx_wait_for_orient(struct bma2xx * bma2xx,
+ struct bma2xx_orient_xyz * orient_xyz)
+{
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+ int rc;
+ enum bma2xx_power_mode request_power[3];
+ struct int_enable int_enable_org;
+ struct int_enable int_enable = {0};
+ struct int_status int_status;
+ struct bma2xx_private_driver_data *pdd;
+
+ pdd = &bma2xx->pdd;
+
+ if (pdd->interrupt) {
+ BMA2XX_ERROR("Interrupt used\n");
+ return SYS_EINVAL;
+ }
+
+ pdd->interrupt = &bma2xx->intr;
+ enable_intpin(bma2xx);
+
+ request_power[0] = BMA2XX_POWER_MODE_LPM_1;
+ request_power[1] = BMA2XX_POWER_MODE_LPM_2;
+ request_power[2] = BMA2XX_POWER_MODE_NORMAL;
+
+ rc = interim_power(bma2xx,
+ request_power,
+ sizeof(request_power) / sizeof(*request_power));
+ if (rc != 0) {
+ goto done;
+ }
+
+ undo_interrupt(&bma2xx->intr);
+
+ rc = bma2xx_get_int_enable(bma2xx, &int_enable_org);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* Leave tap configured as it is since it is on int2*/
+ int_enable.s_tap_int_enable = int_enable_org.s_tap_int_enable;
+ int_enable.d_tap_int_enable = int_enable_org.d_tap_int_enable;
+ int_enable.orient_int_enable = true;
+ rc = bma2xx_set_int_enable(bma2xx, &int_enable);
+ if (rc != 0) {
+ goto done;
+ }
+
+ wait_interrupt(&bma2xx->intr, pdd->int_num);
+
+ rc = bma2xx_get_int_status(bma2xx, &int_status);
+ if (rc != 0) {
+ goto done;
+ }
+
+ /* Back to original interrupts */
+ rc = bma2xx_set_int_enable(bma2xx, &int_enable_org);
+ if (rc != 0) {
+ goto done;
+ }
+
+ rc = default_power(bma2xx);
+ if (rc != 0) {
+ goto done;
+ }
+
+ orient_xyz->orient_xy = int_status.device_orientation;
+ orient_xyz->downward_z = int_status.device_is_down;
+
+done:
+ pdd->interrupt = NULL;
+ disable_intpin(bma2xx);
+ return rc;
+#else
+ return SYS_ENODEV;
+#endif
+}
+
+int
+bma2xx_wait_for_high_g(struct bma2xx * bma2xx)
+{
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+ int rc;
+ enum bma2xx_power_mode request_power[3];
+ struct int_enable int_enable_org;
+ struct int_enable int_enable = { 0 };
+ struct bma2xx_private_driver_data *pdd;
+
+ pdd = &bma2xx->pdd;
+
+ if (pdd->interrupt) {
+ BMA2XX_ERROR("Interrupt used\n");
+ return SYS_EINVAL;
+ }
+
+ pdd->interrupt = &bma2xx->intr;
+ enable_intpin(bma2xx);
+
+ request_power[0] = BMA2XX_POWER_MODE_LPM_1;
+ request_power[1] = BMA2XX_POWER_MODE_LPM_2;
+ request_power[2] = BMA2XX_POWER_MODE_NORMAL;
+
+ rc = interim_power(bma2xx,
+ request_power,
+ sizeof(request_power) / sizeof(*request_power));
+ if (rc != 0) {
+ goto done;
+ }
+
+ undo_interrupt(&bma2xx->intr);
+
+ rc = bma2xx_get_int_enable(bma2xx, &int_enable_org);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* Leave tap configured as it is since it is on int2*/
+ int_enable.s_tap_int_enable = int_enable_org.s_tap_int_enable;
+ int_enable.d_tap_int_enable = int_enable_org.d_tap_int_enable;
+
+ int_enable.high_g_z_int_enable = true;
+ int_enable.high_g_y_int_enable = true;
+ int_enable.high_g_x_int_enable = true;
+
+ rc = bma2xx_set_int_enable(bma2xx, &int_enable);
+ if (rc != 0) {
+ goto done;
+ }
+
+ wait_interrupt(&bma2xx->intr, pdd->int_num);
+
+ rc = bma2xx_set_int_enable(bma2xx, &int_enable_org);
+ if (rc != 0) {
+ goto done;
+ }
+
+ rc = default_power(bma2xx);
+ if (rc != 0) {
+ goto done;
+ }
+
+done:
+ pdd->interrupt = NULL;
+ disable_intpin(bma2xx);
+ return rc;
+#else
+ return SYS_ENODEV;
+#endif
+}
+
+int
+bma2xx_wait_for_low_g(struct bma2xx * bma2xx)
+{
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+ int rc;
+ enum bma2xx_power_mode request_power[3];
+ struct int_enable int_enable_org;
+ struct int_enable int_enable = { 0 };
+ struct bma2xx_private_driver_data *pdd;
+
+ pdd = &bma2xx->pdd;
+
+ if (pdd->interrupt) {
+ BMA2XX_ERROR("Interrupt used\n");
+ return SYS_EINVAL;
+ }
+
+ pdd->interrupt = &bma2xx->intr;
+ enable_intpin(bma2xx);
+
+ request_power[0] = BMA2XX_POWER_MODE_LPM_1;
+ request_power[1] = BMA2XX_POWER_MODE_LPM_2;
+ request_power[2] = BMA2XX_POWER_MODE_NORMAL;
+
+ rc = interim_power(bma2xx,
+ request_power,
+ sizeof(request_power) / sizeof(*request_power));
+ if (rc != 0) {
+ goto done;
+ }
+
+ undo_interrupt(&bma2xx->intr);
+
+ rc = bma2xx_get_int_enable(bma2xx, &int_enable_org);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* Leave tap configured as it is since it is on int2 */
+ int_enable.s_tap_int_enable = int_enable_org.s_tap_int_enable;
+ int_enable.d_tap_int_enable = int_enable_org.d_tap_int_enable;
+
+ int_enable.low_g_int_enable = true;
+
+ rc = bma2xx_set_int_enable(bma2xx, &int_enable);
+ if (rc != 0) {
+ goto done;
+ }
+
+ wait_interrupt(&bma2xx->intr, pdd->int_num);
+
+ rc = bma2xx_set_int_enable(bma2xx, &int_enable_org);
+ if (rc != 0) {
+ goto done;
+ }
+
+ rc = default_power(bma2xx);
+ if (rc != 0) {
+ goto done;
+ }
+
+done:
+ pdd->interrupt = NULL;
+ disable_intpin(bma2xx);
+ return 0;
+#else
+ return SYS_ENODEV;
+#endif
+}
+
+int
+bma2xx_wait_for_tap(struct bma2xx * bma2xx,
+ enum bma2xx_tap_type tap_type)
+{
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+ int rc = 0;
+ enum bma2xx_power_mode request_power[3];
+ struct int_enable int_enable_org;
+ struct int_enable int_enable = { 0 };
+ struct int_routes int_routes;
+ struct int_routes int_routes_org;
+ struct bma2xx_private_driver_data *pdd;
+
+ pdd = &bma2xx->pdd;
+
+ switch (tap_type) {
+ case BMA2XX_TAP_TYPE_DOUBLE:
+ case BMA2XX_TAP_TYPE_SINGLE:
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ rc = bma2xx_get_int_routes(bma2xx, &int_routes_org);
+ if (rc != 0) {
+ return rc;
+ }
+
+ int_routes = int_routes_org;
+ if (tap_type == BMA2XX_TAP_TYPE_DOUBLE) {
+ /* According to BMA2XX when single tap shall not be used we should not
+ * route it to any INTX
+ */
+ int_routes.d_tap_int_route = pdd->int_route;
+ int_routes.s_tap_int_route = INT_ROUTE_NONE;
+ } else {
+ int_routes.d_tap_int_route = INT_ROUTE_NONE;
+ int_routes.s_tap_int_route = pdd->int_route;
+ }
+
+ rc = bma2xx_set_int_routes(bma2xx, &int_routes);
+ if (rc != 0) {
+ return rc;
+ }
+
+ if (pdd->interrupt) {
+ BMA2XX_ERROR("Interrupt used\n");
+ return SYS_EINVAL;
+ }
+
+ pdd->interrupt = &bma2xx->intr;
+ enable_intpin(bma2xx);
+
+ request_power[0] = BMA2XX_POWER_MODE_LPM_1;
+ request_power[1] = BMA2XX_POWER_MODE_LPM_2;
+ request_power[2] = BMA2XX_POWER_MODE_NORMAL;
+
+ rc = interim_power(bma2xx,
+ request_power,
+ sizeof(request_power) / sizeof(*request_power));
+ if (rc != 0) {
+ goto done;
+ }
+
+ undo_interrupt(&bma2xx->intr);
+
+ rc = bma2xx_get_int_enable(bma2xx, &int_enable_org);
+ if (rc != 0) {
+ return rc;
+ }
+
+ int_enable.s_tap_int_enable = tap_type == BMA2XX_TAP_TYPE_SINGLE;
+ int_enable.d_tap_int_enable = tap_type == BMA2XX_TAP_TYPE_DOUBLE;
+
+ rc = bma2xx_set_int_enable(bma2xx, &int_enable);
+ if (rc != 0) {
+ goto done;
+ }
+
+ wait_interrupt(&bma2xx->intr, pdd->int_num);
+
+ rc = bma2xx_set_int_enable(bma2xx, &int_enable_org);
+ if (rc != 0) {
+ goto done;
+ }
+
+ rc = default_power(bma2xx);
+
+done:
+ pdd->interrupt = NULL;
+ disable_intpin(bma2xx);
+ /* Restore previous routing */
+ rc = bma2xx_set_int_routes(bma2xx, &int_routes_org);
+
+ return rc;
+#else
+ return SYS_ENODEV;
+#endif
+}
+
+int
+bma2xx_power_settings(struct bma2xx * bma2xx,
+ enum bma2xx_power_mode power_mode,
+ enum bma2xx_sleep_duration sleep_duration)
+{
+ struct bma2xx_cfg * cfg;
+
+ cfg = &bma2xx->cfg;
+
+ cfg->power_mode = power_mode;
+ cfg->sleep_duration = sleep_duration;
+
+ return default_power(bma2xx);
+}
+
+static int
+sensor_driver_read(struct sensor * sensor,
+ sensor_type_t sensor_type,
+ sensor_data_func_t data_func,
+ void * data_arg,
+ uint32_t timeout)
+{
+ struct bma2xx * bma2xx;
+ const struct bma2xx_cfg * cfg;
+ enum bma2xx_power_mode request_power[3];
+ int rc;
+ struct accel_data accel_data[AXIS_ALL];
+ struct sensor_accel_data sad;
+ float temp_c;
+ struct sensor_temp_data std;
+
+ if ((sensor_type & ~(SENSOR_TYPE_ACCELEROMETER |
+ SENSOR_TYPE_AMBIENT_TEMPERATURE)) != 0) {
+ return SYS_EINVAL;
+ }
+
+ bma2xx = (struct bma2xx *)SENSOR_GET_DEVICE(sensor);
+ cfg = &bma2xx->cfg;
+
+ request_power[0] = BMA2XX_POWER_MODE_LPM_1;
+ request_power[1] = BMA2XX_POWER_MODE_LPM_2;
+ request_power[2] = BMA2XX_POWER_MODE_NORMAL;
+
+ rc = interim_power(bma2xx,
+ request_power,
+ sizeof(request_power) / sizeof(*request_power));
+ if (rc != 0) {
+ return rc;
+ }
+
+ if ((sensor_type & SENSOR_TYPE_ACCELEROMETER) != 0) {
+ rc = bma2xx_get_accel(bma2xx,
+ cfg->g_range,
+ AXIS_X,
+ accel_data + AXIS_X);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = bma2xx_get_accel(bma2xx,
+ cfg->g_range,
+ AXIS_Y,
+ accel_data + AXIS_Y);
+ if (rc != 0) {
+ return rc;
+ }
+ rc = bma2xx_get_accel(bma2xx,
+ cfg->g_range,
+ AXIS_Z,
+ accel_data + AXIS_Z);
+ if (rc != 0) {
+ return rc;
+ }
+
+ sad.sad_x = accel_data[AXIS_X].accel_g;
+ sad.sad_y = accel_data[AXIS_Y].accel_g;
+ sad.sad_z = accel_data[AXIS_Z].accel_g;
+ sad.sad_x_is_valid = 1;
+ sad.sad_y_is_valid = 1;
+ sad.sad_z_is_valid = 1;
+
+ rc = data_func(sensor,
+ data_arg,
+ &sad,
+ SENSOR_TYPE_ACCELEROMETER);
+ if (rc != 0) {
+ return rc;
+ }
+ }
+
+ if ((sensor_type & SENSOR_TYPE_AMBIENT_TEMPERATURE) != 0) {
+ rc = bma2xx_get_temp(bma2xx, &temp_c);
+ if (rc != 0) {
+ return rc;
+ }
+
+ std.std_temp = temp_c;
+ std.std_temp_is_valid = 1;
+
+ rc = data_func(sensor,
+ data_arg,
+ &std,
+ SENSOR_TYPE_AMBIENT_TEMPERATURE);
+ if (rc != 0) {
+ return rc;
+ }
+ }
+
+ rc = default_power(bma2xx);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+static int
+sensor_driver_get_config(struct sensor * sensor,
+ sensor_type_t sensor_type,
+ struct sensor_cfg * cfg)
+{
+ if ((sensor_type & ~(SENSOR_TYPE_ACCELEROMETER |
+ SENSOR_TYPE_AMBIENT_TEMPERATURE)) != 0) {
+ return SYS_EINVAL;
+ }
+ if ((sensor_type & (sensor_type - 1)) != 0) {
+ return SYS_EINVAL;
+ }
+
+ if ((sensor_type & SENSOR_TYPE_ACCELEROMETER) != 0) {
+ cfg->sc_valtype = SENSOR_VALUE_TYPE_FLOAT_TRIPLET;
+ }
+ if ((sensor_type & SENSOR_TYPE_AMBIENT_TEMPERATURE) != 0) {
+ cfg->sc_valtype = SENSOR_VALUE_TYPE_FLOAT;
+ }
+
+ return 0;
+}
+
+static int
+sensor_driver_set_trigger_thresh(struct sensor * sensor,
+ sensor_type_t sensor_type,
+ struct sensor_type_traits * stt)
+{
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+ struct bma2xx * bma2xx;
+ const struct bma2xx_cfg * cfg;
+ int rc;
+ enum bma2xx_power_mode request_power[3];
+ const struct sensor_accel_data * low_thresh;
+ const struct sensor_accel_data * high_thresh;
+ struct int_enable int_enable;
+ float thresh;
+ struct low_g_int_cfg low_g_int_cfg;
+ struct high_g_int_cfg high_g_int_cfg;
+ struct bma2xx_private_driver_data *pdd;
+
+ if (sensor_type != SENSOR_TYPE_ACCELEROMETER) {
+ return SYS_EINVAL;
+ }
+
+ bma2xx = (struct bma2xx *)SENSOR_GET_DEVICE(sensor);
+ cfg = &bma2xx->cfg;
+ pdd = &bma2xx->pdd;
+
+ pdd->read_ctx.srec_type |= sensor_type;
+ pdd->registered_mask |= BMA2XX_READ_MASK;
+ enable_intpin(bma2xx);
+
+ request_power[0] = BMA2XX_POWER_MODE_LPM_1;
+ request_power[1] = BMA2XX_POWER_MODE_LPM_2;
+ request_power[2] = BMA2XX_POWER_MODE_NORMAL;
+
+ rc = interim_power(bma2xx,
+ request_power,
+ sizeof(request_power) / sizeof(*request_power));
+ if (rc != 0) {
+ goto done;
+ }
+
+ low_thresh = stt->stt_low_thresh.sad;
+ high_thresh = stt->stt_high_thresh.sad;
+
+ rc = bma2xx_get_int_enable(bma2xx, &int_enable);
+ if (rc != 0) {
+ goto done;
+ }
+
+ if (low_thresh->sad_x_is_valid |
+ low_thresh->sad_y_is_valid |
+ low_thresh->sad_z_is_valid) {
+ thresh = INFINITY;
+
+ if (low_thresh->sad_x_is_valid) {
+ if (thresh > low_thresh->sad_x) {
+ thresh = low_thresh->sad_x;
+ }
+ }
+ if (low_thresh->sad_y_is_valid) {
+ if (thresh > low_thresh->sad_y) {
+ thresh = low_thresh->sad_y;
+ }
+ }
+ if (low_thresh->sad_z_is_valid) {
+ if (thresh > low_thresh->sad_z) {
+ thresh = low_thresh->sad_z;
+ }
+ }
+
+ low_g_int_cfg.delay_ms = 20;
+ low_g_int_cfg.thresh_g = thresh;
+ low_g_int_cfg.hyster_g = 0.125;
+ low_g_int_cfg.axis_summing = false;
+
+ rc = bma2xx_set_low_g_int_cfg(bma2xx,
+ &low_g_int_cfg);
+ if (rc != 0) {
+ goto done;
+ }
+
+ int_enable.low_g_int_enable = true;
+ }
+
+ if (high_thresh->sad_x_is_valid |
+ high_thresh->sad_y_is_valid |
+ high_thresh->sad_z_is_valid) {
+ thresh = 0.0;
+
+ if (high_thresh->sad_x_is_valid) {
+ if (thresh < high_thresh->sad_x) {
+ thresh = high_thresh->sad_x;
+ }
+ }
+ if (high_thresh->sad_y_is_valid) {
+ if (thresh < high_thresh->sad_y) {
+ thresh = high_thresh->sad_y;
+ }
+ }
+ if (high_thresh->sad_z_is_valid) {
+ if (thresh < high_thresh->sad_z) {
+ thresh = high_thresh->sad_z;
+ }
+ }
+
+ high_g_int_cfg.hyster_g = 0.25;
+ high_g_int_cfg.delay_ms = 32;
+ high_g_int_cfg.thresh_g = thresh;
+
+ rc = bma2xx_set_high_g_int_cfg(bma2xx,
+ cfg->g_range,
+ &high_g_int_cfg);
+ if (rc != 0) {
+ goto done;
+ }
+
+ int_enable.high_g_z_int_enable = high_thresh->sad_z_is_valid;
+ int_enable.high_g_y_int_enable = high_thresh->sad_y_is_valid;
+ int_enable.high_g_x_int_enable = high_thresh->sad_x_is_valid;
+ }
+
+ rc = bma2xx_set_int_enable(bma2xx, &int_enable);
+
+done:
+ if (rc != 0) {
+ /* Something went wrong, unregister from interrupt */
+ pdd->read_ctx.srec_type &= ~sensor_type;
+ pdd->registered_mask &= ~BMA2XX_READ_MASK;
+ disable_intpin(bma2xx);
+ }
+
+ return rc;
+#else
+ return SYS_ENODEV;
+#endif
+}
+
+static int
+sensor_driver_unset_notification(struct sensor * sensor,
+ sensor_event_type_t sensor_event_type)
+{
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+ struct bma2xx * bma2xx;
+ enum bma2xx_power_mode request_power[3];
+ struct int_enable int_enable;
+ struct int_routes int_routes;
+ struct bma2xx_private_driver_data *pdd;
+ int rc;
+
+ if ((sensor_event_type & ~(SENSOR_EVENT_TYPE_DOUBLE_TAP |
+ SENSOR_EVENT_TYPE_SINGLE_TAP)) != 0) {
+ return SYS_EINVAL;
+ }
+
+ /*XXX for now we do not support registering for both events */
+ if (sensor_event_type == (SENSOR_EVENT_TYPE_DOUBLE_TAP |
+ SENSOR_EVENT_TYPE_SINGLE_TAP)) {
+ return SYS_EINVAL;
+ }
+
+ bma2xx = (struct bma2xx *)SENSOR_GET_DEVICE(sensor);
+ pdd = &bma2xx->pdd;
+
+ pdd->notify_ctx.snec_evtype &= ~sensor_event_type;
+ pdd->registered_mask &= ~BMA2XX_NOTIFY_MASK;
+ disable_intpin(bma2xx);
+
+ rc = interim_power(bma2xx,
+ request_power,
+ sizeof(request_power) / sizeof(*request_power));
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* Clear route and interrupts. We can do it for single and double as driver
+ * supports notification only for one of them at the time
+ */
+ rc = bma2xx_get_int_routes(bma2xx, &int_routes);
+ if (rc != 0) {
+ return rc;
+ }
+
+ if (sensor_event_type & SENSOR_EVENT_TYPE_SINGLE_TAP) {
+ int_routes.s_tap_int_route = INT_ROUTE_NONE;
+ }
+
+ if (sensor_event_type & SENSOR_EVENT_TYPE_DOUBLE_TAP) {
+ int_routes.d_tap_int_route = INT_ROUTE_NONE;
+ }
+
+ rc = bma2xx_set_int_routes(bma2xx, &int_routes);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = bma2xx_get_int_enable(bma2xx, &int_enable);
+ if (rc != 0) {
+ return rc;
+ }
+
+ int_enable.d_tap_int_enable = false;
+ int_enable.s_tap_int_enable = false;
+
+ rc = bma2xx_set_int_enable(bma2xx, &int_enable);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+#else
+ return SYS_ENODEV;
+#endif
+}
+
+static int
+sensor_driver_set_notification(struct sensor * sensor,
+ sensor_event_type_t sensor_event_type)
+{
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+ struct bma2xx * bma2xx;
+ int rc;
+ enum bma2xx_power_mode request_power[3];
+ struct int_enable int_enable;
+ struct int_routes int_routes;
+ struct bma2xx_private_driver_data *pdd;
+
+ if ((sensor_event_type & ~(SENSOR_EVENT_TYPE_DOUBLE_TAP |
+ SENSOR_EVENT_TYPE_SINGLE_TAP)) != 0) {
+ return SYS_EINVAL;
+ }
+
+ /*XXX for now we do not support registering for both events */
+ if (sensor_event_type == (SENSOR_EVENT_TYPE_DOUBLE_TAP |
+ SENSOR_EVENT_TYPE_SINGLE_TAP)) {
+ return SYS_EINVAL;
+ }
+
+ bma2xx = (struct bma2xx *)SENSOR_GET_DEVICE(sensor);
+ pdd = &bma2xx->pdd;
+
+ if (pdd->registered_mask & BMA2XX_NOTIFY_MASK) {
+ return SYS_EBUSY;
+ }
+
+ pdd->notify_ctx.snec_evtype |= sensor_event_type;
+ pdd->registered_mask |= BMA2XX_NOTIFY_MASK;
+ enable_intpin(bma2xx);
+
+ request_power[0] = BMA2XX_POWER_MODE_LPM_1;
+ request_power[1] = BMA2XX_POWER_MODE_LPM_2;
+ request_power[2] = BMA2XX_POWER_MODE_NORMAL;
+
+ rc = interim_power(bma2xx,
+ request_power,
+ sizeof(request_power) / sizeof(*request_power));
+ if (rc != 0) {
+ goto done;
+ }
+
+ /* Configure route */
+ rc = bma2xx_get_int_routes(bma2xx, &int_routes);
+ if (rc != 0) {
+ return rc;
+ }
+
+ if (sensor_event_type & SENSOR_EVENT_TYPE_DOUBLE_TAP) {
+ int_routes.d_tap_int_route = pdd->int_route;
+ }
+
+ if (sensor_event_type & SENSOR_EVENT_TYPE_SINGLE_TAP) {
+ int_routes.s_tap_int_route = pdd->int_route;
+ }
+
+ rc = bma2xx_set_int_routes(bma2xx, &int_routes);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* Configure enable event*/
+ rc = bma2xx_get_int_enable(bma2xx, &int_enable);
+ if (rc != 0) {
+ goto done;
+ }
+
+ /* Enable tap event*/
+ int_enable.s_tap_int_enable = sensor_event_type &
+ SENSOR_EVENT_TYPE_SINGLE_TAP;
+ int_enable.d_tap_int_enable = sensor_event_type &
+ SENSOR_EVENT_TYPE_DOUBLE_TAP;
+ rc = bma2xx_set_int_enable(bma2xx, &int_enable);
+
+done:
+ if (rc != 0) {
+ pdd->notify_ctx.snec_evtype &= ~sensor_event_type;
+ pdd->registered_mask &= ~BMA2XX_NOTIFY_MASK;
+ disable_intpin(bma2xx);
+ }
+
+ return rc;
+#else
+ return SYS_ENODEV;
+#endif
+}
+
+static int
+sensor_driver_handle_interrupt(struct sensor * sensor)
+{
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+ struct bma2xx * bma2xx;
+ struct bma2xx_private_driver_data *pdd;
+ struct int_status int_status;
+ int rc;
+
+ bma2xx = (struct bma2xx *)SENSOR_GET_DEVICE(sensor);
+ pdd = &bma2xx->pdd;
+
+ rc = bma2xx_get_int_status(bma2xx, &int_status);
+ if (rc != 0) {
+ BMA2XX_ERROR("Cound not read int status err=0x%02x\n", rc);
+ return rc;
+ }
+
+ if ((pdd->registered_mask & BMA2XX_NOTIFY_MASK) &&
+ (int_status.s_tap_int_active || int_status.d_tap_int_active)) {
+ sensor_mgr_put_notify_evt(&pdd->notify_ctx);
+ }
+
+ if ((pdd->registered_mask & BMA2XX_READ_MASK) &&
+ (int_status.high_g_int_active || int_status.low_g_int_active)) {
+ sensor_mgr_put_read_evt(&pdd->read_ctx);
+ }
+
+ return 0;
+#else
+ return SYS_ENODEV;
+#endif
+}
+
+static struct sensor_driver bma2xx_sensor_driver = {
+ .sd_read = sensor_driver_read,
+ .sd_get_config = sensor_driver_get_config,
+ .sd_set_trigger_thresh = sensor_driver_set_trigger_thresh,
+ .sd_set_notification = sensor_driver_set_notification,
+ .sd_unset_notification = sensor_driver_unset_notification,
+ .sd_handle_interrupt = sensor_driver_handle_interrupt,
+};
+
+int
+bma2xx_config(struct bma2xx * bma2xx, struct bma2xx_cfg * cfg)
+{
+ struct sensor * sensor;
+ int rc;
+ uint8_t chip_id;
+ uint8_t model_chip_id;
+
+ bma2xx->cfg = *cfg;
+
+ sensor = &bma2xx->sensor;
+
+ rc = bma2xx_get_chip_id(bma2xx, &chip_id);
+ if (rc != 0) {
+ return rc;
+ }
+ switch (cfg->model) {
+ case BMA2XX_BMA280:
+ model_chip_id = BMA280_REG_VALUE_CHIP_ID;
+ break;
+ case BMA2XX_BMA253:
+ model_chip_id = BMA253_REG_VALUE_CHIP_ID;
+ break;
+ default:
+ return SYS_EINVAL;
+ }
+
+ if (chip_id != model_chip_id) {
+ BMA2XX_ERROR("received incorrect chip ID 0x%02X\n", chip_id);
+ return SYS_EINVAL;
+ }
+
+ rc = reset_and_recfg(bma2xx);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = default_power(bma2xx);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = sensor_set_type_mask(sensor, cfg->sensor_mask);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+bma2xx_init(struct os_dev * dev, void * arg)
+{
+ struct bma2xx * bma2xx;
+ struct sensor * sensor;
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+ struct bma2xx_private_driver_data *pdd;
+#endif
+ int rc;
+
+ if (!dev || !arg) {
+ return SYS_ENODEV;
+ }
+
+#if MYNEWT_VAL(BMA2XX_LOG)
+ rc = log_register(dev->od_name,
+ &bma2xx_log,
+ &log_console_handler,
+ NULL,
+ LOG_SYSLEVEL);
+ if (rc != 0) {
+ return rc;
+ }
+#endif
+
+ bma2xx = (struct bma2xx *)dev;
+ sensor = &bma2xx->sensor;
+
+ rc = sensor_init(sensor, dev);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = sensor_set_driver(sensor,
+ SENSOR_TYPE_ACCELEROMETER |
+ SENSOR_TYPE_AMBIENT_TEMPERATURE,
+ &bma2xx_sensor_driver);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = sensor_set_interface(sensor, arg);
+ if (rc != 0) {
+ return rc;
+ }
+
+ sensor->s_next_run = OS_TIMEOUT_NEVER;
+
+ rc = sensor_mgr_register(sensor);
+ if (rc != 0) {
+ return rc;
+ }
+
+#if MYNEWT_VAL(SPI_0_MASTER) || MYNEWT_VAL(SPI_1_MASTER)
+ rc = hal_spi_config(sensor->s_itf.si_num, &spi_bma2xx_settings);
+ if (rc == EINVAL) {
+ /* If spi is already enabled, for nrf52, it returns -1, We should not
+ * fail if the spi is already enabled
+ */
+ return rc;
+ }
+
+ rc = hal_spi_enable(sensor->s_itf.si_num);
+ if (rc) {
+ return rc;
+ }
+
+ rc = hal_gpio_init_out(sensor->s_itf.si_cs_pin, 1);
+ if (rc) {
+ return rc;
+ }
+#endif
+
+#if MYNEWT_VAL(BMA2XX_INT_ENABLE)
+ init_interrupt(&bma2xx->intr, bma2xx->sensor.s_itf.si_ints);
+
+ pdd = &bma2xx->pdd;
+
+ pdd->read_ctx.srec_sensor = sensor;
+ pdd->notify_ctx.snec_sensor = sensor;
+
+ rc = init_intpin(bma2xx, interrupt_handler, sensor);
+ if (rc != 0) {
+ return rc;
+ }
+#endif
+
+ bma2xx->power = BMA2XX_POWER_MODE_NORMAL;
+
+ return 0;
+}
diff --git a/hw/drivers/sensors/bma2xx/src/bma2xx_priv.h b/hw/drivers/sensors/bma2xx/src/bma2xx_priv.h
new file mode 100644
index 000000000..3910c965e
--- /dev/null
+++ b/hw/drivers/sensors/bma2xx/src/bma2xx_priv.h
@@ -0,0 +1,670 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef __BMA2XX_PRIV_H__
+#define __BMA2XX_PRIV_H__
+
+#include "bma2xx/bma2xx.h"
+
+#ifdef __cplusplus
+#extern "C" {
+#endif
+
+/*
+ * Full register map:
+ */
+
+#define BMA2XX_SPI_READ_CMD_BIT 0x80
+
+#define REG_ADDR_BGW_CHIPID 0x00 /* r */
+/* RESERVED */ /* */
+#define REG_ADDR_ACCD_X_LSB 0x02 /* r */
+#define REG_ADDR_ACCD_X_MSB 0x03 /* r */
+#define REG_ADDR_ACCD_Y_LSB 0x04 /* r */
+#define REG_ADDR_ACCD_Y_MSB 0x05 /* r */
+#define REG_ADDR_ACCD_Z_LSB 0x06 /* r */
+#define REG_ADDR_ACCD_Z_MSB 0x07 /* r */
+#define REG_ADDR_ACCD_TEMP 0x08 /* r */
+#define REG_ADDR_INT_STATUS_0 0x09 /* r */
+#define REG_ADDR_INT_STATUS_1 0x0A /* r */
+#define REG_ADDR_INT_STATUS_2 0x0B /* r */
+#define REG_ADDR_INT_STATUS_3 0x0C /* r */
+/* RESERVED */ /* */
+#define REG_ADDR_FIFO_STATUS 0x0E /* r */
+#define REG_ADDR_PMU_RANGE 0x0F /* rw */
+#define REG_ADDR_PMU_BW 0x10 /* rw */
+#define REG_ADDR_PMU_LPW 0x11 /* rw */
+#define REG_ADDR_PMU_LOW_POWER 0x12 /* rw */
+#define REG_ADDR_ACCD_HBW 0x13 /* rw */
+#define REG_ADDR_BGW_SOFTRESET 0x14 /* w */
+/* RESERVED */ /* */
+#define REG_ADDR_INT_EN_0 0x16 /* rw */
+#define REG_ADDR_INT_EN_1 0x17 /* rw */
+#define REG_ADDR_INT_EN_2 0x18 /* rw */
+#define REG_ADDR_INT_MAP_0 0x19 /* rw */
+#define REG_ADDR_INT_MAP_1 0x1A /* rw */
+#define REG_ADDR_INT_MAP_2 0x1B /* rw */
+/* RESERVED */ /* */
+/* RESERVED */ /* */
+#define REG_ADDR_INT_SRC 0x1E /* rw */
+/* RESERVED */ /* */
+#define REG_ADDR_INT_OUT_CTRL 0x20 /* rw */
+#define REG_ADDR_INT_RST_LATCH 0x21 /* rw */
+#define REG_ADDR_INT_0 0x22 /* rw */
+#define REG_ADDR_INT_1 0x23 /* rw */
+#define REG_ADDR_INT_2 0x24 /* rw */
+#define REG_ADDR_INT_3 0x25 /* rw */
+#define REG_ADDR_INT_4 0x26 /* rw */
+#define REG_ADDR_INT_5 0x27 /* rw */
+#define REG_ADDR_INT_6 0x28 /* rw */
+#define REG_ADDR_INT_7 0x29 /* rw */
+#define REG_ADDR_INT_8 0x2A /* rw */
+#define REG_ADDR_INT_9 0x2B /* rw */
+#define REG_ADDR_INT_A 0x2C /* rw */
+#define REG_ADDR_INT_B 0x2D /* rw */
+#define REG_ADDR_INT_C 0x2E /* rw */
+#define REG_ADDR_INT_D 0x2F /* rw */
+#define REG_ADDR_FIFO_CONFIG_0 0x30 /* rw */
+/* RESERVED */ /* */
+#define REG_ADDR_PMU_SELF_TEST 0x32 /* rw */
+#define REG_ADDR_TRIM_NVM_CTRL 0x33 /* rw */
+#define REG_ADDR_BGW_SPI3_WDT 0x34 /* rw */
+/* RESERVED */ /* */
+#define REG_ADDR_OFC_CTRL 0x36 /* rw */
+#define REG_ADDR_OFC_SETTING 0x37 /* rw */
+#define REG_ADDR_OFC_OFFSET_X 0x38 /* rw nvm */
+#define REG_ADDR_OFC_OFFSET_Y 0x39 /* rw nvm */
+#define REG_ADDR_OFC_OFFSET_Z 0x3A /* rw nvm */
+#define REG_ADDR_TRIM_GP0 0x3B /* rw nvm */
+#define REG_ADDR_TRIM_GP1 0x3C /* rw nvm */
+/* RESERVED */ /* */
+#define REG_ADDR_FIFO_CONFIG_1 0x3E /* rw */
+#define REG_ADDR_FIFO_DATA 0x3F /* r */
+
+/* BMA253, BMA280 unique settings */
+#define BMA253_REG_VALUE_CHIP_ID 0xFA
+#define BMA253_G_SCALE_2 (0.00098)
+#define BMA253_G_SCALE_4 (0.00195)
+#define BMA253_G_SCALE_8 (0.00391)
+#define BMA253_G_SCALE_16 (0.00781)
+#define BMA253_ACCEL_BIT_SHIFT 4
+
+#define BMA280_REG_VALUE_CHIP_ID 0xFB
+#define BMA280_G_SCALE_2 (0.000244)
+#define BMA280_G_SCALE_4 (0.000488)
+#define BMA280_G_SCALE_8 (0.000977)
+#define BMA280_G_SCALE_16 (0.001953)
+#define BMA280_ACCEL_BIT_SHIFT 2
+/* Magical value that is used to initiate a full reset */
+#define REG_VALUE_SOFT_RESET 0xB6
+
+/* Get the chip ID */
+int
+bma2xx_get_chip_id(const struct bma2xx * bma2xx,
+ uint8_t * chip_id);
+
+/* All three axis types */
+enum axis {
+ AXIS_X = 0,
+ AXIS_Y = 1,
+ AXIS_Z = 2,
+ AXIS_ALL = 3,
+};
+
+/* A single accelerometer measurement for one axis */
+struct accel_data {
+ float accel_g;
+ bool new_data;
+};
+
+/* Get an accelerometer measurement for a single axis */
+int
+bma2xx_get_accel(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ enum axis axis,
+ struct accel_data * accel_data);
+
+/* Get a temperature measurement */
+int
+bma2xx_get_temp(const struct bma2xx * bma2xx,
+ float * temp_c);
+
+/* Which direction in an axis was this interrupt triggered on */
+enum axis_trigger_sign {
+ AXIS_TRIGGER_SIGN_POS = 0,
+ AXIS_TRIGGER_SIGN_NEG = 1,
+};
+
+/* Which axis was this interrupt triggered on */
+struct axis_trigger {
+ enum axis_trigger_sign sign;
+ enum axis axis;
+ bool axis_known;
+};
+
+/* Active status of all interrupts */
+struct int_status {
+ bool flat_int_active;
+ bool orient_int_active;
+ bool s_tap_int_active;
+ bool d_tap_int_active;
+ bool slow_no_mot_int_active;
+ bool slope_int_active;
+ bool high_g_int_active;
+ bool low_g_int_active;
+ bool data_int_active;
+ bool fifo_wmark_int_active;
+ bool fifo_full_int_active;
+ struct axis_trigger tap_trigger;
+ struct axis_trigger slope_trigger;
+ bool device_is_flat;
+ bool device_is_down;
+ enum bma2xx_orient_xy device_orientation;
+ struct axis_trigger high_g_trigger;
+};
+
+/* Get the active status of all interrupts */
+int
+bma2xx_get_int_status(const struct bma2xx * bma2xx,
+ struct int_status * int_status);
+
+/* Get the status and size of the FIFO */
+int
+bma2xx_get_fifo_status(const struct bma2xx * bma2xx,
+ bool * overrun,
+ uint8_t * frame_counter);
+
+/* Get/Set the accelerometer range */
+int
+bma2xx_get_g_range(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range * g_range);
+int
+bma2xx_set_g_range(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range);
+
+/* Get/Set the filter output bandwidth */
+int
+bma2xx_get_filter_bandwidth(const struct bma2xx * bma2xx,
+ enum bma2xx_filter_bandwidth * filter_bandwidth);
+int
+bma2xx_set_filter_bandwidth(const struct bma2xx * bma2xx,
+ enum bma2xx_filter_bandwidth filter_bandwidth);
+
+/* Whether the sleep timer is locked to events or to time */
+enum sleep_timer {
+ SLEEP_TIMER_EVENT_DRIVEN = 0,
+ SLEEP_TIMER_EQUIDISTANT_SAMPLING = 1,
+};
+
+/* Power settings of the device */
+struct power_settings {
+ enum bma2xx_power_mode power_mode;
+ enum bma2xx_sleep_duration sleep_duration;
+ enum sleep_timer sleep_timer;
+};
+
+/* Get/Set the power settings of the device */
+int
+bma2xx_get_power_settings(const struct bma2xx * bma2xx,
+ struct power_settings * power_settings);
+int
+bma2xx_set_power_settings(const struct bma2xx * bma2xx,
+ const struct power_settings * power_settings);
+
+/* Get/Set the data register settings */
+int
+bma2xx_get_data_acquisition(const struct bma2xx * bma2xx,
+ bool * unfiltered_reg_data,
+ bool * disable_reg_shadow);
+int
+bma2xx_set_data_acquisition(const struct bma2xx * bma2xx,
+ bool unfiltered_reg_data,
+ bool disable_reg_shadow);
+
+/* Kick off a full soft reset of the device */
+int
+bma2xx_set_softreset(const struct bma2xx * bma2xx);
+
+/* Enable settings of all interupts */
+struct int_enable {
+ bool flat_int_enable;
+ bool orient_int_enable;
+ bool s_tap_int_enable;
+ bool d_tap_int_enable;
+ bool slope_z_int_enable;
+ bool slope_y_int_enable;
+ bool slope_x_int_enable;
+ bool fifo_wmark_int_enable;
+ bool fifo_full_int_enable;
+ bool data_int_enable;
+ bool low_g_int_enable;
+ bool high_g_z_int_enable;
+ bool high_g_y_int_enable;
+ bool high_g_x_int_enable;
+ bool no_motion_select;
+ bool slow_no_mot_z_int_enable;
+ bool slow_no_mot_y_int_enable;
+ bool slow_no_mot_x_int_enable;
+};
+
+/* Get/Set the enable settings of all interrupts */
+int
+bma2xx_get_int_enable(const struct bma2xx * bma2xx,
+ struct int_enable * int_enable);
+int
+bma2xx_set_int_enable(const struct bma2xx * bma2xx,
+ const struct int_enable * int_enable);
+
+/* Which physical device pin is a given interrupt routed to */
+enum int_route {
+ INT_ROUTE_NONE = 0,
+ INT_ROUTE_PIN_1 = 1,
+ INT_ROUTE_PIN_2 = 2,
+ INT_ROUTE_BOTH = 3,
+};
+
+enum bma2xx_int_num {
+ INT1_PIN,
+ INT2_PIN
+};
+
+/* Pin routing settings of all interrupts */
+struct int_routes {
+ enum int_route flat_int_route;
+ enum int_route orient_int_route;
+ enum int_route s_tap_int_route;
+ enum int_route d_tap_int_route;
+ enum int_route slow_no_mot_int_route;
+ enum int_route slope_int_route;
+ enum int_route high_g_int_route;
+ enum int_route low_g_int_route;
+ enum int_route fifo_wmark_int_route;
+ enum int_route fifo_full_int_route;
+ enum int_route data_int_route;
+};
+
+/* Get/Set the pin routing settings of all interrupts */
+int
+bma2xx_get_int_routes(const struct bma2xx * bma2xx,
+ struct int_routes * int_routes);
+int
+bma2xx_set_int_routes(const struct bma2xx * bma2xx,
+ const struct int_routes * int_routes);
+
+/* Whether each interrupt uses filtered or unfiltered data */
+struct int_filters {
+ bool unfiltered_data_int;
+ bool unfiltered_tap_int;
+ bool unfiltered_slow_no_mot_int;
+ bool unfiltered_slope_int;
+ bool unfiltered_high_g_int;
+ bool unfiltered_low_g_int;
+};
+
+/* Get/Set the filtered data settings of all interrupts */
+int
+bma2xx_get_int_filters(const struct bma2xx * bma2xx,
+ struct int_filters * int_filters);
+int
+bma2xx_set_int_filters(const struct bma2xx * bma2xx,
+ const struct int_filters * int_filters);
+
+/* Drive mode of the interrupt pins */
+enum int_pin_output {
+ INT_PIN_OUTPUT_PUSH_PULL = 0,
+ INT_PIN_OUTPUT_OPEN_DRAIN = 1,
+};
+
+/* Active mode of the interrupt pins */
+enum int_pin_active {
+ INT_PIN_ACTIVE_LOW = 0,
+ INT_PIN_ACTIVE_HIGH = 1,
+};
+
+/* Electrical settings of both interrupt pins */
+struct int_pin_electrical {
+ enum int_pin_output pin1_output;
+ enum int_pin_active pin1_active;
+ enum int_pin_output pin2_output;
+ enum int_pin_active pin2_active;
+};
+
+/* Get/Set the electrical settings of both interrupt pins */
+int
+bma2xx_get_int_pin_electrical(const struct bma2xx * bma2xx,
+ struct int_pin_electrical * electrical);
+int
+bma2xx_set_int_pin_electrical(const struct bma2xx * bma2xx,
+ const struct int_pin_electrical * electrical);
+
+/* Length of time that an interrupt condition should be latched active */
+enum int_latch {
+ INT_LATCH_NON_LATCHED = 0,
+ INT_LATCH_LATCHED = 1,
+ INT_LATCH_TEMPORARY_250_US = 2,
+ INT_LATCH_TEMPORARY_500_US = 3,
+ INT_LATCH_TEMPORARY_1_MS = 4,
+ INT_LATCH_TEMPORARY_12_5_MS = 5,
+ INT_LATCH_TEMPORARY_25_MS = 6,
+ INT_LATCH_TEMPORARY_50_MS = 7,
+ INT_LATCH_TEMPORARY_250_MS = 8,
+ INT_LATCH_TEMPORARY_500_MS = 9,
+ INT_LATCH_TEMPORARY_1_S = 10,
+ INT_LATCH_TEMPORARY_2_S = 11,
+ INT_LATCH_TEMPORARY_4_S = 12,
+ INT_LATCH_TEMPORARY_8_S = 13,
+};
+
+/* Get/Set the interrupt condition latch time */
+int
+bma2xx_get_int_latch(const struct bma2xx * bma2xx,
+ enum int_latch * int_latch);
+int
+bma2xx_set_int_latch(const struct bma2xx * bma2xx,
+ bool reset_ints,
+ enum int_latch int_latch);
+
+/* Settings for the low-g interrupt */
+struct low_g_int_cfg {
+ uint16_t delay_ms;
+ float thresh_g;
+ float hyster_g;
+ bool axis_summing;
+};
+
+/* Get/Set the low-g interrupt settings */
+int
+bma2xx_get_low_g_int_cfg(const struct bma2xx * bma2xx,
+ struct low_g_int_cfg * low_g_int_cfg);
+int
+bma2xx_set_low_g_int_cfg(const struct bma2xx * bma2xx,
+ const struct low_g_int_cfg * low_g_int_cfg);
+
+/* Settings for the high-g interrupt */
+struct high_g_int_cfg {
+ float hyster_g;
+ uint16_t delay_ms;
+ float thresh_g;
+};
+
+/* Get/Set the high-g interrupt settings */
+int
+bma2xx_get_high_g_int_cfg(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ struct high_g_int_cfg * high_g_int_cfg);
+int
+bma2xx_set_high_g_int_cfg(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ const struct high_g_int_cfg * high_g_int_cfg);
+
+/* Settings for the slow/no-motion interrupt */
+struct slow_no_mot_int_cfg {
+ uint16_t duration_p_or_s;
+ float thresh_g;
+};
+
+/* Get/Set the slow/no-motion interrupt settings */
+int
+bma2xx_get_slow_no_mot_int_cfg(const struct bma2xx * bma2xx,
+ bool no_motion_select,
+ enum bma2xx_g_range g_range,
+ struct slow_no_mot_int_cfg * slow_no_mot_int_cfg);
+int
+bma2xx_set_slow_no_mot_int_cfg(const struct bma2xx * bma2xx,
+ bool no_motion_select,
+ enum bma2xx_g_range g_range,
+ const struct slow_no_mot_int_cfg * slow_no_mot_int_cfg);
+
+/* Settings for the slope interrupt */
+struct slope_int_cfg {
+ uint8_t duration_p;
+ float thresh_g;
+};
+
+/* Get/Set the slope interrupt settings */
+int
+bma2xx_get_slope_int_cfg(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ struct slope_int_cfg * slope_int_cfg);
+int
+bma2xx_set_slope_int_cfg(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ const struct slope_int_cfg * slope_int_cfg);
+
+/* Settings for the double/single tap interrupt */
+struct tap_int_cfg {
+ enum bma2xx_tap_quiet tap_quiet;
+ enum bma2xx_tap_shock tap_shock;
+ enum bma2xx_d_tap_window d_tap_window;
+ enum bma2xx_tap_wake_samples tap_wake_samples;
+ float thresh_g;
+};
+
+/* Get/Set the double/single tap interrupt settings */
+int
+bma2xx_get_tap_int_cfg(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ struct tap_int_cfg * tap_int_cfg);
+int
+bma2xx_set_tap_int_cfg(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ const struct tap_int_cfg * tap_int_cfg);
+
+/* Settings for the orientation interrupt */
+struct orient_int_cfg {
+ float hyster_g;
+ enum bma2xx_orient_blocking orient_blocking;
+ enum bma2xx_orient_mode orient_mode;
+ bool signal_up_dn;
+ uint8_t blocking_angle;
+};
+
+/* Get/Set the orientation interrupt settings */
+int
+bma2xx_get_orient_int_cfg(const struct bma2xx * bma2xx,
+ struct orient_int_cfg * orient_int_cfg);
+int
+bma2xx_set_orient_int_cfg(const struct bma2xx * bma2xx,
+ const struct orient_int_cfg * orient_int_cfg);
+
+/* Hold time for flat condition */
+enum flat_hold {
+ FLAT_HOLD_0_MS = 0,
+ FLAT_HOLD_512_MS = 1,
+ FLAT_HOLD_1024_MS = 2,
+ FLAT_HOLD_2048_MS = 3,
+};
+
+/* Settings for the flat interrupt */
+struct flat_int_cfg {
+ uint8_t flat_angle;
+ enum flat_hold flat_hold;
+ uint8_t flat_hyster;
+ bool hyster_enable;
+};
+
+/* Get/Set the flat interrupt settings */
+int
+bma2xx_get_flat_int_cfg(const struct bma2xx * bma2xx,
+ struct flat_int_cfg * flat_int_cfg);
+int
+bma2xx_set_flat_int_cfg(const struct bma2xx * bma2xx,
+ const struct flat_int_cfg * flat_int_cfg);
+
+/* Get/Set the FIFO watermark level */
+int
+bma2xx_get_fifo_wmark_level(const struct bma2xx * bma2xx,
+ uint8_t * wmark_level);
+int
+bma2xx_set_fifo_wmark_level(const struct bma2xx * bma2xx,
+ uint8_t wmark_level);
+
+/* Amplitude of a self-test induced acceleration */
+enum self_test_ampl {
+ SELF_TEST_AMPL_HIGH = 0,
+ SELF_TEST_AMPL_LOW = 1,
+};
+
+/* Direction of a self-test induced acceleration */
+enum self_test_sign {
+ SELF_TEST_SIGN_NEGATIVE = 0,
+ SELF_TEST_SIGN_POSITIVE = 1,
+};
+
+/* Settings for the self-test functionality */
+struct self_test_cfg {
+ enum self_test_ampl self_test_ampl;
+ enum self_test_sign self_test_sign;
+ enum axis self_test_axis;
+ bool self_test_enabled;
+};
+
+/* Get/Set the self-test settings */
+int
+bma2xx_get_self_test_cfg(const struct bma2xx * bma2xx,
+ struct self_test_cfg * self_test_cfg);
+int
+bma2xx_set_self_test_cfg(const struct bma2xx * bma2xx,
+ const struct self_test_cfg * self_test_cfg);
+
+/* Get/Set the NVM reset/write control values */
+int
+bma2xx_get_nvm_control(const struct bma2xx * bma2xx,
+ uint8_t * remaining_cycles,
+ bool * load_from_nvm,
+ bool * nvm_is_ready,
+ bool * nvm_unlocked);
+int
+bma2xx_set_nvm_control(const struct bma2xx * bma2xx,
+ bool load_from_nvm,
+ bool store_into_nvm,
+ bool nvm_unlocked);
+
+/* Length of time before the I2C watchdog fires */
+enum i2c_watchdog {
+ I2C_WATCHDOG_DISABLED = 0,
+ I2C_WATCHDOG_1_MS = 1,
+ I2C_WATCHDOG_50_MS = 2,
+};
+
+/* Get/Set the I2C watchdog settings */
+int
+bma2xx_get_i2c_watchdog(const struct bma2xx * bma2xx,
+ enum i2c_watchdog * i2c_watchdog);
+int
+bma2xx_set_i2c_watchdog(const struct bma2xx * bma2xx,
+ enum i2c_watchdog i2c_watchdog);
+
+/* Offset compensation settings used in slow compensation mode */
+struct slow_ofc_cfg {
+ bool ofc_z_enabled;
+ bool ofc_y_enabled;
+ bool ofc_x_enabled;
+ bool high_bw_cut_off;
+};
+
+/* Get/Set the fast & slow offset compensation mode settings, and reset all
+ * offset compensation values back to NVM defaults */
+int
+bma2xx_get_fast_ofc_cfg(const struct bma2xx * bma2xx,
+ bool * fast_ofc_ready,
+ enum bma2xx_offset_comp_target * ofc_target_z,
+ enum bma2xx_offset_comp_target * ofc_target_y,
+ enum bma2xx_offset_comp_target * ofc_target_x);
+int
+bma2xx_set_fast_ofc_cfg(const struct bma2xx * bma2xx,
+ enum axis fast_ofc_axis,
+ enum bma2xx_offset_comp_target fast_ofc_target,
+ bool trigger_fast_ofc);
+int
+bma2xx_get_slow_ofc_cfg(const struct bma2xx * bma2xx,
+ struct slow_ofc_cfg * slow_ofc_cfg);
+int
+bma2xx_set_slow_ofc_cfg(const struct bma2xx * bma2xx,
+ const struct slow_ofc_cfg * slow_ofc_cfg);
+int
+bma2xx_set_ofc_reset(const struct bma2xx * bma2xx);
+
+/* Get/Set the offset compensation value for a specific axis */
+int
+bma2xx_get_ofc_offset(const struct bma2xx * bma2xx,
+ enum axis axis,
+ float * offset_g);
+int
+bma2xx_set_ofc_offset(const struct bma2xx * bma2xx,
+ enum axis axis,
+ float offset_g);
+
+/* General purpose non-volatile data registers */
+enum saved_data_addr {
+ SAVED_DATA_ADDR_0 = 0,
+ SAVED_DATA_ADDR_1 = 1,
+};
+
+/* Get/Set the data stored in general purpose non-volatile registers */
+int
+bma2xx_get_saved_data(const struct bma2xx * bma2xx,
+ enum saved_data_addr saved_data_addr,
+ uint8_t * saved_data_val);
+int
+bma2xx_set_saved_data(const struct bma2xx * bma2xx,
+ enum saved_data_addr saved_data_addr,
+ uint8_t saved_data_val);
+
+/* Mode that the FIFO is running in */
+enum fifo_mode {
+ FIFO_MODE_BYPASS = 0,
+ FIFO_MODE_FIFO = 1,
+ FIFO_MODE_STREAM = 2,
+};
+
+/* Measurements for which axis to capture into the FIFO */
+enum fifo_data {
+ FIFO_DATA_X_AND_Y_AND_Z = 0,
+ FIFO_DATA_X_ONLY = 1,
+ FIFO_DATA_Y_ONLY = 2,
+ FIFO_DATA_Z_ONLY = 3,
+};
+
+/* FIFO capture and behavior settings */
+struct fifo_cfg {
+ enum fifo_mode fifo_mode;
+ enum fifo_data fifo_data;
+};
+
+/* Get/Set the FIFO capture and behavior settings */
+int
+bma2xx_get_fifo_cfg(const struct bma2xx * bma2xx,
+ struct fifo_cfg * fifo_cfg);
+int
+bma2xx_set_fifo_cfg(const struct bma2xx * bma2xx,
+ const struct fifo_cfg * fifo_cfg);
+
+/* Read a single multi-axis data frame from the FIFO */
+int
+bma2xx_get_fifo(const struct bma2xx * bma2xx,
+ enum bma2xx_g_range g_range,
+ enum fifo_data fifo_data,
+ struct accel_data * accel_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw/drivers/sensors/bma2xx/src/bma2xx_shell.c b/hw/drivers/sensors/bma2xx/src/bma2xx_shell.c
new file mode 100644
index 000000000..d2b6899a9
--- /dev/null
+++ b/hw/drivers/sensors/bma2xx/src/bma2xx_shell.c
@@ -0,0 +1,717 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <errno.h>
+
+#include "syscfg/syscfg.h"
+#include "bma2xx/bma2xx.h"
+#include "bma2xx_priv.h"
+#include "console/console.h"
+#include "shell/shell.h"
+
+#if MYNEWT_VAL(BMA2XX_CLI)
+
+struct self_test_mode {
+ const char * name;
+ float hmult;
+ float lmult;
+};
+
+static const struct self_test_mode self_test_modes[] = {
+ {
+ .name = "default",
+ .hmult = 1.0,
+ .lmult = 0.0,
+ },
+ {
+ .name = "strict",
+ .hmult = 2.0,
+ .lmult = 0.5,
+ },
+};
+
+static int
+bma2xx_self_test_cmd(struct bma2xx * bma2xx,
+ int argc,
+ char * argv[])
+{
+ const struct self_test_mode * self_test_mode;
+ uint8_t i;
+ bool self_test_fail;
+ int rc;
+
+ if (argc != 1) {
+ return EINVAL;
+ }
+
+ self_test_mode = NULL;
+ for (i = 0; i < sizeof(self_test_modes) /
+ sizeof(*self_test_modes); i++) {
+ if (strcmp(self_test_modes[i].name, argv[0]) == 0) {
+ self_test_mode = self_test_modes + i;
+ }
+ }
+
+ if (self_test_mode == NULL) {
+ return EINVAL;
+ }
+
+ rc = bma2xx_self_test(bma2xx,
+ self_test_mode->hmult,
+ self_test_mode->lmult,
+ &self_test_fail);
+ if (rc != 0) {
+ return rc;
+ }
+
+ if (self_test_fail) {
+ console_printf("self test failed\n");
+ } else {
+ console_printf("self test passed\n");
+ }
+
+ return 0;
+}
+
+struct offset_comp_target {
+ const char * name;
+ enum bma2xx_offset_comp_target target;
+};
+
+static const struct offset_comp_target offset_comp_targets[] = {
+ {
+ .name = "0g",
+ .target = BMA2XX_OFFSET_COMP_TARGET_0_G,
+ },
+ {
+ .name = "-1g",
+ .target = BMA2XX_OFFSET_COMP_TARGET_NEG_1_G,
+ },
+ {
+ .name = "+1g",
+ .target = BMA2XX_OFFSET_COMP_TARGET_POS_1_G,
+ },
+};
+
+static int
+bma2xx_offset_compensation_cmd(struct bma2xx * bma2xx,
+ int argc,
+ char * argv[])
+{
+ const struct offset_comp_target * target_x;
+ const struct offset_comp_target * target_y;
+ const struct offset_comp_target * target_z;
+ uint8_t i;
+
+ if (argc != 3) {
+ return EINVAL;
+ }
+
+ target_x = NULL;
+ for (i = 0; i < sizeof(offset_comp_targets) /
+ sizeof(*offset_comp_targets); i++) {
+ if (strcmp(offset_comp_targets[i].name, argv[0]) == 0) {
+ target_x = offset_comp_targets + i;
+ }
+ }
+ target_y = NULL;
+ for (i = 0; i < sizeof(offset_comp_targets) /
+ sizeof(*offset_comp_targets); i++) {
+ if (strcmp(offset_comp_targets[i].name, argv[1]) == 0) {
+ target_y = offset_comp_targets + i;
+ }
+ }
+ target_z = NULL;
+ for (i = 0; i < sizeof(offset_comp_targets) /
+ sizeof(*offset_comp_targets); i++) {
+ if (strcmp(offset_comp_targets[i].name, argv[2]) == 0) {
+ target_z = offset_comp_targets + i;
+ }
+ }
+
+ if (target_x == NULL) {
+ return EINVAL;
+ }
+ if (target_y == NULL) {
+ return EINVAL;
+ }
+ if (target_z == NULL) {
+ return EINVAL;
+ }
+
+ return bma2xx_offset_compensation(bma2xx,
+ target_x->target,
+ target_y->target,
+ target_z->target);
+}
+
+static int
+bma2xx_query_offsets_cmd(struct bma2xx * bma2xx,
+ int argc,
+ char * argv[])
+{
+ int rc;
+ float offset_x_g;
+ float offset_y_g;
+ float offset_z_g;
+ char buffer_x[20];
+ char buffer_y[20];
+ char buffer_z[20];
+
+ if (argc != 0) {
+ return EINVAL;
+ }
+
+ rc = bma2xx_query_offsets(bma2xx,
+ &offset_x_g,
+ &offset_y_g,
+ &offset_z_g);
+ if (rc != 0) {
+ return rc;
+ }
+
+ sensor_ftostr(offset_x_g, buffer_x, sizeof(buffer_x));
+ sensor_ftostr(offset_y_g, buffer_y, sizeof(buffer_y));
+ sensor_ftostr(offset_z_g, buffer_z, sizeof(buffer_z));
+
+ console_printf("offset x = %s offset y = %s offset z = %s\n",
+ buffer_x,
+ buffer_y,
+ buffer_z);
+
+ return 0;
+}
+
+static int
+bma2xx_write_offsets_cmd(struct bma2xx * bma2xx,
+ int argc,
+ char * argv[])
+{
+ if (argc != 0) {
+ return EINVAL;
+ }
+
+ return bma2xx_write_offsets(bma2xx, 0.0, 0.0, 0.0);
+}
+
+struct stream_read_context {
+ uint32_t count;
+};
+
+static bool
+bma2xx_stream_read_cb(void * arg,
+ struct sensor_accel_data * sad)
+{
+ char buffer_x[20];
+ char buffer_y[20];
+ char buffer_z[20];
+ struct stream_read_context * ctx;
+
+ sensor_ftostr(sad->sad_x, buffer_x, sizeof(buffer_x));
+ sensor_ftostr(sad->sad_y, buffer_y, sizeof(buffer_y));
+ sensor_ftostr(sad->sad_z, buffer_z, sizeof(buffer_z));
+
+ console_printf("x = %s y = %s z = %s\n",
+ buffer_x,
+ buffer_y,
+ buffer_z);
+
+ ctx = (struct stream_read_context *)arg;
+ ctx->count--;
+
+ return ctx->count == 0;
+}
+
+static int
+bma2xx_stream_read_cmd(struct bma2xx * bma2xx,
+ int argc,
+ char * argv[])
+{
+ char * end;
+ struct stream_read_context ctx;
+
+ if (argc != 1) {
+ return EINVAL;
+ }
+
+ ctx.count = strtoul(argv[0], &end, 10);
+ if (*end != '\0') {
+ return EINVAL;
+ }
+
+ return bma2xx_stream_read(bma2xx,
+ bma2xx_stream_read_cb,
+ &ctx,
+ 0);
+}
+
+static int
+bma2xx_current_temp_cmd(struct bma2xx * bma2xx,
+ int argc,
+ char * argv[])
+{
+ float temp_c;
+ int rc;
+ char buffer[20];
+
+ if (argc != 0) {
+ return EINVAL;
+ }
+
+ rc = bma2xx_current_temp(bma2xx, &temp_c);
+ if (rc != 0) {
+ return rc;
+ }
+
+ sensor_ftostr(temp_c, buffer, sizeof(buffer));
+
+ console_printf("temp = %s C\n", buffer);
+
+ return 0;
+}
+
+static void
+console_print_orient(const struct bma2xx_orient_xyz * orient_xyz)
+{
+ const char * xy_desc;
+ const char * z_desc;
+
+ switch (orient_xyz->orient_xy) {
+ case BMA2XX_ORIENT_XY_PORTRAIT_UPRIGHT:
+ xy_desc = "portrait-upright";
+ break;
+ case BMA2XX_ORIENT_XY_PORTRAIT_UPSIDE_DOWN:
+ xy_desc = "portrait-upside-down";
+ break;
+ case BMA2XX_ORIENT_XY_LANDSCAPE_LEFT:
+ xy_desc = "landscape-left";
+ break;
+ case BMA2XX_ORIENT_XY_LANDSCAPE_RIGHT:
+ xy_desc = "landscape-right";
+ break;
+ default:
+ xy_desc = "unknown-enum";
+ break;
+ }
+
+ if (orient_xyz->downward_z) {
+ z_desc = "facing-downward";
+ } else {
+ z_desc = "facing-upward";
+ }
+
+ console_printf("xy = %s z = %s\n", xy_desc, z_desc);
+}
+
+static int
+bma2xx_current_orient_cmd(struct bma2xx * bma2xx,
+ int argc,
+ char * argv[])
+{
+ struct bma2xx_orient_xyz orient_xyz;
+ int rc;
+
+ if (argc != 0) {
+ return EINVAL;
+ }
+
+ rc = bma2xx_current_orient(bma2xx, &orient_xyz);
+ if (rc != 0) {
+ return rc;
+ }
+
+ console_print_orient(&orient_xyz);
+
+ return 0;
+}
+
+static int
+bma2xx_wait_for_orient_cmd(struct bma2xx * bma2xx,
+ int argc,
+ char * argv[])
+{
+ struct bma2xx_orient_xyz orient_xyz;
+ int rc;
+
+ if (argc != 0) {
+ return EINVAL;
+ }
+
+ rc = bma2xx_wait_for_orient(bma2xx, &orient_xyz);
+ if (rc != 0) {
+ return rc;
+ }
+
+ console_print_orient(&orient_xyz);
+ console_printf("done!\n");
+
+ return 0;
+}
+
+static int
+bma2xx_wait_for_high_g_cmd(struct bma2xx * bma2xx,
+ int argc,
+ char * argv[])
+{
+ int rc;
+
+ if (argc != 0) {
+ return EINVAL;
+ }
+
+ rc = bma2xx_wait_for_high_g(bma2xx);
+ if (rc != 0) {
+ return rc;
+ }
+
+ console_printf("done!\n");
+
+ return 0;
+}
+
+static int
+bma2xx_wait_for_low_g_cmd(struct bma2xx * bma2xx,
+ int argc,
+ char * argv[])
+{
+ int rc;
+
+ if (argc != 0) {
+ return EINVAL;
+ }
+
+ rc = bma2xx_wait_for_low_g(bma2xx);
+ if (rc != 0) {
+ return rc;
+ }
+
+ console_printf("done!\n");
+
+ return 0;
+}
+
+struct tap_type {
+ const char * name;
+ enum bma2xx_tap_type type;
+};
+
+static const struct tap_type tap_types[] = {
+ {
+ .name = "double",
+ .type = BMA2XX_TAP_TYPE_DOUBLE,
+ },
+ {
+ .name = "single",
+ .type = BMA2XX_TAP_TYPE_SINGLE,
+ },
+};
+
+static int
+bma2xx_wait_for_tap_cmd(struct bma2xx * bma2xx,
+ int argc,
+ char * argv[])
+{
+ const struct tap_type * tap_type;
+ uint8_t i;
+ int rc;
+
+ if (argc != 1) {
+ return EINVAL;
+ }
+
+ tap_type = NULL;
+ for (i = 0; i < sizeof(tap_types) /
+ sizeof(*tap_types); i++) {
+ if (strcmp(tap_types[i].name, argv[0]) == 0) {
+ tap_type = tap_types + i;
+ }
+ }
+
+ if (tap_type == NULL) {
+ return EINVAL;
+ }
+
+ rc = bma2xx_wait_for_tap(bma2xx, tap_type->type);
+ if (rc != 0) {
+ return rc;
+ }
+
+ console_printf("done!\n");
+
+ return 0;
+}
+
+struct power_mode {
+ const char * name;
+ enum bma2xx_power_mode power;
+};
+
+static const struct power_mode power_modes[] = {
+ {
+ .name = "normal",
+ .power = BMA2XX_POWER_MODE_NORMAL,
+ },
+ {
+ .name = "deep-suspend",
+ .power = BMA2XX_POWER_MODE_DEEP_SUSPEND,
+ },
+ {
+ .name = "suspend",
+ .power = BMA2XX_POWER_MODE_SUSPEND,
+ },
+ {
+ .name = "standby",
+ .power = BMA2XX_POWER_MODE_STANDBY,
+ },
+ {
+ .name = "lpm1",
+ .power = BMA2XX_POWER_MODE_LPM_1,
+ },
+ {
+ .name = "lpm2",
+ .power = BMA2XX_POWER_MODE_LPM_2,
+ },
+};
+
+struct sleep_duration {
+ const char * name;
+ enum bma2xx_sleep_duration sleep;
+};
+
+static const struct sleep_duration sleep_durations[] = {
+ {
+ .name = "0.5ms",
+ .sleep = BMA2XX_SLEEP_DURATION_0_5_MS,
+ },
+ {
+ .name = "1ms",
+ .sleep = BMA2XX_SLEEP_DURATION_1_MS,
+ },
+ {
+ .name = "2ms",
+ .sleep = BMA2XX_SLEEP_DURATION_2_MS,
+ },
+ {
+ .name = "4ms",
+ .sleep = BMA2XX_SLEEP_DURATION_4_MS,
+ },
+ {
+ .name = "6ms",
+ .sleep = BMA2XX_SLEEP_DURATION_6_MS,
+ },
+ {
+ .name = "10ms",
+ .sleep = BMA2XX_SLEEP_DURATION_10_MS,
+ },
+ {
+ .name = "25ms",
+ .sleep = BMA2XX_SLEEP_DURATION_25_MS,
+ },
+ {
+ .name = "50ms",
+ .sleep = BMA2XX_SLEEP_DURATION_50_MS,
+ },
+ {
+ .name = "100ms",
+ .sleep = BMA2XX_SLEEP_DURATION_100_MS,
+ },
+ {
+ .name = "500ms",
+ .sleep = BMA2XX_SLEEP_DURATION_500_MS,
+ },
+ {
+ .name = "1s",
+ .sleep = BMA2XX_SLEEP_DURATION_1_S,
+ },
+};
+
+static int
+bma2xx_power_settings_cmd(struct bma2xx * bma2xx,
+ int argc,
+ char * argv[])
+{
+ const struct power_mode * power_mode;
+ const struct sleep_duration * sleep_duration;
+ uint8_t i;
+
+ if (argc != 2) {
+ return EINVAL;
+ }
+
+ power_mode = NULL;
+ for (i = 0; i < sizeof(power_modes) /
+ sizeof(*power_modes); i++) {
+ if (strcmp(power_modes[i].name, argv[0]) == 0) {
+ power_mode = power_modes + i;
+ }
+ }
+
+ sleep_duration = NULL;
+ for (i = 0; i < sizeof(sleep_durations) /
+ sizeof(*sleep_durations); i++) {
+ if (strcmp(sleep_durations[i].name, argv[1]) == 0) {
+ sleep_duration = sleep_durations + i;
+ }
+ }
+
+ if (power_mode == NULL) {
+ return EINVAL;
+ }
+ if (sleep_duration == NULL) {
+ return EINVAL;
+ }
+
+ return bma2xx_power_settings(bma2xx,
+ power_mode->power,
+ sleep_duration->sleep);
+}
+
+struct subcmd {
+ const char * name;
+ const char * help;
+ int (*func)(struct bma2xx * bma2xx,
+ int argc,
+ char * argv[]);
+};
+
+static const struct subcmd supported_subcmds[] = {
+ {
+ .name = "self-test",
+ .help = "<default|strict>",
+ .func = bma2xx_self_test_cmd,
+ },
+ {
+ .name = "offset-compensation",
+ .help = "<x={0g|-1g|+1g}> <y={0g|-1g|+1g}> <z={0g|-1g|+1g}>",
+ .func = bma2xx_offset_compensation_cmd,
+ },
+ {
+ .name = "query-offsets",
+ .help = "",
+ .func = bma2xx_query_offsets_cmd,
+ },
+ {
+ .name = "write-offsets",
+ .help = "",
+ .func = bma2xx_write_offsets_cmd,
+ },
+ {
+ .name = "stream-read",
+ .help = "<num-reads>",
+ .func = bma2xx_stream_read_cmd,
+ },
+ {
+ .name = "current-temp",
+ .help = "",
+ .func = bma2xx_current_temp_cmd,
+ },
+ {
+ .name = "current-orient",
+ .help = "",
+ .func = bma2xx_current_orient_cmd,
+ },
+ {
+ .name = "wait-for-orient",
+ .help = "",
+ .func = bma2xx_wait_for_orient_cmd,
+ },
+ {
+ .name = "wait-for-high-g",
+ .help = "",
+ .func = bma2xx_wait_for_high_g_cmd,
+ },
+ {
+ .name = "wait-for-low-g",
+ .help = "",
+ .func = bma2xx_wait_for_low_g_cmd,
+ },
+ {
+ .name = "wait-for-tap",
+ .help = "<double|single>",
+ .func = bma2xx_wait_for_tap_cmd,
+ },
+ {
+ .name = "power-settings",
+ .help = "<normal|deep-suspend|suspend|standby|lpm1|lpm2>" \
+ "\n " \
+ "<0.5ms|1ms|2ms|4ms|6ms|10ms|25ms|50ms|100ms|500ms|1s>",
+ .func = bma2xx_power_settings_cmd,
+ },
+};
+
+static int
+bma2xx_shell_cmd(int argc, char * argv[])
+{
+ struct os_dev * dev;
+ struct bma2xx * bma2xx;
+ const struct subcmd * subcmd;
+ uint8_t i;
+
+ dev = os_dev_open(MYNEWT_VAL(BMA2XX_SHELL_DEV_NAME), OS_TIMEOUT_NEVER, NULL);
+ if (dev == NULL) {
+ console_printf("failed to open bma2xx_0 device\n");
+ return ENODEV;
+ }
+
+ bma2xx = (struct bma2xx *)dev;
+
+ subcmd = NULL;
+ if (argc > 1) {
+ for (i = 0; i < sizeof(supported_subcmds) /
+ sizeof(*supported_subcmds); i++) {
+ if (strcmp(supported_subcmds[i].name, argv[1]) == 0) {
+ subcmd = supported_subcmds + i;
+ }
+ }
+
+ if (subcmd == NULL) {
+ console_printf("unknown %s subcommand\n", argv[1]);
+ }
+ }
+
+ if (subcmd != NULL) {
+ if (subcmd->func(bma2xx, argc - 2, argv + 2) != 0) {
+ console_printf("could not run %s subcommand\n", argv[1]);
+ console_printf("%s %s\n", subcmd->name, subcmd->help);
+ }
+ } else {
+ for (i = 0; i < sizeof(supported_subcmds) /
+ sizeof(*supported_subcmds); i++) {
+ subcmd = supported_subcmds + i;
+ console_printf("%s %s\n", subcmd->name, subcmd->help);
+ }
+ }
+
+ os_dev_close(dev);
+
+ return 0;
+}
+
+static const struct shell_cmd bma2xx_shell_cmd_desc = {
+ .sc_cmd = "bma2xx",
+ .sc_cmd_func = bma2xx_shell_cmd,
+};
+
+int
+bma2xx_shell_init(void)
+{
+ return shell_cmd_register(&bma2xx_shell_cmd_desc);
+}
+
+#endif
diff --git a/hw/drivers/sensors/bma2xx/syscfg.yml b/hw/drivers/sensors/bma2xx/syscfg.yml
new file mode 100644
index 000000000..42c95de09
--- /dev/null
+++ b/hw/drivers/sensors/bma2xx/syscfg.yml
@@ -0,0 +1,47 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+syscfg.defs:
+ BMA2XX_CLI:
+ description: 'Enable shell support for BMA2XX'
+ value: 0
+ BMA2XX_I2C_WDT:
+ description: 'Enable I2C watchdog functionality'
+ value: 0
+ BMA2XX_INT_ENABLE:
+ description: 'Enable interrupt support, necessary for events'
+ value: 1
+ BMA2XX_INT_CFG_ACTIVE:
+ description: 'Set 0 for active-low, 1 for active-high'
+ value: 1
+ BMA2XX_INT_CFG_OUTPUT:
+ description: 'Set 0 for push-pull, 1 for open-drain'
+ value: 1
+ BMA2XX_INT_PIN_DEVICE:
+ description: 'Interrupt pin number 1 or 2 on accelerometer device'
+ value: 1
+ BMA2XX_INT2_PIN_DEVICE:
+ description: 'Interrupt pin number 1 or 2 on accelerometer device'
+ value: 2
+ BMA2XX_LOG:
+ description: 'Enable BMA2XX logging'
+ value: 0
+ BMA2XX_SHELL_DEV_NAME:
+ description: 'BMA2XX Shell device name'
+ value: "\"bma2xx_0\""
diff --git a/hw/sensor/creator/pkg.yml b/hw/sensor/creator/pkg.yml
index 1c6a2ecd6..d9f4ec092 100644
--- a/hw/sensor/creator/pkg.yml
+++ b/hw/sensor/creator/pkg.yml
@@ -48,6 +48,8 @@ pkg.deps.BMP280_OFB:
- hw/drivers/sensors/bmp280
pkg.deps.BMA253_OFB:
- hw/drivers/sensors/bma253
+pkg.deps.BMA2XX_OFB:
+ - hw/drivers/sensors/bma2xx
pkg.deps.LIS2DW12_OFB:
- hw/drivers/sensors/lis2dw12
pkg.init:
diff --git a/hw/sensor/creator/src/sensor_creator.c b/hw/sensor/creator/src/sensor_creator.c
index 14d3e5566..e2ee8d823 100644
--- a/hw/sensor/creator/src/sensor_creator.c
+++ b/hw/sensor/creator/src/sensor_creator.c
@@ -60,6 +60,10 @@
#include <bma253/bma253.h>
#endif
+#if MYNEWT_VAL(BMA2XX_OFB)
+#include <bma2xx/bma2xx.h>
+#endif
+
#if MYNEWT_VAL(ADXL345_OFB)
#include <adxl345/adxl345.h>
@@ -118,6 +122,10 @@ static struct bmp280 bmp280;
static struct bma253 bma253;
#endif
+#if MYNEWT_VAL(BMA2XX_OFB)
+static struct bma2xx bma2xx;
+#endif
+
#if MYNEWT_VAL(ADXL345_OFB)
static struct adxl345 adxl345;
#endif
@@ -242,10 +250,39 @@ static struct sensor_itf i2c_0_itf_lis = {
.si_num = 0,
.si_addr = 0x18,
.si_ints = {
- { MYNEWT_VAL(BMA253_INT_PIN_HOST), MYNEWT_VAL(BMA253_INT_PIN_DEVICE),
- MYNEWT_VAL(BMA253_INT_CFG_ACTIVE)},
- { MYNEWT_VAL(BMA253_INT2_PIN_HOST), MYNEWT_VAL(BMA253_INT2_PIN_DEVICE),
- MYNEWT_VAL(BMA253_INT_CFG_ACTIVE)}
+ { 26, MYNEWT_VAL(BMA2XX_INT_PIN_DEVICE),
+ MYNEWT_VAL(BMA2XX_INT_CFG_ACTIVE)},
+ { 25, MYNEWT_VAL(BMA2XX_INT2_PIN_DEVICE),
+ MYNEWT_VAL(BMA2XX_INT_CFG_ACTIVE)}
+ },
+};
+#endif
+
+#if MYNEWT_VAL(I2C_0) && MYNEWT_VAL(BMA2XX_OFB)
+static struct sensor_itf spi2c_0_itf_bma2xx = {
+ .si_type = SENSOR_ITF_I2C,
+ .si_num = 0,
+ .si_addr = 0x18,
+ .si_ints = {
+ { 26, MYNEWT_VAL(BMA2XX_INT_PIN_DEVICE),
+ MYNEWT_VAL(BMA2XX_INT_CFG_ACTIVE)},
+ { 25, MYNEWT_VAL(BMA2XX_INT2_PIN_DEVICE),
+ MYNEWT_VAL(BMA2XX_INT_CFG_ACTIVE)}
+ },
+};
+#endif
+#if MYNEWT_VAL(SPI_0_MASTER) && MYNEWT_VAL(BMA2XX_OFB)
+//TODO: Make INT pin nums configurable. Leaving hardcoded
+//to handle multiple bma2xx sensor interface examples
+static struct sensor_itf spi2c_0_itf_bma2xx = {
+ .si_type = SENSOR_ITF_SPI,
+ .si_num = 0,
+ .si_cs_pin = 21,
+ .si_ints = {
+ { 26, MYNEWT_VAL(BMA2XX_INT_PIN_DEVICE),
+ MYNEWT_VAL(BMA2XX_INT_CFG_ACTIVE)},
+ { 25, MYNEWT_VAL(BMA2XX_INT2_PIN_DEVICE),
+ MYNEWT_VAL(BMA2XX_INT_CFG_ACTIVE)}
},
};
#endif
@@ -769,11 +806,12 @@ config_lis2dw12_sensor(void)
cfg.tap.latency = 8; /* 640ms */
cfg.tap.quiet = 0; /* 10ms */
cfg.tap.shock = 3; /* 120ms */
+
cfg.double_tap_event_enable = 0;
- cfg.freefall_dur = 6;
+ cfg.freefall_dur = 6;
cfg.freefall_ths = 3; /* ~312mg */
-
+
cfg.int1_pin_cfg = 0;
cfg.int2_pin_cfg = 0;
cfg.int_enable = 0;
@@ -783,7 +821,7 @@ config_lis2dw12_sensor(void)
cfg.int_active_low = 0;
cfg.slp_mode = 0;
cfg.self_test_mode = LIS2DW12_ST_MODE_DISABLE;
-
+
cfg.fifo_mode = LIS2DW12_FIFO_M_BYPASS;
cfg.fifo_threshold = 32;
@@ -798,16 +836,62 @@ config_lis2dw12_sensor(void)
cfg.low_noise_enable = 1;
cfg.read_mode.mode = LIS2DW12_READ_M_POLL;
+
cfg.mask = SENSOR_TYPE_ACCELEROMETER;
rc = lis2dw12_config((struct lis2dw12 *) dev, &cfg);
assert(rc == 0);
-
+
os_dev_close(dev);
return rc;
}
#endif
+#if MYNEWT_VAL(BMA2XX_OFB)
+/**
+ * BMA2XX sensor default configuration
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+config_bma2xx_sensor(void)
+{
+ struct os_dev * dev;
+ struct bma2xx_cfg cfg;
+ int rc;
+
+ dev = os_dev_open("bma2xx_0", OS_TIMEOUT_NEVER, NULL);
+ assert(dev != NULL);
+
+ cfg.model = BMA2XX_BMA280;
+ cfg.low_g_delay_ms = BMA2XX_LOW_G_DELAY_MS_DEFAULT;
+ cfg.high_g_delay_ms = BMA2XX_HIGH_G_DELAY_MS_DEFAULT;
+ cfg.g_range = BMA2XX_G_RANGE_2;
+ cfg.filter_bandwidth = BMA2XX_FILTER_BANDWIDTH_500_HZ;
+ cfg.use_unfiltered_data = false;
+ cfg.tap_quiet = BMA2XX_TAP_QUIET_30_MS;
+ cfg.tap_shock = BMA2XX_TAP_SHOCK_50_MS;
+ cfg.d_tap_window = BMA2XX_D_TAP_WINDOW_250_MS;
+ cfg.tap_wake_samples = BMA2XX_TAP_WAKE_SAMPLES_16;
+ cfg.tap_thresh_g = 1.0;
+ cfg.offset_x_g = 0.0;
+ cfg.offset_y_g = 0.0;
+ cfg.offset_z_g = 0.0;
+ cfg.orient_blocking = BMA2XX_ORIENT_BLOCKING_NONE;
+ cfg.orient_mode = BMA2XX_ORIENT_MODE_SYMMETRICAL;
+ cfg.power_mode = BMA2XX_POWER_MODE_NORMAL;
+ cfg.sleep_duration = BMA2XX_SLEEP_DURATION_0_5_MS;
+ cfg.sensor_mask = SENSOR_TYPE_ACCELEROMETER;
+
+ rc = bma2xx_config((struct bma2xx *)dev, &cfg);
+ assert(rc == 0);
+
+ os_dev_close(dev);
+
+ return 0;
+}
+#endif
+
/* Sensor device creation */
void
sensor_dev_create(void)
@@ -923,6 +1007,15 @@ sensor_dev_create(void)
assert(rc == 0);
#endif
+#if MYNEWT_VAL(BMA2XX_OFB)
+rc = os_dev_create((struct os_dev *)&bma2xx, "bma2xx_0",
+ OS_DEV_INIT_PRIMARY, 0, bma2xx_init, &spi2c_0_itf_bma2xx);
+assert(rc == 0);
+
+rc = config_bma2xx_sensor();
+assert(rc == 0);
+#endif
+
#if MYNEWT_VAL(ADXL345_OFB)
rc = os_dev_create((struct os_dev *) &adxl345, "adxl345_0",
OS_DEV_INIT_PRIMARY, 0, adxl345_init, (void *)&i2c_0_itf_adxl);
diff --git a/hw/sensor/creator/syscfg.yml b/hw/sensor/creator/syscfg.yml
index 2d750c8c5..48954d07f 100644
--- a/hw/sensor/creator/syscfg.yml
+++ b/hw/sensor/creator/syscfg.yml
@@ -61,4 +61,7 @@ syscfg.defs:
LIS2DW12_OFB:
description: 'LIS2DW12 is present'
value : 0
+ BMA2XX_OFB:
+ description: 'A sensor in the BMA2XX family is present'
+ value : 0
diff --git a/hw/sensor/include/sensor/sensor.h b/hw/sensor/include/sensor/sensor.h
index 9e758e5c8..fccf1cbe2 100644
--- a/hw/sensor/include/sensor/sensor.h
+++ b/hw/sensor/include/sensor/sensor.h
@@ -365,7 +365,7 @@ typedef int (*sensor_read_func_t)(struct sensor *, sensor_type_t,
typedef int (*sensor_get_config_func_t)(struct sensor *, sensor_type_t,
struct sensor_cfg *);
-/**
+/**
* Send a new configuration register set to the sensor.
*
* @param ptr to the sensor-specific stucture
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services