diff --git a/drivers/sensor/sensor_handlers.c b/drivers/sensor/sensor_handlers.c index 63c5359e0cd9b..04ba901780f80 100644 --- a/drivers/sensor/sensor_handlers.c +++ b/drivers/sensor/sensor_handlers.c @@ -68,6 +68,15 @@ static inline int z_vrfy_sensor_get_decoder(const struct device *dev, } #include +static inline int z_vrfy_sensor_upload_fw(const struct device *dev, + const void *fw_buf, size_t fw_len) +{ + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SENSOR)); + K_OOPS(K_SYSCALL_MEMORY_READ(fw_buf, fw_len)); + return z_impl_sensor_upload_fw(dev, fw_buf, fw_len); +} +#include + static inline int z_vrfy_sensor_reconfigure_read_iodev(struct rtio_iodev *iodev, const struct device *sensor, const struct sensor_chan_spec *channels, diff --git a/drivers/sensor/st/lsm6dso16is/Kconfig b/drivers/sensor/st/lsm6dso16is/Kconfig index 74d90671e6adb..e5ea7fdaaea51 100644 --- a/drivers/sensor/st/lsm6dso16is/Kconfig +++ b/drivers/sensor/st/lsm6dso16is/Kconfig @@ -18,6 +18,10 @@ menuconfig LSM6DSO16IS if LSM6DSO16IS +config LSM6DSO16IS_ISPU_ENABLE + bool "ISPU Enable" + select USE_ST_MEMS_ISPU + choice LSM6DSO16IS_TRIGGER_MODE prompt "Trigger mode" help diff --git a/drivers/sensor/st/lsm6dso16is/lsm6dso16is.c b/drivers/sensor/st/lsm6dso16is/lsm6dso16is.c index 1171d7fa380e3..c1281f3cac0f8 100644 --- a/drivers/sensor/st/lsm6dso16is/lsm6dso16is.c +++ b/drivers/sensor/st/lsm6dso16is/lsm6dso16is.c @@ -353,6 +353,22 @@ static int lsm6dso16is_sample_fetch_temp(const struct device *dev) } #endif +#if defined(CONFIG_USE_ST_MEMS_ISPU) +static int lsm6dso16is_sample_fetch_ispu(const struct device *dev) +{ + const struct lsm6dso16is_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lsm6dso16is_data *data = dev->data; + + if (lsm6dso16is_ispu_read_data_raw_get(ctx, &data->ispu[0], 64) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + + return 0; +} +#endif + #if defined(CONFIG_LSM6DSO16IS_SENSORHUB) static int lsm6dso16is_sample_fetch_shub(const struct device *dev) { @@ -383,6 +399,11 @@ static int lsm6dso16is_sample_fetch(const struct device *dev, case SENSOR_CHAN_DIE_TEMP: lsm6dso16is_sample_fetch_temp(dev); break; +#endif +#if defined(CONFIG_USE_ST_MEMS_ISPU) + case SENSOR_CHAN_ST_ISPU: + lsm6dso16is_sample_fetch_ispu(dev); + break; #endif case SENSOR_CHAN_ALL: lsm6dso16is_sample_fetch_accel(dev); @@ -390,6 +411,9 @@ static int lsm6dso16is_sample_fetch(const struct device *dev, #if defined(CONFIG_LSM6DSO16IS_ENABLE_TEMP) lsm6dso16is_sample_fetch_temp(dev); #endif +#if defined(CONFIG_USE_ST_MEMS_ISPU) + lsm6dso16is_sample_fetch_ispu(dev); +#endif #if defined(CONFIG_LSM6DSO16IS_SENSORHUB) if (data->shub_inited) { lsm6dso16is_sample_fetch_shub(dev); @@ -663,6 +687,12 @@ static int lsm6dso16is_channel_get(const struct device *dev, lsm6dso16is_gyro_channel_get_temp(val, data); break; #endif +#if defined(CONFIG_USE_ST_MEMS_ISPU) + case SENSOR_CHAN_ST_ISPU: + val->val1 = data->ispu[12]; + val->val2 = 0; + break; +#endif #if defined(CONFIG_LSM6DSO16IS_SENSORHUB) case SENSOR_CHAN_MAGN_X: case SENSOR_CHAN_MAGN_Y: @@ -710,6 +740,31 @@ static int lsm6dso16is_channel_get(const struct device *dev, return 0; } +static int lsm6dso16is_upload_ispu(const struct device *dev, + const void *fw_buf, + size_t fw_len) +{ + const struct lsm6dso16is_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + const struct mems_conf_op *bufp = (const struct mems_conf_op *)fw_buf; + int i; + + /* Load ISPU configuration */ + for ( i = 0; i < fw_len; i++ ) { + switch(bufp[i].type) { + case MEMS_CONF_OP_TYPE_DELAY: + k_msleep(bufp[i].data); + break; + + case MEMS_CONF_OP_TYPE_WRITE: + ctx->write_reg(ctx->handle, bufp[i].address, (uint8_t *)&bufp[i].data, 1); + break; + } + } + + return 0; +} + static DEVICE_API(sensor, lsm6dso16is_driver_api) = { .attr_set = lsm6dso16is_attr_set, #if CONFIG_LSM6DSO16IS_TRIGGER @@ -717,6 +772,7 @@ static DEVICE_API(sensor, lsm6dso16is_driver_api) = { #endif .sample_fetch = lsm6dso16is_sample_fetch, .channel_get = lsm6dso16is_channel_get, + .upload_fw = lsm6dso16is_upload_ispu, }; static int lsm6dso16is_init_chip(const struct device *dev) diff --git a/drivers/sensor/st/lsm6dso16is/lsm6dso16is.h b/drivers/sensor/st/lsm6dso16is/lsm6dso16is.h index 62f13586cd632..455a4b3415fb5 100644 --- a/drivers/sensor/st/lsm6dso16is/lsm6dso16is.h +++ b/drivers/sensor/st/lsm6dso16is/lsm6dso16is.h @@ -17,6 +17,8 @@ #include #include #include "lsm6dso16is_reg.h" +#include +#include #if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) #include @@ -77,6 +79,9 @@ struct lsm6dso16is_data { #if defined(CONFIG_LSM6DSO16IS_ENABLE_TEMP) int16_t temp_sample; #endif +#if defined(CONFIG_USE_ST_MEMS_ISPU) + uint8_t ispu[64]; +#endif #if defined(CONFIG_LSM6DSO16IS_SENSORHUB) uint8_t ext_data[LSM6DSO16IS_SHUB_MAX_NUM_TARGETS][6]; uint16_t magn_gain; @@ -105,6 +110,10 @@ struct lsm6dso16is_data { const struct sensor_trigger *trig_drdy_gyr; sensor_trigger_handler_t handler_drdy_temp; const struct sensor_trigger *trig_drdy_temp; +#if defined(CONFIG_USE_ST_MEMS_ISPU) + sensor_trigger_handler_t handler_ispu; + const struct sensor_trigger *trig_ispu; +#endif #if defined(CONFIG_LSM6DSO16IS_TRIGGER_OWN_THREAD) K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LSM6DSO16IS_THREAD_STACK_SIZE); diff --git a/drivers/sensor/st/lsm6dso16is/lsm6dso16is_trigger.c b/drivers/sensor/st/lsm6dso16is/lsm6dso16is_trigger.c index 93ce4f6c0b0c0..8341ee68ae2b7 100644 --- a/drivers/sensor/st/lsm6dso16is/lsm6dso16is_trigger.c +++ b/drivers/sensor/st/lsm6dso16is/lsm6dso16is_trigger.c @@ -54,6 +54,54 @@ static int lsm6dso16is_enable_t_int(const struct device *dev, int enable) } #endif +#if defined(CONFIG_USE_ST_MEMS_ISPU) +/** + * lsm6dso16is_enable_ispu_int - ISPU enable selected int pin to generate interrupt + */ +static int lsm6dso16is_enable_ispu_int(const struct device *dev, int enable) +{ + const struct lsm6dso16is_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + int ret; + + if (enable) { + int16_t buf[3]; + + /* dummy read: re-trigger interrupt */ + lsm6dso16is_acceleration_raw_get(ctx, buf); + } + + /* set interrupt */ + if (cfg->drdy_pin == 1) { + lsm6dso16is_pin_int1_route_t val = {0}; + + ret = lsm6dso16is_pin_int1_route_get(ctx, &val); + if (ret < 0) { + LOG_ERR("pint_int1_route_get error"); + return ret; + } + + val.ispu = enable; + + ret = lsm6dso16is_pin_int1_route_set(ctx, val); + } else { + lsm6dso16is_pin_int2_route_t val = {0}; + + ret = lsm6dso16is_pin_int2_route_get(ctx, &val); + if (ret < 0) { + LOG_ERR("pint_int2_route_get error"); + return ret; + } + + val.ispu = enable; + + ret = lsm6dso16is_pin_int2_route_set(ctx, val); + } + + return ret; +} +#endif + /** * lsm6dso16is_enable_xl_int - XL enable selected int pin to generate interrupt */ @@ -189,6 +237,15 @@ int lsm6dso16is_trigger_set(const struct device *dev, } } #endif +#if defined(CONFIG_USE_ST_MEMS_ISPU) + else if ((enum sensor_channel_st_embedded_cores)trig->chan == SENSOR_CHAN_ST_ISPU) { + lsm6dso16is->handler_ispu = handler; + lsm6dso16is->trig_ispu = trig; + + /* ISPU interrupt is already enabled */ + return 0; + } +#endif return -ENOTSUP; } @@ -202,21 +259,18 @@ static void lsm6dso16is_handle_interrupt(const struct device *dev) struct lsm6dso16is_data *lsm6dso16is = dev->data; const struct lsm6dso16is_config *cfg = dev->config; stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lsm6dso16is_status_reg_t status; + lsm6dso16is_status_reg_t status = {0}; - while (1) { - if (lsm6dso16is_status_reg_get(ctx, &status) < 0) { - LOG_DBG("failed reading status reg"); - return; - } + if (lsm6dso16is_status_reg_get(ctx, &status) < 0) { + LOG_DBG("failed reading status reg"); + return; + } - if ((status.xlda == 0) && (status.gda == 0) + if ((status.xlda != 0) || (status.gda != 0) #if defined(CONFIG_LSM6DSO16IS_ENABLE_TEMP) - && (status.tda == 0) + || (status.tda != 0) #endif - ) { - break; - } + ) { if ((status.xlda) && (lsm6dso16is->handler_drdy_acc != NULL)) { lsm6dso16is->handler_drdy_acc(dev, lsm6dso16is->trig_drdy_acc); @@ -230,9 +284,26 @@ static void lsm6dso16is_handle_interrupt(const struct device *dev) if ((status.tda) && (lsm6dso16is->handler_drdy_temp != NULL)) { lsm6dso16is->handler_drdy_temp(dev, lsm6dso16is->trig_drdy_temp); } + } #endif + +#if defined(CONFIG_USE_ST_MEMS_ISPU) + uint32_t ispu_status = 0; + + if (lsm6dso16is_ia_ispu_get(ctx, &ispu_status) < 0) { + LOG_DBG("failed reading status reg"); + return; } + if (ispu_status) { + ispu_status = 0; + if ((lsm6dso16is->handler_ispu != NULL)) { + lsm6dso16is->handler_ispu(dev, lsm6dso16is->trig_ispu); + } + + } +#endif + gpio_pin_interrupt_configure_dt(&cfg->gpio_drdy, GPIO_INT_EDGE_TO_ACTIVE); } diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index ba2b79d285865..2fa92f1386b46 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -705,6 +705,9 @@ struct sensor_read_config { /* Used to submit an RTIO sqe to the sensor's iodev */ typedef void (*sensor_submit_t)(const struct device *sensor, struct rtio_iodev_sqe *sqe); +/* Used to provide a driver specific callback to upload a f/w in the sensor */ +typedef int (*sensor_upload_fw_t)(const struct device *dev, const void *fw_buf, size_t fw_len); + /* The default decoder API */ extern const struct sensor_decoder_api __sensor_default_decoder; @@ -719,6 +722,7 @@ __subsystem struct sensor_driver_api { sensor_channel_get_t channel_get; sensor_get_decoder_t get_decoder; sensor_submit_t submit; + sensor_upload_fw_t upload_fw; }; /** @@ -917,6 +921,32 @@ static inline int z_impl_sensor_channel_get(const struct device *dev, return api->channel_get(dev, chan, val); } +/** + * @brief Upload a Firmware to the sensor + * + * @param[in] dev The sensor device + * @param[in] fw_buf Pointer to the Firmware buffer + * @param[in] fw_len Length of Firmware + * @return 0 on success + * @return < 0 on error + */ +__syscall int sensor_upload_fw(const struct device *dev, + const void *fw_buf, size_t fw_len); + +static inline int z_impl_sensor_upload_fw(const struct device *dev, + const void *fw_buf, size_t fw_len) +{ + const struct sensor_driver_api *api = (const struct sensor_driver_api *)dev->api; + + __ASSERT_NO_MSG(api != NULL); + + if (api->upload_fw == NULL) { + return -ENOSYS; + } + + return api->upload_fw(dev, fw_buf, fw_len); +} + #if defined(CONFIG_SENSOR_ASYNC_API) || defined(__DOXYGEN__) /* diff --git a/include/zephyr/drivers/sensor/st_embedded_cores.h b/include/zephyr/drivers/sensor/st_embedded_cores.h new file mode 100644 index 0000000000000..83da378107fce --- /dev/null +++ b/include/zephyr/drivers/sensor/st_embedded_cores.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 STMicroelectronics. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Extended Public API for STMicroelectronics embedded cores + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_ST_EMBEDDED_CORES_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_ST_EMBEDDED_CORES_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#include + +enum sensor_channel_st_embedded_cores { + SENSOR_CHAN_ST_ISPU = SENSOR_CHAN_PRIV_START, +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_ST_EMBEDDED_CORES_H_ */ diff --git a/include/zephyr/drivers/sensor/st_mems_conf_shared_types.h b/include/zephyr/drivers/sensor/st_mems_conf_shared_types.h new file mode 100644 index 0000000000000..3a80584875c96 --- /dev/null +++ b/include/zephyr/drivers/sensor/st_mems_conf_shared_types.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2025 STMicroelectronics. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/* + * This file contain the MEMS Configuration Shared Types v2.0 that are used inside + * the various algo configuration files. + */ + +#ifndef MEMS_CONF_SHARED_TYPES +#define MEMS_CONF_SHARED_TYPES + +#define MEMS_CONF_ARRAY_LEN(x) (sizeof(x) / sizeof(x[0])) + +/* + * MEMS_CONF_SHARED_TYPES format supports the following operations: + * - MEMS_CONF_OP_TYPE_TYPE_READ: read the register at the location specified + * by the "address" field ("data" field is ignored) + * - MEMS_CONF_OP_TYPE_TYPE_WRITE: write the value specified by the "data" + * field at the location specified by the "address" field + * - MEMS_CONF_OP_TYPE_TYPE_DELAY: wait the number of milliseconds specified by + * the "data" field ("address" field is ignored) + * - MEMS_CONF_OP_TYPE_TYPE_POLL_SET: poll the register at the location + * specified by the "address" field until all the bits identified by the mask + * specified by the "data" field are set to 1 + * - MEMS_CONF_OP_TYPE_TYPE_POLL_RESET: poll the register at the location + * specified by the "address" field until all the bits identified by the mask + * specified by the "data" field are reset to 0 + */ + +struct mems_conf_name_list { + const char *const *list; + uint16_t len; +}; + +enum { + MEMS_CONF_OP_TYPE_READ = 1, + MEMS_CONF_OP_TYPE_WRITE = 2, + MEMS_CONF_OP_TYPE_DELAY = 3, + MEMS_CONF_OP_TYPE_POLL_SET = 4, + MEMS_CONF_OP_TYPE_POLL_RESET = 5 +}; + +struct mems_conf_op { + uint8_t type; + uint8_t address; + uint8_t data; +}; + +struct mems_conf_op_list { + const struct mems_conf_op *list; + uint32_t len; +}; + +#endif /* MEMS_CONF_SHARED_TYPES */ + +#ifndef MEMS_CONF_METADATA_SHARED_TYPES +#define MEMS_CONF_METADATA_SHARED_TYPES + +struct mems_conf_application { + char *name; + char *version; +}; + +struct mems_conf_result { + uint8_t code; + char *label; +}; + +enum { + MEMS_CONF_OUTPUT_CORE_HW = 1, + MEMS_CONF_OUTPUT_CORE_EMB = 2, + MEMS_CONF_OUTPUT_CORE_FSM = 3, + MEMS_CONF_OUTPUT_CORE_MLC = 4, + MEMS_CONF_OUTPUT_CORE_ISPU = 5 +}; + +enum { + MEMS_CONF_OUTPUT_TYPE_UINT8_T = 1, + MEMS_CONF_OUTPUT_TYPE_INT8_T = 2, + MEMS_CONF_OUTPUT_TYPE_CHAR = 3, + MEMS_CONF_OUTPUT_TYPE_UINT16_T = 4, + MEMS_CONF_OUTPUT_TYPE_INT16_T = 5, + MEMS_CONF_OUTPUT_TYPE_UINT32_T = 6, + MEMS_CONF_OUTPUT_TYPE_INT32_T = 7, + MEMS_CONF_OUTPUT_TYPE_UINT64_T = 8, + MEMS_CONF_OUTPUT_TYPE_INT64_T = 9, + MEMS_CONF_OUTPUT_TYPE_HALF = 10, + MEMS_CONF_OUTPUT_TYPE_FLOAT = 11, + MEMS_CONF_OUTPUT_TYPE_DOUBLE = 12 +}; + +struct mems_conf_output { + char *name; + uint8_t core; + uint8_t type; + uint16_t len; + uint8_t reg_addr; + char *reg_name; + uint8_t num_results; + const struct mems_conf_result *results; +}; + +struct mems_conf_output_list { + const struct mems_conf_output *list; + uint16_t len; +}; + +struct mems_conf_mlc_identifier { + uint8_t fifo_tag; + uint16_t id; + char *label; +}; + +struct mems_conf_mlc_identifier_list { + const struct mems_conf_mlc_identifier *list; + uint16_t len; +}; + +#endif /* MEMS_CONF_METADATA_SHARED_TYPES */ diff --git a/modules/hal_st/Kconfig b/modules/hal_st/Kconfig index 43a8320e13bb4..17af49c13b2b1 100644 --- a/modules/hal_st/Kconfig +++ b/modules/hal_st/Kconfig @@ -202,3 +202,6 @@ config USE_STDC_STTS751 bool endif # HAS_STMEMSC + +config USE_ST_MEMS_ISPU + bool