Skip to content

drivers: sensor: tmp11x: add trigger function for alert #93313

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/sensor/ti/tmp11x/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
zephyr_library()

zephyr_library_sources(tmp11x.c)
zephyr_library_sources_ifdef(CONFIG_TMP11X_TRIGGER tmp11x_trigger.c)
9 changes: 9 additions & 0 deletions drivers/sensor/ti/tmp11x/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,12 @@ config TMP11X
select I2C
help
Enable driver for TMP116, TMP117 and TMP119 temperature sensors.

if TMP11X

module = TMP11X
thread_priority = 10
thread_stack_size = 1024
source "drivers/sensor/Kconfig.trigger_template"

endif
181 changes: 164 additions & 17 deletions drivers/sensor/ti/tmp11x/tmp11x.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <zephyr/device.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/pm/device.h>
#include <zephyr/drivers/sensor/tmp11x.h>
#include <zephyr/dt-bindings/sensor/tmp11x.h>
#include <zephyr/sys/util.h>
Expand All @@ -25,8 +26,7 @@

LOG_MODULE_REGISTER(TMP11X, CONFIG_SENSOR_LOG_LEVEL);

static int tmp11x_reg_read(const struct device *dev, uint8_t reg,
uint16_t *val)
int tmp11x_reg_read(const struct device *dev, uint8_t reg, uint16_t *val)
{
const struct tmp11x_dev_config *cfg = dev->config;

Expand All @@ -40,8 +40,7 @@ static int tmp11x_reg_read(const struct device *dev, uint8_t reg,
return 0;
}

static int tmp11x_reg_write(const struct device *dev, uint8_t reg,
uint16_t val)
int tmp11x_reg_write(const struct device *dev, uint8_t reg, uint16_t val)
{
const struct tmp11x_dev_config *cfg = dev->config;
uint8_t tx_buf[3] = {reg, val >> 8, val & 0xFF};
Expand Down Expand Up @@ -71,6 +70,31 @@ static inline bool tmp11x_is_offset_supported(const struct tmp11x_data *drv_data
return drv_data->id == TMP117_DEVICE_ID || drv_data->id == TMP119_DEVICE_ID;
}

/**
* @brief Convert sensor_value temperature to TMP11X register format
*
* This function converts a temperature from sensor_value format (val1 in degrees C,
* val2 in micro-degrees C) to the TMP11X register format. It uses 64-bit arithmetic
* to prevent overflow and clamps the result to the valid int16_t range.
*
* @param val Pointer to sensor_value containing temperature
* @return Temperature value in TMP11X register format (int16_t)
*/
static inline int16_t tmp11x_sensor_value_to_reg_format(const struct sensor_value *val)
{
int64_t temp_micro = ((int64_t)val->val1 * 1000000) + val->val2;
int64_t temp_scaled = (temp_micro * 10) / TMP11X_RESOLUTION;

/* Clamp to int16_t range */
if (temp_scaled > INT16_MAX) {
return INT16_MAX;
} else if (temp_scaled < INT16_MIN) {
return INT16_MIN;
} else {
return (int16_t)temp_scaled;
}
}

static bool check_eeprom_bounds(const struct device *dev, off_t offset,
size_t len)
{
Expand Down Expand Up @@ -310,8 +334,7 @@ static int tmp11x_attr_set(const struct device *dev,
/*
* The offset is encoded into the temperature register format.
*/
value = (((val->val1) * 10000000) + ((val->val2) * 10))
/ (int32_t)TMP11X_RESOLUTION;
value = tmp11x_sensor_value_to_reg_format(val);

return tmp11x_reg_write(dev, TMP117_REG_TEMP_OFFSET, value);

Expand Down Expand Up @@ -347,6 +370,41 @@ static int tmp11x_attr_set(const struct device *dev,
case SENSOR_ATTR_TMP11X_ONE_SHOT_MODE:
return tmp11x_write_config(dev, TMP11X_CFGR_MODE, TMP11X_MODE_ONE_SHOT);

#ifdef CONFIG_TMP11X_TRIGGER
case SENSOR_ATTR_TMP11X_ALERT_PIN_POLARITY:
if (val->val1 == TMP11X_ALERT_PIN_ACTIVE_HIGH) {
return tmp11x_write_config(dev, TMP11X_CFGR_ALERT_PIN_POL,
TMP11X_CFGR_ALERT_PIN_POL);
} else {
return tmp11x_write_config(dev, TMP11X_CFGR_ALERT_PIN_POL, 0);
}

case SENSOR_ATTR_TMP11X_ALERT_MODE:
if (val->val1 == TMP11X_ALERT_THERM_MODE) {
return tmp11x_write_config(dev, TMP11X_CFGR_ALERT_MODE,
TMP11X_CFGR_ALERT_MODE);
} else {
return tmp11x_write_config(dev, TMP11X_CFGR_ALERT_MODE, 0);
}

case SENSOR_ATTR_UPPER_THRESH:
/* Convert temperature to register format */
value = tmp11x_sensor_value_to_reg_format(val);
return tmp11x_reg_write(dev, TMP11X_REG_HIGH_LIM, value);

case SENSOR_ATTR_LOWER_THRESH:
/* Convert temperature to register format */
value = tmp11x_sensor_value_to_reg_format(val);
return tmp11x_reg_write(dev, TMP11X_REG_LOW_LIM, value);
case SENSOR_ATTR_TMP11X_ALERT_PIN_SELECT:
if (val->val1 == TMP11X_ALERT_PIN_ALERT_SEL) {
return tmp11x_write_config(dev, TMP11X_CFGR_ALERT_DR_SEL, 0);
} else {
return tmp11x_write_config(dev, TMP11X_CFGR_ALERT_DR_SEL,
TMP11X_CFGR_ALERT_DR_SEL);
}
#endif /* CONFIG_TMP11X_TRIGGER */

default:
return -ENOTSUP;
}
Expand Down Expand Up @@ -385,6 +443,25 @@ static int tmp11x_attr_get(const struct device *dev, enum sensor_channel chan,
}

return rc;

#ifdef CONFIG_TMP11X_TRIGGER
case SENSOR_ATTR_UPPER_THRESH:
rc = tmp11x_reg_read(dev, TMP11X_REG_HIGH_LIM, &data);
if (rc == 0) {
tmp11x_temperature_to_sensor_value(data, val);
}

return rc;

case SENSOR_ATTR_LOWER_THRESH:
rc = tmp11x_reg_read(dev, TMP11X_REG_LOW_LIM, &data);
if (rc == 0) {
tmp11x_temperature_to_sensor_value(data, val);
}

return rc;
#endif /* CONFIG_TMP11X_TRIGGER */

default:
return -ENOTSUP;
}
Expand All @@ -394,7 +471,10 @@ static DEVICE_API(sensor, tmp11x_driver_api) = {
.attr_set = tmp11x_attr_set,
.attr_get = tmp11x_attr_get,
.sample_fetch = tmp11x_sample_fetch,
.channel_get = tmp11x_channel_get
.channel_get = tmp11x_channel_get,
#ifdef CONFIG_TMP11X_TRIGGER
.trigger_set = tmp11x_trigger_set,
#endif
};

static int tmp11x_init(const struct device *dev)
Expand Down Expand Up @@ -423,19 +503,86 @@ static int tmp11x_init(const struct device *dev)
}

rc = tmp11x_write_config(dev, TMP11X_CFGR_AVG, cfg->oversampling);
if (rc < 0) {
return rc;
}

int8_t value = cfg->alert_pin_polarity ? TMP11X_CFGR_ALERT_PIN_POL : 0;

rc = tmp11x_write_config(dev, TMP11X_CFGR_ALERT_PIN_POL, value);
if (rc < 0) {
return rc;
}

value = cfg->alert_mode ? TMP11X_CFGR_ALERT_MODE : 0;
rc = tmp11x_write_config(dev, TMP11X_CFGR_ALERT_MODE, value);
if (rc < 0) {
return rc;
}

value = cfg->alert_dr_sel ? TMP11X_CFGR_ALERT_DR_SEL : 0;
rc = tmp11x_write_config(dev, TMP11X_CFGR_ALERT_DR_SEL, value);
if (rc < 0) {
return rc;
}

#ifdef CONFIG_TMP11X_TRIGGER
drv_data->dev = dev;
rc = tmp11x_init_interrupt(dev);
if (rc < 0) {
LOG_ERR("%s: Failed to initialize alert pin", dev->name);
return rc;
}
#endif /* CONFIG_TMP11X_TRIGGER */

return rc;
}

#define DEFINE_TMP11X(_num) \
static struct tmp11x_data tmp11x_data_##_num; \
static const struct tmp11x_dev_config tmp11x_config_##_num = { \
.bus = I2C_DT_SPEC_INST_GET(_num), \
.odr = DT_INST_PROP(_num, odr), \
.oversampling = DT_INST_PROP(_num, oversampling), \
}; \
SENSOR_DEVICE_DT_INST_DEFINE(_num, tmp11x_init, NULL, \
&tmp11x_data_##_num, &tmp11x_config_##_num, POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, &tmp11x_driver_api);
#ifdef CONFIG_PM_DEVICE
BUILD_ASSERT(!DT_INST_NODE_HAS_PROP(_num, power_domains), "Driver does not support power domain");
static int tmp11x_pm_control(const struct device *dev, enum pm_device_action action)
{
int ret = 0;

switch (action) {
case PM_DEVICE_ACTION_RESUME: {
const struct tmp11x_dev_config *cfg = dev->config;

ret = tmp11x_write_config(dev, TMP11X_CFGR_CONV, cfg->odr);
if (ret < 0) {
LOG_ERR("Failed to resume TMP11X");
}
break;
}
case PM_DEVICE_ACTION_SUSPEND: {
ret = tmp11x_write_config(dev, TMP11X_CFGR_MODE, TMP11X_MODE_SHUTDOWN);
if (ret < 0) {
LOG_ERR("Failed to suspend TMP11X");
}
break;
}
default:
ret = -ENOTSUP;
}

return ret;
}
#endif /* CONFIG_PM_DEVICE */

#define DEFINE_TMP11X(_num) \
static struct tmp11x_data tmp11x_data_##_num; \
static const struct tmp11x_dev_config tmp11x_config_##_num = { \
.bus = I2C_DT_SPEC_INST_GET(_num), \
.odr = DT_INST_PROP(_num, odr), \
.oversampling = DT_INST_PROP(_num, oversampling), \
.alert_pin_polarity = DT_INST_PROP(_num, alert_polarity), \
.alert_mode = DT_INST_PROP(_num, alert_mode), \
.alert_dr_sel = DT_INST_PROP(_num, alert_dr_sel), \
IF_ENABLED(CONFIG_TMP11X_TRIGGER, \
(.alert_gpio = GPIO_DT_SPEC_INST_GET_OR(_num, alert_gpios, {}),)) }; \
PM_DEVICE_DT_INST_DEFINE(_num, tmp11x_pm_control); \
SENSOR_DEVICE_DT_INST_DEFINE(_num, tmp11x_init, PM_DEVICE_DT_INST_GET(_num), \
&tmp11x_data_##_num, &tmp11x_config_##_num, POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, &tmp11x_driver_api);

DT_INST_FOREACH_STATUS_OKAY(DEFINE_TMP11X)
37 changes: 37 additions & 0 deletions drivers/sensor/ti/tmp11x/tmp11x.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#define ZEPHYR_DRIVERS_SENSOR_TMP11X_TMP11X_H_

#include <zephyr/sys/util_macro.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/i2c.h>

#define TMP11X_REG_TEMP 0x0
#define TMP11X_REG_CFGR 0x1
Expand Down Expand Up @@ -35,6 +37,11 @@
#define TMP11X_EEPROM_UL_UNLOCK BIT(15)
#define TMP11X_EEPROM_UL_BUSY BIT(14)

/* Alert pin configuration bits */
#define TMP11X_CFGR_ALERT_DR_SEL BIT(2) /* ALERT pin select (1=Data ready) (0=alert) */
#define TMP11X_CFGR_ALERT_PIN_POL BIT(3) /* Alert pin polarity */
#define TMP11X_CFGR_ALERT_MODE BIT(4) /* Alert pin mode (1=therm, 0=alert) */

#define TMP11X_AVG_1_SAMPLE 0
#define TMP11X_AVG_8_SAMPLES BIT(5)
#define TMP11X_AVG_32_SAMPLES BIT(6)
Expand All @@ -46,12 +53,42 @@
struct tmp11x_data {
uint16_t sample;
uint16_t id;
#ifdef CONFIG_TMP11X_TRIGGER
const struct device *dev;
struct gpio_callback alert_cb;
sensor_trigger_handler_t alert_handler;
const struct sensor_trigger *alert_trigger;

#if defined(CONFIG_TMP11X_TRIGGER_OWN_THREAD)
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_TMP11X_THREAD_STACK_SIZE);
struct k_thread thread;
struct k_sem gpio_sem;
#elif defined(CONFIG_TMP11X_TRIGGER_GLOBAL_THREAD)
struct k_work work;
#endif /* CONFIG_TMP11X_TRIGGER_OWN_THREAD */
#endif /* CONFIG_TMP11X_TRIGGER */
};

struct tmp11x_dev_config {
struct i2c_dt_spec bus;
uint16_t odr;
uint16_t oversampling;
bool alert_pin_polarity;
bool alert_mode;
bool alert_dr_sel;
#ifdef CONFIG_TMP11X_TRIGGER
struct gpio_dt_spec alert_gpio;
#endif
};

/* Function declarations */
int tmp11x_write_config(const struct device *dev, uint16_t mask, uint16_t conf);
int tmp11x_reg_read(const struct device *dev, uint8_t reg, uint16_t *val);

#ifdef CONFIG_TMP11X_TRIGGER
int tmp11x_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
sensor_trigger_handler_t handler);
int tmp11x_init_interrupt(const struct device *dev);
#endif

#endif /* ZEPHYR_DRIVERS_SENSOR_TMP11X_TMP11X_H_ */
Loading