Skip to content

Commit eb93ba0

Browse files
XenuIsWatchingkartben
authored andcommitted
sensor: lsm6dsv16x: add i3c support
Add I3C support to the lsm6dsv16x. Signed-off-by: Ryan McClelland <[email protected]>
1 parent cbfabf8 commit eb93ba0

File tree

6 files changed

+397
-82
lines changed

6 files changed

+397
-82
lines changed

drivers/sensor/st/lsm6dsv16x/Kconfig

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
# SPDX-License-Identifier: Apache-2.0
55

66
menuconfig LSM6DSV16X
7-
bool "LSM6DSV16X I2C/SPI accelerometer and gyroscope Chip"
7+
bool "LSM6DSV16X I3C/I2C/SPI accelerometer and gyroscope Chip"
88
default y
99
depends on DT_HAS_ST_LSM6DSV16X_ENABLED
1010
depends on ZEPHYR_HAL_ST_MODULE
1111
select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),i2c)
12+
select I3C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),i3c)
1213
select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),spi)
1314
select HAS_STMEMSC
1415
select USE_STDC_LSM6DSV16X
@@ -23,7 +24,7 @@ config LSM6DSV16X_STREAM
2324
bool "Use hardware FIFO to stream data"
2425
select LSM6DSV16X_TRIGGER
2526
default y
26-
depends on I2C_RTIO || SPI_RTIO
27+
depends on I2C_RTIO || SPI_RTIO || I3C_RTIO
2728
depends on SENSOR_ASYNC_API
2829
help
2930
Use this config option to enable streaming sensor data via RTIO subsystem.
@@ -40,16 +41,18 @@ config LSM6DSV16X_TRIGGER_NONE
4041

4142
config LSM6DSV16X_TRIGGER_GLOBAL_THREAD
4243
bool "Use global thread"
43-
depends on GPIO
44+
depends on GPIO || I3C
4445
depends on $(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSV16X),int1-gpios) ||\
45-
$(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSV16X),int2-gpios)
46+
$(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSV16X),int2-gpios) ||\
47+
$(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),i3c)
4648
select LSM6DSV16X_TRIGGER
4749

4850
config LSM6DSV16X_TRIGGER_OWN_THREAD
4951
bool "Use own thread"
50-
depends on GPIO
52+
depends on GPIO || I3C
5153
depends on $(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSV16X),int1-gpios) ||\
52-
$(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSV16X),int2-gpios)
54+
$(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSV16X),int2-gpios) ||\
55+
$(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),i3c)
5356
select LSM6DSV16X_TRIGGER
5457

5558
endchoice

drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.c

Lines changed: 95 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,20 @@ static int lsm6dsv16x_init_chip(const struct device *dev)
951951
uint8_t chip_id;
952952
uint8_t odr, fs;
953953

954+
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
955+
if (cfg->i3c.bus != NULL) {
956+
/*
957+
* Need to grab the pointer to the I3C device descriptor
958+
* before we can talk to the sensor.
959+
*/
960+
lsm6dsv16x->i3c_dev = i3c_device_find(cfg->i3c.bus, &cfg->i3c.dev_id);
961+
if (lsm6dsv16x->i3c_dev == NULL) {
962+
LOG_ERR("Cannot find I3C device descriptor");
963+
return -ENODEV;
964+
}
965+
}
966+
#endif
967+
954968
/* All registers except 0x01 are different between banks, including the WHO_AM_I
955969
* register and the register used for a SW reset. If the lsm6dsv16x wasn't on the user
956970
* bank when it reset, then both the chip id check and the sw reset will fail unless we
@@ -973,13 +987,26 @@ static int lsm6dsv16x_init_chip(const struct device *dev)
973987
return -EIO;
974988
}
975989

976-
/* reset device (sw_por) */
977-
if (lsm6dsv16x_reset_set(ctx, LSM6DSV16X_GLOBAL_RST) < 0) {
978-
return -EIO;
979-
}
990+
/* Resetting the whole device while using I3C will also reset the DA, therefore perform
991+
* only a software reset if the bus is I3C. It should be assumed that the device was
992+
* already fully reset by the I3C CCC RSTACT (whole chip) done as apart of the I3C Bus
993+
* initialization.
994+
*/
995+
if (ON_I3C_BUS(cfg)) {
996+
/* Restore default configuration */
997+
lsm6dsv16x_reset_set(ctx, LSM6DSV16X_RESTORE_CAL_PARAM);
998+
999+
/* wait 150us as reported in AN5763 */
1000+
k_sleep(K_USEC(150));
1001+
} else {
1002+
/* reset device (sw_por) */
1003+
if (lsm6dsv16x_reset_set(ctx, LSM6DSV16X_GLOBAL_RST) < 0) {
1004+
return -EIO;
1005+
}
9801006

981-
/* wait 30ms as reported in AN5763 */
982-
k_sleep(K_MSEC(30));
1007+
/* wait 30ms as reported in AN5763 */
1008+
k_sleep(K_MSEC(30));
1009+
}
9831010

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

1042+
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
1043+
if (IS_ENABLED(CONFIG_LSM6DSV16X_STREAM) && (ON_I3C_BUS(cfg))) {
1044+
/*
1045+
* Set MRL to the Max Size of the FIFO so the entire FIFO can be read
1046+
* out at once
1047+
*/
1048+
struct i3c_ccc_mrl setmrl = {
1049+
.len = 0x0700,
1050+
.ibi_len = lsm6dsv16x->i3c_dev->data_length.max_ibi,
1051+
};
1052+
if (i3c_ccc_do_setmrl(lsm6dsv16x->i3c_dev, &setmrl) < 0) {
1053+
LOG_ERR("failed to set mrl");
1054+
return -EIO;
1055+
}
1056+
}
1057+
#endif
1058+
10151059
if (lsm6dsv16x_block_data_update_set(ctx, 1) < 0) {
10161060
LOG_DBG("failed to set BDU mode");
10171061
return -EIO;
@@ -1164,15 +1208,55 @@ static int lsm6dsv16x_init(const struct device *dev)
11641208
static const struct lsm6dsv16x_config lsm6dsv16x_config_##inst = \
11651209
LSM6DSV16X_CONFIG_I2C(inst); \
11661210

1211+
/*
1212+
* Instantiation macros used when a device is on an I3C bus.
1213+
*/
1214+
1215+
#define LSM6DSV16X_I3C_RTIO_DEFINE(inst) \
1216+
I3C_DT_IODEV_DEFINE(lsm6dsv16x_i3c_iodev_##inst, DT_DRV_INST(inst)); \
1217+
RTIO_DEFINE(lsm6dsv16x_rtio_ctx_##inst, 4, 4);
1218+
1219+
#define LSM6DSV16X_CONFIG_I3C(inst) \
1220+
{ \
1221+
STMEMSC_CTX_I3C(&lsm6dsv16x_config_##inst.stmemsc_cfg), \
1222+
.stmemsc_cfg = { \
1223+
.i3c = &lsm6dsv16x_data_##inst.i3c_dev, \
1224+
}, \
1225+
.i3c.bus = DEVICE_DT_GET(DT_INST_BUS(inst)), \
1226+
.i3c.dev_id = I3C_DEVICE_ID_DT_INST(inst), \
1227+
IF_ENABLED(CONFIG_LSM6DSV16X_TRIGGER, \
1228+
(.int_en_i3c = DT_INST_PROP(inst, int_en_i3c), \
1229+
.bus_act_sel = DT_INST_ENUM_IDX(inst, bus_act_sel_us),)) \
1230+
LSM6DSV16X_CONFIG_COMMON(inst) \
1231+
}
1232+
1233+
#define LSM6DSV16X_DEFINE_I3C(inst) \
1234+
IF_ENABLED(CONFIG_LSM6DSV16X_STREAM, (LSM6DSV16X_I3C_RTIO_DEFINE(inst))); \
1235+
static struct lsm6dsv16x_data lsm6dsv16x_data_##inst = { \
1236+
IF_ENABLED(CONFIG_LSM6DSV16X_STREAM, \
1237+
(.rtio_ctx = &lsm6dsv16x_rtio_ctx_##inst, \
1238+
.iodev = &lsm6dsv16x_i3c_iodev_##inst, \
1239+
.bus_type = BUS_I3C,)) \
1240+
}; \
1241+
static const struct lsm6dsv16x_config lsm6dsv16x_config_##inst = \
1242+
LSM6DSV16X_CONFIG_I3C(inst); \
1243+
1244+
#define LSM6DSV16X_DEFINE_I3C_OR_I2C(inst) \
1245+
COND_CODE_0(DT_INST_PROP_BY_IDX(inst, reg, 1), \
1246+
(LSM6DSV16X_DEFINE_I2C(inst)), \
1247+
(LSM6DSV16X_DEFINE_I3C(inst)))
1248+
11671249
/*
11681250
* Main instantiation macro. Use of COND_CODE_1() selects the right
11691251
* bus-specific macro at preprocessor time.
11701252
*/
11711253

1172-
#define LSM6DSV16X_DEFINE(inst) \
1173-
COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
1174-
(LSM6DSV16X_DEFINE_SPI(inst)), \
1175-
(LSM6DSV16X_DEFINE_I2C(inst))); \
1176-
LSM6DSV16X_DEVICE_INIT(inst)
1254+
#define LSM6DSV16X_DEFINE(inst) \
1255+
COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
1256+
(LSM6DSV16X_DEFINE_SPI(inst)), \
1257+
(COND_CODE_1(DT_INST_ON_BUS(inst, i3c), \
1258+
(LSM6DSV16X_DEFINE_I3C_OR_I2C(inst)), \
1259+
(LSM6DSV16X_DEFINE_I2C(inst))))); \
1260+
LSM6DSV16X_DEVICE_INIT(inst)
11771261

11781262
DT_INST_FOREACH_STATUS_OKAY(LSM6DSV16X_DEFINE)

drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.h

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@
2626
#include <zephyr/drivers/i2c.h>
2727
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */
2828

29+
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
30+
#include <zephyr/drivers/i3c.h>
31+
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) */
32+
33+
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
34+
#define ON_I3C_BUS(cfg) (cfg->i3c.bus != NULL)
35+
#define I3C_INT_PIN(cfg) (cfg->int_en_i3c)
36+
#else
37+
#define ON_I3C_BUS(cfg) (false)
38+
#define I3C_INT_PIN(cfg) (false)
39+
#endif
40+
2941
#define LSM6DSV16X_EN_BIT 0x01
3042
#define LSM6DSV16X_DIS_BIT 0x00
3143

@@ -46,6 +58,9 @@ struct lsm6dsv16x_config {
4658
#endif
4759
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
4860
const struct spi_dt_spec spi;
61+
#endif
62+
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
63+
struct i3c_device_desc **i3c;
4964
#endif
5065
} stmemsc_cfg;
5166
uint8_t accel_pm;
@@ -66,7 +81,18 @@ struct lsm6dsv16x_config {
6681
const struct gpio_dt_spec int2_gpio;
6782
uint8_t drdy_pin;
6883
bool trig_enabled;
84+
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
85+
bool int_en_i3c;
86+
lsm6dsv16x_i3c_ibi_time_t bus_act_sel;
87+
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) */
6988
#endif /* CONFIG_LSM6DSV16X_TRIGGER */
89+
90+
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
91+
struct {
92+
const struct device *bus;
93+
const struct i3c_device_id dev_id;
94+
} i3c;
95+
#endif
7096
};
7197

7298
union samples {
@@ -78,6 +104,19 @@ union samples {
78104

79105
#define LSM6DSV16X_SHUB_MAX_NUM_TARGETS 3
80106

107+
struct lsm6dsv16x_ibi_payload {
108+
uint8_t mdb;
109+
uint8_t fifo_status1;
110+
uint8_t fifo_status2;
111+
uint8_t all_int_src;
112+
uint8_t status_reg;
113+
uint8_t status_reg_ois;
114+
uint8_t status_master_main;
115+
uint8_t emb_func_status;
116+
uint8_t fsm_status;
117+
uint8_t mlc_status;
118+
} __packed;
119+
81120
struct lsm6dsv16x_data {
82121
const struct device *dev;
83122
int16_t acc[3];
@@ -118,8 +157,8 @@ struct lsm6dsv16x_data {
118157
uint8_t accel_batch_odr : 4;
119158
uint8_t gyro_batch_odr : 4;
120159
uint8_t temp_batch_odr : 2;
121-
uint8_t bus_type : 1; /* I2C is 0, SPI is 1 */
122-
uint8_t reserved : 5;
160+
uint8_t bus_type : 2; /* I2C is 0, SPI is 1, I3C is 2 */
161+
uint8_t reserved : 4;
123162
#endif
124163

125164
#ifdef CONFIG_LSM6DSV16X_TRIGGER
@@ -136,16 +175,22 @@ struct lsm6dsv16x_data {
136175
#if defined(CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD)
137176
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LSM6DSV16X_THREAD_STACK_SIZE);
138177
struct k_thread thread;
139-
struct k_sem gpio_sem;
178+
struct k_sem intr_sem;
140179
#elif defined(CONFIG_LSM6DSV16X_TRIGGER_GLOBAL_THREAD)
141180
struct k_work work;
142181
#endif
143182
#endif /* CONFIG_LSM6DSV16X_TRIGGER */
183+
184+
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
185+
struct i3c_device_desc *i3c_dev;
186+
struct lsm6dsv16x_ibi_payload ibi_payload;
187+
#endif
144188
};
145189

146190
#ifdef CONFIG_LSM6DSV16X_STREAM
147191
#define BUS_I2C 0
148192
#define BUS_SPI 1
193+
#define BUS_I3C 2
149194

150195
static inline uint8_t lsm6dsv16x_bus_reg(struct lsm6dsv16x_data *data, uint8_t x)
151196
{

0 commit comments

Comments
 (0)