diff --git a/drivers/sensor/sensirion/CMakeLists.txt b/drivers/sensor/sensirion/CMakeLists.txt index 68a26c2518a..2ef59c627dc 100644 --- a/drivers/sensor/sensirion/CMakeLists.txt +++ b/drivers/sensor/sensirion/CMakeLists.txt @@ -6,4 +6,5 @@ add_subdirectory_ifdef(CONFIG_SGP40 sgp40) add_subdirectory_ifdef(CONFIG_SHT3XD sht3xd) add_subdirectory_ifdef(CONFIG_SHT4X sht4x) add_subdirectory_ifdef(CONFIG_SHTCX shtcx) +add_subdirectory_ifdef(CONFIG_STS4X sts4x) # zephyr-keep-sorted-stop diff --git a/drivers/sensor/sensirion/Kconfig b/drivers/sensor/sensirion/Kconfig index 87409404fa8..6d1f48dbe95 100644 --- a/drivers/sensor/sensirion/Kconfig +++ b/drivers/sensor/sensirion/Kconfig @@ -6,4 +6,5 @@ source "drivers/sensor/sensirion/sgp40/Kconfig" source "drivers/sensor/sensirion/sht3xd/Kconfig" source "drivers/sensor/sensirion/sht4x/Kconfig" source "drivers/sensor/sensirion/shtcx/Kconfig" +source "drivers/sensor/sensirion/sts4x/Kconfig" # zephyr-keep-sorted-stop diff --git a/drivers/sensor/sensirion/sts4x/CMakeLists.txt b/drivers/sensor/sensirion/sts4x/CMakeLists.txt new file mode 100644 index 00000000000..832fce63296 --- /dev/null +++ b/drivers/sensor/sensirion/sts4x/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(sts4x.c) diff --git a/drivers/sensor/sensirion/sts4x/Kconfig b/drivers/sensor/sensirion/sts4x/Kconfig new file mode 100644 index 00000000000..d37ea8c8ed9 --- /dev/null +++ b/drivers/sensor/sensirion/sts4x/Kconfig @@ -0,0 +1,13 @@ +# Drivers configuration options for Sensirion STS4x + +# Copyright (c) 2024 Jan Fäh +# SPDX-License-Identifier: Apache-2.0 + +config STS4X + bool "STS4x Temperature Sensor" + default y + depends on DT_HAS_SENSIRION_STS4X_ENABLED + select I2C + select CRC + help + Enable driver for the Sensirion STS4x temperature sensors. diff --git a/drivers/sensor/sensirion/sts4x/sts4x.c b/drivers/sensor/sensirion/sts4x/sts4x.c new file mode 100644 index 00000000000..288622bca2e --- /dev/null +++ b/drivers/sensor/sensirion/sts4x/sts4x.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2024 Jan Fäh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT sensirion_sts4x + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(STS4X, CONFIG_SENSOR_LOG_LEVEL); + +#define STS4X_CMD_RESET 0x94 + +#define STS4X_RESET_TIME 1 + +#define STS4X_CRC_POLY 0x31 +#define STS4X_CRC_INIT 0xFF + +#define STS4X_MAX_TEMP 175 +#define STS4X_MIN_TEMP -45 + +struct sts4x_config { + struct i2c_dt_spec bus; + uint8_t repeatability; +}; + +struct sts4x_data { + uint16_t temp_sample; +}; + +static const uint8_t measure_cmds[3] = {0xE0, 0xF6, 0xFD}; +static const uint16_t measure_time_us[3] = {1600, 4500, 8300}; + +static int sts4x_crc_check(uint16_t value, uint8_t sensor_crc) +{ + uint8_t buf[2]; + + sys_put_be16(value, buf); + + uint8_t calculated_crc = crc8(buf, 2, STS4X_CRC_POLY, STS4X_CRC_INIT, false); + + if (calculated_crc == sensor_crc) { + return 0; + } + + return -EIO; +} + +static int sts4x_write_command(const struct device *dev, uint8_t cmd) +{ + const struct sts4x_config *cfg = dev->config; + uint8_t tx_buf = cmd; + + return i2c_write_dt(&cfg->bus, &tx_buf, 1); +} + +static int sts4x_read_sample(const struct device *dev, uint16_t *temp_sample) +{ + const struct sts4x_config *cfg = dev->config; + uint8_t rx_buf[3]; + int ret; + + ret = i2c_read_dt(&cfg->bus, rx_buf, sizeof(rx_buf)); + if (ret < 0) { + LOG_ERR("Failed to read data."); + return ret; + } + + *temp_sample = sys_get_be16(rx_buf); + ret = sts4x_crc_check(*temp_sample, rx_buf[2]); + if (ret < 0) { + LOG_ERR("Invalid CRC."); + return ret; + } + + return 0; +} + +static int sts4x_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct sts4x_data *data = dev->data; + const struct sts4x_config *cfg = dev->config; + int ret; + + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_AMBIENT_TEMP) { + ret = sts4x_write_command(dev, measure_cmds[cfg->repeatability]); + if (ret < 0) { + LOG_ERR("Failed to write measure command."); + return ret; + } + + k_usleep(measure_time_us[cfg->repeatability]); + + ret = sts4x_read_sample(dev, &data->temp_sample); + if (ret < 0) { + LOG_ERR("Failed to get temperature data."); + return ret; + } + + return 0; + } else { + return -ENOTSUP; + } +} + +static int sts4x_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + const struct sts4x_data *data = dev->data; + + if (chan == SENSOR_CHAN_AMBIENT_TEMP) { + int64_t temp; + + temp = data->temp_sample * STS4X_MAX_TEMP; + val->val1 = (int32_t)(temp / 0xFFFF) + STS4X_MIN_TEMP; + val->val2 = ((temp % 0xFFFF) * 1000000) / 0xFFFF; + } else { + return -ENOTSUP; + } + return 0; +} + +static int sts4x_init(const struct device *dev) +{ + const struct sts4x_config *cfg = dev->config; + int ret; + + if (!i2c_is_ready_dt(&cfg->bus)) { + LOG_ERR("Device not ready."); + return -ENODEV; + } + + ret = sts4x_write_command(dev, STS4X_CMD_RESET); + if (ret < 0) { + LOG_ERR("Failed to reset the device."); + return ret; + } + + k_msleep(STS4X_RESET_TIME); + + return 0; +} + +static const struct sensor_driver_api sts4x_api_funcs = { + .sample_fetch = sts4x_sample_fetch, + .channel_get = sts4x_channel_get, +}; + +#define STS4X_INIT(inst) \ + static struct sts4x_data sts4x_data_##inst; \ + static const struct sts4x_config sts4x_config_##inst = { \ + .bus = I2C_DT_SPEC_INST_GET(inst), \ + .repeatability = DT_INST_PROP(inst, repeatability), \ + }; \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, sts4x_init, NULL, &sts4x_data_##inst, \ + &sts4x_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &sts4x_api_funcs); + +DT_INST_FOREACH_STATUS_OKAY(STS4X_INIT) diff --git a/dts/bindings/sensor/sensirion,sts4x.yaml b/dts/bindings/sensor/sensirion,sts4x.yaml new file mode 100644 index 00000000000..da01cbd3633 --- /dev/null +++ b/dts/bindings/sensor/sensirion,sts4x.yaml @@ -0,0 +1,22 @@ +# Copyright (c) 2024, Jan Fäh +# SPDX-License-Identifier: Apache-2.0 + +description: Sensirion STS4x temperature sensor + +compatible: "sensirion,sts4x" + +include: [sensor-device.yaml, i2c-device.yaml] + +properties: + repeatability: + type: int + required: true + description: | + Repeatability of the T Measurement + 0 = low -> 1.6 ms + 1 = med -> 4.5 ms + 2 = high -> 8.3 ms + enum: + - 0 + - 1 + - 2 diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 9a21c61a698..9b1a5cd1f95 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -1125,3 +1125,9 @@ test_i2c_ilps22qs: ilps22qs@9c { avg = ; fs = ; }; + +test_i2c_sts4x: sts4x@9d { + compatible = "sensirion,sts4x"; + reg = <0x99>; + repeatability = <2>; +};