mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/6] iio: adc: versal-sysmon: Add OT alarm, shutdown and thermal zone support
@ 2026-11-02 12:21 Amit Kumar Mahapatra
  2026-11-02 12:21 ` [PATCH 1/6] iio: adc: versal-sysmon: fix race in interrupt teardown Amit Kumar Mahapatra
                   ` (5 more replies)
  0 siblings, 6 replies; 9+ messages in thread
From: Amit Kumar Mahapatra @ 2026-11-02 12:21 UTC (permalink / raw)
  To: Jonathan Cameron, Michal Simek, Sai Krishna Potthuri,
	David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, devicetree, linux-arm-kernel, linux-kernel,
	amitrkcian2002, Amit Kumar Mahapatra

This patch series:
- Fixes a race between the interrupt teardown and the interrupt handler
- Validates the temperature hysteresis written by userspace and read
  from hardware at probe
- Adds a .shutdown callback so the SysMon alarm interrupts are disabled
  when the system shuts down or kexecs into another kernel
- Adds the over-temperature (OT) alarm as an event-only channel labelled
  "ot", alongside the existing device temperature event
- Updates the Versal SysMon maintainers: removes Salih Erim, who is no
  longer with AMD, and adds myself
- Describes the SysMon in the Versal NET device tree, with a thermal
  zone on its device temperature
- Adds thermal zone support for the SysMon using the existing
  generic-adc-thermal driver

Amit Kumar Mahapatra (6):
  iio: adc: versal-sysmon: fix race in interrupt teardown
  iio: adc: versal-sysmon: validate temperature hysteresis
  iio: adc: versal-sysmon: disable interrupts on shutdown
  iio: adc: versal-sysmon: add over-temperature alarm events
  arm64: versal-net: Add SysMon and thermal zone
  MAINTAINERS: update Versal SysMon maintainers

 MAINTAINERS                                |   2 +-
 arch/arm64/boot/dts/xilinx/versal-net.dtsi |  29 ++++
 drivers/iio/adc/versal-sysmon-core.c       | 158 +++++++++++++++++----
 drivers/iio/adc/versal-sysmon.c            |   6 +
 drivers/iio/adc/versal-sysmon.h            |  15 +-
 5 files changed, 182 insertions(+), 28 deletions(-)


base-commit: a3b3580713f3ac5a32dc2874ee546828977a1d68
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/6] iio: adc: versal-sysmon: fix race in interrupt teardown
  2026-11-02 12:21 [PATCH 0/6] iio: adc: versal-sysmon: Add OT alarm, shutdown and thermal zone support Amit Kumar Mahapatra
@ 2026-11-02 12:21 ` Amit Kumar Mahapatra
  2026-11-02 12:21 ` [PATCH 2/6] iio: adc: versal-sysmon: validate temperature hysteresis Amit Kumar Mahapatra
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Amit Kumar Mahapatra @ 2026-11-02 12:21 UTC (permalink / raw)
  To: Jonathan Cameron, Michal Simek, Sai Krishna Potthuri,
	David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, devicetree, linux-arm-kernel, linux-kernel,
	amitrkcian2002, Amit Kumar Mahapatra

sysmon_disable_interrupts() masks all interrupts, clears masked_temp and
cancels the unmask worker, but leaves the interrupt handler live. A
worker that is already running can re-enable an alarm through IER after
the mask write. If that alarm fires, the handler queues the worker again
after cancel_delayed_work_sync() has returned. On unbind this action runs
before devm releases the IRQ, so the queued work can run after the
devm-allocated iio_dev that embeds it has been freed.

Disable the IRQ first so that no handler is running or can start, then
clear masked_temp and cancel the worker, and mask all interrupts last,
once nothing is left that can unmask them. Record the IRQ number for
this.

Fixes: c7f7eb10638f ("iio: adc: versal-sysmon: add threshold event support")
Signed-off-by: Amit Kumar Mahapatra <amit.kumar-mahapatra@amd.com>
---
 drivers/iio/adc/versal-sysmon-core.c | 5 ++++-
 drivers/iio/adc/versal-sysmon.h      | 2 ++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/iio/adc/versal-sysmon-core.c b/drivers/iio/adc/versal-sysmon-core.c
index 1b55d343982e..6b9a58e19831 100644
--- a/drivers/iio/adc/versal-sysmon-core.c
+++ b/drivers/iio/adc/versal-sysmon-core.c
@@ -781,12 +781,14 @@ static void sysmon_disable_interrupts(void *data)
 {
 	struct sysmon *sysmon = data;
 
-	regmap_write(sysmon->regmap, SYSMON_IDR, SYSMON_INTR_ALL_MASK);
+	disable_irq(sysmon->irq);
 
 	scoped_guard(spinlock_irq, &sysmon->irq_lock)
 		sysmon->masked_temp = 0;
 
 	cancel_delayed_work_sync(&sysmon->sysmon_unmask_work);
+
+	regmap_write(sysmon->regmap, SYSMON_IDR, SYSMON_INTR_ALL_MASK);
 }
 
 static int sysmon_init_interrupt(struct sysmon *sysmon,
@@ -807,6 +809,7 @@ static int sysmon_init_interrupt(struct sysmon *sysmon,
 	if (ret)
 		return ret;
 	sysmon->temp_mask = imr & SYSMON_TEMP_INTR_MASK;
+	sysmon->irq = irq;
 
 	ret = devm_request_irq(dev, irq, sysmon_iio_irq, 0, "sysmon-irq", indio_dev);
 	if (ret)
diff --git a/drivers/iio/adc/versal-sysmon.h b/drivers/iio/adc/versal-sysmon.h
index bb9a75bf71c0..701ef9b56263 100644
--- a/drivers/iio/adc/versal-sysmon.h
+++ b/drivers/iio/adc/versal-sysmon.h
@@ -85,6 +85,7 @@ struct regmap;
  * @regmap: register map for hardware access
  * @lock: protects read-modify-write sequences on threshold registers
  *        and cached state that spans multiple regmap calls
+ * @irq: interrupt number, 0 when events are not supported
  * @irq_lock: protects interrupt mask register updates (MMIO path only)
  * @masked_temp: currently masked temperature alarm bits
  * @temp_mask: temperature interrupt configuration mask
@@ -101,6 +102,7 @@ struct sysmon {
 	 * that spans multiple regmap calls.
 	 */
 	struct mutex lock;
+	int irq;
 	/*
 	 * Protects interrupt mask register updates.  Only used on the
 	 * MMIO path (fast_io regmap); I2C has no IRQ and never reaches
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 2/6] iio: adc: versal-sysmon: validate temperature hysteresis
  2026-11-02 12:21 [PATCH 0/6] iio: adc: versal-sysmon: Add OT alarm, shutdown and thermal zone support Amit Kumar Mahapatra
  2026-11-02 12:21 ` [PATCH 1/6] iio: adc: versal-sysmon: fix race in interrupt teardown Amit Kumar Mahapatra
@ 2026-11-02 12:21 ` Amit Kumar Mahapatra
  2026-11-02 12:21 ` [PATCH 3/6] iio: adc: versal-sysmon: disable interrupts on shutdown Amit Kumar Mahapatra
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Amit Kumar Mahapatra @ 2026-11-02 12:21 UTC (permalink / raw)
  To: Jonathan Cameron, Michal Simek, Sai Krishna Potthuri,
	David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, devicetree, linux-arm-kernel, linux-kernel,
	amitrkcian2002, Amit Kumar Mahapatra

The hysteresis written through sysfs is only checked for being negative.
A large value makes upper_mc - hysteresis in sysmon_update_temp_lower()
overflow before it is clamped. Reject values above the full Q8.7 span of
511992 millicelsius, and name the Q8.7 temperature limits so that the
span and the existing range checks share one definition.

The cached hysteresis is seeded at probe from the threshold registers
without checking that the lower threshold is not above the upper one.
Treat that case as zero hysteresis, as negative values are rejected on
the write path.

Fixes: c7f7eb10638f ("iio: adc: versal-sysmon: add threshold event support")
Signed-off-by: Amit Kumar Mahapatra <amit.kumar-mahapatra@amd.com>
---
 drivers/iio/adc/versal-sysmon-core.c | 10 +++++-----
 drivers/iio/adc/versal-sysmon.h      |  4 ++++
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/iio/adc/versal-sysmon-core.c b/drivers/iio/adc/versal-sysmon-core.c
index 6b9a58e19831..6595d07038c1 100644
--- a/drivers/iio/adc/versal-sysmon-core.c
+++ b/drivers/iio/adc/versal-sysmon-core.c
@@ -352,7 +352,8 @@ static int sysmon_update_temp_lower(struct sysmon *sysmon)
 		return ret;
 
 	sysmon_q8p7_to_millicelsius(upper_reg, &upper_mc);
-	lower_mc = clamp(upper_mc - sysmon->temp_hysteresis, -256000, 255992);
+	lower_mc = clamp(upper_mc - sysmon->temp_hysteresis,
+			 SYSMON_TEMP_MIN_MC, SYSMON_TEMP_MAX_MC);
 	sysmon_millicelsius_to_q8p7(&raw_val, lower_mc);
 
 	return regmap_write(sysmon->regmap, SYSMON_TEMP_TH_LOW, raw_val);
@@ -429,8 +430,7 @@ static int sysmon_write_event_value(struct iio_dev *indio_dev,
 	case IIO_TEMP:
 		switch (info) {
 		case IIO_EV_INFO_VALUE:
-			/* Q8.7 signed range: -256000 to +255992 mC */
-			if (val < -256000 || val > 255992)
+			if (val < SYSMON_TEMP_MIN_MC || val > SYSMON_TEMP_MAX_MC)
 				return -EINVAL;
 
 			sysmon_millicelsius_to_q8p7(&raw_val, val);
@@ -443,7 +443,7 @@ static int sysmon_write_event_value(struct iio_dev *indio_dev,
 			return sysmon_update_temp_lower(sysmon);
 
 		case IIO_EV_INFO_HYSTERESIS:
-			if (val < 0)
+			if (val < 0 || val > SYSMON_TEMP_MAX_MC - SYSMON_TEMP_MIN_MC)
 				return -EINVAL;
 
 			sysmon->temp_hysteresis = val;
@@ -838,7 +838,7 @@ static int sysmon_init_hysteresis(struct sysmon *sysmon, int *hysteresis)
 
 	sysmon_q8p7_to_millicelsius(upper_reg, &upper_mc);
 	sysmon_q8p7_to_millicelsius(lower_reg, &lower_mc);
-	*hysteresis = upper_mc - lower_mc;
+	*hysteresis = max(upper_mc - lower_mc, 0);
 
 	return 0;
 }
diff --git a/drivers/iio/adc/versal-sysmon.h b/drivers/iio/adc/versal-sysmon.h
index 701ef9b56263..a1ac3289719c 100644
--- a/drivers/iio/adc/versal-sysmon.h
+++ b/drivers/iio/adc/versal-sysmon.h
@@ -75,6 +75,10 @@ struct regmap;
 #define SYSMON_FRACTIONAL_SHIFT		7U
 #define SYSMON_SUPPLY_MANTISSA_BITS	16
 
+/* Q8.7 signed temperature range in millicelsius */
+#define SYSMON_TEMP_MIN_MC		-256000
+#define SYSMON_TEMP_MAX_MC		255992
+
 /* Bits per alarm register */
 #define SYSMON_ALARM_BITS_PER_REG	32
 
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 3/6] iio: adc: versal-sysmon: disable interrupts on shutdown
  2026-11-02 12:21 [PATCH 0/6] iio: adc: versal-sysmon: Add OT alarm, shutdown and thermal zone support Amit Kumar Mahapatra
  2026-11-02 12:21 ` [PATCH 1/6] iio: adc: versal-sysmon: fix race in interrupt teardown Amit Kumar Mahapatra
  2026-11-02 12:21 ` [PATCH 2/6] iio: adc: versal-sysmon: validate temperature hysteresis Amit Kumar Mahapatra
@ 2026-11-02 12:21 ` Amit Kumar Mahapatra
  2026-11-02 12:21 ` [PATCH 4/6] iio: adc: versal-sysmon: add over-temperature alarm events Amit Kumar Mahapatra
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Amit Kumar Mahapatra @ 2026-11-02 12:21 UTC (permalink / raw)
  To: Jonathan Cameron, Michal Simek, Sai Krishna Potthuri,
	David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, devicetree, linux-arm-kernel, linux-kernel,
	amitrkcian2002, Amit Kumar Mahapatra

Interrupt teardown is registered with devm_add_action_or_reset(), so
sysmon_disable_interrupts() runs when the driver is unbound but not when
the system shuts down: device_shutdown() invokes only the driver's
.shutdown callback, which this driver does not implement.

The device is therefore left with its alarm interrupts enabled in
hardware once Linux has stopped servicing them.

Add a .shutdown callback performing the same teardown, so the device is
quiesced before control is handed on. The helper lives in the core
module, so it is exported for the platform front-end. It skips a
device described without an interrupt, which never set up interrupt
handling.

Disabling the interrupts at shutdown is safe to have and not a must have
requirement for shutdown.

Signed-off-by: Amit Kumar Mahapatra <amit.kumar-mahapatra@amd.com>
---
 drivers/iio/adc/versal-sysmon-core.c | 19 +++++++++++++++++++
 drivers/iio/adc/versal-sysmon.c      |  6 ++++++
 drivers/iio/adc/versal-sysmon.h      |  1 +
 3 files changed, 26 insertions(+)

diff --git a/drivers/iio/adc/versal-sysmon-core.c b/drivers/iio/adc/versal-sysmon-core.c
index 6595d07038c1..d39aaba9a8b6 100644
--- a/drivers/iio/adc/versal-sysmon-core.c
+++ b/drivers/iio/adc/versal-sysmon-core.c
@@ -1000,6 +1000,8 @@ int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap)
 	if (!indio_dev)
 		return -ENOMEM;
 
+	dev_set_drvdata(dev, indio_dev);
+
 	sysmon = iio_priv(indio_dev);
 	sysmon->regmap = regmap;
 	sysmon->temp_oversampling = 1;
@@ -1050,6 +1052,23 @@ int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap)
 }
 EXPORT_SYMBOL_NS_GPL(devm_versal_sysmon_core_probe, "VERSAL_SYSMON");
 
+/**
+ * versal_sysmon_shutdown() - Disable SysMon interrupts on system shutdown
+ * @dev: SysMon device
+ *
+ * Interrupt teardown is a devm action, which runs on driver unbind but not
+ * on system shutdown, so disable the interrupts here as well.
+ */
+void versal_sysmon_shutdown(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct sysmon *sysmon = iio_priv(indio_dev);
+
+	if (sysmon->irq > 0)
+		sysmon_disable_interrupts(sysmon);
+}
+EXPORT_SYMBOL_NS_GPL(versal_sysmon_shutdown, "VERSAL_SYSMON");
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("AMD Versal SysMon Core Driver");
 MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>");
diff --git a/drivers/iio/adc/versal-sysmon.c b/drivers/iio/adc/versal-sysmon.c
index 529d0486c9f9..4d5e3d14cf15 100644
--- a/drivers/iio/adc/versal-sysmon.c
+++ b/drivers/iio/adc/versal-sysmon.c
@@ -71,6 +71,11 @@ static int sysmon_platform_probe(struct platform_device *pdev)
 	return devm_versal_sysmon_core_probe(dev, regmap);
 }
 
+static void sysmon_platform_shutdown(struct platform_device *pdev)
+{
+	versal_sysmon_shutdown(&pdev->dev);
+}
+
 static const struct of_device_id sysmon_of_match_table[] = {
 	{ .compatible = "xlnx,versal-sysmon" },
 	{ }
@@ -79,6 +84,7 @@ MODULE_DEVICE_TABLE(of, sysmon_of_match_table);
 
 static struct platform_driver sysmon_platform_driver = {
 	.probe = sysmon_platform_probe,
+	.shutdown = sysmon_platform_shutdown,
 	.driver = {
 		.name = "versal-sysmon",
 		.of_match_table = sysmon_of_match_table,
diff --git a/drivers/iio/adc/versal-sysmon.h b/drivers/iio/adc/versal-sysmon.h
index a1ac3289719c..a21dacc13471 100644
--- a/drivers/iio/adc/versal-sysmon.h
+++ b/drivers/iio/adc/versal-sysmon.h
@@ -122,5 +122,6 @@ struct sysmon {
 };
 
 int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap);
+void versal_sysmon_shutdown(struct device *dev);
 
 #endif /* _VERSAL_SYSMON_H_ */
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 4/6] iio: adc: versal-sysmon: add over-temperature alarm events
  2026-11-02 12:21 [PATCH 0/6] iio: adc: versal-sysmon: Add OT alarm, shutdown and thermal zone support Amit Kumar Mahapatra
                   ` (2 preceding siblings ...)
  2026-11-02 12:21 ` [PATCH 3/6] iio: adc: versal-sysmon: disable interrupts on shutdown Amit Kumar Mahapatra
@ 2026-11-02 12:21 ` Amit Kumar Mahapatra
  2026-11-02 12:21 ` [PATCH 5/6] arm64: versal-net: Add SysMon and thermal zone Amit Kumar Mahapatra
  2026-11-02 12:21 ` [PATCH 6/6] MAINTAINERS: update Versal SysMon maintainers Amit Kumar Mahapatra
  5 siblings, 0 replies; 9+ messages in thread
From: Amit Kumar Mahapatra @ 2026-11-02 12:21 UTC (permalink / raw)
  To: Jonathan Cameron, Michal Simek, Sai Krishna Potthuri,
	David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, devicetree, linux-arm-kernel, linux-kernel,
	amitrkcian2002, Amit Kumar Mahapatra

The SysMon has two independent temperature comparators. The driver
exposes only DEVICE_TEMP on interrupt bit 9; the over-temperature alarm
on bit 8, with its own threshold pair at OT_TEMP_TH_LOWER and
OT_TEMP_TH_UPPER, is not reported to userspace at all.

The two are structurally identical: an upper threshold, a lower
threshold acting as the hysteresis floor, and a hysteresis mode bit in
ALARM_CONFIG, bit 0 for OT and bit 1 for DEVICE_TEMP. Per AM006 the
over-temperature shutdown response is a PMC function configured at
design time, so the kernel's role here is threshold configuration and
notification rather than acting on the alarm.

IIO identifies an event by channel, type and direction, and both
comparators are rising thresholds on the same aggregate temperature, so
they cannot share a channel. Add an event-only channel labelled "ot"
carrying the OT thresholds.

The channel is appended after the device tree derived channels because
io-channels phandle arguments are raw array positions, and placing it
earlier would silently repoint existing consumers. It is created only
when the device has an interrupt, as without one it would carry no
events.

Signed-off-by: Amit Kumar Mahapatra <amit.kumar-mahapatra@amd.com>
---
 drivers/iio/adc/versal-sysmon-core.c | 128 ++++++++++++++++++++++-----
 drivers/iio/adc/versal-sysmon.h      |   8 +-
 2 files changed, 113 insertions(+), 23 deletions(-)

diff --git a/drivers/iio/adc/versal-sysmon-core.c b/drivers/iio/adc/versal-sysmon-core.c
index d39aaba9a8b6..bb8737ac5638 100644
--- a/drivers/iio/adc/versal-sysmon-core.c
+++ b/drivers/iio/adc/versal-sysmon-core.c
@@ -34,7 +34,8 @@
  */
 static const int sysmon_oversampling_avail[] = { 1, 2, 4, 8, 16 };
 
-/* TEMP hysteresis mode bit in SYSMON_TEMP_EV_CFG */
+/* Hysteresis mode bits in SYSMON_TEMP_EV_CFG (AM006 ALARM_CONFIG) */
+#define SYSMON_OT_HYST_MASK		BIT(0)
 #define SYSMON_TEMP_HYST_MASK		BIT(1)
 
 /* Compute alarm register offset from a channel address */
@@ -62,9 +63,41 @@ enum sysmon_alarm_bit {
 	SYSMON_BIT_ALARM2 = 2,
 	SYSMON_BIT_ALARM3 = 3,
 	SYSMON_BIT_ALARM4 = 4,
+	SYSMON_BIT_OT = 8,
 	SYSMON_BIT_TEMP = 9,
 };
 
+/*
+ * The two temperature comparators are identical in layout: an upper
+ * threshold, a lower threshold acting as the hysteresis floor, and a
+ * hysteresis cached in millicelsius because the hardware only stores the
+ * two thresholds. DEVICE_TEMP drives bit 9, the over-temperature alarm
+ * bit 8.
+ */
+struct sysmon_comparator {
+	unsigned int th_up;
+	unsigned int th_low;
+	int *hysteresis;
+};
+
+static bool sysmon_chan_is_ot(const struct iio_chan_spec *chan)
+{
+	return chan->address == SYSMON_OT_TH_UP;
+}
+
+static struct sysmon_comparator sysmon_get_comparator(struct sysmon *sysmon,
+						      const struct iio_chan_spec *chan)
+{
+	if (sysmon_chan_is_ot(chan))
+		return (struct sysmon_comparator){
+			SYSMON_OT_TH_UP, SYSMON_OT_TH_LOW, &sysmon->ot_hysteresis
+		};
+
+	return (struct sysmon_comparator){
+		SYSMON_TEMP_TH_UP, SYSMON_TEMP_TH_LOW, &sysmon->temp_hysteresis
+	};
+}
+
 /* Temperature event specification: rising threshold + hysteresis only */
 static const struct iio_event_spec sysmon_temp_events[] = {
 	{
@@ -221,7 +254,8 @@ static int sysmon_read_raw(struct iio_dev *indio_dev,
 static u32 sysmon_get_event_mask(const struct iio_chan_spec *chan)
 {
 	if (chan->type == IIO_TEMP)
-		return BIT(SYSMON_BIT_TEMP);
+		return sysmon_chan_is_ot(chan) ? BIT(SYSMON_BIT_OT) :
+						 BIT(SYSMON_BIT_TEMP);
 
 	return BIT(chan->address / SYSMON_ALARM_BITS_PER_REG);
 }
@@ -340,23 +374,24 @@ static int sysmon_write_event_config(struct iio_dev *indio_dev,
  * cached hysteresis. Called when either upper threshold or hysteresis
  * is written.
  */
-static int sysmon_update_temp_lower(struct sysmon *sysmon)
+static int sysmon_update_temp_lower(struct sysmon *sysmon,
+				    const struct sysmon_comparator *cmp)
 {
 	unsigned int upper_reg;
 	int upper_mc, lower_mc;
 	u32 raw_val;
 	int ret;
 
-	ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &upper_reg);
+	ret = regmap_read(sysmon->regmap, cmp->th_up, &upper_reg);
 	if (ret)
 		return ret;
 
 	sysmon_q8p7_to_millicelsius(upper_reg, &upper_mc);
-	lower_mc = clamp(upper_mc - sysmon->temp_hysteresis,
+	lower_mc = clamp(upper_mc - *cmp->hysteresis,
 			 SYSMON_TEMP_MIN_MC, SYSMON_TEMP_MAX_MC);
 	sysmon_millicelsius_to_q8p7(&raw_val, lower_mc);
 
-	return regmap_write(sysmon->regmap, SYSMON_TEMP_TH_LOW, raw_val);
+	return regmap_write(sysmon->regmap, cmp->th_low, raw_val);
 }
 
 static int sysmon_read_event_value(struct iio_dev *indio_dev,
@@ -374,10 +409,12 @@ static int sysmon_read_event_value(struct iio_dev *indio_dev,
 	guard(mutex)(&sysmon->lock);
 
 	switch (chan->type) {
-	case IIO_TEMP:
+	case IIO_TEMP: {
+		struct sysmon_comparator cmp = sysmon_get_comparator(sysmon, chan);
+
 		switch (info) {
 		case IIO_EV_INFO_VALUE:
-			ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &reg_val);
+			ret = regmap_read(sysmon->regmap, cmp.th_up, &reg_val);
 			if (ret)
 				return ret;
 
@@ -386,12 +423,13 @@ static int sysmon_read_event_value(struct iio_dev *indio_dev,
 			return IIO_VAL_INT;
 
 		case IIO_EV_INFO_HYSTERESIS:
-			*val = sysmon->temp_hysteresis;
+			*val = *cmp.hysteresis;
 			return IIO_VAL_INT;
 
 		default:
 			return -EINVAL;
 		}
+	}
 
 	case IIO_VOLTAGE:
 		offset = sysmon_supply_thresh_offset(chan->address, dir);
@@ -427,7 +465,9 @@ static int sysmon_write_event_value(struct iio_dev *indio_dev,
 	guard(mutex)(&sysmon->lock);
 
 	switch (chan->type) {
-	case IIO_TEMP:
+	case IIO_TEMP: {
+		struct sysmon_comparator cmp = sysmon_get_comparator(sysmon, chan);
+
 		switch (info) {
 		case IIO_EV_INFO_VALUE:
 			if (val < SYSMON_TEMP_MIN_MC || val > SYSMON_TEMP_MAX_MC)
@@ -435,24 +475,25 @@ static int sysmon_write_event_value(struct iio_dev *indio_dev,
 
 			sysmon_millicelsius_to_q8p7(&raw_val, val);
 
-			ret = regmap_write(sysmon->regmap, SYSMON_TEMP_TH_UP, raw_val);
+			ret = regmap_write(sysmon->regmap, cmp.th_up, raw_val);
 			if (ret)
 				return ret;
 
 			/* Recompute lower = upper - hysteresis */
-			return sysmon_update_temp_lower(sysmon);
+			return sysmon_update_temp_lower(sysmon, &cmp);
 
 		case IIO_EV_INFO_HYSTERESIS:
 			if (val < 0 || val > SYSMON_TEMP_MAX_MC - SYSMON_TEMP_MIN_MC)
 				return -EINVAL;
 
-			sysmon->temp_hysteresis = val;
+			*cmp.hysteresis = val;
 
-			return sysmon_update_temp_lower(sysmon);
+			return sysmon_update_temp_lower(sysmon, &cmp);
 
 		default:
 			return -EINVAL;
 		}
+	}
 
 	case IIO_VOLTAGE:
 		offset = sysmon_supply_thresh_offset(chan->address, dir);
@@ -672,6 +713,16 @@ static int sysmon_handle_event(struct iio_dev *indio_dev, u32 event)
 		sysmon->masked_temp |= BIT(SYSMON_BIT_TEMP);
 		return 0;
 
+	case SYSMON_BIT_OT:
+		sysmon_push_event(indio_dev, SYSMON_OT_TH_UP);
+
+		ret = regmap_write(sysmon->regmap, SYSMON_IDR, BIT(SYSMON_BIT_OT));
+		if (ret)
+			return ret;
+
+		sysmon->masked_temp |= BIT(SYSMON_BIT_OT);
+		return 0;
+
 	case SYSMON_BIT_ALARM0:
 	case SYSMON_BIT_ALARM1:
 	case SYSMON_BIT_ALARM2:
@@ -822,23 +873,24 @@ static int sysmon_init_interrupt(struct sysmon *sysmon,
  * Initialize the cached hysteresis for a temperature channel from the
  * current hardware threshold registers: hysteresis = upper - lower.
  */
-static int sysmon_init_hysteresis(struct sysmon *sysmon, int *hysteresis)
+static int sysmon_init_hysteresis(struct sysmon *sysmon,
+				  const struct sysmon_comparator *cmp)
 {
 	unsigned int upper_reg, lower_reg;
 	int upper_mc, lower_mc;
 	int ret;
 
-	ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &upper_reg);
+	ret = regmap_read(sysmon->regmap, cmp->th_up, &upper_reg);
 	if (ret)
 		return ret;
 
-	ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_LOW, &lower_reg);
+	ret = regmap_read(sysmon->regmap, cmp->th_low, &lower_reg);
 	if (ret)
 		return ret;
 
 	sysmon_q8p7_to_millicelsius(upper_reg, &upper_mc);
 	sysmon_q8p7_to_millicelsius(lower_reg, &lower_mc);
-	*hysteresis = max(upper_mc - lower_mc, 0);
+	*cmp->hysteresis = max(upper_mc - lower_mc, 0);
 
 	return 0;
 }
@@ -880,6 +932,9 @@ static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev, int ir
 
 	num_static = ARRAY_SIZE(temp_channels);
 	num_chan = size_add(num_temp, size_add(num_static, num_supply));
+	/* The over-temperature channel exists only when events do */
+	if (irq > 0)
+		num_chan = size_add(num_chan, 1);
 	sysmon_channels = devm_kcalloc(dev, num_chan, sizeof(*sysmon_channels), GFP_KERNEL);
 	if (!sysmon_channels)
 		return -ENOMEM;
@@ -960,6 +1015,25 @@ static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev, int ir
 		};
 	}
 
+	/*
+	 * Over-temperature alarm. The OT comparator watches the same
+	 * aggregate temperature as channel 0 but against its own threshold
+	 * pair, and IIO cannot express two rising thresholds on one channel.
+	 * It has no reading of its own, so only event attributes and a label
+	 * are exposed. Appended last, because io-channels phandle arguments
+	 * are raw array positions and inserting it earlier would silently
+	 * repoint every existing consumer.
+	 */
+	if (irq > 0)
+		sysmon_channels[idx++] = (struct iio_chan_spec) {
+			.type = IIO_TEMP,
+			.indexed = 1,
+			.address = SYSMON_OT_TH_UP,
+			.event_spec = sysmon_temp_events,
+			.num_event_specs = ARRAY_SIZE(sysmon_temp_events),
+			.datasheet_name = "ot",
+		};
+
 	indio_dev->num_channels = idx;
 	indio_dev->info = &sysmon_iio_info;
 
@@ -1032,14 +1106,26 @@ int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap)
 		return ret;
 
 	if (irq > 0) {
-		/* Set hysteresis mode for temperature threshold */
+		struct sysmon_comparator cmp;
+
+		/* Set hysteresis mode for both temperature comparators */
 		ret = regmap_set_bits(sysmon->regmap, SYSMON_TEMP_EV_CFG,
-				      SYSMON_TEMP_HYST_MASK);
+				      SYSMON_TEMP_HYST_MASK | SYSMON_OT_HYST_MASK);
 		if (ret)
 			return ret;
 
 		/* Initialize cached hysteresis from hardware registers */
-		ret = sysmon_init_hysteresis(sysmon, &sysmon->temp_hysteresis);
+		cmp = (struct sysmon_comparator){
+			SYSMON_TEMP_TH_UP, SYSMON_TEMP_TH_LOW, &sysmon->temp_hysteresis
+		};
+		ret = sysmon_init_hysteresis(sysmon, &cmp);
+		if (ret)
+			return ret;
+
+		cmp = (struct sysmon_comparator){
+			SYSMON_OT_TH_UP, SYSMON_OT_TH_LOW, &sysmon->ot_hysteresis
+		};
+		ret = sysmon_init_hysteresis(sysmon, &cmp);
 		if (ret)
 			return ret;
 
diff --git a/drivers/iio/adc/versal-sysmon.h b/drivers/iio/adc/versal-sysmon.h
index a21dacc13471..d0a9bb1293c7 100644
--- a/drivers/iio/adc/versal-sysmon.h
+++ b/drivers/iio/adc/versal-sysmon.h
@@ -32,6 +32,8 @@ struct regmap;
 #define SYSMON_SUPPLY_EN_AVG_BASE	0x1958
 #define SYSMON_TEMP_TH_LOW		0x1970
 #define SYSMON_TEMP_TH_UP		0x1974
+#define SYSMON_OT_TH_LOW		0x1978
+#define SYSMON_OT_TH_UP			0x197C
 #define SYSMON_SUPPLY_TH_LOW		0x1980
 #define SYSMON_SUPPLY_TH_UP		0x1C80
 #define SYSMON_TEMP_EV_CFG		0x1F84
@@ -53,8 +55,8 @@ struct regmap;
 #define SYSMON_NO_OF_EVENTS		32
 #define SYSMON_INTR_ALL_MASK		GENMASK(31, 0)
 
-/* ISR/IMR temperature alarm mask (bit 9) */
-#define SYSMON_TEMP_INTR_MASK		BIT(9)
+/* ISR/IMR temperature alarm mask: OT (bit 8) and DEVICE_TEMP (bit 9) */
+#define SYSMON_TEMP_INTR_MASK		GENMASK(9, 8)
 
 /* SYSMON_CONFIG: supply oversampling ratio */
 #define SYSMON_CONFIG_SUPPLY_OSR	GENMASK(17, 14)
@@ -94,6 +96,7 @@ struct regmap;
  * @masked_temp: currently masked temperature alarm bits
  * @temp_mask: temperature interrupt configuration mask
  * @temp_hysteresis: cached DEVICE_TEMP hysteresis in millicelsius
+ * @ot_hysteresis: cached OT hysteresis in millicelsius
  * @sysmon_unmask_work: re-enables events after alarm condition clears
  * @temp_oversampling: current temp oversampling ratio
  * @supply_oversampling: current supply oversampling ratio
@@ -116,6 +119,7 @@ struct sysmon {
 	unsigned int masked_temp;
 	unsigned int temp_mask;
 	int temp_hysteresis;
+	int ot_hysteresis;
 	struct delayed_work sysmon_unmask_work;
 	unsigned int temp_oversampling;
 	unsigned int supply_oversampling;
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 5/6] arm64: versal-net: Add SysMon and thermal zone
  2026-11-02 12:21 [PATCH 0/6] iio: adc: versal-sysmon: Add OT alarm, shutdown and thermal zone support Amit Kumar Mahapatra
                   ` (3 preceding siblings ...)
  2026-11-02 12:21 ` [PATCH 4/6] iio: adc: versal-sysmon: add over-temperature alarm events Amit Kumar Mahapatra
@ 2026-11-02 12:21 ` Amit Kumar Mahapatra
  2026-11-02 14:53   ` Michal Simek
  2026-11-02 12:21 ` [PATCH 6/6] MAINTAINERS: update Versal SysMon maintainers Amit Kumar Mahapatra
  5 siblings, 1 reply; 9+ messages in thread
From: Amit Kumar Mahapatra @ 2026-11-02 12:21 UTC (permalink / raw)
  To: Jonathan Cameron, Michal Simek, Sai Krishna Potthuri,
	David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, devicetree, linux-arm-kernel, linux-kernel,
	amitrkcian2002, Amit Kumar Mahapatra

Describe the System Monitor (SysMon) block in the PMC, which provides
on-chip voltage and temperature monitoring, and use its device
temperature channel as the sensor for a thermal zone.

SysMon channel 0 is the current maximum temperature across all active
satellites.

The thermal zone has a critical trip at 125C. Passive trips and cooling
maps, voltage channels and per-satellite temperature channels depend on
the design and are left to board files.

Signed-off-by: Amit Kumar Mahapatra <amit.kumar-mahapatra@amd.com>
---
 arch/arm64/boot/dts/xilinx/versal-net.dtsi | 29 ++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/arch/arm64/boot/dts/xilinx/versal-net.dtsi b/arch/arm64/boot/dts/xilinx/versal-net.dtsi
index 21bb917bcba1..394181c9a751 100644
--- a/arch/arm64/boot/dts/xilinx/versal-net.dtsi
+++ b/arch/arm64/boot/dts/xilinx/versal-net.dtsi
@@ -735,6 +735,28 @@ versal_fpga: versal-fpga {
 		compatible = "xlnx,versal-fpga";
 	};
 
+	sysmon_temp: thermal-sensor {
+		compatible = "generic-adc-thermal";
+		#thermal-sensor-cells = <0>;
+		io-channels = <&sysmon0 0>;
+		io-channel-names = "sensor-channel";
+	};
+
+	thermal-zones {
+		versal_thermal: versal-thermal {
+			polling-delay = <1000>; /* milliseconds */
+			thermal-sensors = <&sysmon_temp>;
+
+			trips {
+				ot_crit: ot-crit {
+					temperature = <125000>; /* millicelsius */
+					hysteresis = <0>; /* millicelsius */
+					type = "critical";
+				};
+			};
+		};
+	};
+
 	amba: axi {
 		compatible = "simple-bus";
 		bootph-all;
@@ -1033,6 +1055,13 @@ spi1: spi@f1970000 {
 			clock-names = "ref_clk", "pclk";
 		};
 
+		sysmon0: sysmon@f1270000 {
+			compatible = "xlnx,versal-sysmon";
+			reg = <0 0xf1270000 0 0x4000>;
+			interrupts = <0 202 4>;
+			#io-channel-cells = <1>;
+		};
+
 		ttc0: timer@f1dc0000 {
 			compatible = "cdns,ttc";
 			status = "disabled";
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 6/6] MAINTAINERS: update Versal SysMon maintainers
  2026-11-02 12:21 [PATCH 0/6] iio: adc: versal-sysmon: Add OT alarm, shutdown and thermal zone support Amit Kumar Mahapatra
                   ` (4 preceding siblings ...)
  2026-11-02 12:21 ` [PATCH 5/6] arm64: versal-net: Add SysMon and thermal zone Amit Kumar Mahapatra
@ 2026-11-02 12:21 ` Amit Kumar Mahapatra
  2026-11-02 12:53   ` Michal Simek
  5 siblings, 1 reply; 9+ messages in thread
From: Amit Kumar Mahapatra @ 2026-11-02 12:21 UTC (permalink / raw)
  To: Jonathan Cameron, Michal Simek, Sai Krishna Potthuri,
	David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, devicetree, linux-arm-kernel, linux-kernel,
	amitrkcian2002, Amit Kumar Mahapatra

Replace Salih Erim with myself as a maintainer of the Versal SysMon
driver.

Signed-off-by: Amit Kumar Mahapatra <amit.kumar-mahapatra@amd.com>
---
 MAINTAINERS | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index ecc22d1149d1..e3aca3bee13a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -30023,8 +30023,8 @@ F:	drivers/edac/versalnet_edac.c
 F:	include/linux/cdx/edac_cdx_pcol.h
 
 XILINX VERSAL SYSMON DRIVER
-M:	Salih Erim <salih.erim@amd.com>
 M:	Sai Krishna Potthuri <sai.krishna.potthuri@amd.com>
+M:	Amit Kumar Mahapatra <amit.kumar-mahapatra@amd.com>
 L:	linux-iio@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/iio/adc/xlnx,versal-sysmon.yaml
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 6/6] MAINTAINERS: update Versal SysMon maintainers
  2026-11-02 12:21 ` [PATCH 6/6] MAINTAINERS: update Versal SysMon maintainers Amit Kumar Mahapatra
@ 2026-11-02 12:53   ` Michal Simek
  0 siblings, 0 replies; 9+ messages in thread
From: Michal Simek @ 2026-11-02 12:53 UTC (permalink / raw)
  To: Amit Kumar Mahapatra, Jonathan Cameron, Sai Krishna Potthuri,
	David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, devicetree, linux-arm-kernel, linux-kernel, amitrkcian2002



On 11/2/26 13:21, Amit Kumar Mahapatra wrote:
> Replace Salih Erim with myself as a maintainer of the Versal SysMon
> driver.
> 
> Signed-off-by: Amit Kumar Mahapatra <amit.kumar-mahapatra@amd.com>
> ---
>   MAINTAINERS | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ecc22d1149d1..e3aca3bee13a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -30023,8 +30023,8 @@ F:	drivers/edac/versalnet_edac.c
>   F:	include/linux/cdx/edac_cdx_pcol.h
>   
>   XILINX VERSAL SYSMON DRIVER
> -M:	Salih Erim <salih.erim@amd.com>
>   M:	Sai Krishna Potthuri <sai.krishna.potthuri@amd.com>
> +M:	Amit Kumar Mahapatra <amit.kumar-mahapatra@amd.com>
>   L:	linux-iio@vger.kernel.org
>   S:	Maintained
>   F:	Documentation/devicetree/bindings/iio/adc/xlnx,versal-sysmon.yaml

Acked-by: Michal Simek <michal.simek@amd.com>

Thanks,
Michal

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 5/6] arm64: versal-net: Add SysMon and thermal zone
  2026-11-02 12:21 ` [PATCH 5/6] arm64: versal-net: Add SysMon and thermal zone Amit Kumar Mahapatra
@ 2026-11-02 14:53   ` Michal Simek
  0 siblings, 0 replies; 9+ messages in thread
From: Michal Simek @ 2026-11-02 14:53 UTC (permalink / raw)
  To: Amit Kumar Mahapatra, Jonathan Cameron, Sai Krishna Potthuri,
	David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, devicetree, linux-arm-kernel, linux-kernel, amitrkcian2002



On 11/2/26 13:21, Amit Kumar Mahapatra wrote:
> Describe the System Monitor (SysMon) block in the PMC, which provides
> on-chip voltage and temperature monitoring, and use its device
> temperature channel as the sensor for a thermal zone.
> 
> SysMon channel 0 is the current maximum temperature across all active
> satellites.
> 
> The thermal zone has a critical trip at 125C. Passive trips and cooling
> maps, voltage channels and per-satellite temperature channels depend on
> the design and are left to board files.
> 
> Signed-off-by: Amit Kumar Mahapatra <amit.kumar-mahapatra@amd.com>
> ---
>   arch/arm64/boot/dts/xilinx/versal-net.dtsi | 29 ++++++++++++++++++++++
>   1 file changed, 29 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/xilinx/versal-net.dtsi b/arch/arm64/boot/dts/xilinx/versal-net.dtsi
> index 21bb917bcba1..394181c9a751 100644
> --- a/arch/arm64/boot/dts/xilinx/versal-net.dtsi
> +++ b/arch/arm64/boot/dts/xilinx/versal-net.dtsi
> @@ -735,6 +735,28 @@ versal_fpga: versal-fpga {
>   		compatible = "xlnx,versal-fpga";
>   	};
>   
> +	sysmon_temp: thermal-sensor {
> +		compatible = "generic-adc-thermal";
> +		#thermal-sensor-cells = <0>;
> +		io-channels = <&sysmon0 0>;
> +		io-channel-names = "sensor-channel";
> +	};
> +
> +	thermal-zones {
> +		versal_thermal: versal-thermal {
> +			polling-delay = <1000>; /* milliseconds */
> +			thermal-sensors = <&sysmon_temp>;
> +
> +			trips {
> +				ot_crit: ot-crit {
> +					temperature = <125000>; /* millicelsius */
> +					hysteresis = <0>; /* millicelsius */
> +					type = "critical";
> +				};
> +			};
> +		};
> +	};
> +
>   	amba: axi {
>   		compatible = "simple-bus";
>   		bootph-all;
> @@ -1033,6 +1055,13 @@ spi1: spi@f1970000 {
>   			clock-names = "ref_clk", "pclk";
>   		};
>   
> +		sysmon0: sysmon@f1270000 {
> +			compatible = "xlnx,versal-sysmon";
> +			reg = <0 0xf1270000 0 0x4000>;
> +			interrupts = <0 202 4>;
> +			#io-channel-cells = <1>;
> +		};

This should have status = "disabled"; because I expect it is configuration 
related and it might not be available. (Or not available via MMIO access).

Pretty much this patch should be sent separately. This patch series don't have 
changes in dt binding. That's why it should go via my tree because there is no 
dependency.

Thanks,
Michal



^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-11-02 14:54 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-02 12:21 [PATCH 0/6] iio: adc: versal-sysmon: Add OT alarm, shutdown and thermal zone support Amit Kumar Mahapatra
2026-11-02 12:21 ` [PATCH 1/6] iio: adc: versal-sysmon: fix race in interrupt teardown Amit Kumar Mahapatra
2026-11-02 12:21 ` [PATCH 2/6] iio: adc: versal-sysmon: validate temperature hysteresis Amit Kumar Mahapatra
2026-11-02 12:21 ` [PATCH 3/6] iio: adc: versal-sysmon: disable interrupts on shutdown Amit Kumar Mahapatra
2026-11-02 12:21 ` [PATCH 4/6] iio: adc: versal-sysmon: add over-temperature alarm events Amit Kumar Mahapatra
2026-11-02 12:21 ` [PATCH 5/6] arm64: versal-net: Add SysMon and thermal zone Amit Kumar Mahapatra
2026-11-02 14:53   ` Michal Simek
2026-11-02 12:21 ` [PATCH 6/6] MAINTAINERS: update Versal SysMon maintainers Amit Kumar Mahapatra
2026-11-02 12:53   ` Michal Simek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®