[PATCH 3/5] thermal: renesas: rzg3e: Fix race between set_trips() and get_temp()

From: Ovidiu Panait

Date: Wed Sep 16 2026 - 08:01:46 EST


Datasheet section 7.11.9.2 "Conversion Start Trigger" states that a
conversion must only be started while no other conversion is in
progress:

"Before making the setting to start conversion by software or an ELC
trigger, check that the CONV bit of the sensor status register is 0b."

set_trips() starts a conversion at the end of the function and returns
without waiting for it to finish. A get_temp() call arriving right after
that starts a conversion while the CONV bit may still be set, violating
the requirement above.

Fix this by:
- polling for CONV == 0 in get_temp() before starting a conversion
- not starting a conversion at the end of set_trips() anymore

The conversion started at the end of set_trips() was supposed to check
whether the thresholds have been passed, since the hw cannot raise
interrupts on its own, but only when the temperature is read. However,
the thermal core reads the temperature and computes the trip window from
it just before calling into set_trips(), so reading the temperature again
straight away is useless.

Fixes: dc67521c20b7 ("thermal/drivers/renesas/rzg3e: Fix add thermal driver for the Renesas RZ/G3E SoC")
Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@xxxxxxxxxxx>
---
drivers/thermal/renesas/rzg3e_thermal.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/thermal/renesas/rzg3e_thermal.c b/drivers/thermal/renesas/rzg3e_thermal.c
index 45f67b2e1131..58fdcc66456a 100644
--- a/drivers/thermal/renesas/rzg3e_thermal.c
+++ b/drivers/thermal/renesas/rzg3e_thermal.c
@@ -225,6 +225,16 @@ static int rzg3e_thermal_get_temp(struct thermal_zone_device *tz, int *temp)

guard(mutex)(&priv->lock);

+ /* Make sure a previous conversion is not in progress */
+ ret = readl_poll_timeout(priv->base + TSU_SSR, status,
+ !(status & TSU_SSR_CONV),
+ TSU_POLL_DELAY_US,
+ USEC_PER_MSEC);
+ if (ret) {
+ dev_err(priv->dev, "Timeout waiting for conversion\n");
+ goto out;
+ }
+
/* Clear any previous conversion status */
writel(TSU_SICR_ADCLR, priv->base + TSU_SICR);

@@ -304,9 +314,8 @@ static int rzg3e_thermal_set_trips(struct thermal_zone_device *tz,
/* Enable comparison with "out of range" mode (CMPCOND=0) */
writel(TSU_CMSR_CMPEN, priv->base + TSU_CMSR);

- /* Unmask compare IRQ and start a conversion to evaluate window */
+ /* Unmask compare IRQ */
writel(TSU_SIER_CMPIE, priv->base + TSU_SIER);
- writel(TSU_STRGR_ADST, priv->base + TSU_STRGR);

pm_runtime_mark_last_busy(priv->dev);
pm_runtime_put_autosuspend(priv->dev);
--
2.34.1