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/22 18:24:03 UTC

[mynewt-core] branch master updated (5e25531 -> c0f7072)

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

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


    from 5e25531  hw/mcu/da1469x: Add support for both edges GPIO interrupt trigger
     new cc1504f  hw/sensors: Add driver for BMA400
     new c0f7072  hw/sensors: BMA400 sleep/wake notification

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 hw/drivers/sensors/bma400/include/bma400/bma400.h |  625 +++++++
 hw/drivers/sensors/{bma2xx => bma400}/pkg.yml     |   11 +-
 hw/drivers/sensors/bma400/src/bma400.c            | 1959 +++++++++++++++++++++
 hw/drivers/sensors/bma400/src/bma400_priv.h       |  467 +++++
 hw/drivers/sensors/bma400/src/bma400_shell.c      | 1442 +++++++++++++++
 hw/drivers/sensors/{bma2xx => bma400}/syscfg.yml  |   68 +-
 6 files changed, 4541 insertions(+), 31 deletions(-)
 create mode 100755 hw/drivers/sensors/bma400/include/bma400/bma400.h
 copy hw/drivers/sensors/{bma2xx => bma400}/pkg.yml (83%)
 mode change 100644 => 100755
 create mode 100755 hw/drivers/sensors/bma400/src/bma400.c
 create mode 100755 hw/drivers/sensors/bma400/src/bma400_priv.h
 create mode 100755 hw/drivers/sensors/bma400/src/bma400_shell.c
 copy hw/drivers/sensors/{bma2xx => bma400}/syscfg.yml (51%)
 mode change 100644 => 100755

[mynewt-core] 02/02: hw/sensors: BMA400 sleep/wake notification

Posted by je...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit c0f7072bd7c27613c867a5a155fa8e41748f9bfd
Author: Jerzy Kasenberg <je...@codecoup.pl>
AuthorDate: Fri Feb 18 14:10:48 2022 +0100

    hw/sensors: BMA400 sleep/wake notification
    
    Sleep and wake notification was not working.
    For this to work interrupt pin that is dedicated to wake state
    has to be re-armed for different edge since there is no
    sleep-change notification and some MCUs supported in mynewt
    don't have trigger for both edges so far.
---
 hw/drivers/sensors/bma400/include/bma400/bma400.h |  3 +
 hw/drivers/sensors/bma400/src/bma400.c            | 69 +++++++++++++++++++++--
 2 files changed, 66 insertions(+), 6 deletions(-)

diff --git a/hw/drivers/sensors/bma400/include/bma400/bma400.h b/hw/drivers/sensors/bma400/include/bma400/bma400.h
index b160b79..98d445b 100755
--- a/hw/drivers/sensors/bma400/include/bma400/bma400.h
+++ b/hw/drivers/sensors/bma400/include/bma400/bma400.h
@@ -25,6 +25,7 @@
 #include <sensor/sensor.h>
 #include <sensor/accel.h>
 #include <sensor/temperature.h>
+#include <hal/hal_gpio.h>
 #include "../../src/bma400_priv.h"
 
 #ifdef __cplusplus
@@ -475,6 +476,7 @@ struct bma400_int {
     bool asleep;
     /* Configured interrupts */
     struct sensor_int ints[2];
+    hal_gpio_irq_trig_t armed_trigger[2];
 };
 
 /* Device private data */
@@ -490,6 +492,7 @@ struct bma400_private_driver_data {
     /* Shadow copy of registers */
     struct bma400_reg_cache cache;
     uint8_t transact;
+    uint8_t woke;
 
     /* Active interrupt state */
     struct bma400_int intr;
diff --git a/hw/drivers/sensors/bma400/src/bma400.c b/hw/drivers/sensors/bma400/src/bma400.c
index 1c2ba1e..c13ed50 100755
--- a/hw/drivers/sensors/bma400/src/bma400.c
+++ b/hw/drivers/sensors/bma400/src/bma400.c
@@ -728,6 +728,31 @@ bma400_set_acc_cfg(struct bma400 *bma400, struct bma400_acc_cfg *cfg)
     return bma400_commit(bma400);
 }
 
+static void
+bma400_arm_interrupt(struct bma400 *bma400, bma400_int_num_t int_num, hal_gpio_irq_trig_t trig)
+{
+    struct bma400_private_driver_data *pdd;
+    pdd = &bma400->pdd;
+    int host_pin;
+    int int_ix = (int)int_num - 1;
+
+    if (int_ix >= 0 && pdd->intr.armed_trigger[int_ix] != trig) {
+        host_pin = pdd->intr.ints[int_ix].host_pin;
+        if (pdd->intr.armed_trigger[int_ix] != HAL_GPIO_TRIG_NONE) {
+            hal_gpio_irq_release(host_pin);
+        }
+
+        pdd->intr.armed_trigger[int_ix] = trig;
+        if (trig != HAL_GPIO_TRIG_NONE) {
+            hal_gpio_irq_init(host_pin,
+                              bma400_interrupt_handler, bma400,
+                              trig,
+                              HAL_GPIO_PULL_NONE);
+            hal_gpio_irq_enable(host_pin);
+        }
+    }
+}
+
 int
 bma400_set_int12_cfg(struct bma400 *bma400, struct bma400_int_pin_cfg *cfg)
 {
@@ -741,9 +766,7 @@ bma400_set_int12_cfg(struct bma400 *bma400, struct bma400_int_pin_cfg *cfg)
             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);
+            bma400_arm_interrupt(bma400, BMA400_INT1_PIN, trig);
         }
     }
     if (cfg->int2_host_pin != bma400->pdd.intr.ints[1].host_pin) {
@@ -754,9 +777,7 @@ bma400_set_int12_cfg(struct bma400 *bma400, struct bma400_int_pin_cfg *cfg)
             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_arm_interrupt(bma400, BMA400_INT2_PIN, trig);
         }
     }
 
@@ -882,6 +903,10 @@ bma400_set_wakeup(struct bma400 *bma400, struct bma400_wakeup_cfg *cfg)
     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);
 
+    if (cfg->int_num != BMA400_NO_INT_PIN) {
+        bma400->pdd.allowed_events |= SENSOR_EVENT_TYPE_SLEEP | SENSOR_EVENT_TYPE_WAKEUP;
+    }
+
     return bma400_commit(bma400);
 }
 
@@ -1658,8 +1683,13 @@ bma400_sensor_handle_interrupt(struct sensor *sensor)
     struct bma400_private_driver_data *pdd;
     struct bma400_int_status int_status;
     int rc;
+    uint8_t woke;
+    int8_t wakeup_pin;
+    int wakeup_pin_state;
+    int16_t host_wakeup_pin;
 
     bma400 = (struct bma400 *)SENSOR_GET_DEVICE(sensor);
+    wakeup_pin = (int8_t)bma400->cfg.wakeup_cfg.int_num - 1;
     pdd = &bma400->pdd;
 
     rc = bma400_get_int_status(bma400, &int_status);
@@ -1668,6 +1698,33 @@ bma400_sensor_handle_interrupt(struct sensor *sensor)
         return rc;
     }
 
+    if (wakeup_pin >= 0 &&
+        (pdd->notify_ctx.snec_evtype & (SENSOR_EVENT_TYPE_WAKEUP | SENSOR_EVENT_TYPE_SLEEP)) != 0) {
+        host_wakeup_pin = pdd->intr.ints[wakeup_pin].host_pin;
+        wakeup_pin_state = hal_gpio_read(host_wakeup_pin);
+        woke = wakeup_pin_state == pdd->intr.ints[wakeup_pin].active;
+
+        bma400_arm_interrupt(bma400, bma400->cfg.wakeup_cfg.int_num,
+                             wakeup_pin_state ? HAL_GPIO_TRIG_FALLING : HAL_GPIO_TRIG_RISING);
+
+        if (woke != pdd->woke) {
+            pdd->woke = woke;
+            /*
+             * Wakeup interrupt pin stays active whole time till device goes to sleep,
+             * notify client only once.
+             */
+            if (woke) {
+                if (pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_WAKEUP) {
+                    sensor_mgr_put_notify_evt(&pdd->notify_ctx, SENSOR_EVENT_TYPE_WAKEUP);
+                }
+            } else {
+                if (pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_SLEEP) {
+                    sensor_mgr_put_notify_evt(&pdd->notify_ctx, SENSOR_EVENT_TYPE_SLEEP);
+                }
+            }
+        }
+    }
+
     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);

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

Posted by je...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit cc1504f0451ddfb477ffb96a73dec0c79abfcb80
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 |  622 +++++++
 hw/drivers/sensors/bma400/pkg.yml                 |   42 +
 hw/drivers/sensors/bma400/src/bma400.c            | 1902 +++++++++++++++++++++
 hw/drivers/sensors/bma400/src/bma400_priv.h       |  467 +++++
 hw/drivers/sensors/bma400/src/bma400_shell.c      | 1442 ++++++++++++++++
 hw/drivers/sensors/bma400/syscfg.yml              |   83 +
 6 files changed, 4558 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..b160b79
--- /dev/null
+++ b/hw/drivers/sensors/bma400/include/bma400/bma400.h
@@ -0,0 +1,622 @@
+/*
+ * 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_acc_cfg {
+    bma400_filt1_bandwidth_t filt1_bw;
+    bma400_osr_lp_t osr_lp;
+    bma400_power_mode_t power_mode_conf;
+    bma400_g_range_t acc_range;
+    bma400_oversampling_t osr;
+    bma400_odr_t acc_odr;
+    bma400_data_src_t data_src_reg;
+};
+
+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 (in 2.5ms units)
+     * 0-4095 (0-10.237s)
+     */
+    uint16_t timeout_threshold;
+    bma400_autolowpow_timeout_t timeout;
+    /* data ready as source for auto-low-power condition */
+    uint8_t drdy_lowpow_trig : 1;
+    /* generic interrupt 1 as source for auto-low-power condition */
+    uint8_t trig_gen1 : 1;
+};
+
+struct bma400_autowakeup_cfg {
+    /*
+     * auto-wake-up timeout threshold (in 2.5ms units)
+     * 0-4095 (0-10.237s)
+     */
+    /* wake-up timeout threshold */
+    uint16_t timeout_threshold;
+    /* wake-up timeout as source for auto-wake-up condition */
+    uint8_t wkup_timeout: 1;
+    /* wake-up interrupt as source for auto-wake-up condition */
+    uint8_t wkup_int: 1;
+};
+
+struct bma400_wakeup_cfg {
+    bma400_wkup_refu_t wkup_refu;
+    /* number of data samples used for interrupt condition evaluation */
+    uint8_t num_of_samples;
+    /* enable wake-up interrupt for x channel */
+    uint8_t wkup_x_en : 1;
+    /* enable wake-up interrupt for y channel */
+    uint8_t wkup_y_en : 1;
+    /* enable wake-up interrupt for z channel */
+    uint8_t wkup_z_en : 1;
+
+    uint8_t int_wkup_thres;
+    int8_t int_wkup_refx;
+    int8_t int_wkup_refy;
+    int8_t int_wkup_refz;
+
+    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_BELOW_THRESHOLD = BMA400_GEN_CRITERION_INACTIVITY,
+    BMA400_GEN_CRITERION_ACTIVITY,
+    BMA400_GEN_CRITERION_ABOVE_THRESHOLD = 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 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;
+
+    /* Accelerometer configuration */
+    struct bma400_acc_cfg acc_cfg;
+    /* Interrupt configuration */
+    struct bma400_int_pin_cfg int_pin_cfg;
+
+    /* Tap (double & single) event configuration */
+    struct bma400_tap_cfg tap_cfg;
+    /* Orientation detection configuration */
+    struct bma400_orient_cfg orient_cfg;
+    /* Auto low power configuration */
+    struct bma400_autolowpow_cfg autolowpow_cfg;
+    /* Auto wakeup configuration */
+    struct bma400_autowakeup_cfg autowakeup_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 bma400_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_read_fifo(struct bma400 *bma400, uint16_t *fifo_count, struct sensor_accel_data *sad);
+
+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]);
+
+int bma400_set_power_mode(struct bma400 *bma400, bma400_power_mode_t mode);
+int bma400_get_power_mode(struct bma400 *bma400, bma400_power_mode_t *power_mode);
+
+int bma400_set_odr(struct bma400 *bma400, bma400_odr_t odr);
+int bma400_set_data_src(struct bma400 *bma400, bma400_data_src_t src);
+
+int bma400_set_acc_cfg(struct bma400 *bma400, struct bma400_acc_cfg *cfg);
+
+/**
+ * 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..1c2ba1e
--- /dev/null
+++ b/hw/drivers/sensors/bma400/src/bma400.c
@@ -0,0 +1,1902 @@
+/*
+ * 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))
+
+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
+};
+
+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 */
+            j = 0;
+        }
+    }
+    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;
+    uint8_t *cache_ptr = NULL;
+
+    if (reg >= BMA400_REG_ACC_CONFIG0 && reg <= BMA400_REG_TAP_CONFIG1) {
+        cache_ptr = &bma400->pdd.cache.regs[reg - BMA400_REG_ACC_CONFIG0];
+    }
+
+    if (cache_ptr && !bma400->pdd.cache.always_read) {
+        *data = *cache_ptr;
+        rc = 0;
+    } else {
+        rc = bma400_read(bma400, reg, data, 1);
+        if (rc == 0 && cache_ptr) {
+            *cache_ptr = *data;
+        }
+    }
+
+    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;
+}
+
+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);
+}
+
+/**
+ * Convert acceleration data from 16 bits signed value to floating point number
+ *
+ * @param int32g gravity (7FFF = +32G, 0001 = -32G)
+ * @return gravity in m/s^2
+ */
+static float
+convert_int32g_to_f(int16_t int32g)
+{
+    return int32g * (STANDARD_ACCEL_GRAVITY / 1024);
+}
+
+/**
+ * Convert data from ACC_x_LSB, ACC_x_MSB to signed value in range (7FFF = +32G, 0001 = -32G)
+ * 12 bits data is not signed extended when read from registers.
+ *
+ * @param data  bytes read from ACC_x_LSB, ACC_x_MSB registers
+ * @param range range configured in ACC_CONFIG1 register
+ * @return gravity value sign extended
+ */
+static int16_t
+convert_raw_to_int32g(const uint8_t *data, bma400_g_range_t range)
+{
+    return ((int16_t)((data[1] << 12) | (data[0] << 4))) >> (4 - range);
+}
+
+/**
+ * Convert 2 bytes data read from FIFO to signed value in range (7FFF = +32G, 0001 = -32G)
+ * @param data  two bytes read from FIFO
+ * @param range range configured in ACC_CONFIG1 register
+ * @return gravity value sign extended
+ */
+static int16_t
+convert_fifo_to_int32g(uint8_t lo, uint8_t hi, bma400_g_range_t range)
+{
+    return ((int16_t)((hi << 8) | lo)) >> (4 - range);
+}
+
+bma400_g_range_t
+bma400_get_cached_range(struct bma400 *bma400)
+{
+    return (bma400->pdd.cache.acc_config1 & BMA400_ACC_CONFIG1_ACC_RANGE) >> __builtin_ctz(BMA400_ACC_CONFIG1_ACC_RANGE);
+}
+
+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) {
+        *accel_data = convert_int32g_to_f(convert_raw_to_int32g(data, bma400_get_cached_range(bma400)));
+    }
+
+    return rc;
+}
+
+/**
+ * Reads acc data
+ *
+ * @param bma400     the device
+ * @param accel_data 3 axis integer data
+ * @return 0 on success, non-zero on failure.
+ */
+int
+bma400_get_accel_int_32g(struct bma400 *bma400, int16_t accel_data[3])
+{
+    uint8_t data[6];
+    int rc;
+    uint8_t range;
+
+    rc = bma400_get_register_field(bma400, BMA400_REG_ACC_CONFIG0, BMA400_ACC_CONFIG1_ACC_RANGE, &range);
+    if (rc) {
+        goto end;
+    }
+
+    rc = bma400_read(bma400, BMA400_REG_ACC_X_LSB, data, sizeof(data));
+    if (rc) {
+        goto end;
+    }
+
+    /* Shift left to remove unused bits, then shift right to saturate with range 32g */
+    accel_data[0] = convert_raw_to_int32g(&data[0], range);
+    accel_data[1] = convert_raw_to_int32g(&data[2], range);
+    accel_data[2] = convert_raw_to_int32g(&data[4], range);
+
+end:
+    return rc;
+}
+
+int
+bma400_get_accel(struct bma400 *bma400, float accel_data[3])
+{
+    int16_t data[3];
+    int rc;
+
+    rc = bma400_get_accel_int_32g(bma400, data);
+    if (rc == 0) {
+        accel_data[0] = convert_int32g_to_f(data[0]);
+        accel_data[1] = convert_int32g_to_f(data[1]);
+        accel_data[2] = convert_int32g_to_f(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 bma400_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_acc_cfg(struct bma400 *bma400, struct bma400_acc_cfg *cfg)
+{
+    bma400_begin_transact(bma400);
+
+    bma400_set_filt1_bandwidth(bma400, cfg->filt1_bw);
+    bma400_set_register_field(bma400, BMA400_REG_ACC_CONFIG0, BMA400_ACC_CONFIG0_OSR_LP, cfg->osr_lp);
+    bma400_set_power_mode(bma400, cfg->power_mode_conf);
+
+    bma400_set_g_range(bma400, cfg->acc_range);
+    bma400_set_odr(bma400, cfg->acc_odr);
+
+    bma400_set_data_src(bma400, cfg->data_src_reg);
+
+    return bma400_commit(bma400);
+}
+
+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 (cfg->int1_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 (cfg->int2_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);
+    /* If Gen2int is selected source of resetting low power timeout enabled it in INT_CONFIG0 register */
+    if (cfg->timeout == BMA400_AUTOLOWPOW_TIMEOUT_2) {
+        bma400_set_register_field(bma400, BMA400_REG_INT_CONFIG0, BMA400_INT_CONFIG0_GEN2_INT_EN, 1);
+    }
+
+    return bma400_commit(bma400);
+}
+
+int
+bma400_set_autowakeup(struct bma400 *bma400, struct bma400_autowakeup_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_AUTOWAKEUP_1, BMA400_AUTOWAKEUP_1_WKUP_INT, cfg->wkup_int);
+
+    return bma400_commit(bma400);
+}
+
+int
+bma400_set_wakeup(struct bma400 *bma400, struct bma400_wakeup_cfg *cfg)
+{
+    bma400_begin_transact(bma400);
+
+    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_CONFIG0_GEN1_ACT_Z_EN, cfg->gen_act_z_en);
+    bma400_set_register_field(bma400, BMA400_REG_GEN1INT_CONFIG0 + gen_int_off, BMA400_GEN1INT_CONFIG0_GEN1_ACT_Y_EN, cfg->gen_act_y_en);
+    bma400_set_register_field(bma400, BMA400_REG_GEN1INT_CONFIG0 + gen_int_off, BMA400_GEN1INT_CONFIG0_GEN1_ACT_X_EN, cfg->gen_act_x_en);
+    bma400_set_register_field(bma400, BMA400_REG_GEN1INT_CONFIG0 + gen_int_off, BMA400_GEN1INT_CONFIG0_GEN1_DATA_SRC, cfg->gen_data_src);
+    bma400_set_register_field(bma400, BMA400_REG_GEN1INT_CONFIG0 + gen_int_off, BMA400_GEN1INT_CONFIG0_GEN1_ACT_REFU, cfg->gen_act_refu);
+    bma400_set_register_field(bma400, BMA400_REG_GEN1INT_CONFIG0 + gen_int_off, BMA400_GEN1INT_CONFIG0_GEN1_ACT_HYST, cfg->gen_act_hyst);
+    bma400_set_register_field(bma400, BMA400_REG_GEN1INT_CONFIG1 + gen_int_off, BMA400_GEN1INT_CONFIG1_GEN1_CRITERION_SEL, cfg->gen_criterion_sel);
+    bma400_set_register_field(bma400, BMA400_REG_GEN1INT_CONFIG1 + gen_int_off, BMA400_GEN1INT_CONFIG1_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_QUIET, cfg->quite);
+    bma400_set_register_field(bma400, BMA400_REG_TAP_CONFIG1, BMA400_TAP_CONFIG1_QUIET_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_CONFIG0_FIFO_Z_EN, cfg->fifo_z_en);
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_CONFIG0, BMA400_FIFO_CONFIG0_FIFO_Y_EN, cfg->fifo_y_en);
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_CONFIG0, BMA400_FIFO_CONFIG0_FIFO_X_EN, cfg->fifo_x_en);
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_CONFIG0, BMA400_FIFO_CONFIG0_FIFO_8BIT_EN, cfg->fifo_8bit_en);
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_CONFIG0, BMA400_FIFO_CONFIG0_FIFO_DATA_SRC, cfg->fifo_data_src);
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_CONFIG0, BMA400_FIFO_CONFIG0_FIFO_TIME_EN, cfg->fifo_time_en);
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_CONFIG0, BMA400_FIFO_CONFIG0_FIFO_STOP_ON_FULL, cfg->fifo_stop_on_full);
+    bma400_set_register_field(bma400, BMA400_REG_FIFO_CONFIG0, BMA400_FIFO_CONFIG0_AUTO_FLUSH, cfg->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];
+    int16_t acc_32g;
+    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);
+    bma400_g_range_t range = bma400_get_cached_range(bma400);
+
+    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] & 0xE0) {
+            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) {
+                        acc_32g = convert_fifo_to_int32g(0, data[1], range);
+                    } else {
+                        acc_32g = convert_fifo_to_int32g(data[1], data[2], range);
+                    }
+                    sad->sad_x = convert_int32g_to_f(acc_32g);
+                }
+                if (cfg->fifo_y_en) {
+                    sad->sad_y_is_valid = 1;
+                    if (cfg->fifo_8bit_en) {
+                        acc_32g = convert_fifo_to_int32g(0, data[2], range);
+                    } else {
+                        acc_32g = convert_fifo_to_int32g(data[3], data[4], range);
+                    }
+                    sad->sad_y = convert_int32g_to_f(acc_32g);
+                }
+                if (cfg->fifo_z_en) {
+                    sad->sad_z_is_valid = 1;
+                    if (cfg->fifo_8bit_en) {
+                        acc_32g = convert_fifo_to_int32g(0, data[3], range);
+                    } else {
+                        acc_32g = convert_fifo_to_int32g(data[5], data[6], range);
+                    }
+                    sad->sad_z = convert_int32g_to_f(acc_32g);
+                }
+                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_acc_cfg(bma400, &cfg->acc_cfg);
+    bma400_set_int12_cfg(bma400, &cfg->int_pin_cfg);
+    bma400_set_fifo_cfg(bma400, &bma400->cfg.fifo_cfg);
+    bma400_set_autolowpow_mode(bma400, &bma400->cfg.autolowpow_cfg);
+    bma400_set_autowakeup(bma400, &bma400->cfg.autowakeup_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]);
+
+    rc = bma400_commit(bma400);
+
+    return rc;
+}
+
+#if MYNEWT_VAL(BMA400_INT_ENABLE)
+
+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->intr.ints[0].host_pin >= 0) {
+            hal_gpio_irq_enable(pdd->intr.ints[0].host_pin);
+        }
+        if (pdd->intr.ints[1].host_pin >= 0) {
+            hal_gpio_irq_enable(pdd->intr.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->intr.ints[0].host_pin);
+        }
+        if (pdd->interrupt->ints[1].host_pin >= 0) {
+            hal_gpio_irq_enable(pdd->intr.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;
+    int i;
+    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;
+    uint8_t old_config[17];
+    struct bma400_int_status int_status;
+
+    pdd = &bma400->pdd;
+
+    memcpy(old_config, pdd->cache.regs, sizeof(old_config));
+
+    stop_ticks = 0;
+
+    bma400_begin_transact(bma400);
+    /* Clear int */
+    bma400_get_int_status(bma400, &int_status);
+    bma400_set_power_mode(bma400, BMA400_POWER_MODE_NORMAL);
+    bma400_set_register(bma400, BMA400_REG_AUTOLOWPOW_1, 0);
+    bma400_set_register(bma400, BMA400_REG_INT1_MAP, BMA400_INT1_MAP_DRDY_INT1);
+    bma400_set_register(bma400, BMA400_REG_INT_CONFIG0, BMA400_INT_CONFIG0_DRDY_INT_EN);
+    bma400_set_register(bma400, BMA400_REG_INT_CONFIG1, 0);
+
+    rc = bma400_commit(bma400);
+
+#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
+
+    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;
+        }
+    }
+
+done:
+#if MYNEWT_VAL(BMA400_INT_ENABLE)
+    pdd->interrupt = NULL;
+    disable_intpin(bma400);
+#endif
+    bma400_begin_transact(bma400);
+    for (i = 0; i < sizeof(old_config); ++i) {
+        (void)bma400_set_register(bma400, BMA400_REG_ACC_CONFIG0 + i, old_config[i]);
+    }
+    (void)bma400_commit(bma400);
+
+    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_INT_EN, on);
+    }
+    if (sensor_event_type == SENSOR_EVENT_TYPE_ORIENT_CHANGE ||
+        sensor_event_type == SENSOR_EVENT_TYPE_ORIENT_X_CHANGE ||
+        sensor_event_type == SENSOR_EVENT_TYPE_ORIENT_Y_CHANGE ||
+        sensor_event_type == SENSOR_EVENT_TYPE_ORIENT_Z_CHANGE ||
+        sensor_event_type == SENSOR_EVENT_TYPE_ORIENT_X_H_CHANGE ||
+        sensor_event_type == SENSOR_EVENT_TYPE_ORIENT_Y_H_CHANGE ||
+        sensor_event_type == SENSOR_EVENT_TYPE_ORIENT_Z_H_CHANGE ||
+        sensor_event_type == SENSOR_EVENT_TYPE_ORIENT_X_L_CHANGE ||
+        sensor_event_type == SENSOR_EVENT_TYPE_ORIENT_Y_L_CHANGE ||
+        sensor_event_type == SENSOR_EVENT_TYPE_ORIENT_Z_L_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_process_orientation_change(struct bma400 *bma400)
+{
+    struct bma400_private_driver_data *pdd = &bma400->pdd;
+    int16_t accel[3];
+    uint8_t refu[6] = {0};
+    int max_accel_axis = 0;
+    int max_accel;
+    int rc;
+
+    rc = bma400_get_accel_int_32g(bma400, accel);
+    if (rc == 0) {
+        max_accel = abs(accel[0]);
+        if (max_accel < abs(accel[1])) {
+            max_accel = abs(accel[1]);
+            max_accel_axis = 1;
+        }
+        if (max_accel < abs(accel[2])) {
+            max_accel = abs(accel[2]);
+            max_accel_axis = 2;
+        }
+        if (accel[max_accel_axis] < 0) {
+            max_accel = -max_accel;
+        }
+        /* When manual update is selected write refu */
+        if (0 == (bma400->pdd.cache.orientch_config0 & BMA400_ORIENTCH_CONFIG0_ORIENT_REFU)) {
+            refu[max_accel_axis * 2] = (uint8_t)max_accel;
+            refu[max_accel_axis * 2 + 1] = (uint8_t)(max_accel >> 8);
+            bma400_write(bma400, BMA400_REG_ORIENTCH_CONFIG4, refu, 6);
+        }
+
+        if ((pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_ORIENT_X_H_CHANGE) &&
+            max_accel_axis == 0 && accel[0] > 0) {
+            sensor_mgr_put_notify_evt(&pdd->notify_ctx, SENSOR_EVENT_TYPE_ORIENT_X_H_CHANGE);
+        } else if ((pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_ORIENT_X_L_CHANGE) &&
+            max_accel_axis == 0 && accel[0] < 0) {
+            sensor_mgr_put_notify_evt(&pdd->notify_ctx, SENSOR_EVENT_TYPE_ORIENT_X_L_CHANGE);
+        }
+        if ((pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_ORIENT_Y_H_CHANGE) &&
+            max_accel_axis == 1 && accel[1] > 0) {
+            sensor_mgr_put_notify_evt(&pdd->notify_ctx, SENSOR_EVENT_TYPE_ORIENT_Y_H_CHANGE);
+        } else if ((pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_ORIENT_Y_L_CHANGE) &&
+            max_accel_axis == 1 && accel[1] < 0) {
+            sensor_mgr_put_notify_evt(&pdd->notify_ctx, SENSOR_EVENT_TYPE_ORIENT_Y_L_CHANGE);
+        }
+        if ((pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_ORIENT_Z_H_CHANGE) &&
+            max_accel_axis == 2 && accel[2] > 0) {
+            sensor_mgr_put_notify_evt(&pdd->notify_ctx, SENSOR_EVENT_TYPE_ORIENT_Z_H_CHANGE);
+        } else if ((pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_ORIENT_Z_L_CHANGE) &&
+            max_accel_axis == 2 && accel[2] < 0) {
+            sensor_mgr_put_notify_evt(&pdd->notify_ctx, SENSOR_EVENT_TYPE_ORIENT_Z_L_CHANGE);
+        }
+        if ((pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_ORIENT_CHANGE)) {
+            sensor_mgr_put_notify_evt(&pdd->notify_ctx, SENSOR_EVENT_TYPE_ORIENT_CHANGE);
+        }
+    }
+    return rc;
+}
+
+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 bma400_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);
+    }
+    if ((pdd->notify_ctx.snec_evtype & (SENSOR_EVENT_TYPE_ORIENT_CHANGE |
+            SENSOR_EVENT_TYPE_ORIENT_X_CHANGE |
+            SENSOR_EVENT_TYPE_ORIENT_Y_CHANGE |
+            SENSOR_EVENT_TYPE_ORIENT_Z_CHANGE |
+            SENSOR_EVENT_TYPE_ORIENT_X_H_CHANGE |
+            SENSOR_EVENT_TYPE_ORIENT_Y_H_CHANGE |
+            SENSOR_EVENT_TYPE_ORIENT_Z_H_CHANGE |
+            SENSOR_EVENT_TYPE_ORIENT_X_L_CHANGE |
+            SENSOR_EVENT_TYPE_ORIENT_Y_L_CHANGE |
+            SENSOR_EVENT_TYPE_ORIENT_Z_L_CHANGE)) &&
+        (int_status.int_stat0 & BMA400_INT_STAT0_ORIENTCH_INT_STAT)) {
+        rc = bma400_process_orientation_change(bma400);
+    }
+
+    return rc;
+#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..023c253
--- /dev/null
+++ b/hw/drivers/sensors/bma400/src/bma400_priv.h
@@ -0,0 +1,467 @@
+/*
+ * 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             0x04
+#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_STEP_STAT_STEP_STAT_FIELD            0x03
+
+#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_INT_EN             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_CONFIG0_FIFO_Z_EN               0x80
+#define BMA400_FIFO_CONFIG0_FIFO_Y_EN               0x40
+#define BMA400_FIFO_CONFIG0_FIFO_X_EN               0x20
+#define BMA400_FIFO_CONFIG0_FIFO_8BIT_EN            0x10
+#define BMA400_FIFO_CONFIG0_FIFO_DATA_SRC           0x08
+#define BMA400_FIFO_CONFIG0_FIFO_TIME_EN            0x04
+#define BMA400_FIFO_CONFIG0_FIFO_STOP_ON_FULL       0x02
+#define BMA400_FIFO_CONFIG0_AUTO_FLUSH              0x01
+
+#define BMA400_FIFO_PWR_CONFIG_FIFO_READ_DISABLE    0x01
+
+#define BMA400_AUTOLOWPOW_0_AUTO_LP_TIMEOUT_THRES   0xFF
+#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    0xFF
+#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_CONFIG0_GEN1_ACT_Z_EN        0x80
+#define BMA400_GEN1INT_CONFIG0_GEN1_ACT_Y_EN        0x40
+#define BMA400_GEN1INT_CONFIG0_GEN1_ACT_X_EN        0x20
+#define BMA400_GEN1INT_CONFIG0_GEN1_DATA_SRC        0x10
+#define BMA400_GEN1INT_CONFIG0_GEN1_ACT_REFU        0x0c
+#define BMA400_GEN1INT_CONFIG0_GEN1_ACT_HYST        0x03
+
+#define BMA400_GEN1INT_CONFIG1_GEN1_CRITERION_SEL   0x02
+#define BMA400_GEN1INT_CONFIG1_GEN1_COMB_SEL        0x01
+
+#define BMA400_GEN2INT_CONFIG0_GEN2_ACT_Z_EN        0x80
+#define BMA400_GEN2INT_CONFIG0_GEN2_ACT_Y_EN        0x40
+#define BMA400_GEN2INT_CONFIG0_GEN2_ACT_X_EN        0x20
+#define BMA400_GEN2INT_CONFIG0_GEN2_DATA_SRC        0x10
+#define BMA400_GEN2INT_CONFIG0_GEN2_ACT_REFU        0x0c
+#define BMA400_GEN2INT_CONFIG0_GEN2_ACT_HYST        0x03
+
+#define BMA400_GEN2INT_CONFIG1_GEN2_CRITERION_SEL   0x02
+#define BMA400_GEN2INT_CONFIG1_GEN2_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_QUIET_DT                 0x30
+#define BMA400_TAP_CONFIG1_QUIET                    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 reserved5[1];
+            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;
+    bool always_read;
+};
+
+/* Active status of all interrupts */
+struct bma400_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_set_register_field(struct bma400 *bma400, uint8_t reg,
+                              uint8_t field_mask, uint8_t field_val);
+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..e1aee59
--- /dev/null
+++ b/hw/drivers/sensors/bma400/src/bma400_shell.c
@@ -0,0 +1,1442 @@
+/*
+ * 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);
+
+#if MYNEWT_VAL(SHELL_CMD_HELP)
+#define HELP(a) &(bma400_##a##_help)
+
+const struct shell_param dump_params[] = {
+    { "nz",     "show registers if not zero" },
+    { "acc",    "show ACC_CONFIGx" },
+    { "step",   "show STEP_CONFIGxx" },
+    { "orient", "show ORIENT_CONFIGx" },
+    { "tap",    "show TAP_CONFIGx" },
+    { "int",    "show INT_xxxx" },
+    { "gen",    "show GENyINTx" },
+    { "gen1",   "show GEN1INTx" },
+    { "gen2",   "show GEN2INTx" },
+    { "time",   "show TIMEx" },
+    { "meas",   "show ACC_x_LSB/MSB" },
+    { "lp",     "show AUTOLOWPOW_x" },
+    { "wkup",   "show WKUP_INT_CONFIGxx" },
+    { NULL, NULL },
+};
+
+static const struct shell_cmd_help bma400_dump_help = {
+    .summary = "Displays bma400 registers",
+    .usage = "dump "
+#if MYNEWT_VAL(BMA400_CLI_DECODE)
+        "[decode] "
+#endif
+    "[all] [nz] [acc] [step] [orient] [tap] [int] [gen[1|2]] [time] [meas] [lp] [wkup]",
+    .params = dump_params,
+};
+
+#if MYNEWT_VAL(BMA400_CLI_DECODE)
+static const struct shell_cmd_help bma400_decode_help = {
+    .summary = "Enables or disables decoding of registers",
+    .usage = "decode 1 | 0",
+    .params = NULL,
+};
+#endif
+
+static const struct shell_cmd_help bma400_r_help = {
+    .summary = "Read sensor data",
+    .usage = "r <num>",
+    .params = NULL,
+};
+
+static const struct shell_cmd_help bma400_normal_help = {
+    .summary = "Switches to normal mode",
+    .usage = NULL,
+    .params = NULL,
+};
+
+static const struct shell_cmd_help bma400_lp_help = {
+    .summary = "Switches to low power mode",
+    .usage = NULL,
+    .params = NULL,
+};
+
+static const struct shell_cmd_help bma400_sleep_help = {
+    .summary = "Switches to sleep mode",
+    .usage = NULL,
+    .params = NULL,
+};
+
+static const struct shell_cmd_help bma400_peek_help = {
+    .summary = "Read single register value",
+    .usage = "peek <addr>",
+    .params = NULL,
+};
+
+static const struct shell_cmd_help bma400_poke_help = {
+    .summary = "Write single register value",
+    .usage = "poke <addr> <val>",
+    .params = NULL,
+};
+
+static const struct shell_cmd_help bma400_fifo_help = {
+    .summary = "Dumps fifo",
+    .usage = NULL,
+    .params = NULL,
+};
+
+static const struct shell_cmd_help bma400_test_help = {
+    .summary = "Runs self-test",
+    .usage = NULL,
+    .params = NULL,
+};
+
+static const struct shell_cmd_help bma400_reg_cmd_help = {
+    .summary = "Reads or write register",
+    .usage = "<reg_name> [<reg_value>]",
+    .params = NULL,
+};
+
+#if MYNEWT_VAL(bma400_USE_CHARGE_CONTROL)
+static const struct shell_cmd_help bma400_listen_help = {
+    .summary = "Starts or stops charging state notifications",
+    .usage = "listen start | stop",
+    .params = NULL,
+};
+#endif
+
+#else
+#define HELP(a) NULL
+#endif
+
+static struct shell_cmd bma400_shell_cmd_struct = {
+    .sc_cmd = "bma400",
+    .sc_cmd_func = bma400_shell_cmd
+};
+
+static struct bma400 *bma400_shell_device;
+
+static int
+bma400_shell_open_device(void)
+{
+    if (bma400_shell_device) {
+        return 0;
+    }
+
+    bma400_shell_device = (struct bma400 *)os_dev_open(MYNEWT_VAL(BMA400_SHELL_DEV_NAME),
+                                                       1000, NULL);
+
+    if (bma400_shell_device) {
+        bma400_shell_device->pdd.cache.always_read = true;
+    }
+    return bma400_shell_device ? 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] [acc] [step] [orient] [tap] [int] [time] [meas] [lp] [wkup] \n");
+    console_printf("\tpeek <reg>\n");
+    console_printf("\tpoke <reg> <value>\n");
+    console_printf("\tnormal\n");
+    console_printf("\tsleep\n");
+    console_printf("\tlp\n");
+    console_printf("\tfifo\n");
+    console_printf("\ttest\n");
+
+    return 0;
+}
+
+static int
+bma400_shell_read(uint8_t reg, uint8_t *buffer, uint8_t len)
+{
+    int rc = bma400_shell_open_device();
+    if (rc == 0) {
+        rc = bma400_read(bma400_shell_device, reg, buffer, len);
+    }
+    return rc;
+}
+
+static int
+bma400_shell_get_register(uint8_t reg, uint8_t *val)
+{
+    int rc = bma400_shell_open_device();
+    if (rc == 0) {
+        rc = bma400_get_register(bma400_shell_device, reg, val);
+    }
+    return rc;
+}
+
+static int
+bma400_shell_set_register(uint8_t reg, uint8_t val)
+{
+    int rc = bma400_shell_open_device();
+    if (rc == 0) {
+        rc = bma400_set_register(bma400_shell_device, reg, val);
+    }
+    return rc;
+}
+
+static int
+bma400_shell_set_register_field(uint8_t reg, uint8_t field_mask, uint8_t field_val)
+{
+    int rc = bma400_shell_open_device();
+    if (rc == 0) {
+        rc = bma400_set_register_field(bma400_shell_device, reg, field_mask, field_val);
+    }
+    return rc;
+}
+
+static int
+bma400_shell_self_test(bool *self_test_fail)
+{
+    int rc = bma400_shell_open_device();
+    if (rc == 0) {
+        rc = bma400_self_test(bma400_shell_device, self_test_fail);
+    }
+    return rc;
+}
+
+static int
+bma400_shell_get_accel(float accel_data[3])
+{
+    int rc = bma400_shell_open_device();
+    if (rc == 0) {
+        rc = bma400_get_accel(bma400_shell_device, accel_data);
+    }
+    return rc;
+}
+
+static int
+bma400_shell_get_fifo_count(uint16_t *fifo_bytes)
+{
+    int rc = bma400_shell_open_device();
+    if (rc == 0) {
+        rc = bma400_get_fifo_count(bma400_shell_device, fifo_bytes);
+    }
+    return rc;
+}
+
+static int
+bma400_shell_read_fifo(uint16_t *fifo_count, struct sensor_accel_data *sad)
+{
+    int rc = bma400_shell_open_device();
+    if (rc == 0) {
+        rc = bma400_read_fifo(bma400_shell_device, fifo_count, sad);
+    }
+    return rc;
+}
+
+static int
+bma400_shell_cmd_read_chipid(int argc, char **argv)
+{
+    int rc;
+    uint8_t chipid;
+    (void)argc;
+    (void)argv;
+
+    rc = bma400_shell_read(BMA400_REG_CHIPID, &chipid, 1);
+    if (rc == 0) {
+        console_printf("CHIP_ID:0x%02X\n", chipid);
+    }
+
+    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 > 2) {
+        return bma400_shell_err_too_many_args(argv[1]);
+    }
+
+    /* Check if more than one sample requested */
+    if (argc == 2) {
+        val = parse_ll_bounds(argv[1], 1, UINT16_MAX, &rc);
+        if (rc) {
+            return bma400_shell_err_invalid_arg(argv[2]);
+        }
+        samples = val;
+    }
+
+    while (samples--) {
+
+        rc = bma400_shell_get_accel(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 BIT(n) (1 << (n))
+
+typedef enum {
+    GRP_CFG              = BIT(0),
+    GRP_MEASUREMENT      = BIT(1),
+    GRP_TIME             = BIT(2),
+    GRP_FIFO             = BIT(3),
+    GRP_STEP             = BIT(4),
+    GRP_INT              = BIT(5),
+    GRP_ACC              = BIT(6),
+    GRP_AUTOLOWPOW       = BIT(7),
+    GRP_AUTOWAKEUP       = BIT(8),
+    GRP_ORIENT           = BIT(9),
+    GRP_GEN1INT          = BIT(10),
+    GRP_GEN2INT          = BIT(11),
+    GRP_ACTIVITY         = BIT(12),
+    GRP_TAP              = BIT(13),
+    GRP_GLOBAL           = BIT(14),
+    GRP_STATUS           = BIT(15),
+    GRP_ALL              = 0xFFFF,
+} bma400_reg_grp_t;
+
+/*
+ * Struct for field name description.
+ * Used for argument validation and field decoding
+ */
+struct reg_field {
+    /* Name of field */
+    const char *fld_name;
+    bool fld_show_bits;
+    /* Mask of bit field to set or extract */
+    uint8_t fld_mask;
+    /* Function that will convert register value to descriptive string */
+    const char *(*fld_decode_value)(const struct reg_field *field,
+                                    uint8_t reg_val, char *buf);
+    /* Argument that could be used by above function */
+    const void *fld_arg;
+};
+
+struct bma400_reg {
+    const char *reg_name;
+    uint8_t reg_addr;
+    bma400_reg_grp_t reg_grp;
+    uint8_t seq;
+    /* Array of bit fields */
+    const struct reg_field *fields;
+};
+
+#if MYNEWT_VAL(BMA400_CLI_DECODE)
+
+static bool bma400_cli_decode_fields = true;
+
+/* Change ix value to string from table.
+ * Table is NULL terminated. Access outside of range will result in
+ * returning ??? string
+ */
+static const char *
+val_decode_from_table(const char *const tab[], int ix)
+{
+    while (ix && tab[ix]) {
+        ix--;
+        tab++;
+    }
+    if (tab[0]) {
+        return tab[0];
+    } else {
+        return "???";
+    }
+}
+
+/* Decode bit field using table with mapped values */
+static const char *
+reg_decode_from_table(const struct reg_field *field,
+                      uint8_t reg_val, char *buf)
+{
+    uint8_t val = (reg_val & field->fld_mask) >> __builtin_ctz(field->fld_mask);
+    const char *const *table = field->fld_arg;
+
+    return strcpy(buf, val_decode_from_table(table, val));
+}
+
+#define FIELD_NUM(reg, field) { .fld_name = #field, \
+    .fld_show_bits = 1, .fld_mask = BMA400_##reg##_##field }
+#define FIELD_TAB(reg, field, tab) { .fld_name = #field, \
+    .fld_show_bits = 1, .fld_mask = BMA400_##reg##_##field, .fld_decode_value = (reg_decode_from_table), .fld_arg = (tab) }
+#define FIELD_FUN(reg, field, fun, arg) { .fld_name = #field, \
+    .fld_show_bits = 1, .fld_mask = BMA400_##reg##_##field, .fld_decode_value = (fun), .fld_arg = (arg) }
+
+/* Fields for INT_STAT0 register */
+static const struct reg_field INT_STAT0_fields[] = {
+    FIELD_NUM(INT_STAT0, DRDY_INT_STAT),
+    FIELD_NUM(INT_STAT0, FWM_INT_STAT),
+    FIELD_NUM(INT_STAT0, FFULL_INT_STAT),
+    FIELD_NUM(INT_STAT0, IENG_OVERRUN_STAT),
+    FIELD_NUM(INT_STAT0, GEN2_INT_STAT),
+    FIELD_NUM(INT_STAT0, GEN1_INT_STAT),
+    FIELD_NUM(INT_STAT0, ORIENTCH_INT_STAT),
+    FIELD_NUM(INT_STAT0, WKUP_INT_STAT),
+    { NULL }
+};
+
+/* Fields for INT_STAT1 register */
+static const struct reg_field INT_STAT1_fields[] = {
+    FIELD_NUM(INT_STAT1, IENG_OVERRUN_STAT),
+    FIELD_NUM(INT_STAT1, D_TAP_INT_STAT),
+    FIELD_NUM(INT_STAT1, S_TAP_INT_STAT),
+    FIELD_NUM(INT_STAT1, STEP_INT_STAT),
+    { NULL }
+};
+
+/* Fields for INT_STAT2 register */
+static const struct reg_field INT_STAT2_fields[] = {
+    FIELD_NUM(INT_STAT2, IENG_OVERRUN_STAT),
+    FIELD_NUM(INT_STAT2, ACTCH_Z_INT_STAT),
+    FIELD_NUM(INT_STAT2, ACTCH_Y_INT_STAT),
+    FIELD_NUM(INT_STAT2, ACTCH_X_INT_STAT),
+    { NULL }
+};
+
+static const char *const step_stat_filed[] = {
+    "still",
+    "walking",
+    "running",
+    NULL,
+};
+
+/* Fields for STEP_STAT register */
+static const struct reg_field STEP_STAT_fields[] = {
+    FIELD_TAB(STEP_STAT, STEP_STAT_FIELD, step_stat_filed),
+    { NULL }
+};
+
+static const char *const osr_lp_filed[] = {
+    "0.4 * ODR",
+    "0.2 * ODR",
+    NULL,
+};
+
+static const char *const power_mode_filed[] = {
+    "sleep",
+    "low power",
+    "normal",
+    "reserved",
+    NULL,
+};
+
+/* Fields for ACC_CONFIG0 register */
+static const struct reg_field ACC_CONFIG0_fields[] = {
+    FIELD_NUM(ACC_CONFIG0, FILT1_BW),
+    FIELD_TAB(ACC_CONFIG0, OSR_LP, osr_lp_filed),
+    FIELD_TAB(ACC_CONFIG0, POWER_MODE_CONF, power_mode_filed),
+    { NULL }
+};
+
+static const char *const acc_range_filed[] = {
+    "+/- 2g",
+    "+/- 4g",
+    "+/- 8g",
+    "+/- 16g",
+    NULL,
+};
+
+static const char *const acc_odr_filed[] = {
+    "reserved",
+    "reserved",
+    "reserved",
+    "reserved",
+    "reserved",
+    "12.5 Hz",
+    "25 Hz",
+    "50 Hz",
+    "100 Hz",
+    "200 Hz",
+    "400 Hz",
+    "800 Hz",
+    NULL,
+};
+
+/* Fields for ACC_CONFIG1 register */
+static const struct reg_field ACC_CONFIG1_fields[] = {
+    FIELD_TAB(ACC_CONFIG1, ACC_RANGE, acc_range_filed),
+    FIELD_NUM(ACC_CONFIG1, OSR),
+    FIELD_TAB(ACC_CONFIG1, ACC_ODR, acc_odr_filed),
+    { NULL }
+};
+
+static const char *const data_src_reg_filed[] = {
+    "acc_filt1 variable ODR filter",
+    "acc_filt2 fixed 100Hz ODR filter",
+    "acc_filt_lp fixed 100Hz ODR filter, 1Hz bandwitdh",
+    "acc_filt1 variable ODR filter",
+    NULL,
+};
+
+/* Fields for ACC_CONFIG2 register */
+static const struct reg_field ACC_CONFIG2_fields[] = {
+    FIELD_TAB(ACC_CONFIG2, DATA_SRC_REG, data_src_reg_filed),
+    { NULL }
+};
+
+/* Fields for INT_CONFIG0 register */
+static const struct reg_field INT_CONFIG0_fields[] = {
+    FIELD_NUM(INT_CONFIG0, DRDY_INT_EN),
+    FIELD_NUM(INT_CONFIG0, FWM_INT_EN),
+    FIELD_NUM(INT_CONFIG0, FFULL_INT_EN),
+    FIELD_NUM(INT_CONFIG0, GEN2_INT_EN),
+    FIELD_NUM(INT_CONFIG0, GEN1_INT_EN),
+    FIELD_NUM(INT_CONFIG0, ORIENTCH_INT_EN),
+    { NULL }
+};
+
+/* Fields for INT_CONFIG1 register */
+static const struct reg_field INT_CONFIG1_fields[] = {
+    FIELD_NUM(INT_CONFIG1, LATCH_INT),
+    FIELD_NUM(INT_CONFIG1, ACTCH_INT_EN),
+    FIELD_NUM(INT_CONFIG1, D_TAP_INT_EN),
+    FIELD_NUM(INT_CONFIG1, S_TAP_INT_EN),
+    FIELD_NUM(INT_CONFIG1, STEP_INT_EN),
+    { NULL }
+};
+
+/* Fields for INT1_MAP register */
+static const struct reg_field INT1_MAP_fields[] = {
+    FIELD_NUM(INT1_MAP, DRDY_INT1),
+    FIELD_NUM(INT1_MAP, FWM_INT1),
+    FIELD_NUM(INT1_MAP, FFULL_INT1),
+    FIELD_NUM(INT1_MAP, IENG_OVERRUN_INT1),
+    FIELD_NUM(INT1_MAP, GEN2_INT1),
+    FIELD_NUM(INT1_MAP, GEN1_INT1),
+    FIELD_NUM(INT1_MAP, ORIENTCH_INT1),
+    FIELD_NUM(INT1_MAP, WKUP_INT1),
+    { NULL }
+};
+
+/* Fields for INT2_MAP register */
+static const struct reg_field INT2_MAP_fields[] = {
+    FIELD_NUM(INT2_MAP, DRDY_INT2),
+    FIELD_NUM(INT2_MAP, FWM_INT2),
+    FIELD_NUM(INT2_MAP, FFULL_INT2),
+    FIELD_NUM(INT2_MAP, IENG_OVERRUN_INT2),
+    FIELD_NUM(INT2_MAP, GEN2_INT2),
+    FIELD_NUM(INT2_MAP, GEN1_INT2),
+    FIELD_NUM(INT2_MAP, ORIENTCH_INT2),
+    FIELD_NUM(INT2_MAP, WKUP_INT2),
+    { NULL }
+};
+
+/* Fields for INT12_MAP register */
+static const struct reg_field INT12_MAP_fields[] = {
+    FIELD_NUM(INT12_MAP, ACTCH_INT2),
+    FIELD_NUM(INT12_MAP, TAP_INT2),
+    FIELD_NUM(INT12_MAP, STEP_INT2),
+    FIELD_NUM(INT12_MAP, ACTCH_INT1),
+    FIELD_NUM(INT12_MAP, TAP_INT1),
+    FIELD_NUM(INT12_MAP, STEP_INT1),
+    { NULL }
+};
+
+/* Fields for INT12_IO_CTRL register */
+static const struct reg_field INT12_IO_CTRL_fields[] = {
+    FIELD_NUM(INT12_IO_CTRL, INT2_OD),
+    FIELD_NUM(INT12_IO_CTRL, INT2_LVL),
+    FIELD_NUM(INT12_IO_CTRL, INT1_OD),
+    FIELD_NUM(INT12_IO_CTRL, INT1_LVL),
+    { NULL }
+};
+
+/* Fields for FIFO_CONFIG0 register */
+static const struct reg_field FIFO_CONFIG0_fields[] = {
+    FIELD_NUM(FIFO_CONFIG0, FIFO_Z_EN),
+    FIELD_NUM(FIFO_CONFIG0, FIFO_Y_EN),
+    FIELD_NUM(FIFO_CONFIG0, FIFO_X_EN),
+    FIELD_NUM(FIFO_CONFIG0, FIFO_8BIT_EN),
+    FIELD_NUM(FIFO_CONFIG0, FIFO_DATA_SRC),
+    FIELD_NUM(FIFO_CONFIG0, FIFO_TIME_EN),
+    FIELD_NUM(FIFO_CONFIG0, FIFO_STOP_ON_FULL),
+    FIELD_NUM(FIFO_CONFIG0, AUTO_FLUSH),
+    { NULL }
+};
+
+/* Fields for FIFO_PWR_CONFIG register */
+static const struct reg_field FIFO_PWR_CONFIG_fields[] = {
+    FIELD_NUM(FIFO_PWR_CONFIG, FIFO_READ_DISABLE),
+    { NULL }
+};
+
+static const char *const auto_lp_timeout_filed[] = {
+    "0 Low-power timeout disabled",
+    "1 Low-power timeout active, device shall switch into low power mode as soon timeout counter is expired",
+    "2 Low-power timeout active, as 0x01, but timeout counter resets if gen2_int is asserted",
+    "3 Low-power timeout active, device shall switch into low power mode as soon timeout counter is expired",
+    NULL,
+};
+
+/* Fields for AUTOLOWPOW_1 register */
+static const struct reg_field AUTOLOWPOW_1_fields[] = {
+    FIELD_NUM(AUTOLOWPOW_1, AUTO_LP_TIMEOUT_THRES),
+    FIELD_TAB(AUTOLOWPOW_1, AUTO_LP_TIMEOUT, auto_lp_timeout_filed),
+    FIELD_NUM(AUTOLOWPOW_1, GEN1_INT),
+    FIELD_NUM(AUTOLOWPOW_1, DRDY_LOWPOW_TRIG),
+    { NULL }
+};
+
+/* Fields for AUTOWAKEUP_1 register */
+static const struct reg_field AUTOWAKEUP_1_fields[] = {
+    FIELD_NUM(AUTOWAKEUP_1, WAKEUP_TIMEOUT_THRES),
+    FIELD_NUM(AUTOWAKEUP_1, WKUP_TIMEOUT),
+    FIELD_NUM(AUTOWAKEUP_1, WKUP_INT),
+    { NULL }
+};
+
+static const char *const wkup_refu_field[] = {
+    "manual update (reference registers are updated by external MCU)",
+    "one time automated update before going into low power mode",
+    "every time after data conversion",
+    NULL,
+};
+
+/* Fields for WKUP_INT_CONFIG0 register */
+static const struct reg_field WKUP_INT_CONFIG0_fields[] = {
+    FIELD_NUM(WKUP_INT_CONFIG0, WKUP_Z_EN),
+    FIELD_NUM(WKUP_INT_CONFIG0, WKUP_Y_EN),
+    FIELD_NUM(WKUP_INT_CONFIG0, WKUP_X_EN),
+    FIELD_NUM(WKUP_INT_CONFIG0, NUM_OF_SAMPLES),
+    FIELD_TAB(WKUP_INT_CONFIG0, WKUP_REFU, wkup_refu_field),
+    { NULL }
+};
+
+static const char *const orient_data_src_field[] = {
+    "acc_filt2",
+    "acc_filt_lp",
+    NULL,
+};
+
+static const char *const orient_refu_field[] = {
+    "manual update (reference registers are updated by serial interface command)",
+    "one time automated update using acc_filt2 data",
+    "one time automated update using acc_filt_lp data",
+    NULL,
+};
+
+/* Fields for ORIENTCH_CONFIG0 register */
+static const struct reg_field ORIENTCH_CONFIG0_fields[] = {
+    FIELD_NUM(ORIENTCH_CONFIG0, ORIENT_Z_EN),
+    FIELD_NUM(ORIENTCH_CONFIG0, ORIENT_Y_EN),
+    FIELD_NUM(ORIENTCH_CONFIG0, ORIENT_X_EN),
+    FIELD_TAB(ORIENTCH_CONFIG0, ORIENT_DATA_SRC, orient_data_src_field),
+    FIELD_TAB(ORIENTCH_CONFIG0, ORIENT_REFU, orient_refu_field),
+    { NULL }
+};
+
+
+static const char *const gen1_data_src_field[] = {
+    "acc_filt1",
+    "acc_filt2",
+    NULL,
+};
+
+static const char *const gen1_act_refu_field[] = {
+    "manual update (reference registers are updated by a serial interface command)",
+    "one time automated update by the selected data source",
+    "every time automated update by the selected data source",
+    "every time automated update by acc_filt_lp",
+    NULL,
+};
+
+static const char *const gen1_act_hyst_field[] = {
+    "no hysteresis",
+    "24mg hysteresis",
+    "48mg hysteresis",
+    "96mg hysteresis",
+    NULL,
+};
+
+/* Fields for GEN1INT_CONFIG0 register */
+static const struct reg_field GEN1INT_CONFIG0_fields[] = {
+    FIELD_NUM(GEN1INT_CONFIG0, GEN1_ACT_Z_EN),
+    FIELD_NUM(GEN1INT_CONFIG0, GEN1_ACT_Y_EN),
+    FIELD_NUM(GEN1INT_CONFIG0, GEN1_ACT_X_EN),
+    FIELD_TAB(GEN1INT_CONFIG0, GEN1_DATA_SRC, gen1_data_src_field),
+    FIELD_TAB(GEN1INT_CONFIG0, GEN1_ACT_REFU, gen1_act_refu_field),
+    FIELD_TAB(GEN1INT_CONFIG0, GEN1_ACT_HYST, gen1_act_hyst_field),
+    { NULL }
+};
+
+static const char *const gen1_criterion_sel_field[] = {
+    "acceleration below threshold: inactivity detection",
+    "acceleration above threshold: activity detection",
+    NULL,
+};
+
+static const char *const gen1_comb_sel_field[] = {
+    "OR combination of x/y/z axis evaluation results",
+    "AND combination of x/y/z axis evaluation results",
+    NULL,
+};
+
+/* Fields for GEN1INT_CONFIG1 register */
+static const struct reg_field GEN1INT_CONFIG1_fields[] = {
+    FIELD_TAB(GEN1INT_CONFIG1, GEN1_CRITERION_SEL, gen1_criterion_sel_field),
+    FIELD_TAB(GEN1INT_CONFIG1, GEN1_COMB_SEL, gen1_comb_sel_field),
+    { NULL }
+};
+
+
+/* Fields for GEN2INT_CONFIG0 register */
+static const struct reg_field GEN2INT_CONFIG0_fields[] = {
+    FIELD_NUM(GEN2INT_CONFIG0, GEN2_ACT_Z_EN),
+    FIELD_NUM(GEN2INT_CONFIG0, GEN2_ACT_Y_EN),
+    FIELD_NUM(GEN2INT_CONFIG0, GEN2_ACT_X_EN),
+    FIELD_TAB(GEN2INT_CONFIG0, GEN2_DATA_SRC, gen1_data_src_field),
+    FIELD_TAB(GEN2INT_CONFIG0, GEN2_ACT_REFU, gen1_act_refu_field),
+    FIELD_TAB(GEN2INT_CONFIG0, GEN2_ACT_HYST, gen1_act_hyst_field),
+    { NULL }
+};
+
+/* Fields for GEN2INT_CONFIG1 register */
+static const struct reg_field GEN2INT_CONFIG1_fields[] = {
+    FIELD_TAB(GEN2INT_CONFIG1, GEN2_CRITERION_SEL, gen1_criterion_sel_field),
+    FIELD_TAB(GEN2INT_CONFIG1, GEN2_COMB_SEL, gen1_comb_sel_field),
+    { NULL }
+};
+
+#define actch_data_src_field gen1_data_src_field
+
+static const char *const actch_npts_field[] = {
+    "32 points",
+    "64 points",
+    "128 points",
+    "256 points",
+    "512 points",
+    NULL,
+};
+
+/* Fields for ACTCH_CONFIG1 register */
+static const struct reg_field ACTCH_CONFIG1_fields[] = {
+    FIELD_NUM(ACTCH_CONFIG1, ACTCH_Z_EN),
+    FIELD_NUM(ACTCH_CONFIG1, ACTCH_Y_EN),
+    FIELD_NUM(ACTCH_CONFIG1, ACTCH_X_EN),
+    FIELD_TAB(ACTCH_CONFIG1, ACTCH_DATA_SRC, actch_data_src_field),
+    FIELD_TAB(ACTCH_CONFIG1, ACTCH_NPTS, actch_npts_field),
+    { NULL }
+};
+
+static const char *const sel_axis_field[] = {
+    "use Z axis data",
+    "use Y axis data",
+    "use X axis data",
+    NULL,
+};
+
+/* Fields for TAP_CONFIG register */
+static const struct reg_field TAP_CONFIG_fields[] = {
+    FIELD_TAB(TAP_CONFIG, SEL_AXIS, sel_axis_field),
+    FIELD_NUM(TAP_CONFIG, TAP_SENSITIVITY),
+    { NULL }
+};
+
+static const char *const quiet_dt_field[] = {
+    "4 data samples minimum time between double taps",
+    "8 data samples minimum time between double taps",
+    "12 data samples minimum time between double taps",
+    "16 data samples minimum time between double taps",
+    NULL,
+};
+
+static const char *const quiet_field[] = {
+    "60 data samples quiet tie between single or doube taps",
+    "80 data samples quiet tie between single or doube taps",
+    "100 data samples quiet tie between single or doube taps",
+    "120 data samples quiet tie between single or doube taps",
+    NULL,
+};
+
+static const char *const tics_th_field[] = {
+    "6 data samples for high-low tap signal change time",
+    "9 data samples for high-low tap signal change time",
+    "12 data samples for high-low tap signal change time",
+    "18 data samples for high-low tap signal change time",
+    NULL,
+};
+
+/* Fields for TAP_CONFIG1 register */
+static const struct reg_field TAP_CONFIG1_fields[] = {
+    FIELD_TAB(TAP_CONFIG1, QUIET_DT, quiet_dt_field),
+    FIELD_TAB(TAP_CONFIG1, QUIET, quiet_field),
+    FIELD_TAB(TAP_CONFIG1, TICS_TH, tics_th_field),
+    { NULL }
+};
+
+static const char *
+field_bit_string(const struct reg_field *field, uint8_t val, char *buf)
+{
+    int lsb = __builtin_ctz(field->fld_mask);
+    int msb = lsb + __builtin_popcount(field->fld_mask) - 1;
+    int i;
+
+    buf[8] = '\0';
+    for (i = 0; i < 8; ++i) {
+        if (i >= lsb && i <= msb) {
+            buf[7 - i] = (char)('0' + (val & 1));
+        } else {
+            buf[7 - i] = '.';
+        }
+        val >>= 1;
+    }
+
+    return buf;
+}
+
+static int
+field_int_value(const struct reg_field *field, uint32_t val)
+{
+    uint8_t fld_pos = __builtin_ctz(field->fld_mask);
+    return (int)((val & field->fld_mask) >> fld_pos);
+}
+
+#define REG(name, grp) { .reg_name = #name, .reg_addr = BMA400_REG_ ## name, .reg_grp = (grp), .seq = 0, .fields = name##_fields }
+
+static int
+bma400_shell_cmd_decode(int argc, char **argv)
+{
+    long long val;
+    int status;
+
+    if (argc == 2) {
+        val = parse_ll_bounds(argv[1], 0, 1, &status);
+        if (status == 0) {
+            bma400_cli_decode_fields = val != 0;
+        }
+    }
+    console_printf("decode %d\n", (int)bma400_cli_decode_fields);
+
+    return 0;
+}
+
+#else
+#define bma400_cli_decode_fields false
+
+#define REG(name, grp) { .reg_name = #name, .reg_addr = BMA400_REG_ ## name, .reg_grp = (grp), .seq = 0, .fields = NULL }
+#endif
+
+#define REGS(name, grp, seq) { .reg_name = #name, .reg_addr = BMA400_REG_ ## name, .reg_grp = (grp), seq, .fields = NULL }
+#define REGNF(name, grp) { .reg_name = #name, .reg_addr = BMA400_REG_ ## name, .reg_grp = (grp), .seq = 0, .fields = NULL }
+
+const struct bma400_reg bma400_regs[] = {
+    /* Dump all the register values for debug purposes */
+    REGNF(CHIPID, GRP_GLOBAL),
+    REGNF(ERR_REG, GRP_GLOBAL),
+    REGNF(STATUS, GRP_GLOBAL),
+    REGS(ACC_X_LSB, GRP_MEASUREMENT, 0),
+    REGS(ACC_X_MSB, GRP_MEASUREMENT, 1),
+    REGS(ACC_Y_LSB, GRP_MEASUREMENT, 0),
+    REGS(ACC_Y_MSB, GRP_MEASUREMENT, 1),
+    REGS(ACC_Z_LSB, GRP_MEASUREMENT, 0),
+    REGS(ACC_Z_MSB, GRP_MEASUREMENT, 1),
+    REGS(SENSOR_TIME0, GRP_TIME, 0),
+    REGS(SENSOR_TIME1, GRP_TIME, 1),
+    REGS(SENSOR_TIME2, GRP_TIME, 2),
+    REGNF(EVENT, GRP_STATUS),
+    REG(INT_STAT0, GRP_INT | GRP_GEN1INT | GRP_GEN2INT | GRP_ORIENT | GRP_AUTOWAKEUP),
+    REG(INT_STAT1, GRP_INT | GRP_TAP | GRP_STEP),
+    REG(INT_STAT2, GRP_INT | GRP_ACTIVITY),
+    REGNF(TEMP_DATA, GRP_MEASUREMENT),
+    REGS(FIFO_LENGTH0, GRP_FIFO, 0),
+    REGS(FIFO_LENGTH1, GRP_FIFO, 1),
+    REGS(STEP_CNT_0, GRP_STEP, 0),
+    REGS(STEP_CNT_1, GRP_STEP, 1),
+    REGS(STEP_CNT_2, GRP_STEP, 2),
+    REG(STEP_STAT, GRP_STEP),
+    REG(ACC_CONFIG0, GRP_ACC | GRP_CFG),
+    REG(ACC_CONFIG1, GRP_ACC | GRP_CFG),
+    REG(ACC_CONFIG2, GRP_ACC | GRP_CFG),
+    REG(INT_CONFIG0, GRP_INT | GRP_CFG | GRP_GEN1INT | GRP_GEN2INT | GRP_ORIENT),
+    REG(INT_CONFIG1, GRP_INT | GRP_CFG | GRP_TAP | GRP_STEP),
+    REG(INT1_MAP, GRP_INT | GRP_CFG | GRP_GEN1INT | GRP_GEN2INT | GRP_ORIENT | GRP_AUTOWAKEUP),
+    REG(INT2_MAP, GRP_INT | GRP_CFG | GRP_GEN1INT | GRP_GEN2INT | GRP_ORIENT | GRP_AUTOWAKEUP),
+    REG(INT12_MAP, GRP_INT | GRP_CFG | GRP_TAP | GRP_ACTIVITY | GRP_STEP),
+    REG(INT12_IO_CTRL, GRP_INT | GRP_CFG),
+    REG(FIFO_CONFIG0, GRP_FIFO | GRP_CFG),
+    REGNF(FIFO_CONFIG1, GRP_FIFO | GRP_CFG),
+    REGNF(FIFO_CONFIG2, GRP_FIFO | GRP_CFG),
+    REG(FIFO_PWR_CONFIG, GRP_FIFO | GRP_CFG),
+    REGNF(AUTOLOWPOW_0, GRP_AUTOLOWPOW | GRP_CFG),
+    REG(AUTOLOWPOW_1, GRP_AUTOLOWPOW | GRP_CFG),
+    REGNF(AUTOWAKEUP_0, GRP_AUTOWAKEUP | GRP_CFG),
+    REG(AUTOWAKEUP_1, GRP_AUTOWAKEUP | GRP_CFG),
+    REG(WKUP_INT_CONFIG0, GRP_AUTOWAKEUP | GRP_CFG),
+    REGNF(WKUP_INT_CONFIG1, GRP_AUTOWAKEUP | GRP_CFG),
+    REGNF(WKUP_INT_CONFIG2, GRP_AUTOWAKEUP | GRP_CFG),
+    REGNF(WKUP_INT_CONFIG3, GRP_AUTOWAKEUP | GRP_CFG),
+    REGNF(WKUP_INT_CONFIG4, GRP_AUTOWAKEUP | GRP_CFG),
+    REG(ORIENTCH_CONFIG0, GRP_ORIENT | GRP_CFG),
+    REGNF(ORIENTCH_CONFIG1, GRP_ORIENT | GRP_CFG),
+    REGNF(ORIENTCH_CONFIG3, GRP_ORIENT | GRP_CFG),
+    REGNF(ORIENTCH_CONFIG4, GRP_ORIENT | GRP_CFG),
+    REGNF(ORIENTCH_CONFIG5, GRP_ORIENT | GRP_CFG),
+    REGNF(ORIENTCH_CONFIG6, GRP_ORIENT | GRP_CFG),
+    REGNF(ORIENTCH_CONFIG7, GRP_ORIENT | GRP_CFG),
+    REGNF(ORIENTCH_CONFIG8, GRP_ORIENT | GRP_CFG),
+    REGNF(ORIENTCH_CONFIG9, GRP_ORIENT | GRP_CFG),
+    REG(GEN1INT_CONFIG0, GRP_GEN1INT | GRP_CFG),
+    REG(GEN1INT_CONFIG1, GRP_GEN1INT | GRP_CFG),
+    REGNF(GEN1INT_CONFIG2, GRP_GEN1INT | GRP_CFG),
+    REGNF(GEN1INT_CONFIG3, GRP_GEN1INT | GRP_CFG),
+    REGNF(GEN1INT_CONFIG31, GRP_GEN1INT | GRP_CFG),
+    REGNF(GEN1INT_CONFIG4, GRP_GEN1INT | GRP_CFG),
+    REGNF(GEN1INT_CONFIG5, GRP_GEN1INT | GRP_CFG),
+    REGNF(GEN1INT_CONFIG6, GRP_GEN1INT | GRP_CFG),
+    REGNF(GEN1INT_CONFIG7, GRP_GEN1INT | GRP_CFG),
+    REGNF(GEN1INT_CONFIG8, GRP_GEN1INT | GRP_CFG),
+    REGNF(GEN1INT_CONFIG9, GRP_GEN1INT | GRP_CFG),
+    REG(GEN2INT_CONFIG0, GRP_GEN2INT | GRP_CFG),
+    REG(GEN2INT_CONFIG1, GRP_GEN2INT | GRP_CFG),
+    REGNF(GEN2INT_CONFIG2, GRP_GEN2INT | GRP_CFG),
+    REGNF(GEN2INT_CONFIG3, GRP_GEN2INT | GRP_CFG),
+    REGNF(GEN2INT_CONFIG31, GRP_GEN2INT | GRP_CFG),
+    REGNF(GEN2INT_CONFIG4, GRP_GEN2INT | GRP_CFG),
+    REGNF(GEN2INT_CONFIG5, GRP_GEN2INT | GRP_CFG),
+    REGNF(GEN2INT_CONFIG6, GRP_GEN2INT | GRP_CFG),
+    REGNF(GEN2INT_CONFIG7, GRP_GEN2INT | GRP_CFG),
+    REGNF(GEN2INT_CONFIG8, GRP_GEN2INT | GRP_CFG),
+    REGNF(GEN2INT_CONFIG9, GRP_GEN2INT | GRP_CFG),
+    REGNF(ACTCH_CONFIG0, GRP_ACTIVITY | GRP_CFG),
+    REG(ACTCH_CONFIG1, GRP_ACTIVITY | GRP_CFG),
+    REG(TAP_CONFIG, GRP_TAP | GRP_CFG),
+    REG(TAP_CONFIG1, GRP_TAP | GRP_CFG),
+    REGNF(IF_CONF, GRP_GLOBAL),
+    REGNF(SELF_TEST, GRP_GLOBAL),
+    REGNF(STEP_COUNTER_CONFIG0, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG1, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG2, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG3, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG4, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG5, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG6, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG7, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG8, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG9, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG10, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG11, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG12, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG13, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG14, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG15, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG16, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG17, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG18, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG19, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG20, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG21, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG22, GRP_STEP | GRP_CFG),
+    REGNF(STEP_COUNTER_CONFIG23, GRP_STEP | GRP_CFG),
+};
+#define NUM_BMA400_REGS ARRAY_SIZE(bma400_regs)
+
+static void
+bma400_shell_dump_register(const struct bma400_reg *reg, uint8_t val, bool non_zero_only, bool decode)
+{
+#if MYNEWT_VAL(BMA400_CLI_DECODE)
+    const struct reg_field *field;
+    char binary[9];
+    char buf[100];
+    uint8_t bit_field_val;
+#endif
+    if (MYNEWT_VAL(BMA400_CLI_DECODE) == 0 || !non_zero_only || val != 0) {
+        console_printf("%-22s = 0x%02x \n", reg->reg_name, (int)val);
+    }
+#if MYNEWT_VAL(BMA400_CLI_DECODE)
+    if (decode && reg->fields) {
+        for (field = reg->fields; field->fld_name; ++field) {
+            if (field->fld_decode_value) {
+                field->fld_decode_value(field, val, buf);
+                if (field->fld_show_bits) {
+                    console_printf("%22s = %s %s\n", field->fld_name,
+                                   field_bit_string(field, val, binary), buf);
+                } else {
+                    console_printf("%22s = %s\n", field->fld_name, buf);
+                }
+            } else {
+                bit_field_val = field_int_value(field, val);
+                if (!non_zero_only || bit_field_val != 0) {
+                    console_printf("%22s = %s %d\n", field->fld_name,
+                                   field_bit_string(field, val, binary),
+                                   bit_field_val);
+                }
+            }
+        }
+    }
+#endif
+}
+
+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;
+    bool decode = bma400_cli_decode_fields;
+
+    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 |= GRP_ACC;
+        } else if (0 == strcmp(argv[i], "step")) {
+            sel |= GRP_STEP;
+        } else if (0 == strcmp(argv[i], "int")) {
+            sel |= GRP_INT;
+        } else if (0 == strcmp(argv[i], "orient")) {
+            sel |= GRP_ORIENT;
+        } else if (0 == strcmp(argv[i], "lp")) {
+            sel |= GRP_AUTOLOWPOW;
+        } else if (0 == strcmp(argv[i], "wkup")) {
+            sel |= GRP_AUTOWAKEUP;
+        } else if (0 == strcmp(argv[i], "tap")) {
+            sel |= GRP_TAP;
+        } else if (0 == strcmp(argv[i], "gen1")) {
+            sel |= GRP_GEN1INT;
+        } else if (0 == strcmp(argv[i], "gen2")) {
+            sel |= GRP_GEN2INT;
+        } else if (0 == strcmp(argv[i], "gen")) {
+            sel |= GRP_GEN1INT | GRP_GEN2INT;
+        } else if (0 == strcmp(argv[i], "time")) {
+            sel |= GRP_TIME;
+        } else if (0 == strcmp(argv[i], "meas")) {
+            sel |= GRP_MEASUREMENT;
+        } else if (0 == strcmp(argv[i], "fifo")) {
+            sel |= GRP_FIFO;
+#if MYNEWT_VAL(BMA400_CLI_DECODE)
+        } else if (0 == strcmp(argv[i], "decode")) {
+            decode = true;
+#endif
+        }
+    }
+    if (sel == 0) {
+        sel = GRP_ALL;
+    }
+    for (i = 0; rc == 0 && i < ARRAY_SIZE(bma400_regs); ++i) {
+        if (bma400_regs[i].reg_grp & sel) {
+            rc = bma400_shell_get_register(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 {
+                bma400_shell_dump_register(&bma400_regs[i], val, non_zero_only, decode);
+            }
+        }
+    }
+
+    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_shell_get_register(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_shell_set_register(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_fifo(int argc, char **argv)
+{
+    int rc;
+    uint16_t fifo_count;
+    struct sensor_accel_data sad;
+    char tmpstr[13];
+    int n = 0;
+    (void)argc;
+    (void)argv;
+
+    rc = bma400_shell_get_fifo_count(&fifo_count);
+    if (rc == 0) {
+        if (fifo_count == 0) {
+            console_printf("FIFO empty\n");
+            return 0;
+        }
+    }
+    while (fifo_count && rc == 0) {
+        rc = bma400_shell_read_fifo(&fifo_count, &sad);
+        if (rc == 0) {
+            ++n;
+            console_printf("%d ", n);
+            if (sad.sad_x_is_valid) {
+                console_printf("x:%s ", sensor_ftostr(sad.sad_x, tmpstr, 13));
+            }
+            if (sad.sad_y_is_valid) {
+                console_printf("y:%s ", sensor_ftostr(sad.sad_y, tmpstr, 13));
+            }
+            if (sad.sad_y_is_valid) {
+                console_printf("z:%s ", sensor_ftostr(sad.sad_z, tmpstr, 13));
+            }
+            console_printf("\n");
+        }
+    }
+
+    return 0;
+}
+
+static void
+bma400_shell_set_power_mode(bma400_power_mode_t mode)
+{
+    int rc;
+
+    rc = bma400_shell_set_register_field(BMA400_REG_ACC_CONFIG0, BMA400_ACC_CONFIG0_POWER_MODE_CONF, mode);
+    if (rc) {
+        console_printf("BMA400 communication failed %d\n", rc);
+    }
+}
+static int
+bma400_shell_cmd_sleep(int argc, char **argv)
+{
+    (void)argc;
+    (void)argv;
+
+    bma400_shell_set_power_mode(BMA400_POWER_MODE_SLEEP);
+
+    return 0;
+}
+
+static int
+bma400_shell_cmd_lp(int argc, char **argv)
+{
+    (void)argc;
+    (void)argv;
+
+    bma400_shell_set_power_mode(BMA400_POWER_MODE_LOW);
+
+    return 0;
+}
+
+static int
+bma400_shell_cmd_normal(int argc, char **argv)
+{
+    (void)argc;
+    (void)argv;
+
+    bma400_shell_set_power_mode(BMA400_POWER_MODE_NORMAL);
+
+    return 0;
+}
+
+static int
+bma400_shell_cmd_test(int argc, char **argv)
+{
+    int rc;
+    bool result = 0;
+    (void)argc;
+    (void)argv;
+
+    rc = bma400_shell_self_test(&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_reg_cmd(int argc, char **argv)
+{
+    const struct bma400_reg *reg = NULL;
+    uint8_t val;
+    uint8_t old_val;
+    int status;
+    int i;
+    int add;
+    int remove;
+    int n;
+    bool dump = false;
+    bool decode = bma400_cli_decode_fields;
+
+    for (i = 0; i < NUM_BMA400_REGS; ++i) {
+        if (strcasecmp(bma400_regs[i].reg_name, argv[0]) == 0) {
+            reg = bma400_regs + i;
+        }
+    }
+    if (!reg) {
+        return 0;
+    }
+
+    if (argc == 1) {
+        dump = true;
+#if MYNEWT_VAL(BMA400_CLI_DECODE)
+    } else if (strcmp(argv[1], "decode") == 0) {
+        dump = true;
+        decode = true;
+#endif
+    } else {
+        add = argv[1][0] == '+';
+        remove = argv[1][0] == '-';
+        n = add | remove;
+        val = (uint32_t)parse_ull_bounds(&argv[1][n], 0, 0xFFFFFFFF, &status);
+        if (status) {
+            console_printf("Invalid register value %s\n", argv[1]);
+            return 0;
+        }
+
+    }
+    if (dump) {
+        bma400_shell_get_register(reg->reg_addr, &val);
+        bma400_shell_dump_register(reg, val, false, decode);
+    } else {
+        if (add | remove) {
+            bma400_shell_get_register(reg->reg_addr, &old_val);
+            if (add) {
+                val |= old_val;
+            } else {
+                val = old_val & ~(val);
+            }
+        }
+        bma400_shell_set_register(reg->reg_addr, val);
+    }
+
+    return 0;
+}
+
+#define REG_NAME(short_name) #short_name
+
+static const struct shell_cmd bma400_cmds[] = {
+#if MYNEWT_VAL(BMA400_CLI_DECODE)
+    SHELL_CMD("decode", bma400_shell_cmd_decode, HELP(decode)),
+#endif
+    SHELL_CMD("r", bma400_shell_cmd_read, HELP(r)),
+    SHELL_CMD("dump", bma400_shell_cmd_dump, HELP(dump)),
+    SHELL_CMD("chipid", bma400_shell_cmd_read_chipid, NULL),
+    SHELL_CMD("peek", bma400_shell_cmd_peek, HELP(peek)),
+    SHELL_CMD("poke", bma400_shell_cmd_poke, HELP(poke)),
+    SHELL_CMD("fifo", bma400_shell_cmd_fifo, HELP(fifo)),
+    SHELL_CMD("sleep", bma400_shell_cmd_sleep, HELP(sleep)),
+    SHELL_CMD("lp", bma400_shell_cmd_lp, HELP(lp)),
+    SHELL_CMD("normal", bma400_shell_cmd_normal, HELP(normal)),
+    SHELL_CMD("test", bma400_shell_cmd_test, HELP(test)),
+    SHELL_CMD(REG_NAME(ACC_CONFIG0), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(ACC_CONFIG1), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(ACC_CONFIG2), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(INT_CONFIG0), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(INT_CONFIG1), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(INT1_MAP), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(INT2_MAP), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(INT12_MAP), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(INT12_IO_CTRL), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(FIFO_CONFIG0), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(FIFO_CONFIG1), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(FIFO_CONFIG2), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(FIFO_PWR_CONFIG), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(AUTOLOWPOW_0), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(AUTOLOWPOW_1), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(AUTOWAKEUP_0), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(AUTOWAKEUP_1), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(WKUP_INT_CONFIG0), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(WKUP_INT_CONFIG1), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(WKUP_INT_CONFIG2), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(WKUP_INT_CONFIG3), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(WKUP_INT_CONFIG4), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(ORIENTCH_CONFIG0), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(ORIENTCH_CONFIG1), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(ORIENTCH_CONFIG3), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(ORIENTCH_CONFIG4), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(ORIENTCH_CONFIG5), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(ORIENTCH_CONFIG6), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(ORIENTCH_CONFIG7), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(ORIENTCH_CONFIG8), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(ORIENTCH_CONFIG9), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN1INT_CONFIG0), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN1INT_CONFIG1), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN1INT_CONFIG2), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN1INT_CONFIG3), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN1INT_CONFIG31), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN1INT_CONFIG4), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN1INT_CONFIG5), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN1INT_CONFIG6), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN1INT_CONFIG7), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN1INT_CONFIG8), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN1INT_CONFIG9), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN2INT_CONFIG0), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN2INT_CONFIG1), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN2INT_CONFIG2), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN2INT_CONFIG3), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN2INT_CONFIG31), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN2INT_CONFIG4), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN2INT_CONFIG5), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN2INT_CONFIG6), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN2INT_CONFIG7), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN2INT_CONFIG8), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(GEN2INT_CONFIG9), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(ACTCH_CONFIG0), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(ACTCH_CONFIG1), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(TAP_CONFIG), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(REG_NAME(TAP_CONFIG1), bma400_reg_cmd, HELP(reg_cmd)),
+    SHELL_CMD(NULL, NULL, NULL)
+};
+
+static int
+bma400_shell_cmd(int argc, char **argv)
+{
+    const struct shell_cmd *cmd;
+
+    if (argc == 1) {
+        return bma400_shell_help();
+    }
+
+    for (cmd = bma400_cmds; cmd->sc_cmd; ++cmd) {
+        if (strcmp(argv[1], cmd->sc_cmd) == 0) {
+            return cmd->sc_cmd_func(argc - 1, &argv[1]);
+        }
+    }
+
+    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);
+
+    rc = shell_register("bma400", bma400_cmds);
+
+    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..70be518
--- /dev/null
+++ b/hw/drivers/sensors/bma400/syscfg.yml
@@ -0,0 +1,83 @@
+#
+# 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
+    BMA400_CLI_DECODE:
+        description: 'Decode registers fields in shell'
+        value: 0
+    ### 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)