Skip to content

Commit ceadedf

Browse files
tobiwan88cfriedt
authored andcommitted
drivers: sensor: tmp11x: add trigger for alert and pm
Allows to configure the alert or therm mode for triggers based on the low/high temperature treshholds Also adding simple PM Signed-off-by: Tobias Meyer <[email protected]>
1 parent afa529e commit ceadedf

File tree

11 files changed

+424
-18
lines changed

11 files changed

+424
-18
lines changed

drivers/sensor/ti/tmp11x/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
zephyr_library()
44

55
zephyr_library_sources(tmp11x.c)
6+
zephyr_library_sources_ifdef(CONFIG_TMP11X_TRIGGER tmp11x_trigger.c)

drivers/sensor/ti/tmp11x/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,12 @@ config TMP11X
1010
select I2C
1111
help
1212
Enable driver for TMP116, TMP117 and TMP119 temperature sensors.
13+
14+
if TMP11X
15+
16+
module = TMP11X
17+
thread_priority = 10
18+
thread_stack_size = 1024
19+
source "drivers/sensor/Kconfig.trigger_template"
20+
21+
endif

drivers/sensor/ti/tmp11x/tmp11x.c

Lines changed: 164 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <zephyr/device.h>
1010
#include <zephyr/drivers/i2c.h>
1111
#include <zephyr/drivers/sensor.h>
12+
#include <zephyr/pm/device.h>
1213
#include <zephyr/drivers/sensor/tmp11x.h>
1314
#include <zephyr/dt-bindings/sensor/tmp11x.h>
1415
#include <zephyr/sys/util.h>
@@ -25,8 +26,7 @@
2526

2627
LOG_MODULE_REGISTER(TMP11X, CONFIG_SENSOR_LOG_LEVEL);
2728

28-
static int tmp11x_reg_read(const struct device *dev, uint8_t reg,
29-
uint16_t *val)
29+
int tmp11x_reg_read(const struct device *dev, uint8_t reg, uint16_t *val)
3030
{
3131
const struct tmp11x_dev_config *cfg = dev->config;
3232

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

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

73+
/**
74+
* @brief Convert sensor_value temperature to TMP11X register format
75+
*
76+
* This function converts a temperature from sensor_value format (val1 in degrees C,
77+
* val2 in micro-degrees C) to the TMP11X register format. It uses 64-bit arithmetic
78+
* to prevent overflow and clamps the result to the valid int16_t range.
79+
*
80+
* @param val Pointer to sensor_value containing temperature
81+
* @return Temperature value in TMP11X register format (int16_t)
82+
*/
83+
static inline int16_t tmp11x_sensor_value_to_reg_format(const struct sensor_value *val)
84+
{
85+
int64_t temp_micro = ((int64_t)val->val1 * 1000000) + val->val2;
86+
int64_t temp_scaled = (temp_micro * 10) / TMP11X_RESOLUTION;
87+
88+
/* Clamp to int16_t range */
89+
if (temp_scaled > INT16_MAX) {
90+
return INT16_MAX;
91+
} else if (temp_scaled < INT16_MIN) {
92+
return INT16_MIN;
93+
} else {
94+
return (int16_t)temp_scaled;
95+
}
96+
}
97+
7498
static bool check_eeprom_bounds(const struct device *dev, off_t offset,
7599
size_t len)
76100
{
@@ -310,8 +334,7 @@ static int tmp11x_attr_set(const struct device *dev,
310334
/*
311335
* The offset is encoded into the temperature register format.
312336
*/
313-
value = (((val->val1) * 10000000) + ((val->val2) * 10))
314-
/ (int32_t)TMP11X_RESOLUTION;
337+
value = tmp11x_sensor_value_to_reg_format(val);
315338

316339
return tmp11x_reg_write(dev, TMP117_REG_TEMP_OFFSET, value);
317340

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

373+
#ifdef CONFIG_TMP11X_TRIGGER
374+
case SENSOR_ATTR_TMP11X_ALERT_PIN_POLARITY:
375+
if (val->val1 == TMP11X_ALERT_PIN_ACTIVE_HIGH) {
376+
return tmp11x_write_config(dev, TMP11X_CFGR_ALERT_PIN_POL,
377+
TMP11X_CFGR_ALERT_PIN_POL);
378+
} else {
379+
return tmp11x_write_config(dev, TMP11X_CFGR_ALERT_PIN_POL, 0);
380+
}
381+
382+
case SENSOR_ATTR_TMP11X_ALERT_MODE:
383+
if (val->val1 == TMP11X_ALERT_THERM_MODE) {
384+
return tmp11x_write_config(dev, TMP11X_CFGR_ALERT_MODE,
385+
TMP11X_CFGR_ALERT_MODE);
386+
} else {
387+
return tmp11x_write_config(dev, TMP11X_CFGR_ALERT_MODE, 0);
388+
}
389+
390+
case SENSOR_ATTR_UPPER_THRESH:
391+
/* Convert temperature to register format */
392+
value = tmp11x_sensor_value_to_reg_format(val);
393+
return tmp11x_reg_write(dev, TMP11X_REG_HIGH_LIM, value);
394+
395+
case SENSOR_ATTR_LOWER_THRESH:
396+
/* Convert temperature to register format */
397+
value = tmp11x_sensor_value_to_reg_format(val);
398+
return tmp11x_reg_write(dev, TMP11X_REG_LOW_LIM, value);
399+
case SENSOR_ATTR_TMP11X_ALERT_PIN_SELECT:
400+
if (val->val1 == TMP11X_ALERT_PIN_ALERT_SEL) {
401+
return tmp11x_write_config(dev, TMP11X_CFGR_ALERT_DR_SEL, 0);
402+
} else {
403+
return tmp11x_write_config(dev, TMP11X_CFGR_ALERT_DR_SEL,
404+
TMP11X_CFGR_ALERT_DR_SEL);
405+
}
406+
#endif /* CONFIG_TMP11X_TRIGGER */
407+
350408
default:
351409
return -ENOTSUP;
352410
}
@@ -385,6 +443,25 @@ static int tmp11x_attr_get(const struct device *dev, enum sensor_channel chan,
385443
}
386444

387445
return rc;
446+
447+
#ifdef CONFIG_TMP11X_TRIGGER
448+
case SENSOR_ATTR_UPPER_THRESH:
449+
rc = tmp11x_reg_read(dev, TMP11X_REG_HIGH_LIM, &data);
450+
if (rc == 0) {
451+
tmp11x_temperature_to_sensor_value(data, val);
452+
}
453+
454+
return rc;
455+
456+
case SENSOR_ATTR_LOWER_THRESH:
457+
rc = tmp11x_reg_read(dev, TMP11X_REG_LOW_LIM, &data);
458+
if (rc == 0) {
459+
tmp11x_temperature_to_sensor_value(data, val);
460+
}
461+
462+
return rc;
463+
#endif /* CONFIG_TMP11X_TRIGGER */
464+
388465
default:
389466
return -ENOTSUP;
390467
}
@@ -394,7 +471,10 @@ static DEVICE_API(sensor, tmp11x_driver_api) = {
394471
.attr_set = tmp11x_attr_set,
395472
.attr_get = tmp11x_attr_get,
396473
.sample_fetch = tmp11x_sample_fetch,
397-
.channel_get = tmp11x_channel_get
474+
.channel_get = tmp11x_channel_get,
475+
#ifdef CONFIG_TMP11X_TRIGGER
476+
.trigger_set = tmp11x_trigger_set,
477+
#endif
398478
};
399479

400480
static int tmp11x_init(const struct device *dev)
@@ -423,19 +503,86 @@ static int tmp11x_init(const struct device *dev)
423503
}
424504

425505
rc = tmp11x_write_config(dev, TMP11X_CFGR_AVG, cfg->oversampling);
506+
if (rc < 0) {
507+
return rc;
508+
}
509+
510+
int8_t value = cfg->alert_pin_polarity ? TMP11X_CFGR_ALERT_PIN_POL : 0;
511+
512+
rc = tmp11x_write_config(dev, TMP11X_CFGR_ALERT_PIN_POL, value);
513+
if (rc < 0) {
514+
return rc;
515+
}
516+
517+
value = cfg->alert_mode ? TMP11X_CFGR_ALERT_MODE : 0;
518+
rc = tmp11x_write_config(dev, TMP11X_CFGR_ALERT_MODE, value);
519+
if (rc < 0) {
520+
return rc;
521+
}
522+
523+
value = cfg->alert_dr_sel ? TMP11X_CFGR_ALERT_DR_SEL : 0;
524+
rc = tmp11x_write_config(dev, TMP11X_CFGR_ALERT_DR_SEL, value);
525+
if (rc < 0) {
526+
return rc;
527+
}
528+
529+
#ifdef CONFIG_TMP11X_TRIGGER
530+
drv_data->dev = dev;
531+
rc = tmp11x_init_interrupt(dev);
532+
if (rc < 0) {
533+
LOG_ERR("%s: Failed to initialize alert pin", dev->name);
534+
return rc;
535+
}
536+
#endif /* CONFIG_TMP11X_TRIGGER */
426537

427538
return rc;
428539
}
429540

430-
#define DEFINE_TMP11X(_num) \
431-
static struct tmp11x_data tmp11x_data_##_num; \
432-
static const struct tmp11x_dev_config tmp11x_config_##_num = { \
433-
.bus = I2C_DT_SPEC_INST_GET(_num), \
434-
.odr = DT_INST_PROP(_num, odr), \
435-
.oversampling = DT_INST_PROP(_num, oversampling), \
436-
}; \
437-
SENSOR_DEVICE_DT_INST_DEFINE(_num, tmp11x_init, NULL, \
438-
&tmp11x_data_##_num, &tmp11x_config_##_num, POST_KERNEL, \
439-
CONFIG_SENSOR_INIT_PRIORITY, &tmp11x_driver_api);
541+
#ifdef CONFIG_PM_DEVICE
542+
BUILD_ASSERT(!DT_INST_NODE_HAS_PROP(_num, power_domains), "Driver does not support power domain");
543+
static int tmp11x_pm_control(const struct device *dev, enum pm_device_action action)
544+
{
545+
int ret = 0;
546+
547+
switch (action) {
548+
case PM_DEVICE_ACTION_RESUME: {
549+
const struct tmp11x_dev_config *cfg = dev->config;
550+
551+
ret = tmp11x_write_config(dev, TMP11X_CFGR_CONV, cfg->odr);
552+
if (ret < 0) {
553+
LOG_ERR("Failed to resume TMP11X");
554+
}
555+
break;
556+
}
557+
case PM_DEVICE_ACTION_SUSPEND: {
558+
ret = tmp11x_write_config(dev, TMP11X_CFGR_MODE, TMP11X_MODE_SHUTDOWN);
559+
if (ret < 0) {
560+
LOG_ERR("Failed to suspend TMP11X");
561+
}
562+
break;
563+
}
564+
default:
565+
ret = -ENOTSUP;
566+
}
567+
568+
return ret;
569+
}
570+
#endif /* CONFIG_PM_DEVICE */
571+
572+
#define DEFINE_TMP11X(_num) \
573+
static struct tmp11x_data tmp11x_data_##_num; \
574+
static const struct tmp11x_dev_config tmp11x_config_##_num = { \
575+
.bus = I2C_DT_SPEC_INST_GET(_num), \
576+
.odr = DT_INST_PROP(_num, odr), \
577+
.oversampling = DT_INST_PROP(_num, oversampling), \
578+
.alert_pin_polarity = DT_INST_PROP(_num, alert_polarity), \
579+
.alert_mode = DT_INST_PROP(_num, alert_mode), \
580+
.alert_dr_sel = DT_INST_PROP(_num, alert_dr_sel), \
581+
IF_ENABLED(CONFIG_TMP11X_TRIGGER, \
582+
(.alert_gpio = GPIO_DT_SPEC_INST_GET_OR(_num, alert_gpios, {}),)) }; \
583+
PM_DEVICE_DT_INST_DEFINE(_num, tmp11x_pm_control); \
584+
SENSOR_DEVICE_DT_INST_DEFINE(_num, tmp11x_init, PM_DEVICE_DT_INST_GET(_num), \
585+
&tmp11x_data_##_num, &tmp11x_config_##_num, POST_KERNEL, \
586+
CONFIG_SENSOR_INIT_PRIORITY, &tmp11x_driver_api);
440587

441588
DT_INST_FOREACH_STATUS_OKAY(DEFINE_TMP11X)

drivers/sensor/ti/tmp11x/tmp11x.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#define ZEPHYR_DRIVERS_SENSOR_TMP11X_TMP11X_H_
99

1010
#include <zephyr/sys/util_macro.h>
11+
#include <zephyr/drivers/gpio.h>
12+
#include <zephyr/drivers/i2c.h>
1113

1214
#define TMP11X_REG_TEMP 0x0
1315
#define TMP11X_REG_CFGR 0x1
@@ -35,6 +37,11 @@
3537
#define TMP11X_EEPROM_UL_UNLOCK BIT(15)
3638
#define TMP11X_EEPROM_UL_BUSY BIT(14)
3739

40+
/* Alert pin configuration bits */
41+
#define TMP11X_CFGR_ALERT_DR_SEL BIT(2) /* ALERT pin select (1=Data ready) (0=alert) */
42+
#define TMP11X_CFGR_ALERT_PIN_POL BIT(3) /* Alert pin polarity */
43+
#define TMP11X_CFGR_ALERT_MODE BIT(4) /* Alert pin mode (1=therm, 0=alert) */
44+
3845
#define TMP11X_AVG_1_SAMPLE 0
3946
#define TMP11X_AVG_8_SAMPLES BIT(5)
4047
#define TMP11X_AVG_32_SAMPLES BIT(6)
@@ -46,12 +53,42 @@
4653
struct tmp11x_data {
4754
uint16_t sample;
4855
uint16_t id;
56+
#ifdef CONFIG_TMP11X_TRIGGER
57+
const struct device *dev;
58+
struct gpio_callback alert_cb;
59+
sensor_trigger_handler_t alert_handler;
60+
const struct sensor_trigger *alert_trigger;
61+
62+
#if defined(CONFIG_TMP11X_TRIGGER_OWN_THREAD)
63+
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_TMP11X_THREAD_STACK_SIZE);
64+
struct k_thread thread;
65+
struct k_sem gpio_sem;
66+
#elif defined(CONFIG_TMP11X_TRIGGER_GLOBAL_THREAD)
67+
struct k_work work;
68+
#endif /* CONFIG_TMP11X_TRIGGER_OWN_THREAD */
69+
#endif /* CONFIG_TMP11X_TRIGGER */
4970
};
5071

5172
struct tmp11x_dev_config {
5273
struct i2c_dt_spec bus;
5374
uint16_t odr;
5475
uint16_t oversampling;
76+
bool alert_pin_polarity;
77+
bool alert_mode;
78+
bool alert_dr_sel;
79+
#ifdef CONFIG_TMP11X_TRIGGER
80+
struct gpio_dt_spec alert_gpio;
81+
#endif
5582
};
5683

84+
/* Function declarations */
85+
int tmp11x_write_config(const struct device *dev, uint16_t mask, uint16_t conf);
86+
int tmp11x_reg_read(const struct device *dev, uint8_t reg, uint16_t *val);
87+
88+
#ifdef CONFIG_TMP11X_TRIGGER
89+
int tmp11x_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
90+
sensor_trigger_handler_t handler);
91+
int tmp11x_init_interrupt(const struct device *dev);
92+
#endif
93+
5794
#endif /* ZEPHYR_DRIVERS_SENSOR_TMP11X_TMP11X_H_ */

0 commit comments

Comments
 (0)