drivers: sensors: Add driver for LM95234 temperature sensor

Add a driver for the National/TI LM95234 Quad Remote Diode and Local
Temperature Sensor with SMBus Interface and TruTherm Technology.

Signed-off-by: Robert Hancock <robert.hancock@calian.com>
This commit is contained in:
Robert Hancock 2024-01-31 15:12:39 -06:00 committed by Alberto Escolar
commit 2d171efcec
8 changed files with 376 additions and 0 deletions

View file

@ -8,6 +8,7 @@ add_subdirectory_ifdef(CONFIG_INA219 ina219)
add_subdirectory_ifdef(CONFIG_INA226 ina226)
add_subdirectory_ifdef(CONFIG_INA23X ina23x)
add_subdirectory_ifdef(CONFIG_INA3221 ina3221)
add_subdirectory_ifdef(CONFIG_LM95234 lm95234)
add_subdirectory_ifdef(CONFIG_OPT3001 opt3001)
add_subdirectory_ifdef(CONFIG_TI_HDC ti_hdc)
add_subdirectory_ifdef(CONFIG_TI_HDC20XX ti_hdc20xx)

View file

@ -8,6 +8,7 @@ source "drivers/sensor/ti/ina219/Kconfig"
source "drivers/sensor/ti/ina226/Kconfig"
source "drivers/sensor/ti/ina23x/Kconfig"
source "drivers/sensor/ti/ina3221/Kconfig"
source "drivers/sensor/ti/lm95234/Kconfig"
source "drivers/sensor/ti/opt3001/Kconfig"
source "drivers/sensor/ti/ti_hdc/Kconfig"
source "drivers/sensor/ti/ti_hdc20xx/Kconfig"

View file

@ -0,0 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_sources(lm95234.c)

View file

@ -0,0 +1,13 @@
# LM95234 temperature sensor config
# Copyright (c) 2024 Calian Advanced Technologies
# SPDX-License-Identifier: Apache-2.0
config LM95234
bool "LM95234 Temperature Sensor"
default y
depends on DT_HAS_NATIONAL_LM95234_ENABLED
select I2C
help
Enable the driver for the LM95234 Quad Remote Diode and Local
Temperature Sensor with SMBus Interface.

View file

@ -0,0 +1,322 @@
/*
* Copyright (c) 2024 Calian Advanced Technologies
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT national_lm95234
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/sensor/lm95234.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(LM95234, CONFIG_SENSOR_LOG_LEVEL);
#define LM95234_REG_LOCAL_TEMP_SIGNED_MSB 0x10
#define LM95234_REG_LOCAL_TEMP_SIGNED_LSB 0x20
#define LM95234_REG_REMOTE_TEMP_1_SIGNED_MSB 0x11
#define LM95234_REG_REMOTE_TEMP_1_SIGNED_LSB 0x21
#define LM95234_REG_REMOTE_TEMP_2_SIGNED_MSB 0x12
#define LM95234_REG_REMOTE_TEMP_2_SIGNED_LSB 0x22
#define LM95234_REG_REMOTE_TEMP_3_SIGNED_MSB 0x13
#define LM95234_REG_REMOTE_TEMP_3_SIGNED_LSB 0x23
#define LM95234_REG_REMOTE_TEMP_4_SIGNED_MSB 0x14
#define LM95234_REG_REMOTE_TEMP_4_SIGNED_LSB 0x24
#define LM95234_REG_REMOTE_TEMP_1_UNSIGNED_MSB 0x19
#define LM95234_REG_REMOTE_TEMP_1_UNSIGNED_LSB 0x29
#define LM95234_REG_REMOTE_TEMP_2_UNSIGNED_MSB 0x1a
#define LM95234_REG_REMOTE_TEMP_2_UNSIGNED_LSB 0x2a
#define LM95234_REG_REMOTE_TEMP_3_UNSIGNED_MSB 0x1b
#define LM95234_REG_REMOTE_TEMP_3_UNSIGNED_LSB 0x2b
#define LM95234_REG_REMOTE_TEMP_4_UNSIGNED_MSB 0x1c
#define LM95234_REG_REMOTE_TEMP_4_UNSIGNED_LSB 0x2c
#define LM95234_REG_DIODE_MODEL_SELECT 0x30
#define LM95234_REG_REMOTE_1_OFFSET 0x31
#define LM95234_REG_REMOTE_2_OFFSET 0x32
#define LM95234_REG_REMOTE_3_OFFSET 0x33
#define LM95234_REG_REMOTE_4_OFFSET 0x34
#define LM95234_REG_CONFIG 0x03
#define LM95234_REG_CONV_RATE 0x04
#define LM95234_REG_CHANNEL_CONV_ENABLE 0x05
#define LM95234_REG_FILTER_SETTING 0x06
#define LM95234_REG_ONESHOT 0x0f
#define LM95234_REG_COMMON_STATUS 0x02
#define LM95234_REG_STATUS_1 0x07
#define LM95234_REG_STATUS_2 0x08
#define LM95234_REG_STATUS_3 0x09
#define LM95234_REG_STATUS_4 0x0a
#define LM95234_REG_DIODE_MODEL_STATUS 0x38
#define LM95234_REG_TCRIT1_MASK 0x0c
#define LM95234_REG_TCRIT2_MASK 0x0d
#define LM95234_REG_TCRIT3_MASK 0x0e
#define LM95234_REG_LOCAL_TCRIT_LIMIT 0x40
#define LM95234_REG_REMOTE1_TCRIT1_LIMIT 0x41
#define LM95234_REG_REMOTE2_TCRIT1_LIMIT 0x42
#define LM95234_REG_REMOTE3_TCRIT_LIMIT 0x43
#define LM95234_REG_REMOTE4_TCRIT_LIMIT 0x44
#define LM95234_REG_REMOTE1_TCRIT23_LIMIT 0x49
#define LM95234_REG_REMOTE2_TCRIT23_LIMIT 0x4a
#define LM95234_REG_COMMON_TCRIT_HYSTERESIS 0x5a
#define LM95234_REG_MANUF_ID 0xfe
#define LM95234_REG_REV_ID 0xff
#define LM95234_MAN_ID 0x01
#define LM95234_CHIP_ID 0x79
#define LM95234_CONFIG_STANDBY BIT(6)
struct lm95234_data {
/** Temperatures in raw format read from sensor */
int32_t local;
int32_t remote[4];
};
struct lm95234_config {
struct i2c_dt_spec i2c;
};
static inline int lm95234_fetch_temp(const struct lm95234_config *cfg, struct lm95234_data *data,
enum sensor_channel chan, int32_t *output)
{
int ret;
uint8_t val;
int32_t result = 0;
if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
uint16_t temp;
int offset = (chan - SENSOR_CHAN_LM95234_REMOTE_TEMP_1);
ret = i2c_reg_read_byte_dt(&cfg->i2c,
LM95234_REG_REMOTE_TEMP_1_UNSIGNED_MSB + offset, &val);
if (ret) {
return ret;
}
temp = val << 8;
ret = i2c_reg_read_byte_dt(&cfg->i2c,
LM95234_REG_REMOTE_TEMP_1_UNSIGNED_LSB + offset, &val);
if (ret) {
return ret;
}
temp |= val;
result = temp;
}
/* Read signed temperature if unsigned temperature is 0, or for local sensor */
if (chan == SENSOR_CHAN_AMBIENT_TEMP || result == 0) {
int offset = chan == SENSOR_CHAN_AMBIENT_TEMP ? 0 :
(chan - SENSOR_CHAN_LM95234_REMOTE_TEMP_1 + 1);
int16_t temp;
ret = i2c_reg_read_byte_dt(&cfg->i2c,
LM95234_REG_LOCAL_TEMP_SIGNED_MSB + offset, &val);
if (ret) {
return ret;
}
temp = val << 8;
ret = i2c_reg_read_byte_dt(&cfg->i2c,
LM95234_REG_LOCAL_TEMP_SIGNED_LSB + offset, &val);
if (ret) {
return ret;
}
temp |= val;
result = temp;
}
*output = result;
return 0;
}
static int lm95234_sample_fetch(const struct device *dev,
enum sensor_channel chan)
{
struct lm95234_data *data = dev->data;
const struct lm95234_config *cfg = dev->config;
enum pm_device_state pm_state;
int ret;
(void)pm_device_state_get(dev, &pm_state);
if (pm_state != PM_DEVICE_STATE_ACTIVE) {
ret = -EIO;
return ret;
}
switch ((uint32_t)chan) {
case SENSOR_CHAN_ALL:
ret = lm95234_fetch_temp(cfg, data, SENSOR_CHAN_AMBIENT_TEMP, &data->local);
if (ret)
return ret;
for (int i = 0; i < ARRAY_SIZE(data->remote); i++) {
ret = lm95234_fetch_temp(cfg, data,
SENSOR_CHAN_LM95234_REMOTE_TEMP_1 + i,
&data->remote[i]);
if (ret)
return ret;
}
break;
case SENSOR_CHAN_AMBIENT_TEMP:
ret = lm95234_fetch_temp(cfg, data, chan, &data->local);
break;
case SENSOR_CHAN_LM95234_REMOTE_TEMP_1:
case SENSOR_CHAN_LM95234_REMOTE_TEMP_2:
case SENSOR_CHAN_LM95234_REMOTE_TEMP_3:
case SENSOR_CHAN_LM95234_REMOTE_TEMP_4:
ret = lm95234_fetch_temp(cfg, data, chan,
&data->remote[chan - SENSOR_CHAN_LM95234_REMOTE_TEMP_1]);
break;
default:
ret = -ENOTSUP;
break;
}
return ret;
}
static int lm95234_channel_get(const struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
struct lm95234_data *data = dev->data;
int32_t raw_temp;
switch ((uint32_t)chan) {
case SENSOR_CHAN_AMBIENT_TEMP:
raw_temp = data->local;
break;
case SENSOR_CHAN_LM95234_REMOTE_TEMP_1:
case SENSOR_CHAN_LM95234_REMOTE_TEMP_2:
case SENSOR_CHAN_LM95234_REMOTE_TEMP_3:
case SENSOR_CHAN_LM95234_REMOTE_TEMP_4:
raw_temp = data->remote[chan - SENSOR_CHAN_LM95234_REMOTE_TEMP_1];
break;
default:
return -ENOTSUP;
}
/* Raw data format is 8 bits integer, 5 bits fractional, 3 bits zero */
val->val1 = raw_temp / 256;
val->val2 = (raw_temp % 256) * 1000000 / 256;
return 0;
}
static const struct sensor_driver_api lm95234_driver_api = {
.sample_fetch = lm95234_sample_fetch,
.channel_get = lm95234_channel_get,
};
static int lm95234_init(const struct device *dev)
{
const struct lm95234_config *cfg = dev->config;
int ret = 0;
uint8_t value, model_select, model_status;
if (!i2c_is_ready_dt(&cfg->i2c)) {
LOG_ERR("I2C dev not ready");
return -ENODEV;
}
ret = i2c_reg_read_byte_dt(&cfg->i2c, LM95234_REG_MANUF_ID, &value);
if (ret) {
LOG_ERR("Could not read manufacturer ID: %d", ret);
return ret;
}
if (value != LM95234_MAN_ID) {
LOG_ERR("Invalid manufacturer ID: %02x", value);
return -ENODEV;
}
ret = i2c_reg_read_byte_dt(&cfg->i2c, LM95234_REG_REV_ID, &value);
if (ret) {
LOG_ERR("Could not read revision ID: %d", ret);
return ret;
}
if (value != LM95234_CHIP_ID) {
LOG_ERR("Invalid chip ID: %02x", value);
return -ENODEV;
}
ret = i2c_reg_read_byte_dt(&cfg->i2c, LM95234_REG_CONFIG, &value);
if (ret) {
LOG_ERR("Could not read config: %d", ret);
return ret;
}
if (value & LM95234_CONFIG_STANDBY) {
value &= ~LM95234_CONFIG_STANDBY;
ret = i2c_reg_write_byte_dt(&cfg->i2c, LM95234_REG_CONFIG, value);
if (ret) {
LOG_ERR("Could not write config: %d", ret);
return ret;
}
}
ret = i2c_reg_read_byte_dt(&cfg->i2c, LM95234_REG_DIODE_MODEL_SELECT, &model_select);
if (ret) {
LOG_ERR("Could not read diode model select: %d", ret);
return ret;
}
ret = i2c_reg_read_byte_dt(&cfg->i2c, LM95234_REG_DIODE_MODEL_STATUS, &model_status);
if (ret) {
LOG_ERR("Could not read diode model status: %d", ret);
return ret;
}
/**
* Check if any remote inputs have a 3904 transistor detected but are not configured
* as such. If so, configure them as 3904 transistors.
*/
if (model_select & model_status) {
model_select &= ~model_status;
ret = i2c_reg_write_byte_dt(&cfg->i2c, LM95234_REG_DIODE_MODEL_SELECT,
model_select);
if (ret) {
LOG_ERR("Could not write diode model select: %d", ret);
return ret;
}
}
#ifdef CONFIG_PM_DEVICE_RUNTIME
pm_device_init_suspended(dev);
ret = pm_device_runtime_enable(dev);
if (ret < 0 && ret != -ENOTSUP) {
LOG_ERR("Failed to enable runtime power management");
return ret;
}
#endif
return 0;
}
#ifdef CONFIG_PM_DEVICE
static int lm95234_pm_action(const struct device *dev, enum pm_device_action action)
{
switch (action) {
case PM_DEVICE_ACTION_TURN_ON:
case PM_DEVICE_ACTION_RESUME:
case PM_DEVICE_ACTION_TURN_OFF:
case PM_DEVICE_ACTION_SUSPEND:
break;
default:
return -ENOTSUP;
}
return 0;
}
#endif
#define LM95234_INST(inst) \
static struct lm95234_data lm95234_data_##inst; \
static const struct lm95234_config lm95234_config_##inst = { \
.i2c = I2C_DT_SPEC_INST_GET(inst), \
}; \
PM_DEVICE_DT_INST_DEFINE(inst, lm95234_pm_action); \
SENSOR_DEVICE_DT_INST_DEFINE(inst, lm95234_init, \
PM_DEVICE_DT_INST_GET(inst), \
&lm95234_data_##inst, \
&lm95234_config_##inst, \
POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, \
&lm95234_driver_api);
DT_INST_FOREACH_STATUS_OKAY(LM95234_INST)

View file

@ -0,0 +1,8 @@
# Copyright (c) 2024 Calian Advanced Technologies
# SPDX-License-Identifier: Apache-2.0
description: LM95234 Quad Remote Diode and Local Temperature Sensor with SMBus Interface
compatible: "national,lm95234"
include: [sensor-device.yaml, i2c-device.yaml]

View file

@ -0,0 +1,20 @@
/*
* Copyright (c) 2024, Calian Advanced Technologies
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_LM95234_H_
#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_LM95234_H_
#include <zephyr/drivers/sensor.h>
enum sensor_channel_lm95234 {
/* External temperature inputs */
SENSOR_CHAN_LM95234_REMOTE_TEMP_1 = SENSOR_CHAN_PRIV_START,
SENSOR_CHAN_LM95234_REMOTE_TEMP_2,
SENSOR_CHAN_LM95234_REMOTE_TEMP_3,
SENSOR_CHAN_LM95234_REMOTE_TEMP_4
};
#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_LM95234_H_ */

View file

@ -1055,3 +1055,9 @@ test_i2c_shtc1: shtc1@8e {
measure-mode = "low-power";
clock-stretching;
};
test_i2c_lm95234: lm95234@8f {
compatible = "national,lm95234";
reg = <0x8f>;
status = "okay";
};