You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by vi...@apache.org on 2018/04/18 21:43:05 UTC
[mynewt-core] branch master updated: Sensors/BMA2XX - New PR from
PR #699 comments (#1018)
This is an automated email from the ASF dual-hosted git repository.
vipulrahane pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
The following commit(s) were added to refs/heads/master by this push:
new bac5f88 Sensors/BMA2XX - New PR from PR #699 comments (#1018)
bac5f88 is described below
commit bac5f886532d83b1b73de62f6be917daf02f2c5b
Author: joshgrob <jo...@grobtech.com>
AuthorDate: Wed Apr 18 16:43:02 2018 -0500
Sensors/BMA2XX - New PR from PR #699 comments (#1018)
* sensors/bma2xx: Syscfg setup
* sensors/bma2xx: first driver files
* sensors/bma2xx: remove pins from configs, model cfg option
* sensors/bma2xx: PR #697 fixes. typos, config for I2C
* sensors/bma2xx: fixed method line and added todo comments for INT pins
---
apps/sensors_test/src/main.c | 6 +
apps/sensors_test/syscfg.yml | 1 +
hw/bsp/bmd300eval/src/hal_bsp.c | 14 +
hw/bsp/bmd300eval/syscfg.yml | 7 +
hw/drivers/sensors/bma2xx/README.md | 189 +
hw/drivers/sensors/bma2xx/include/bma2xx/bma2xx.h | 464 ++
hw/drivers/sensors/bma2xx/pkg.yml | 38 +
hw/drivers/sensors/bma2xx/src/bma2xx.c | 4941 +++++++++++++++++++++
hw/drivers/sensors/bma2xx/src/bma2xx_priv.h | 670 +++
hw/drivers/sensors/bma2xx/src/bma2xx_shell.c | 717 +++
hw/drivers/sensors/bma2xx/syscfg.yml | 47 +
hw/sensor/creator/pkg.yml | 2 +
hw/sensor/creator/src/sensor_creator.c | 109 +-
hw/sensor/creator/syscfg.yml | 3 +
hw/sensor/include/sensor/sensor.h | 2 +-
15 files changed, 7201 insertions(+), 9 deletions(-)
diff --git a/apps/sensors_test/src/main.c b/apps/sensors_test/src/main.c
index 87c08eb..0f270bd 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 997235b..87a449b 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 cb9550d..af16b2b 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 ba2435d..4d5cead 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 0000000..4fdd76e
--- /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 0000000..cac3959
--- /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 0000000..aaf26ad
--- /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 0000000..f8a1f1e
--- /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 0000000..3910c96
--- /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 0000000..d2b6899
--- /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 0000000..42c95de
--- /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 1c6a2ec..d9f4ec0 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 14d3e55..e2ee8d8 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 2d750c8..48954d0 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 9e758e5..fccf1cb 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
--
To stop receiving notification emails like this one, please contact
vipulrahane@apache.org.