You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by je...@apache.org on 2022/02/01 13:29:41 UTC

[mynewt-core] 01/01: hw/sensors: Add driver for BMA400

This is an automated email from the ASF dual-hosted git repository.

jerzy pushed a commit to branch kasjer/bma400
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit 066ffe4e5d4c31415a99f92ec644030ef504dc16
Author: Jerzy Kasenberg <je...@codecoup.pl>
AuthorDate: Tue Feb 1 12:44:42 2022 +0100

    hw/sensors: Add driver for BMA400
---
 hw/drivers/sensors/bma400/include/bma400/bma400.h |  629 ++++++++
 hw/drivers/sensors/bma400/pkg.yml                 |   42 +
 hw/drivers/sensors/bma400/src/bma400.c            | 1741 +++++++++++++++++++++
 hw/drivers/sensors/bma400/src/bma400_priv.h       |  452 ++++++
 hw/drivers/sensors/bma400/src/bma400_shell.c      |  497 ++++++
 hw/drivers/sensors/bma400/syscfg.yml              |   81 +
 6 files changed, 3442 insertions(+)

diff --git a/hw/drivers/sensors/bma400/include/bma400/bma400.h b/hw/drivers/sensors/bma400/include/bma400/bma400.h
new file mode 100755
index 0000000..1de7d3b
--- /dev/null
+++ b/hw/drivers/sensors/bma400/include/bma400/bma400.h
@@ -0,0 +1,629 @@
+/*
+ * 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 __BMA400_H__
+#define __BMA400_H__
+
+#include <os/os.h>
+#include <os/os_dev.h>
+#include <sensor/sensor.h>
+#include <sensor/accel.h>
+#include <sensor/temperature.h>
+#include "../../src/bma400_priv.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bme400_notif_cfg {
+    sensor_event_type_t event;
+    uint8_t int_num;
+    uint16_t notif_src;
+    uint8_t int_cfg;
+};
+
+struct bma400_int_pin_cfg {
+    int16_t int1_host_pin;
+    int16_t int2_host_pin;
+    /* INT1 is active high */
+    uint8_t int1_level : 1;
+    /* INT2 is active high */
+    uint8_t int2_level : 1;
+    /* INT1 is open drain */
+    uint8_t int1_od : 1;
+    /* INT2 is open drain */
+    uint8_t int2_od : 1;
+    /* latching mode */
+    uint8_t latch_int : 1;
+};
+
+/* Range of acceleration measurements */
+typedef enum {
+    BMA400_G_RANGE_2G               = 0,
+    BMA400_G_RANGE_4G               = 1,
+    BMA400_G_RANGE_8G               = 2,
+    BMA400_G_RANGE_16G              = 3,
+} bma400_g_range_t;
+
+/* Power mode for the device */
+typedef enum {
+    BMA400_POWER_MODE_SLEEP         = 0,
+    BMA400_POWER_MODE_LOW           = 1,
+    BMA400_POWER_MODE_NORMAL        = 2,
+} bma400_power_mode_t;
+
+/* Filter 1 bandwidth */
+typedef enum {
+    /* 0.48 x ODR */
+    BMA400_FILT1_BW_0,
+    /* 0.24 x ODR */
+    BMA400_FILT1_BW_1,
+} bma400_filt1_bandwidth_t;
+
+/* Oversampling ration for low power mode */
+typedef enum {
+    /* 0.4 x ODR */
+    BMA400_FILT1_BW_0_4_x_ODR       = 0,
+    /* 0.2 x ODR */
+    BMA400_FILT1_BW_0_2_x_ODR       = 1,
+} bma400_osr_lp_t;
+
+/* Oversampling */
+typedef enum {
+    BMA400_OSR_0  = 0,
+    BMA400_OSR_LOWEST_ACCURACY      = BMA400_OSR_0,
+    BMA400_OSR_LOWEST_POWER         = BMA400_OSR_0,
+    BMA400_OSR_1  = 1,
+    BMA400_OSR_2  = 2,
+    BMA400_OSR_3  = 3,
+    BMA400_OSR_HIGHEST_ACCURACY     = BMA400_OSR_3,
+    BMA400_OSR_HIGHEST_POWER        = BMA400_OSR_3,
+} bma400_oversampling_t;
+
+/* How often acceleration measurements are taken */
+typedef enum {
+    BMA400_ODR_12_5_HZ              = 0x5,
+    BMA400_ODR_25_HZ                = 0x6,
+    BMA400_ODR_50_HZ                = 0x7,
+    BMA400_ODR_100_HZ               = 0x8,
+    BMA400_ODR_200_HZ               = 0x9,
+    BMA400_ODR_400_HZ               = 0xA,
+    BMA400_ODR_800_HZ               = 0xB,
+} bma400_odr_t;
+
+typedef enum {
+    BMA400_TAP_AXIS_Z,
+    BMA400_TAP_AXIS_Y,
+    BMA400_TAP_AXIS_X,
+} bma400_tap_axis_t;
+
+/*
+ * Maximum time between upper and lower peak of a tap, in data samples
+ * this time depends on the mechanics of the device tapped onto
+ */
+typedef enum {
+    BMA400_TAP_TICS_TH_6,
+    BMA400_TAP_TICS_TH_9,
+    BMA400_TAP_TICS_TH_12,
+    BMA400_TAP_TICS_TH_18,
+} bma400_tap_tics_th_t;
+
+/*
+ * Minimum quiet time before and after double tap, in data samples
+ * This time also defines the longest time interval between two taps so that
+ * they are considered as double tap
+ */
+typedef enum {
+    BMA400_TAP_60_SAMPLES,
+    BMA400_TAP_80_SAMPLES,
+    BMA400_TAP_100_SAMPLES,
+    BMA400_TAP_120_SAMPLES,
+} bma400_tap_quite_t;
+
+/*
+ * Minimum time between the two taps of a double tap, in data samples.
+ */
+typedef enum {
+    BMA400_D_TAP_4_SAMPLES,
+    BMA400_D_TAP_8_SAMPLES,
+    BMA400_D_TAP_12_SAMPLES,
+    BMA400_D_TAP_16_SAMPLES,
+} bma400_d_tap_quite_t;
+
+typedef enum {
+    BMA400_TAP_SENSITIVITY_0,
+    BMA400_TAP_SENSITIVITY_HIGHEST = BMA400_TAP_SENSITIVITY_0,
+    BMA400_TAP_SENSITIVITY_1,
+    BMA400_TAP_SENSITIVITY_2,
+    BMA400_TAP_SENSITIVITY_3,
+    BMA400_TAP_SENSITIVITY_4,
+    BMA400_TAP_SENSITIVITY_5,
+    BMA400_TAP_SENSITIVITY_6,
+    BMA400_TAP_SENSITIVITY_7,
+    BMA400_TAP_SENSITIVITY_LOWEST = BMA400_TAP_SENSITIVITY_7,
+} bma400_tap_sensitivity_t;
+
+typedef enum {
+    BMA400_NO_INT_PIN,
+    BMA400_INT1_PIN,
+    BMA400_INT2_PIN,
+} bma400_int_num_t;
+
+/* Settings for the double/single tap interrupt */
+struct bma400_tap_cfg {
+    /* sensitivity of the tap algorith */
+    bma400_tap_sensitivity_t tap_sensitivity;
+
+    bma400_tap_axis_t sel_axis;
+    /*
+     * Maximum time between upper and lower peak of a tap, in data samples
+     * this time depends on the mechanics of the device tapped onto
+     */
+    bma400_tap_tics_th_t tics_th;
+    /*
+     * Minimum quiet time before and after double tap, in data samples
+     * This time also defines the longest time interval between two taps so that
+     * they are considered as double tap
+     */
+    bma400_tap_quite_t quite;
+    /* Minimum time between the two taps of a double tap, in data samples */
+    bma400_d_tap_quite_t quite_dt;
+
+    bma400_int_num_t int_num;
+};
+
+typedef enum {
+    /* 12.5Hz to 800 Hz */
+    BMA400_ACC_FILT1,
+    /* 100Hz */
+    BMA400_ACC_FILT2,
+} bma400_acc_filt_t;
+
+typedef enum {
+    BMA400_ORIENT_REFU_MANUAL,
+    BMA400_ORIENT_REFU_ONE_TIME_2,
+    BMA400_ORIENT_REFU_ONE_TIME_LP,
+} bma400_orient_refu_t;
+
+typedef enum {
+    BMA400_ORIENT_DATA_SRC_FILT2,
+    BMA400_ORIENT_DATA_SRC_FILT_LP,
+} bma400_orient_data_src_t;
+
+typedef enum {
+    /* Variable ODR filter */
+    BMA400_DATA_SRC_FILT1,
+    /* 100 Hz output data rate filter */
+    BMA400_DATA_SRC_FILT2,
+    /* 100 Hz output data rate filter, 1Hz bandwidth */
+    BMA400_DATA_SRC_FILT_LP,
+} bma400_data_src_t;
+
+struct bma400_orient_cfg {
+    uint8_t orient_x_en : 1;
+    uint8_t orient_y_en : 1;
+    uint8_t orient_z_en : 1;
+    /* reference update mode for orientation changed interrupt */
+    bma400_orient_refu_t orient_refu;
+    /* data source selection for orientation changed interrupt evaluation */
+    bma400_orient_data_src_t orient_data_src;
+    /* threshold configuration for orientation changed interrupt 8mg/lsb resolution */
+    uint8_t orient_thres;
+    /* duration for (stable) new orientation before interrupt is triggered
+       duration is a multiple of the number of data samples processed (ODR=100HZ) from
+       the selected filter */
+    uint8_t orient_dur;
+    uint16_t int_orient_refx;
+    uint16_t int_orient_refy;
+    uint16_t int_orient_refz;
+    bma400_int_num_t int_num;
+};
+
+typedef enum {
+    BMA400_ACTIVITY_DATA_SRC_FILT1,
+    BMA400_ACTIVITY_DATA_SRC_FILT2,
+} bma400_activity_data_src_t;
+
+typedef enum {
+    BMA400_ACTIVITY_32_POINTS,
+    BMA400_ACTIVITY_64_POINTS,
+    BMA400_ACTIVITY_128_POINTS,
+    BMA400_ACTIVITY_256_POINTS,
+    BMA400_ACTIVITY_512_POINTS,
+} bma400_activity_data_points_t;
+
+struct bma400_activity_cfg {
+    /* threshold configuration for activity changed interrupt: 8mg/g resolution */
+    uint8_t actch_thres;
+    uint8_t actch_x_en : 1;
+    uint8_t actch_y_en : 1;
+    uint8_t actch_z_en : 1;
+    bma400_activity_data_src_t actch_data_src;
+    /* number of points for evaluation of the activity */
+    bma400_activity_data_points_t actch_npts;
+
+    bma400_int_num_t int_num;
+    /* User selectable event type for activity interrupt */
+    sensor_event_type_t event_type;
+};
+
+/* Array of step counter configuration registers values for wrist (default) */
+extern const uint8_t BMA400_STEP_COUNTER_WRIST_CONFIG[];
+/* Array of step counter configuration registers values for non-wrist application */
+extern const uint8_t BMA400_STEP_COUNTER_NON_WRIST_CONFIG[];
+
+struct bma400_step_cfg {
+    const uint8_t *step_counter_config;
+    bma400_int_num_t int_num;
+};
+
+typedef enum {
+    BMA400_AUTOLOWPOW_TIMEOUT_DISABLE,
+    BMA400_AUTOLOWPOW_TIMEOUT_1,
+    BMA400_AUTOLOWPOW_TIMEOUT_2,
+} bma400_autolowpow_timeout_t;
+
+typedef enum {
+    /* manual update (reference registers are updated by external MCU) */
+    BMA400_WKUP_REFU_MANUAL,
+    /* one time automated update before going into low power mode */
+    BMA400_WKUP_REFU_ONETIME,
+    /* every time after data conversion */
+    BMA400_WKUP_REFU_EVERYTIME,
+} bma400_wkup_refu_t;
+
+struct bma400_autolowpow_cfg {
+    /* auto-low-power timeout threshold */
+    uint8_t timeout_threshold;
+    bma400_autolowpow_timeout_t timeout;
+    /* data ready as source for auto-low-power condition */
+    uint8_t drdy_lowpow_trig : 1;
+    /* wake-up interrupt as source for auto-wake-up condition */
+    uint8_t wkup_int : 1;
+    /* generic interrupt 1 as source for auto-low-power condition */
+    uint8_t trig_gen1 : 1;
+};
+
+struct bma400_wakeup_cfg {
+    /* wake-up timeout threshold */
+    uint8_t timeout_threshold;
+    /* wake-up timeout as source for auto-wake-up condition */
+    bool wkup_timeout;
+    /* wake-up interrupt as source for auto-wake-up condition */
+    bool wkup_int;
+
+    bma400_wkup_refu_t wkup_refu;
+    uint8_t int_wkup_thres;
+    int8_t int_wkup_refx;
+    int8_t int_wkup_refy;
+    int8_t int_wkup_refz;
+    /* enable wake-up interrupt for x channel */
+    bool wkup_x_en;
+    /* enable wake-up interrupt for y channel */
+    bool wkup_y_en;
+    /* enable wake-up interrupt for z channel */
+    bool wkup_z_en;
+    /* number of data samples used for interrupt condition evaluation */
+    uint8_t num_of_samples;
+
+    bma400_int_num_t int_num;
+};
+
+typedef enum {
+    BMA400_HYST_NO_HYST,
+    BMA400_HYST_24mg,
+    BMA400_HYST_48mg,
+    BMA400_HYST_96mg,
+} bma400_gen_act_hyst_t;
+
+typedef enum {
+    BMA400_GEN_ACT_REFU_MANUAL,
+    BMA400_GEN_ACT_REFU_ONETIME,
+    BMA400_GEN_ACT_REFU_EVERYTIME,
+    BMA400_GEN_ACT_REFU_EVERYTIME_LP,
+} bma400_gen_act_refu_t;
+
+typedef enum {
+    BMA400_GEN_DATA_SRC_FILT1,
+    BMA400_GEN_DATA_SRC_FILT2,
+} bma400_gen_data_src_t;
+
+typedef enum {
+    BMA400_GEN_COMB_SEL_OR,
+    BMA400_GEN_COMB_SEL_AND,
+} bma400_gen_comb_sel_t;
+
+typedef enum {
+    BMA400_GEN_CRITERION_INACTIVITY,
+    BMA400_GEN_CRITERION_ACTIVITY,
+} bma400_gen_criterion_sel_t;
+
+typedef enum {
+    BMA400_GEN_INT_1,
+    BMA400_GEN_INT_2,
+} bma400_get_int_t;
+
+struct bma400_gen_int_cfg {
+    bool gen_act_z_en;
+    bool gen_act_y_en;
+    bool gen_act_x_en;
+    bma400_gen_data_src_t gen_data_src;
+    bma400_gen_act_refu_t gen_act_refu;
+    bma400_gen_act_hyst_t gen_act_hyst;
+    bma400_gen_comb_sel_t gen_comb_sel;
+    bma400_gen_criterion_sel_t gen_criterion_sel;
+    uint8_t get_int_thres;
+    uint16_t get_int_dur;
+    uint16_t get_int_th_refx;
+    uint16_t get_int_th_refy;
+    uint16_t get_int_th_refz;
+
+    bma400_int_num_t int_num;
+
+    /* User selectable event type for general interrupt */
+    sensor_event_type_t event_type;
+};
+
+struct bma400_fifo_cfg {
+    uint8_t fifo_z_en : 1;
+    uint8_t fifo_y_en : 1;
+    uint8_t fifo_x_en : 1;
+    uint8_t fifo_8bit_en : 1;
+    uint8_t fifo_time_en : 1;
+    uint8_t fifo_stop_on_full : 1;
+    uint8_t fifo_auto_flush : 1;
+    uint8_t fifo_read_disable : 1;
+
+    uint8_t fifo_data_src : 1;
+    uint16_t watermark;
+
+    bma400_int_num_t int_num;
+};
+
+struct bma400_create_dev_cfg {
+#if MYNEWT_VAL(BUS_DRIVER_PRESENT)
+    bool node_is_spi;
+    union {
+#if MYNEWT_VAL(BMA400_SPI_SUPPORT)
+        struct bus_spi_node_cfg spi_cfg;
+#endif
+#if MYNEWT_VAL(BMA400_I2C_SUPPORT)
+        struct bus_i2c_node_cfg i2c_cfg;
+#endif
+    };
+#else
+    struct sensor_itf itf;
+#endif
+};
+
+/* Default configuration values to use with the device */
+struct bma400_cfg {
+
+    bool stream_read_mode;
+    struct bma400_int_pin_cfg int_pin_cfg;
+
+    /* Accelerometer configuration */
+    bma400_g_range_t g_range;
+    /* Power mode: normal/low power/sleep */
+    bma400_power_mode_t power_mode;
+    /* Data source variable/fixed ODR */
+    bma400_data_src_t data_src;
+    /* Filter bandwitdth */
+    bma400_filt1_bandwidth_t filt1_bw;
+    /* Tap (double & single) event configuration */
+    struct bma400_tap_cfg tap_cfg;
+    /* Orientation detection configuration */
+    struct bma400_orient_cfg orient_cfg;
+    /* Auto low power management configuration */
+    struct bma400_autolowpow_cfg autolowpow_cfg;
+    /* Wakeup configuration */
+    struct bma400_wakeup_cfg wakeup_cfg;
+    /* Fifo configuration */
+    struct bma400_fifo_cfg fifo_cfg;
+    /* Activity detection configuration */
+    struct bma400_activity_cfg activity_cfg;
+    /* Step counter configuration */
+    struct bma400_step_cfg step_cfg;
+    /* General interrupt config */
+    struct bma400_gen_int_cfg gen_int_cfg[2];
+
+    /* Applicable sensor types supported */
+    sensor_type_t sensor_mask;
+};
+
+//struct bma400_init_cfg {
+//
+//    bool stream_read_mode;
+////    int8_t int
+//    struct bma400_int_pin_cfg *int_pin_cfg;
+//
+//    /* Accelerometer configuration */
+//    bma400_g_range_t g_range;
+//    /* Power mode: normal/low power/sleep */
+//    bma400_power_mode_t power_mode;
+//    /* Data source variable/fixed ODR */
+//    bma400_data_src_t data_src;
+//    /* Filter bandwitdth */
+//    bma400_filt1_bandwidth_t filt1_bw;
+//    /* Tap (double & single) event configuration */
+//    struct bma400_tap_cfg *tap_cfg;
+//    /* Orientation detection configuration */
+//    struct bma400_orient_cfg *orient_cfg;
+//    /* Auto low power management configuration */
+//    struct bma400_autolowpow_cfg *autolowpow_cfg;
+//    /* Wakeup configuration */
+//    struct bma400_wakeup_cfg *wakeup_cfg;
+//    /* Fifo configuration */
+//    struct bma400_fifo_cfg *fifo_cfg;
+//    /* Activity detection configuration */
+//    struct bma400_activity_cfg *activity_cfg;
+//    /* Step counter configuration */
+//    struct bma400_step_cfg *step_cfg;
+//    /* General interrupt config */
+//    struct bma400_gen_int_cfg *gen_int_cfg[2];
+//
+//    /* Applicable sensor types supported */
+//    sensor_type_t sensor_mask;
+//};
+
+/* Used to track interrupt state to wake any present waiters */
+struct bma400_int {
+    /* 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[2];
+};
+
+/* Device private data */
+struct bma400_private_driver_data {
+    struct bma400_int *interrupt;
+    struct sensor_notify_ev_ctx notify_ctx;
+    uint8_t registered_mask;
+    sensor_event_type_t allowed_events;
+
+    uint8_t int_num;
+    uint8_t int_ref_cnt;
+
+    /* Shadow copy of registers */
+    struct bma400_reg_cache cache;
+    uint8_t transact;
+
+    /* Active interrupt state */
+    struct bma400_int intr;
+};
+
+/* The device itself */
+struct bma400 {
+#if MYNEWT_VAL(BUS_DRIVER_PRESENT)
+    union {
+        struct bus_i2c_node i2c_node;
+        struct bus_spi_node spi_node;
+    };
+    bool node_is_spi;
+#else
+    /* Underlying OS device */
+    struct os_dev dev;
+#endif
+    /* The sensor infrastructure */
+    struct sensor sensor;
+
+    /* Default configuration values */
+    struct bma400_cfg cfg;
+
+    /* Private driver data */
+    struct bma400_private_driver_data pdd;
+};
+
+/**
+ * Perform a self test of the device and report on its health.
+ *
+ * @param The device object.
+ * @param The result of the self-test: false if passed, true if failed.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int bma400_self_test(struct bma400 *bma400, bool *self_test_fail);
+
+/* Get an accelerometer measurement for a single axis */
+int bma400_get_axis_accel(struct bma400 *bma400,
+                         bma400_axis_t axis,
+                         float *accel_data);
+
+/* Get a temperature measurement */
+int bma400_get_temp(struct bma400 *bma400, float *temp_c);
+
+/* Get the active status of all interrupts */
+int bma400_get_int_status(struct bma400 *bma400,
+                          struct int_status *int_status);
+
+/* Get the size of the FIFO */
+int bma400_get_fifo_count(struct bma400 *bma400, uint16_t *fifo_bytes);
+
+/* Get/Set the accelerometer range */
+int bma400_get_g_range(struct bma400 *bma400, bma400_g_range_t *g_range);
+int bma400_set_g_range(struct bma400 *bma400, bma400_g_range_t g_range);
+
+int bma400_set_filt1_bandwidth(struct bma400 *bma400, bma400_filt1_bandwidth_t bandwidth);
+
+int bma400_set_fifo_cfg(struct bma400 *bma400, struct bma400_fifo_cfg *cfg);
+int bma400_set_orient_cfg(struct bma400 *bma400, struct bma400_orient_cfg *cfg);
+
+int bma400_get_step_counter(struct bma400 *bma400, uint32_t *counter);
+
+int bma400_stream_read(struct sensor *sensor,
+                       sensor_type_t sensor_type,
+                       sensor_data_func_t data_func,
+                       void *read_arg,
+                       uint32_t time_ms);
+
+int bma400_get_accel(struct bma400 *bma400, float accel_data[3]);
+
+/**
+ * Configure the sensor.
+ *
+ * @param bma400 the device object
+ * @param cfg    sensor config
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma400_config(struct bma400 *bma400, struct bma400_cfg *cfg);
+
+/**
+ * Expects to be called back through os_dev_create().
+ *
+ * @param dev the device object associated with this accelerometer
+ * @param argument passed to OS device init
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma400_init(struct os_dev *dev, void *arg);
+
+/**
+ * Create bma400 device
+ *
+ * @param bma400 device object to initialize
+ * @param name   name of the device
+ * @param cfg    device configuration
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int bma400_create_dev(struct bma400 *bma400, const char *name,
+                      const struct bma400_create_dev_cfg *cfg);
+
+#if MYNEWT_VAL(BMA400_CLI)
+/**
+ * Initialize the BMA400 shell extensions.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma400_shell_init(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw/drivers/sensors/bma400/pkg.yml b/hw/drivers/sensors/bma400/pkg.yml
new file mode 100755
index 0000000..adebe92
--- /dev/null
+++ b/hw/drivers/sensors/bma400/pkg.yml
@@ -0,0 +1,42 @@
+#
+# 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/bma400
+pkg.description: Driver for the Bosch BMA400 accelerometer.
+pkg.keywords:
+    - bma400
+    - i2c
+    - spi
+    - sensor
+
+pkg.deps:
+    - "@apache-mynewt-core/kernel/os"
+    - "@apache-mynewt-core/hw/hal"
+    - "@apache-mynewt-core/hw/sensor"
+    - "@apache-mynewt-core/hw/util/i2cn"
+    - "@apache-mynewt-core/sys/log/modlog"
+
+pkg.req_apis:
+    - stats
+
+pkg.deps.BMA400_CLI:
+    - "@apache-mynewt-core/util/parse"
+
+pkg.init.BMA400_CLI:
+    bma400_shell_init: 'MYNEWT_VAL(BMA400_CLI_SYSINIT_STAGE)'
diff --git a/hw/drivers/sensors/bma400/src/bma400.c b/hw/drivers/sensors/bma400/src/bma400.c
new file mode 100755
index 0000000..f7656a4
--- /dev/null
+++ b/hw/drivers/sensors/bma400/src/bma400.c
@@ -0,0 +1,1741 @@
+/*
+ * 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 <assert.h>
+#include <string.h>
+
+#include <os/mynewt.h>
+#include <hal/hal_gpio.h>
+#include <modlog/modlog.h>
+#include <stats/stats.h>
+#include "defs/error.h"
+#include "bma400/bma400.h"
+#include "bma400_priv.h"
+#if MYNEWT_VAL(BUS_DRIVER_PRESENT)
+#include <bus/drivers/i2c_common.h>
+#include <bus/drivers/spi_common.h>
+#else /* BUS_DRIVER_PRESENT */
+#include <hal/hal_spi.h>
+#include <hal/hal_i2c.h>
+#include <i2cn/i2cn.h>
+#endif /* BUS_DRIVER_PRESENT */
+
+#define BMA400_NOTIFY_MASK  0x01
+#define BMA400_READ_MASK    0x02
+
+#define GET_FIELD(reg_val, field_mask) \
+        (((reg_val) & (field_mask)) >> __builtin_ctz(field_mask))
+#define SET_FIELD(field_val, field_mask)   \
+        (((field_val) << __builtin_ctz(field_mask)) & (field_mask))
+
+#define BMA400_FIELD_VAL(field_name, reg_val) (((reg_val) & (BMA400_ ## field_name)) >> __builtin_ctz(BMA400_ ## field_name))
+
+const uint8_t BMA400_STEP_COUNTER_WRIST_CONFIG[] = {
+    1, 45, 123, 212, 68, 1, 59, 122, 219, 123, 63, 108, 205, 39, 25, 150, 160, 195, 14, 12, 60, 240, 0, 247
+};
+
+const uint8_t BMA400_STEP_COUNTER_NON_WRIST_CONFIG[] = {
+    1, 50, 120, 230, 135, 0, 132, 108, 156, 117, 100, 126, 170, 12, 12, 74, 160, 0, 0, 12, 60, 240, 1, 0
+};
+
+#pragma GCC optimize ("Og")
+
+static void
+delay_msec(uint32_t delay)
+{
+    delay = (delay * OS_TICKS_PER_SEC) / 1000 + 1;
+    os_time_delay(delay);
+}
+
+#if MYNEWT_VAL(BMA400_INT_ENABLE)
+static void
+init_interrupt(struct bma400_int *interrupt)
+{
+    os_error_t error;
+
+    interrupt->ints[0].host_pin = -1;
+    interrupt->ints[1].host_pin = -1;
+
+    error = os_sem_init(&interrupt->wait, 0);
+    assert(error == OS_OK);
+}
+
+static void
+undo_interrupt(struct bma400_int *interrupt)
+{
+    (void)os_sem_pend(&interrupt->wait, 0);
+}
+
+static void
+wait_interrupt(struct bma400_int *interrupt)
+{
+    os_error_t error;
+
+    error = os_sem_pend(&interrupt->wait, OS_WAIT_FOREVER);
+    assert(error == OS_OK);
+}
+
+static void
+wake_interrupt(struct bma400_int *interrupt)
+{
+    os_error_t error;
+
+    if (os_sem_get_count(&interrupt->wait) == 0) {
+        error = os_sem_release(&interrupt->wait);
+        assert(error == OS_OK);
+    }
+}
+
+static void
+bma400_interrupt_handler(void *arg)
+{
+    struct bma400 *bma400 = arg;
+
+    if (bma400->pdd.interrupt) {
+        wake_interrupt(bma400->pdd.interrupt);
+    }
+
+    sensor_mgr_put_interrupt_evt(&bma400->sensor);
+}
+#endif
+
+#if !MYNEWT_VAL(BUS_DRIVER_PRESENT)
+/**
+ * Read number of data byte from BMA400 sensor over I2C
+ *
+ * @param bma400 The device
+ * @param reg    register address
+ * @param buffer data buffer
+ * @param len    number of bytes to read
+ *
+ * @return 0 on success, non-zero on failure
+ */
+static int
+bma400_i2c_read(struct bma400 *bma400, uint8_t reg,
+                uint8_t *buffer, uint8_t len)
+{
+    int rc;
+    struct hal_i2c_master_data data_struct = {
+        .address = bma400->sensor.s_itf.si_addr,
+        .len = 1,
+        .buffer = &reg
+    };
+
+    /* First byte is register address */
+    rc = i2cn_master_write(bma400->sensor.s_itf.si_num,
+                           &data_struct, MYNEWT_VAL(BMA400_I2C_TIMEOUT_TICKS),
+                           1,
+                           MYNEWT_VAL(BMA400_I2C_TIMEOUT_TICKS));
+    if (rc) {
+        BMA400_LOG_ERROR("I2C access failed at address 0x%02X\n",
+                         data_struct.address);
+        STATS_INC(g_bma400_stats, read_errors);
+        goto end;
+    }
+
+    data_struct.buffer = buffer;
+    data_struct.len = len;
+
+    /* Read data from register(s) */
+    rc = i2cn_master_read(bma400->sensor.s_itf.si_num, &data_struct,
+                          MYNEWT_VAL(BMA400_I2C_TIMEOUT_TICKS), len,
+                          MYNEWT_VAL(BMA400_I2C_RETRIES));
+    if (rc) {
+        BMA400_LOG_ERROR("Failed to read from 0x%02X:0x%02X\n",
+                         data_struct.address, reg);
+        STATS_INC(g_bma400_stats, read_errors);
+    }
+
+end:
+
+    return rc;
+}
+
+/**
+ * Read number of data bytes from BMA400 sensor over SPI
+ *
+ * @param bma400 The device
+ * @param reg    register address
+ * @param buffer buffer for register data
+ * @param len    number of bytes to read
+ *
+ * @return 0 on success, non-zero on failure
+ */
+static int
+bma400_spi_read(struct bma400 *bma400, uint8_t reg,
+                uint8_t *buffer, uint8_t len)
+{
+    int i;
+    uint16_t retval;
+    int rc = 0;
+
+    /* Select the device */
+    hal_gpio_write(bma400->sensor.s_itf.si_cs_pin, 0);
+
+    /* Send the address */
+    retval = hal_spi_tx_val(bma400->sensor.s_itf.si_num, BMA400_SPI_READ_CMD_BIT(reg));
+    if (retval == 0xFFFF) {
+        rc = SYS_EINVAL;
+        BMA400_LOG_ERROR("SPI_%u register write failed addr:0x%02X\n",
+                         bma400->sensor.s_itf.si_num, reg);
+        STATS_INC(g_bma400_stats, read_errors);
+        goto end;
+    }
+    /* Dummy byte */
+    retval = hal_spi_tx_val(bma400->sensor.s_itf.si_num, 0xFF);
+
+    for (i = 0; i < len; i++) {
+        /* Read data */
+        retval = hal_spi_tx_val(bma400->sensor.s_itf.si_num, 0xFF);
+        if (retval == 0xFFFF) {
+            rc = SYS_EINVAL;
+            BMA400_LOG_ERROR("SPI_%u read failed addr:0x%02X\n",
+                             bma400->sensor.s_itf.si_num, reg);
+            STATS_INC(g_bma400_stats, read_errors);
+            goto end;
+        }
+        buffer[i] = retval;
+    }
+
+end:
+    /* De-select the device */
+    hal_gpio_write(bma400->sensor.s_itf.si_cs_pin, 1);
+
+    return rc;
+}
+
+/**
+ * Write number of bytes to BMA400 sensor over I2C
+ *
+ * @param bma400 The device
+ * @param buffer data buffer (reg1,val1,reg2,val2...)
+ * @param len    number of bytes to write
+ *
+ * @return 0 on success, non-zero on failure
+ */
+static int
+bma400_i2c_write(struct bma400 *bma400, const uint8_t *buffer, uint8_t len)
+{
+    int i, j;
+    int rc = 0;
+    struct hal_i2c_master_data data_struct = {
+        .address = bma400->sensor.s_itf.si_addr,
+        .len = len,
+        .buffer = (uint8_t)buffer
+    };
+    rc = i2cn_master_write(bma400->sensor.s_itf.si_num, &data_struct,
+                           MYNEWT_VAL(BMA400_I2C_TIMEOUT_TICKS), 1,
+                           MYNEWT_VAL(BMA400_I2C_RETRIES));
+    if (rc) {
+        BMA400_LOG_ERROR("I2C access failed at address 0x%02X\n",
+                         data_struct.address);
+        STATS_INC(g_bma400_stats, write_errors);
+        break;
+    }
+
+    return rc;
+}
+
+/**
+ * Write number of bytes to BMA400 sensor over SPI
+ *
+ * @param bma400 The device
+ * @param buffer data buffer (reg1,val1,reg2,val2...)
+ * @param len    number of bytes to write
+ *
+ * @return 0 on success, non-zero on failure
+ */
+static int
+bma400_spi_write(struct bma400 *bma400, uint8_t reg,
+                 const uint8_t *buffer, uint8_t len)
+{
+    int i;
+    int rc = 0;
+
+    /* Select the device */
+    hal_gpio_write(bma400->sensor.s_itf.si_cs_pin, 0);
+
+    for (i = 0; i < len; i++) {
+        rc = hal_spi_tx_val(bma400->sensor.s_itf.si_num, buffer[i]);
+        if (rc == 0xFFFF) {
+            rc = SYS_EINVAL;
+            BMA400_LOG_ERROR("SPI_%u write failed addr:0x%02X\n",
+                             bma400->sensor.s_itf.si_num, reg);
+            STATS_INC(g_bma400_stats, write_errors);
+            goto end;
+        }
+    }
+
+end:
+    /* De-select the device */
+    hal_gpio_write(bma400->sensor.s_itf.si_cs_pin, 1);
+
+    return rc;
+}
+#endif /* BUS_DRIVER_PRESENT */
+
+int
+bma400_write(struct bma400 *bma400, uint8_t reg,
+             const uint8_t *buffer, uint8_t len)
+{
+    int rc = 0;
+    int i, j;
+    uint8_t write_data[32];
+
+    for (i = 0, j = 0; rc == 0 && i < len; ++reg) {
+        write_data[j++] = reg;
+        write_data[j++] = buffer[i++];
+        if (j >= sizeof(write_data) || i >= len) {
+#if MYNEWT_VAL(BUS_DRIVER_PRESENT)
+            rc = bus_node_simple_write((struct os_dev *)bma400, &write_data, j);
+        }
+#else /* BUS_DRIVER_PRESENT */
+        rc = sensor_itf_lock(&bma400->sensor.s_itf, MYNEWT_VAL(BMA400_ITF_LOCK_TMO));
+        if (rc) {
+            break;
+        }
+
+        if (bma400->sensor.s_itf.si_type == SENSOR_ITF_I2C) {
+            rc = bma400_i2c_write(bma400, reg, write_data, j);
+        } else {
+            rc = bma400_spi_write(bma400, reg, write_data, j);
+        }
+
+        sensor_itf_unlock(&bma400->sensor.s_itf);
+#endif /* BUS_DRIVER_PRESENT */
+    }
+    return rc;
+}
+
+int
+bma400_read(struct bma400 *bma400, uint8_t reg,
+            uint8_t *buffer, uint8_t len)
+{
+    int rc;
+
+#if MYNEWT_VAL(BUS_DRIVER_PRESENT)
+    uint8_t reg_and_dummy[2] = { reg, 0 };
+
+    if (bma400->node_is_spi) {
+        BMA400_SPI_READ_CMD_BIT(reg);
+    }
+
+    rc = bus_node_simple_write_read_transact((struct os_dev *)bma400, reg_and_dummy, bma400->node_is_spi ? 2 : 1,
+                                             buffer, len);
+#else /* BUS_DRIVER_PRESENT */
+    rc = sensor_itf_lock(&bma400->sensor.s_itf, MYNEWT_VAL(BMA400_ITF_LOCK_TMO));
+    if (rc) {
+        goto end;
+    }
+
+    if (bma400->sensor.s_itf.si_type == SENSOR_ITF_I2C) {
+        rc = bma400_i2c_read(bma400, reg, buffer, len);
+    } else {
+        rc = bma400_spi_read(bma400, reg, buffer, len);
+    }
+
+    sensor_itf_unlock(&bma400->sensor.s_itf);
+end:
+#endif /* BUS_DRIVER_PRESENT */
+
+    return rc;
+}
+
+int
+bma400_get_register(struct bma400 *bma400, uint8_t reg, uint8_t *data)
+{
+    int rc;
+
+    if (reg >= BMA400_REG_ACC_CONFIG0 && reg <= BMA400_REG_TAP_CONFIG1) {
+        *data = bma400->pdd.cache.regs[reg - BMA400_REG_ACC_CONFIG0];
+        rc = 0;
+    } else {
+        rc = bma400_read(bma400, reg, data, 1);
+    }
+
+    return rc;
+}
+
+int
+bma400_set_register(struct bma400 *bma400, uint8_t reg, uint8_t data)
+{
+    int rc = 0;
+    int ix;
+    bool write_back;
+
+    if (reg >= BMA400_REG_ACC_CONFIG0 && reg <= BMA400_REG_TAP_CONFIG1) {
+        ix = reg - BMA400_REG_ACC_CONFIG0;
+    } else {
+        ix = -1;
+        write_back = true;
+    }
+
+    if (ix >= 0) {
+        write_back = bma400->pdd.cache.regs[ix] != data;
+        bma400->pdd.cache.regs[ix] = data;
+        if (write_back && bma400->pdd.transact) {
+            bma400->pdd.cache.dirty |= 1ULL << ix;
+            write_back = false;
+        }
+    }
+
+    if (write_back) {
+        rc = bma400_write(bma400, reg, &data, 1);
+        if (rc == 0 && ix >= 0) {
+            bma400->pdd.cache.dirty &= ~(1ULL << ix);
+        }
+    }
+
+    return rc;
+}
+
+static void
+bma400_begin_transact(struct bma400 *bma400)
+{
+    bma400->pdd.transact++;
+}
+
+static int
+bma400_commit(struct bma400 *bma400)
+{
+    int rc = 0;
+    int first_dirty = 0;
+    int clean_count;
+    int dirty_count;
+    uint64_t dirty_mask;
+
+    dirty_mask = bma400->pdd.cache.dirty;
+    if (--bma400->pdd.transact == 0) {
+        while (rc == 0 && dirty_mask) {
+            clean_count = __builtin_ctzll(dirty_mask);
+            dirty_mask >>= clean_count;
+            dirty_mask ^= ~0;
+            dirty_count = __builtin_ctzll(dirty_mask);
+            dirty_mask ^= ~0;
+            dirty_mask >>= dirty_count;
+            first_dirty += clean_count;
+            rc = bma400_write(bma400, first_dirty + BMA400_REG_ACC_CONFIG0,
+                              bma400->pdd.cache.regs + first_dirty, dirty_count);
+            if (rc == 0) {
+                bma400->pdd.cache.dirty = dirty_mask << (first_dirty + dirty_count);
+            }
+            first_dirty += dirty_count;
+        }
+    }
+
+    return rc;
+}
+
+static int
+bma400_set_register_field(struct bma400 *bma400, uint8_t reg,
+                          uint8_t field_mask, uint8_t field_val)
+{
+    int rc;
+
+    uint8_t new_data;
+    uint8_t old_data;
+
+    rc = bma400_get_register(bma400, reg, &old_data);
+    if (rc) {
+        goto end;
+    }
+
+    new_data = ((old_data & (~field_mask)) | SET_FIELD(field_val, field_mask));
+
+    /* Try to limit bus access if possible */
+    if (new_data != old_data) {
+        rc = bma400_set_register(bma400, reg, new_data);
+    }
+end:
+    return rc;
+}
+
+static int
+bma400_get_register_field(struct bma400 *bma400, uint8_t reg,
+                          uint8_t field_mask, uint8_t *field_val)
+{
+    int rc;
+    uint8_t reg_val;
+
+    rc = bma400_get_register(bma400, reg, &reg_val);
+    if (rc) {
+        goto end;
+    }
+
+    *field_val = GET_FIELD(reg_val, field_mask);
+
+end:
+    return rc;
+}
+
+int
+bma400_get_chip_id(struct bma400 *bma400, uint8_t *chip_id)
+{
+    return bma400_get_register(bma400, BMA400_REG_CHIPID, chip_id);
+}
+
+static const float range_mult_arr[] = {
+    2 * STANDARD_ACCEL_GRAVITY / 32768,
+    4 * STANDARD_ACCEL_GRAVITY / 32768,
+    8 * STANDARD_ACCEL_GRAVITY / 32768,
+    16 * STANDARD_ACCEL_GRAVITY / 32768,
+};
+
+static float
+range_mult(struct bma400 *bma400)
+{
+    return range_mult_arr[GET_FIELD(bma400->pdd.cache.acc_config1, BMA400_ACC_CONFIG1_ACC_RANGE)];
+}
+
+static void
+compute_accel_data(struct bma400 *bma400, int16_t raw_accel, float *accel_data)
+{
+    *accel_data = raw_accel * range_mult(bma400);
+}
+
+int
+bma400_get_axis_accel(struct bma400 *bma400, bma400_axis_t axis, float *accel_data)
+{
+    uint8_t base_addr;
+    uint8_t data[2];
+    int rc = 0;
+
+    switch (axis) {
+    case AXIS_X:
+        base_addr = BMA400_REG_ACC_X_LSB;
+        break;
+    case AXIS_Y:
+        base_addr = BMA400_REG_ACC_Y_LSB;
+        break;
+    case AXIS_Z:
+        base_addr = BMA400_REG_ACC_Z_LSB;
+        break;
+    default:
+        rc = SYS_EINVAL;
+    }
+
+    if (rc == 0) {
+        rc = bma400_read(bma400, base_addr, data, sizeof(data));
+    }
+    if (rc == 0) {
+        compute_accel_data(bma400, ((int16_t)data[1] << 12) | (((int16_t)data[0]) << 4), accel_data);
+    }
+
+    return rc;
+}
+
+int
+bma400_get_accel(struct bma400 *bma400, float accel_data[3])
+{
+    uint8_t data[6];
+    int rc;
+
+    rc = bma400_read(bma400, BMA400_REG_ACC_X_LSB, data, sizeof(data));
+    if (rc == 0) {
+        compute_accel_data(bma400, ((int16_t)data[1] << 12) | (((int16_t)data[0]) << 4), &accel_data[0]);
+        compute_accel_data(bma400, ((int16_t)data[3] << 12) | (((int16_t)data[2]) << 4), &accel_data[1]);
+        compute_accel_data(bma400, ((int16_t)data[5] << 12) | (((int16_t)data[4]) << 4), &accel_data[2]);
+    }
+
+    return rc;
+}
+
+int
+bma400_get_temp(struct bma400 *bma400, float *temp_c)
+{
+    int8_t data;
+    int rc;
+
+    rc = bma400_get_register(bma400, BMA400_REG_TEMP_DATA, (uint8_t *)&data);
+    if (rc == 0) {
+        *temp_c = data * 0.5f + 23.0f;
+    }
+
+    return rc;
+}
+
+int
+bma400_get_int_status(struct bma400 *bma400,
+                      struct int_status *int_status)
+{
+    int rc;
+
+    rc = bma400_read(bma400, BMA400_REG_INT_STAT0, &int_status->int_stat0, sizeof(*int_status));
+
+    return rc;
+}
+
+int
+bma400_get_fifo_count(struct bma400 *bma400, uint16_t *fifo_bytes)
+{
+    uint8_t data[2];
+    int rc;
+
+    rc = bma400_read(bma400, BMA400_REG_FIFO_LENGTH0, data, 2);
+    if (rc == 0) {
+        *fifo_bytes = data[0] | ((data[1] & 0x07) << 8);
+    }
+    return rc;
+}
+
+int
+bma400_get_g_range(struct bma400 *bma400,
+                   bma400_g_range_t *g_range)
+{
+    uint8_t field_val;
+    int rc;
+
+    rc = bma400_get_register_field(bma400, BMA400_REG_ACC_CONFIG1, BMA400_ACC_CONFIG1_ACC_RANGE, &field_val);
+    if (rc != 0) {
+        *g_range = (bma400_g_range_t)field_val;
+    }
+
+    return rc;
+}
+
+int
+bma400_set_g_range(struct bma400 *bma400,
+                   bma400_g_range_t g_range)
+{
+    return bma400_set_register_field(bma400, BMA400_REG_ACC_CONFIG1, BMA400_ACC_CONFIG1_ACC_RANGE, (uint8_t)g_range);
+}
+
+int
+bma400_set_filt1_bandwidth(struct bma400 *bma400, bma400_filt1_bandwidth_t bandwidth)
+{
+    return bma400_set_register_field(bma400, BMA400_REG_ACC_CONFIG0, BMA400_ACC_CONFIG0_FILT1_BW, (uint8_t)bandwidth);
+}
+
+int
+bma400_set_power_mode(struct bma400 *bma400, bma400_power_mode_t power_mode)
+{
+    return bma400_set_register_field(bma400, BMA400_REG_ACC_CONFIG0, BMA400_ACC_CONFIG0_POWER_MODE_CONF,
+                                     (uint8_t)power_mode);
+}
+
+int
+bma400_get_power_mode(struct bma400 *bma400, bma400_power_mode_t *power_mode)
+{
+    return bma400_get_register_field(bma400, BMA400_REG_ACC_CONFIG0, BMA400_ACC_CONFIG0_POWER_MODE_CONF,
+                                     (uint8_t *)power_mode);
+}
+
+int
+bma400_set_odr(struct bma400 *bma400, bma400_odr_t odr)
+{
+    return bma400_set_register_field(bma400, BMA400_REG_ACC_CONFIG1, BMA400_ACC_CONFIG1_ACC_ODR, (uint8_t)odr);
+}
+
+int
+bma400_set_data_src(struct bma400 *bma400, bma400_data_src_t src)
+{
+    return bma400_set_register_field(bma400, BMA400_REG_ACC_CONFIG2, BMA400_ACC_CONFIG2_DATA_SRC_REG, (uint8_t)src);
+}
+
+int
+bma400_set_int12_cfg(struct bma400 *bma400, struct bma400_int_pin_cfg *cfg)
+{
+    hal_gpio_irq_trig_t trig;
+
+    if (cfg->int1_host_pin != bma400->pdd.intr.ints[0].host_pin) {
+        if (bma400->pdd.intr.ints[0].host_pin >= 0) {
+            hal_gpio_irq_release(bma400->pdd.intr.ints[0].host_pin);
+        }
+        if (bma400->pdd.intr.ints[0].host_pin >= 0) {
+            trig = cfg->int1_level ? HAL_GPIO_TRIG_RISING : HAL_GPIO_TRIG_FALLING;
+            bma400->pdd.intr.ints[0].host_pin = cfg->int1_host_pin;
+            bma400->pdd.intr.ints[0].active = cfg->int1_level;
+            hal_gpio_irq_init(cfg->int1_host_pin,
+                              bma400_interrupt_handler,
+                              bma400, trig, HAL_GPIO_PULL_NONE);
+        }
+    }
+    if (cfg->int2_host_pin != bma400->pdd.intr.ints[1].host_pin) {
+        if (bma400->pdd.intr.ints[1].host_pin >= 0) {
+            hal_gpio_irq_release(bma400->pdd.intr.ints[1].host_pin);
+        }
+        if (bma400->pdd.intr.ints[1].host_pin >= 0) {
+            trig = cfg->int1_level ? HAL_GPIO_TRIG_RISING : HAL_GPIO_TRIG_FALLING;
+            bma400->pdd.intr.ints[1].host_pin = cfg->int2_host_pin;
+            bma400->pdd.intr.ints[1].active = cfg->int2_level;
+            hal_gpio_irq_init(cfg->int2_host_pin,
+                              bma400_interrupt_handler,
+                              bma400, trig, HAL_GPIO_PULL_NONE);
+        }
+    }
+
+    bma400_begin_transact(bma400);
+
+    bma400_set_register_field(bma400, BMA400_REG_INT12_IO_CTRL, BMA400_INT12_IO_CTRL_INT1_LVL, cfg->int1_level);
+    bma400_set_register_field(bma400, BMA400_REG_INT12_IO_CTRL, BMA400_INT12_IO_CTRL_INT2_LVL, cfg->int2_level);
+    bma400_set_register_field(bma400, BMA400_REG_INT12_IO_CTRL, BMA400_INT12_IO_CTRL_INT1_OD, cfg->int1_od);
+    bma400_set_register_field(bma400, BMA400_REG_INT12_IO_CTRL, BMA400_INT12_IO_CTRL_INT2_OD, cfg->int2_od);
+    bma400_set_register_field(bma400, BMA400_REG_INT_CONFIG1, BMA400_INT_CONFIG1_LATCH_INT, cfg->latch_int);
+
+    return bma400_commit(bma400);
+}
+
+int
+bma400_set_activity_cfg(struct bma400 *bma400, struct bma400_activity_cfg *cfg)
+{
+    bma400_begin_transact(bma400);
+
+    bma400_set_register(bma400, BMA400_REG_ACTCH_CONFIG0, cfg->actch_thres);
+    bma400_set_register_field(bma400, BMA400_REG_ACTCH_CONFIG1, BMA400_ACTCH_CONFIG1_ACTCH_X_EN, cfg->actch_x_en);
+    bma400_set_register_field(bma400, BMA400_REG_ACTCH_CONFIG1, BMA400_ACTCH_CONFIG1_ACTCH_Y_EN, cfg->actch_y_en);
+    bma400_set_register_field(bma400, BMA400_REG_ACTCH_CONFIG1, BMA400_ACTCH_CONFIG1_ACTCH_Z_EN, cfg->actch_z_en);
+    bma400_set_register_field(bma400, BMA400_REG_ACTCH_CONFIG1, BMA400_ACTCH_CONFIG1_ACTCH_NPTS, cfg->actch_npts);
+
+    bma400_set_register_field(bma400, BMA400_REG_INT12_MAP, BMA400_INT12_MAP_ACTCH_INT1,
+                              cfg->int_num == BMA400_INT1_PIN);
+    bma400_set_register_field(bma400, BMA400_REG_INT12_MAP, BMA400_INT12_MAP_ACTCH_INT2,
+                              cfg->int_num == BMA400_INT2_PIN);
+
+    if (cfg->int_num != BMA400_NO_INT_PIN) {
+        bma400->pdd.allowed_events |= cfg->event_type;
+    } else {
+        bma400->pdd.allowed_events &= ~cfg->event_type;
+    }
+
+    return bma400_commit(bma400);
+}
+
+int
+bma400_set_step_counter_cfg(struct bma400 *bma400, struct bma400_step_cfg *cfg)
+{
+    int rc = 0;
+
+    if (cfg->step_counter_config) {
+        rc = bma400_write(bma400, BMA400_REG_STEP_COUNTER_CONFIG0, cfg->step_counter_config, 24);
+    }
+
+    if (rc == 0) {
+        bma400_begin_transact(bma400);
+
+        bma400_set_register_field(bma400, BMA400_REG_INT12_MAP, BMA400_INT12_MAP_STEP_INT1,
+                                  cfg->int_num == BMA400_INT1_PIN);
+        bma400_set_register_field(bma400, BMA400_REG_INT12_MAP, BMA400_INT12_MAP_STEP_INT2,
+                                  cfg->int_num == BMA400_INT2_PIN);
+
+        rc = bma400_commit(bma400);
+    }
+    return rc;
+}
+
+int
+bma400_get_step_counter(struct bma400 *bma400, uint32_t *counter)
+{
+    int rc;
+    uint8_t data[3];
+
+    rc = bma400_read(bma400, BMA400_REG_STEP_CNT_0, data, 3);
+    if (rc == 0) {
+        *counter = data[0] + (data[1] << 8) + (data[2] << 16);
+    }
+
+    return rc;
+}
+
+int
+bma400_set_autolowpow_mode(struct bma400 *bma400, struct bma400_autolowpow_cfg *cfg)
+{
+    bma400_begin_transact(bma400);
+
+    bma400_set_register(bma400, BMA400_REG_AUTOLOWPOW_0, cfg->timeout_threshold >> 4);
+    bma400_set_register_field(bma400, BMA400_REG_AUTOLOWPOW_1, BMA400_AUTOLOWPOW_1_AUTO_LP_TIMEOUT_THRES, cfg->timeout_threshold & 15);
+    bma400_set_register_field(bma400, BMA400_REG_AUTOLOWPOW_1, BMA400_AUTOLOWPOW_1_AUTO_LP_TIMEOUT, cfg->timeout);
+    bma400_set_register_field(bma400, BMA400_REG_AUTOLOWPOW_1, BMA400_AUTOLOWPOW_1_GEN1_INT, cfg->trig_gen1);
+    bma400_set_register_field(bma400, BMA400_REG_AUTOLOWPOW_1, BMA400_AUTOLOWPOW_1_DRDY_LOWPOW_TRIG, cfg->drdy_lowpow_trig);
+
+    return bma400_commit(bma400);
+}
+
+int
+bma400_set_wakeup(struct bma400 *bma400, struct bma400_wakeup_cfg *cfg)
+{
+    bma400_begin_transact(bma400);
+
+    bma400_set_register(bma400, BMA400_REG_AUTOWAKEUP_0, cfg->timeout_threshold >> 4);
+    bma400_set_register_field(bma400, BMA400_REG_AUTOWAKEUP_1, BMA400_AUTOWAKEUP_1_WAKEUP_TIMEOUT_THRES, cfg->timeout_threshold & 15);
+    bma400_set_register_field(bma400, BMA400_REG_AUTOWAKEUP_1, BMA400_AUTOWAKEUP_1_WKUP_TIMEOUT, cfg->wkup_timeout);
+    bma400_set_register_field(bma400, BMA400_REG_AUTOLOWPOW_1, BMA400_AUTOWAKEUP_1_WKUP_INT, cfg->wkup_int);
+
+    bma400_set_register_field(bma400, BMA400_REG_WKUP_INT_CONFIG0, BMA400_WKUP_INT_CONFIG0_WKUP_Z_EN, cfg->wkup_z_en);
+    bma400_set_register_field(bma400, BMA400_REG_WKUP_INT_CONFIG0, BMA400_WKUP_INT_CONFIG0_WKUP_Y_EN, cfg->wkup_y_en);
+    bma400_set_register_field(bma400, BMA400_REG_WKUP_INT_CONFIG0, BMA400_WKUP_INT_CONFIG0_WKUP_X_EN, cfg->wkup_x_en);
+    bma400_set_register_field(bma400, BMA400_REG_WKUP_INT_CONFIG0, BMA400_WKUP_INT_CONFIG0_NUM_OF_SAMPLES, cfg->num_of_samples);
+    bma400_set_register_field(bma400, BMA400_REG_WKUP_INT_CONFIG0, BMA400_WKUP_INT_CONFIG0_WKUP_REFU, cfg->wkup_refu);
+
+    bma400_set_register(bma400, BMA400_REG_WKUP_INT_CONFIG1, cfg->int_wkup_thres);
+    bma400_set_register(bma400, BMA400_REG_WKUP_INT_CONFIG2, cfg->int_wkup_refx);
+    bma400_set_register(bma400, BMA400_REG_WKUP_INT_CONFIG3, cfg->int_wkup_refy);
+    bma400_set_register(bma400, BMA400_REG_WKUP_INT_CONFIG4, cfg->int_wkup_refz);
+
+    bma400_set_register_field(bma400, BMA400_REG_INT1_MAP, BMA400_INT1_MAP_WKUP_INT1, cfg->int_num == BMA400_INT1_PIN);
+    bma400_set_register_field(bma400, BMA400_REG_INT2_MAP, BMA400_INT2_MAP_WKUP_INT2, cfg->int_num == BMA400_INT2_PIN);
+
+    return bma400_commit(bma400);
+}
+
+int
+bma400_set_gen_int(struct bma400 *bma400, bma400_get_int_t gen_int, struct bma400_gen_int_cfg *cfg)
+{
+    uint8_t gen_int_off = gen_int * (BMA400_REG_GEN2INT_CONFIG0 - BMA400_REG_GEN1INT_CONFIG0);
+    bma400_begin_transact(bma400);
+
+    bma400_set_register_field(bma400, BMA400_REG_GEN1INT_CONFIG0 + gen_int_off, BMA400_GEN1INT_CONFIG_0_GEN1_ACT_Z_EN, cfg->gen_act_z_en);
+    bma400_set_register_field(bma400, BMA400_REG_GEN1INT_CONFIG0 + gen_int_off, BMA400_GEN1INT_CONFIG_0_GEN1_ACT_Y_EN, cfg->gen_act_y_en);
+    bma400_set_register_field(bma400, BMA400_REG_GEN1INT_CONFIG0 + gen_int_off, BMA400_GEN1INT_CONFIG_0_GEN1_ACT_X_EN, cfg->gen_act_x_en);
+    bma400_set_register_field(bma400, BMA400_REG_GEN1INT_CONFIG0 + gen_int_off, BMA400_GEN1INT_CONFIG_0_GEN1_DATA_SRC, cfg->gen_data_src);
+    bma400_set_register_field(bma400, BMA400_REG_GEN1INT_CONFIG0 + gen_int_off, BMA400_GEN1INT_CONFIG_0_GEN1_ACT_REFU, cfg->gen_act_refu);
+    bma400_set_register_field(bma400, BMA400_REG_GEN1INT_CONFIG0 + gen_int_off, BMA400_GEN1INT_CONFIG_0_GEN1_ACT_HYST, cfg->gen_act_hyst);
+    bma400_set_register_field(bma400, BMA400_REG_GEN1INT_CONFIG1 + gen_int_off, BMA400_GEN1INT_CONFIG_1_GEN1_CRITERION_SEL, cfg->gen_criterion_sel);
+    bma400_set_register_field(bma400, BMA400_REG_GEN1INT_CONFIG1 + gen_int_off, BMA400_GEN1INT_CONFIG_1_GEN1_COMB_SEL, cfg->gen_comb_sel);
+
+    bma400_set_register(bma400, BMA400_REG_GEN1INT_CONFIG2 + gen_int_off, cfg->get_int_thres);
+    bma400_set_register(bma400, BMA400_REG_GEN1INT_CONFIG3 + gen_int_off, cfg->get_int_dur >> 8);
+    bma400_set_register(bma400, BMA400_REG_GEN1INT_CONFIG31 + gen_int_off, (uint8_t)cfg->get_int_dur);
+    bma400_set_register(bma400, BMA400_REG_GEN1INT_CONFIG4 + gen_int_off, (uint8_t)cfg->get_int_th_refx);
+    bma400_set_register(bma400, BMA400_REG_GEN1INT_CONFIG5 + gen_int_off, cfg->get_int_th_refx >> 8);
+    bma400_set_register(bma400, BMA400_REG_GEN1INT_CONFIG6 + gen_int_off, (uint8_t)cfg->get_int_th_refy);
+    bma400_set_register(bma400, BMA400_REG_GEN1INT_CONFIG7 + gen_int_off, cfg->get_int_th_refy >> 8);
+    bma400_set_register(bma400, BMA400_REG_GEN1INT_CONFIG8 + gen_int_off, (uint8_t)cfg->get_int_th_refz);
+    bma400_set_register(bma400, BMA400_REG_GEN1INT_CONFIG9 + gen_int_off, cfg->get_int_th_refz >> 8);
+
+    if (gen_int == BMA400_GEN_INT_1) {
+        bma400_set_register_field(bma400, BMA400_REG_INT1_MAP, BMA400_INT1_MAP_GEN1_INT1,
+                                  cfg->int_num == BMA400_INT1_PIN);
+        bma400_set_register_field(bma400, BMA400_REG_INT2_MAP, BMA400_INT2_MAP_GEN1_INT2,
+                                  cfg->int_num == BMA400_INT2_PIN);
+    } else {
+        bma400_set_register_field(bma400, BMA400_REG_INT1_MAP, BMA400_INT1_MAP_GEN2_INT1,
+                                  cfg->int_num == BMA400_INT1_PIN);
+        bma400_set_register_field(bma400, BMA400_REG_INT2_MAP, BMA400_INT2_MAP_GEN2_INT2,
+                                  cfg->int_num == BMA400_INT2_PIN);
+    }
+    if (cfg->event_type) {
+        bma400->pdd.allowed_events |= cfg->event_type;
+    } else {
+        bma400->pdd.allowed_events &= ~cfg->event_type;
+    }
+
+    return bma400_commit(bma400);
+}
+
+int
+bma400_soft_reset(struct bma400 *bma400)
+{
+    int rc = 0;
+    uint8_t ready = 0;
+
+    while (rc == 0 && !ready) {
+        rc = bma400_get_register_field(bma400, BMA400_REG_STATUS, BMA400_STATUS_CMD_RDY, &ready);
+    }
+    if (rc == 0) {
+        rc = bma400_set_register(bma400, BMA400_REG_CMD, BMA400_CMD_SOFT_RESET);
+        ready = rc != 0;
+    }
+    while (rc == 0 && !ready) {
+        rc = bma400_get_register_field(bma400, BMA400_REG_STATUS, BMA400_STATUS_CMD_RDY, &ready);
+    }
+
+    bma400->pdd.cache.dirty = 0;
+    if (rc == 0) {
+        rc = bma400_read(bma400, BMA400_REG_ACC_CONFIG0, bma400->pdd.cache.regs, sizeof(bma400->pdd.cache.regs));
+    }
+
+    return rc;
+}
+
+int
+bma400_set_orient_cfg(struct bma400 *bma400,
+                      struct bma400_orient_cfg *cfg)
+{
+    bma400_begin_transact(bma400);
+
+    bma400_set_register_field(bma400, BMA400_REG_ORIENTCH_CONFIG0, BMA400_ORIENTCH_CONFIG0_ORIENT_Z_EN, cfg->orient_z_en);
+    bma400_set_register_field(bma400, BMA400_REG_ORIENTCH_CONFIG0, BMA400_ORIENTCH_CONFIG0_ORIENT_Y_EN, cfg->orient_y_en);
+    bma400_set_register_field(bma400, BMA400_REG_ORIENTCH_CONFIG0, BMA400_ORIENTCH_CONFIG0_ORIENT_X_EN, cfg->orient_x_en);
+    bma400_set_register_field(bma400, BMA400_REG_ORIENTCH_CONFIG0, BMA400_ORIENTCH_CONFIG0_ORIENT_DATA_SRC, cfg->orient_data_src);
+    bma400_set_register_field(bma400, BMA400_REG_ORIENTCH_CONFIG0, BMA400_ORIENTCH_CONFIG0_ORIENT_REFU, cfg->orient_refu);
+    bma400_set_register(bma400, BMA400_REG_ORIENTCH_CONFIG1, cfg->orient_thres);
+    bma400_set_register(bma400, BMA400_REG_ORIENTCH_CONFIG3, cfg->orient_dur);
+    bma400_set_register(bma400, BMA400_REG_ORIENTCH_CONFIG4, (uint8_t)cfg->int_orient_refx);
+    bma400_set_register(bma400, BMA400_REG_ORIENTCH_CONFIG5, cfg->int_orient_refx >> 8);
+    bma400_set_register(bma400, BMA400_REG_ORIENTCH_CONFIG6, (uint8_t)cfg->int_orient_refy);
+    bma400_set_register(bma400, BMA400_REG_ORIENTCH_CONFIG7, cfg->int_orient_refy >> 8);
+    bma400_set_register(bma400, BMA400_REG_ORIENTCH_CONFIG8, (uint8_t)cfg->int_orient_refz);
+    bma400_set_register(bma400, BMA400_REG_ORIENTCH_CONFIG9, cfg->int_orient_refz >> 8);
+
+    bma400_set_register_field(bma400, BMA400_REG_INT1_MAP, BMA400_INT1_MAP_ORIENTCH_INT1, cfg->int_num == BMA400_INT1_PIN);
+    bma400_set_register_field(bma400, BMA400_REG_INT2_MAP, BMA400_INT2_MAP_ORIENTCH_INT2, cfg->int_num == BMA400_INT2_PIN);
+
+    if (cfg->int_num != BMA400_NO_INT_PIN) {
+        bma400->pdd.allowed_events |= SENSOR_EVENT_TYPE_ORIENT_CHANGE;
+    } else {
+        bma400->pdd.allowed_events &= ~SENSOR_EVENT_TYPE_ORIENT_CHANGE;
+    }
+
+    return bma400_commit(bma400);
+}
+
+int
+bma400_set_tap_cfg(struct bma400 *bma400, struct bma400_tap_cfg *cfg)
+{
+    int rc;
+
+    bma400_begin_transact(bma400);
+
+    bma400_set_register_field(bma400, BMA400_REG_TAP_CONFIG0, BMA400_TAP_CONFIG_SEL_AXIS, cfg->sel_axis);
+    bma400_set_register_field(bma400, BMA400_REG_TAP_CONFIG0, BMA400_TAP_CONFIG_TAP_SENSITIVITY, cfg->tap_sensitivity);
+    bma400_set_register_field(bma400, BMA400_REG_TAP_CONFIG1, BMA400_TAP_CONFIG1_TICS_TH, cfg->tics_th);
+    bma400_set_register_field(bma400, BMA400_REG_TAP_CONFIG1, BMA400_TAP_CONFIG1_QUITE, cfg->quite);
+    bma400_set_register_field(bma400, BMA400_REG_TAP_CONFIG1, BMA400_TAP_CONFIG1_QUITE_DT, cfg->quite_dt);
+
+    bma400_set_register_field(bma400, BMA400_REG_INT12_MAP, BMA400_INT12_MAP_TAP_INT1, cfg->int_num == BMA400_INT1_PIN);
+    bma400_set_register_field(bma400, BMA400_REG_INT12_MAP, BMA400_INT12_MAP_TAP_INT2, cfg->int_num == BMA400_INT2_PIN);
+
+    if (cfg->int_num != BMA400_NO_INT_PIN) {
+        bma400->pdd.allowed_events |= SENSOR_EVENT_TYPE_SINGLE_TAP | SENSOR_EVENT_TYPE_DOUBLE_TAP;
+    } else {
+        bma400->pdd.allowed_events &= ~(SENSOR_EVENT_TYPE_SINGLE_TAP | SENSOR_EVENT_TYPE_DOUBLE_TAP);
+    }
+
+    rc = bma400_commit(bma400);
+
+    return rc;
+}
+
+int
+bma400_get_fifo_watermark(struct bma400 *bma400, uint16_t *watermark)
+{
+    uint8_t data[2];
+    int rc;
+
+    rc = bma400_get_register(bma400, BMA400_REG_FIFO_CONFIG1, &data[0]);
+
+    if (rc == 0) {
+        rc = bma400_get_register((struct bma400 *)bma400, BMA400_REG_FIFO_CONFIG2, &data[1]);
+    }
+    if (rc == 0) {
+        *watermark = data[0] | ((data[1] & 7) << 8);
+    }
+
+    return rc;
+}
+
+int
+bma400_set_fifo_watermark(struct bma400 *bma400, uint16_t watermark)
+{
+    bma400_begin_transact(bma400);
+
+    bma400_set_register(bma400, BMA400_REG_FIFO_CONFIG1, (uint8_t)watermark);
+    bma400_set_register(bma400, BMA400_REG_FIFO_CONFIG2, watermark >> 8);
+
+    return bma400_commit(bma400);
+}
+
+int
+bma400_set_fifo_cfg(struct bma400 *bma400,
+                    struct bma400_fifo_cfg *cfg)
+{
+    bma400_begin_transact(bma400);
+
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_CONFIG0, BMA400_FIFO_CONFIG_0_FIFO_Z_EN, cfg->fifo_z_en);
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_CONFIG0, BMA400_FIFO_CONFIG_0_FIFO_Y_EN, cfg->fifo_y_en);
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_CONFIG0, BMA400_FIFO_CONFIG_0_FIFO_X_EN, cfg->fifo_x_en);
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_CONFIG0, BMA400_FIFO_CONFIG_0_FIFO_8BIT_EN, cfg->fifo_8bit_en);
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_CONFIG0, BMA400_FIFO_CONFIG_0_FIFO_DATA_SRC, cfg->fifo_data_src);
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_CONFIG0, BMA400_FIFO_CONFIG_0_FIFO_TIME_EN, cfg->fifo_time_en);
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_CONFIG0, BMA400_FIFO_CONFIG_0_FIFO_STOP_ON_FULL, cfg->fifo_stop_on_full);
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_CONFIG0, BMA400_FIFO_CONFIG_0_FIFO_AUTO_FLUSH, cfg->fifo_auto_flush);
+    bma400_set_fifo_watermark(bma400, cfg->watermark);
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_PWR_CONFIG, BMA400_FIFO_PWR_CONFIG_FIFO_READ_DISABLE, cfg->fifo_read_disable);
+
+    bma400_set_register_field(bma400, BMA400_REG_INT1_MAP, BMA400_INT1_MAP_FWM_INT1, cfg->int_num == BMA400_INT1_PIN);
+    bma400_set_register_field(bma400, BMA400_REG_INT2_MAP, BMA400_INT2_MAP_FWM_INT2, cfg->int_num == BMA400_INT2_PIN);
+
+    return bma400_commit(bma400);
+}
+
+int
+bma400_read_fifo(struct bma400 *bma400, uint16_t *fifo_count, struct sensor_accel_data *sad)
+{
+    uint8_t data[1 + 6];
+    int rc;
+    struct bma400_fifo_cfg *cfg = &bma400->cfg.fifo_cfg;
+    int data_record_size = 1 + (cfg->fifo_x_en + cfg->fifo_y_en + cfg->fifo_z_en) * (2 - cfg->fifo_8bit_en);
+
+    for (;;) {
+        if (*fifo_count < sizeof(data)) {
+            rc = bma400_get_fifo_count(bma400, fifo_count);
+            if (rc != 0 || *fifo_count < sizeof(data)) {
+                return rc;
+            }
+        }
+
+        rc = bma400_read(bma400, BMA400_REG_FIFO_DATA, data, sizeof(data));
+        if (rc == 0) {
+            switch (data[0] & 0xF0) {
+            case 0x80: /* Data frame */
+                *fifo_count -= data_record_size;
+                if (cfg->fifo_x_en) {
+                    sad->sad_x_is_valid = 1;
+                    if (cfg->fifo_8bit_en) {
+                        compute_accel_data(bma400, data[1] << 8, &sad->sad_x);
+                    } else {
+                        compute_accel_data(bma400, (data[2] << 8) | (uint8_t)(data[1] << 4), &sad->sad_x);
+                    }
+                }
+                if (cfg->fifo_y_en) {
+                    sad->sad_y_is_valid = 1;
+                    if (cfg->fifo_8bit_en) {
+                        compute_accel_data(bma400, data[2] << 8, &sad->sad_y);
+                    } else {
+                        compute_accel_data(bma400, (data[4] << 8) | (uint8_t)(data[3] << 4), &sad->sad_y);
+                    }
+                }
+                if (cfg->fifo_z_en) {
+                    sad->sad_z_is_valid = 1;
+                    if (cfg->fifo_8bit_en) {
+                        compute_accel_data(bma400, data[3] << 8, &sad->sad_z);
+                    } else {
+                        compute_accel_data(bma400, (data[6] << 8) | (uint8_t)(data[5] << 4), &sad->sad_z);
+                    }
+                }
+                return 0;
+                break;
+            case 0xA0: /* Time frame */
+                *fifo_count -= 4;
+                break;
+            case 0x40: /* Control frame */
+                *fifo_count -= 2;
+                break;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int
+reset_and_recfg(struct bma400 *bma400)
+{
+    struct bma400_cfg *cfg;
+    int rc;
+
+    cfg = &bma400->cfg;
+
+    rc = bma400_soft_reset(bma400);
+    if (rc != 0) {
+        return rc;
+    }
+
+    bma400_begin_transact(bma400);
+
+    bma400_set_int12_cfg(bma400, &cfg->int_pin_cfg);
+    bma400_set_g_range(bma400, cfg->g_range);
+    bma400_set_filt1_bandwidth(bma400, cfg->filt1_bw);
+    bma400_set_fifo_cfg(bma400, &bma400->cfg.fifo_cfg);
+    bma400_set_autolowpow_mode(bma400, &bma400->cfg.autolowpow_cfg);
+    bma400_set_wakeup(bma400, &bma400->cfg.wakeup_cfg);
+    bma400_set_orient_cfg(bma400, &bma400->cfg.orient_cfg);
+    bma400_set_tap_cfg(bma400, &bma400->cfg.tap_cfg);
+    bma400_set_activity_cfg(bma400, &bma400->cfg.activity_cfg);
+    bma400_set_step_counter_cfg(bma400, &bma400->cfg.step_cfg);
+    bma400_set_gen_int(bma400, BMA400_GEN_INT_1, &bma400->cfg.gen_int_cfg[0]);
+    bma400_set_gen_int(bma400, BMA400_GEN_INT_2, &bma400->cfg.gen_int_cfg[1]);
+    bma400_set_power_mode(bma400, cfg->power_mode);
+
+    rc = bma400_commit(bma400);
+
+    return rc;
+}
+
+#if MYNEWT_VAL(BMA400_INT_ENABLE)
+//static int
+//init_intpins(struct bma400 *bma400, hal_gpio_irq_handler_t handler)
+//{
+//    int rc = 0;
+//
+//    hal_gpio_irq_trig_t trig;
+//
+//    if (bma400->cfg.int_pin_cfg.int1_host_pin >= 0) {
+//        trig = bma400->cfg.int_pin_cfg.int1_level ? HAL_GPIO_TRIG_RISING : HAL_GPIO_TRIG_FALLING;
+//        rc = hal_gpio_irq_init(bma400->cfg.int_pin_cfg.int1_host_pin,
+//                               handler,
+//                               bma400,
+//                               trig,
+//                               HAL_GPIO_PULL_NONE);
+//    }
+//    if (bma400->cfg.int_pin_cfg.int2_host_pin >= 0) {
+//        trig = bma400->cfg.int_pin_cfg.int2_level ? HAL_GPIO_TRIG_RISING : HAL_GPIO_TRIG_FALLING;
+//        rc = hal_gpio_irq_init(bma400->cfg.int_pin_cfg.int2_host_pin,
+//                               handler,
+//                               bma400,
+//                               trig,
+//                               HAL_GPIO_PULL_NONE);
+//    }
+//
+//    return rc;
+//}
+
+static void
+enable_intpin(struct bma400 *bma400)
+{
+    struct bma400_private_driver_data *pdd = &bma400->pdd;
+    pdd->int_ref_cnt++;
+
+    if (pdd->int_ref_cnt == 1) {
+        if (pdd->interrupt->ints[0].host_pin >= 0) {
+            hal_gpio_irq_enable(pdd->interrupt->ints[0].host_pin);
+        }
+        if (pdd->interrupt->ints[1].host_pin >= 0) {
+            hal_gpio_irq_enable(pdd->interrupt->ints[1].host_pin);
+        }
+    }
+}
+
+static void
+disable_intpin(struct bma400 *bma400)
+{
+    struct bma400_private_driver_data *pdd = &bma400->pdd;
+
+    if (pdd->int_ref_cnt == 0) {
+        return;
+    }
+
+    if (--pdd->int_ref_cnt == 0) {
+        if (pdd->interrupt->ints[0].host_pin >= 0) {
+            hal_gpio_irq_enable(pdd->interrupt->ints[0].host_pin);
+        }
+        if (pdd->interrupt->ints[1].host_pin >= 0) {
+            hal_gpio_irq_enable(pdd->interrupt->ints[1].host_pin);
+        }
+    }
+}
+#endif
+
+int
+bma400_self_test(struct bma400 *bma400, bool *self_test_fail)
+{
+    float positive_vals[3];
+    float negative_vals[3];
+    int rc;
+
+    bma400_begin_transact(bma400);
+
+    /* Disable all interrupts */
+    bma400_set_register(bma400, BMA400_REG_INT_CONFIG0, 0);
+    bma400_set_register(bma400, BMA400_REG_INT_CONFIG1, 0);
+    /* Normal mode */
+    bma400_set_register(bma400, BMA400_REG_ACC_CONFIG0, 2);
+    /* 4G, 100Hz */
+    bma400_set_register(bma400, BMA400_REG_ACC_CONFIG1, 0x48);
+
+    rc = bma400_commit(bma400);
+    if (rc) {
+        goto end;
+    }
+
+    delay_msec(2);
+
+    /* Positive self-test excitation */
+    rc = bma400_set_register(bma400, BMA400_REG_SELF_TEST, 0x07);
+    if (rc) {
+        goto end;
+    }
+    delay_msec(50);
+
+    rc = bma400_get_accel(bma400, positive_vals);
+    if (rc) {
+        goto end;
+    }
+
+    /* Negative self-test excitation */
+    rc = bma400_set_register(bma400, BMA400_REG_SELF_TEST, 0x0F);
+    if (rc) {
+        goto end;
+    }
+
+    delay_msec(50);
+
+    rc = bma400_get_accel(bma400, negative_vals);
+    if (rc) {
+        goto end;
+    }
+
+    rc = bma400_set_register(bma400, BMA400_REG_SELF_TEST, 0);
+    if (rc) {
+        goto end;
+    }
+
+    /*
+     * Self-test minimum difference for positive - negative excitation acceleration are:
+     * x-axis: 1500mg, y-axis: 1200mg, z-axis: 250mg
+     */
+    *self_test_fail = (positive_vals[0] - negative_vals[0]) < (1.5f * STANDARD_ACCEL_GRAVITY) ||
+                      (positive_vals[1] - negative_vals[1]) < (1.2f * STANDARD_ACCEL_GRAVITY) ||
+                      (positive_vals[2] - negative_vals[2]) < (0.25f * STANDARD_ACCEL_GRAVITY);
+
+end:
+    return rc;
+}
+
+/**
+ * Do accelerometer polling reads
+ *
+ * @param The sensor ptr
+ * @param The sensor type
+ * @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
+bma400_poll_read(struct sensor *sensor, sensor_type_t sensor_type,
+                 sensor_data_func_t data_func, void *data_arg,
+                 uint32_t timeout)
+{
+    int rc = SYS_EINVAL;
+    struct bma400 *bma400 = (struct bma400 *)SENSOR_GET_DEVICE(sensor);
+    float accel_data[3];
+    struct sensor_accel_data sad;
+    struct sensor_temp_data std;
+    bma400_power_mode_t power_mode = BMA400_POWER_MODE_NORMAL;
+
+    rc = bma400_get_power_mode(bma400, &power_mode);
+    if (rc) {
+        goto end;
+    }
+    if (power_mode == BMA400_POWER_MODE_SLEEP) {
+        rc = bma400_set_power_mode(bma400, BMA400_POWER_MODE_NORMAL);
+        if (rc) {
+            goto end;
+        }
+    }
+
+    if ((sensor_type & SENSOR_TYPE_ACCELEROMETER) != 0) {
+        rc = bma400_get_accel(bma400, accel_data);
+        if (rc != 0) {
+            goto end;
+        }
+        sad.sad_x = accel_data[0];
+        sad.sad_y = accel_data[1];
+        sad.sad_z = accel_data[2];
+        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) {
+            goto end;
+        }
+    }
+
+    if ((sensor_type & SENSOR_TYPE_TEMPERATURE) != 0) {
+        rc = bma400_get_temp(bma400, &std.std_temp);
+        if (rc != 0) {
+            goto end;
+        }
+
+        std.std_temp_is_valid = 1;
+
+        rc = data_func(sensor,
+                       data_arg,
+                       &std,
+                       SENSOR_TYPE_TEMPERATURE);
+    }
+end:
+    if (power_mode == BMA400_POWER_MODE_SLEEP) {
+        rc = bma400_set_power_mode(bma400, BMA400_POWER_MODE_SLEEP);
+    }
+
+    return rc;
+}
+
+int
+bma400_stream_read(struct sensor *sensor,
+                   sensor_type_t sensor_type,
+                   sensor_data_func_t data_func,
+                   void *read_arg,
+                   uint32_t time_ms)
+{
+    int rc;
+    os_time_t time_ticks;
+    os_time_t stop_ticks;
+    struct sensor_accel_data sad;
+    struct bma400_private_driver_data *pdd;
+    struct bma400 *bma400 = (struct bma400 *)SENSOR_GET_DEVICE(sensor);
+    uint16_t fifo_count = 0;
+
+    pdd = &bma400->pdd;
+
+    stop_ticks = 0;
+
+    rc = bma400_set_power_mode(bma400, BMA400_POWER_MODE_NORMAL);
+    if (rc != 0) {
+        return rc;
+    }
+
+#if MYNEWT_VAL(BMA400_INT_ENABLE)
+    undo_interrupt(&bma400->pdd.intr);
+
+    if (pdd->interrupt) {
+        return SYS_EBUSY;
+    }
+    pdd->interrupt = &bma400->pdd.intr;
+    enable_intpin(bma400);
+#endif
+
+    bma400_set_fifo_cfg(bma400, &bma400->cfg.fifo_cfg);
+
+    bma400_set_register_field(bma400, BMA400_REG_INT_CONFIG0, BMA400_INT_CONFIG0_FWM_INT_EN, 1);
+
+    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 (;;) {
+        wait_interrupt(&bma400->pdd.intr);
+
+        rc = bma400_read_fifo(bma400, &fifo_count, &sad);
+        if (rc != 0) {
+            goto done;
+        }
+
+        if (data_func(sensor, read_arg, &sad, SENSOR_TYPE_ACCELEROMETER)) {
+            break;
+        }
+
+        if (time_ms != 0 && OS_TIME_TICK_GT(os_time_get(), stop_ticks)) {
+            break;
+        }
+    }
+
+//    rc = bma400_set_int_enable(bma400, &int_enable_org);
+
+done:
+#if MYNEWT_VAL(BMA400_INT_ENABLE)
+    pdd->interrupt = NULL;
+    disable_intpin(bma400);
+#endif
+
+    return rc;
+}
+
+static int
+bma400_sensor_read(struct sensor *sensor,
+                   sensor_type_t sensor_type,
+                   sensor_data_func_t data_func,
+                   void *data_arg,
+                   uint32_t timeout)
+{
+    int rc;
+    struct bma400 *bma400;
+
+    if ((sensor_type & ~(SENSOR_TYPE_ACCELEROMETER |
+                         SENSOR_TYPE_TEMPERATURE)) != 0) {
+        rc = SYS_EINVAL;
+        goto end;
+    }
+
+    bma400 = (struct bma400 *)SENSOR_GET_DEVICE(sensor);
+
+    if (bma400->cfg.stream_read_mode) {
+        rc = bma400_stream_read(sensor, sensor_type, data_func, data_arg, timeout);
+    } else {
+        rc = bma400_poll_read(sensor, sensor_type, data_func, data_arg, timeout);
+    }
+
+end:
+
+    return rc;
+}
+
+static int
+bma400_sensor_get_config(struct sensor *sensor,
+                         sensor_type_t sensor_type,
+                         struct sensor_cfg *cfg)
+{
+    int rc = 0;
+
+    /* Only one bit should be set in sensor_type mask */
+    if ((sensor_type & (sensor_type - 1)) != 0) {
+        return SYS_EINVAL;
+    }
+
+    if (sensor_type & SENSOR_TYPE_ACCELEROMETER) {
+        cfg->sc_valtype = SENSOR_VALUE_TYPE_FLOAT_TRIPLET;
+    } else if (sensor_type & SENSOR_TYPE_TEMPERATURE) {
+        cfg->sc_valtype = SENSOR_VALUE_TYPE_FLOAT;
+    } else {
+        rc = SYS_EINVAL;
+    }
+
+    return rc;
+}
+
+static int
+bma400_sensor_set_config(struct sensor *sensor, void *cfg)
+{
+    struct bma400 *bma400;
+
+    bma400 = (struct bma400 *)SENSOR_GET_DEVICE(sensor);
+
+    return bma400_config(bma400, (struct bma400_cfg *)cfg);
+}
+
+static void
+bma400_set_event_int(struct bma400 *bma400, sensor_event_type_t sensor_event_type, int on)
+{
+    if (sensor_event_type == SENSOR_EVENT_TYPE_DOUBLE_TAP) {
+        bma400_set_register_field(bma400, BMA400_REG_INT_CONFIG1, BMA400_INT_CONFIG1_D_TAP_INT_EN, on);
+    }
+    if (sensor_event_type == SENSOR_EVENT_TYPE_SINGLE_TAP) {
+        bma400_set_register_field(bma400, BMA400_REG_INT_CONFIG1, BMA400_INT_CONFIG1_S_TAP_INT_EN, on);
+    }
+    if (sensor_event_type == bma400->cfg.gen_int_cfg[0].event_type) {
+        bma400_set_register_field(bma400, BMA400_REG_INT_CONFIG0, BMA400_INT_CONFIG0_GEN1_INT_EN, on);
+    }
+    if (sensor_event_type == bma400->cfg.gen_int_cfg[1].event_type) {
+        bma400_set_register_field(bma400, BMA400_REG_INT_CONFIG0, BMA400_INT_CONFIG0_GEN2_INT_EN, on);
+    }
+    if (sensor_event_type == bma400->cfg.activity_cfg.event_type) {
+        bma400_set_register_field(bma400, BMA400_REG_INT_CONFIG1, BMA400_INT_CONFIG1_ACTCH_INTEN, on);
+    }
+    if (sensor_event_type == SENSOR_EVENT_TYPE_ORIENT_CHANGE) {
+        bma400_set_register_field(bma400, BMA400_REG_INT_CONFIG0, BMA400_INT_CONFIG0_ORIENTCH_INT_EN, on);
+    }
+}
+
+static int
+bma400_sensor_unset_notification(struct sensor *sensor,
+                                 sensor_event_type_t registered_event)
+{
+#if MYNEWT_VAL(BMA400_INT_ENABLE)
+    struct bma400 *bma400 = (struct bma400 *)SENSOR_GET_DEVICE(sensor);
+    struct bma400_private_driver_data *pdd = &bma400->pdd;
+    int rc;
+
+    /* Supported event check */
+    if ((registered_event & pdd->notify_ctx.snec_evtype) == 0) {
+        return SYS_EINVAL;
+    }
+
+    pdd = &bma400->pdd;
+
+    pdd->notify_ctx.snec_evtype &= ~registered_event;
+
+    bma400_begin_transact(bma400);
+
+    bma400_set_event_int(bma400, registered_event, 0);
+
+    rc = bma400_commit(bma400);
+
+    if (pdd->notify_ctx.snec_evtype == 0) {
+        disable_intpin(bma400);
+    }
+
+    return rc;
+#else
+    return SYS_ENODEV;
+#endif
+}
+
+static int
+bma400_sensor_set_notification(struct sensor *sensor,
+                               sensor_event_type_t requested_event)
+{
+#if MYNEWT_VAL(BMA400_INT_ENABLE)
+    int rc;
+    struct bma400 *bma400 = (struct bma400 *)SENSOR_GET_DEVICE(sensor);
+    struct bma400_private_driver_data *pdd;
+
+    pdd = &bma400->pdd;
+
+    /* Supported event check */
+    if ((requested_event & ~(pdd->allowed_events)) != 0) {
+        return SYS_EINVAL;
+    }
+
+    bma400_begin_transact(bma400);
+
+    bma400_set_event_int(bma400, requested_event, 1);
+
+    rc = bma400_commit(bma400);
+
+    if (rc == 0) {
+        if (pdd->notify_ctx.snec_evtype == 0) {
+            enable_intpin(bma400);
+        }
+        pdd->notify_ctx.snec_evtype |= requested_event;
+    }
+
+    return rc;
+#else
+    return SYS_ENODEV;
+#endif
+}
+
+static int
+bma400_sensor_handle_interrupt(struct sensor *sensor)
+{
+#if MYNEWT_VAL(BMA400_INT_ENABLE)
+    struct bma400 *bma400;
+    struct bma400_private_driver_data *pdd;
+    struct int_status int_status;
+    int rc;
+
+    bma400 = (struct bma400 *)SENSOR_GET_DEVICE(sensor);
+    pdd = &bma400->pdd;
+
+    rc = bma400_get_int_status(bma400, &int_status);
+    if (rc != 0) {
+        BMA400_LOG_ERROR("Can not read int status err=0x%02x\n", rc);
+        return rc;
+    }
+
+    if ((pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_SINGLE_TAP) &&
+        (int_status.int_stat1 & BMA400_INT_STAT1_S_TAP_INT_STAT)) {
+        sensor_mgr_put_notify_evt(&pdd->notify_ctx, SENSOR_EVENT_TYPE_SINGLE_TAP);
+    }
+    if ((pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_DOUBLE_TAP) &&
+        (int_status.int_stat1 & BMA400_INT_STAT1_D_TAP_INT_STAT)) {
+        sensor_mgr_put_notify_evt(&pdd->notify_ctx, SENSOR_EVENT_TYPE_DOUBLE_TAP);
+    }
+    if ((pdd->notify_ctx.snec_evtype & bma400->cfg.gen_int_cfg[0].event_type) &&
+        (int_status.int_stat0 & BMA400_INT_STAT0_GEN1_INT_STAT)) {
+        sensor_mgr_put_notify_evt(&pdd->notify_ctx, bma400->cfg.gen_int_cfg[0].event_type);
+    }
+    if ((pdd->notify_ctx.snec_evtype & bma400->cfg.gen_int_cfg[1].event_type) &&
+        (int_status.int_stat0 & BMA400_INT_STAT0_GEN2_INT_STAT)) {
+        sensor_mgr_put_notify_evt(&pdd->notify_ctx, bma400->cfg.gen_int_cfg[1].event_type);
+    }
+    if ((pdd->notify_ctx.snec_evtype & bma400->cfg.activity_cfg.event_type) &&
+        (int_status.int_stat0 & BMA400_INT_STAT2_ACTCH_XYZ_INT_STAT)) {
+        sensor_mgr_put_notify_evt(&pdd->notify_ctx, bma400->cfg.activity_cfg.event_type);
+    }
+
+    return 0;
+#else
+    return SYS_ENODEV;
+#endif
+}
+
+static struct sensor_driver bma400_sensor_driver = {
+    .sd_read               = bma400_sensor_read,
+    .sd_set_config         = bma400_sensor_set_config,
+    .sd_get_config         = bma400_sensor_get_config,
+    .sd_set_notification   = bma400_sensor_set_notification,
+    .sd_unset_notification = bma400_sensor_unset_notification,
+    .sd_handle_interrupt   = bma400_sensor_handle_interrupt,
+};
+
+int
+bma400_config(struct bma400 *bma400, struct bma400_cfg *cfg)
+{
+    struct sensor * sensor;
+    int rc;
+    uint8_t chip_id;
+
+    bma400->cfg = *cfg;
+
+    sensor = &bma400->sensor;
+
+    rc = bma400_get_chip_id(bma400, &chip_id);
+    if (rc != 0) {
+        return rc;
+    }
+    if (chip_id != 0x90) {
+        BMA400_LOG_ERROR("received incorrect chip ID 0x%02X\n", chip_id);
+        return SYS_EINVAL;
+    }
+
+    rc = reset_and_recfg(bma400);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = sensor_set_type_mask(sensor, cfg->sensor_mask);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+int
+bma400_init(struct os_dev *dev, void *arg)
+{
+    struct bma400 *bma400 = (struct bma400 *)dev;
+    struct sensor *sensor;
+    struct bma400_private_driver_data *pdd;
+    int rc;
+
+    if (!dev) {
+        return SYS_ENODEV;
+    }
+
+    sensor = &bma400->sensor;
+
+    rc = sensor_init(sensor, dev);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = sensor_set_driver(sensor,
+                           SENSOR_TYPE_ACCELEROMETER |
+                           SENSOR_TYPE_TEMPERATURE,
+                           &bma400_sensor_driver);
+    if (rc != 0) {
+        return rc;
+    }
+
+    if (arg) {
+        rc = sensor_set_interface(sensor, arg);
+        if (rc != 0) {
+            return rc;
+        }
+    }
+
+    rc = sensor_mgr_register(sensor);
+    if (rc != 0) {
+        return rc;
+    }
+
+#if !MYNEWT_VAL(BUS_DRIVER_PRESENT)
+#if MYNEWT_VAL(SPI_0_MASTER) || MYNEWT_VAL(SPI_1_MASTER)
+    rc = hal_spi_config(sensor->s_itf.si_num, &spi_bma400_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
+#endif
+
+#if MYNEWT_VAL(BMA400_INT_ENABLE)
+    init_interrupt(&bma400->pdd.intr);
+
+    pdd = &bma400->pdd;
+
+    pdd->notify_ctx.snec_sensor = sensor;
+#endif
+
+    return 0;
+}
+
+#if MYNEWT_VAL(BUS_DRIVER_PRESENT)
+static void
+init_node_cb(struct bus_node *bnode, void *arg)
+{
+    bma400_init((struct os_dev *)bnode, arg);
+}
+
+#if MYNEWT_VAL(BMA400_I2C_SUPPORT)
+static int
+bma400_create_i2c_sensor_dev(struct bma400 *bma400, const char *name,
+                             const struct bma400_create_dev_cfg *cfg)
+{
+    const struct bus_i2c_node_cfg *i2c_cfg = &cfg->i2c_cfg;
+    struct bus_node_callbacks cbs = {
+        .init = init_node_cb,
+    };
+    int rc;
+
+    bma400->node_is_spi = false;
+
+    bma400->sensor.s_itf.si_dev = &bma400->i2c_node.bnode.odev;
+    bus_node_set_callbacks((struct os_dev *)bma400, &cbs);
+
+    rc = bus_i2c_node_create(name, &bma400->i2c_node, i2c_cfg, NULL);
+
+    return rc;
+}
+#endif
+
+#if MYNEWT_VAL(BMA400_SPI_SUPPORT)
+static int
+bma400_create_spi_sensor_dev(struct bma400 *bma400, const char *name,
+                              const struct bma400_create_dev_cfg *cfg)
+{
+    const struct bus_spi_node_cfg *spi_cfg = &cfg->spi_cfg;
+    struct bus_node_callbacks cbs = {
+        .init = init_node_cb,
+    };
+    int rc;
+
+    bma400->node_is_spi = true;
+
+    bma400->sensor.s_itf.si_dev = &bma400->spi_node.bnode.odev;
+    bus_node_set_callbacks((struct os_dev *)bma400, &cbs);
+
+    rc = bus_spi_node_create(name, &bma400->spi_node, spi_cfg, NULL);
+
+    return rc;
+}
+#endif
+
+int
+bma400_create_dev(struct bma400 *bma400, const char *name,
+                  const struct bma400_create_dev_cfg *cfg)
+{
+#if MYNEWT_VAL(BMA400_SPI_SUPPORT)
+    if (cfg->node_is_spi) {
+        return bma400_create_spi_sensor_dev(bma400, name, cfg);
+    }
+#endif
+#if MYNEWT_VAL(BMA400_I2C_SUPPORT)
+    if (!cfg->node_is_spi) {
+        return bma400_create_i2c_sensor_dev(bma400, name, cfg);
+    }
+#endif
+    return SYS_EINVAL;
+}
+
+#else
+int
+bma400_create_dev(struct bma400 *bma400, const char *name,
+                  const struct bma400_create_dev_cfg *cfg)
+{
+    return os_dev_create((struct os_dev *)bma400, name,
+                         OS_DEV_INIT_PRIMARY, 0, bma400_init, (void *)&cfg->itf);
+}
+
+#endif /* BUS_DRIVER_PRESENT */
diff --git a/hw/drivers/sensors/bma400/src/bma400_priv.h b/hw/drivers/sensors/bma400/src/bma400_priv.h
new file mode 100755
index 0000000..55b905b
--- /dev/null
+++ b/hw/drivers/sensors/bma400/src/bma400_priv.h
@@ -0,0 +1,452 @@
+/*
+ * 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 __BMA400_PRIV_H__
+#define __BMA400_PRIV_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bma400;
+
+/*
+ * Full register map:
+ */
+
+#define BMA400_REG_CHIPID                           0x00
+#define BMA400_REG_ERR_REG                          0x02
+#define BMA400_REG_STATUS                           0x03
+#define BMA400_REG_ACC_X_LSB                        0x04
+#define BMA400_REG_ACC_X_MSB                        0x05
+#define BMA400_REG_ACC_Y_LSB                        0x06
+#define BMA400_REG_ACC_Y_MSB                        0x07
+#define BMA400_REG_ACC_Z_LSB                        0x08
+#define BMA400_REG_ACC_Z_MSB                        0x09
+#define BMA400_REG_SENSOR_TIME0                     0x0a
+#define BMA400_REG_SENSOR_TIME1                     0x0b
+#define BMA400_REG_SENSOR_TIME2                     0x0c
+#define BMA400_REG_EVENT                            0x0d
+#define BMA400_REG_INT_STAT0                        0x0e
+#define BMA400_REG_INT_STAT1                        0x0f
+#define BMA400_REG_INT_STAT2                        0x10
+#define BMA400_REG_TEMP_DATA                        0x11
+#define BMA400_REG_FIFO_LENGTH0                     0x12
+#define BMA400_REG_FIFO_LENGTH1                     0x13
+#define BMA400_REG_FIFO_DATA                        0x14
+#define BMA400_REG_STEP_CNT_0                       0x15
+#define BMA400_REG_STEP_CNT_1                       0x16
+#define BMA400_REG_STEP_CNT_2                       0x17
+#define BMA400_REG_STEP_STAT                        0x18
+
+#define BMA400_REG_ACC_CONFIG0                      0x19
+#define BMA400_REG_ACC_CONFIG1                      0x1a
+#define BMA400_REG_ACC_CONFIG2                      0x1b
+#define BMA400_REG_INT_CONFIG0                      0x1f
+#define BMA400_REG_INT_CONFIG1                      0x20
+#define BMA400_REG_INT1_MAP                         0x21
+#define BMA400_REG_INT2_MAP                         0x22
+#define BMA400_REG_INT12_MAP                        0x23
+#define BMA400_REG_INT12_IO_CTRL                    0x24
+
+#define BMA400_REG_FIFO_CONFIG0                     0x26
+#define BMA400_REG_FIFO_CONFIG1                     0x27
+#define BMA400_REG_FIFO_CONFIG2                     0x28
+#define BMA400_REG_FIFO_PWR_CONFIG                  0x29
+#define BMA400_REG_AUTOLOWPOW_0                     0x2a
+#define BMA400_REG_AUTOLOWPOW_1                     0x2b
+#define BMA400_REG_AUTOWAKEUP_0                     0x2c
+#define BMA400_REG_AUTOWAKEUP_1                     0x2d
+
+#define BMA400_REG_WKUP_INT_CONFIG0                 0x2f
+#define BMA400_REG_WKUP_INT_CONFIG1                 0x30
+#define BMA400_REG_WKUP_INT_CONFIG2                 0x31
+#define BMA400_REG_WKUP_INT_CONFIG3                 0x32
+#define BMA400_REG_WKUP_INT_CONFIG4                 0x33
+
+#define BMA400_REG_ORIENTCH_CONFIG0                 0x35
+#define BMA400_REG_ORIENTCH_CONFIG1                 0x36
+
+#define BMA400_REG_ORIENTCH_CONFIG3                 0x38
+#define BMA400_REG_ORIENTCH_CONFIG4                 0x39
+#define BMA400_REG_ORIENTCH_CONFIG5                 0x3a
+#define BMA400_REG_ORIENTCH_CONFIG6                 0x3b
+#define BMA400_REG_ORIENTCH_CONFIG7                 0x3c
+#define BMA400_REG_ORIENTCH_CONFIG8                 0x3d
+#define BMA400_REG_ORIENTCH_CONFIG9                 0x3e
+#define BMA400_REG_GEN1INT_CONFIG0                  0x3f
+#define BMA400_REG_GEN1INT_CONFIG1                  0x40
+#define BMA400_REG_GEN1INT_CONFIG2                  0x41
+#define BMA400_REG_GEN1INT_CONFIG3                  0x42
+#define BMA400_REG_GEN1INT_CONFIG31                 0x43
+#define BMA400_REG_GEN1INT_CONFIG4                  0x44
+#define BMA400_REG_GEN1INT_CONFIG5                  0x45
+#define BMA400_REG_GEN1INT_CONFIG6                  0x46
+#define BMA400_REG_GEN1INT_CONFIG7                  0x47
+#define BMA400_REG_GEN1INT_CONFIG8                  0x48
+#define BMA400_REG_GEN1INT_CONFIG9                  0x49
+#define BMA400_REG_GEN2INT_CONFIG0                  0x4a
+#define BMA400_REG_GEN2INT_CONFIG1                  0x4b
+#define BMA400_REG_GEN2INT_CONFIG2                  0x4c
+#define BMA400_REG_GEN2INT_CONFIG3                  0x4d
+#define BMA400_REG_GEN2INT_CONFIG31                 0x4e
+#define BMA400_REG_GEN2INT_CONFIG4                  0x4f
+#define BMA400_REG_GEN2INT_CONFIG5                  0x50
+#define BMA400_REG_GEN2INT_CONFIG6                  0x51
+#define BMA400_REG_GEN2INT_CONFIG7                  0x52
+#define BMA400_REG_GEN2INT_CONFIG8                  0x53
+#define BMA400_REG_GEN2INT_CONFIG9                  0x54
+#define BMA400_REG_ACTCH_CONFIG0                    0x55
+#define BMA400_REG_ACTCH_CONFIG1                    0x56
+#define BMA400_REG_TAP_CONFIG                       0x57
+#define BMA400_REG_TAP_CONFIG0                      BMA400_REG_TAP_CONFIG
+#define BMA400_REG_TAP_CONFIG1                      0x58
+
+#define BMA400_REG_STEP_COUNTER_CONFIG0             0x59
+#define BMA400_REG_STEP_COUNTER_CONFIG1             0x5a
+#define BMA400_REG_STEP_COUNTER_CONFIG2             0x5b
+#define BMA400_REG_STEP_COUNTER_CONFIG3             0x5c
+#define BMA400_REG_STEP_COUNTER_CONFIG4             0x5d
+#define BMA400_REG_STEP_COUNTER_CONFIG5             0x5e
+#define BMA400_REG_STEP_COUNTER_CONFIG6             0x5f
+#define BMA400_REG_STEP_COUNTER_CONFIG7             0x60
+#define BMA400_REG_STEP_COUNTER_CONFIG8             0x61
+#define BMA400_REG_STEP_COUNTER_CONFIG9             0x62
+#define BMA400_REG_STEP_COUNTER_CONFIG10            0x63
+#define BMA400_REG_STEP_COUNTER_CONFIG11            0x64
+#define BMA400_REG_STEP_COUNTER_CONFIG12            0x65
+#define BMA400_REG_STEP_COUNTER_CONFIG13            0x66
+#define BMA400_REG_STEP_COUNTER_CONFIG14            0x67
+#define BMA400_REG_STEP_COUNTER_CONFIG15            0x68
+#define BMA400_REG_STEP_COUNTER_CONFIG16            0x69
+#define BMA400_REG_STEP_COUNTER_CONFIG17            0x6a
+#define BMA400_REG_STEP_COUNTER_CONFIG18            0x6b
+#define BMA400_REG_STEP_COUNTER_CONFIG19            0x6c
+#define BMA400_REG_STEP_COUNTER_CONFIG20            0x6d
+#define BMA400_REG_STEP_COUNTER_CONFIG21            0x6e
+#define BMA400_REG_STEP_COUNTER_CONFIG22            0x6f
+#define BMA400_REG_STEP_COUNTER_CONFIG23            0x70
+
+#define BMA400_REG_IF_CONF                          0x7c
+#define BMA400_REG_SELF_TEST                        0x7d
+#define BMA400_REG_CMD                              0x7e
+
+/* Set Read operation bit in SPI communication */
+#define BMA400_SPI_READ_CMD_BIT(_reg)               (_reg |= 0x80)
+
+#define BMA400_STATUS_DRDY_STAT                     0x80
+#define BMA400_STATUS_CMD_RDY                       0x10
+#define BMA400_STATUS_POWER_MODE_STAT               0x06
+#define BMA400_STATUS_INT_ACTIVE                    0x01
+
+#define BMA400_STATUS_SLEEP_MODE                    0x00
+#define BMA400_STATUS_LOW_POWER_MODE                0x02
+#define BMA400_STATUS_NORMAL_MODE                   0x04
+
+#define BMA400_EVENT_POR_DETECTED                   0x01
+
+#define BMA400_INT_STAT0_DRDY_INT_STAT              0x80
+#define BMA400_INT_STAT0_FWM_INT_STAT               0x40
+#define BMA400_INT_STAT0_FFULL_INT_STAT             0x20
+#define BMA400_INT_STAT0_IENG_OVERRUN_STAT          0x10
+#define BMA400_INT_STAT0_GEN2_INT_STAT              0x08
+#define BMA400_INT_STAT0_GEN1_INT_STAT              0x04
+#define BMA400_INT_STAT0_ORIENTCH_INT_STAT          0x02
+#define BMA400_INT_STAT0_WKUP_INT_STAT              0x01
+
+#define BMA400_INT_STAT1_IENG_OVERRUN_STAT          0x10
+#define BMA400_INT_STAT1_D_TAP_INT_STAT             0x08
+#define BMA400_INT_STAT1_S_TAP_INT_STAT             0x08
+#define BMA400_INT_STAT1_STEP_INT_STAT              0x03
+
+#define BMA400_INT_STAT1_STEP_DETECTED              0x01
+#define BMA400_INT_STAT1_STEP_D_DETECTED            0x02
+
+#define BMA400_INT_STAT2_IENG_OVERRUN_STAT          0x10
+#define BMA400_INT_STAT2_ACTCH_Z_INT_STAT           0x04
+#define BMA400_INT_STAT2_ACTCH_Y_INT_STAT           0x02
+#define BMA400_INT_STAT2_ACTCH_X_INT_STAT           0x01
+#define BMA400_INT_STAT2_ACTCH_XYZ_INT_STAT         0x07
+
+#define BMA400_ACC_CONFIG0_FILT1_BW                 0x80
+#define BMA400_ACC_CONFIG0_OSR_LP                   0x60
+#define BMA400_ACC_CONFIG0_POWER_MODE_CONF          0x03
+
+#define BMA400_ACC_CONFIG0_SLEEP_MODE               0x00
+#define BMA400_ACC_CONFIG0_LOW_POWER_MODE           0x01
+#define BMA400_ACC_CONFIG0_NORMAL_MODE              0x02
+
+#define BMA400_ACC_CONFIG1_ACC_RANGE                0xc0
+#define BMA400_ACC_CONFIG1_OSR                      0x30
+#define BMA400_ACC_CONFIG1_ACC_ODR                  0x0f
+
+#define BMA400_ACC_CONFIG1_ODR_12_5_HZ              0x05
+#define BMA400_ACC_CONFIG1_ODR_25_HZ                0x06
+#define BMA400_ACC_CONFIG1_ODR_50_HZ                0x07
+#define BMA400_ACC_CONFIG1_ODR_100_HZ               0x08
+#define BMA400_ACC_CONFIG1_ODR_200_HZ               0x09
+#define BMA400_ACC_CONFIG1_ODR_400_HZ               0x0a
+#define BMA400_ACC_CONFIG1_ODR_800_HZ               0x0b
+
+#define BMA400_ACC_CONFIG1_ACC_RANGE_2G             0
+#define BMA400_ACC_CONFIG1_ACC_RANGE_4G             1
+#define BMA400_ACC_CONFIG1_ACC_RANGE_8G             2
+#define BMA400_ACC_CONFIG1_ACC_RANGE_16G            3
+
+#define BMA400_ACC_CONFIG2_DATA_SRC_REG             0x0c
+#define BMA400_ACC_CONFIG2_ODR_VARIABLE             0x00
+#define BMA400_ACC_CONFIG2_ODR_100_HZ               0x04
+#define BMA400_ACC_CONFIG2_ODR_100_HZ_1HZ_BW        0x08
+
+#define BMA400_INT_CONFIG0_DRDY_INT_EN              0x80
+#define BMA400_INT_CONFIG0_FWM_INT_EN               0x40
+#define BMA400_INT_CONFIG0_FFULL_INT_EN             0x20
+#define BMA400_INT_CONFIG0_GEN2_INT_EN              0x08
+#define BMA400_INT_CONFIG0_GEN1_INT_EN              0x04
+#define BMA400_INT_CONFIG0_ORIENTCH_INT_EN          0x02
+
+#define BMA400_INT_CONFIG1_LATCH_INT                0x80
+#define BMA400_INT_CONFIG1_ACTCH_INTEN              0x10
+#define BMA400_INT_CONFIG1_D_TAP_INT_EN             0x08
+#define BMA400_INT_CONFIG1_S_TAP_INT_EN             0x04
+#define BMA400_INT_CONFIG1_STEP_INT_EN              0x01
+
+#define BMA400_INT1_MAP_DRDY_INT1                   0x80
+#define BMA400_INT1_MAP_FWM_INT1                    0x40
+#define BMA400_INT1_MAP_FFULL_INT1                  0x20
+#define BMA400_INT1_MAP_IENG_OVERRUN_INT1           0x10
+#define BMA400_INT1_MAP_GEN2_INT1                   0x08
+#define BMA400_INT1_MAP_GEN1_INT1                   0x04
+#define BMA400_INT1_MAP_ORIENTCH_INT1               0x02
+#define BMA400_INT1_MAP_WKUP_INT1                   0x01
+
+#define BMA400_INT2_MAP_DRDY_INT2                   0x80
+#define BMA400_INT2_MAP_FWM_INT2                    0x40
+#define BMA400_INT2_MAP_FFULL_INT2                  0x20
+#define BMA400_INT2_MAP_IENG_OVERRUN_INT2           0x10
+#define BMA400_INT2_MAP_GEN2_INT2                   0x08
+#define BMA400_INT2_MAP_GEN1_INT2                   0x04
+#define BMA400_INT2_MAP_ORIENTCH_INT2               0x02
+#define BMA400_INT2_MAP_WKUP_INT2                   0x01
+
+#define BMA400_INT12_MAP_ACTCH_INT2                 0x80
+#define BMA400_INT12_MAP_TAP_INT2                   0x40
+#define BMA400_INT12_MAP_STEP_INT2                  0x10
+#define BMA400_INT12_MAP_ACTCH_INT1                 0x08
+#define BMA400_INT12_MAP_TAP_INT1                   0x04
+#define BMA400_INT12_MAP_STEP_INT1                  0x01
+
+#define BMA400_INT12_IO_CTRL_INT2_OD                0x40
+#define BMA400_INT12_IO_CTRL_INT2_LVL               0x20
+#define BMA400_INT12_IO_CTRL_INT1_OD                0x04
+#define BMA400_INT12_IO_CTRL_INT1_LVL               0x02
+
+#define BMA400_FIFO_CONFIG_0_FIFO_Z_EN              0x80
+#define BMA400_FIFO_CONFIG_0_FIFO_Y_EN              0x40
+#define BMA400_FIFO_CONFIG_0_FIFO_X_EN              0x20
+#define BMA400_FIFO_CONFIG_0_FIFO_8BIT_EN           0x10
+#define BMA400_FIFO_CONFIG_0_FIFO_DATA_SRC          0x08
+#define BMA400_FIFO_CONFIG_0_FIFO_TIME_EN           0x04
+#define BMA400_FIFO_CONFIG_0_FIFO_STOP_ON_FULL      0x02
+#define BMA400_FIFO_CONFIG_0_FIFO_AUTO_FLUSH        0x01
+
+#define BMA400_FIFO_PWR_CONFIG_FIFO_READ_DISABLE    0x01
+
+#define BMA400_AUTOLOWPOW_0_AUTO_LP_TIMEOUT_THRES   0x0F
+#define BMA400_AUTOLOWPOW_1_AUTO_LP_TIMEOUT_THRES   0xF0
+#define BMA400_AUTOLOWPOW_1_AUTO_LP_TIMEOUT         0x0C
+#define BMA400_AUTOLOWPOW_1_GEN1_INT                0x02
+#define BMA400_AUTOLOWPOW_1_DRDY_LOWPOW_TRIG        0x01
+
+#define BMA400_AUTOWAKEUP_0_WAKEUP_TIMEOUT_THRES    0x0F
+#define BMA400_AUTOWAKEUP_1_WAKEUP_TIMEOUT_THRES    0xF0
+#define BMA400_AUTOWAKEUP_1_WKUP_TIMEOUT            0x04
+#define BMA400_AUTOWAKEUP_1_WKUP_INT                0x02
+
+#define BMA400_WKUP_INT_CONFIG0_WKUP_Z_EN           0x80
+#define BMA400_WKUP_INT_CONFIG0_WKUP_Y_EN           0x40
+#define BMA400_WKUP_INT_CONFIG0_WKUP_X_EN           0x20
+#define BMA400_WKUP_INT_CONFIG0_NUM_OF_SAMPLES      0x1C
+#define BMA400_WKUP_INT_CONFIG0_WKUP_REFU           0x03
+
+#define BMA400_ORIENTCH_CONFIG0_ORIENT_Z_EN         0x80
+#define BMA400_ORIENTCH_CONFIG0_ORIENT_Y_EN         0x40
+#define BMA400_ORIENTCH_CONFIG0_ORIENT_X_EN         0x20
+#define BMA400_ORIENTCH_CONFIG0_ORIENT_DATA_SRC     0x10
+#define BMA400_ORIENTCH_CONFIG0_ORIENT_REFU         0x0c
+
+#define BMA400_GEN1INT_CONFIG_0_GEN1_ACT_Z_EN       0x80
+#define BMA400_GEN1INT_CONFIG_0_GEN1_ACT_Y_EN       0x40
+#define BMA400_GEN1INT_CONFIG_0_GEN1_ACT_X_EN       0x20
+#define BMA400_GEN1INT_CONFIG_0_GEN1_DATA_SRC       0x10
+#define BMA400_GEN1INT_CONFIG_0_GEN1_ACT_REFU       0x0c
+#define BMA400_GEN1INT_CONFIG_0_GEN1_ACT_HYST       0x03
+
+#define BMA400_GEN1INT_CONFIG_1_GEN1_CRITERION_SEL  0x02
+#define BMA400_GEN1INT_CONFIG_1_GEN1_COMB_SEL       0x01
+
+#define BMA400_ACTCH_CONFIG1_ACTCH_Z_EN             0x80
+#define BMA400_ACTCH_CONFIG1_ACTCH_Y_EN             0x40
+#define BMA400_ACTCH_CONFIG1_ACTCH_X_EN             0x20
+#define BMA400_ACTCH_CONFIG1_ACTCH_DATA_SRC         0x10
+#define BMA400_ACTCH_CONFIG1_ACTCH_NPTS             0x0f
+
+#define BMA400_TAP_CONFIG_SEL_AXIS                  0x18
+#define BMA400_TAP_CONFIG_TAP_SENSITIVITY           0x07
+
+#define BMA400_TAP_CONFIG1_QUITE_DT                 0x30
+#define BMA400_TAP_CONFIG1_QUITE                    0x0c
+#define BMA400_TAP_CONFIG1_TICS_TH                  0x03
+
+/* Magical value that is used to initiate a full reset */
+#define BMA400_CMD_SOFT_RESET           0xb6
+#define BMA400_CMD_FIFO_FLUSH           0xb0
+#define BMA400_CMD_STEP_CNT_CLEAR       0xb1
+
+/* Get the chip ID */
+int
+bma400_get_chip_id(struct bma400 *bma400, uint8_t *chip_id);
+
+/* All three axis types */
+typedef enum {
+    AXIS_X   = 0,
+    AXIS_Y   = 1,
+    AXIS_Z   = 2,
+    AXIS_ALL = 3,
+} bma400_axis_t;
+
+struct bma400_reg_cache {
+    union {
+        uint8_t regs[64];
+        struct {
+            uint8_t acc_config0;
+            uint8_t acc_config1;
+            uint8_t acc_config2;
+            uint8_t reserved1[3];
+            uint8_t int_config0;
+            uint8_t int_config1;
+            uint8_t int1_map;
+            uint8_t int2_map;
+            uint8_t int12_map;
+            uint8_t int12_io_ctrl;
+            uint8_t reserved2[1];
+            uint8_t fifo_config0;
+            uint8_t fifo_config1;
+            uint8_t fifo_config2;
+            uint8_t fifo_pwr_config;
+            uint8_t autolowpow_0;
+            uint8_t autolowpow_1;
+            uint8_t autowakeup_0;
+            uint8_t autowakeup_1;
+            uint8_t reserved3[1];
+            uint8_t wkup_int_config0;
+            uint8_t wkup_int_config1;
+            uint8_t wkup_int_config2;
+            uint8_t wkup_int_config3;
+            uint8_t wkup_int_config4;
+            uint8_t reserved4[1];
+            uint8_t orientch_config0;
+            uint8_t orientch_config1;
+            uint8_t orientch_config2;
+            uint8_t orientch_config3;
+            uint8_t orientch_config4;
+            uint8_t orientch_config5;
+            uint8_t orientch_config6;
+            uint8_t orientch_config7;
+            uint8_t orientch_config8;
+            uint8_t orientch_config9;
+            uint8_t gen1int_config0;
+            uint8_t gen1int_config1;
+            uint8_t gen1int_config2;
+            uint8_t gen1int_config3;
+            uint8_t gen1int_config31;
+            uint8_t gen1int_config4;
+            uint8_t gen1int_config5;
+            uint8_t gen1int_config6;
+            uint8_t gen1int_config7;
+            uint8_t gen1int_config8;
+            uint8_t gen1int_config9;
+            uint8_t gen2int_config0;
+            uint8_t gen2int_config1;
+            uint8_t gen2int_config2;
+            uint8_t gen2int_config3;
+            uint8_t gen2int_config31;
+            uint8_t gen2int_config4;
+            uint8_t gen2int_config5;
+            uint8_t gen2int_config6;
+            uint8_t gen2int_config7;
+            uint8_t gen2int_config8;
+            uint8_t gen2int_config9;
+            uint8_t acth_config0;
+            uint8_t acth_config1;
+            uint8_t tap_config0;
+            uint8_t tap_config1;
+        };
+    };
+    uint64_t dirty;
+};
+
+/* Active status of all interrupts */
+struct int_status {
+    uint8_t int_stat0;
+    uint8_t int_stat1;
+    uint8_t int_stat2;
+};
+
+/* Kick off a full soft reset of the device */
+int
+bma400_soft_reset(struct bma400 *bma400);
+
+/* 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 FIFO watermark level */
+int
+bma400_get_fifo_watermark(struct bma400 *bma400,
+                          uint16_t *watermark);
+int
+bma400_set_fifo_watermark(struct bma400 *bma400,
+                          uint16_t watermark);
+
+int bma400_get_register(struct bma400 *bma400, uint8_t reg, uint8_t *data);
+int bma400_set_register(struct bma400 *bma400, uint8_t reg, uint8_t data);
+int bma400_read(struct bma400 *bma400, uint8_t reg, uint8_t *buffer, uint8_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw/drivers/sensors/bma400/src/bma400_shell.c b/hw/drivers/sensors/bma400/src/bma400_shell.c
new file mode 100755
index 0000000..82b1cf5
--- /dev/null
+++ b/hw/drivers/sensors/bma400/src/bma400_shell.c
@@ -0,0 +1,497 @@
+/*
+ * 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 <string.h>
+#include <errno.h>
+#include "os/mynewt.h"
+#include "console/console.h"
+#include "sensor/accel.h"
+#include "bma400/bma400.h"
+#include "bma400_priv.h"
+
+#if MYNEWT_VAL(BMA400_CLI) && MYNEWT_VAL(SENSOR_CLI)
+
+#include "shell/shell.h"
+#include "parse/parse.h"
+
+#define BMA400_CLI_FIRST_REGISTER 0x00
+#define BMA400_CLI_LAST_REGISTER  0x7E
+
+
+static int bma400_shell_cmd(int argc, char **argv);
+
+static struct shell_cmd bma400_shell_cmd_struct = {
+    .sc_cmd = "bma400",
+    .sc_cmd_func = bma400_shell_cmd
+};
+
+static struct bma400 *g_bma400;
+
+static int
+bma400_shell_open_device(void)
+{
+    if (g_bma400) {
+        return 0;
+    }
+
+    g_bma400 = (struct bma400 *)os_dev_open(MYNEWT_VAL(BMA400_SHELL_DEV_NAME),
+                                            1000, NULL);
+
+    return g_bma400 ? 0 : SYS_ENODEV;
+}
+
+static int
+bma400_shell_err_too_many_args(char *cmd_name)
+{
+    console_printf("Error: too many arguments for command \"%s\"\n",
+                   cmd_name);
+    return EINVAL;
+}
+
+static int
+bma400_shell_err_too_few_args(char *cmd_name)
+{
+    console_printf("Error: too few arguments for command \"%s\"\n",
+                   cmd_name);
+    return EINVAL;
+}
+
+static int
+bma400_shell_err_unknown_arg(char *cmd_name)
+{
+    console_printf("Error: unknown argument \"%s\"\n",
+                   cmd_name);
+    return EINVAL;
+}
+
+static int
+bma400_shell_err_invalid_arg(char *cmd_name)
+{
+    console_printf("Error: invalid argument \"%s\"\n",
+                   cmd_name);
+    return EINVAL;
+}
+
+static int
+bma400_shell_help(void)
+{
+    console_printf("%s cmd [args...]\n", bma400_shell_cmd_struct.sc_cmd);
+    console_printf("cmd:\n");
+    console_printf("\tr    <n_samples>\n");
+    console_printf("\tchipid\n");
+    console_printf("\tdump [nz] [ass] [step] [orient] [tap] [int] [time] [meas] [lp] [wkup] \n");
+    console_printf("\tpeek <reg>\n");
+    console_printf("\tpoke <reg> <value>\n");
+    console_printf("\ttest\n");
+
+    return 0;
+}
+
+static int
+bma400_shell_cmd_read_chipid(int argc, char **argv)
+{
+    int rc;
+    uint8_t chipid;
+
+    rc = bma400_read(g_bma400, BMA400_REG_CHIPID, &chipid, 1);
+    if (rc) {
+        goto err;
+    }
+
+    console_printf("CHIP_ID:0x%02X\n", chipid);
+
+    return 0;
+err:
+    return rc;
+}
+
+static int
+bma400_shell_cmd_read(int argc, char **argv)
+{
+    uint16_t samples = 1;
+    uint16_t val;
+    int rc;
+    char tmpstr[13];
+    float acc[3];
+
+    if (argc > 3) {
+        return bma400_shell_err_too_many_args(argv[1]);
+    }
+
+    /* Check if more than one sample requested */
+    if (argc == 3) {
+        val = parse_ll_bounds(argv[2], 1, UINT16_MAX, &rc);
+        if (rc) {
+            return bma400_shell_err_invalid_arg(argv[2]);
+        }
+        samples = val;
+    }
+
+    while (samples--) {
+
+        rc = bma400_get_accel(g_bma400, acc);
+        if (rc) {
+            console_printf("Read failed: %d\n", rc);
+            return rc;
+        }
+
+        console_printf("x:%s ", sensor_ftostr(acc[0], tmpstr, 13));
+        console_printf("y:%s ", sensor_ftostr(acc[1], tmpstr, 13));
+        console_printf("z:%s\n", sensor_ftostr(acc[2], tmpstr, 13));
+    }
+
+    return 0;
+}
+
+#define REGS(name, grp, seq) { #name, BMA400_REG_ ## name, BMA400_ ## grp, seq }
+#define REGSCFG(name, grp, seq) { #name, BMA400_REG_ ## name, BMA400_ ## grp | BMA400_CFG, seq }
+#define REGCFG(name, grp) { #name, BMA400_REG_ ## name, BMA400_ ## grp | BMA400_CFG, 0 }
+#define REG(name, grp) { #name, BMA400_REG_ ## name, BMA400_ ## grp, 0 }
+#define BIT(n) (1 << (n))
+
+typedef enum {
+    BMA400_CFG              = BIT(0),
+    BMA400_MEASUREMENT      = BIT(1),
+    BMA400_TIME             = BIT(2),
+    BMA400_FIFO             = BIT(3),
+    BMA400_STEP             = BIT(4),
+    BMA400_INT              = BIT(5),
+    BMA400_ACC              = BIT(6),
+    BMA400_AUTOLOWPOW       = BIT(7),
+    BMA400_AUTOWAKEUP       = BIT(8),
+    BMA400_ORIENT           = BIT(9),
+    BMA400_GEN1INT          = BIT(10),
+    BMA400_GEN2INT          = BIT(11),
+    BMA400_ACTIVITY         = BIT(12),
+    BMA400_TAP              = BIT(13),
+    BMA400_GLOBAL           = BIT(14),
+    BMA400_STATUS           = BIT(15),
+    BMA400_ALL              = 0xFFFF,
+} bma400_reg_grp_t;
+
+struct bma400_reg {
+    const char *reg_name;
+    uint8_t reg_addr;
+    bma400_reg_grp_t grp;
+    uint8_t seq;
+} bma400_regs[] = {
+    /* Dump all the register values for debug purposes */
+    REG(CHIPID, GLOBAL),
+    REG(ERR_REG, GLOBAL),
+    REG(STATUS, GLOBAL),
+    REGS(ACC_X_LSB, MEASUREMENT, 0),
+    REGS(ACC_X_MSB, MEASUREMENT, 1),
+    REGS(ACC_Y_LSB, MEASUREMENT, 0),
+    REGS(ACC_Y_MSB, MEASUREMENT, 1),
+    REGS(ACC_Z_LSB, MEASUREMENT, 0),
+    REGS(ACC_Z_MSB, MEASUREMENT, 1),
+    REGS(SENSOR_TIME0, TIME, 0),
+    REGS(SENSOR_TIME1, TIME, 1),
+    REGS(SENSOR_TIME2, TIME, 2),
+    REG(EVENT, STATUS),
+    REG(INT_STAT0, INT),
+    REG(INT_STAT1, INT),
+    REG(INT_STAT2, INT),
+    REG(TEMP_DATA, MEASUREMENT),
+    REGS(FIFO_LENGTH0, FIFO, 0),
+    REGS(FIFO_LENGTH1, FIFO, 1),
+    REGS(STEP_CNT_0, STEP, 0),
+    REGS(STEP_CNT_1, STEP, 1),
+    REGS(STEP_CNT_2, STEP, 2),
+    REG(STEP_STAT, STEP),
+    REGCFG(ACC_CONFIG0, ACC),
+    REGCFG(ACC_CONFIG1, ACC),
+    REGCFG(ACC_CONFIG2, ACC),
+    REGCFG(INT_CONFIG0, INT),
+    REGCFG(INT_CONFIG1, INT),
+    REGCFG(INT1_MAP, INT),
+    REGCFG(INT2_MAP, INT),
+    REGCFG(INT12_MAP, INT),
+    REGCFG(INT12_IO_CTRL, INT),
+    REGCFG(FIFO_CONFIG0, FIFO),
+    REGCFG(FIFO_CONFIG1, FIFO),
+    REGCFG(FIFO_CONFIG2, FIFO),
+    REGCFG(FIFO_PWR_CONFIG, FIFO),
+    REGCFG(AUTOLOWPOW_0, AUTOLOWPOW),
+    REGCFG(AUTOLOWPOW_1, AUTOLOWPOW),
+    REGCFG(AUTOWAKEUP_0, AUTOWAKEUP),
+    REGCFG(AUTOWAKEUP_1, AUTOWAKEUP),
+    REGCFG(WKUP_INT_CONFIG0, AUTOWAKEUP),
+    REGCFG(WKUP_INT_CONFIG1, AUTOWAKEUP),
+    REGCFG(WKUP_INT_CONFIG2, AUTOWAKEUP),
+    REGCFG(WKUP_INT_CONFIG3, AUTOWAKEUP),
+    REGCFG(WKUP_INT_CONFIG4, AUTOWAKEUP),
+    REGCFG(ORIENTCH_CONFIG0, ORIENT),
+    REGCFG(ORIENTCH_CONFIG1, ORIENT),
+    REGCFG(ORIENTCH_CONFIG3, ORIENT),
+    REGCFG(ORIENTCH_CONFIG4, ORIENT),
+    REGCFG(ORIENTCH_CONFIG5, ORIENT),
+    REGCFG(ORIENTCH_CONFIG6, ORIENT),
+    REGCFG(ORIENTCH_CONFIG7, ORIENT),
+    REGCFG(ORIENTCH_CONFIG8, ORIENT),
+    REGCFG(ORIENTCH_CONFIG9, ORIENT),
+    REGCFG(GEN1INT_CONFIG0, GEN1INT),
+    REGCFG(GEN1INT_CONFIG1, GEN1INT),
+    REGCFG(GEN1INT_CONFIG2, GEN1INT),
+    REGCFG(GEN1INT_CONFIG3, GEN1INT),
+    REGCFG(GEN1INT_CONFIG31, GEN1INT),
+    REGCFG(GEN1INT_CONFIG4, GEN1INT),
+    REGCFG(GEN1INT_CONFIG5, GEN1INT),
+    REGCFG(GEN1INT_CONFIG6, GEN1INT),
+    REGCFG(GEN1INT_CONFIG7, GEN1INT),
+    REGCFG(GEN1INT_CONFIG8, GEN1INT),
+    REGCFG(GEN1INT_CONFIG9, GEN1INT),
+    REGCFG(GEN2INT_CONFIG0, GEN2INT),
+    REGCFG(GEN2INT_CONFIG1, GEN2INT),
+    REGCFG(GEN2INT_CONFIG2, GEN2INT),
+    REGCFG(GEN2INT_CONFIG3, GEN2INT),
+    REGCFG(GEN2INT_CONFIG31, GEN2INT),
+    REGCFG(GEN2INT_CONFIG4, GEN2INT),
+    REGCFG(GEN2INT_CONFIG5, GEN2INT),
+    REGCFG(GEN2INT_CONFIG6, GEN2INT),
+    REGCFG(GEN2INT_CONFIG7, GEN2INT),
+    REGCFG(GEN2INT_CONFIG8, GEN2INT),
+    REGCFG(GEN2INT_CONFIG9, GEN2INT),
+    REGCFG(ACTCH_CONFIG0, ACTIVITY),
+    REGCFG(ACTCH_CONFIG1, ACTIVITY),
+    REGCFG(TAP_CONFIG0, TAP),
+    REGCFG(TAP_CONFIG1, TAP),
+    REG(IF_CONF, GLOBAL),
+    REG(SELF_TEST, GLOBAL),
+    REGCFG(STEP_COUNTER_CONFIG0, STEP),
+    REGCFG(STEP_COUNTER_CONFIG1, STEP),
+    REGCFG(STEP_COUNTER_CONFIG2, STEP),
+    REGCFG(STEP_COUNTER_CONFIG3, STEP),
+    REGCFG(STEP_COUNTER_CONFIG4, STEP),
+    REGCFG(STEP_COUNTER_CONFIG5, STEP),
+    REGCFG(STEP_COUNTER_CONFIG6, STEP),
+    REGCFG(STEP_COUNTER_CONFIG7, STEP),
+    REGCFG(STEP_COUNTER_CONFIG8, STEP),
+    REGCFG(STEP_COUNTER_CONFIG9, STEP),
+    REGCFG(STEP_COUNTER_CONFIG10, STEP),
+    REGCFG(STEP_COUNTER_CONFIG11, STEP),
+    REGCFG(STEP_COUNTER_CONFIG12, STEP),
+    REGCFG(STEP_COUNTER_CONFIG13, STEP),
+    REGCFG(STEP_COUNTER_CONFIG14, STEP),
+    REGCFG(STEP_COUNTER_CONFIG15, STEP),
+    REGCFG(STEP_COUNTER_CONFIG16, STEP),
+    REGCFG(STEP_COUNTER_CONFIG17, STEP),
+    REGCFG(STEP_COUNTER_CONFIG18, STEP),
+    REGCFG(STEP_COUNTER_CONFIG19, STEP),
+    REGCFG(STEP_COUNTER_CONFIG20, STEP),
+    REGCFG(STEP_COUNTER_CONFIG21, STEP),
+    REGCFG(STEP_COUNTER_CONFIG22, STEP),
+    REGCFG(STEP_COUNTER_CONFIG23, STEP),
+};
+
+static int
+bma400_shell_cmd_dump(int argc, char **argv)
+{
+    int i;
+    int rc = 0;
+    uint8_t val;
+    bma400_reg_grp_t sel = 0;
+    bool non_zero_only = false;
+
+    for (i = 1; i < argc; ++i) {
+        if (0 == strcmp(argv[i], "all")) {
+            sel = 0xFFFF;
+            non_zero_only = false;
+        } else if (0 == strcmp(argv[i], "nz")) {
+            non_zero_only = true;
+        } else if (0 == strcmp(argv[i], "acc")) {
+            sel |= BMA400_ACC;
+        } else if (0 == strcmp(argv[i], "step")) {
+            sel |= BMA400_STEP;
+        } else if (0 == strcmp(argv[i], "int")) {
+            sel |= BMA400_INT;
+        } else if (0 == strcmp(argv[i], "orient")) {
+            sel |= BMA400_ORIENT;
+        } else if (0 == strcmp(argv[i], "lp")) {
+            sel |= BMA400_AUTOLOWPOW;
+        } else if (0 == strcmp(argv[i], "wkup")) {
+            sel |= BMA400_AUTOWAKEUP;
+        } else if (0 == strcmp(argv[i], "tap")) {
+            sel |= BMA400_TAP;
+        } else if (0 == strcmp(argv[i], "time")) {
+            sel |= BMA400_TIME;
+        } else if (0 == strcmp(argv[i], "meas")) {
+            sel |= BMA400_MEASUREMENT;
+        }
+    }
+    if (sel == 0) {
+        sel = BMA400_ALL;
+    }
+    for (i = 0; rc == 0 && i < ARRAY_SIZE(bma400_regs); ++i) {
+        if (bma400_regs[i].grp & sel) {
+            rc = bma400_get_register(g_bma400, bma400_regs[i].reg_addr, &val);
+            if (rc) {
+                console_printf("Error reading register 0x%X (%s), rc = %d\n", bma400_regs[i].reg_addr,
+                               bma400_regs[i].reg_name, rc);
+            } else if (!non_zero_only || val != 0){
+                console_printf("%21s 0x%02X = %02x\n", bma400_regs[i].reg_name,
+                               bma400_regs[i].reg_addr, val);
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int
+bma400_shell_cmd_peek(int argc, char **argv)
+{
+    int rc;
+    uint8_t value;
+    uint8_t reg;
+
+    if (argc > 3) {
+        return bma400_shell_err_too_many_args(argv[1]);
+    } else if (argc < 3) {
+        return bma400_shell_err_too_few_args(argv[1]);
+    }
+
+    reg = parse_ll_bounds(argv[2], BMA400_CLI_FIRST_REGISTER, BMA400_CLI_LAST_REGISTER, &rc);
+    if (rc != 0) {
+        return bma400_shell_err_invalid_arg(argv[2]);
+    }
+
+    rc = bma400_get_register(g_bma400, reg, &value);
+    if (rc) {
+        console_printf("peek failed %d\n", rc);
+    }else{
+        console_printf("reg 0x%02X(%d) = 0x%02X\n", reg, reg, value);
+    }
+
+    return 0;
+}
+
+static int
+bma400_shell_cmd_poke(int argc, char **argv)
+{
+    int rc;
+    uint8_t reg;
+    uint8_t value;
+
+    if (argc > 4) {
+        return bma400_shell_err_too_many_args(argv[1]);
+    } else if (argc < 4) {
+        return bma400_shell_err_too_few_args(argv[1]);
+    }
+
+    reg = parse_ll_bounds(argv[2], BMA400_CLI_FIRST_REGISTER, BMA400_CLI_LAST_REGISTER, &rc);
+    if (rc != 0) {
+        return bma400_shell_err_invalid_arg(argv[2]);
+   }
+
+    value = parse_ll_bounds(argv[3], 0, 255, &rc);
+    if (rc != 0) {
+        return bma400_shell_err_invalid_arg(argv[3]);
+    }
+
+    rc = bma400_set_register(g_bma400, reg, value);
+    if (rc) {
+        console_printf("poke failed %d\n", rc);
+    }else{
+        console_printf("wrote: 0x%02X(%d) to 0x%02X\n", value, value, reg);
+    }
+
+    return 0;
+}
+
+static int
+bma400_shell_cmd_test(int argc, char **argv)
+{
+    int rc;
+    bool result = 0;
+
+    rc = bma400_self_test(g_bma400, &result);
+    if (rc) {
+        goto err;
+    }
+
+    if (result) {
+        console_printf("SELF TEST: FAILED\n");
+    } else {
+        console_printf("SELF TEST: PASSED\n");
+    }
+
+    return 0;
+err:
+    return rc;
+}
+
+static int
+bma400_shell_cmd(int argc, char **argv)
+{
+    if (argc == 1) {
+        return bma400_shell_help();
+    }
+
+    if (bma400_shell_open_device()) {
+        console_printf("Error: device not found \"%s\"\n",
+                       MYNEWT_VAL(BMA400_SHELL_DEV_NAME));
+        return 0;
+    }
+
+    /* Read command (get a new data sample) */
+    if (argc > 1 && strcmp(argv[1], "r") == 0) {
+        return bma400_shell_cmd_read(argc, argv);
+    }
+
+    /* Chip ID */
+    if (argc > 1 && strcmp(argv[1], "chipid") == 0) {
+        return bma400_shell_cmd_read_chipid(argc, argv);
+    }
+
+    /* Dump */
+    if (argc > 1 && strcmp(argv[1], "dump") == 0) {
+        return bma400_shell_cmd_dump(argc, argv);
+    }
+
+    /* Peek */
+    if (argc > 1 && strcmp(argv[1], "peek") == 0) {
+        return bma400_shell_cmd_peek(argc, argv);
+    }
+
+    /* Poke */
+    if (argc > 1 && strcmp(argv[1], "poke") == 0) {
+        return bma400_shell_cmd_poke(argc, argv);
+    }
+
+    /* Test */
+    if (argc > 1 && strcmp(argv[1], "test") == 0) {
+        return bma400_shell_cmd_test(argc, argv);
+    }
+
+    return bma400_shell_err_unknown_arg(argv[1]);
+}
+
+int
+bma400_shell_init(void)
+{
+    int rc;
+
+    rc = shell_cmd_register(&bma400_shell_cmd_struct);
+    SYSINIT_PANIC_ASSERT(rc == 0);
+
+    return rc;
+}
+
+#endif
diff --git a/hw/drivers/sensors/bma400/syscfg.yml b/hw/drivers/sensors/bma400/syscfg.yml
new file mode 100755
index 0000000..15c8b57
--- /dev/null
+++ b/hw/drivers/sensors/bma400/syscfg.yml
@@ -0,0 +1,81 @@
+#
+# 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:
+    BMA400_SPI_SUPPORT:
+        description: 'Whether BMA400 driver should support SPI interface'
+        value: 1
+    BMA400_I2C_SUPPORT:
+        description: 'Whether BMA400 driver should support I2C interface'
+        value: 1
+    BMA400_CLI:
+        description: 'Enable shell support for BMA400'
+        value: 0
+    BMA400_I2C_WDT:
+        description: 'Enable I2C watchdog functionality'
+        value: 0
+    BMA400_INT_ENABLE:
+        description: 'Enable interrupt support, necessary for events'
+        value: 1
+    BMA400_INT_CFG_ACTIVE:
+        description: 'Set 0 for active-low, 1 for active-high'
+        value: 1
+    BMA400_INT_CFG_OUTPUT:
+        description: 'Set 0 for push-pull, 1 for open-drain'
+        value: 1
+    BMA400_INT_PIN_DEVICE:
+        description: 'Interrupt pin number 1 or 2 on accelerometer device'
+        value: 1
+    BMA400_INT2_PIN_DEVICE:
+        description: 'Interrupt pin number 1 or 2 on accelerometer device'
+        value: 2
+    BMA400_LOG:
+        description: 'Enable BMA400 logging'
+        value: 0
+    BMA400_SHELL_DEV_NAME:
+        description: 'BMA400 Shell device name'
+        value: "\"bma400_0\""
+    BMA400_ITF_LOCK_TMO:
+        description: 'BMA400 interface lock timeout in milliseconds'
+        value: 1000
+    BMA400_I2C_RETRIES:
+        description: >
+            Number of retries to use for failed I2C communication.  A retry is
+            used when the BMA400 sends an unexpected NACK.
+        value: 2
+    BMA400_I2C_TIMEOUT_TICKS:
+        description: >
+            Number of OS ticks to wait for each I2C transaction to complete.
+        value: 3
+
+    ### Log settings.
+
+    BMA400_LOG_MODULE:
+        description: 'Numeric module ID to use for BMA400 log messages.'
+        value: 204
+    BMA400_LOG_LVL:
+        description: 'Minimum level for the BMA400 log.'
+        value: 1
+    BMA400_CLI_SYSINIT_STAGE:
+        description: 'Sysinit stage for the BMA400 shell'
+        value: 500
+syscfg.logs:
+    BMA400_LOG:
+        module: MYNEWT_VAL(BMA400_LOG_MODULE)
+        level: MYNEWT_VAL(BMA400_LOG_LVL)