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:04 UTC

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

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)