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