Skip to contentSkip to conversation

thermal/drivers/samsung: acpm-tmu: Fixes and cleanups for GS101 TMU

PATCH Applied Tudor Ambarus 3 participants 33 messages Oct 26 – Nov 11

Subsystems (4)
lore
Share & tools
lore

Tudor Ambarus

author maintainer
#0 lore raw

cover thermal/drivers/samsung: acpm-tmu: Fixes and cleanups for GS101 TMU

Hi,

The series is structured with fixes first (patches 1-10) followed by cleanups (patches 11-15), so the fixes can be picked up for the -rc phase if desired. Patches 11-12 are placed immediately after the fixes in case it is also preferred to take the driver and module renames before v7.4 is released.

Thanks,
ta

---
Tudor Ambarus (15):
thermal/drivers/samsung: Select REGMAP_MMIO for EXYNOS_ACPM_THERMAL thermal/drivers/samsung: Depend on PM for EXYNOS_ACPM_THERMAL thermal/drivers/samsung: acpm-tmu: Fix acpm_tmu_resume() error handling thermal/drivers/samsung: acpm-tmu: Disable IRQ across system suspend/resume thermal/drivers/samsung: acpm-tmu: Implement .change_mode() callback thermal/drivers/samsung: acpm-tmu: Rely on devres for probe error and remove teardown thermal/drivers/samsung: acpm-tmu: Return -ENODATA when sensor is disabled thermal/drivers/samsung: acpm-tmu: Annotate lockless sensor->enabled access thermal/drivers/samsung: acpm-tmu: Fix IRQ locking and error handling
MAINTAINERS: Use linux-pm mailing list for Samsung Exynos ACPM thermal driver thermal/drivers/samsung: acpm-tmu: Rename platform driver to "exynos-acpm-tmu" thermal/drivers/samsung: Drop redundant composite object in Makefile thermal/drivers/samsung: acpm-tmu: Disable regmap locking for MMIO INTPEND reads thermal/drivers/samsung: acpm-tmu: Clean up probe error logging thermal/drivers/samsung: acpm-tmu: Simplify pm_runtime_resume_and_get() error checks

 MAINTAINERS                        |   2 +-
 drivers/thermal/samsung/Kconfig    |   2 +
 drivers/thermal/samsung/Makefile   |   3 +-
 drivers/thermal/samsung/acpm-tmu.c | 232 +++++++++++++++----------------------
 4 files changed, 98 insertions(+), 141 deletions(-)

---
base-commit: 7be4bc52fd9e0e55dc9a2e0232b89427d2c4b614
change-id: 20261014-acpm-tmu-fixes-8788d122bf1e

Best regards,

Signature · 1 line
Tudor Ambarus <[email protected]>
author maintainer
#1 lore raw

PATCH 1/15 thermal/drivers/samsung: Select REGMAP_MMIO for EXYNOS_ACPM_THERMAL

The Exynos ACPM TMU driver calls devm_regmap_init_mmio() in acpm_tmu_probe(), which requires CONFIG_REGMAP_MMIO.

When ARCH_EXYNOS is enabled, REGMAP_MMIO is selected transitively via EXYNOS_PMU. However, both the Samsung thermal menu and EXYNOS_ACPM_PROTOCOL allow COMPILE_TEST builds with ARCH_EXYNOS disabled (COMPILE_TEST && !ARCH_EXYNOS), where nothing in EXYNOS_ACPM_THERMAL's dependency chain selects REGMAP_MMIO, resulting in build failures when REGMAP_MMIO is not enabled by another driver.

Select REGMAP_MMIO under config EXYNOS_ACPM_THERMAL.

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/Kconfig | 1 +
 1 file changed, 1 insertion(+)
drivers/thermal/samsung/Kconfig +1 -0
index f63eeae304b7..18ab4ffc8671 100644
@@ -16,6 +16,7 @@ config EXYNOS_ACPM_THERMAL
 	depends on THERMAL_OF
 	depends on HAS_IOMEM
 	depends on EXYNOS_ACPM_PROTOCOL
+	select REGMAP_MMIO
 	default ARCH_EXYNOS
 	help
 	  Support for the Thermal Management Unit (TMU) on Samsung Exynos SoCs
Signature · 1 line
2.56.0.257.gf7497c7d27-goog
#2 lore raw

[thermal: thermal/linux-next] thermal/drivers/samsung: Select REGMAP_MMIO for EXYNOS_ACPM_THERMAL

The following commit has been merged into the thermal/linux-next branch of thermal:

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     e7c21e12c48e95865c85bdf4431e595359d8abf4
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//e7c21e12c48e95865c85bdf4431e595359d8abf4
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:18 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:50 +01:00

thermal/drivers/samsung: Select REGMAP_MMIO for EXYNOS_ACPM_THERMAL

The Exynos ACPM TMU driver calls devm_regmap_init_mmio() in acpm_tmu_probe(), which requires CONFIG_REGMAP_MMIO.

When ARCH_EXYNOS is enabled, REGMAP_MMIO is selected transitively via EXYNOS_PMU. However, both the Samsung thermal menu and EXYNOS_ACPM_PROTOCOL allow COMPILE_TEST builds with ARCH_EXYNOS disabled (COMPILE_TEST && !ARCH_EXYNOS), where nothing in EXYNOS_ACPM_THERMAL's dependency chain selects REGMAP_MMIO, resulting in build failures when REGMAP_MMIO is not enabled by another driver.

Select REGMAP_MMIO under config EXYNOS_ACPM_THERMAL.

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/Kconfig | 1 +
 1 file changed, 1 insertion(+)
drivers/thermal/samsung/Kconfig +1 -0
index f63eeae..18ab4ff 100644
@@ -16,6 +16,7 @@ config EXYNOS_ACPM_THERMAL
 	depends on THERMAL_OF
 	depends on HAS_IOMEM
 	depends on EXYNOS_ACPM_PROTOCOL
+	select REGMAP_MMIO
 	default ARCH_EXYNOS
 	help
 	  Support for the Thermal Management Unit (TMU) on Samsung Exynos SoCs
author maintainer
#3 lore raw

PATCH 2/15 thermal/drivers/samsung: Depend on PM for EXYNOS_ACPM_THERMAL

In reply to Tudor Ambarus

The Exynos ACPM TMU driver only prepares and enables its APB clock (priv->clk) from its runtime PM resume callback (acpm_tmu_runtime_resume()).

Neither ARM64 nor ARCH_EXYNOS selects CONFIG_PM. When CONFIG_PM is disabled, pm_runtime_resume_and_get() is a stub returning 0 without invoking acpm_tmu_runtime_resume(), leaving the APB clock gated when acpm_tmu_thread_fn() reads the memory-mapped INTPEND registers.

Add a PM dependency to EXYNOS_ACPM_THERMAL.

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/Kconfig | 1 +
 1 file changed, 1 insertion(+)
drivers/thermal/samsung/Kconfig +1 -0
index 18ab4ffc8671..b879a63e97c7 100644
@@ -15,6 +15,7 @@ config EXYNOS_ACPM_THERMAL
 	tristate "Exynos ACPM thermal management unit driver"
 	depends on THERMAL_OF
 	depends on HAS_IOMEM
+	depends on PM
 	depends on EXYNOS_ACPM_PROTOCOL
 	select REGMAP_MMIO
 	default ARCH_EXYNOS
Signature · 1 line
2.56.0.257.gf7497c7d27-goog
#4 lore raw

[thermal: thermal/linux-next] thermal/drivers/samsung: Depend on PM for EXYNOS_ACPM_THERMAL

The following commit has been merged into the thermal/linux-next branch of thermal:

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     91bd8661501baae56980c0a3406774eacf4e645a
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//91bd8661501baae56980c0a3406774eacf4e645a
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:19 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:50 +01:00

thermal/drivers/samsung: Depend on PM for EXYNOS_ACPM_THERMAL

The Exynos ACPM TMU driver only prepares and enables its APB clock (priv->clk) from its runtime PM resume callback (acpm_tmu_runtime_resume()).

Neither ARM64 nor ARCH_EXYNOS selects CONFIG_PM. When CONFIG_PM is disabled, pm_runtime_resume_and_get() is a stub returning 0 without invoking acpm_tmu_runtime_resume(), leaving the APB clock gated when acpm_tmu_thread_fn() reads the memory-mapped INTPEND registers.

Add a PM dependency to EXYNOS_ACPM_THERMAL.

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/Kconfig | 1 +
 1 file changed, 1 insertion(+)
drivers/thermal/samsung/Kconfig +1 -0
index 18ab4ff..b879a63 100644
@@ -15,6 +15,7 @@ config EXYNOS_ACPM_THERMAL
 	tristate "Exynos ACPM thermal management unit driver"
 	depends on THERMAL_OF
 	depends on HAS_IOMEM
+	depends on PM
 	depends on EXYNOS_ACPM_PROTOCOL
 	select REGMAP_MMIO
 	default ARCH_EXYNOS
author maintainer
#5 lore raw

PATCH 3/15 thermal/drivers/samsung: acpm-tmu: Fix acpm_tmu_resume() error handling

In reply to Tudor Ambarus

Unlike .suspend(), system resume cannot be aborted: device_resume() clears dev->power.is_suspended before invoking .resume(), and on error merely logs the failure and continues into normal system operation without re-enabling runtime PM on the driver's behalf.

acpm_tmu_resume() treats errors by rolling back into a suspended state, causing three problems:
1. acpm_tmu_suspend() disables runtime PM via pm_runtime_force_suspend(). If ops->resume() fails before pm_runtime_force_resume() runs, or if acpm_tmu_control() fails and the rollback path calls pm_runtime_force_suspend(), dev->power.disable_depth remains at 1 with the device runtime-suspended. Every subsequent pm_runtime_resume_and_get() then fails with -EACCES, breaking thermal zone operations and causing future system suspends to abort in acpm_tmu_suspend().
2. Calling ops->suspend() on error leaves the ACPM TMU firmware in the suspended state while Linux considers the device awake, so subsequent thermal zone operations run against suspended firmware and the next acpm_tmu_suspend() issues an unbalanced ops->suspend() call.
3. Rolling back sensors via acpm_tmu_control_rollback() when a single sensor fails to re-enable disables sensors that already resumed and skips remaining sensors, leaving active CPU clusters without thermal monitoring.

Mirror acpm_tmu_suspend() in reverse order by calling pm_runtime_force_resume() at the start of acpm_tmu_resume(), and drop the pm_runtime_force_suspend() and ops->suspend() error rollback paths. Re-enable sensors on a best-effort basis so any sensor that fails remains marked !sensor->enabled for the thermal core's post-resume update, and drop the now-unused rollback parameter from acpm_tmu_control().

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/acpm-tmu.c | 48 ++++++++++----------------------------
 1 file changed, 12 insertions(+), 36 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +12 -36
index f9802080acd7..f490551de69a 100644
@@ -172,7 +172,7 @@ static void acpm_tmu_control_rollback(struct acpm_tmu_priv *priv, int start_idx)
 	}
 }
 
-static int acpm_tmu_control(struct acpm_tmu_priv *priv, bool on, bool rollback)
+static int acpm_tmu_control(struct acpm_tmu_priv *priv, bool on)
 {
 	struct device *dev = priv->dev;
 	int i, ret, err = 0;
@@ -191,16 +191,8 @@ static int acpm_tmu_control(struct acpm_tmu_priv *priv, bool on, bool rollback)
 		mutex_lock(&sensor->lock);
 		ret = acpm_tmu_op_tz_control(sensor, on);
 		mutex_unlock(&sensor->lock);
-		if (ret) {
-			if (!err)
-				err = ret;
-
-			/* On enable, stop on first error if rollback is requested */
-			if (on && rollback) {
-				acpm_tmu_control_rollback(priv, i - 1);
-				break;
-			}
-		}
+		if (ret && !err)
+			err = ret;
 	}
 
 	pm_runtime_put_sync(dev);
@@ -539,7 +531,7 @@ static void acpm_tmu_remove(struct platform_device *pdev)
 	 * immediately, preventing clock leaks when the driver is removed.
 	 */
 	pm_runtime_dont_use_autosuspend(&pdev->dev);
-	acpm_tmu_control(priv, false, false);
+	acpm_tmu_control(priv, false);
 }
 
 static int acpm_tmu_suspend(struct device *dev)
@@ -549,7 +541,7 @@ static int acpm_tmu_suspend(struct device *dev)
 	const struct acpm_tmu_ops *ops = &handle->ops->tmu;
 	int ret, restore_ret;
 
-	ret = acpm_tmu_control(priv, false, false);
+	ret = acpm_tmu_control(priv, false);
 	if (ret)
 		goto err_restore_sensors;
 
@@ -571,7 +563,7 @@ static int acpm_tmu_suspend(struct device *dev)
 			restore_ret);
 
 err_restore_sensors:
-	restore_ret = acpm_tmu_control(priv, true, false);
+	restore_ret = acpm_tmu_control(priv, true);
 	if (restore_ret)
 		dev_err(dev, "Failed to re-enable TMU after suspend failure: %d\n",
 			restore_ret);
@@ -584,34 +576,18 @@ static int acpm_tmu_resume(struct device *dev)
 	struct acpm_tmu_priv *priv = dev_get_drvdata(dev);
 	struct acpm_handle *handle = priv->handle;
 	const struct acpm_tmu_ops *ops = &handle->ops->tmu;
-	int ret, restore_ret;
-
-	/* APB clock not required for this specific msg */
-	ret = ops->resume(handle, priv->mbox_chan_id);
-	if (ret)
-		return ret;
+	int ret;
 
 	ret = pm_runtime_force_resume(dev);
 	if (ret)
-		goto err_suspend_acpm;
+		return ret;
 
-	ret = acpm_tmu_control(priv, true, true);
+	/* APB clock not required for this specific msg */
+	ret = ops->resume(handle, priv->mbox_chan_id);
 	if (ret)
-		goto err_suspend_pm;
-
-	return 0;
+		return ret;
 
-err_suspend_pm:
-	restore_ret = pm_runtime_force_suspend(dev);
-	if (restore_ret)
-		dev_err(dev, "Failed to force suspend during resume rollback: %d\n",
-			restore_ret);
-err_suspend_acpm:
-	restore_ret = ops->suspend(handle, priv->mbox_chan_id);
-	if (restore_ret)
-		dev_err(dev, "Failed to suspend ACPM during resume rollback: %d\n",
-			restore_ret);
-	return ret;
+	return acpm_tmu_control(priv, true);
 }
 
 static int acpm_tmu_runtime_suspend(struct device *dev)
Signature · 1 line
2.56.0.257.gf7497c7d27-goog
#6 lore raw

[thermal: thermal/linux-next] thermal/drivers/samsung: acpm-tmu: Fix acpm_tmu_resume() error handling

The following commit has been merged into the thermal/linux-next branch of thermal:

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     2cc5bc4c8be4c83211ddeb0fe38d46d7f239b85f
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//2cc5bc4c8be4c83211ddeb0fe38d46d7f239b85f
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:20 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:50 +01:00

thermal/drivers/samsung: acpm-tmu: Fix acpm_tmu_resume() error handling

Unlike .suspend(), system resume cannot be aborted: device_resume() clears dev->power.is_suspended before invoking .resume(), and on error merely logs the failure and continues into normal system operation without re-enabling runtime PM on the driver's behalf.

acpm_tmu_resume() treats errors by rolling back into a suspended state, causing three problems:
1. acpm_tmu_suspend() disables runtime PM via pm_runtime_force_suspend(). If ops->resume() fails before pm_runtime_force_resume() runs, or if acpm_tmu_control() fails and the rollback path calls pm_runtime_force_suspend(), dev->power.disable_depth remains at 1 with the device runtime-suspended. Every subsequent pm_runtime_resume_and_get() then fails with -EACCES, breaking thermal zone operations and causing future system suspends to abort in acpm_tmu_suspend().
2. Calling ops->suspend() on error leaves the ACPM TMU firmware in the suspended state while Linux considers the device awake, so subsequent thermal zone operations run against suspended firmware and the next acpm_tmu_suspend() issues an unbalanced ops->suspend() call.
3. Rolling back sensors via acpm_tmu_control_rollback() when a single sensor fails to re-enable disables sensors that already resumed and skips remaining sensors, leaving active CPU clusters without thermal monitoring.

Mirror acpm_tmu_suspend() in reverse order by calling pm_runtime_force_resume() at the start of acpm_tmu_resume(), and drop the pm_runtime_force_suspend() and ops->suspend() error rollback paths. Re-enable sensors on a best-effort basis so any sensor that fails remains marked !sensor->enabled for the thermal core's post-resume update, and drop the now-unused rollback parameter from acpm_tmu_control().

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/acpm-tmu.c | 48 +++++++----------------------
 1 file changed, 12 insertions(+), 36 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +12 -36
index f980208..f490551 100644
@@ -172,7 +172,7 @@ static void acpm_tmu_control_rollback(struct acpm_tmu_priv *priv, int start_idx)
 	}
 }
 
-static int acpm_tmu_control(struct acpm_tmu_priv *priv, bool on, bool rollback)
+static int acpm_tmu_control(struct acpm_tmu_priv *priv, bool on)
 {
 	struct device *dev = priv->dev;
 	int i, ret, err = 0;
@@ -191,16 +191,8 @@ static int acpm_tmu_control(struct acpm_tmu_priv *priv, bool on, bool rollback)
 		mutex_lock(&sensor->lock);
 		ret = acpm_tmu_op_tz_control(sensor, on);
 		mutex_unlock(&sensor->lock);
-		if (ret) {
-			if (!err)
-				err = ret;
-
-			/* On enable, stop on first error if rollback is requested */
-			if (on && rollback) {
-				acpm_tmu_control_rollback(priv, i - 1);
-				break;
-			}
-		}
+		if (ret && !err)
+			err = ret;
 	}
 
 	pm_runtime_put_sync(dev);
@@ -539,7 +531,7 @@ static void acpm_tmu_remove(struct platform_device *pdev)
 	 * immediately, preventing clock leaks when the driver is removed.
 	 */
 	pm_runtime_dont_use_autosuspend(&pdev->dev);
-	acpm_tmu_control(priv, false, false);
+	acpm_tmu_control(priv, false);
 }
 
 static int acpm_tmu_suspend(struct device *dev)
@@ -549,7 +541,7 @@ static int acpm_tmu_suspend(struct device *dev)
 	const struct acpm_tmu_ops *ops = &handle->ops->tmu;
 	int ret, restore_ret;
 
-	ret = acpm_tmu_control(priv, false, false);
+	ret = acpm_tmu_control(priv, false);
 	if (ret)
 		goto err_restore_sensors;
 
@@ -571,7 +563,7 @@ err_resume_acpm:
 			restore_ret);
 
 err_restore_sensors:
-	restore_ret = acpm_tmu_control(priv, true, false);
+	restore_ret = acpm_tmu_control(priv, true);
 	if (restore_ret)
 		dev_err(dev, "Failed to re-enable TMU after suspend failure: %d\n",
 			restore_ret);
@@ -584,34 +576,18 @@ static int acpm_tmu_resume(struct device *dev)
 	struct acpm_tmu_priv *priv = dev_get_drvdata(dev);
 	struct acpm_handle *handle = priv->handle;
 	const struct acpm_tmu_ops *ops = &handle->ops->tmu;
-	int ret, restore_ret;
-
-	/* APB clock not required for this specific msg */
-	ret = ops->resume(handle, priv->mbox_chan_id);
-	if (ret)
-		return ret;
+	int ret;
 
 	ret = pm_runtime_force_resume(dev);
 	if (ret)
-		goto err_suspend_acpm;
+		return ret;
 
-	ret = acpm_tmu_control(priv, true, true);
+	/* APB clock not required for this specific msg */
+	ret = ops->resume(handle, priv->mbox_chan_id);
 	if (ret)
-		goto err_suspend_pm;
-
-	return 0;
+		return ret;
 
-err_suspend_pm:
-	restore_ret = pm_runtime_force_suspend(dev);
-	if (restore_ret)
-		dev_err(dev, "Failed to force suspend during resume rollback: %d\n",
-			restore_ret);
-err_suspend_acpm:
-	restore_ret = ops->suspend(handle, priv->mbox_chan_id);
-	if (restore_ret)
-		dev_err(dev, "Failed to suspend ACPM during resume rollback: %d\n",
-			restore_ret);
-	return ret;
+	return acpm_tmu_control(priv, true);
 }
 
 static int acpm_tmu_runtime_suspend(struct device *dev)
author maintainer
#7 lore raw

PATCH 4/15 thermal/drivers/samsung: acpm-tmu: Disable IRQ across system suspend/resume

In reply to Tudor Ambarus

The PM core masks device IRQs in dpm_suspend_noirq() and unmasks them in dpm_resume_noirq(), leaving the TMU interrupt enabled after acpm_tmu_suspend() and before acpm_tmu_resume() while runtime PM is disabled and PCLK is gated:

1. If acpm_tmu_thread_fn() runs in that window, pm_runtime_resume_and_get() fails with -EACCES and returns IRQ_NONE without clearing the level-high hardware interrupt, triggering an unhandled IRQF_ONESHOT interrupt storm when the line is unmasked.
2. If acpm_tmu_thread_fn() is already running when acpm_tmu_suspend() executes, pm_runtime_force_suspend() ignores usage_count and gates PCLK underneath MMIO INTPEND reads.

Call disable_irq() at the start of acpm_tmu_suspend() to mask and synchronize the interrupt before tearing down sensors and runtime PM, and re-enable it with enable_irq() on acpm_tmu_suspend() rollback and before returning from acpm_tmu_resume().

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/acpm-tmu.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +12 -3
index f490551de69a..55ee97218f47 100644
@@ -541,6 +541,8 @@ static int acpm_tmu_suspend(struct device *dev)
 	const struct acpm_tmu_ops *ops = &handle->ops->tmu;
 	int ret, restore_ret;
 
+	disable_irq(priv->irq);
+
 	ret = acpm_tmu_control(priv, false);
 	if (ret)
 		goto err_restore_sensors;
@@ -568,6 +570,8 @@ static int acpm_tmu_suspend(struct device *dev)
 		dev_err(dev, "Failed to re-enable TMU after suspend failure: %d\n",
 			restore_ret);
 
+	enable_irq(priv->irq);
+
 	return ret;
 }
 
@@ -580,14 +584,19 @@ static int acpm_tmu_resume(struct device *dev)
 
 	ret = pm_runtime_force_resume(dev);
 	if (ret)
-		return ret;
+		goto out_enable_irq;
 
 	/* APB clock not required for this specific msg */
 	ret = ops->resume(handle, priv->mbox_chan_id);
 	if (ret)
-		return ret;
+		goto out_enable_irq;
+
+	ret = acpm_tmu_control(priv, true);
 
-	return acpm_tmu_control(priv, true);
+out_enable_irq:
+	enable_irq(priv->irq);
+
+	return ret;
 }
 
 static int acpm_tmu_runtime_suspend(struct device *dev)
Signature · 1 line
2.56.0.257.gf7497c7d27-goog
#8 lore raw

[thermal: thermal/linux-next] thermal/drivers/samsung: acpm-tmu: Disable IRQ across system suspend/resume

The following commit has been merged into the thermal/linux-next branch of thermal:

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     e0e2dbdc45f208c1d14cf891175378e93dde5098
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//e0e2dbdc45f208c1d14cf891175378e93dde5098
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:21 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:50 +01:00

thermal/drivers/samsung: acpm-tmu: Disable IRQ across system suspend/resume

The PM core masks device IRQs in dpm_suspend_noirq() and unmasks them in dpm_resume_noirq(), leaving the TMU interrupt enabled after acpm_tmu_suspend() and before acpm_tmu_resume() while runtime PM is disabled and PCLK is gated:

1. If acpm_tmu_thread_fn() runs in that window, pm_runtime_resume_and_get() fails with -EACCES and returns IRQ_NONE without clearing the level-high hardware interrupt, triggering an unhandled IRQF_ONESHOT interrupt storm when the line is unmasked.
2. If acpm_tmu_thread_fn() is already running when acpm_tmu_suspend() executes, pm_runtime_force_suspend() ignores usage_count and gates PCLK underneath MMIO INTPEND reads.

Call disable_irq() at the start of acpm_tmu_suspend() to mask and synchronize the interrupt before tearing down sensors and runtime PM, and re-enable it with enable_irq() on acpm_tmu_suspend() rollback and before returning from acpm_tmu_resume().

---
 drivers/thermal/samsung/acpm-tmu.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +12 -3
index f490551..55ee972 100644
@@ -541,6 +541,8 @@ static int acpm_tmu_suspend(struct device *dev)
 	const struct acpm_tmu_ops *ops = &handle->ops->tmu;
 	int ret, restore_ret;
 
+	disable_irq(priv->irq);
+
 	ret = acpm_tmu_control(priv, false);
 	if (ret)
 		goto err_restore_sensors;
@@ -568,6 +570,8 @@ err_restore_sensors:
 		dev_err(dev, "Failed to re-enable TMU after suspend failure: %d\n",
 			restore_ret);
 
+	enable_irq(priv->irq);
+
 	return ret;
 }
 
@@ -580,14 +584,19 @@ static int acpm_tmu_resume(struct device *dev)
 
 	ret = pm_runtime_force_resume(dev);
 	if (ret)
-		return ret;
+		goto out_enable_irq;
 
 	/* APB clock not required for this specific msg */
 	ret = ops->resume(handle, priv->mbox_chan_id);
 	if (ret)
-		return ret;
+		goto out_enable_irq;
+
+	ret = acpm_tmu_control(priv, true);
 
-	return acpm_tmu_control(priv, true);
+out_enable_irq:
+	enable_irq(priv->irq);
+
+	return ret;
 }
 
 static int acpm_tmu_runtime_suspend(struct device *dev)
author maintainer
#9 lore raw

PATCH 5/15 thermal/drivers/samsung: acpm-tmu: Implement .change_mode() callback

In reply to Tudor Ambarus

Because acpm-tmu did not implement the .change_mode() callback and instead enabled the hardware sensor manually after registration, the hardware sensor state was out of sync with the thermal core:

1. Disabling a thermal zone (e.g. via /sys/class/thermal/thermal_zone*/mode or thermal_of_zone_unregister()) only set tz->mode to THERMAL_DEVICE_DISABLED and stopped software polling, while leaving sensor->enabled true and the ACPM TMU sensor active in hardware. Consequently, crossing a trip threshold still fired the hardware IRQ and ran acpm_tmu_thread_fn(), where thermal_zone_device_update() returned early without updating the trip window. Direct sysfs and hwmon temperature reads via thermal_zone_get_temp() also continued to resume the device and query ACPM over IPC on a disabled zone.
2. System suspend/resume paths in acpm_tmu_control() unconditionally toggled all registered sensors without checking the thermal zone mode or current hardware state. As a result, acpm_tmu_suspend() issued redundant disable IPC calls for already-disabled zones, acpm_tmu_resume() unconditionally re-enabled zones that had been disabled via sysfs prior to suspend, and suspend error recovery sent redundant enable IPC calls to sensors that had not yet been disabled.
3. devm_thermal_of_zone_register() enables the zone and triggers an initial thermal_zone_device_update() before returning. Because sensor->enabled was still false during registration, the initial acpm_tmu_get_temp() call failed with -EAGAIN and scheduled a retry, requiring a manual sensor enable and a second thermal_zone_device_update() call in acpm_tmu_probe().

Implement the .change_mode() callback to manage sensor hardware state transitions directly through the thermal core and record the requested zone mode in sensor->mode. Update acpm_tmu_control() to only toggle sensors whose zone mode is THERMAL_DEVICE_ENABLED and whose sensor->enabled state differs from the target state. Drop the redundant manual sensor enablement and thermal_zone_device_update() call from acpm_tmu_probe().

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/acpm-tmu.c | 59 ++++++++++++++++++++++++++------------
 1 file changed, 40 insertions(+), 19 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +40 -19
index 55ee97218f47..69793fce3bf1 100644
@@ -68,6 +68,7 @@ struct acpm_tmu_sensor {
 	struct thermal_zone_device *tzd;
 	struct acpm_tmu_priv *priv;
 	struct mutex lock; /* protects sensor state */
+	enum thermal_device_mode mode;
 	bool enabled;
 };
 
@@ -188,9 +189,12 @@ static int acpm_tmu_control(struct acpm_tmu_priv *priv, bool on)
 		if (!sensor->tzd)
 			continue;
 
-		mutex_lock(&sensor->lock);
-		ret = acpm_tmu_op_tz_control(sensor, on);
-		mutex_unlock(&sensor->lock);
+		scoped_guard(mutex, &sensor->lock) {
+			ret = 0;
+			if (sensor->mode == THERMAL_DEVICE_ENABLED &&
+			    sensor->enabled != on)
+				ret = acpm_tmu_op_tz_control(sensor, on);
+		}
 		if (ret && !err)
 			err = ret;
 	}
@@ -313,7 +317,34 @@ static int acpm_tmu_set_trips(struct thermal_zone_device *tz, int low, int high)
 	return ret;
 }
 
+static int acpm_tmu_change_mode(struct thermal_zone_device *tz,
+				enum thermal_device_mode mode)
+{
+	struct acpm_tmu_sensor *sensor = thermal_zone_device_priv(tz);
+	struct acpm_tmu_priv *priv = sensor->priv;
+	struct device *dev = priv->dev;
+	bool enable = (mode == THERMAL_DEVICE_ENABLED);
+	int ret;
+
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret)
+		return ret;
+
+	scoped_guard(mutex, &sensor->lock) {
+		ret = 0;
+		if (sensor->enabled != enable)
+			ret = acpm_tmu_op_tz_control(sensor, enable);
+		if (!ret)
+			sensor->mode = mode;
+	}
+
+	pm_runtime_put_autosuspend(dev);
+
+	return ret;
+}
+
 static const struct thermal_zone_device_ops acpm_tmu_sensor_ops = {
+	.change_mode = acpm_tmu_change_mode,
 	.get_temp = acpm_tmu_get_temp,
 	.set_trips = acpm_tmu_set_trips,
 };
@@ -463,17 +494,17 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 
 	for (i = 0; i < priv->num_sensors; i++) {
 		struct acpm_tmu_sensor *sensor = &priv->sensors[i];
+		struct thermal_zone_device *tzd;
 
 		mutex_init(&sensor->lock);
 		sensor->group = &data->sensor_groups[i];
 		sensor->priv = priv;
 
-		sensor->tzd = devm_thermal_of_zone_register(dev, i, sensor,
-							    &acpm_tmu_sensor_ops);
-		if (IS_ERR(sensor->tzd)) {
-			ret = PTR_ERR(sensor->tzd);
+		tzd = devm_thermal_of_zone_register(dev, i, sensor,
+						    &acpm_tmu_sensor_ops);
+		if (IS_ERR(tzd)) {
+			ret = PTR_ERR(tzd);
 			if (ret == -ENODEV) {
-				sensor->tzd = NULL;
 				dev_dbg(dev, "Sensor %d not used in DT, skipping\n", i);
 				continue;
 			}
@@ -481,17 +512,7 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 			ret = dev_err_probe(dev, ret, "Failed to register sensor %d\n", i);
 			goto err_rollback;
 		}
-
-		mutex_lock(&sensor->lock);
-		ret = acpm_tmu_op_tz_control(sensor, true);
-		mutex_unlock(&sensor->lock);
-		if (ret) {
-			ret = dev_err_probe(dev, ret, "Failed to enable sensor %d\n", i);
-			goto err_rollback;
-		}
-
-		thermal_zone_device_update(sensor->tzd,
-					   THERMAL_EVENT_UNSPECIFIED);
+		sensor->tzd = tzd;
 
 		ret = devm_thermal_add_hwmon_sysfs(dev, sensor->tzd);
 		if (ret)
Signature · 1 line
2.56.0.257.gf7497c7d27-goog
#10 lore raw

[thermal: thermal/linux-next] thermal/drivers/samsung: acpm-tmu: Implement .change_mode() callback

The following commit has been merged into the thermal/linux-next branch of thermal:

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     09e928b13aaddbefc08aeca13b1a78bd8b0feb14
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//09e928b13aaddbefc08aeca13b1a78bd8b0feb14
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:22 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:50 +01:00

thermal/drivers/samsung: acpm-tmu: Implement .change_mode() callback

Because acpm-tmu did not implement the .change_mode() callback and instead enabled the hardware sensor manually after registration, the hardware sensor state was out of sync with the thermal core:

1. Disabling a thermal zone (e.g. via /sys/class/thermal/thermal_zone*/mode or thermal_of_zone_unregister()) only set tz->mode to THERMAL_DEVICE_DISABLED and stopped software polling, while leaving sensor->enabled true and the ACPM TMU sensor active in hardware. Consequently, crossing a trip threshold still fired the hardware IRQ and ran acpm_tmu_thread_fn(), where thermal_zone_device_update() returned early without updating the trip window. Direct sysfs and hwmon temperature reads via thermal_zone_get_temp() also continued to resume the device and query ACPM over IPC on a disabled zone.
2. System suspend/resume paths in acpm_tmu_control() unconditionally toggled all registered sensors without checking the thermal zone mode or current hardware state. As a result, acpm_tmu_suspend() issued redundant disable IPC calls for already-disabled zones, acpm_tmu_resume() unconditionally re-enabled zones that had been disabled via sysfs prior to suspend, and suspend error recovery sent redundant enable IPC calls to sensors that had not yet been disabled.
3. devm_thermal_of_zone_register() enables the zone and triggers an initial thermal_zone_device_update() before returning. Because sensor->enabled was still false during registration, the initial acpm_tmu_get_temp() call failed with -EAGAIN and scheduled a retry, requiring a manual sensor enable and a second thermal_zone_device_update() call in acpm_tmu_probe().

Implement the .change_mode() callback to manage sensor hardware state transitions directly through the thermal core and record the requested zone mode in sensor->mode. Update acpm_tmu_control() to only toggle sensors whose zone mode is THERMAL_DEVICE_ENABLED and whose sensor->enabled state differs from the target state. Drop the redundant manual sensor enablement and thermal_zone_device_update() call from acpm_tmu_probe().

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/acpm-tmu.c | 59 +++++++++++++++++++----------
 1 file changed, 40 insertions(+), 19 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +40 -19
index 55ee972..69793fc 100644
@@ -68,6 +68,7 @@ struct acpm_tmu_sensor {
 	struct thermal_zone_device *tzd;
 	struct acpm_tmu_priv *priv;
 	struct mutex lock; /* protects sensor state */
+	enum thermal_device_mode mode;
 	bool enabled;
 };
 
@@ -188,9 +189,12 @@ static int acpm_tmu_control(struct acpm_tmu_priv *priv, bool on)
 		if (!sensor->tzd)
 			continue;
 
-		mutex_lock(&sensor->lock);
-		ret = acpm_tmu_op_tz_control(sensor, on);
-		mutex_unlock(&sensor->lock);
+		scoped_guard(mutex, &sensor->lock) {
+			ret = 0;
+			if (sensor->mode == THERMAL_DEVICE_ENABLED &&
+			    sensor->enabled != on)
+				ret = acpm_tmu_op_tz_control(sensor, on);
+		}
 		if (ret && !err)
 			err = ret;
 	}
@@ -313,7 +317,34 @@ static int acpm_tmu_set_trips(struct thermal_zone_device *tz, int low, int high)
 	return ret;
 }
 
+static int acpm_tmu_change_mode(struct thermal_zone_device *tz,
+				enum thermal_device_mode mode)
+{
+	struct acpm_tmu_sensor *sensor = thermal_zone_device_priv(tz);
+	struct acpm_tmu_priv *priv = sensor->priv;
+	struct device *dev = priv->dev;
+	bool enable = (mode == THERMAL_DEVICE_ENABLED);
+	int ret;
+
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret)
+		return ret;
+
+	scoped_guard(mutex, &sensor->lock) {
+		ret = 0;
+		if (sensor->enabled != enable)
+			ret = acpm_tmu_op_tz_control(sensor, enable);
+		if (!ret)
+			sensor->mode = mode;
+	}
+
+	pm_runtime_put_autosuspend(dev);
+
+	return ret;
+}
+
 static const struct thermal_zone_device_ops acpm_tmu_sensor_ops = {
+	.change_mode = acpm_tmu_change_mode,
 	.get_temp = acpm_tmu_get_temp,
 	.set_trips = acpm_tmu_set_trips,
 };
@@ -463,17 +494,17 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 
 	for (i = 0; i < priv->num_sensors; i++) {
 		struct acpm_tmu_sensor *sensor = &priv->sensors[i];
+		struct thermal_zone_device *tzd;
 
 		mutex_init(&sensor->lock);
 		sensor->group = &data->sensor_groups[i];
 		sensor->priv = priv;
 
-		sensor->tzd = devm_thermal_of_zone_register(dev, i, sensor,
-							    &acpm_tmu_sensor_ops);
-		if (IS_ERR(sensor->tzd)) {
-			ret = PTR_ERR(sensor->tzd);
+		tzd = devm_thermal_of_zone_register(dev, i, sensor,
+						    &acpm_tmu_sensor_ops);
+		if (IS_ERR(tzd)) {
+			ret = PTR_ERR(tzd);
 			if (ret == -ENODEV) {
-				sensor->tzd = NULL;
 				dev_dbg(dev, "Sensor %d not used in DT, skipping\n", i);
 				continue;
 			}
@@ -481,17 +512,7 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 			ret = dev_err_probe(dev, ret, "Failed to register sensor %d\n", i);
 			goto err_rollback;
 		}
-
-		mutex_lock(&sensor->lock);
-		ret = acpm_tmu_op_tz_control(sensor, true);
-		mutex_unlock(&sensor->lock);
-		if (ret) {
-			ret = dev_err_probe(dev, ret, "Failed to enable sensor %d\n", i);
-			goto err_rollback;
-		}
-
-		thermal_zone_device_update(sensor->tzd,
-					   THERMAL_EVENT_UNSPECIFIED);
+		sensor->tzd = tzd;
 
 		ret = devm_thermal_add_hwmon_sysfs(dev, sensor->tzd);
 		if (ret)
author maintainer
#11 lore raw

PATCH 6/15 thermal/drivers/samsung: acpm-tmu: Rely on devres for probe error and remove teardown

In reply to Tudor Ambarus

Disabling sensors manually on acpm_tmu_probe() failure or in acpm_tmu_remove() happens before devres unregisters the thermal zones, leaving live zones backed by disabled hardware.

With .change_mode() implemented, devres tears down the IRQ, thermal zones, and runtime PM in reverse registration order:
devm_thermal_of_zone_release() disables each sensor via thermal_zone_device_disable(), and devm_pm_runtime_enable() disables autosuspend and runtime PM.

Drop acpm_tmu_remove(), acpm_tmu_control_rollback(), and the manual teardown in acpm_tmu_probe(), and switch acpm_tmu_control() to pm_runtime_put_autosuspend() since pm_runtime_put_sync() was only needed by acpm_tmu_remove().

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/acpm-tmu.c | 56 ++++----------------------------------
 1 file changed, 5 insertions(+), 51 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +5 -51
index 69793fce3bf1..4257bec802c1 100644
@@ -153,26 +153,6 @@ static int acpm_tmu_op_tz_control(struct acpm_tmu_sensor *sensor, bool on)
 	return 0;
 }
 
-static void acpm_tmu_control_rollback(struct acpm_tmu_priv *priv, int start_idx)
-{
-	int i;
-
-	for (i = start_idx; i >= 0; i--) {
-		struct acpm_tmu_sensor *sensor = &priv->sensors[i];
-		int ret;
-
-		if (!sensor->tzd)
-			continue;
-
-		mutex_lock(&sensor->lock);
-		ret = acpm_tmu_op_tz_control(sensor, false);
-		mutex_unlock(&sensor->lock);
-		if (ret)
-			dev_err(priv->dev, "Rollback: Failed to disable sensor %d: %d\n",
-				i, ret);
-	}
-}
-
 static int acpm_tmu_control(struct acpm_tmu_priv *priv, bool on)
 {
 	struct device *dev = priv->dev;
@@ -199,7 +179,7 @@ static int acpm_tmu_control(struct acpm_tmu_priv *priv, bool on)
 			err = ret;
 	}
 
-	pm_runtime_put_sync(dev);
+	pm_runtime_put_autosuspend(dev);
 
 	return err;
 }
@@ -489,7 +469,7 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 	ret = acpm_handle->ops->tmu.init(acpm_handle, priv->mbox_chan_id);
 	if (ret) {
 		ret = dev_err_probe(dev, ret, "Failed to init TMU\n");
-		goto err_pm_put;
+		goto out_pm_put;
 	}
 
 	for (i = 0; i < priv->num_sensors; i++) {
@@ -510,7 +490,7 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 			}
 
 			ret = dev_err_probe(dev, ret, "Failed to register sensor %d\n", i);
-			goto err_rollback;
+			goto out_pm_put;
 		}
 		sensor->tzd = tzd;
 
@@ -522,39 +502,14 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 	ret = devm_request_threaded_irq(dev, priv->irq, NULL,
 					acpm_tmu_thread_fn, IRQF_ONESHOT,
 					dev_name(dev), priv);
-	if (ret) {
+	if (ret)
 		ret = dev_err_probe(dev, ret, "Failed to request irq\n");
-		goto err_rollback;
-	}
 
+out_pm_put:
 	pm_runtime_put_autosuspend(dev);
-
-	return 0;
-
-err_rollback:
-	acpm_tmu_control_rollback(priv, i - 1);
-err_pm_put:
-	pm_runtime_dont_use_autosuspend(dev);
-	pm_runtime_put_sync(dev);
 	return ret;
 }
 
-static void acpm_tmu_remove(struct platform_device *pdev)
-{
-	struct acpm_tmu_priv *priv = platform_get_drvdata(pdev);
-
-	/* Stop IRQ first to prevent race with thread_fn */
-	disable_irq(priv->irq);
-
-	/*
-	 * Disable autosuspend to force the subsequent pm_runtime_put_sync()
-	 * inside acpm_tmu_control() to synchronously suspend the device
-	 * immediately, preventing clock leaks when the driver is removed.
-	 */
-	pm_runtime_dont_use_autosuspend(&pdev->dev);
-	acpm_tmu_control(priv, false);
-}
-
 static int acpm_tmu_suspend(struct device *dev)
 {
 	struct acpm_tmu_priv *priv = dev_get_drvdata(dev);
@@ -648,7 +603,6 @@ static struct platform_driver acpm_tmu_driver = {
 		.of_match_table = acpm_tmu_match,
 	},
 	.probe = acpm_tmu_probe,
-	.remove = acpm_tmu_remove,
 };
 module_platform_driver(acpm_tmu_driver);
 
Signature · 1 line
2.56.0.257.gf7497c7d27-goog
#12 lore raw

[thermal: thermal/linux-next] thermal/drivers/samsung: acpm-tmu: Rely on devres for probe error and remove teardown

The following commit has been merged into the thermal/linux-next branch of thermal:

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     3980362b31bf935b778dea1a8d90590ecef82e8d
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//3980362b31bf935b778dea1a8d90590ecef82e8d
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:23 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:50 +01:00

thermal/drivers/samsung: acpm-tmu: Rely on devres for probe error and remove teardown

Disabling sensors manually on acpm_tmu_probe() failure or in acpm_tmu_remove() happens before devres unregisters the thermal zones, leaving live zones backed by disabled hardware.

With .change_mode() implemented, devres tears down the IRQ, thermal zones, and runtime PM in reverse registration order:
devm_thermal_of_zone_release() disables each sensor via thermal_zone_device_disable(), and devm_pm_runtime_enable() disables autosuspend and runtime PM.

Drop acpm_tmu_remove(), acpm_tmu_control_rollback(), and the manual teardown in acpm_tmu_probe(), and switch acpm_tmu_control() to pm_runtime_put_autosuspend() since pm_runtime_put_sync() was only needed by acpm_tmu_remove().

---
 drivers/thermal/samsung/acpm-tmu.c | 56 ++---------------------------
 1 file changed, 5 insertions(+), 51 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +5 -51
index 69793fc..4257bec 100644
@@ -153,26 +153,6 @@ static int acpm_tmu_op_tz_control(struct acpm_tmu_sensor *sensor, bool on)
 	return 0;
 }
 
-static void acpm_tmu_control_rollback(struct acpm_tmu_priv *priv, int start_idx)
-{
-	int i;
-
-	for (i = start_idx; i >= 0; i--) {
-		struct acpm_tmu_sensor *sensor = &priv->sensors[i];
-		int ret;
-
-		if (!sensor->tzd)
-			continue;
-
-		mutex_lock(&sensor->lock);
-		ret = acpm_tmu_op_tz_control(sensor, false);
-		mutex_unlock(&sensor->lock);
-		if (ret)
-			dev_err(priv->dev, "Rollback: Failed to disable sensor %d: %d\n",
-				i, ret);
-	}
-}
-
 static int acpm_tmu_control(struct acpm_tmu_priv *priv, bool on)
 {
 	struct device *dev = priv->dev;
@@ -199,7 +179,7 @@ static int acpm_tmu_control(struct acpm_tmu_priv *priv, bool on)
 			err = ret;
 	}
 
-	pm_runtime_put_sync(dev);
+	pm_runtime_put_autosuspend(dev);
 
 	return err;
 }
@@ -489,7 +469,7 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 	ret = acpm_handle->ops->tmu.init(acpm_handle, priv->mbox_chan_id);
 	if (ret) {
 		ret = dev_err_probe(dev, ret, "Failed to init TMU\n");
-		goto err_pm_put;
+		goto out_pm_put;
 	}
 
 	for (i = 0; i < priv->num_sensors; i++) {
@@ -510,7 +490,7 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 			}
 
 			ret = dev_err_probe(dev, ret, "Failed to register sensor %d\n", i);
-			goto err_rollback;
+			goto out_pm_put;
 		}
 		sensor->tzd = tzd;
 
@@ -522,39 +502,14 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 	ret = devm_request_threaded_irq(dev, priv->irq, NULL,
 					acpm_tmu_thread_fn, IRQF_ONESHOT,
 					dev_name(dev), priv);
-	if (ret) {
+	if (ret)
 		ret = dev_err_probe(dev, ret, "Failed to request irq\n");
-		goto err_rollback;
-	}
 
+out_pm_put:
 	pm_runtime_put_autosuspend(dev);
-
-	return 0;
-
-err_rollback:
-	acpm_tmu_control_rollback(priv, i - 1);
-err_pm_put:
-	pm_runtime_dont_use_autosuspend(dev);
-	pm_runtime_put_sync(dev);
 	return ret;
 }
 
-static void acpm_tmu_remove(struct platform_device *pdev)
-{
-	struct acpm_tmu_priv *priv = platform_get_drvdata(pdev);
-
-	/* Stop IRQ first to prevent race with thread_fn */
-	disable_irq(priv->irq);
-
-	/*
-	 * Disable autosuspend to force the subsequent pm_runtime_put_sync()
-	 * inside acpm_tmu_control() to synchronously suspend the device
-	 * immediately, preventing clock leaks when the driver is removed.
-	 */
-	pm_runtime_dont_use_autosuspend(&pdev->dev);
-	acpm_tmu_control(priv, false);
-}
-
 static int acpm_tmu_suspend(struct device *dev)
 {
 	struct acpm_tmu_priv *priv = dev_get_drvdata(dev);
@@ -648,7 +603,6 @@ static struct platform_driver acpm_tmu_driver = {
 		.of_match_table = acpm_tmu_match,
 	},
 	.probe = acpm_tmu_probe,
-	.remove = acpm_tmu_remove,
 };
 module_platform_driver(acpm_tmu_driver);
 
author maintainer
#13 lore raw

PATCH 7/15 thermal/drivers/samsung: acpm-tmu: Return -ENODATA when sensor is disabled

In reply to Tudor Ambarus

In the thermal core, returning -EAGAIN from .get_temp() instructs __thermal_zone_device_update() -> thermal_zone_recheck() to schedule a 250 ms (4 Hz) retry loop with no backoff. If re-enabling a sensor fails (for example on resume, or after an acpm_tmu_update_thresholds() failure when polling is active), sensor->enabled remains false while tz->mode is still THERMAL_DEVICE_ENABLED, causing an infinite 4 Hz retry loop instead of backing off and disabling the broken zone via thermal_zone_broken_disable(). In addition, hwmon's temp_input_show() forwards -EAGAIN directly to userspace rather than -ENODATA.

Return -ENODATA instead of -EAGAIN when !sensor->enabled in acpm_tmu_get_temp().

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/acpm-tmu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +2 -2
index 4257bec802c1..1f56c69af76f 100644
@@ -200,7 +200,7 @@ static int acpm_tmu_get_temp(struct thermal_zone_device *tz, int *temp)
 	 * after PM resume.
 	 */
 	if (!sensor->enabled)
-		return -EAGAIN;
+		return -ENODATA;
 
 	ret = pm_runtime_resume_and_get(dev);
 	if (ret < 0)
@@ -208,7 +208,7 @@ static int acpm_tmu_get_temp(struct thermal_zone_device *tz, int *temp)
 
 	scoped_guard(mutex, &sensor->lock) {
 		if (!sensor->enabled) {
-			ret = -EAGAIN;
+			ret = -ENODATA;
 		} else {
 			ret = ops->read_temp(handle, priv->mbox_chan_id,
 					     sensor->group->id, &acpm_temp);
Signature · 1 line
2.56.0.257.gf7497c7d27-goog
#14 lore raw

[thermal: thermal/linux-next] thermal/drivers/samsung: acpm-tmu: Return -ENODATA when sensor is disabled

The following commit has been merged into the thermal/linux-next branch of thermal:

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     f04aff1cbba0080cd4af80134bbf4ac7452b2b8d
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//f04aff1cbba0080cd4af80134bbf4ac7452b2b8d
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:24 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:50 +01:00

thermal/drivers/samsung: acpm-tmu: Return -ENODATA when sensor is disabled

In the thermal core, returning -EAGAIN from .get_temp() instructs __thermal_zone_device_update() -> thermal_zone_recheck() to schedule a 250 ms (4 Hz) retry loop with no backoff. If re-enabling a sensor fails (for example on resume, or after an acpm_tmu_update_thresholds() failure when polling is active), sensor->enabled remains false while tz->mode is still THERMAL_DEVICE_ENABLED, causing an infinite 4 Hz retry loop instead of backing off and disabling the broken zone via thermal_zone_broken_disable(). In addition, hwmon's temp_input_show() forwards -EAGAIN directly to userspace rather than -ENODATA.

Return -ENODATA instead of -EAGAIN when !sensor->enabled in acpm_tmu_get_temp().

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/acpm-tmu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +2 -2
index 4257bec..1f56c69 100644
@@ -200,7 +200,7 @@ static int acpm_tmu_get_temp(struct thermal_zone_device *tz, int *temp)
 	 * after PM resume.
 	 */
 	if (!sensor->enabled)
-		return -EAGAIN;
+		return -ENODATA;
 
 	ret = pm_runtime_resume_and_get(dev);
 	if (ret < 0)
@@ -208,7 +208,7 @@ static int acpm_tmu_get_temp(struct thermal_zone_device *tz, int *temp)
 
 	scoped_guard(mutex, &sensor->lock) {
 		if (!sensor->enabled) {
-			ret = -EAGAIN;
+			ret = -ENODATA;
 		} else {
 			ret = ops->read_temp(handle, priv->mbox_chan_id,
 					     sensor->group->id, &acpm_temp);
author maintainer
#15 lore raw

PATCH 8/15 thermal/drivers/samsung: acpm-tmu: Annotate lockless sensor->enabled access

In reply to Tudor Ambarus

acpm_tmu_get_temp() reads sensor->enabled outside sensor->lock as a fast path before resuming the device via runtime PM, while acpm_tmu_op_tz_control() updates sensor->enabled under sensor->lock. Because both accesses are plain C accesses, concurrent execution is a data race.

Pair READ_ONCE() on the lockless fast-path read with WRITE_ONCE() in acpm_tmu_op_tz_control() to prevent compiler misoptimizations and KCSAN data-race warnings.

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/acpm-tmu.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +3 -2
index 1f56c69af76f..65be8884a8c5 100644
@@ -7,6 +7,7 @@
 
 #include <linux/cleanup.h>
 #include <linux/clk.h>
+#include <linux/compiler.h>
 #include <linux/device/devres.h>
 #include <linux/err.h>
 #include <linux/firmware/samsung/exynos-acpm-protocol.h>
@@ -148,7 +149,7 @@ static int acpm_tmu_op_tz_control(struct acpm_tmu_sensor *sensor, bool on)
 	if (ret)
 		return ret;
 
-	sensor->enabled = on;
+	WRITE_ONCE(sensor->enabled, on);
 
 	return 0;
 }
@@ -199,7 +200,7 @@ static int acpm_tmu_get_temp(struct thermal_zone_device *tz, int *temp)
 	 * concurrent disabling is caught by the second check under the lock
 	 * after PM resume.
 	 */
-	if (!sensor->enabled)
+	if (!READ_ONCE(sensor->enabled))
 		return -ENODATA;
 
 	ret = pm_runtime_resume_and_get(dev);
Signature · 1 line
2.56.0.257.gf7497c7d27-goog
#16 lore raw

[thermal: thermal/linux-next] thermal/drivers/samsung: acpm-tmu: Annotate lockless sensor->enabled access

The following commit has been merged into the thermal/linux-next branch of thermal:

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     95580915961eca39d4f3159cb4a235f25ea301b5
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//95580915961eca39d4f3159cb4a235f25ea301b5
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:25 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:50 +01:00

thermal/drivers/samsung: acpm-tmu: Annotate lockless sensor->enabled access

acpm_tmu_get_temp() reads sensor->enabled outside sensor->lock as a fast path before resuming the device via runtime PM, while acpm_tmu_op_tz_control() updates sensor->enabled under sensor->lock. Because both accesses are plain C accesses, concurrent execution is a data race.

Pair READ_ONCE() on the lockless fast-path read with WRITE_ONCE() in acpm_tmu_op_tz_control() to prevent compiler misoptimizations and KCSAN data-race warnings.

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/acpm-tmu.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +3 -2
index 1f56c69..65be888 100644
@@ -7,6 +7,7 @@
 
 #include <linux/cleanup.h>
 #include <linux/clk.h>
+#include <linux/compiler.h>
 #include <linux/device/devres.h>
 #include <linux/err.h>
 #include <linux/firmware/samsung/exynos-acpm-protocol.h>
@@ -148,7 +149,7 @@ static int acpm_tmu_op_tz_control(struct acpm_tmu_sensor *sensor, bool on)
 	if (ret)
 		return ret;
 
-	sensor->enabled = on;
+	WRITE_ONCE(sensor->enabled, on);
 
 	return 0;
 }
@@ -199,7 +200,7 @@ static int acpm_tmu_get_temp(struct thermal_zone_device *tz, int *temp)
 	 * concurrent disabling is caught by the second check under the lock
 	 * after PM resume.
 	 */
-	if (!sensor->enabled)
+	if (!READ_ONCE(sensor->enabled))
 		return -ENODATA;
 
 	ret = pm_runtime_resume_and_get(dev);
author maintainer
#17 lore raw

PATCH 9/15 thermal/drivers/samsung: acpm-tmu: Fix IRQ locking and error handling

In reply to Tudor Ambarus

acpm_tmu_has_pending_irq() acquires and releases sensor->lock around the INTPEND read, and acpm_tmu_thread_fn() re-acquires it to call ops->clear_tz_irq(), leaving a window where concurrent .set_trips() or .change_mode() calls can modify sensor state in between. Moreover, if ops->clear_tz_irq() fails, acpm_tmu_thread_fn() still sets handled = true and updates the thermal zone while INTPEND remains asserted; conversely, returning IRQ_NONE on a level-high IRQF_ONESHOT line re-triggers the interrupt up to 100,000 times before the spurious IRQ detector disables it, so unthrottled dev_err() calls flood the kernel log.

Replace acpm_tmu_has_pending_irq() with acpm_tmu_clear_pending_irq() so both the INTPEND check and ops->clear_tz_irq() run under a single guard(mutex)(&sensor->lock), only mark the IRQ handled and update the thermal zone when an interrupt was pending and cleared, and rate-limit the error messages on both IRQ_NONE failure paths in the threaded IRQ handler.

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/acpm-tmu.c | 42 ++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 22 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +20 -22
index 65be8884a8c5..42b338d8d093 100644
@@ -330,11 +330,12 @@ static const struct thermal_zone_device_ops acpm_tmu_sensor_ops = {
 	.set_trips = acpm_tmu_set_trips,
 };
 
-static int acpm_tmu_has_pending_irq(struct acpm_tmu_sensor *sensor,
-				    bool *pending_irq)
+static bool acpm_tmu_clear_pending_irq(struct acpm_tmu_sensor *sensor)
 {
 	struct acpm_tmu_priv *priv = sensor->priv;
+	const struct acpm_tmu_ops *ops = &priv->handle->ops->tmu;
 	unsigned long mask = sensor->group->mask;
+	bool pending_irq = false;
 	int i, ret;
 	u32 val;
 
@@ -343,53 +344,50 @@ static int acpm_tmu_has_pending_irq(struct acpm_tmu_sensor *sensor,
 	for_each_set_bit(i, &mask, EXYNOS_TMU_SENSORS_MAX_COUNT) {
 		ret = regmap_field_read(priv->regmap_fields[i], &val);
 		if (ret)
-			return ret;
+			return false;
 
 		if (val) {
-			*pending_irq = true;
+			pending_irq = true;
 			break;
 		}
 	}
 
-	return 0;
+	if (!pending_irq)
+		return false;
+
+	ret = ops->clear_tz_irq(priv->handle, priv->mbox_chan_id,
+				sensor->group->id);
+	if (ret) {
+		dev_err_ratelimited(priv->dev,
+				    "Sensor %u: failed to clear IRQ (%d)\n",
+				    sensor->group->id, ret);
+		return false;
+	}
+
+	return true;
 }
 
 static irqreturn_t acpm_tmu_thread_fn(int irq, void *id)
 {
 	struct acpm_tmu_priv *priv = id;
-	struct acpm_handle *handle = priv->handle;
-	const struct acpm_tmu_ops *ops = &handle->ops->tmu;
 	struct device *dev = priv->dev;
 	bool handled = false;
 	int i, ret;
 
 	ret = pm_runtime_resume_and_get(dev);
 	if (ret) {
-		dev_err(dev, "Failed to resume: %d\n", ret);
+		dev_err_ratelimited(dev, "Failed to resume: %d\n", ret);
 		return IRQ_NONE;
 	}
 
 	for (i = 0; i < priv->num_sensors; i++) {
 		struct acpm_tmu_sensor *sensor = &priv->sensors[i];
-		bool pending_irq = false;
-
-		if (!sensor->tzd)
-			continue;
 
-		ret = acpm_tmu_has_pending_irq(sensor, &pending_irq);
-		if (ret || !pending_irq)
+		if (!sensor->tzd || !acpm_tmu_clear_pending_irq(sensor))
 			continue;
 
 		handled = true;
 
-		scoped_guard(mutex, &sensor->lock) {
-			ret = ops->clear_tz_irq(handle, priv->mbox_chan_id,
-						sensor->group->id);
-			if (ret)
-				dev_err(priv->dev, "Sensor %d: failed to clear IRQ (%d)\n",
-					i, ret);
-		}
-
 		thermal_zone_device_update(sensor->tzd,
 					   THERMAL_EVENT_UNSPECIFIED);
 	}
Signature · 1 line
2.56.0.257.gf7497c7d27-goog
#18 lore raw

[thermal: thermal/linux-next] thermal/drivers/samsung: acpm-tmu: Fix IRQ locking and error handling

The following commit has been merged into the thermal/linux-next branch of thermal:

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     2237a6871722f9cafedf6820527a88430df26be2
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//2237a6871722f9cafedf6820527a88430df26be2
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:26 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:51 +01:00

thermal/drivers/samsung: acpm-tmu: Fix IRQ locking and error handling

acpm_tmu_has_pending_irq() acquires and releases sensor->lock around the INTPEND read, and acpm_tmu_thread_fn() re-acquires it to call ops->clear_tz_irq(), leaving a window where concurrent .set_trips() or .change_mode() calls can modify sensor state in between. Moreover, if ops->clear_tz_irq() fails, acpm_tmu_thread_fn() still sets handled = true and updates the thermal zone while INTPEND remains asserted; conversely, returning IRQ_NONE on a level-high IRQF_ONESHOT line re-triggers the interrupt up to 100,000 times before the spurious IRQ detector disables it, so unthrottled dev_err() calls flood the kernel log.

Replace acpm_tmu_has_pending_irq() with acpm_tmu_clear_pending_irq() so both the INTPEND check and ops->clear_tz_irq() run under a single guard(mutex)(&sensor->lock), only mark the IRQ handled and update the thermal zone when an interrupt was pending and cleared, and rate-limit the error messages on both IRQ_NONE failure paths in the threaded IRQ handler.

Fixes 50a2c5d4062a ("thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101")
---
 drivers/thermal/samsung/acpm-tmu.c | 42 +++++++++++++----------------
 1 file changed, 20 insertions(+), 22 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +20 -22
index 65be888..42b338d 100644
@@ -330,11 +330,12 @@ static const struct thermal_zone_device_ops acpm_tmu_sensor_ops = {
 	.set_trips = acpm_tmu_set_trips,
 };
 
-static int acpm_tmu_has_pending_irq(struct acpm_tmu_sensor *sensor,
-				    bool *pending_irq)
+static bool acpm_tmu_clear_pending_irq(struct acpm_tmu_sensor *sensor)
 {
 	struct acpm_tmu_priv *priv = sensor->priv;
+	const struct acpm_tmu_ops *ops = &priv->handle->ops->tmu;
 	unsigned long mask = sensor->group->mask;
+	bool pending_irq = false;
 	int i, ret;
 	u32 val;
 
@@ -343,53 +344,50 @@ static int acpm_tmu_has_pending_irq(struct acpm_tmu_sensor *sensor,
 	for_each_set_bit(i, &mask, EXYNOS_TMU_SENSORS_MAX_COUNT) {
 		ret = regmap_field_read(priv->regmap_fields[i], &val);
 		if (ret)
-			return ret;
+			return false;
 
 		if (val) {
-			*pending_irq = true;
+			pending_irq = true;
 			break;
 		}
 	}
 
-	return 0;
+	if (!pending_irq)
+		return false;
+
+	ret = ops->clear_tz_irq(priv->handle, priv->mbox_chan_id,
+				sensor->group->id);
+	if (ret) {
+		dev_err_ratelimited(priv->dev,
+				    "Sensor %u: failed to clear IRQ (%d)\n",
+				    sensor->group->id, ret);
+		return false;
+	}
+
+	return true;
 }
 
 static irqreturn_t acpm_tmu_thread_fn(int irq, void *id)
 {
 	struct acpm_tmu_priv *priv = id;
-	struct acpm_handle *handle = priv->handle;
-	const struct acpm_tmu_ops *ops = &handle->ops->tmu;
 	struct device *dev = priv->dev;
 	bool handled = false;
 	int i, ret;
 
 	ret = pm_runtime_resume_and_get(dev);
 	if (ret) {
-		dev_err(dev, "Failed to resume: %d\n", ret);
+		dev_err_ratelimited(dev, "Failed to resume: %d\n", ret);
 		return IRQ_NONE;
 	}
 
 	for (i = 0; i < priv->num_sensors; i++) {
 		struct acpm_tmu_sensor *sensor = &priv->sensors[i];
-		bool pending_irq = false;
-
-		if (!sensor->tzd)
-			continue;
 
-		ret = acpm_tmu_has_pending_irq(sensor, &pending_irq);
-		if (ret || !pending_irq)
+		if (!sensor->tzd || !acpm_tmu_clear_pending_irq(sensor))
 			continue;
 
 		handled = true;
 
-		scoped_guard(mutex, &sensor->lock) {
-			ret = ops->clear_tz_irq(handle, priv->mbox_chan_id,
-						sensor->group->id);
-			if (ret)
-				dev_err(priv->dev, "Sensor %d: failed to clear IRQ (%d)\n",
-					i, ret);
-		}
-
 		thermal_zone_device_update(sensor->tzd,
 					   THERMAL_EVENT_UNSPECIFIED);
 	}
author maintainer
#19 lore raw

PATCH 10/15 MAINTAINERS: Use linux-pm mailing list for Samsung Exynos ACPM thermal driver

In reply to Tudor Ambarus

List the power management and thermal subsystem mailing list ([email protected]) instead of the general [email protected] list under SAMSUNG EXYNOS ACPM THERMAL DRIVER.

Fixes 05657c7822f2 ("MAINTAINERS: Add entry for Samsung Exynos ACPM thermal driver")
---
 MAINTAINERS | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
MAINTAINERS +1 -1
index 0e9fe9c2a39b..6da7c884373a 100644
@@ -24382,7 +24382,7 @@ F:	include/linux/firmware/samsung/exynos-acpm-protocol.h
 
 SAMSUNG EXYNOS ACPM THERMAL DRIVER
 M:	Tudor Ambarus <[email protected]>
-L:	[email protected]
+L:	[email protected]
 L:	[email protected]
 S:	Supported
 F:	Documentation/devicetree/bindings/thermal/google,gs101-tmu-top.yaml
Signature · 1 line
2.56.0.257.gf7497c7d27-goog
#20 lore raw

[thermal: thermal/linux-next] MAINTAINERS: Use linux-pm mailing list for Samsung Exynos ACPM thermal driver

The following commit has been merged into the thermal/linux-next branch of thermal:

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     9745df063ef8190d713f90ffd215f39838ad6e83
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//9745df063ef8190d713f90ffd215f39838ad6e83
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:27 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:51 +01:00

MAINTAINERS: Use linux-pm mailing list for Samsung Exynos ACPM thermal driver

List the power management and thermal subsystem mailing list ([email protected]) instead of the general [email protected] list under SAMSUNG EXYNOS ACPM THERMAL DRIVER.

Fixes 05657c7822f2 ("MAINTAINERS: Add entry for Samsung Exynos ACPM thermal driver")
---
 MAINTAINERS | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
MAINTAINERS +1 -1
index 93abbb3..586ac46 100644
@@ -24899,7 +24899,7 @@ F:	include/linux/firmware/samsung/exynos-acpm-protocol.h
 
 SAMSUNG EXYNOS ACPM THERMAL DRIVER
 M:	Tudor Ambarus <[email protected]>
-L:	[email protected]
+L:	[email protected]
 L:	[email protected]
 S:	Supported
 F:	Documentation/devicetree/bindings/thermal/google,gs101-tmu-top.yaml
author maintainer
#21 lore raw

PATCH 11/15 thermal/drivers/samsung: acpm-tmu: Rename platform driver to "exynos-acpm-tmu"

In reply to Tudor Ambarus

Rename the platform driver from "gs-tmu" to "exynos-acpm-tmu" to reflect that the ACPM TMU architecture is shared across Samsung Exynos SoCs (such as GS101, AutoV920, and Exynos850) rather than being specific to GS101, matching "exynos-acpm-protocol" in drivers/firmware/samsung/.

---
 drivers/thermal/samsung/acpm-tmu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/thermal/samsung/acpm-tmu.c +1 -1
index 42b338d8d093..2324efcffb84 100644
@@ -597,7 +597,7 @@ static const struct dev_pm_ops acpm_tmu_pm_ops = {
 
 static struct platform_driver acpm_tmu_driver = {
 	.driver = {
-		.name   = "gs-tmu",
+		.name   = "exynos-acpm-tmu",
 		.pm     = pm_ptr(&acpm_tmu_pm_ops),
 		.of_match_table = acpm_tmu_match,
 	},
Signature · 1 line
2.56.0.257.gf7497c7d27-goog
#22 lore raw

[thermal: thermal/linux-next] thermal/drivers/samsung: acpm-tmu: Rename platform driver to "exynos-acpm-tmu"

The following commit has been merged into the thermal/linux-next branch of thermal:

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     ba446bdd27d4a2a6c0cb267f51a6ecc47cf19cf9
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//ba446bdd27d4a2a6c0cb267f51a6ecc47cf19cf9
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:28 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:51 +01:00

thermal/drivers/samsung: acpm-tmu: Rename platform driver to "exynos-acpm-tmu"

Rename the platform driver from "gs-tmu" to "exynos-acpm-tmu" to reflect that the ACPM TMU architecture is shared across Samsung Exynos SoCs (such as GS101, AutoV920, and Exynos850) rather than being specific to GS101, matching "exynos-acpm-protocol" in drivers/firmware/samsung/.

---
 drivers/thermal/samsung/acpm-tmu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/thermal/samsung/acpm-tmu.c +1 -1
index 42b338d..2324efc 100644
@@ -597,7 +597,7 @@ static const struct dev_pm_ops acpm_tmu_pm_ops = {
 
 static struct platform_driver acpm_tmu_driver = {
 	.driver = {
-		.name   = "gs-tmu",
+		.name   = "exynos-acpm-tmu",
 		.pm     = pm_ptr(&acpm_tmu_pm_ops),
 		.of_match_table = acpm_tmu_match,
 	},
#23 lore raw

Re: [thermal: thermal/linux-next] thermal/drivers/samsung: acpm-tmu: Rename platform driver to "exynos-acpm-tmu"

Quoted 10 lines · thermal-bot for Tudor Ambarus

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     ba446bdd27d4a2a6c0cb267f51a6ecc47cf19cf9
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//ba446bdd27d4a2a6c0cb267f51a6ecc47cf19cf9
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:28 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:51 +01:00

thermal/drivers/samsung: acpm-tmu: Rename platform driver to "exynos-acpm-tmu"

Also, the fix for this problem was sent here earlier:
https://lore.kernel.org/linux-samsung-soc/[email protected]/

Why taking this one and ignoring the fix that was sent earlier -- this should be at least explained.

Quoted 6 lines

Rename the platform driver from "gs-tmu" to "exynos-acpm-tmu" to reflect that the ACPM TMU architecture is shared across Samsung Exynos SoCs (such as GS101, AutoV920, and Exynos850) rather than being specific to GS101, matching "exynos-acpm-protocol" in drivers/firmware/samsung/.

I don't recall suggesting this. Reporting -- yes, but not renaming to "exynos-acpm-tmu".

This was reported months ago and was never fixed in the updated series for acpm-tmu.c.

Quoted 12 lines
---
 drivers/thermal/samsung/acpm-tmu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/thermal/samsung/acpm-tmu.c +0 -0
index 42b338d..2324efc 100644

drivers/thermal/samsung/acpm-tmu.c static const struct dev_pm_ops acpm_tmu_pm_ops = { · line 600

Quoted 5 lines
drivers/thermal/samsung/acpm-tmu.c +1 -1
@@ -597,7 +597,7 @@ static const struct dev_pm_ops acpm_tmu_pm_ops = {
 
 static struct platform_driver acpm_tmu_driver = {
 	.driver = {
-		.name   = "gs-tmu",
+		.name   = "exynos-acpm-tmu",

It is minor but it potentially clashes with exynos-acpm-tmu firmware file name. All other names in file acpm-tmu.c are "acpm-tmu".

author maintainer
#24 lore raw

Re: [thermal: thermal/linux-next] thermal/drivers/samsung: acpm-tmu: Rename platform driver to "exynos-acpm-tmu"

Quoted 10 lines · Alexey Klimov
Quoted 9 lines · thermal-bot for Tudor Ambarus

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     ba446bdd27d4a2a6c0cb267f51a6ecc47cf19cf9
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//ba446bdd27d4a2a6c0cb267f51a6ecc47cf19cf9
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:28 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:51 +01:00
Quoted 7 lines
Quoted 1 line

thermal/drivers/samsung: acpm-tmu: Rename platform driver to "exynos-acpm-tmu"

Also, the fix for this problem was sent here earlier:
https://lore.kernel.org/linux-samsung-soc/[email protected]/

Why taking this one and ignoring the fix that was sent earlier -- this should be at least explained.

I guess it slipped through the cracks, as it did for me.

Quoted 10 lines
Quoted 7 lines

Rename the platform driver from "gs-tmu" to "exynos-acpm-tmu" to reflect that the ACPM TMU architecture is shared across Samsung Exynos SoCs (such as GS101, AutoV920, and Exynos850) rather than being specific to GS101, matching "exynos-acpm-protocol" in drivers/firmware/samsung/.

I don't recall suggesting this. Reporting -- yes, but not renaming to "exynos-acpm-tmu".

my apologies, it wasn't intended. If you have a strong opinion on the tag type, I guess Daniel can drop it.

Quoted 17 lines

This was reported months ago and was never fixed in the updated series for acpm-tmu.c.

Quoted 13 lines
---
 drivers/thermal/samsung/acpm-tmu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/thermal/samsung/acpm-tmu.c +0 -0
index 42b338d..2324efc 100644
@@ -597,7 +597,7 @@ static const struct dev_pm_ops acpm_tmu_pm_ops = {
 
Quoted 6 lines

drivers/thermal/samsung/acpm-tmu.c static const struct dev_pm_ops acpm_tmu_pm_ops = { · line 600

Quoted 4 lines
drivers/thermal/samsung/acpm-tmu.c +1 -1
 static struct platform_driver acpm_tmu_driver = {
 	.driver = {
-		.name   = "gs-tmu",
+		.name   = "exynos-acpm-tmu",

It is minor but it potentially clashes with exynos-acpm-tmu firmware

There's no driver name for the firmware tmu commands helpers but I see your point.

Quoted 1 line

file name. All other names in file acpm-tmu.c are "acpm-tmu".

I think "exynos-acpm-tmu" is fine, it aligns with "exynos-acpm-protocol" from drivers/firmware/samsung/exynos-acpm.c. I guess you may rename "acpm-clocks" (drivers/clk/samsung/clk-acpm.c) to "exynos-acpm-clocks", but I wouldn't bother too much. If you have a strong opinion on "acpm-tmu" send a patch on top please.

Cheers,
ta

author maintainer
#25 lore raw

PATCH 12/15 thermal/drivers/samsung: Drop redundant composite object in Makefile

In reply to Tudor Ambarus

The Exynos ACPM thermal driver consists of a single source file (acpm-tmu.c). Build acpm-tmu.o directly under CONFIG_EXYNOS_ACPM_THERMAL instead of wrapping it in a single-file exynos_acpm_thermal.o composite object.

---
 drivers/thermal/samsung/Makefile | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/thermal/samsung/Makefile +1 -2
index daed80647c34..d5b6e9e05377 100644
@@ -4,5 +4,4 @@
 #
 obj-$(CONFIG_EXYNOS_THERMAL)			+= exynos_thermal.o
 exynos_thermal-y				:= exynos_tmu.o
-obj-$(CONFIG_EXYNOS_ACPM_THERMAL)		+= exynos_acpm_thermal.o
-exynos_acpm_thermal-y				:= acpm-tmu.o
+obj-$(CONFIG_EXYNOS_ACPM_THERMAL)		+= acpm-tmu.o
Signature · 1 line
2.56.0.257.gf7497c7d27-goog
#26 lore raw

[thermal: thermal/linux-next] thermal/drivers/samsung: Drop redundant composite object in Makefile

The following commit has been merged into the thermal/linux-next branch of thermal:

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     133c6b01f134b6f3da2961099ab2fffe6e9a5f3d
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//133c6b01f134b6f3da2961099ab2fffe6e9a5f3d
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:29 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:51 +01:00

thermal/drivers/samsung: Drop redundant composite object in Makefile

The Exynos ACPM thermal driver consists of a single source file (acpm-tmu.c). Build acpm-tmu.o directly under CONFIG_EXYNOS_ACPM_THERMAL instead of wrapping it in a single-file exynos_acpm_thermal.o composite object.

---
 drivers/thermal/samsung/Makefile | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/thermal/samsung/Makefile +1 -2
index daed806..d5b6e9e 100644
@@ -4,5 +4,4 @@
 #
 obj-$(CONFIG_EXYNOS_THERMAL)			+= exynos_thermal.o
 exynos_thermal-y				:= exynos_tmu.o
-obj-$(CONFIG_EXYNOS_ACPM_THERMAL)		+= exynos_acpm_thermal.o
-exynos_acpm_thermal-y				:= acpm-tmu.o
+obj-$(CONFIG_EXYNOS_ACPM_THERMAL)		+= acpm-tmu.o
author maintainer
#27 lore raw

PATCH 13/15 thermal/drivers/samsung: acpm-tmu: Disable regmap locking for MMIO INTPEND reads

In reply to Tudor Ambarus

The regmap in acpm-tmu is only used for full-width 32-bit relaxed MMIO reads of the INTPEND registers, with no read-modify-write operations or regmap cache. Set .disable_locking = true in gs101_regmap_config to avoid unnecessary regmap lock overhead on every INTPEND register read.

---
 drivers/thermal/samsung/acpm-tmu.c | 1 +
 1 file changed, 1 insertion(+)
drivers/thermal/samsung/acpm-tmu.c +1 -0
index 2324efcffb84..fd491b4f305d 100644
@@ -127,6 +127,7 @@ static const struct regmap_config gs101_regmap_config = {
 	.reg_stride = 4,
 	.val_bits = 32,
 	.use_relaxed_mmio = true,
+	.disable_locking = true,
 	.max_register = GS101_REG_INTPEND(15),
 };
 
Signature · 1 line
2.56.0.257.gf7497c7d27-goog
#28 lore raw

[thermal: thermal/linux-next] thermal/drivers/samsung: acpm-tmu: Disable regmap locking for MMIO INTPEND reads

The following commit has been merged into the thermal/linux-next branch of thermal:

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     6eb64c42a31531de51b735a1709ac8b7c24bbb4e
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//6eb64c42a31531de51b735a1709ac8b7c24bbb4e
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:30 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:51 +01:00

thermal/drivers/samsung: acpm-tmu: Disable regmap locking for MMIO INTPEND reads

The regmap in acpm-tmu is only used for full-width 32-bit relaxed MMIO reads of the INTPEND registers, with no read-modify-write operations or regmap cache. Set .disable_locking = true in gs101_regmap_config to avoid unnecessary regmap lock overhead on every INTPEND register read.

---
 drivers/thermal/samsung/acpm-tmu.c | 1 +
 1 file changed, 1 insertion(+)
drivers/thermal/samsung/acpm-tmu.c +1 -0
index 2324efc..fd491b4 100644
@@ -127,6 +127,7 @@ static const struct regmap_config gs101_regmap_config = {
 	.reg_stride = 4,
 	.val_bits = 32,
 	.use_relaxed_mmio = true,
+	.disable_locking = true,
 	.max_register = GS101_REG_INTPEND(15),
 };
 
author maintainer
#29 lore raw

PATCH 14/15 thermal/drivers/samsung: acpm-tmu: Clean up probe error logging

In reply to Tudor Ambarus

platform_get_irq(), devm_thermal_add_hwmon_sysfs(), and devm_request_threaded_irq() already log an error or warning message internally on failure, so drop the duplicate call-site messages in acpm_tmu_probe(). Also update the copy-pasted "Unable to map syscon registers" message on devm_regmap_field_bulk_alloc() failure to "Failed to allocate regmap fields".

---
 drivers/thermal/samsung/acpm-tmu.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +3 -7
index fd491b4f305d..bce4674be58e 100644
@@ -444,7 +444,7 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 					   data->reg_fields, REG_INTPEND_COUNT);
 	if (ret)
 		return dev_err_probe(dev, ret,
-				     "Unable to map syscon registers\n");
+				     "Failed to allocate regmap fields\n");
 
 	priv->clk = devm_clk_get(dev, NULL);
 	if (IS_ERR(priv->clk))
@@ -453,7 +453,7 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 
 	priv->irq = platform_get_irq(pdev, 0);
 	if (priv->irq < 0)
-		return dev_err_probe(dev, priv->irq, "Failed to get irq\n");
+		return priv->irq;
 
 	pm_runtime_set_autosuspend_delay(dev, 100);
 	pm_runtime_use_autosuspend(dev);
@@ -494,16 +494,12 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 		}
 		sensor->tzd = tzd;
 
-		ret = devm_thermal_add_hwmon_sysfs(dev, sensor->tzd);
-		if (ret)
-			dev_warn(dev, "Failed to add hwmon sysfs!\n");
+		devm_thermal_add_hwmon_sysfs(dev, sensor->tzd);
 	}
 
 	ret = devm_request_threaded_irq(dev, priv->irq, NULL,
 					acpm_tmu_thread_fn, IRQF_ONESHOT,
 					dev_name(dev), priv);
-	if (ret)
-		ret = dev_err_probe(dev, ret, "Failed to request irq\n");
 
 out_pm_put:
 	pm_runtime_put_autosuspend(dev);
Signature · 1 line
2.56.0.257.gf7497c7d27-goog
#30 lore raw

[thermal: thermal/linux-next] thermal/drivers/samsung: acpm-tmu: Clean up probe error logging

The following commit has been merged into the thermal/linux-next branch of thermal:

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     f316fea84421e3ca569d861ebc7e17632ac54cc2
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//f316fea84421e3ca569d861ebc7e17632ac54cc2
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:31 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:51 +01:00

thermal/drivers/samsung: acpm-tmu: Clean up probe error logging

platform_get_irq(), devm_thermal_add_hwmon_sysfs(), and devm_request_threaded_irq() already log an error or warning message internally on failure, so drop the duplicate call-site messages in acpm_tmu_probe(). Also update the copy-pasted "Unable to map syscon registers" message on devm_regmap_field_bulk_alloc() failure to "Failed to allocate regmap fields".

---
 drivers/thermal/samsung/acpm-tmu.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +3 -7
index fd491b4..bce4674 100644
@@ -444,7 +444,7 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 					   data->reg_fields, REG_INTPEND_COUNT);
 	if (ret)
 		return dev_err_probe(dev, ret,
-				     "Unable to map syscon registers\n");
+				     "Failed to allocate regmap fields\n");
 
 	priv->clk = devm_clk_get(dev, NULL);
 	if (IS_ERR(priv->clk))
@@ -453,7 +453,7 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 
 	priv->irq = platform_get_irq(pdev, 0);
 	if (priv->irq < 0)
-		return dev_err_probe(dev, priv->irq, "Failed to get irq\n");
+		return priv->irq;
 
 	pm_runtime_set_autosuspend_delay(dev, 100);
 	pm_runtime_use_autosuspend(dev);
@@ -494,16 +494,12 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 		}
 		sensor->tzd = tzd;
 
-		ret = devm_thermal_add_hwmon_sysfs(dev, sensor->tzd);
-		if (ret)
-			dev_warn(dev, "Failed to add hwmon sysfs!\n");
+		devm_thermal_add_hwmon_sysfs(dev, sensor->tzd);
 	}
 
 	ret = devm_request_threaded_irq(dev, priv->irq, NULL,
 					acpm_tmu_thread_fn, IRQF_ONESHOT,
 					dev_name(dev), priv);
-	if (ret)
-		ret = dev_err_probe(dev, ret, "Failed to request irq\n");
 
 out_pm_put:
 	pm_runtime_put_autosuspend(dev);
author maintainer
#31 lore raw

PATCH 15/15 thermal/drivers/samsung: acpm-tmu: Simplify pm_runtime_resume_and_get() error checks

In reply to Tudor Ambarus

Unlike pm_runtime_get_sync(), pm_runtime_resume_and_get() returns 0 on success or a negative error code on failure. Check "if (ret)" consistently across all pm_runtime_resume_and_get() call sites in acpm-tmu.c.

---
 drivers/thermal/samsung/acpm-tmu.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +3 -3
index bce4674be58e..7c30401f8fc7 100644
@@ -161,7 +161,7 @@ static int acpm_tmu_control(struct acpm_tmu_priv *priv, bool on)
 	int i, ret, err = 0;
 
 	ret = pm_runtime_resume_and_get(dev);
-	if (ret < 0)
+	if (ret)
 		return ret;
 
 	for (i = 0; i < priv->num_sensors; i++) {
@@ -205,7 +205,7 @@ static int acpm_tmu_get_temp(struct thermal_zone_device *tz, int *temp)
 		return -ENODATA;
 
 	ret = pm_runtime_resume_and_get(dev);
-	if (ret < 0)
+	if (ret)
 		return ret;
 
 	scoped_guard(mutex, &sensor->lock) {
@@ -463,7 +463,7 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 		return dev_err_probe(dev, ret, "Failed to enable runtime PM\n");
 
 	ret = pm_runtime_resume_and_get(dev);
-	if (ret < 0)
+	if (ret)
 		return dev_err_probe(dev, ret, "Failed to resume device\n");
 
 	ret = acpm_handle->ops->tmu.init(acpm_handle, priv->mbox_chan_id);
Signature · 1 line
2.56.0.257.gf7497c7d27-goog
#32 lore raw

[thermal: thermal/linux-next] thermal/drivers/samsung: acpm-tmu: Simplify pm_runtime_resume_and_get() error checks

The following commit has been merged into the thermal/linux-next branch of thermal:

The following commit has been merged into the thermal/linux-next branch of thermal:

Commit-ID:     32cb06b34701827db0ff34244d84fc74e40ca350
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//32cb06b34701827db0ff34244d84fc74e40ca350
Author:        Tudor Ambarus <[email protected]>
AuthorDate:    Mon, 26 Oct 2026 16:01:32 
Committer:     Daniel Lezcano <[email protected]>
CommitterDate: Tue, 03 Nov 2026 19:51:51 +01:00

thermal/drivers/samsung: acpm-tmu: Simplify pm_runtime_resume_and_get() error checks

Unlike pm_runtime_get_sync(), pm_runtime_resume_and_get() returns 0 on success or a negative error code on failure. Check "if (ret)" consistently across all pm_runtime_resume_and_get() call sites in acpm-tmu.c.

---
 drivers/thermal/samsung/acpm-tmu.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/thermal/samsung/acpm-tmu.c +3 -3
index bce4674..7c30401 100644
@@ -161,7 +161,7 @@ static int acpm_tmu_control(struct acpm_tmu_priv *priv, bool on)
 	int i, ret, err = 0;
 
 	ret = pm_runtime_resume_and_get(dev);
-	if (ret < 0)
+	if (ret)
 		return ret;
 
 	for (i = 0; i < priv->num_sensors; i++) {
@@ -205,7 +205,7 @@ static int acpm_tmu_get_temp(struct thermal_zone_device *tz, int *temp)
 		return -ENODATA;
 
 	ret = pm_runtime_resume_and_get(dev);
-	if (ret < 0)
+	if (ret)
 		return ret;
 
 	scoped_guard(mutex, &sensor->lock) {
@@ -463,7 +463,7 @@ static int acpm_tmu_probe(struct platform_device *pdev)
 		return dev_err_probe(dev, ret, "Failed to enable runtime PM\n");
 
 	ret = pm_runtime_resume_and_get(dev);
-	if (ret < 0)
+	if (ret)
 		return dev_err_probe(dev, ret, "Failed to resume device\n");
 
 	ret = acpm_handle->ops->tmu.init(acpm_handle, priv->mbox_chan_id);