diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig index 3aca00f403c..f92b2192903 100644 --- a/drivers/sensors/Kconfig +++ b/drivers/sensors/Kconfig @@ -429,6 +429,13 @@ config SENSORS_LSM9DS1 ---help--- Enable driver support for the STMicro LSM9DS1. +config SENSORS_MSA301 + bool "MSA301 support" + default n + select I2C + ---help--- + Enable driver support for the MSA301. + config LSM9DS1_I2C_FREQUENCY int "LSM9DS1 I2C frequency" default 400000 diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs index b9ade92c614..5ee59bbefc9 100644 --- a/drivers/sensors/Make.defs +++ b/drivers/sensors/Make.defs @@ -96,6 +96,10 @@ ifeq ($(CONFIG_SENSORS_LSM9DS1),y) CSRCS += lsm9ds1.c endif +ifeq ($(CONFIG_SENSORS_MSA301),y) + CSRCS += msa301.c +endif + ifeq ($(CONFIG_SENSORS_LPS25H),y) CSRCS += lps25h.c endif diff --git a/drivers/sensors/msa301.c b/drivers/sensors/msa301.c new file mode 100644 index 00000000000..151bac10f6b --- /dev/null +++ b/drivers/sensors/msa301.c @@ -0,0 +1,735 @@ +/**************************************************************************** + * drivers/sensors/msa301.c + * Author: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_MSA301) + +struct msa301_dev_s +{ + FAR struct i2c_master_s * i2c; /* I2C interface */ + uint8_t addr; /* I2C address */ + msa301_range_t range; + FAR const struct msa301_ops_s *ops; + sem_t exclsem; + struct msa301_sensor_data_s sensor_data; /* Sensor data container */ +}; + +struct msa301_ops_s +{ + CODE int (*config)(FAR struct msa301_dev_s *priv); + CODE int (*start)(FAR struct msa301_dev_s *priv); + CODE int (*stop)(FAR struct msa301_dev_s *priv); + CODE int (*sensor_read)(FAR struct msa301_dev_s *priv); +}; + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +# ifndef CONFIG_MSA301_I2C_FREQUENCY +# define CONFIG_MSA301_I2C_FREQUENCY 400000 +# endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* I2C Helpers */ + +static int msa301_readreg8(FAR struct msa301_dev_s *priv, + uint8_t regaddr, FAR uint8_t *regval); +static int msa301_writereg8(FAR struct msa301_dev_s *priv, + uint8_t regaddr, uint8_t regval); +static int msa301_readreg(FAR struct msa301_dev_s *priv, + uint8_t regaddr, FAR uint8_t *regval, uint8_t len); + +/* Accelerometer Operations */ + +static int msa301_sensor_config(FAR struct msa301_dev_s *priv); +static int msa301_sensor_start(FAR struct msa301_dev_s *priv); +static int msa301_sensor_stop(FAR struct msa301_dev_s *priv); +static int msa301_sensor_read(FAR struct msa301_dev_s *priv); + +/* Character Driver Methods */ + +static int msa301_open(FAR struct file *filep); +static int msa301_close(FAR struct file *filep); +static ssize_t msa301_read(FAR struct file *filep, + FAR char *buffer, size_t buflen); +static ssize_t msa301_write(FAR struct file *filep, + FAR const char *buffer, size_t buflen); +static int msa301_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); + +/* Common Register Function */ + +static int msa301_register(FAR const char * devpath, + FAR struct i2c_master_s * i2c, + uint8_t addr, + FAR const struct msa301_ops_s *ops); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_fops = { + msa301_open, + msa301_close, + msa301_read, + msa301_write, + NULL, + msa301_ioctl, + NULL +# ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + , + NULL +# endif +}; + +static const struct msa301_ops_s g_msa301_sensor_ops = { + msa301_sensor_config, + msa301_sensor_start, + msa301_sensor_stop, + msa301_sensor_read, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int msa301_readreg(FAR struct msa301_dev_s *priv, + uint8_t regaddr, FAR uint8_t *regval, uint8_t len) +{ + struct i2c_config_s config; + int ret; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(regval != NULL); + + /* Set up the I2C configuration */ + + config.frequency = CONFIG_MSA301_I2C_FREQUENCY; + config.address = priv->addr; + config.addrlen = 7; + + /* Write the register address */ + + ret = i2c_write(priv->i2c, &config, ®addr, sizeof(regaddr)); + if (ret < 0) + { + snerr("ERROR: i2c_write failed: %d\n", ret); + return ret; + } + + /* Restart and read 8 bits from the register */ + + ret = i2c_read(priv->i2c, &config, regval, len); + if (ret < 0) + { + snerr("ERROR: i2c_read failed: %d\n", ret); + return ret; + } + + return OK; +} +/**************************************************************************** + * Name: msa301_readreg8 + * + * Description: + * Read from an 8-bit register. + * + ****************************************************************************/ + +static int msa301_readreg8(FAR struct msa301_dev_s *priv, + uint8_t regaddr, FAR uint8_t *regval) +{ + struct i2c_config_s config; + int ret; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(regval != NULL); + + /* Set up the I2C configuration */ + + config.frequency = CONFIG_MSA301_I2C_FREQUENCY; + config.address = priv->addr; + config.addrlen = 7; + + /* Write the register address */ + + ret = i2c_write(priv->i2c, &config, ®addr, sizeof(regaddr)); + if (ret < 0) + { + snerr("ERROR: i2c_write failed: %d\n", ret); + return ret; + } + + /* Restart and read 8 bits from the register */ + + ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval)); + if (ret < 0) + { + snerr("ERROR: i2c_read failed: %d\n", ret); + return ret; + } + + sninfo("addr: %02x value: %02x\n", regaddr, *regval); + + return OK; +} + +/**************************************************************************** + * Name: msa301_writereg8 + * + * Description: + * Write to an 8-bit register. + * + ****************************************************************************/ + +static int msa301_writereg8(FAR struct msa301_dev_s *priv, + uint8_t regaddr, uint8_t regval) +{ + struct i2c_config_s config; + uint8_t buffer[2]; + int ret; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + + /* Set up a 2-byte message to send */ + + buffer[0] = regaddr; + buffer[1] = regval; + + /* Set up the I2C configuration */ + + config.frequency = CONFIG_MSA301_I2C_FREQUENCY; + config.address = priv->addr; + config.addrlen = 7; + + /* Write the register address followed by the data (no RESTART) */ + + ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer)); + if (ret < 0) + { + snerr("ERROR: i2c_write failed: %d\n", ret); + return ret; + } + + sninfo("addr: %02x value: %02x\n", regaddr, regval); + + return OK; +} + +static int msa301_set_range(FAR struct msa301_dev_s *priv, msa301_range_t range) +{ + uint8_t ctl; + + if (range > MSA301_RANGE_16_G) + { + return -1; + } + + msa301_readreg8(priv, MSA301_REG_RESRANGE, &ctl); + ctl &= ~(MSA301_CTL_RANGE_MASK); + ctl |= (range << MSA301_CTL_RANGE_SHIFT); + msa301_writereg8(priv, MSA301_REG_RESRANGE, ctl); + + priv->range = range; + + return OK; +} + +static int msa301_set_rate(FAR struct msa301_dev_s *priv, msa301_rate_t rate) +{ + uint8_t ctl; + + msa301_readreg8(priv, MSA301_REG_ODR, &ctl); + ctl &= ~(MSA301_CTL_RATE_MASK); + ctl |= (rate << MSA301_CTL_RATE_SHIFT); + msa301_writereg8(priv, MSA301_REG_ODR, ctl); + + return OK; +} + +static int msa301_set_powermode(FAR struct msa301_dev_s *priv, msa301_powermode_t mode) +{ + uint8_t ctl; + + msa301_readreg8(priv, MSA301_REG_POWERMODE, &ctl); + ctl &= ~(MSA301_CTL_POWERMODE_MASK); + ctl |= (mode << MSA301_CTL_POWERMODE_SHIFT); + msa301_writereg8(priv, MSA301_REG_POWERMODE, ctl); + + return OK; +} + +static int msa301_set_resolution(FAR struct msa301_dev_s *priv, msa301_resolution_t resolution) +{ + uint8_t ctl; + + msa301_readreg8(priv, MSA301_REG_RESRANGE, &ctl); + ctl &= ~(MSA301_CTL_RESOLUTION_MASK); + ctl |= (resolution << MSA301_CTL_RESOLUTION_SHIFT); + msa301_writereg8(priv, MSA301_REG_RESRANGE, ctl); + + return OK; +} + +static int msa301_set_axis(FAR struct msa301_dev_s *priv, uint8_t enable) +{ + uint8_t ctl; + + msa301_readreg8(priv, MSA301_REG_ODR, &ctl); + ctl &= ~(MSA301_CTL_AXIS_MASK); + if (enable) + { + ctl |= (MSA301_ENABLE_AXIS << MSA301_CTL_AXIS_SHIFT); + } + else + { + ctl |= (MSA301_DISABLE_AXIS << MSA301_CTL_AXIS_SHIFT); + } + + msa301_writereg8(priv, MSA301_REG_ODR, ctl); + + return OK; +} + +static int msa301_sensor_config(FAR struct msa301_dev_s *priv) +{ + /* Sanity check */ + DEBUGASSERT(priv != NULL); + + msa301_set_resolution(priv, MSA301_RESOLUTION_14); + msa301_set_rate(priv, MSA301_RATE_500_HZ); + msa301_set_range(priv, MSA301_RANGE_4_G); + msa301_set_powermode(priv, MSA301_SUSPENDMODE); + + return OK; +} + +/**************************************************************************** + * Name: msa301_sensor_start + * + * Description: + * Start the accelerometer. + * + ****************************************************************************/ + +static int msa301_sensor_start(FAR struct msa301_dev_s *priv) +{ + /* Sanity check */ + DEBUGASSERT(priv != NULL); + + // Power normal + msa301_set_powermode(priv, MSA301_NORMALMODE); + + /* Enable the accelerometer */ + msa301_set_axis(priv, 1); + + up_mdelay(5); + + sninfo("Starting...."); + + return OK; +} + +/**************************************************************************** + * Name: msa301_sensor_stop + * + * Description: + * Stop the accelerometer. + * + ****************************************************************************/ + +static int msa301_sensor_stop(FAR struct msa301_dev_s *priv) +{ + /* Sanity check */ + DEBUGASSERT(priv != NULL); + + /* Disable the accelerometer */ + msa301_set_axis(priv, 0); + + // Power suspend + msa301_set_powermode(priv, MSA301_SUSPENDMODE); + + sninfo("Stoping...."); + + return OK; +} + +/**************************************************************************** + * Name: msa301_sensor_read + * + * Description: + * Read the sensor. + * A sensor in a steady state on a horizontal surface will + * measure 0 g on both the X-axis and Y-axis, whereas the Z-axis will + * measure 1 g. The X- and Y-axis have an offset + * of 40 mg/LSB + * + ****************************************************************************/ + +static int msa301_sensor_read(FAR struct msa301_dev_s *priv) +{ + DEBUGASSERT(priv != NULL); + + uint8_t xyz_value[6] = { 0 }; + if (msa301_readreg(priv, MSA301_REG_OUT_X_L, xyz_value, 6) < 0) + { + return -EIO; + } + + priv->sensor_data.x_data = xyz_value[1] << 8 | xyz_value[0]; + priv->sensor_data.y_data = xyz_value[3] << 8 | xyz_value[2]; + priv->sensor_data.z_data = xyz_value[5] << 8 | xyz_value[4]; + + /* 14 bit resolution */ + priv->sensor_data.x_data >>= 2; + priv->sensor_data.y_data >>= 2; + priv->sensor_data.z_data >>= 2; + + float scale = 1; + if (priv->range == MSA301_RANGE_2_G) + { + scale = 4096; + } + else if (priv->range == MSA301_RANGE_4_G) + { + scale = 2048; + } + else if (priv->range == MSA301_RANGE_8_G) + { + scale = 1024; + } + else if (priv->range == MSA301_RANGE_16_G) + { + scale = 512; + } + + priv->sensor_data.x_acc = (float)priv->sensor_data.x_data / scale; + priv->sensor_data.y_acc = (float)priv->sensor_data.y_data / scale; + priv->sensor_data.z_acc = (float)priv->sensor_data.z_data / scale; + + return OK; +} + +/**************************************************************************** + * Name: msa301_open + * + * Description: + * This method is called when the device is opened. + * + ****************************************************************************/ + +static int msa301_open(FAR struct file *filep) +{ + FAR struct inode * inode; + FAR struct msa301_dev_s *priv; + + DEBUGASSERT(filep != NULL); + inode = filep->f_inode; + + DEBUGASSERT(inode != NULL); + priv = (FAR struct msa301_dev_s *)inode->i_private; + + DEBUGASSERT(priv != NULL); + + nxsem_wait(&priv->exclsem); + + priv->ops->start(priv); + + return OK; +} + +/**************************************************************************** + * Name: msa301_close + * + * Description: + * This method is called when the device is closed. + * + ****************************************************************************/ + +static int msa301_close(FAR struct file *filep) +{ + FAR struct inode * inode; + FAR struct msa301_dev_s *priv; + + DEBUGASSERT(filep != NULL); + inode = filep->f_inode; + + DEBUGASSERT(inode != NULL); + priv = (FAR struct msa301_dev_s *)inode->i_private; + + DEBUGASSERT(priv != NULL); + + priv->ops->stop(priv); + + nxsem_post(&priv->exclsem); + + return OK; +} + +/**************************************************************************** + * Name: msa301_read + * + * Description: + * The standard read method. + * + ****************************************************************************/ + +static ssize_t msa301_read(FAR struct file *filep, + FAR char *buffer, size_t buflen) +{ + FAR struct inode * inode; + FAR struct msa301_dev_s *priv; + + /* Sanity check */ + + DEBUGASSERT(filep != NULL); + inode = filep->f_inode; + + DEBUGASSERT(inode != NULL); + priv = (FAR struct msa301_dev_s *)inode->i_private; + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(buffer != NULL); + + if (buflen < sizeof(struct msa301_sensor_data_s)) + { + return -ENOMEM; + } + + if (priv->ops->sensor_read(priv) < 0) + { + return -EIO; + } + + int datalen = sizeof(struct msa301_sensor_data_s); + memcpy(buffer, &priv->sensor_data, datalen); + + return datalen; +} + +/**************************************************************************** + * Name: msa301_write + * + * Description: + * A dummy write method. + * + ****************************************************************************/ + +static ssize_t msa301_write(FAR struct file *filep, + FAR const char *buffer, size_t buflen) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: msa301_ioctl + * + * Description: + * The standard ioctl method. + * + ****************************************************************************/ + +static int msa301_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode * inode; + FAR struct msa301_dev_s *priv; + int ret; + + /* Sanity check */ + + DEBUGASSERT(filep != NULL); + inode = filep->f_inode; + + DEBUGASSERT(inode != NULL); + priv = (FAR struct msa301_dev_s *)inode->i_private; + + DEBUGASSERT(priv != NULL); + + /* Handle ioctl commands */ + + switch (cmd) + { + case SNIOC_MSA301_START: + ret = priv->ops->start(priv); + break; + + case SNIOC_MSA301_STOP: + ret = priv->ops->stop(priv); + break; + + case SNIOC_MSA301_SET_RANGE: + ret = msa301_set_range(priv, arg); + break; + + case SNIOC_MSA301_SET_RATE: + ret = msa301_set_rate(priv, arg); + break; + + /* Unrecognized commands */ + default: + snerr("ERROR: Unrecognized cmd: %d arg: %lu\n", cmd, arg); + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: msa301_register + * + * Description: + * Register the msa301 accelerometer, gyroscope device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register, e.g. + * "/dev/msa301". + * i2c - An I2C driver instance. + * addr - The I2C address of the msa301 accelerometer, gyroscope or + * magnetometer. + * ops - The device operations structure. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int msa301_register(FAR const char * devpath, + FAR struct i2c_master_s * i2c, + uint8_t addr, + FAR const struct msa301_ops_s *ops) +{ + FAR struct msa301_dev_s *priv; + int ret; + + /* Sanity check */ + + DEBUGASSERT(devpath != NULL); + DEBUGASSERT(i2c != NULL); + + /* Initialize the device's structure */ + + priv = (FAR struct msa301_dev_s *)kmm_malloc(sizeof(*priv)); + if (priv == NULL) + { + snerr("ERROR: Failed to allocate instance\n"); + return -ENOMEM; + } + + priv->i2c = i2c; + priv->addr = addr; + priv->ops = ops; + + /* ID check */ + uint8_t id = 0; + msa301_readreg8(priv, MSA301_REG_PARTID, &id); + if (id != 0x13) + { + snerr("ERROR: Failed to read msa301 id\n"); + kmm_free(priv); + return -EIO; + } + + /* Configure the device */ + ret = priv->ops->config(priv); + if (ret < 0) + { + snerr("ERROR: Failed to configure device: %d\n", ret); + kmm_free(priv); + return ret; + } + + nxsem_init(&priv->exclsem, 0, 1); + + /* Register the character driver */ + ret = register_driver(devpath, &g_fops, 0666, priv); + if (ret < 0) + { + snerr("ERROR: Failed to register driver: %d\n", ret); + nxsem_destroy(&priv->exclsem); + kmm_free(priv); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: msa301_sensor_register + * + * Description: + * Register the msa301 accelerometer character device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register, + * e.g. "/dev/msa301". + * i2c - An I2C driver instance. + * addr - The I2C address of the msa301 accelerometer. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int msa301_sensor_register(FAR const char * devpath, + FAR struct i2c_master_s *i2c) +{ + return msa301_register(devpath, i2c, MSA301_ACCEL_ADDR0, &g_msa301_sensor_ops); +} +#endif /* CONFIG_I2C && CONFIG_SENSORS_MSA301 */ diff --git a/include/nuttx/sensors/msa301.h b/include/nuttx/sensors/msa301.h new file mode 100644 index 00000000000..05f517e6e0e --- /dev/null +++ b/include/nuttx/sensors/msa301.h @@ -0,0 +1,118 @@ +#ifndef __MSA301_H +#define __MSA301_H + +#include +#include + +#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_MSA301) + +#define MSA301_ACCEL_ADDR0 0x26 + +#define SNIOC_MSA301_START _SNIOC(0x0001) +#define SNIOC_MSA301_STOP _SNIOC(0x0002) +#define SNIOC_MSA301_SET_RANGE _SNIOC(0x0003) +#define SNIOC_MSA301_SET_RATE _SNIOC(0x0004) + +#define MSA301_REG_PARTID 0x01 +#define MSA301_REG_OUT_X_L 0x02 +#define MSA301_REG_OUT_X_H 0x03 +#define MSA301_REG_OUT_Y_L 0x04 +#define MSA301_REG_OUT_Y_H 0x05 +#define MSA301_REG_OUT_Z_L 0x06 +#define MSA301_REG_OUT_Z_H 0x07 +#define MSA301_REG_MOTIONINT 0x09 +#define MSA301_REG_DATAINT 0x0A +#define MSA301_REG_CLICKSTATUS 0x0B +#define MSA301_REG_RESRANGE 0x0F +#define MSA301_REG_ODR 0x10 +#define MSA301_REG_POWERMODE 0x11 +#define MSA301_REG_INTSET0 0x16 +#define MSA301_REG_INTSET1 0x17 +#define MSA301_REG_INTMAP0 0x19 +#define MSA301_REG_INTMAP1 0x1A +#define MSA301_REG_TAPDUR 0x2A +#define MSA301_REG_TAPTH 0x2B + +/** The accelerometer ranges */ +typedef enum { + MSA301_RANGE_2_G = 0x0, ///< +/- 2g + MSA301_RANGE_4_G = 0x1, ///< +/- 4g + MSA301_RANGE_8_G = 0x2, ///< +/- 8g + MSA301_RANGE_16_G = 0x3, ///< +/- 16g +} msa301_range_t; + +#define MSA301_CTL_RANGE_SHIFT (0x0) +#define MSA301_CTL_RANGE_MASK (0x3<<0) + +/** The accelerometer data rate */ +typedef enum { + MSA301_RATE_1_HZ = 0, ///< 1 Hz + MSA301_RATE_1_95_HZ = 1, ///< 1.95 Hz + MSA301_RATE_3_9_HZ = 2, ///< 3.9 Hz + MSA301_RATE_7_81_HZ = 3, ///< 7.81 Hz + MSA301_RATE_15_63_HZ = 4, ///< 15.63 Hz + MSA301_RATE_31_25_HZ = 5, ///< 31.25 Hz + MSA301_RATE_62_5_HZ = 6, ///< 62.5 Hz + MSA301_RATE_125_HZ = 7, ///< 125 Hz + MSA301_RATE_250_HZ = 8, ///< 250 Hz + MSA301_RATE_500_HZ = 9, ///< 500 Hz + MSA301_RATE_1000_HZ = 10, ///< 1000 Hz +} msa301_rate_t; + +#define MSA301_CTL_RATE_SHIFT (0x0) +#define MSA301_CTL_RATE_MASK (0xF<<0) + +#define MSA301_ENABLE_AXIS (0x0) +#define MSA301_DISABLE_AXIS (0x7) +#define MSA301_CTL_AXIS_SHIFT (0x05) +#define MSA301_CTL_AXIS_MASK (0x7<<5) + +/** The accelerometer power mode */ +typedef enum { + MSA301_NORMALMODE = 0x00, ///< Normal (high speed) mode + MSA301_LOWPOWERMODE = 0x01, ///< Low power (slow speed) mode + MSA301_SUSPENDMODE = 0x10, ///< Suspend (sleep) mode +} msa301_powermode_t; + +#define MSA301_CTL_POWERMODE_SHIFT (0x6) +#define MSA301_CTL_POWERMODE_MASK (0x3<<6) + +/** The accelerometer read resolution */ +typedef enum { + MSA301_RESOLUTION_14 = 0, ///< 14-bit resolution + MSA301_RESOLUTION_12 = 1, ///< 12-bit resolution + MSA301_RESOLUTION_10 = 2, ///< 10-bit resolution + MSA301_RESOLUTION_8 = 3, ///< 8-bit resolution +} msa301_resolution_t; + +#define MSA301_CTL_RESOLUTION_SHIFT (0x2) +#define MSA301_CTL_RESOLUTION_MASK (0x3<<2) + +struct msa301_sensor_data_s +{ + int16_t x_data; + int16_t y_data; + int16_t z_data; + + float x_acc; /* X axis acceleration */ + float y_acc; /* Y axis acceleration */ + float z_acc; /* Z axis acceleration */ +}; + + +#ifdef __cplusplus +extern "C" +{ +#endif + +int msa301_sensor_register(FAR const char *devpath, + FAR struct i2c_master_s *i2c + ); + +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_I2C && CONFIG_SENSORS_MSA301 */ +#endif +