* [PATCH 1/2] dt-bindings: iio: ti,tmp117: describe interrupts for TMP117
2026-10-05 14:44 [PATCH 0/2] Add interrupt support on TMP117 Thomas Bonnefille
@ 2026-10-05 14:44 ` Thomas Bonnefille
2026-10-05 14:44 ` [PATCH 2/2] iio: temperature: tmp117: add support for HIGH and LOW alerts Thomas Bonnefille
1 sibling, 0 replies; 6+ messages in thread
From: Thomas Bonnefille @ 2026-10-05 14:44 UTC (permalink / raw)
To: Puranjay Mohan, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Thomas Petazzoni, Miquèl Raynal, linux-iio, devicetree,
linux-kernel, Thomas Bonnefille
The TMP117 can send alerts when the temperature crosses a low or high
limit. This triggers an interrupt on the ALERT pin.
Add the optional interrupts property.
Signed-off-by: Thomas Bonnefille <thomas.bonnefille@bootlin.com>
---
Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml b/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml
index 7fb3e68207919..68ee936722ded 100644
--- a/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml
+++ b/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml
@@ -30,6 +30,11 @@ properties:
reg:
maxItems: 1
+ interrupts:
+ description: |
+ Interrupt line connected to the ALERT output of the sensor.
+ maxItems: 1
+
vcc-supply:
description: provide VCC power to the sensor.
@@ -45,6 +50,8 @@ additionalProperties: false
examples:
- |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
i2c {
#address-cells = <1>;
#size-cells = <0>;
@@ -52,6 +59,8 @@ examples:
tmp117@48 {
compatible = "ti,tmp117";
reg = <0x48>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
vcc-supply = <&pmic_reg_3v3>;
};
};
--
2.55.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 2/2] iio: temperature: tmp117: add support for HIGH and LOW alerts
2026-10-05 14:44 [PATCH 0/2] Add interrupt support on TMP117 Thomas Bonnefille
2026-10-05 14:44 ` [PATCH 1/2] dt-bindings: iio: ti,tmp117: describe interrupts for TMP117 Thomas Bonnefille
@ 2026-10-05 14:44 ` Thomas Bonnefille
2026-10-06 4:47 ` kernel test robot
` (2 more replies)
1 sibling, 3 replies; 6+ messages in thread
From: Thomas Bonnefille @ 2026-10-05 14:44 UTC (permalink / raw)
To: Puranjay Mohan, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Thomas Petazzoni, Miquèl Raynal, linux-iio, devicetree,
linux-kernel, Thomas Bonnefille
The TMP117/116/119 chips allow the user to set an alert if the
temperature reaches a HIGH or LOW limit.
Add support for setting the high and low alert limits.
An IIO event is generated when the temperature crosses either limit
thanks to an interrupt on the Alert pin.
Signed-off-by: Thomas Bonnefille <thomas.bonnefille@bootlin.com>
---
drivers/iio/temperature/tmp117.c | 145 +++++++++++++++++++++++++++++++++++++++
1 file changed, 145 insertions(+)
diff --git a/drivers/iio/temperature/tmp117.c b/drivers/iio/temperature/tmp117.c
index 74cb8d62bef3c..d2924e9a7f97b 100644
--- a/drivers/iio/temperature/tmp117.c
+++ b/drivers/iio/temperature/tmp117.c
@@ -22,9 +22,12 @@
#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
+#include <linux/iio/events.h>
#define TMP117_REG_TEMP 0x0
#define TMP117_REG_CFGR 0x1
+#define TMP117_CFGR_HIGH_ALERT BIT(15)
+#define TMP117_CFGR_LOW_ALERT BIT(14)
#define TMP117_REG_HIGH_LIM 0x2
#define TMP117_REG_LOW_LIM 0x3
#define TMP117_REG_EEPROM_UL 0x4
@@ -37,6 +40,13 @@
#define TMP117_RESOLUTION_10UC 78125
#define MICRODEGREE_PER_10MILLIDEGREE 10000
+/*
+ * The temperature limit registers store a signed 16-bit value with an LSB of
+ * TMP117_RESOLUTION_10UC / MICRODEGREE_PER_10MILLIDEGREE = 125/16 m°C.
+ */
+#define TMP117_LIMIT_LSB_NUM 125
+#define TMP117_LIMIT_LSB_DEN 16
+
#define TMP116_DEVICE_ID 0x1116
#define TMP117_DEVICE_ID 0x0117
#define TMP119_DEVICE_ID 0x2117
@@ -52,6 +62,112 @@ struct tmp11x_info {
int num_channels;
};
+static irqreturn_t tmp117_interrupt_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct tmp117_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = i2c_smbus_read_word_swapped(data->client, TMP117_REG_CFGR);
+ if (ret < 0 || !(ret & (TMP117_CFGR_HIGH_ALERT | TMP117_CFGR_LOW_ALERT)))
+ return IRQ_NONE;
+
+ if (ret & TMP117_CFGR_HIGH_ALERT)
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ iio_get_time_ns(indio_dev));
+
+ if (ret & TMP117_CFGR_LOW_ALERT)
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING),
+ iio_get_time_ns(indio_dev));
+
+ return IRQ_HANDLED;
+}
+
+static int tmp117_read_thresh(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct tmp117_data *data = iio_priv(indio_dev);
+ s32 ret;
+ u8 reg;
+
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ reg = TMP117_REG_HIGH_LIM;
+ break;
+ case IIO_EV_DIR_FALLING:
+ reg = TMP117_REG_LOW_LIM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (info != IIO_EV_INFO_VALUE || type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+ ret = i2c_smbus_read_word_swapped(data->client, reg);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Report the threshold in millidegrees Celsius as an exact fraction:
+ * value = raw * TMP117_LIMIT_LSB_NUM / TMP117_LIMIT_LSB_DEN.
+ */
+ *val = sign_extend32(ret, 15) * TMP117_LIMIT_LSB_NUM;
+ *val2 = TMP117_LIMIT_LSB_DEN;
+
+ return IIO_VAL_FRACTIONAL;
+}
+
+static int tmp117_write_thresh(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct tmp117_data *data = iio_priv(indio_dev);
+ s64 tmp;
+ u8 reg;
+
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ reg = TMP117_REG_HIGH_LIM;
+ break;
+ case IIO_EV_DIR_FALLING:
+ reg = TMP117_REG_LOW_LIM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (info != IIO_EV_INFO_VALUE || type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ /*
+ * The threshold is passed in millidegrees Celsius as
+ * value = val + val2 / 1000000 (val2 holds the fractional part, with
+ * the sign taken from val). Convert it back with the same LSB ratio:
+ * raw = value / (TMP117_LIMIT_LSB_NUM / TMP117_LIMIT_LSB_DEN).
+ */
+ tmp = (val < 0) ? (s64)val * 1000000 - val2
+ : (s64)val * 1000000 + val2;
+ tmp = DIV_ROUND_CLOSEST(tmp * TMP117_LIMIT_LSB_DEN,
+ (s64)TMP117_LIMIT_LSB_NUM * 1000000);
+ tmp = clamp_t(s64, tmp, S16_MIN, S16_MAX);
+
+ return i2c_smbus_write_word_swapped(data->client,
+ reg, tmp);
+}
+
static int tmp117_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
@@ -112,12 +228,27 @@ static int tmp117_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec
}
}
+static const struct iio_event_spec tmp11x_obj_event[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+};
+
static const struct iio_chan_spec tmp117_channels[] = {
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_CALIBBIAS) |
BIT(IIO_CHAN_INFO_SCALE),
+ .event_spec = tmp11x_obj_event,
+ .num_event_specs = ARRAY_SIZE(tmp11x_obj_event),
},
};
@@ -126,6 +257,8 @@ static const struct iio_chan_spec tmp116_channels[] = {
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
+ .event_spec = tmp11x_obj_event,
+ .num_event_specs = ARRAY_SIZE(tmp11x_obj_event),
},
};
@@ -150,6 +283,8 @@ static const struct tmp11x_info tmp119_channels_info = {
static const struct iio_info tmp117_info = {
.read_raw = tmp117_read_raw,
.write_raw = tmp117_write_raw,
+ .read_event_value = tmp117_read_thresh,
+ .write_event_value = tmp117_write_thresh,
};
static int tmp117_probe(struct i2c_client *client)
@@ -208,6 +343,16 @@ static int tmp117_probe(struct i2c_client *client)
indio_dev->num_channels = match_data->num_channels;
indio_dev->name = match_data->name;
+ if (client->irq) {
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, tmp117_interrupt_handler,
+ IRQF_ONESHOT, match_data->name,
+ indio_dev);
+ if (ret) {
+ dev_err_probe(&client->dev, ret, "irq request error\n");
+ return ret;
+ }
+ }
return devm_iio_device_register(&client->dev, indio_dev);
}
--
2.55.0
^ permalink raw reply [flat|nested] 6+ messages in thread