Linux Power Management development
 help / color / mirror / Atom feed
* [PATCH v2] thermal: spacemit: k1: add shutdown action and reorder registration order
@ 2026-07-16  7:04 Pei Xiao
  2026-07-22  7:54 ` Troy Mitchell
  0 siblings, 1 reply; 2+ messages in thread
From: Pei Xiao @ 2026-07-16  7:04 UTC (permalink / raw)
  To: shuwei.wu, troy.mitchell, rafael, linux-pm, linux-riscv, spacemit,
	linux-kernel, dlan, daniel.lezcano
  Cc: Pei Xiao

Add a devm action to clean hardware interrupts, sampling, and control
registers on driver unbind, mirroring what k1_tsensor_init() sets up.

Reorder the registration order within probe(): register the thermal
zones first, then request the IRQ, and register the shutdown action
last.  On removal, the hardware interrupt is disabled first, then the
IRQ is released, and finally the thermal zones are released.  This
avoids the IRQ thread accessing an already unregistered thermal zone
during devres cleanup.

Signed-off-by: Pei Xiao <xiaopei01@kylinos.cn>
---
changlog in v2:
1.Disable all regs mirroring what k1_tsensor_init() sets up
2.reorder registration order
3.rename devm_k1_tsensor_shutdown to k1_tsensor_shutdown_action
4.modify git commit log 
---
 drivers/thermal/spacemit/k1_tsensor.c | 73 ++++++++++++++++++++++-----
 1 file changed, 60 insertions(+), 13 deletions(-)

diff --git a/drivers/thermal/spacemit/k1_tsensor.c b/drivers/thermal/spacemit/k1_tsensor.c
index 79222d233129..ab12e2ec8ae4 100644
--- a/drivers/thermal/spacemit/k1_tsensor.c
+++ b/drivers/thermal/spacemit/k1_tsensor.c
@@ -199,6 +199,39 @@ static irqreturn_t k1_tsensor_irq_thread(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static void k1_tsensor_shutdown(struct k1_tsensor *ts)
+{
+	u32 val;
+
+	/* Disable all interrupts */
+	writel(0xffffffff, ts->base + K1_TSENSOR_INT_EN_REG);
+
+	/* Disable all sensors */
+	val = readl(ts->base + K1_TSENSOR_EN_REG);
+	val &= ~K1_TSENSOR_EN_ALL;
+	writel(val, ts->base + K1_TSENSOR_EN_REG);
+
+	/* Clear the sampling configuration set by k1_tsensor_init() */
+	val = readl(ts->base + K1_TSENSOR_TIME_REG);
+	val &= ~(K1_TSENSOR_TIME_FILTER_PERIOD |
+		 K1_TSENSOR_TIME_ADC_CNT_RST |
+		 K1_TSENSOR_TIME_WAIT_REF_CNT);
+	writel(val, ts->base + K1_TSENSOR_TIME_REG);
+
+	/* Clear the control bits configured by k1_tsensor_init() */
+	val = readl(ts->base + K1_TSENSOR_PCTRL_REG);
+	val &= ~(K1_TSENSOR_PCTRL_RAW_SEL |
+		 K1_TSENSOR_PCTRL_TEMP_MODE |
+		 K1_TSENSOR_PCTRL_HW_AUTO_MODE |
+		 K1_TSENSOR_PCTRL_ENABLE);
+	writel(val, ts->base + K1_TSENSOR_PCTRL_REG);
+}
+
+static void k1_tsensor_shutdown_action(void *data)
+{
+	k1_tsensor_shutdown(data);
+}
+
 static int k1_tsensor_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -229,34 +262,48 @@ static int k1_tsensor_probe(struct platform_device *pdev)
 
 	k1_tsensor_init(ts);
 
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
-
-	ret = devm_request_threaded_irq(dev, irq, NULL,
-					k1_tsensor_irq_thread,
-					IRQF_ONESHOT, "k1_tsensor", ts);
-	if (ret < 0)
-		return ret;
-
 	for (i = 0; i < MAX_SENSOR_NUMBER; ++i) {
 		ts->ch[i].id = i;
 		ts->ch[i].ts = ts;
 		ts->ch[i].tzd = devm_thermal_of_zone_register(dev, i, ts->ch + i, &k1_tsensor_ops);
-		if (IS_ERR(ts->ch[i].tzd))
-			return PTR_ERR(ts->ch[i].tzd);
+		if (IS_ERR(ts->ch[i].tzd)) {
+			ret = PTR_ERR(ts->ch[i].tzd);
+			goto err_shutdown;
+		}
 
 		/* Attach sysfs hwmon attributes for userspace monitoring */
 		ret = devm_thermal_add_hwmon_sysfs(dev, ts->ch[i].tzd);
 		if (ret)
 			dev_warn(dev, "Failed to add hwmon sysfs attributes\n");
+	}
 
-		k1_tsensor_enable_irq(ts->ch + i);
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		ret = irq;
+		goto err_shutdown;
 	}
 
+	ret = devm_request_threaded_irq(dev, irq, NULL,
+					k1_tsensor_irq_thread,
+					IRQF_ONESHOT, "k1_tsensor", ts);
+	if (ret < 0)
+		goto err_shutdown;
+
+	ret = devm_add_action_or_reset(dev, k1_tsensor_shutdown_action, ts);
+	if (ret)
+		return ret;
+
+	/* Enable interrupts only after all zones and the handler are ready */
+	for (i = 0; i < MAX_SENSOR_NUMBER; ++i)
+		k1_tsensor_enable_irq(ts->ch + i);
+
 	platform_set_drvdata(pdev, ts);
 
 	return 0;
+
+err_shutdown:
+	k1_tsensor_shutdown(ts);
+	return ret;
 }
 
 static const struct of_device_id k1_tsensor_dt_ids[] = {
-- 
2.25.1


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

* Re: [PATCH v2] thermal: spacemit: k1: add shutdown action and reorder registration order
  2026-07-16  7:04 [PATCH v2] thermal: spacemit: k1: add shutdown action and reorder registration order Pei Xiao
@ 2026-07-22  7:54 ` Troy Mitchell
  0 siblings, 0 replies; 2+ messages in thread
From: Troy Mitchell @ 2026-07-22  7:54 UTC (permalink / raw)
  To: Pei Xiao, shuwei.wu, troy.mitchell, rafael, linux-pm, linux-riscv,
	spacemit, linux-kernel, dlan, daniel.lezcano

On Thu Jul 16, 2026 at 12:04 AM PDT, Pei Xiao wrote:
> Add a devm action to clean hardware interrupts, sampling, and control
> registers on driver unbind, mirroring what k1_tsensor_init() sets up.
>
> Reorder the registration order within probe(): register the thermal
> zones first, then request the IRQ, and register the shutdown action
> last.  On removal, the hardware interrupt is disabled first, then the
> IRQ is released, and finally the thermal zones are released.  This
> avoids the IRQ thread accessing an already unregistered thermal zone
> during devres cleanup.
>
> Signed-off-by: Pei Xiao <xiaopei01@kylinos.cn>
Reviewed-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>

Thanks.

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

end of thread, other threads:[~2026-07-22  7:56 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-16  7:04 [PATCH v2] thermal: spacemit: k1: add shutdown action and reorder registration order Pei Xiao
2026-07-22  7:54 ` Troy Mitchell

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