Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers: sensor: lsm6dsv16x: add i3c support #79346

Merged
merged 3 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion drivers/sensor/st/lps2xdf/lps2xdf_trigger.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ int lps2xdf_init_interrupt(const struct device *dev, enum sensor_variant variant

#if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) ||\
DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c))
if (cfg->i3c.bus == NULL) {
if (cfg->i3c.bus != NULL) {
/* I3C IBI does not utilize GPIO interrupt. */
lps2xdf->i3c_dev->ibi_cb = lps2xdf_ibi_cb;

Expand Down
15 changes: 9 additions & 6 deletions drivers/sensor/st/lsm6dsv16x/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
# SPDX-License-Identifier: Apache-2.0

menuconfig LSM6DSV16X
bool "LSM6DSV16X I2C/SPI accelerometer and gyroscope Chip"
bool "LSM6DSV16X I3C/I2C/SPI accelerometer and gyroscope Chip"
default y
depends on DT_HAS_ST_LSM6DSV16X_ENABLED
depends on ZEPHYR_HAL_ST_MODULE
select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),i2c)
select I3C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),i3c)
select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),spi)
select HAS_STMEMSC
select USE_STDC_LSM6DSV16X
Expand All @@ -23,7 +24,7 @@ config LSM6DSV16X_STREAM
bool "Use hardware FIFO to stream data"
select LSM6DSV16X_TRIGGER
default y
depends on I2C_RTIO || SPI_RTIO
depends on I2C_RTIO || SPI_RTIO || I3C_RTIO
depends on SENSOR_ASYNC_API
help
Use this config option to enable streaming sensor data via RTIO subsystem.
Expand All @@ -40,16 +41,18 @@ config LSM6DSV16X_TRIGGER_NONE

config LSM6DSV16X_TRIGGER_GLOBAL_THREAD
bool "Use global thread"
depends on GPIO
depends on GPIO || I3C
avisconti marked this conversation as resolved.
Show resolved Hide resolved
depends on $(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSV16X),int1-gpios) ||\
$(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSV16X),int2-gpios)
$(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSV16X),int2-gpios) ||\
$(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),i3c)
select LSM6DSV16X_TRIGGER

config LSM6DSV16X_TRIGGER_OWN_THREAD
bool "Use own thread"
depends on GPIO
depends on GPIO || I3C
avisconti marked this conversation as resolved.
Show resolved Hide resolved
depends on $(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSV16X),int1-gpios) ||\
$(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSV16X),int2-gpios)
$(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSV16X),int2-gpios) ||\
$(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),i3c)
select LSM6DSV16X_TRIGGER

endchoice
Expand Down
106 changes: 95 additions & 11 deletions drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.c
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,20 @@ static int lsm6dsv16x_init_chip(const struct device *dev)
uint8_t chip_id;
uint8_t odr, fs;

#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
if (cfg->i3c.bus != NULL) {
/*
* Need to grab the pointer to the I3C device descriptor
* before we can talk to the sensor.
*/
lsm6dsv16x->i3c_dev = i3c_device_find(cfg->i3c.bus, &cfg->i3c.dev_id);
if (lsm6dsv16x->i3c_dev == NULL) {
LOG_ERR("Cannot find I3C device descriptor");
return -ENODEV;
}
}
#endif

/* All registers except 0x01 are different between banks, including the WHO_AM_I
* register and the register used for a SW reset. If the lsm6dsv16x wasn't on the user
* bank when it reset, then both the chip id check and the sw reset will fail unless we
Expand All @@ -973,13 +987,26 @@ static int lsm6dsv16x_init_chip(const struct device *dev)
return -EIO;
}

/* reset device (sw_por) */
if (lsm6dsv16x_reset_set(ctx, LSM6DSV16X_GLOBAL_RST) < 0) {
return -EIO;
}
/* Resetting the whole device while using I3C will also reset the DA, therefore perform
* only a software reset if the bus is I3C. It should be assumed that the device was
* already fully reset by the I3C CCC RSTACT (whole chip) done as apart of the I3C Bus
* initialization.
*/
if (ON_I3C_BUS(cfg)) {
/* Restore default configuration */
lsm6dsv16x_reset_set(ctx, LSM6DSV16X_RESTORE_CAL_PARAM);

/* wait 150us as reported in AN5763 */
k_sleep(K_USEC(150));
} else {
/* reset device (sw_por) */
if (lsm6dsv16x_reset_set(ctx, LSM6DSV16X_GLOBAL_RST) < 0) {
return -EIO;
}

/* wait 30ms as reported in AN5763 */
k_sleep(K_MSEC(30));
/* wait 30ms as reported in AN5763 */
k_sleep(K_MSEC(30));
}

fs = cfg->accel_range;
LOG_DBG("accel range is %d", fs);
Expand Down Expand Up @@ -1012,6 +1039,23 @@ static int lsm6dsv16x_init_chip(const struct device *dev)
return -EIO;
}

#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
if (IS_ENABLED(CONFIG_LSM6DSV16X_STREAM) && (ON_I3C_BUS(cfg))) {
/*
* Set MRL to the Max Size of the FIFO so the entire FIFO can be read
* out at once
*/
struct i3c_ccc_mrl setmrl = {
.len = 0x0700,
.ibi_len = lsm6dsv16x->i3c_dev->data_length.max_ibi,
};
if (i3c_ccc_do_setmrl(lsm6dsv16x->i3c_dev, &setmrl) < 0) {
LOG_ERR("failed to set mrl");
return -EIO;
}
}
#endif

if (lsm6dsv16x_block_data_update_set(ctx, 1) < 0) {
LOG_DBG("failed to set BDU mode");
return -EIO;
Expand Down Expand Up @@ -1164,15 +1208,55 @@ static int lsm6dsv16x_init(const struct device *dev)
static const struct lsm6dsv16x_config lsm6dsv16x_config_##inst = \
LSM6DSV16X_CONFIG_I2C(inst); \

/*
* Instantiation macros used when a device is on an I3C bus.
*/

#define LSM6DSV16X_I3C_RTIO_DEFINE(inst) \
I3C_DT_IODEV_DEFINE(lsm6dsv16x_i3c_iodev_##inst, DT_DRV_INST(inst)); \
RTIO_DEFINE(lsm6dsv16x_rtio_ctx_##inst, 4, 4);

#define LSM6DSV16X_CONFIG_I3C(inst) \
{ \
STMEMSC_CTX_I3C(&lsm6dsv16x_config_##inst.stmemsc_cfg), \
.stmemsc_cfg = { \
.i3c = &lsm6dsv16x_data_##inst.i3c_dev, \
}, \
.i3c.bus = DEVICE_DT_GET(DT_INST_BUS(inst)), \
.i3c.dev_id = I3C_DEVICE_ID_DT_INST(inst), \
IF_ENABLED(CONFIG_LSM6DSV16X_TRIGGER, \
(.int_en_i3c = DT_INST_PROP(inst, int_en_i3c), \
.bus_act_sel = DT_INST_ENUM_IDX(inst, bus_act_sel_us),)) \
LSM6DSV16X_CONFIG_COMMON(inst) \
}

#define LSM6DSV16X_DEFINE_I3C(inst) \
IF_ENABLED(CONFIG_LSM6DSV16X_STREAM, (LSM6DSV16X_I3C_RTIO_DEFINE(inst))); \
static struct lsm6dsv16x_data lsm6dsv16x_data_##inst = { \
IF_ENABLED(CONFIG_LSM6DSV16X_STREAM, \
(.rtio_ctx = &lsm6dsv16x_rtio_ctx_##inst, \
.iodev = &lsm6dsv16x_i3c_iodev_##inst, \
.bus_type = BUS_I3C,)) \
}; \
static const struct lsm6dsv16x_config lsm6dsv16x_config_##inst = \
LSM6DSV16X_CONFIG_I3C(inst); \

#define LSM6DSV16X_DEFINE_I3C_OR_I2C(inst) \
COND_CODE_0(DT_INST_PROP_BY_IDX(inst, reg, 1), \
(LSM6DSV16X_DEFINE_I2C(inst)), \
(LSM6DSV16X_DEFINE_I3C(inst)))

/*
* Main instantiation macro. Use of COND_CODE_1() selects the right
* bus-specific macro at preprocessor time.
*/

#define LSM6DSV16X_DEFINE(inst) \
COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
(LSM6DSV16X_DEFINE_SPI(inst)), \
(LSM6DSV16X_DEFINE_I2C(inst))); \
LSM6DSV16X_DEVICE_INIT(inst)
#define LSM6DSV16X_DEFINE(inst) \
COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
(LSM6DSV16X_DEFINE_SPI(inst)), \
(COND_CODE_1(DT_INST_ON_BUS(inst, i3c), \
(LSM6DSV16X_DEFINE_I3C_OR_I2C(inst)), \
(LSM6DSV16X_DEFINE_I2C(inst))))); \
LSM6DSV16X_DEVICE_INIT(inst)

DT_INST_FOREACH_STATUS_OKAY(LSM6DSV16X_DEFINE)
51 changes: 48 additions & 3 deletions drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@
#include <zephyr/drivers/i2c.h>
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */

#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
#include <zephyr/drivers/i3c.h>
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) */

#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
#define ON_I3C_BUS(cfg) (cfg->i3c.bus != NULL)
#define I3C_INT_PIN(cfg) (cfg->int_en_i3c)
#else
#define ON_I3C_BUS(cfg) (false)
#define I3C_INT_PIN(cfg) (false)
#endif

#define LSM6DSV16X_EN_BIT 0x01
#define LSM6DSV16X_DIS_BIT 0x00

Expand All @@ -46,6 +58,9 @@ struct lsm6dsv16x_config {
#endif
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
const struct spi_dt_spec spi;
#endif
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
struct i3c_device_desc **i3c;
#endif
} stmemsc_cfg;
uint8_t accel_pm;
Expand All @@ -66,7 +81,18 @@ struct lsm6dsv16x_config {
const struct gpio_dt_spec int2_gpio;
uint8_t drdy_pin;
bool trig_enabled;
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
bool int_en_i3c;
lsm6dsv16x_i3c_ibi_time_t bus_act_sel;
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) */
#endif /* CONFIG_LSM6DSV16X_TRIGGER */

#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
struct {
const struct device *bus;
const struct i3c_device_id dev_id;
} i3c;
#endif
};

union samples {
Expand All @@ -78,6 +104,19 @@ union samples {

#define LSM6DSV16X_SHUB_MAX_NUM_TARGETS 3

struct lsm6dsv16x_ibi_payload {
uint8_t mdb;
uint8_t fifo_status1;
uint8_t fifo_status2;
uint8_t all_int_src;
uint8_t status_reg;
uint8_t status_reg_ois;
uint8_t status_master_main;
uint8_t emb_func_status;
uint8_t fsm_status;
uint8_t mlc_status;
} __packed;

struct lsm6dsv16x_data {
const struct device *dev;
int16_t acc[3];
Expand Down Expand Up @@ -118,8 +157,8 @@ struct lsm6dsv16x_data {
uint8_t accel_batch_odr : 4;
uint8_t gyro_batch_odr : 4;
uint8_t temp_batch_odr : 2;
uint8_t bus_type : 1; /* I2C is 0, SPI is 1 */
uint8_t reserved : 5;
uint8_t bus_type : 2; /* I2C is 0, SPI is 1, I3C is 2 */
uint8_t reserved : 4;
#endif

#ifdef CONFIG_LSM6DSV16X_TRIGGER
Expand All @@ -136,16 +175,22 @@ struct lsm6dsv16x_data {
#if defined(CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD)
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LSM6DSV16X_THREAD_STACK_SIZE);
struct k_thread thread;
struct k_sem gpio_sem;
struct k_sem intr_sem;
avisconti marked this conversation as resolved.
Show resolved Hide resolved
#elif defined(CONFIG_LSM6DSV16X_TRIGGER_GLOBAL_THREAD)
struct k_work work;
#endif
#endif /* CONFIG_LSM6DSV16X_TRIGGER */

#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
struct i3c_device_desc *i3c_dev;
struct lsm6dsv16x_ibi_payload ibi_payload;
#endif
};

#ifdef CONFIG_LSM6DSV16X_STREAM
#define BUS_I2C 0
#define BUS_SPI 1
#define BUS_I3C 2

static inline uint8_t lsm6dsv16x_bus_reg(struct lsm6dsv16x_data *data, uint8_t x)
{
Expand Down
Loading
Loading