diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 8690f659ccd..ae3d8cc2082 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -56,6 +56,8 @@ source "drivers/sensor/bmg160/Kconfig" source "drivers/sensor/bmi160/Kconfig" +source "drivers/sensor/bmm150/Kconfig" + source "drivers/sensor/dht/Kconfig" source "drivers/sensor/fxas21002/Kconfig" diff --git a/drivers/sensor/Makefile b/drivers/sensor/Makefile index 3214f330eb6..8ebbd6e8f97 100644 --- a/drivers/sensor/Makefile +++ b/drivers/sensor/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_BMC150_MAGN) += bmc150_magn/ obj-$(CONFIG_BME280) += bme280/ obj-$(CONFIG_BMG160) += bmg160/ obj-$(CONFIG_BMI160) += bmi160/ +obj-$(CONFIG_BMM150) += bmm150/ obj-$(CONFIG_DHT) += dht/ obj-$(CONFIG_FXAS21002) += fxas21002/ obj-$(CONFIG_FXOS8700) += fxos8700/ diff --git a/drivers/sensor/bmm150/Kconfig b/drivers/sensor/bmm150/Kconfig new file mode 100644 index 00000000000..f4c50befd9c --- /dev/null +++ b/drivers/sensor/bmm150/Kconfig @@ -0,0 +1,74 @@ +# Kconfig - BMM150 Geomagnetic sensor configuration options + +# +# Copyright (c) 2017 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +menuconfig BMM150 + bool "BMM150 I2C Geomagnetic Chip" + depends on SENSOR && I2C + default n + help + Enable driver for BMM150 I2C-based Geomagnetic sensor. +if BMM150 + +config BMM150_DEV_NAME + string "BMM150 device name" + default "bmm150" + +config BMM150_I2C_ADDR + hex "BMM150 I2C slave address" + default 0x10 + help + Specify the I2C slave address for the BMM150. + Possible addresses are 0x10,0x11,0x12,0x13. + +config BMM150_I2C_MASTER_DEV_NAME + string "I2C master where BMM150 is connected" + default "I2C_0" + help + Specify the device name of the I2C master device to which BMM150 + is connected. + +choice + prompt "Default preset" + default BMM150_PRESET_REGULAR + help + Specify the default preset (x/y oversampling, z oversampling, sampling + frequency). + +config BMM150_PRESET_LOW_POWER + bool "Low power (3, 3, 10)" + +config BMM150_PRESET_REGULAR + bool "Regular (9, 15, 10)" + +config BMM150_PRESET_ENHANCED_REGULAR + bool "Enhanced regular (15, 27, 10)" + +config BMM150_PRESET_HIGH_ACCURACY + bool "High accuracy (47, 83, 20)" + +endchoice + +config BMM150_SAMPLING_RATE_RUNTIME + bool "Enable dynamic sampling rate" + default n + help + Enable alteration of sampling rate attribute at runtime. + +config BMM150_SAMPLING_REP_XY + bool "Enable dynamic XY oversampling" + default n + help + Enable alteration of XY oversampling at runtime. + +config BMM150_SAMPLING_REP_Z + bool "Enable dynamic Z oversampling" + default n + help + Enable alteration of Z oversampling at runtime. + +endif # BMM150 diff --git a/drivers/sensor/bmm150/Makefile b/drivers/sensor/bmm150/Makefile new file mode 100644 index 00000000000..34c07841e23 --- /dev/null +++ b/drivers/sensor/bmm150/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_BMM150) += bmm150.o diff --git a/drivers/sensor/bmm150/bmm150.c b/drivers/sensor/bmm150/bmm150.c new file mode 100644 index 00000000000..720efef8106 --- /dev/null +++ b/drivers/sensor/bmm150/bmm150.c @@ -0,0 +1,606 @@ +/* bmm150.c - Driver for Bosch BMM150 Geomagnetic Sensor */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bmm150.h" + +static const struct { + int freq; + u8_t reg_val; +} bmm150_samp_freq_table[] = { { 2, 0x01 }, + { 6, 0x02 }, + { 8, 0x03 }, + { 10, 0x00 }, + { 15, 0x04 }, + { 20, 0x05 }, + { 25, 0x06 }, + { 30, 0x07 } }; + +static const struct bmm150_preset { + u8_t rep_xy; + u8_t rep_z; + u8_t odr; +} bmm150_presets_table[] = { + [BMM150_LOW_POWER_PRESET] = { 3, 3, 10 }, + [BMM150_REGULAR_PRESET] = { 9, 15, 10 }, + [BMM150_ENHANCED_REGULAR_PRESET] = { 15, 27, 10 }, + [BMM150_HIGH_ACCURACY_PRESET] = { 47, 83, 20 } +}; + +static int bmm150_set_power_mode(struct device *dev, + enum bmm150_power_modes mode, + int state) +{ + struct bmm150_data *data = dev->driver_data; + const struct bmm150_config *config = dev->config->config_info; + + switch (mode) { + case BMM150_POWER_MODE_SUSPEND: + if (i2c_reg_update_byte(data->i2c, + config->i2c_slave_addr, + BMM150_REG_POWER, + BMM150_MASK_POWER_CTL, + !state) < 0) { + return -EIO; + } + k_busy_wait(5 * USEC_PER_MSEC); + + return 0; + case BMM150_POWER_MODE_SLEEP: + return i2c_reg_update_byte(data->i2c, + config->i2c_slave_addr, + BMM150_REG_OPMODE_ODR, + BMM150_MASK_OPMODE, + BMM150_MODE_SLEEP << + BMM150_SHIFT_OPMODE); + break; + case BMM150_POWER_MODE_NORMAL: + return i2c_reg_update_byte(data->i2c, + config->i2c_slave_addr, + BMM150_REG_OPMODE_ODR, + BMM150_MASK_OPMODE, + BMM150_MODE_NORMAL << + BMM150_SHIFT_OPMODE); + break; + } + + return -ENOTSUP; + +} + +static int bmm150_set_odr(struct device *dev, u8_t val) +{ + struct bmm150_data *data = dev->driver_data; + const struct bmm150_config *config = dev->config->config_info; + u8_t i; + + for (i = 0; i < ARRAY_SIZE(bmm150_samp_freq_table); ++i) { + if (val <= bmm150_samp_freq_table[i].freq) { + return i2c_reg_update_byte(data->i2c, + config->i2c_slave_addr, + BMM150_REG_OPMODE_ODR, + BMM150_MASK_ODR, + (bmm150_samp_freq_table[i]. + reg_val << + BMM150_SHIFT_ODR)); + } + } + return -ENOTSUP; +} + +#if defined(BMM150_SET_ATTR) +static int bmm150_read_rep_xy(struct device *dev) +{ + struct bmm150_data *data = dev->driver->data; + const struct bmm150_config *config = dev->config->config_info; + u8_t reg_val; + + if (i2c_reg_read_byte(data->i2c, config->i2c_slave_addr, + BMM150_REG_REP_XY, ®_val) < 0) { + return -EIO; + } + + data->rep_xy = BMM150_REGVAL_TO_REPXY((u8_t)(reg_val)); + + return 0; +} + +static int bmm150_read_rep_z(struct device *dev) +{ + struct bmm150_data *data = dev->driver_data; + const struct bmm150_config *config = dev->config->config_info; + u8_t reg_val; + + if (i2c_reg_read_byte(data->i2c, config->i2c_slave_addr, + BMM150_REG_REP_Z, ®_val) < 0) { + return -EIO; + } + + data->rep_z = BMM150_REGVAL_TO_REPZ((int)(reg_val)); + + return 0; +} + +static int bmm150_compute_max_odr(struct device *dev, int rep_xy, + int rep_z, int *max_odr) +{ + struct bmm150_data *data = dev->driver_data; + + if (rep_xy == 0) { + if (data->rep_xy <= 0) { + if (bmm150_read_rep_xy(dev) < 0) { + return -EIO; + } + } + rep_xy = data->rep_xy; + } + + if (rep_z == 0) { + if (data->rep_z <= 0) { + if (bmm150_read_rep_z(dev) < 0) { + return -EIO; + } + } + rep_z = data->rep_z; + } + + /* Equation reference Datasheet 4.2.4 */ + *max_odr = 1000000 / (145 * rep_xy + 500 * rep_z + 980); + + return 0; +} +#endif + +#if defined(BMM150_SET_ATTR_REP) +static int bmm150_read_odr(struct device *dev) +{ + struct bmm150_data *data = dev->driver_data; + const struct bmm150_config *config = dev->config->config_info; + u8_t i, odr_val, reg_val; + + if (i2c_reg_read_byte(data->i2c, config->i2c_slave_addr, + BMM150_REG_OPMODE_ODR, ®_val) < 0) { + return -EIO; + } + + odr_val = (reg_val & BMM150_MASK_ODR) >> BMM150_SHIFT_ODR; + + for (i = 0; i < ARRAY_SIZE(bmm150_samp_freq_table); ++i) { + if (bmm150_samp_freq_table[i].reg_val == odr_val) { + data->odr = bmm150_samp_freq_table[i].freq; + return 0; + } + } + + return -ENOTSUP; +} +#endif + +#if defined(CONFIG_BMM150_SAMPLING_REP_XY) +static int bmm150_write_rep_xy(struct device *dev, int val) +{ + struct bmm150_data *data = dev->driver_data; + const struct bmm150_config *config = dev->config->config_info; + + if (i2c_reg_update_byte(data->i2c, config->i2c_slave_addr, + BMM150_REG_REP_XY, + BMM150_REG_REP_DATAMASK, + BMM150_REPXY_TO_REGVAL(val)) < 0) { + return -EIO; + } + + data->rep_xy = val; + + return 0; +} +#endif + +#if defined(CONFIG_BMM150_SAMPLING_REP_Z) +static int bmm150_write_rep_z(struct device *dev, int val) +{ + struct bmm150_data *data = dev->driver_data; + const struct bmm150_config *config = dev->config->config_info; + + if (i2c_reg_update_byte(data->i2c, config->i2c_slave_addr, + BMM150_REG_REP_Z, + BMM150_REG_REP_DATAMASK, + BMM150_REPZ_TO_REGVAL(val)) < 0) { + return -EIO; + } + + data->rep_z = val; + + return 0; +} +#endif + +/* Reference Datasheet 4.3.2 */ +static s32_t bmm150_compensate_xy(struct bmm150_trim_regs *tregs, + s16_t xy, uint16_t rhall, bool is_x) +{ + s8_t txy1, txy2; + s16_t val; + u16_t prevalue; + s32_t temp1, temp2, temp3; + + if (xy == BMM150_XY_OVERFLOW_VAL) { + return INT32_MIN; + } + + if (!rhall) { + rhall = tregs->xyz1; + } + + if (is_x) { + txy1 = tregs->x1; + txy2 = tregs->x2; + } else { + txy1 = tregs->y1; + txy2 = tregs->y2; + } + + prevalue = (u16_t)((((s32_t)tregs->xyz1) << 14) / rhall); + + val = (s16_t)((prevalue) - ((u16_t)0x4000)); + + temp1 = (((s32_t)tregs->xy2) * ((((s32_t)val) * ((s32_t)val)) >> 7)); + + temp2 = ((s32_t)val) * ((s32_t)(((s16_t)tregs->xy1) << 7)); + + temp3 = (((((temp1 + temp2) >> 9) + + ((s32_t)0x100000)) * ((s32_t)(((s16_t)txy2) + + ((s16_t)0xA0)))) >> 12); + + val = ((s16_t)((((s32_t)xy) * temp3) >> 13)) + (((s16_t)txy1) << 3); + + return (int32_t)val; +} + +static s32_t bmm150_compensate_z(struct bmm150_trim_regs *tregs, + s16_t z, u16_t rhall) +{ + s32_t val, temp1, temp2; + s16_t temp3; + + if (z == BMM150_Z_OVERFLOW_VAL) { + return INT32_MIN; + } + + temp1 = (((s32_t)(z - tregs->z4)) << 15); + + temp2 = ((((s32_t)tregs->z3) * + ((s32_t)(((s16_t)rhall) - ((s16_t)tregs->xyz1)))) >> 2); + + temp3 = ((s16_t)(((((s32_t)tregs->z1) * + ((((s16_t)rhall) << 1))) + (1 << 15)) >> 16)); + + val = ((temp1 - temp2) / (tregs->z2 + temp3)); + + return val; +} + +static int bmm150_sample_fetch(struct device *dev, enum sensor_channel chan) +{ + + struct bmm150_data *drv_data = dev->driver_data; + const struct bmm150_config *config = dev->config->config_info; + u16_t values[BMM150_AXIS_XYZR_MAX]; + s16_t raw_x, raw_y, raw_z; + u16_t rhall; + + __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || + chan == SENSOR_CHAN_MAGN_ANY); + + if (i2c_burst_read(drv_data->i2c, config->i2c_slave_addr, + BMM150_REG_X_L, (u8_t *)values, + sizeof(values)) < 0) { + SYS_LOG_ERR("failed to read sample"); + return -EIO; + } + + raw_x = (s16_t)sys_le16_to_cpu(values[BMM150_AXIS_X]) >> + BMM150_SHIFT_XY_L; + raw_y = (s16_t)sys_le16_to_cpu(values[BMM150_AXIS_Y]) >> + BMM150_SHIFT_XY_L; + raw_z = (s16_t)sys_le16_to_cpu(values[BMM150_AXIS_Z]) >> + BMM150_SHIFT_Z_L; + + rhall = sys_le16_to_cpu(values[BMM150_RHALL]) >> + BMM150_SHIFT_RHALL_L; + + drv_data->sample_x = bmm150_compensate_xy(&drv_data->tregs, + raw_x, rhall, true); + drv_data->sample_y = bmm150_compensate_xy(&drv_data->tregs, + raw_y, rhall, false); + drv_data->sample_z = bmm150_compensate_z(&drv_data->tregs, + raw_z, rhall); + + return 0; +} + +/* + * Datasheet specify raw units are 16 LSB/uT and this function converts it to + * Gauss + */ +static void bmm150_convert(struct sensor_value *val, int raw_val) +{ + /* val = raw_val / 1600 */ + val->val1 = raw_val / 1600; + val->val2 = ((s32_t)raw_val * (1000000 / 1600)) % 1000000; +} + +static int bmm150_channel_get(struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct bmm150_data *drv_data = dev->driver_data; + + switch (chan) { + case SENSOR_CHAN_MAGN_X: + bmm150_convert(val, drv_data->sample_x); + break; + case SENSOR_CHAN_MAGN_Y: + bmm150_convert(val, drv_data->sample_y); + break; + case SENSOR_CHAN_MAGN_Z: + bmm150_convert(val, drv_data->sample_x); + break; + case SENSOR_CHAN_MAGN_ANY: + bmm150_convert(val, drv_data->sample_x); + bmm150_convert(val + 1, drv_data->sample_y); + bmm150_convert(val + 2, drv_data->sample_z); + break; + default: + return -EINVAL; + } + + return 0; +} + +#if defined(BMM150_SET_ATTR_REP) +static inline int bmm150_attr_set_rep(struct device *dev, + enum sensor_channel chan, + const struct sensor_value *val) +{ + struct bmm150_data *data = dev->driver_data; + int max_odr; + + switch (chan) { +#if defined(CONFIG_BMM150_SAMPLING_REP_XY) + case SENSOR_CHAN_MAGN_X: + case SENSOR_CHAN_MAGN_Y: + if (val->val1 < 1 || val->val1 > 511) { + return -EINVAL; + } + + if (bmm150_compute_max_odr(dev, val->val1, 0, + &max_odr) < 0) { + return -EIO; + } + + if (data->odr <= 0) { + if (bmm150_read_odr(dev) < 0) { + return -EIO; + } + } + + if (data->odr > max_odr) { + return -EINVAL; + } + + if (bmm150_write_rep_xy(dev, val->val1) < 0) { + return -EIO; + } + break; +#endif + +#if defined(CONFIG_BMM150_SAMPLING_REP_Z) + case SENSOR_CHAN_MAGN_Z: + if (val->val1 < 1 || val->val1 > 256) { + return -EINVAL; + } + + if (bmm150_compute_max_odr(dev, 0, val->val1, + &max_odr) < 0) { + return -EIO; + } + + if (data->odr <= 0) { + if (bmm150_read_odr(dev) < 0) { + return -EIO; + } + } + + if (data->odr > max_odr) { + return -EINVAL; + } + + if (bmm150_write_rep_z(dev, val->val1) < 0) { + return -EIO; + } + break; +#endif + default: + return -EINVAL; + } + + return 0; +} +#endif + +#if defined(BMM150_SET_ATTR) +static int bmm150_attr_set(struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + struct bmm150_magn_data *data = dev->driver_data; + + switch (attr) { +#if defined(CONFIG_BMM150_SAMPLING_RATE_RUNTIME) + case SENSOR_ATTR_SAMPLING_FREQUENCY: + if (data->max_odr <= 0) { + if (bmm150_compute_max_odr(dev, 0, 0, + &data->max_odr) < 0) { + return -EIO; + } + } + + if (data->max_odr < val->val1) { + SYS_LOG_ERR("not supported with current oversampling"); + return -ENOTSUP; + } + + if (bmm150_set_odr(dev, (u8_t)(val->val1)) < 0) { + return -EIO; + } + break; +#endif +#if defined(BMM150_SET_ATTR_REP) + case SENSOR_ATTR_OVERSAMPLING: + bmm150_attr_set_rep(dev, chan, val); + break; +#endif + default: + return -EINVAL; + } + + return 0; +} +#endif + +static const struct sensor_driver_api bmm150_api_funcs = { +#if defined(BMM150_SET_ATTR) + .attr_set = bmm150_attr_set, +#endif + .sample_fetch = bmm150_sample_fetch, + .channel_get = bmm150_channel_get, +}; + +static int bmm150_init_chip(struct device *dev) +{ + struct bmm150_data *data = dev->driver_data; + const struct bmm150_config *config = dev->config->config_info; + u8_t chip_id; + struct bmm150_preset preset; + + if (bmm150_set_power_mode(dev, BMM150_POWER_MODE_NORMAL, 0) < 0) { + SYS_LOG_ERR("failed to bring up device from normal mode"); + return -EIO; + } + + if (bmm150_set_power_mode(dev, BMM150_POWER_MODE_SUSPEND, 1) < 0) { + SYS_LOG_ERR("failed to bring up device in suspend mode"); + return -EIO; + } + + if (bmm150_set_power_mode(dev, BMM150_POWER_MODE_SUSPEND, 0) + < 0) { + SYS_LOG_ERR("failed to bring up device from suspend mode"); + return -EIO; + } + + if (i2c_reg_read_byte(data->i2c, config->i2c_slave_addr, + BMM150_REG_CHIP_ID, &chip_id) < 0) { + SYS_LOG_ERR("failed reading chip id"); + goto err_poweroff; + } + + if (chip_id != BMM150_CHIP_ID_VAL) { + SYS_LOG_ERR("invalid chip id 0x%x", chip_id); + goto err_poweroff; + } + + preset = bmm150_presets_table[BMM150_DEFAULT_PRESET]; + if (bmm150_set_odr(dev, preset.odr) < 0) { + SYS_LOG_ERR("failed to set ODR to %d", + preset.odr); + goto err_poweroff; + } + + if (i2c_reg_write_byte(data->i2c, config->i2c_slave_addr, + BMM150_REG_REP_XY, + BMM150_REPXY_TO_REGVAL(preset.rep_xy)) + < 0) { + SYS_LOG_ERR("failed to set REP XY to %d", + preset.rep_xy); + goto err_poweroff; + } + + if (i2c_reg_write_byte(data->i2c, config->i2c_slave_addr, + BMM150_REG_REP_Z, + BMM150_REPZ_TO_REGVAL(preset.rep_z)) < 0) { + SYS_LOG_ERR("failed to set REP Z to %d", + preset.rep_z); + goto err_poweroff; + } + + if (bmm150_set_power_mode(dev, BMM150_POWER_MODE_NORMAL, 1) + < 0) { + SYS_LOG_ERR("failed to power on device"); + } + + if (i2c_burst_read(data->i2c, config->i2c_slave_addr, + BMM150_REG_TRIM_START, (u8_t *)&data->tregs, + sizeof(data->tregs)) < 0) { + SYS_LOG_ERR("failed to read trim regs"); + goto err_poweroff; + } + + data->rep_xy = 0; + data->rep_z = 0; + data->odr = 0; + data->max_odr = 0; + data->sample_x = 0; + data->sample_y = 0; + data->sample_z = 0; + + data->tregs.xyz1 = sys_le16_to_cpu(data->tregs.xyz1); + data->tregs.z1 = sys_le16_to_cpu(data->tregs.z1); + data->tregs.z2 = sys_le16_to_cpu(data->tregs.z2); + data->tregs.z3 = sys_le16_to_cpu(data->tregs.z3); + data->tregs.z4 = sys_le16_to_cpu(data->tregs.z4); + + return 0; + +err_poweroff: + bmm150_set_power_mode(dev, BMM150_POWER_MODE_NORMAL, 0); + bmm150_set_power_mode(dev, BMM150_POWER_MODE_SUSPEND, 1); + return -EIO; +} + +static int bmm150_init(struct device *dev) +{ + const struct bmm150_config *const config = + dev->config->config_info; + struct bmm150_data *data = dev->driver_data; + + data->i2c = device_get_binding(config->i2c_master_dev_name); + if (!data->i2c) { + SYS_LOG_ERR("i2c master not found: %s", + config->i2c_master_dev_name); + return -EINVAL; + } + + if (bmm150_init_chip(dev) < 0) { + SYS_LOG_ERR("failed to initialize chip"); + return -EIO; + } + + return 0; +} + +static const struct bmm150_config bmm150_config = { + .i2c_master_dev_name = CONFIG_BMM150_I2C_MASTER_DEV_NAME, + .i2c_slave_addr = BMM150_I2C_ADDR, +}; + +static struct bmm150_data bmm150_data; + +DEVICE_AND_API_INIT(bmm150, CONFIG_BMM150_DEV_NAME, bmm150_init, + &bmm150_data, &bmm150_config, POST_KERNEL, + CONFIG_SENSOR_INIT_PRIORITY, &bmm150_api_funcs); diff --git a/drivers/sensor/bmm150/bmm150.h b/drivers/sensor/bmm150/bmm150.h new file mode 100644 index 00000000000..82c731ea54d --- /dev/null +++ b/drivers/sensor/bmm150/bmm150.h @@ -0,0 +1,164 @@ +/* sensor_bmm150.h - header file for BMM150 Geomagnetic sensor driver */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SENSOR_BMM150_H_ +#define _SENSOR_BMM150_H_ + + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#define BMM150_REG_CHIP_ID 0x40 +#define BMM150_CHIP_ID_VAL 0x32 + +#define BMM150_REG_X_L 0x42 +#define BMM150_REG_X_M 0x43 +#define BMM150_REG_Y_L 0x44 +#define BMM150_REG_Y_M 0x45 +#define BMM150_SHIFT_XY_L 3 +#define BMM150_REG_Z_L 0x46 +#define BMM150_REG_Z_M 0x47 +#define BMM150_SHIFT_Z_L 1 +#define BMM150_REG_RHALL_L 0x48 +#define BMM150_REG_RHALL_M 0x49 +#define BMM150_SHIFT_RHALL_L 2 + +#define BMM150_REG_INT_STATUS 0x4A + +#define BMM150_REG_POWER 0x4B +#define BMM150_MASK_POWER_CTL BIT(0) + +#define BMM150_REG_OPMODE_ODR 0x4C +#define BMM150_MASK_OPMODE (BIT(2) | BIT(1)) +#define BMM150_SHIFT_OPMODE 1 +#define BMM150_MODE_NORMAL 0x00 +#define BMM150_MODE_FORCED 0x01 +#define BMM150_MODE_SLEEP 0x03 +#define BMM150_MASK_ODR (BIT(5) | BIT(4) | BIT(3)) +#define BMM150_SHIFT_ODR 3 + +#define BMM150_REG_LOW_THRESH 0x4F +#define BMM150_REG_HIGH_THRESH 0x50 +#define BMM150_REG_REP_XY 0x51 +#define BMM150_REG_REP_Z 0x52 +#define BMM150_REG_REP_DATAMASK 0xFF + +#define BMM150_REG_TRIM_START 0x5D +#define BMM150_REG_TRIM_END 0x71 + +#define BMM150_XY_OVERFLOW_VAL -4096 +#define BMM150_Z_OVERFLOW_VAL -16384 + +#define BMM150_REGVAL_TO_REPXY(regval) (((regval) * 2) + 1) +#define BMM150_REGVAL_TO_REPZ(regval) ((regval) + 1) +#define BMM150_REPXY_TO_REGVAL(rep) (((rep) - 1) / 2) +#define BMM150_REPZ_TO_REGVAL(rep) ((rep) - 1) + +#define BMM150_REG_INT 0x4D + +#define BMM150_REG_INT_DRDY 0x4E +#define BMM150_MASK_DRDY_EN BIT(7) +#define BMM150_SHIFT_DRDY_EN 7 +#define BMM150_DRDY_INT3 BIT(6) +#define BMM150_MASK_DRDY_Z_EN BIT(5) +#define BMM150_MASK_DRDY_Y_EN BIT(4) +#define BMM150_MASK_DRDY_X_EN BIT(3) +#define BMM150_MASK_DRDY_DR_POLARITY BIT(2) +#define BMM150_SHIFT_DRDY_DR_POLARITY 2 +#define BMM150_MASK_DRDY_LATCHING BIT(1) +#define BMM150_MASK_DRDY_INT3_POLARITY BIT(0) + +#define BMM150_I2C_ADDR CONFIG_BMM150_I2C_ADDR + +#if defined(CONFIG_BMM150_SAMPLING_REP_XY) || \ + defined(CONFIG_BMM150_SAMPLING_REP_Z) + #define BMM150_SET_ATTR_REP +#endif + +#if defined(CONFIG_BMM150_MAGN_SAMPLING_RATE_RUNTIME) || \ + defined(BMM150_MAGN_SET_ATTR_REP) + #define BMM150_MAGN_SET_ATTR +#endif + + +struct bmm150_config { + char *i2c_master_dev_name; + u16_t i2c_slave_addr; +}; + +struct bmm150_trim_regs { + s8_t x1; + s8_t y1; + u16_t reserved1; + u8_t reserved2; + s16_t z4; + s8_t x2; + s8_t y2; + u16_t reserved3; + s16_t z2; + u16_t z1; + u16_t xyz1; + s16_t z3; + s8_t xy2; + u8_t xy1; +} __packed; + +struct bmm150_data { + struct device *i2c; + struct k_sem sem; + struct bmm150_trim_regs tregs; + int rep_xy, rep_z, odr, max_odr; + int sample_x, sample_y, sample_z; +}; + +enum bmm150_power_modes { + BMM150_POWER_MODE_SUSPEND, + BMM150_POWER_MODE_SLEEP, + BMM150_POWER_MODE_NORMAL +}; + +enum bmm150_axis { + BMM150_AXIS_X, + BMM150_AXIS_Y, + BMM150_AXIS_Z, + BMM150_RHALL, + BMM150_AXIS_XYZ_MAX = BMM150_RHALL, + BMM150_AXIS_XYZR_MAX +}; + +enum bmm150_presets { + BMM150_LOW_POWER_PRESET, + BMM150_REGULAR_PRESET, + BMM150_ENHANCED_REGULAR_PRESET, + BMM150_HIGH_ACCURACY_PRESET +}; + +#if defined(CONFIG_BMM150_PRESET_LOW_POWER) + #define BMM150_DEFAULT_PRESET BMM150LOW_POWER_PRESET +#elif defined(CONFIG_BMM150_PRESET_REGULAR) + #define BMM150_DEFAULT_PRESET BMM150_REGULAR_PRESET +#elif defined(CONFIG_BMM150_PRESET_ENHANCED_REGULAR) + #define BMM150_DEFAULT_PRESET BMM150_ENHANCED_REGULAR_PRESET +#elif defined(CONFIG_BMM150_PRESET_HIGH_ACCURACY) + #define BMM150_DEFAULT_PRESET BMM150_HIGH_ACCURACY_PRESET +#endif + +#define SYS_LOG_DOMAIN "BMM150" +#define SYS_LOG_LEVEL CONFIG_SYS_LOG_SENSOR_LEVEL +#include +#endif /* __SENSOR_BMM150_H__ */