766 lines
20 KiB
C
766 lines
20 KiB
C
/* sensor_lsm9ds0_mfd.c - Driver for LSM9DS0 accelerometer, magnetometer
|
|
* and temperature (MFD) sensor driver
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2016 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT st_lsm9ds0_mfd
|
|
|
|
#include <zephyr/drivers/sensor.h>
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/device.h>
|
|
#include <zephyr/init.h>
|
|
#include <zephyr/drivers/i2c.h>
|
|
#include <zephyr/sys/byteorder.h>
|
|
#include <zephyr/drivers/gpio.h>
|
|
#include <zephyr/logging/log.h>
|
|
|
|
#include "lsm9ds0_mfd.h"
|
|
|
|
LOG_MODULE_REGISTER(LSM9DS0_MFD, CONFIG_SENSOR_LOG_LEVEL);
|
|
|
|
static inline int lsm9ds0_mfd_reboot_memory(const struct device *dev)
|
|
{
|
|
const struct lsm9ds0_mfd_config *config = dev->config;
|
|
|
|
if (i2c_reg_update_byte_dt(&config->i2c, LSM9DS0_MFD_REG_CTRL_REG0_XM,
|
|
LSM9DS0_MFD_MASK_CTRL_REG0_XM_BOOT,
|
|
1 << LSM9DS0_MFD_SHIFT_CTRL_REG0_XM_BOOT) < 0) {
|
|
return -EIO;
|
|
}
|
|
|
|
k_busy_wait(USEC_PER_MSEC * 50U);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if !defined(LSM9DS0_MFD_ACCEL_DISABLED)
|
|
static inline int lsm9ds0_mfd_accel_set_odr_raw(const struct device *dev,
|
|
uint8_t odr)
|
|
{
|
|
const struct lsm9ds0_mfd_config *config = dev->config;
|
|
|
|
return i2c_reg_update_byte_dt(&config->i2c, LSM9DS0_MFD_REG_CTRL_REG1_XM,
|
|
LSM9DS0_MFD_MASK_CTRL_REG1_XM_AODR,
|
|
odr << LSM9DS0_MFD_SHIFT_CTRL_REG1_XM_AODR);
|
|
}
|
|
|
|
#if defined(CONFIG_LSM9DS0_MFD_ACCEL_SAMPLING_RATE_RUNTIME)
|
|
static const struct {
|
|
int freq_int;
|
|
int freq_micro;
|
|
} lsm9ds0_mfd_accel_odr_map[] = { {0, 0},
|
|
{3, 125000},
|
|
{6, 250000},
|
|
{12, 500000},
|
|
{25, 0},
|
|
{50, 0},
|
|
{100, 0},
|
|
{200, 0},
|
|
{400, 0},
|
|
{800, 0},
|
|
{1600, 0} };
|
|
|
|
static int lsm9ds0_mfd_accel_set_odr(const struct device *dev,
|
|
const struct sensor_value *val)
|
|
{
|
|
uint8_t i;
|
|
|
|
for (i = 0U; i < ARRAY_SIZE(lsm9ds0_mfd_accel_odr_map); ++i) {
|
|
if (val->val1 < lsm9ds0_mfd_accel_odr_map[i].freq_int ||
|
|
(val->val1 == lsm9ds0_mfd_accel_odr_map[i].freq_int &&
|
|
val->val2 <= lsm9ds0_mfd_accel_odr_map[i].freq_micro)) {
|
|
return lsm9ds0_mfd_accel_set_odr_raw(dev, i);
|
|
}
|
|
}
|
|
|
|
return -ENOTSUP;
|
|
}
|
|
#endif
|
|
|
|
static inline int lsm9ds0_mfd_accel_set_fs_raw(const struct device *dev,
|
|
uint8_t fs)
|
|
{
|
|
const struct lsm9ds0_mfd_config *config = dev->config;
|
|
|
|
if (i2c_reg_update_byte_dt(&config->i2c, LSM9DS0_MFD_REG_CTRL_REG2_XM,
|
|
LSM9DS0_MFD_MASK_CTRL_REG2_XM_AFS,
|
|
fs << LSM9DS0_MFD_SHIFT_CTRL_REG2_XM_AFS) < 0) {
|
|
return -EIO;
|
|
}
|
|
|
|
#if defined(CONFIG_LSM9DS0_MFD_ACCEL_FULL_SCALE_RUNTIME)
|
|
data->accel_fs = fs;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_LSM9DS0_MFD_ACCEL_FULL_SCALE_RUNTIME)
|
|
static const struct {
|
|
int fs;
|
|
} lsm9ds0_mfd_accel_fs_map[] = { {2},
|
|
{4},
|
|
{6},
|
|
{8},
|
|
{16} };
|
|
|
|
static int lsm9ds0_mfd_accel_set_fs(const struct device *dev, int val)
|
|
{
|
|
uint8_t i;
|
|
|
|
for (i = 0U; i < ARRAY_SIZE(lsm9ds0_mfd_accel_fs_map); ++i) {
|
|
if (val <= lsm9ds0_mfd_accel_fs_map[i].fs) {
|
|
return lsm9ds0_mfd_accel_set_fs_raw(dev, i);
|
|
}
|
|
}
|
|
|
|
return -ENOTSUP;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if !defined(LSM9DS0_MFD_MAGN_DISABLED)
|
|
static inline int lsm9ds0_mfd_magn_set_odr_raw(const struct device *dev,
|
|
uint8_t odr)
|
|
{
|
|
const struct lsm9ds0_mfd_config *config = dev->config;
|
|
|
|
return i2c_reg_update_byte_dt(&config->i2c, LSM9DS0_MFD_REG_CTRL_REG5_XM,
|
|
LSM9DS0_MFD_MASK_CTRL_REG5_XM_M_ODR,
|
|
odr << LSM9DS0_MFD_SHIFT_CTRL_REG5_XM_M_ODR);
|
|
}
|
|
|
|
#if defined(CONFIG_LSM9DS0_MFD_MAGN_SAMPLING_RATE_RUNTIME)
|
|
static const struct {
|
|
int freq_int;
|
|
int freq_micro;
|
|
} lsm9ds0_mfd_magn_odr_map[] = { {0, 0},
|
|
{3, 125000},
|
|
{6, 250000},
|
|
{12, 500000},
|
|
{25, 0},
|
|
{50, 0},
|
|
{100, 0} };
|
|
|
|
static int lsm9ds0_mfd_magn_set_odr(const struct device *dev,
|
|
const struct sensor_value *val)
|
|
{
|
|
uint8_t i;
|
|
|
|
for (i = 0U; i < ARRAY_SIZE(lsm9ds0_mfd_accel_odr_map); ++i) {
|
|
if (val->val1 < lsm9ds0_mfd_accel_odr_map[i].freq_int ||
|
|
(val->val1 == lsm9ds0_mfd_accel_odr_map[i].freq_int &&
|
|
val->val2 <= lsm9ds0_mfd_accel_odr_map[i].freq_micro)) {
|
|
return lsm9ds0_mfd_magn_set_odr_raw(dev, i);
|
|
}
|
|
}
|
|
|
|
return -ENOTSUP;
|
|
}
|
|
#endif
|
|
|
|
static inline int lsm9ds0_mfd_magn_set_fs_raw(const struct device *dev,
|
|
uint8_t fs)
|
|
{
|
|
const struct lsm9ds0_mfd_config *config = dev->config;
|
|
|
|
if (i2c_reg_update_byte_dt(&config->i2c, LSM9DS0_MFD_REG_CTRL_REG6_XM,
|
|
LSM9DS0_MFD_MASK_CTRL_REG6_XM_MFS,
|
|
fs << LSM9DS0_MFD_SHIFT_CTRL_REG6_XM_MFS) < 0) {
|
|
return -EIO;
|
|
}
|
|
|
|
#if defined(CONFIG_LSM9DS0_MFD_MAGN_FULL_SCALE_RUNTIME)
|
|
data->magn_fs = fs;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_LSM9DS0_MFD_MAGN_FULL_SCALE_RUNTIME)
|
|
static const struct {
|
|
int fs;
|
|
} lsm9ds0_mfd_magn_fs_map[] = { {2},
|
|
{4},
|
|
{8},
|
|
{12} };
|
|
|
|
static int lsm9ds0_mfd_magn_set_fs(const struct device *dev,
|
|
const struct sensor_value *val)
|
|
{
|
|
uint8_t i;
|
|
|
|
for (i = 0U; i < ARRAY_SIZE(lsm9ds0_mfd_magn_fs_map); ++i) {
|
|
if (val->val1 <= lsm9ds0_mfd_magn_fs_map[i].fs) {
|
|
return lsm9ds0_mfd_magn_set_fs_raw(dev, i);
|
|
}
|
|
}
|
|
|
|
return -ENOTSUP;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if !defined(LSM9DS0_MFD_ACCEL_DISABLED)
|
|
static inline int lsm9ds0_mfd_sample_fetch_accel(const struct device *dev)
|
|
{
|
|
struct lsm9ds0_mfd_data *data = dev->data;
|
|
const struct lsm9ds0_mfd_config *config = dev->config;
|
|
uint8_t out_l, out_h;
|
|
|
|
#if defined(CONFIG_LSM9DS0_MFD_ACCEL_ENABLE_X)
|
|
if (i2c_reg_read_byte_dt(&config->i2c, LSM9DS0_MFD_REG_OUT_X_L_A, &out_l) < 0 ||
|
|
i2c_reg_read_byte_dt(&config->i2c, LSM9DS0_MFD_REG_OUT_X_H_A, &out_h) < 0) {
|
|
LOG_DBG("failed to read accel sample (X axis)");
|
|
return -EIO;
|
|
}
|
|
|
|
data->sample_accel_x = (int16_t)((uint16_t)(out_l) |
|
|
((uint16_t)(out_h) << 8));
|
|
#endif
|
|
|
|
#if defined(CONFIG_LSM9DS0_MFD_ACCEL_ENABLE_Y)
|
|
if (i2c_reg_read_byte_dt(&config->i2c, LSM9DS0_MFD_REG_OUT_Y_L_A, &out_l) < 0 ||
|
|
i2c_reg_read_byte_dt(&config->i2c, LSM9DS0_MFD_REG_OUT_Y_H_A, &out_h) < 0) {
|
|
LOG_DBG("failed to read accel sample (Y axis)");
|
|
return -EIO;
|
|
}
|
|
|
|
data->sample_accel_y = (int16_t)((uint16_t)(out_l) |
|
|
((uint16_t)(out_h) << 8));
|
|
#endif
|
|
|
|
#if defined(CONFIG_LSM9DS0_MFD_ACCEL_ENABLE_Z)
|
|
if (i2c_reg_read_byte_dt(&config->i2c, LSM9DS0_MFD_REG_OUT_Z_L_A, &out_l) < 0 ||
|
|
i2c_reg_read_byte_dt(&config->i2c, LSM9DS0_MFD_REG_OUT_Z_H_A, &out_h) < 0) {
|
|
LOG_DBG("failed to read accel sample (Z axis)");
|
|
return -EIO;
|
|
}
|
|
|
|
data->sample_accel_z = (int16_t)((uint16_t)(out_l) |
|
|
((uint16_t)(out_h) << 8));
|
|
#endif
|
|
|
|
#if defined(CONFIG_LSM9DS0_MFD_ACCEL_FULL_SCALE_RUNTIME)
|
|
data->sample_accel_fs = data->accel_fs;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(LSM9DS0_MFD_MAGN_DISABLED)
|
|
static inline int lsm9ds0_mfd_sample_fetch_magn(const struct device *dev)
|
|
{
|
|
struct lsm9ds0_mfd_data *data = dev->data;
|
|
const struct lsm9ds0_mfd_config *config = dev->config;
|
|
uint8_t out_l, out_h;
|
|
|
|
if (i2c_reg_read_byte_dt(&config->i2c, LSM9DS0_MFD_REG_OUT_X_L_M, &out_l) < 0 ||
|
|
i2c_reg_read_byte_dt(&config->i2c, LSM9DS0_MFD_REG_OUT_X_H_M, &out_h) < 0) {
|
|
LOG_DBG("failed to read magn sample (X axis)");
|
|
return -EIO;
|
|
}
|
|
|
|
data->sample_magn_x = (int16_t)((uint16_t)(out_l) |
|
|
((uint16_t)(out_h) << 8));
|
|
|
|
if (i2c_reg_read_byte_dt(&config->i2c, LSM9DS0_MFD_REG_OUT_Y_L_M, &out_l) < 0 ||
|
|
i2c_reg_read_byte_dt(&config->i2c, LSM9DS0_MFD_REG_OUT_Y_H_M, &out_h) < 0) {
|
|
LOG_DBG("failed to read magn sample (Y axis)");
|
|
return -EIO;
|
|
}
|
|
|
|
data->sample_magn_y = (int16_t)((uint16_t)(out_l) |
|
|
((uint16_t)(out_h) << 8));
|
|
|
|
if (i2c_reg_read_byte_dt(&config->i2c, LSM9DS0_MFD_REG_OUT_Z_L_M, &out_l) < 0 ||
|
|
i2c_reg_read_byte_dt(&config->i2c, LSM9DS0_MFD_REG_OUT_Z_H_M, &out_h) < 0) {
|
|
LOG_DBG("failed to read magn sample (Z axis)");
|
|
return -EIO;
|
|
}
|
|
|
|
data->sample_magn_z = (int16_t)((uint16_t)(out_l) |
|
|
((uint16_t)(out_h) << 8));
|
|
|
|
#if defined(CONFIG_LSM9DS0_MFD_MAGN_FULL_SCALE_RUNTIME)
|
|
data->sample_magn_fs = data->magn_fs;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(LSM9DS0_MFD_TEMP_DISABLED)
|
|
static inline int lsm9ds0_mfd_sample_fetch_temp(const struct device *dev)
|
|
{
|
|
struct lsm9ds0_mfd_data *data = dev->data;
|
|
const struct lsm9ds0_mfd_config *config = dev->config;
|
|
uint8_t out_l, out_h;
|
|
|
|
if (i2c_reg_read_byte_dt(&config->i2c, LSM9DS0_MFD_REG_OUT_TEMP_L_XM, &out_l) < 0 ||
|
|
i2c_reg_read_byte_dt(&config->i2c, LSM9DS0_MFD_REG_OUT_TEMP_H_XM, &out_h) < 0) {
|
|
LOG_DBG("failed to read temperature sample\n");
|
|
return -EIO;
|
|
}
|
|
|
|
data->sample_temp = (int16_t)((uint16_t)(out_l) |
|
|
((uint16_t)(out_h) << 8));
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static inline int lsm9ds0_mfd_sample_fetch_all(const struct device *dev)
|
|
{
|
|
#if !defined(LSM9DS0_MFD_ACCEL_DISABLED)
|
|
if (lsm9ds0_mfd_sample_fetch_accel(dev) < 0) {
|
|
return -EIO;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(LSM9DS0_MFD_MAGN_DISABLED)
|
|
if (lsm9ds0_mfd_sample_fetch_magn(dev) < 0) {
|
|
return -EIO;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(LSM9DS0_MFD_TEMP_DISABLED)
|
|
if (lsm9ds0_mfd_sample_fetch_temp(dev) < 0) {
|
|
return -EIO;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int lsm9ds0_mfd_sample_fetch(const struct device *dev,
|
|
enum sensor_channel chan)
|
|
{
|
|
switch (chan) {
|
|
#if !defined(LSM9DS0_MFD_ACCEL_DISABLED)
|
|
case SENSOR_CHAN_ACCEL_XYZ:
|
|
return lsm9ds0_mfd_sample_fetch_accel(dev);
|
|
#endif
|
|
#if !defined(LSM9DS0_MFD_MAGN_DISABLED)
|
|
case SENSOR_CHAN_MAGN_XYZ:
|
|
return lsm9ds0_mfd_sample_fetch_magn(dev);
|
|
#endif
|
|
#if !defined(LSM9DS0_MFD_TEMP_DISABLED)
|
|
case SENSOR_CHAN_DIE_TEMP:
|
|
return lsm9ds0_mfd_sample_fetch_temp(dev);
|
|
#endif
|
|
case SENSOR_CHAN_ALL:
|
|
return lsm9ds0_mfd_sample_fetch_all(dev);
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if !defined(LSM9DS0_MFD_ACCEL_DISABLED)
|
|
static inline void lsm9ds0_mfd_convert_accel(struct sensor_value *val,
|
|
int raw_val,
|
|
float scale)
|
|
{
|
|
double dval;
|
|
|
|
dval = (double)(raw_val) * (double)scale;
|
|
val->val1 = (int32_t)dval;
|
|
val->val2 = ((int32_t)(dval * 1000000)) % 1000000;
|
|
}
|
|
|
|
static inline int lsm9ds0_mfd_get_accel_channel(enum sensor_channel chan,
|
|
struct sensor_value *val,
|
|
struct lsm9ds0_mfd_data *data,
|
|
float scale)
|
|
{
|
|
switch (chan) {
|
|
case SENSOR_CHAN_ACCEL_X:
|
|
lsm9ds0_mfd_convert_accel(val, data->sample_accel_x, scale);
|
|
break;
|
|
case SENSOR_CHAN_ACCEL_Y:
|
|
lsm9ds0_mfd_convert_accel(val, data->sample_accel_y, scale);
|
|
break;
|
|
case SENSOR_CHAN_ACCEL_Z:
|
|
lsm9ds0_mfd_convert_accel(val, data->sample_accel_z, scale);
|
|
break;
|
|
case SENSOR_CHAN_ACCEL_XYZ:
|
|
lsm9ds0_mfd_convert_accel(val, data->sample_accel_x, scale);
|
|
lsm9ds0_mfd_convert_accel(val + 1, data->sample_accel_y, scale);
|
|
lsm9ds0_mfd_convert_accel(val + 2, data->sample_accel_z, scale);
|
|
break;
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline int lsm9ds0_mfd_get_accel(const struct device *dev,
|
|
enum sensor_channel chan,
|
|
struct sensor_value *val)
|
|
{
|
|
struct lsm9ds0_mfd_data *data = dev->data;
|
|
|
|
#if defined(CONFIG_LSM9DS0_MFD_ACCEL_FULL_SCALE_RUNTIME)
|
|
switch (data->sample_accel_fs) {
|
|
case 0:
|
|
return lsm9ds0_mfd_get_accel_channel(chan, val, data,
|
|
2.0 * 9.807 / 32767.0);
|
|
case 1:
|
|
return lsm9ds0_mfd_get_accel_channel(chan, val, data,
|
|
4.0 * 9.807 / 32767.0);
|
|
case 2:
|
|
return lsm9ds0_mfd_get_accel_channel(chan, val, data,
|
|
6.0 * 9.807 / 32767.0);
|
|
case 3:
|
|
return lsm9ds0_mfd_get_accel_channel(chan, val, data,
|
|
8.0 * 9.807 / 32767.0);
|
|
case 4:
|
|
return lsm9ds0_mfd_get_accel_channel(chan, val, data,
|
|
16.0 * 9.807 / 32767.0);
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
#elif defined(CONFIG_LSM9DS0_MFD_ACCEL_FULL_SCALE_2)
|
|
return lsm9ds0_mfd_get_accel_channel(chan, val, data,
|
|
2.0 * 9.807 / 32767.0);
|
|
#elif defined(CONFIG_LSM9DS0_MFD_ACCEL_FULL_SCALE_4)
|
|
return lsm9ds0_mfd_get_accel_channel(chan, val, data,
|
|
4.0 * 9.807 / 32767.0);
|
|
#elif defined(CONFIG_LSM9DS0_MFD_ACCEL_FULL_SCALE_6)
|
|
return lsm9ds0_mfd_get_accel_channel(chan, val, data,
|
|
6.0 * 9.807 / 32767.0);
|
|
#elif defined(CONFIG_LSM9DS0_MFD_ACCEL_FULL_SCALE_8)
|
|
return lsm9ds0_mfd_get_accel_channel(chan, val, data,
|
|
8.0 * 9.807 / 32767.0);
|
|
#elif defined(CONFIG_LSM9DS0_MFD_ACCEL_FULL_SCALE_16)
|
|
return lsm9ds0_mfd_get_accel_channel(chan, val, data,
|
|
16.0 * 9.807 / 32767.0);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(LSM9DS0_MFD_MAGN_DISABLED)
|
|
static inline void lsm9ds0_mfd_convert_magn(struct sensor_value *val,
|
|
int raw_val,
|
|
float scale)
|
|
{
|
|
double dval;
|
|
|
|
dval = (double)(raw_val) * (double)scale;
|
|
val->val1 = (int32_t)dval;
|
|
val->val2 = ((int32_t)(dval * 1000000)) % 1000000;
|
|
}
|
|
|
|
static inline int lsm9ds0_mfd_get_magn_channel(enum sensor_channel chan,
|
|
struct sensor_value *val,
|
|
struct lsm9ds0_mfd_data *data,
|
|
float scale)
|
|
{
|
|
switch (chan) {
|
|
case SENSOR_CHAN_MAGN_X:
|
|
lsm9ds0_mfd_convert_magn(val, data->sample_magn_x, scale);
|
|
break;
|
|
case SENSOR_CHAN_MAGN_Y:
|
|
lsm9ds0_mfd_convert_magn(val, data->sample_magn_y, scale);
|
|
break;
|
|
case SENSOR_CHAN_MAGN_Z:
|
|
lsm9ds0_mfd_convert_magn(val, data->sample_magn_z, scale);
|
|
break;
|
|
case SENSOR_CHAN_MAGN_XYZ:
|
|
lsm9ds0_mfd_convert_magn(val, data->sample_magn_x, scale);
|
|
lsm9ds0_mfd_convert_magn(val + 1, data->sample_magn_y, scale);
|
|
lsm9ds0_mfd_convert_magn(val + 2, data->sample_magn_z, scale);
|
|
break;
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline int lsm9ds0_mfd_get_magn(const struct device *dev,
|
|
enum sensor_channel chan,
|
|
struct sensor_value *val)
|
|
{
|
|
struct lsm9ds0_mfd_data *data = dev->data;
|
|
|
|
#if defined(CONFIG_LSM9DS0_MFD_MAGN_FULL_SCALE_RUNTIME)
|
|
switch (data->sample_magn_fs) {
|
|
case 0:
|
|
return lsm9ds0_mfd_get_magn_channel(chan, val, data,
|
|
2.0 / 32767.0);
|
|
case 1:
|
|
return lsm9ds0_mfd_get_magn_channel(chan, val, data,
|
|
4.0 / 32767.0);
|
|
case 2:
|
|
return lsm9ds0_mfd_get_magn_channel(chan, val, data,
|
|
8.0 / 32767.0);
|
|
case 3:
|
|
return lsm9ds0_mfd_get_magn_channel(chan, val, data,
|
|
12.0 / 32767.0);
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
#elif defined(CONFIG_LSM9DS0_MFD_MAGN_FULL_SCALE_2)
|
|
return lsm9ds0_mfd_get_magn_channel(chan, val, data, 2.0 / 32767.0);
|
|
#elif defined(CONFIG_LSM9DS0_MFD_MAGN_FULL_SCALE_4)
|
|
return lsm9ds0_mfd_get_magn_channel(chan, val, data, 4.0 / 32767.0);
|
|
#elif defined(CONFIG_LSM9DS0_MFD_MAGN_FULL_SCALE_8)
|
|
return lsm9ds0_mfd_get_magn_channel(chan, val, data, 8.0 / 32767.0);
|
|
#elif defined(CONFIG_LSM9DS0_MFD_MAGN_FULL_SCALE_12)
|
|
return lsm9ds0_mfd_get_magn_channel(chan, val, data, 12.0 / 32767.0);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int lsm9ds0_mfd_channel_get(const struct device *dev,
|
|
enum sensor_channel chan,
|
|
struct sensor_value *val)
|
|
{
|
|
#if !defined(LSM9DS0_MFD_TEMP_DISABLED)
|
|
struct lsm9ds0_mfd_data *data = dev->data;
|
|
#endif
|
|
|
|
switch (chan) {
|
|
#if !defined(LSM9DS0_MFD_ACCEL_DISABLED)
|
|
case SENSOR_CHAN_ACCEL_X:
|
|
case SENSOR_CHAN_ACCEL_Y:
|
|
case SENSOR_CHAN_ACCEL_Z:
|
|
case SENSOR_CHAN_ACCEL_XYZ:
|
|
return lsm9ds0_mfd_get_accel(dev, chan, val);
|
|
#endif
|
|
#if !defined(LSM9DS0_MFD_MAGN_DISABLED)
|
|
case SENSOR_CHAN_MAGN_X:
|
|
case SENSOR_CHAN_MAGN_Y:
|
|
case SENSOR_CHAN_MAGN_Z:
|
|
case SENSOR_CHAN_MAGN_XYZ:
|
|
return lsm9ds0_mfd_get_magn(dev, chan, val);
|
|
#endif
|
|
#if !defined(LSM9DS0_MFD_TEMP_DISABLED)
|
|
case SENSOR_CHAN_DIE_TEMP:
|
|
val->val1 = data->sample_temp;
|
|
val->val2 = 0;
|
|
return 0;
|
|
#endif
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
}
|
|
|
|
#if defined(LSM9DS0_MFD_ATTR_SET_ACCEL)
|
|
static inline int lsm9ds0_mfd_attr_set_accel(const struct device *dev,
|
|
enum sensor_attribute attr,
|
|
const struct sensor_value *val)
|
|
{
|
|
switch (attr) {
|
|
#if defined(CONFIG_LSM9DS0_MFD_ACCEL_SAMPLING_RATE_RUNTIME)
|
|
case SENSOR_ATTR_SAMPLING_FREQUENCY:
|
|
return lsm9ds0_mfd_accel_set_odr(dev, val);
|
|
#endif
|
|
#if defined(CONFIG_LSM9DS0_MFD_ACCEL_FULL_SCALE_RUNTIME)
|
|
case SENSOR_ATTR_FULL_SCALE:
|
|
return lsm9ds0_mfd_accel_set_fs(dev, sensor_ms2_to_g(val));
|
|
#endif
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(LSM9DS0_MFD_ATTR_SET_MAGN)
|
|
static inline int lsm9ds0_mfd_attr_set_magn(const struct device *dev,
|
|
enum sensor_attribute attr,
|
|
const struct sensor_value *val)
|
|
{
|
|
switch (attr) {
|
|
#if defined(CONFIG_LSM9DS0_MFD_MAGN_SAMPLING_RATE_RUNTIME)
|
|
case SENSOR_ATTR_SAMPLING_FREQUENCY:
|
|
return lsm9ds0_mfd_magn_set_odr(dev, val);
|
|
#endif
|
|
#if defined(CONFIG_LSM9DS0_MFD_MAGN_FULL_SCALE_RUNTIME)
|
|
case SENSOR_ATTR_FULL_SCALE:
|
|
return lsm9ds0_mfd_magn_set_fs(dev, val);
|
|
#endif
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(LSM9DS0_MFD_ATTR_SET)
|
|
static int lsm9ds0_mfd_attr_set(const struct device *dev,
|
|
enum sensor_channel chan,
|
|
enum sensor_attribute attr,
|
|
const struct sensor_value *val)
|
|
{
|
|
|
|
switch (chan) {
|
|
#if defined(LSM9DS0_MFD_ATTR_SET_ACCEL)
|
|
case SENSOR_CHAN_ACCEL_X:
|
|
case SENSOR_CHAN_ACCEL_Y:
|
|
case SENSOR_CHAN_ACCEL_Z:
|
|
case SENSOR_CHAN_ACCEL_XYZ:
|
|
return lsm9ds0_mfd_attr_set_accel(dev, attr, val);
|
|
#endif
|
|
#if defined(LSM9DS0_MFD_ATTR_SET_MAGN)
|
|
case SENSOR_CHAN_MAGN_X:
|
|
case SENSOR_CHAN_MAGN_Y:
|
|
case SENSOR_CHAN_MAGN_Z:
|
|
case SENSOR_CHAN_MAGN_XYZ:
|
|
return lsm9ds0_mfd_attr_set_magn(dev, attr, val);
|
|
#endif
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static const struct sensor_driver_api lsm9ds0_mfd_api_funcs = {
|
|
.sample_fetch = lsm9ds0_mfd_sample_fetch,
|
|
.channel_get = lsm9ds0_mfd_channel_get,
|
|
#if defined(LSM9DS0_MFD_ATTR_SET)
|
|
.attr_set = lsm9ds0_mfd_attr_set,
|
|
#endif
|
|
};
|
|
|
|
static int lsm9ds0_mfd_init_chip(const struct device *dev)
|
|
{
|
|
const struct lsm9ds0_mfd_config *config = dev->config;
|
|
uint8_t chip_id;
|
|
|
|
if (lsm9ds0_mfd_reboot_memory(dev) < 0) {
|
|
LOG_DBG("failed to reset device");
|
|
return -EIO;
|
|
}
|
|
|
|
if (i2c_reg_read_byte_dt(&config->i2c, LSM9DS0_MFD_REG_WHO_AM_I_XM, &chip_id) < 0) {
|
|
LOG_DBG("failed reading chip id");
|
|
return -EIO;
|
|
}
|
|
|
|
if (chip_id != LSM9DS0_MFD_VAL_WHO_AM_I_XM) {
|
|
LOG_DBG("invalid chip id 0x%x", chip_id);
|
|
return -EIO;
|
|
}
|
|
|
|
LOG_DBG("chip id 0x%x", chip_id);
|
|
|
|
#if !defined(LSM9DS0_MFD_ACCEL_DISABLED)
|
|
if (i2c_reg_update_byte_dt(&config->i2c, LSM9DS0_MFD_REG_CTRL_REG1_XM,
|
|
LSM9DS0_MFD_MASK_CTRL_REG1_XM_BDU |
|
|
LSM9DS0_MFD_MASK_CTRL_REG1_XM_AODR,
|
|
(1 << LSM9DS0_MFD_SHIFT_CTRL_REG1_XM_BDU) |
|
|
(LSM9DS0_MFD_ACCEL_DEFAULT_AODR <<
|
|
LSM9DS0_MFD_SHIFT_CTRL_REG1_XM_AODR))) {
|
|
LOG_DBG("failed to set AODR and BDU");
|
|
return -EIO;
|
|
}
|
|
|
|
if (lsm9ds0_mfd_accel_set_fs_raw(dev, LSM9DS0_MFD_ACCEL_DEFAULT_FS)) {
|
|
LOG_DBG("failed to set accelerometer full-scale");
|
|
return -EIO;
|
|
}
|
|
|
|
if (i2c_reg_update_byte_dt(&config->i2c, LSM9DS0_MFD_REG_CTRL_REG1_XM,
|
|
LSM9DS0_MFD_MASK_CTRL_REG1_XM_AXEN |
|
|
LSM9DS0_MFD_MASK_CTRL_REG1_XM_AYEN |
|
|
LSM9DS0_MFD_MASK_CTRL_REG1_XM_AZEN,
|
|
(LSM9DS0_MFD_ACCEL_ENABLE_X <<
|
|
LSM9DS0_MFD_SHIFT_CTRL_REG1_XM_AXEN) |
|
|
(LSM9DS0_MFD_ACCEL_ENABLE_Y <<
|
|
LSM9DS0_MFD_SHIFT_CTRL_REG1_XM_AYEN) |
|
|
(LSM9DS0_MFD_ACCEL_ENABLE_Z <<
|
|
LSM9DS0_MFD_SHIFT_CTRL_REG1_XM_AZEN)) < 0) {
|
|
LOG_DBG("failed to set accelerometer axis enable bits\n");
|
|
return -EIO;
|
|
}
|
|
|
|
#elif !defined(LSM9DS0_MFD_MAGN_DISABLED)
|
|
if (i2c_reg_update_byte_dt(&config->i2c, LSM9DS0_MFD_REG_CTRL_REG1_XM,
|
|
LSM9DS0_MFD_MASK_CTRL_REG1_XM_BDU,
|
|
1 << LSM9DS0_MFD_SHIFT_CTRL_REG1_XM_BDU) < 0) {
|
|
LOG_DBG("failed to set BDU\n");
|
|
return -EIO;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(LSM9DS0_MFD_MAGN_DISABLED)
|
|
if (i2c_reg_update_byte_dt(&config->i2c, LSM9DS0_MFD_REG_CTRL_REG7_XM,
|
|
LSM9DS0_MFD_MASK_CTRL_REG7_XM_MD,
|
|
(0 << LSM9DS0_MFD_SHIFT_CTRL_REG7_XM_MD)) < 0) {
|
|
LOG_DBG("failed to power on magnetometer");
|
|
return -EIO;
|
|
}
|
|
|
|
if (lsm9ds0_mfd_magn_set_odr_raw(dev, LSM9DS0_MFD_MAGN_DEFAULT_M_ODR)) {
|
|
LOG_DBG("failed to set magnetometer sampling rate");
|
|
return -EIO;
|
|
}
|
|
|
|
if (lsm9ds0_mfd_magn_set_fs_raw(dev, LSM9DS0_MFD_MAGN_DEFAULT_FS)) {
|
|
LOG_DBG("failed to set magnetometer full-scale");
|
|
return -EIO;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(LSM9DS0_MFD_TEMP_DISABLED)
|
|
if (i2c_reg_update_byte_dt(&config->i2c, LSM9DS0_MFD_REG_CTRL_REG5_XM,
|
|
LSM9DS0_MFD_MASK_CTRL_REG5_XM_TEMP_EN,
|
|
1 << LSM9DS0_MFD_SHIFT_CTRL_REG5_XM_TEMP_EN) < 0) {
|
|
LOG_DBG("failed to power on temperature sensor");
|
|
return -EIO;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
int lsm9ds0_mfd_init(const struct device *dev)
|
|
{
|
|
const struct lsm9ds0_mfd_config * const config = dev->config;
|
|
|
|
if (!device_is_ready(config->i2c.bus)) {
|
|
LOG_ERR("Bus device is not ready");
|
|
return -ENODEV;
|
|
}
|
|
|
|
if (lsm9ds0_mfd_init_chip(dev) < 0) {
|
|
LOG_DBG("failed to initialize chip");
|
|
return -EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define LSM9DS0_MFD_DEFINE(inst) \
|
|
static struct lsm9ds0_mfd_data lsm9ds0_mfd_data_##inst; \
|
|
\
|
|
static const struct lsm9ds0_mfd_config lsm9ds0_mfd_config_##inst = { \
|
|
.i2c = I2C_DT_SPEC_INST_GET(inst), \
|
|
}; \
|
|
\
|
|
SENSOR_DEVICE_DT_INST_DEFINE(inst, lsm9ds0_mfd_init, NULL, \
|
|
&lsm9ds0_mfd_data_##inst, &lsm9ds0_mfd_config_##inst, POST_KERNEL,\
|
|
CONFIG_SENSOR_INIT_PRIORITY, &lsm9ds0_mfd_api_funcs); \
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(LSM9DS0_MFD_DEFINE)
|