driver/sensor: lsm6dso: Add support

Add support to STM LSM6DSO 6-axis IMU sensor driver.
This driver supports communication with device though both
I2C and SPI bus and both polling and drdy trigger mode.

This driver supports also the sensorhub mode with the possibility
to connect a maximum of two external devices, typically a
magnetometer and an environmental sensor, currently selected among
following devices: lis2mdl magnetometer, lps22hh or lps22hb
pressure and temperature sensors, HTS221 humidity sensor.

Signed-off-by: Armando Visconti <armando.visconti@st.com>
This commit is contained in:
Armando Visconti 2019-02-18 15:17:54 +01:00 committed by Maureen Helm
commit 72ae24d8d5
15 changed files with 2558 additions and 0 deletions

View file

@ -0,0 +1,789 @@
/* ST Microelectronics LSM6DSO 6-axis IMU sensor driver
*
* Copyright (c) 2019 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/lsm6dso.pdf
*/
#include <device.h>
#include <drivers/i2c.h>
#include <sys/byteorder.h>
#include <sys/__assert.h>
#include <sys/util.h>
#include <kernel.h>
#include <sensor.h>
#include <logging/log.h>
#include "lsm6dso.h"
#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
LOG_MODULE_DECLARE(LSM6DSO);
#define LSM6DSO_SHUB_DATA_OUT 0x02
#define LSM6DSO_SHUB_SLV0_ADDR 0x15
#define LSM6DSO_SHUB_SLV0_SUBADDR 0x16
#define LSM6DSO_SHUB_SLV0_CONFIG 0x17
#define LSM6DSO_SHUB_SLV1_ADDR 0x18
#define LSM6DSO_SHUB_SLV1_SUBADDR 0x19
#define LSM6DSO_SHUB_SLV1_CONFIG 0x1A
#define LSM6DSO_SHUB_SLV2_ADDR 0x1B
#define LSM6DSO_SHUB_SLV2_SUBADDR 0x1C
#define LSM6DSO_SHUB_SLV2_CONFIG 0x1D
#define LSM6DSO_SHUB_SLV3_ADDR 0x1E
#define LSM6DSO_SHUB_SLV3_SUBADDR 0x1F
#define LSM6DSO_SHUB_SLV3_CONFIG 0x20
#define LSM6DSO_SHUB_SLV0_DATAWRITE 0x21
#define LSM6DSO_SHUB_STATUS_MASTER 0x22
#define LSM6DSO_SHUB_STATUS_SLV0_NACK BIT(3)
#define LSM6DSO_SHUB_STATUS_ENDOP BIT(0)
#define LSM6DSO_SHUB_SLVX_WRITE 0x0
#define LSM6DSO_SHUB_SLVX_READ 0x1
static u8_t num_ext_dev;
static u8_t shub_ext[LSM6DSO_SHUB_MAX_NUM_SLVS];
static int lsm6dso_shub_write_slave_reg(struct lsm6dso_data *data,
u8_t slv_addr, u8_t slv_reg,
u8_t *value, u16_t len);
static int lsm6dso_shub_read_slave_reg(struct lsm6dso_data *data,
u8_t slv_addr, u8_t slv_reg,
u8_t *value, u16_t len);
static void lsm6dso_shub_enable(struct lsm6dso_data *data, u8_t enable);
/*
* LIS2MDL magn device specific part
*/
#ifdef CONFIG_LSM6DSO_EXT_LIS2MDL
#define LIS2MDL_CFG_REG_A 0x60
#define LIS2MDL_CFG_REG_B 0x61
#define LIS2MDL_CFG_REG_C 0x62
#define LIS2MDL_STATUS_REG 0x67
#define LIS2MDL_SW_RESET 0x20
#define LIS2MDL_ODR_10HZ 0x00
#define LIS2MDL_ODR_100HZ 0x0C
#define LIS2MDL_OFF_CANC 0x02
#define LIS2MDL_SENSITIVITY 1500
static int lsm6dso_lis2mdl_init(struct lsm6dso_data *data, u8_t i2c_addr)
{
u8_t mag_cfg[2];
data->magn_gain = LIS2MDL_SENSITIVITY;
/* sw reset device */
mag_cfg[0] = LIS2MDL_SW_RESET;
lsm6dso_shub_write_slave_reg(data, i2c_addr,
LIS2MDL_CFG_REG_A, mag_cfg, 1);
k_sleep(10); /* turn-on time in ms */
/* configure mag */
mag_cfg[0] = LIS2MDL_ODR_10HZ;
mag_cfg[1] = LIS2MDL_OFF_CANC;
lsm6dso_shub_write_slave_reg(data, i2c_addr,
LIS2MDL_CFG_REG_A, mag_cfg, 2);
return 0;
}
static const u16_t lis2mdl_map[] = {10, 20, 50, 100};
static int lsm6dso_lis2mdl_odr_set(struct lsm6dso_data *data,
u8_t i2c_addr, u16_t freq)
{
u8_t odr, cfg;
for (odr = 0; odr < ARRAY_SIZE(lis2mdl_map); odr++) {
if (freq == lis2mdl_map[odr]) {
break;
}
}
if (odr == ARRAY_SIZE(lis2mdl_map)) {
LOG_DBG("shub: LIS2MDL freq val %d not supported.", freq);
return -ENOTSUP;
}
cfg = (odr << 2);
lsm6dso_shub_write_slave_reg(data, i2c_addr,
LIS2MDL_CFG_REG_A, &cfg, 1);
lsm6dso_shub_enable(data, 1);
return 0;
}
static int lsm6dso_lis2mdl_conf(struct lsm6dso_data *data, u8_t i2c_addr,
enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
switch (attr) {
case SENSOR_ATTR_SAMPLING_FREQUENCY:
return lsm6dso_lis2mdl_odr_set(data, i2c_addr, val->val1);
default:
LOG_DBG("shub: LIS2MDL attribute not supported.");
return -ENOTSUP;
}
return 0;
}
#endif /* CONFIG_LSM6DSO_EXT_LIS2MDL */
/*
* HTS221 humidity device specific part
*/
#ifdef CONFIG_LSM6DSO_EXT_HTS221
#define HTS221_AUTOINCREMENT BIT(7)
#define HTS221_REG_CTRL1 0x20
#define HTS221_ODR_1HZ 0x01
#define HTS221_BDU 0x04
#define HTS221_PD 0x80
#define HTS221_REG_CONV_START 0x30
static int lsmdso_hts221_read_conv_data(struct lsm6dso_data *data,
u8_t i2c_addr)
{
u8_t buf[16], i;
struct hts221_data *ht = &data->hts221;
for (i = 0; i < sizeof(buf); i += 7) {
unsigned char len = MIN(7, sizeof(buf) - i);
if (lsm6dso_shub_read_slave_reg(data, i2c_addr,
(HTS221_REG_CONV_START + i) |
HTS221_AUTOINCREMENT,
&buf[i], len) < 0) {
LOG_DBG("shub: failed to read hts221 conv data");
return -EIO;
}
}
ht->y0 = buf[0] / 2;
ht->y1 = buf[1] / 2;
ht->x0 = sys_le16_to_cpu(buf[6] | (buf[7] << 8));
ht->x1 = sys_le16_to_cpu(buf[10] | (buf[11] << 8));
return 0;
}
static int lsm6dso_hts221_init(struct lsm6dso_data *data, u8_t i2c_addr)
{
u8_t hum_cfg;
/* configure ODR and BDU */
hum_cfg = HTS221_ODR_1HZ | HTS221_BDU | HTS221_PD;
lsm6dso_shub_write_slave_reg(data, i2c_addr,
HTS221_REG_CTRL1, &hum_cfg, 1);
return lsmdso_hts221_read_conv_data(data, i2c_addr);
}
static const u16_t hts221_map[] = {0, 1, 7, 12};
static int lsm6dso_hts221_odr_set(struct lsm6dso_data *data,
u8_t i2c_addr, u16_t freq)
{
u8_t odr, cfg;
for (odr = 0; odr < ARRAY_SIZE(hts221_map); odr++) {
if (freq == hts221_map[odr]) {
break;
}
}
if (odr == ARRAY_SIZE(hts221_map)) {
LOG_DBG("shub: HTS221 freq val %d not supported.", freq);
return -ENOTSUP;
}
cfg = odr | HTS221_BDU | HTS221_PD;
lsm6dso_shub_write_slave_reg(data, i2c_addr,
HTS221_REG_CTRL1, &cfg, 1);
lsm6dso_shub_enable(data, 1);
return 0;
}
static int lsm6dso_hts221_conf(struct lsm6dso_data *data, u8_t i2c_addr,
enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
switch (attr) {
case SENSOR_ATTR_SAMPLING_FREQUENCY:
return lsm6dso_hts221_odr_set(data, i2c_addr, val->val1);
default:
LOG_DBG("shub: HTS221 attribute not supported.");
return -ENOTSUP;
}
return 0;
}
#endif /* CONFIG_LSM6DSO_EXT_HTS221 */
/*
* LPS22HB baro/temp device specific part
*/
#ifdef CONFIG_LSM6DSO_EXT_LPS22HB
#define LPS22HB_CTRL_REG1 0x10
#define LPS22HB_CTRL_REG2 0x11
#define LPS22HB_SW_RESET 0x04
#define LPS22HB_ODR_10HZ 0x20
#define LPS22HB_LPF_EN 0x08
#define LPS22HB_BDU_EN 0x02
static int lsm6dso_lps22hb_init(struct lsm6dso_data *data, u8_t i2c_addr)
{
u8_t baro_cfg[2];
/* sw reset device */
baro_cfg[0] = LPS22HB_SW_RESET;
lsm6dso_shub_write_slave_reg(data, i2c_addr,
LPS22HB_CTRL_REG2, baro_cfg, 1);
k_sleep(1); /* turn-on time in ms */
/* configure device */
baro_cfg[0] = LPS22HB_ODR_10HZ | LPS22HB_LPF_EN | LPS22HB_BDU_EN;
lsm6dso_shub_write_slave_reg(data, i2c_addr,
LPS22HB_CTRL_REG1, baro_cfg, 1);
return 0;
}
#endif /* CONFIG_LSM6DSO_EXT_LPS22HB */
/*
* LPS22HH baro/temp device specific part
*/
#ifdef CONFIG_LSM6DSO_EXT_LPS22HH
#define LPS22HH_CTRL_REG1 0x10
#define LPS22HH_CTRL_REG2 0x11
#define LPS22HH_SW_RESET 0x04
#define LPS22HH_IF_ADD_INC 0x10
#define LPS22HH_ODR_10HZ 0x20
#define LPS22HH_LPF_EN 0x08
#define LPS22HH_BDU_EN 0x02
static int lsm6dso_lps22hh_init(struct lsm6dso_data *data, u8_t i2c_addr)
{
u8_t baro_cfg[2];
/* sw reset device */
baro_cfg[0] = LPS22HH_SW_RESET;
lsm6dso_shub_write_slave_reg(data, i2c_addr,
LPS22HH_CTRL_REG2, baro_cfg, 1);
k_sleep(100); /* turn-on time in ms */
/* configure device */
baro_cfg[0] = LPS22HH_IF_ADD_INC;
lsm6dso_shub_write_slave_reg(data, i2c_addr,
LPS22HH_CTRL_REG2, baro_cfg, 1);
baro_cfg[0] = LPS22HH_ODR_10HZ | LPS22HH_LPF_EN | LPS22HH_BDU_EN;
lsm6dso_shub_write_slave_reg(data, i2c_addr,
LPS22HH_CTRL_REG1, baro_cfg, 1);
return 0;
}
static const u16_t lps22hh_map[] = {0, 1, 10, 25, 50, 75, 100, 200};
static int lsm6dso_lps22hh_odr_set(struct lsm6dso_data *data,
u8_t i2c_addr, u16_t freq)
{
u8_t odr, cfg;
for (odr = 0; odr < ARRAY_SIZE(lps22hh_map); odr++) {
if (freq == lps22hh_map[odr]) {
break;
}
}
if (odr == ARRAY_SIZE(lps22hh_map)) {
LOG_DBG("shub: LPS22HH freq val %d not supported.", freq);
return -ENOTSUP;
}
cfg = (odr << 4) | LPS22HH_LPF_EN | LPS22HH_BDU_EN;
lsm6dso_shub_write_slave_reg(data, i2c_addr,
LPS22HH_CTRL_REG1, &cfg, 1);
lsm6dso_shub_enable(data, 1);
return 0;
}
static int lsm6dso_lps22hh_conf(struct lsm6dso_data *data, u8_t i2c_addr,
enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
switch (attr) {
case SENSOR_ATTR_SAMPLING_FREQUENCY:
return lsm6dso_lps22hh_odr_set(data, i2c_addr, val->val1);
default:
LOG_DBG("shub: LPS22HH attribute not supported.");
return -ENOTSUP;
}
return 0;
}
#endif /* CONFIG_LSM6DSO_EXT_LPS22HH */
/* List of supported external sensors */
static struct lsm6dso_shub_slist {
enum sensor_channel type;
u8_t i2c_addr[2];
u8_t ext_i2c_addr;
u8_t wai_addr;
u8_t wai_val;
u8_t out_data_addr;
u8_t out_data_len;
u8_t sh_out_reg;
int (*dev_init)(struct lsm6dso_data *data, u8_t i2c_addr);
int (*dev_conf)(struct lsm6dso_data *data, u8_t i2c_addr,
enum sensor_channel chan, enum sensor_attribute attr,
const struct sensor_value *val);
} lsm6dso_shub_slist[] = {
#ifdef CONFIG_LSM6DSO_EXT_LIS2MDL
{
/* LIS2MDL */
.type = SENSOR_CHAN_MAGN_XYZ,
.i2c_addr = { 0x1E },
.wai_addr = 0x4F,
.wai_val = 0x40,
.out_data_addr = 0x68,
.out_data_len = 0x06,
.dev_init = (lsm6dso_lis2mdl_init),
.dev_conf = (lsm6dso_lis2mdl_conf),
},
#endif /* CONFIG_LSM6DSO_EXT_LIS2MDL */
#ifdef CONFIG_LSM6DSO_EXT_HTS221
{
/* HTS221 */
.type = SENSOR_CHAN_HUMIDITY,
.i2c_addr = { 0x5F },
.wai_addr = 0x0F,
.wai_val = 0xBC,
.out_data_addr = 0x28 | HTS221_AUTOINCREMENT,
.out_data_len = 0x02,
.dev_init = (lsm6dso_hts221_init),
.dev_conf = (lsm6dso_hts221_conf),
},
#endif /* CONFIG_LSM6DSO_EXT_HTS221 */
#ifdef CONFIG_LSM6DSO_EXT_LPS22HB
{
/* LPS22HB */
.type = SENSOR_CHAN_PRESS,
.i2c_addr = { 0x5C, 0x5D },
.wai_addr = 0x0F,
.wai_val = 0xB1,
.out_data_addr = 0x28,
.out_data_len = 0x05,
.dev_init = (lsm6dso_lps22hb_init),
},
#endif /* CONFIG_LSM6DSO_EXT_LPS22HB */
#ifdef CONFIG_LSM6DSO_EXT_LPS22HH
{
/* LPS22HH */
.type = SENSOR_CHAN_PRESS,
.i2c_addr = { 0x5C, 0x5D },
.wai_addr = 0x0F,
.wai_val = 0xB3,
.out_data_addr = 0x28,
.out_data_len = 0x05,
.dev_init = (lsm6dso_lps22hh_init),
.dev_conf = (lsm6dso_lps22hh_conf),
},
#endif /* CONFIG_LSM6DSO_EXT_LPS22HH */
};
static inline void lsm6dso_shub_wait_completed(struct lsm6dso_data *data)
{
u16_t freq;
freq = (data->accel_freq == 0) ? 26 : data->accel_freq;
k_sleep((2000U / freq) + 1);
}
static inline void lsm6dso_shub_embedded_en(struct lsm6dso_data *data, bool on)
{
if (on) {
lsm6dso_mem_bank_set(data->ctx, LSM6DSO_SENSOR_HUB_BANK);
} else {
lsm6dso_mem_bank_set(data->ctx, LSM6DSO_USER_BANK);
}
k_busy_wait(150);
}
static int lsm6dso_shub_read_embedded_regs(struct lsm6dso_data *data,
u8_t reg_addr,
u8_t *value, int len)
{
lsm6dso_shub_embedded_en(data, true);
if (lsm6dso_read_reg(data->ctx, reg_addr, value, len) < 0) {
LOG_DBG("shub: failed to read external reg: %02x", reg_addr);
lsm6dso_shub_embedded_en(data, false);
return -EIO;
}
lsm6dso_shub_embedded_en(data, false);
return 0;
}
static int lsm6dso_shub_write_embedded_regs(struct lsm6dso_data *data,
u8_t reg_addr,
u8_t *value, u8_t len)
{
lsm6dso_shub_embedded_en(data, true);
if (lsm6dso_write_reg(data->ctx, reg_addr, value, len) < 0) {
LOG_DBG("shub: failed to write external reg: %02x", reg_addr);
lsm6dso_shub_embedded_en(data, false);
return -EIO;
}
lsm6dso_shub_embedded_en(data, false);
return 0;
}
static void lsm6dso_shub_enable(struct lsm6dso_data *data, u8_t enable)
{
/* Enable Accel @26hz */
if (!data->accel_freq) {
u8_t odr = (enable) ? 2 : 0;
if (lsm6dso_xl_data_rate_set(data->ctx, odr) < 0) {
LOG_DBG("shub: failed to set XL sampling rate");
return;
}
}
lsm6dso_shub_embedded_en(data, true);
if (lsm6dso_sh_master_set(data->ctx, enable) < 0) {
LOG_DBG("shub: failed to set master on");
lsm6dso_shub_embedded_en(data, false);
return;
}
lsm6dso_shub_embedded_en(data, false);
}
/* must be called with master on */
static int lsm6dso_shub_check_slv0_nack(struct lsm6dso_data *data)
{
u8_t status;
if (lsm6dso_shub_read_embedded_regs(data, LSM6DSO_SHUB_STATUS_MASTER,
&status, 1) < 0) {
LOG_DBG("shub: error reading embedded reg");
return -EIO;
}
if (status & (LSM6DSO_SHUB_STATUS_SLV0_NACK)) {
LOG_DBG("shub: SLV0 nacked");
return -EIO;
}
return 0;
}
/*
* use SLV0 for generic read to slave device
*/
static int lsm6dso_shub_read_slave_reg(struct lsm6dso_data *data,
u8_t slv_addr, u8_t slv_reg,
u8_t *value, u16_t len)
{
u8_t slave[3];
slave[0] = (slv_addr << 1) | LSM6DSO_SHUB_SLVX_READ;
slave[1] = slv_reg;
slave[2] = (len & 0x7);
if (lsm6dso_shub_write_embedded_regs(data, LSM6DSO_SHUB_SLV0_ADDR,
slave, 3) < 0) {
LOG_DBG("shub: error writing embedded reg");
return -EIO;
}
/* turn SH on */
lsm6dso_shub_enable(data, 1);
lsm6dso_shub_wait_completed(data);
/* read data from external slave */
lsm6dso_shub_embedded_en(data, true);
if (lsm6dso_read_reg(data->ctx, LSM6DSO_SHUB_DATA_OUT,
value, len) < 0) {
LOG_DBG("shub: error reading sensor data");
return -EIO;
}
lsm6dso_shub_embedded_en(data, false);
if (lsm6dso_shub_check_slv0_nack(data) < 0) {
lsm6dso_shub_enable(data, 0);
return -EIO;
}
lsm6dso_shub_enable(data, 0);
return 0;
}
/*
* use SLV0 to configure slave device
*/
static int lsm6dso_shub_write_slave_reg(struct lsm6dso_data *data,
u8_t slv_addr, u8_t slv_reg,
u8_t *value, u16_t len)
{
u8_t slv_cfg[3];
u8_t cnt = 0U;
while (cnt < len) {
slv_cfg[0] = (slv_addr << 1) & ~LSM6DSO_SHUB_SLVX_READ;
slv_cfg[1] = slv_reg + cnt;
if (lsm6dso_shub_write_embedded_regs(data,
LSM6DSO_SHUB_SLV0_ADDR,
slv_cfg, 2) < 0) {
LOG_DBG("shub: error writing embedded reg");
return -EIO;
}
slv_cfg[0] = value[cnt];
if (lsm6dso_shub_write_embedded_regs(data,
LSM6DSO_SHUB_SLV0_DATAWRITE,
slv_cfg, 1) < 0) {
LOG_DBG("shub: error writing embedded reg");
return -EIO;
}
/* turn SH on */
lsm6dso_shub_enable(data, 1);
lsm6dso_shub_wait_completed(data);
if (lsm6dso_shub_check_slv0_nack(data) < 0) {
lsm6dso_shub_enable(data, 0);
return -EIO;
}
lsm6dso_shub_enable(data, 0);
cnt++;
}
/* Put SLV0 in IDLE mode */
slv_cfg[0] = 0x7;
slv_cfg[1] = 0x0;
slv_cfg[2] = 0x0;
if (lsm6dso_shub_write_embedded_regs(data, LSM6DSO_SHUB_SLV0_ADDR,
slv_cfg, 3) < 0) {
LOG_DBG("shub: error writing embedded reg");
return -EIO;
}
return 0;
}
/*
* SLAVEs configurations:
*
* - SLAVE 0: used for configuring all slave devices
* - SLAVE 1: used as data read channel for external slave device #1
* - SLAVE 2: used as data read channel for external slave device #2
* - SLAVE 3: used for generic reads while data channel is enabled
*/
static int lsm6dso_shub_set_data_channel(struct lsm6dso_data *data)
{
u8_t n, i, slv_cfg[6];
struct lsm6dso_shub_slist *sp;
/* Set data channel for slave devices */
for (n = 0; n < num_ext_dev; n++) {
sp = &lsm6dso_shub_slist[shub_ext[n]];
i = n * 3;
slv_cfg[i] = (sp->ext_i2c_addr << 1) | LSM6DSO_SHUB_SLVX_READ;
slv_cfg[i + 1] = sp->out_data_addr;
slv_cfg[i + 2] = sp->out_data_len;
}
if (lsm6dso_shub_write_embedded_regs(data,
LSM6DSO_SHUB_SLV1_ADDR,
slv_cfg, n*3) < 0) {
LOG_DBG("shub: error writing embedded reg");
return -EIO;
}
/* Configure the master */
lsm6dso_aux_sens_on_t aux = LSM6DSO_SLV_0_1_2;
if (lsm6dso_sh_slave_connected_set(data->ctx, aux) < 0) {
LOG_DBG("shub: error setting aux sensors");
return -EIO;
}
lsm6dso_write_once_t wo = LSM6DSO_ONLY_FIRST_CYCLE;
if (lsm6dso_sh_write_mode_set(data->ctx, wo) < 0) {
LOG_DBG("shub: error setting write once");
return -EIO;
}
/* turn SH on */
lsm6dso_shub_enable(data, 1);
lsm6dso_shub_wait_completed(data);
return 0;
}
int lsm6dso_shub_get_idx(enum sensor_channel type)
{
u8_t n;
struct lsm6dso_shub_slist *sp;
for (n = 0; n < num_ext_dev; n++) {
sp = &lsm6dso_shub_slist[shub_ext[n]];
if (sp->type == type)
return n;
}
return -ENOTSUP;
}
int lsm6dso_shub_fetch_external_devs(struct device *dev)
{
u8_t n;
struct lsm6dso_data *data = dev->driver_data;
struct lsm6dso_shub_slist *sp;
/* read data from external slave */
lsm6dso_shub_embedded_en(data, true);
for (n = 0; n < num_ext_dev; n++) {
sp = &lsm6dso_shub_slist[shub_ext[n]];
if (lsm6dso_read_reg(data->ctx, sp->sh_out_reg,
data->ext_data[n], sp->out_data_len) < 0) {
LOG_DBG("shub: failed to read sample");
return -EIO;
}
}
lsm6dso_shub_embedded_en(data, false);
return 0;
}
int lsm6dso_shub_config(struct device *dev, enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
struct lsm6dso_data *data = dev->driver_data;
struct lsm6dso_shub_slist *sp = NULL;
u8_t n;
for (n = 0; n < num_ext_dev; n++) {
sp = &lsm6dso_shub_slist[shub_ext[n]];
if (sp->type == chan)
break;
}
if (n == num_ext_dev) {
LOG_DBG("shub: chan not supported");
return -ENOTSUP;
}
if (sp == NULL || sp->dev_conf == NULL) {
LOG_DBG("shub: chan not configurable");
return -ENOTSUP;
}
return sp->dev_conf(data, sp->ext_i2c_addr, chan, attr, val);
}
int lsm6dso_shub_init(struct device *dev)
{
struct lsm6dso_data *data = dev->driver_data;
u8_t i, n = 0, regn;
u8_t chip_id;
struct lsm6dso_shub_slist *sp;
for (n = 0; n < ARRAY_SIZE(lsm6dso_shub_slist); n++) {
if (num_ext_dev >= LSM6DSO_SHUB_MAX_NUM_SLVS)
break;
chip_id = 0;
sp = &lsm6dso_shub_slist[n];
/*
* The external sensor may have different I2C address.
* So, try them one by one until we read the correct
* chip ID.
*/
for (i = 0U; i < ARRAY_SIZE(sp->i2c_addr); i++) {
if (lsm6dso_shub_read_slave_reg(data,
sp->i2c_addr[i],
sp->wai_addr,
&chip_id, 1) < 0) {
LOG_DBG("shub: failed reading chip id");
continue;
}
if (chip_id == sp->wai_val) {
break;
}
}
if (i >= ARRAY_SIZE(sp->i2c_addr)) {
LOG_DBG("shub: invalid chip id 0x%x", chip_id);
continue;
}
LOG_INF("shub: Ext Device Chip Id: %02x", chip_id);
sp->ext_i2c_addr = sp->i2c_addr[i];
shub_ext[num_ext_dev++] = n;
}
if (num_ext_dev == 0) {
LOG_ERR("shub: no slave devices found");
return -EINVAL;
}
/* init external devices */
for (n = 0, regn = 0; n < num_ext_dev; n++) {
sp = &lsm6dso_shub_slist[shub_ext[n]];
sp->sh_out_reg = LSM6DSO_SHUB_DATA_OUT + regn;
regn += sp->out_data_len;
sp->dev_init(data, sp->ext_i2c_addr);
}
lsm6dso_shub_set_data_channel(data);
return 0;
}