From 516e5d61c6a4870658839d4dc0c89ac2a6536877 Mon Sep 17 00:00:00 2001 From: Jaakko Rautiainen Date: Mon, 12 Aug 2024 14:53:49 +0300 Subject: [PATCH] drivers: sensor: ti: tmp435: added driver for TMP435 The TMP435 is a remote temperature sensor monitor with a built-in local temperature sensor. Signed-off-by: Jaakko Rautiainen --- drivers/sensor/ti/CMakeLists.txt | 1 + drivers/sensor/ti/Kconfig | 1 + drivers/sensor/ti/tmp435/CMakeLists.txt | 7 + drivers/sensor/ti/tmp435/Kconfig | 11 ++ drivers/sensor/ti/tmp435/tmp435.c | 214 ++++++++++++++++++++++++ drivers/sensor/ti/tmp435/tmp435.h | 44 +++++ dts/bindings/sensor/ti,tmp435.yaml | 36 ++++ tests/drivers/build_all/sensor/i2c.dtsi | 9 +- 8 files changed, 322 insertions(+), 1 deletion(-) create mode 100644 drivers/sensor/ti/tmp435/CMakeLists.txt create mode 100644 drivers/sensor/ti/tmp435/Kconfig create mode 100644 drivers/sensor/ti/tmp435/tmp435.c create mode 100644 drivers/sensor/ti/tmp435/tmp435.h create mode 100644 dts/bindings/sensor/ti,tmp435.yaml diff --git a/drivers/sensor/ti/CMakeLists.txt b/drivers/sensor/ti/CMakeLists.txt index 452d0e8e37a..8a497df2948 100644 --- a/drivers/sensor/ti/CMakeLists.txt +++ b/drivers/sensor/ti/CMakeLists.txt @@ -20,4 +20,5 @@ add_subdirectory_ifdef(CONFIG_TMP108 tmp108) add_subdirectory_ifdef(CONFIG_TMP112 tmp112) add_subdirectory_ifdef(CONFIG_TMP114 tmp114) add_subdirectory_ifdef(CONFIG_TMP116 tmp116) +add_subdirectory_ifdef(CONFIG_TMP435 tmp435) # zephyr-keep-sorted-stop diff --git a/drivers/sensor/ti/Kconfig b/drivers/sensor/ti/Kconfig index f0655981a4c..7e9f0e95f29 100644 --- a/drivers/sensor/ti/Kconfig +++ b/drivers/sensor/ti/Kconfig @@ -20,4 +20,5 @@ source "drivers/sensor/ti/tmp108/Kconfig" source "drivers/sensor/ti/tmp112/Kconfig" source "drivers/sensor/ti/tmp114/Kconfig" source "drivers/sensor/ti/tmp116/Kconfig" +source "drivers/sensor/ti/tmp435/Kconfig" # zephyr-keep-sorted-stop diff --git a/drivers/sensor/ti/tmp435/CMakeLists.txt b/drivers/sensor/ti/tmp435/CMakeLists.txt new file mode 100644 index 00000000000..c84b5c95445 --- /dev/null +++ b/drivers/sensor/ti/tmp435/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2024 Bittium Corporation +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_library() + +zephyr_library_sources(tmp435.c) diff --git a/drivers/sensor/ti/tmp435/Kconfig b/drivers/sensor/ti/tmp435/Kconfig new file mode 100644 index 00000000000..dfbd455fcc5 --- /dev/null +++ b/drivers/sensor/ti/tmp435/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Bittium Corporation +# SPDX-License-Identifier: Apache-2.0 +# + +config TMP435 + bool "TMP435 temperature sensor" + default y + depends on DT_HAS_TI_TMP435_ENABLED + select I2C + help + Enable the driver for the TMP435 temperature sensor diff --git a/drivers/sensor/ti/tmp435/tmp435.c b/drivers/sensor/ti/tmp435/tmp435.c new file mode 100644 index 00000000000..54cda9f402f --- /dev/null +++ b/drivers/sensor/ti/tmp435/tmp435.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2024 Bittium Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_tmp435 + +#include +#include + +#include +#include +#include +#include +#include +#include "tmp435.h" + +LOG_MODULE_REGISTER(TMP435, CONFIG_SENSOR_LOG_LEVEL); + +static inline int tmp435_reg_read(const struct tmp435_config *cfg, uint8_t reg, uint8_t *buf, + uint32_t size) +{ + return i2c_burst_read_dt(&cfg->i2c, reg, buf, size); +} + +static inline int tmp435_reg_write(const struct tmp435_config *cfg, uint8_t reg, uint8_t *buf, + uint32_t size) +{ + return i2c_burst_write_dt(&cfg->i2c, reg, buf, size); +} + +static inline int tmp435_get_status(const struct tmp435_config *cfg, uint8_t *status) +{ + return tmp435_reg_read(cfg, TMP435_STATUS_REG, status, 1); +} + +static int tmp435_one_shot(const struct device *dev) +{ + uint8_t data = 0; + uint8_t status = 0; + int ret = 0; + const struct tmp435_config *cfg = dev->config; + + data = 1; /* write anything to start */ + ret = tmp435_reg_write(cfg, TMP435_ONE_SHOT_START_REG, &data, 1); + for (uint16_t i = 0; i < TMP435_CONV_LOOP_LIMIT; i++) { + ret = tmp435_get_status(cfg, &status); + if (ret < 0) { + LOG_DBG("Failed to read TMP435_STATUS_REG, ret:%d", ret); + } else { + if (status & TMP435_STATUS_REG_BUSY) { + /* conversion not ready */ + k_msleep(10); + } else { + LOG_DBG("conv over, loops:%d status:%x", i, status); + break; + } + } + } + return ret; +} + +static int tmp435_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + int ret = 0; + uint8_t value = 0; + int32_t temp = 0; + const struct tmp435_config *cfg = dev->config; + struct tmp435_data *data = dev->data; + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP && + chan != SENSOR_CHAN_AMBIENT_TEMP) { + return -ENOTSUP; + } + tmp435_one_shot(dev); /* start conversion */ + if ((chan == SENSOR_CHAN_ALL) || (chan == SENSOR_CHAN_DIE_TEMP)) { + ret = tmp435_reg_read(cfg, TMP435_LOCAL_TEMP_H_REG, &value, sizeof(value)); + if (ret < 0) { + LOG_ERR("Failed to read TMP435_LOCAL_TEMP_H_REG, ret:%d", ret); + return ret; + } + temp = value; + ret = tmp435_reg_read(cfg, TMP435_LOCAL_TEMP_L_REG, &value, sizeof(value)); + if (ret < 0) { + LOG_ERR("Failed to read TMP435_LOCAL_TEMP_L_REG, ret:%d", ret); + return ret; + } + if (value > TMP435_FRACTION_INC) { + temp++; + } + data->temp_die = temp + tmp435_temp_offset; + } + + if ((chan == SENSOR_CHAN_ALL) || (chan == SENSOR_CHAN_AMBIENT_TEMP)) { + if (!(cfg->external_channel)) { + return 0; /* not enabled, just return */ + } + ret = tmp435_reg_read(cfg, TMP435_REMOTE_TEMP_H_REG, &value, sizeof(value)); + if (ret < 0) { + LOG_ERR("Failed to read TMP435_REMOTE_TEMP_H_REG ret:%d", ret); + return ret; + } + temp = value; + ret = tmp435_reg_read(cfg, TMP435_REMOTE_TEMP_L_REG, &value, sizeof(value)); + if (ret < 0) { + LOG_ERR("Failed to read TMP435_REMOTE_TEMP_L_REG, ret:%d", ret); + return ret; + } + if (value > TMP435_FRACTION_INC) { + temp++; + } + data->temp_ambient = temp + tmp435_temp_offset; + } + return 0; +} + +static int tmp435_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + int ret = 0; + struct tmp435_data *data = dev->data; + const struct tmp435_config *cfg = dev->config; + + switch (chan) { + + case SENSOR_CHAN_DIE_TEMP: + val->val1 = data->temp_die; + val->val2 = 0; + break; + case SENSOR_CHAN_AMBIENT_TEMP: + if (cfg->external_channel) { + val->val1 = data->temp_ambient; + val->val2 = 0; + } else { + ret = -ENOTSUP; + } + break; + default: + ret = -ENOTSUP; + break; + } + return ret; +} + +static const struct sensor_driver_api tmp435_driver_api = { + .sample_fetch = tmp435_sample_fetch, + .channel_get = tmp435_channel_get, +}; + +static int tmp435_init(const struct device *dev) +{ + uint8_t data = 0; + int ret = 0; + const struct tmp435_config *cfg = dev->config; + + if (!(i2c_is_ready_dt(&cfg->i2c))) { + LOG_ERR("I2C dev not ready"); + return -ENODEV; + } + + data = 1; /* write anything to reset */ + ret = tmp435_reg_write(cfg, TMP435_SOFTWARE_RESET_REG, &data, 1); + if (ret < 0) { + LOG_ERR("Failed to write TMP435_SOFTWARE_RESET_REG ret:%d", ret); + return ret; + } + + data = TMP435_CONF_REG_1_DATA; + ret = tmp435_reg_write(cfg, TMP435_CONF_REG_1, &data, 1); + if (ret < 0) { + LOG_ERR("Failed to write TMP435_CONF_REG_1 ret:%d", ret); + return ret; + } + + data = TMP435_CONF_REG_2_DATA; + if (cfg->external_channel) { + data = data + TMP435_CONF_REG_2_REN; + } + if (cfg->resistance_correction) { + data = data + TMP435_CONF_REG_2_RC; + } + ret = tmp435_reg_write(cfg, TMP435_CONF_REG_2, &data, 1); + if (ret < 0) { + LOG_ERR("Failed to write TMP435_CONF_REG_2 ret:%d", ret); + return ret; + } + + data = cfg->beta_compensation; + ret = tmp435_reg_write(cfg, TMP435_BETA_RANGE_REG, &data, 1); + if (ret < 0) { + LOG_ERR("Failed to write TMP435_BETA_RANGE_REG ret:%d", ret); + return ret; + } + return 0; +} + +/* + * Device creation macros + */ + +#define TMP435_INST(inst) \ + static struct tmp435_data tmp435_data_##inst; \ + static const struct tmp435_config tmp435_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + .external_channel = DT_INST_PROP(inst, external_channel), \ + .resistance_correction = DT_INST_PROP(inst, resistance_correction), \ + .beta_compensation = DT_INST_PROP(inst, beta_compensation), \ + }; \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, tmp435_init, NULL, &tmp435_data_##inst, \ + &tmp435_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &tmp435_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(TMP435_INST) diff --git a/drivers/sensor/ti/tmp435/tmp435.h b/drivers/sensor/ti/tmp435/tmp435.h new file mode 100644 index 00000000000..f138e15f37b --- /dev/null +++ b/drivers/sensor/ti/tmp435/tmp435.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 Bittium Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_TMP435_H_ +#define ZEPHYR_DRIVERS_SENSOR_TMP435_H_ + +#define TMP435_CONF_REG_1 0x03 +#define TMP435_CONF_REG_1_DATA 0xc4 +/* [7]=1 ALERT Masked, [6]=1 Shut Down (one shot mode), [2]=1 −55 C to +150 C */ +#define TMP435_CONF_REG_2 0x1a +#define TMP435_CONF_REG_2_REN 0x10 /* [4]=1 External channel 1 enabled */ +#define TMP435_CONF_REG_2_RC 0x04 /* [2]=1 Resistance correction enabled */ +#define TMP435_CONF_REG_2_DATA 0x08 /* [3]=1 Local channel enabled */ +#define TMP435_BETA_RANGE_REG 0x25 +#define TMP435_STATUS_REG 0x02 +#define TMP435_STATUS_REG_BUSY 0x80 /* conv not ready */ +#define TMP435_SOFTWARE_RESET_REG 0xfc +#define TMP435_ONE_SHOT_START_REG 0x0f +#define TMP435_LOCAL_TEMP_H_REG 0x00 +#define TMP435_LOCAL_TEMP_L_REG 0x15 +#define TMP435_REMOTE_TEMP_H_REG 0x01 +#define TMP435_REMOTE_TEMP_L_REG 0x10 + +#define TMP435_CONV_LOOP_LIMIT 50 /* max 50*10 ms */ +#define TMP435_FRACTION_INC 0x80 /* 0.5000 */ + +static const int32_t tmp435_temp_offset = -64; + +struct tmp435_data { + int32_t temp_die; /* Celsius degrees */ + int32_t temp_ambient; /* Celsius degrees */ +}; + +struct tmp435_config { + struct i2c_dt_spec i2c; + bool external_channel; + bool resistance_correction; + uint8_t beta_compensation; +}; + +#endif /* ZEPHYR_DRIVERS_SENSOR_TMP435_H_ */ diff --git a/dts/bindings/sensor/ti,tmp435.yaml b/dts/bindings/sensor/ti,tmp435.yaml new file mode 100644 index 00000000000..5dc71b49f09 --- /dev/null +++ b/dts/bindings/sensor/ti,tmp435.yaml @@ -0,0 +1,36 @@ +# +# Copyright (c) 2024 Bittium Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: Texas Instruments TMP435 temperature sensor + +compatible: "ti,tmp435" + +bus: tmp435 + +include: [sensor-device.yaml, i2c-device.yaml] + +properties: + external-channel: + description: External temperature measurement is enabled + type: boolean + resistance-correction: + description: | + Resistance correction feature for the external + temperature channel. If not enabled then conversion + is faster but with lower accuracy. + type: boolean + beta-compensation: + description: | + Beta Compensation Configuration, see Table 8 + from TMP435 data sheet, some common values. + 0x0f, Automatically selected range 7 (beta > 27.0) or + Automatically detected diode connected sensor + 0x07, Manually disabled beta correction + Default is common value for general purpose transistors. + type: int + default: 0x0f + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 978f026b312..42ead34803b 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -1219,7 +1219,14 @@ test_i2c_tmag3001: tmag3001@a8 { status = "okay"; reg = <0xa8>; int-gpios = <&test_gpio 15 1>; - operation-mode = ; angle-magnitude-axis = ; }; + +test_i2c_tmp435: tmp435@a9 { + compatible = "ti,tmp435"; + reg = <0xa9>; + external-channel; + resistance-correction; + beta-compensation = <0x0f>; +};