From 3384ebb00feb0de26b1f843eab01908a69db6332 Mon Sep 17 00:00:00 2001 From: Jilay Pandya Date: Fri, 18 Aug 2023 18:56:46 +0200 Subject: [PATCH] driver: sensor: adds basic support for analog devices ltc2990 This commit adds Kconfig variables to configure ADLTC2990. This commit adds basic driver code for analog devices ltc2990 sensor. Signed-off-by: Jilay Pandya --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/adltc2990/CMakeLists.txt | 6 + drivers/sensor/adltc2990/Kconfig | 13 + drivers/sensor/adltc2990/adltc2990.c | 470 +++++++++++++++++++++++ drivers/sensor/adltc2990/adltc2990.h | 63 +++ drivers/sensor/adltc2990/adltc2990_reg.h | 54 +++ tests/drivers/build_all/sensor/i2c.dtsi | 12 + 8 files changed, 620 insertions(+) create mode 100644 drivers/sensor/adltc2990/CMakeLists.txt create mode 100644 drivers/sensor/adltc2990/Kconfig create mode 100644 drivers/sensor/adltc2990/adltc2990.c create mode 100644 drivers/sensor/adltc2990/adltc2990.h create mode 100644 drivers/sensor/adltc2990/adltc2990_reg.h diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index e905bb3ef7f..e2d46e88fd6 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory_ifdef(CONFIG_A01NYUB a01nyub) add_subdirectory_ifdef(CONFIG_ADC_CMP_NPCX nuvoton_adc_cmp_npcx) +add_subdirectory_ifdef(CONFIG_ADLTC2990 adltc2990) add_subdirectory_ifdef(CONFIG_ADT7310 adt7310) add_subdirectory_ifdef(CONFIG_ADT7420 adt7420) add_subdirectory_ifdef(CONFIG_ADXL345 adxl345) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index fb4080c7823..cd4faef46e4 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -58,6 +58,7 @@ config SENSOR_INFO comment "Device Drivers" source "drivers/sensor/a01nyub/Kconfig" +source "drivers/sensor/adltc2990/Kconfig" source "drivers/sensor/adt7310/Kconfig" source "drivers/sensor/adt7420/Kconfig" source "drivers/sensor/adxl345/Kconfig" diff --git a/drivers/sensor/adltc2990/CMakeLists.txt b/drivers/sensor/adltc2990/CMakeLists.txt new file mode 100644 index 00000000000..45ca5eb803b --- /dev/null +++ b/drivers/sensor/adltc2990/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright(c) 2023 Carl Zeiss Meditec AG +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(adltc2990.c) diff --git a/drivers/sensor/adltc2990/Kconfig b/drivers/sensor/adltc2990/Kconfig new file mode 100644 index 00000000000..260ae6af66b --- /dev/null +++ b/drivers/sensor/adltc2990/Kconfig @@ -0,0 +1,13 @@ +# ADLTC2990 Quad I2C Voltage, Current and Temperature sensor configuration options + +# Copyright(c) 2023 Carl Zeiss Meditec AG +# SPDX-License-Identifier: Apache-2.0 + +config ADLTC2990 + bool "ADLTC2990 Quad I2C Voltage, Current and Temperature Monitor" + default y + depends on DT_HAS_ADI_ADLTC2990_ENABLED + select I2C + help + Enable the driver for Analog Devices LTC2990 + Quad I2C Voltage, Current and Temperature Monitor. diff --git a/drivers/sensor/adltc2990/adltc2990.c b/drivers/sensor/adltc2990/adltc2990.c new file mode 100644 index 00000000000..2e410505136 --- /dev/null +++ b/drivers/sensor/adltc2990/adltc2990.c @@ -0,0 +1,470 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2023 Carl Zeiss Meditec AG + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_adltc2990 + +#include +#include + +#include "adltc2990_reg.h" +#include "adltc2990.h" + +#include +LOG_MODULE_REGISTER(adltc2990, CONFIG_SENSOR_LOG_LEVEL); + +static enum adltc2990_monitoring_type adltc2990_get_v1_v2_measurement_modes(uint8_t mode_4_3, + uint8_t mode_2_0) +{ + if (mode_2_0 > ADLTC2990_MODE_2_0_MAX_VALUE || mode_4_3 > ADLTC2990_MODE_4_3_MAX_VALUE) { + LOG_ERR("Invalid Measurement Mode"); + return -EINVAL; + } + if (mode_4_3 == ADLTC2990_MEASURE_INTERNAL_TEMPERATURE_ONLY || + mode_4_3 == ADLTC2990_MEASURE_PINS_V3_V4_ONLY) { + return NOTHING; + } + + enum adltc2990_monitoring_type type = NOTHING; + + switch (mode_2_0) { + case ADLTC2990_MODE_V1_V2_TR2: + case ADLTC2990_MODE_V1_V2_V3_V4: { + type = VOLTAGE_SINGLEENDED; + break; + } + case ADLTC2990_MODE_V1_MINUS_V2_TR2: + case ADLTC2990_MODE_V1_MINUS_V2_V3_V4: + case ADLTC2990_MODE_V1_MINUS_V2_V3_MINUS_V4: { + type = VOLTAGE_DIFFERENTIAL; + break; + } + case ADLTC2990_MODE_TR1_V3_V4: + case ADLTC2990_MODE_TR1_V3_MINUS_V4: { + case ADLTC2990_MODE_TR1_TR2: + type = TEMPERATURE; + break; + } + default: { + break; + } + } + return type; +} + +static enum adltc2990_monitoring_type adltc2990_get_v3_v4_measurement_modes(uint8_t mode_4_3, + uint8_t mode_2_0) +{ + if (mode_2_0 > ADLTC2990_MODE_2_0_MAX_VALUE || mode_4_3 > ADLTC2990_MODE_4_3_MAX_VALUE) { + LOG_ERR("Invalid Measurement Mode"); + return -EINVAL; + } + if (mode_4_3 == ADLTC2990_MEASURE_INTERNAL_TEMPERATURE_ONLY || + mode_4_3 == ADLTC2990_MEASURE_PINS_V1_V2_ONLY) { + return NOTHING; + } + + enum adltc2990_monitoring_type type = NOTHING; + + switch (mode_2_0) { + case ADLTC2990_MODE_V1_V2_TR2: + case ADLTC2990_MODE_V1_MINUS_V2_TR2: + case ADLTC2990_MODE_TR1_TR2: { + type = TEMPERATURE; + break; + } + + case ADLTC2990_MODE_V1_MINUS_V2_V3_V4: + case ADLTC2990_MODE_TR1_V3_V4: + case ADLTC2990_MODE_V1_V2_V3_V4: { + type = VOLTAGE_SINGLEENDED; + break; + } + case ADLTC2990_MODE_TR1_V3_MINUS_V4: + case ADLTC2990_MODE_V1_MINUS_V2_V3_MINUS_V4: { + type = VOLTAGE_DIFFERENTIAL; + break; + } + default: { + break; + } + } + return type; +} + +static bool adltc2990_is_busy(const struct device *dev) +{ + const struct adltc2990_config *cfg = dev->config; + uint8_t status_reg = 0; + + i2c_reg_read_byte_dt(&cfg->bus, ADLTC2990_REG_STATUS, &status_reg); + return status_reg & BIT(0); +} + +static void adltc2990_get_v1_v2_val(const struct device *dev, struct sensor_value *val, + uint8_t num_values, uint8_t *const offset_index) +{ + struct adltc2990_data *data = dev->data; + + for (uint8_t index = 0; index < num_values; index++) { + val[index].val1 = data->pins_v1_v2_values[index] / 1000000; + val[index].val2 = data->pins_v1_v2_values[index] % 1000000; + *offset_index = index + 1; + } +} + +static void adltc2990_get_v3_v4_val(const struct device *dev, struct sensor_value *val, + uint8_t num_values, uint8_t const *const offset) +{ + struct adltc2990_data *data = dev->data; + + uint8_t offset_index = *offset; + + for (uint8_t index = 0; index < num_values; index++) { + val[index + offset_index].val1 = data->pins_v3_v4_values[index] / 1000000; + val[index + offset_index].val2 = data->pins_v3_v4_values[index] % 1000000; + } +} + +static int adltc2990_trigger_measurement(const struct device *dev) +{ + const struct adltc2990_config *cfg = dev->config; + + return i2c_reg_write_byte_dt(&cfg->bus, ADLTC2990_REG_TRIGGER, 0x1); +} + +static int32_t adltc2990_get_property_value(const struct device *dev, + enum adltc2990_monitoring_type type, + enum adltc2990_monitor_pins pin) +{ + const struct adltc2990_config *cfg = dev->config; + + uint8_t msb_value = 0, lsb_value = 0; + uint8_t msb_address, lsb_address; + + switch (pin) { + case V1: { + msb_address = ADLTC2990_REG_V1_MSB; + lsb_address = ADLTC2990_REG_V1_LSB; + break; + } + case V2: { + msb_address = ADLTC2990_REG_V2_MSB; + lsb_address = ADLTC2990_REG_V2_LSB; + break; + } + case V3: { + msb_address = ADLTC2990_REG_V3_MSB; + lsb_address = ADLTC2990_REG_V3_LSB; + break; + } + case V4: { + msb_address = ADLTC2990_REG_V4_MSB; + lsb_address = ADLTC2990_REG_V4_LSB; + break; + } + case INTERNAL_TEMPERATURE: { + msb_address = ADLTC2990_REG_INTERNAL_TEMP_MSB; + lsb_address = ADLTC2990_REG_INTERNAL_TEMP_LSB; + break; + } + case SUPPLY_VOLTAGE: { + msb_address = ADLTC2990_REG_VCC_MSB; + lsb_address = ADLTC2990_REG_VCC_LSB; + break; + } + default: { + LOG_ERR("Trying to access illegal register"); + return -EINVAL; + } + } + + i2c_reg_read_byte_dt(&cfg->bus, msb_address, &msb_value); + i2c_reg_read_byte_dt(&cfg->bus, lsb_address, &lsb_value); + uint16_t conversion_factor; + uint8_t negative_bit_index; + + if (type == VOLTAGE_SINGLEENDED) { + conversion_factor = ADLTC2990_VOLTAGE_SINGLEENDED_CONVERSION_FACTOR; + negative_bit_index = 14; + } else if (type == VOLTAGE_DIFFERENTIAL) { + conversion_factor = ADLTC2990_VOLTAGE_DIFFERENTIAL_CONVERSION_FACTOR; + negative_bit_index = 14; + } else if (type == TEMPERATURE) { + conversion_factor = ADLTC2990_TEMPERATURE_CONVERSION_FACTOR; + negative_bit_index = 12; + } else { + LOG_ERR("unknown type"); + return -EINVAL; + } + + int16_t value = (msb_value<<8)+lsb_value; + + int32_t voltage_value = (value << (31-negative_bit_index))>>(31-negative_bit_index); + + return (voltage_value * conversion_factor) / 100; +} + +static int adltc2990_init(const struct device *dev) +{ + const struct adltc2990_config *cfg = dev->config; + + if (!i2c_is_ready_dt(&cfg->bus)) { + LOG_ERR("I2C bus %s not ready", cfg->bus.bus->name); + return -ENODEV; + } + + const uint8_t ctrl_reg_setting = cfg->temp_format << 7 | cfg->acq_format << 6 | 0 << 5 | + cfg->measurement_mode[1] << 3 | cfg->measurement_mode[0]; + + LOG_DBG("Setting Control Register to: 0x%x", ctrl_reg_setting); + int err = i2c_reg_write_byte_dt(&cfg->bus, ADLTC2990_REG_CONTROL, ctrl_reg_setting); + + if (err < 0) { + LOG_ERR("configuring for single bus failed: %d", err); + return err; + } + LOG_INF("Initializing ADLTC2990 with name %s", dev->name); + return 0; +} + +static int adltc2990_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct adltc2990_data *data = dev->data; + const struct adltc2990_config *cfg = dev->config; + enum adltc2990_monitoring_type mode_v1_v2 = adltc2990_get_v1_v2_measurement_modes( + cfg->measurement_mode[1], cfg->measurement_mode[0]); + enum adltc2990_monitoring_type mode_v3_v4 = adltc2990_get_v3_v4_measurement_modes( + cfg->measurement_mode[1], cfg->measurement_mode[0]); + + float voltage_divider_ratio; + + switch (chan) { + case SENSOR_CHAN_DIE_TEMP: { + data->internal_temperature = + adltc2990_get_property_value(dev, TEMPERATURE, INTERNAL_TEMPERATURE); + break; + } + case SENSOR_CHAN_CURRENT: { + if (!(mode_v1_v2 == VOLTAGE_DIFFERENTIAL || mode_v3_v4 == VOLTAGE_DIFFERENTIAL)) { + LOG_ERR("Sensor is not configured to measure Current"); + return -EINVAL; + } + if (mode_v1_v2 == VOLTAGE_DIFFERENTIAL) { + data->pins_v1_v2_values[0] = + (adltc2990_get_property_value(dev, VOLTAGE_DIFFERENTIAL, V1) * + ADLTC2990_MICROOHM_CONVERSION_FACTOR) / + cfg->pins_v1_v2.pins_current_resistor; + } + if (mode_v3_v4 == VOLTAGE_DIFFERENTIAL) { + data->pins_v3_v4_values[0] = + (adltc2990_get_property_value(dev, VOLTAGE_DIFFERENTIAL, V3) * + ADLTC2990_MICROOHM_CONVERSION_FACTOR) / + cfg->pins_v3_v4.pins_current_resistor; + } + break; + } + case SENSOR_CHAN_VOLTAGE: { + data->supply_voltage = + adltc2990_get_property_value(dev, VOLTAGE_SINGLEENDED, SUPPLY_VOLTAGE) + + 2500000; + + if (mode_v1_v2 == VOLTAGE_DIFFERENTIAL) { + data->pins_v1_v2_values[0] = + adltc2990_get_property_value(dev, VOLTAGE_DIFFERENTIAL, V1); + } else if (mode_v1_v2 == VOLTAGE_SINGLEENDED) { + uint32_t v1_r1 = + cfg->pins_v1_v2.voltage_divider_resistors.v1_r1_r2[0]; + uint32_t v1_r2 = + cfg->pins_v1_v2.voltage_divider_resistors.v2_r1_r2[1]; + voltage_divider_ratio = DIV_ROUND_CLOSEST(v1_r1 + v1_r2, v1_r2); + data->pins_v1_v2_values[0] = + adltc2990_get_property_value(dev, VOLTAGE_SINGLEENDED, V1) * + voltage_divider_ratio; + + uint32_t v2_r1 = + cfg->pins_v1_v2.voltage_divider_resistors.v2_r1_r2[0]; + uint32_t v2_r2 = + cfg->pins_v1_v2.voltage_divider_resistors.v2_r1_r2[1]; + voltage_divider_ratio = DIV_ROUND_CLOSEST(v2_r1 + v2_r2, v2_r2); + data->pins_v1_v2_values[1] = + adltc2990_get_property_value(dev, VOLTAGE_SINGLEENDED, V2) * + voltage_divider_ratio; + } + + if (mode_v3_v4 == VOLTAGE_DIFFERENTIAL) { + data->pins_v3_v4_values[0] = + adltc2990_get_property_value(dev, VOLTAGE_DIFFERENTIAL, V3); + } else if (mode_v3_v4 == VOLTAGE_SINGLEENDED) { + uint32_t v3_r1 = + cfg->pins_v3_v4.voltage_divider_resistors.v3_r1_r2[0]; + uint32_t v3_r2 = + cfg->pins_v3_v4.voltage_divider_resistors.v3_r1_r2[1]; + voltage_divider_ratio = DIV_ROUND_CLOSEST(v3_r1 + v3_r2, v3_r2); + data->pins_v3_v4_values[0] = + adltc2990_get_property_value(dev, VOLTAGE_SINGLEENDED, V3) * + voltage_divider_ratio; + + uint32_t v4_r1 = + cfg->pins_v3_v4.voltage_divider_resistors.v4_r1_r2[0]; + uint32_t v4_r2 = + cfg->pins_v3_v4.voltage_divider_resistors.v4_r1_r2[1]; + voltage_divider_ratio = DIV_ROUND_CLOSEST((v4_r1 + v4_r2), v4_r2); + data->pins_v3_v4_values[1] = + adltc2990_get_property_value(dev, VOLTAGE_SINGLEENDED, V4) * + voltage_divider_ratio; + } + break; + } + case SENSOR_CHAN_AMBIENT_TEMP: { + if (!(mode_v1_v2 == TEMPERATURE || mode_v3_v4 == TEMPERATURE)) { + LOG_ERR("Sensor is not configured to measure Ambient Temperature"); + return -EINVAL; + } + if (mode_v1_v2 == TEMPERATURE) { + data->pins_v1_v2_values[0] = + adltc2990_get_property_value(dev, TEMPERATURE, V1); + } + if (mode_v3_v4 == TEMPERATURE) { + data->pins_v3_v4_values[1] = + adltc2990_get_property_value(dev, TEMPERATURE, V3); + } + break; + } + case SENSOR_CHAN_ALL: { + if (adltc2990_is_busy(dev)) { + LOG_INF("ADLTC2990 conversion ongoing"); + return -EBUSY; + } + adltc2990_trigger_measurement(dev); + break; + } + default: { + LOG_ERR("does not measure channel: %d", chan); + return -ENOTSUP; + } + } + + return 0; +} + +static int adltc2990_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + if (val == NULL) { + LOG_ERR("Argument of type sensor_value* cannot be null "); + return -EINVAL; + } + struct adltc2990_data *data = dev->data; + const struct adltc2990_config *cfg = dev->config; + enum adltc2990_monitoring_type mode_v1_v2 = adltc2990_get_v1_v2_measurement_modes( + cfg->measurement_mode[1], cfg->measurement_mode[0]); + enum adltc2990_monitoring_type mode_v3_v4 = adltc2990_get_v3_v4_measurement_modes( + cfg->measurement_mode[1], cfg->measurement_mode[0]); + + uint8_t offset_index = 0, num_values_v1_v2 = 0, num_values_v3_v4 = 0; + + switch (chan) { + case SENSOR_CHAN_DIE_TEMP: { + val->val1 = data->internal_temperature / 10000; + val->val2 = data->internal_temperature % 10000; + LOG_DBG("Internal Temperature Value is:%d.%d", val->val1, val->val2); + break; + } + case SENSOR_CHAN_VOLTAGE: { + if (mode_v1_v2 == VOLTAGE_SINGLEENDED) { + LOG_DBG("Getting V1,V2"); + num_values_v1_v2 = ADLTC2990_VOLTAGE_SINGLE_ENDED_VALUES; + } else if (mode_v1_v2 == VOLTAGE_DIFFERENTIAL) { + LOG_DBG("Getting V3-V4"); + num_values_v1_v2 = ADLTC2990_VOLTAGE_DIFF_VALUES; + } + if (mode_v3_v4 == VOLTAGE_SINGLEENDED) { + LOG_DBG("Getting V3,V4"); + num_values_v3_v4 = ADLTC2990_VOLTAGE_SINGLE_ENDED_VALUES; + } else if (mode_v3_v4 == VOLTAGE_DIFFERENTIAL) { + LOG_DBG("Getting V3-V4"); + num_values_v3_v4 = ADLTC2990_VOLTAGE_DIFF_VALUES; + } + val[num_values_v1_v2 + num_values_v3_v4].val1 = data->supply_voltage / 1000000; + val[num_values_v1_v2 + num_values_v3_v4].val2 = data->supply_voltage % 1000000; + break; + } + case SENSOR_CHAN_CURRENT: { + if (!(mode_v1_v2 == VOLTAGE_DIFFERENTIAL || mode_v3_v4 == VOLTAGE_DIFFERENTIAL)) { + LOG_ERR("Sensor is not configured to measure Current"); + return -EINVAL; + } + if (mode_v1_v2 == VOLTAGE_DIFFERENTIAL && mode_v3_v4 == VOLTAGE_DIFFERENTIAL) { + LOG_DBG("Getting I12 and I34"); + num_values_v1_v2 = ADLTC2990_CURRENT_VALUES; + num_values_v3_v4 = ADLTC2990_CURRENT_VALUES; + } else if (mode_v1_v2 == VOLTAGE_DIFFERENTIAL) { + LOG_DBG("Getting I12"); + num_values_v1_v2 = ADLTC2990_CURRENT_VALUES; + } else if (mode_v3_v4 == VOLTAGE_DIFFERENTIAL) { + LOG_DBG("Getting I34"); + num_values_v3_v4 = ADLTC2990_CURRENT_VALUES; + } + break; + } + case SENSOR_CHAN_AMBIENT_TEMP: { + if (!(mode_v1_v2 == TEMPERATURE || mode_v3_v4 == TEMPERATURE)) { + LOG_ERR("Sensor is not configured to measure Ambient Temperature"); + return -EINVAL; + } + if (mode_v1_v2 == TEMPERATURE && mode_v3_v4 == TEMPERATURE) { + LOG_DBG("Getting T12 and T34"); + num_values_v1_v2 = ADLTC2990_TEMP_VALUES; + num_values_v3_v4 = ADLTC2990_TEMP_VALUES; + } else if (mode_v1_v2 == TEMPERATURE) { + LOG_DBG("Getting T12"); + num_values_v1_v2 = ADLTC2990_TEMP_VALUES; + } else if (mode_v3_v4 == TEMPERATURE) { + LOG_DBG("Getting T34"); + num_values_v3_v4 = ADLTC2990_TEMP_VALUES; + } + break; + } + default: { + return -ENOTSUP; + } + } + + adltc2990_get_v1_v2_val(dev, val, num_values_v1_v2, &offset_index); + adltc2990_get_v3_v4_val(dev, val, num_values_v3_v4, &offset_index); + return 0; +} + +static const struct sensor_driver_api adltc2990_driver_api = { + .sample_fetch = adltc2990_sample_fetch, + .channel_get = adltc2990_channel_get, +}; + +#define ADLTC2990_DEFINE(inst) \ + static struct adltc2990_data adltc2990_data_##inst; \ + static const struct adltc2990_config adltc2990_config_##inst = { \ + .bus = I2C_DT_SPEC_INST_GET(inst), \ + .temp_format = DT_INST_PROP(inst, temperature_format), \ + .acq_format = DT_INST_PROP(inst, acquistion_format), \ + .measurement_mode = DT_INST_PROP(inst, measurement_mode), \ + .pins_v1_v2.pins_current_resistor = \ + DT_INST_PROP_OR(inst, pins_v1_v2_current_resistor, 1), \ + .pins_v1_v2.voltage_divider_resistors.v1_r1_r2 = \ + DT_INST_PROP_OR(inst, pin_v1_voltage_divider_resistors, NULL), \ + .pins_v1_v2.voltage_divider_resistors.v2_r1_r2 = \ + DT_INST_PROP_OR(inst, pin_v2_voltage_divider_resistors, NULL), \ + .pins_v3_v4.pins_current_resistor = \ + DT_INST_PROP_OR(inst, pins_v3_v4_current_resistor, 1), \ + .pins_v3_v4.voltage_divider_resistors.v3_r1_r2 = \ + DT_INST_PROP_OR(inst, pin_v3_voltage_divider_resistors, NULL), \ + .pins_v3_v4.voltage_divider_resistors.v4_r1_r2 = \ + DT_INST_PROP_OR(inst, pin_v4_voltage_divider_resistors, NULL)}; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, adltc2990_init, NULL, &adltc2990_data_##inst, \ + &adltc2990_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &adltc2990_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(ADLTC2990_DEFINE) diff --git a/drivers/sensor/adltc2990/adltc2990.h b/drivers/sensor/adltc2990/adltc2990.h new file mode 100644 index 00000000000..f1c20d33b23 --- /dev/null +++ b/drivers/sensor/adltc2990/adltc2990.h @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2023 Carl Zeiss Meditec AG + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_ADLTC2990_H +#define ZEPHYR_DRIVERS_SENSOR_ADLTC2990_H + +#include +#include +#include +#include + +enum adltc2990_monitor_pins { + V1, + V2, + V3, + V4, + INTERNAL_TEMPERATURE, + SUPPLY_VOLTAGE +} adltc2990_monitor_pins; + +enum adltc2990_monitoring_type { + NOTHING, + VOLTAGE_DIFFERENTIAL, + VOLTAGE_SINGLEENDED, + TEMPERATURE +} adltc2990_monitoring_type; + +union voltage_divider_resistors { + struct { + uint32_t v1_r1_r2[2]; + uint32_t v2_r1_r2[2]; + }; + struct { + uint32_t v3_r1_r2[2]; + uint32_t v4_r1_r2[2]; + }; +}; + +struct pins_configuration { + uint32_t pins_current_resistor; + union voltage_divider_resistors voltage_divider_resistors; +}; + +struct adltc2990_data { + int32_t internal_temperature; + int32_t supply_voltage; + int32_t pins_v1_v2_values[2]; + int32_t pins_v3_v4_values[2]; +}; + +struct adltc2990_config { + struct i2c_dt_spec bus; + uint8_t temp_format; + uint8_t acq_format; + uint8_t measurement_mode[2]; + struct pins_configuration pins_v1_v2; + struct pins_configuration pins_v3_v4; +}; + +#endif /* ZEPHYR_DRIVERS_SENSOR_ADLTC2990_H */ diff --git a/drivers/sensor/adltc2990/adltc2990_reg.h b/drivers/sensor/adltc2990/adltc2990_reg.h new file mode 100644 index 00000000000..3b23b8b066f --- /dev/null +++ b/drivers/sensor/adltc2990/adltc2990_reg.h @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2023 Carl Zeiss Meditec AG + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_ADLTC2990_REG_H +#define ZEPHYR_DRIVERS_SENSOR_ADLTC2990_REG_H + +#define ADLTC2990_REG_STATUS 0x00U +#define ADLTC2990_REG_CONTROL 0x01U +#define ADLTC2990_REG_TRIGGER 0x02U +#define ADLTC2990_REG_UNUSED 0x03U +#define ADLTC2990_REG_INTERNAL_TEMP_MSB 0x04U +#define ADLTC2990_REG_INTERNAL_TEMP_LSB 0x05U +#define ADLTC2990_REG_V1_MSB 0x06U +#define ADLTC2990_REG_V1_LSB 0x07U +#define ADLTC2990_REG_V2_MSB 0x08U +#define ADLTC2990_REG_V2_LSB 0x09U +#define ADLTC2990_REG_V3_MSB 0x0AU +#define ADLTC2990_REG_V3_LSB 0x0BU +#define ADLTC2990_REG_V4_MSB 0x0CU +#define ADLTC2990_REG_V4_LSB 0x0DU +#define ADLTC2990_REG_VCC_MSB 0x0EU +#define ADLTC2990_REG_VCC_LSB 0x0FU + +#define ADLTC2990_VOLTAGE_SINGLE_ENDED_VALUES 2U +#define ADLTC2990_VOLTAGE_DIFF_VALUES 1U +#define ADLTC2990_TEMP_VALUES 1U +#define ADLTC2990_CURRENT_VALUES 1U +#define ADLTC2990_MICROOHM_CONVERSION_FACTOR 1000000U + +#define ADLTC2990_MODE_V1_V2_TR2 0U +#define ADLTC2990_MODE_V1_MINUS_V2_TR2 1U +#define ADLTC2990_MODE_V1_MINUS_V2_V3_V4 2U +#define ADLTC2990_MODE_TR1_V3_V4 3U +#define ADLTC2990_MODE_TR1_V3_MINUS_V4 4U +#define ADLTC2990_MODE_TR1_TR2 5U +#define ADLTC2990_MODE_V1_MINUS_V2_V3_MINUS_V4 6U +#define ADLTC2990_MODE_V1_V2_V3_V4 7U + +#define ADLTC2990_MEASURE_INTERNAL_TEMPERATURE_ONLY 0U +#define ADLTC2990_MEASURE_PINS_V1_V2_ONLY 1U +#define ADLTC2990_MEASURE_PINS_V3_V4_ONLY 2U +#define ADLTC2990_MEASURE_ALL_PINS_PER_MODE_2_0 3U + +#define ADLTC2990_VOLTAGE_SINGLEENDED_CONVERSION_FACTOR 30518 +#define ADLTC2990_VOLTAGE_DIFFERENTIAL_CONVERSION_FACTOR 1942 +#define ADLTC2990_TEMPERATURE_CONVERSION_FACTOR 62500 + +#define ADLTC2990_MODE_2_0_MAX_VALUE 7U +#define ADLTC2990_MODE_4_3_MAX_VALUE 3U + +#endif /* ZEPHYR_DRIVERS_SENSOR_ADLTC2990_REG_H */ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 9b04fc5226f..1409b74ea68 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -753,3 +753,15 @@ test_i2c_tsl2540: tsl2540@71 { reg = <0x71>; int-gpios = <&test_gpio 0 0>; }; + +test_i2c_adltc2990@72 { + compatible = "adi,adltc2990"; + reg = <0x72>; + status = "okay"; + measurement-mode = <7 3>; + pins-v1-v2-current-resistor = <1>; + pin-v1-voltage-divider-resistors = <100 10>; + pin-v2-voltage-divider-resistors = <100 10>; + pin-v3-voltage-divider-resistors = <100 100>; + pin-v4-voltage-divider-resistors = <0 1>; +};