LoongArch architecture development
 help / color / mirror / Atom feed
* [PATCH v6 0/7] thermal: loongson2: Add support for Loongson-2K0300 SoC
@ 2026-09-28  4:44 Binbin Zhou
  2026-09-28  4:44 ` [PATCH v6 1/7] thermal/drivers/loongson2: Correct thermal sensor registration loop Binbin Zhou
                   ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: Binbin Zhou @ 2026-09-28  4:44 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Yinbo Zhu, Rafael J . Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-pm,
	Binbin Zhou

Hi all:

This patch series adds thermal zone support for the Loongson-2K0300 SoC.

The Loongson-2K0300's thermal sensor is generally compatible with the
existing Loongson-2K series, but it features several key differences:
1. It has an independent CPU ID register for reading chip version
information.
2. The raw temperature output field has been extended from 8 bits to 11
bits.
3. The temperature calculation formula has been updated to incorporate a
correction factor based on the version information.

To ensure robustness on older hardware revisions, a fallback mechanism
is included: if the calculated temperature falls outside the valid range
(-55 TO 125),  the driver falls back to a simpler calculation and prints
a warning.

The series also includes fixes and cleanups for the existing Loongson-2
thermal driver, which are necessary to support the new SoC cleanly.

The patchset have been validated on the Loongson-2K series development boards.

Thanks.
Binbin

=========
V6:
 - Rebase on linux-pm/thermal;
Patch (2/7):
 - New patch;
 - Fix incorrect clamp() argument order for thermal trip points;
Patch (3/7):
 - New patch;
 - Fix Loongson-2K2000 trip point programming by adding a per-SoC
   set_trips_regs callback and handling the split HI_GATE registers;
Patch (4/7):
 - New patch;
 - cleanup: use GENMASK/FIELD_* helpers, add named constants, and factor
   common trip point setup;
Patch (5/7):
 - New patch;
 - refactor: move thermal_zone_device_ops into chip_data and replace the
   Loongson-2K2000 flag special case with an optional init_extend_resource
   callback;
Patch (7/7):
 - Updated the 10-bit output to 11-bit in commit message;
 - Temporarily remove the implementation of `set_trips`;
 - Remove unnecessary header files;
 - Rewrite `get_temp`, separating `read_calib` and `detect_old_fuse` into
   new functions to be called during the probe;
 - Use macros to define the relevant numbers.

Link to V5:
https://lore.kernel.org/all/cover.1789546118.git.zhoubinbin@loongson.cn/#t

V5:
 - Rebase on linux-pm/thermal;
 - Drop patch-3 for it was applied.

Link to V4:
https://lore.kernel.org/all/cover.1785829933.git.zhoubinbin@loongson.cn/

V4:
 - Rebase on linux-mfd/for-mfd-next;
Patch (3/5):
 - Remove the operation that adds `compatible` to the `select` node.

Link to V3:
https://lore.kernel.org/all/cover.1785480242.git.zhoubinbin@loongson.cn/

V3:
Patch (2/5):
 - New patch for moving thermal_ops to chip_data;
Patch (3/5):
 - Correct spelling errors;
Patch (4/5):
 - Add Acked-by from Conor, thanks;
Patch (5/5):
 - Keep loongson2_thermal_data->chip_data as const, and use
   data->flags as the private data.
 - Renmae LOONGSON2_THSENS_OUT_10B_MASK ->
   LOONGSON2_THSENS_OUT_11B_MASK;

Link to V2:
https://lore.kernel.org/all/cover.1784619512.git.zhoubinbin@loongson.cn/

V2:
Patch (1/4):
 - New patch form Sashiko;
Patch (2/4):
 - New patch for adding chipid syscon compatible;
Patch (3/4):
 - Use `loongson,chipid` phandle replace reg property;
Patch (3/4):
 - Refact `calib_offset` calculate routing;
 - Add LS2K0300_OLD_FUSE_FLAG flag.

Link to V1:
https://lore.kernel.org/all/cover.1783670011.git.zhoubinbin@loongson.cn/

Binbin Zhou (7):
  thermal/drivers/loongson2: Correct thermal sensor registration loop
  thermal/drivers/loongson2: Fix clamp() usage for thermal trip points
  thermal/drivers/loongson2: Fix Loongson-2K2000 trip point programming
  thermal/drivers/loongson2: Use bitfields and per-SoC thermal ops
  thermal/drivers/loongson2: Move per-SoC ops into chip data
  dt-bindings: thermal: loongson,ls2k-thermal: Add compatible for
    Loongson-2K0300
  thermal/drivers/loongson2: Add Loongson-2K0300 support

 .../thermal/loongson,ls2k-thermal.yaml        |  73 +++-
 drivers/thermal/loongson2_thermal.c           | 336 ++++++++++++++----
 2 files changed, 321 insertions(+), 88 deletions(-)


base-commit: ec0d89150a9381d591344a9f6f5428655c227a7f
-- 
2.52.0


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

* [PATCH v6 1/7] thermal/drivers/loongson2: Correct thermal sensor registration loop
  2026-09-28  4:44 [PATCH v6 0/7] thermal: loongson2: Add support for Loongson-2K0300 SoC Binbin Zhou
@ 2026-09-28  4:44 ` Binbin Zhou
  2026-09-28  7:15   ` Daniel Lezcano
  2026-09-28  4:44 ` [PATCH v6 2/7] thermal/drivers/loongson2: Fix clamp() usage for thermal trip points Binbin Zhou
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: Binbin Zhou @ 2026-09-28  4:44 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Yinbo Zhu, Rafael J . Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-pm,
	Binbin Zhou, stable, Sashiko

The registration loop in loongson2_thermal_probe() incorrectly uses
dev_err_probe() when the sensor is not present (-ENODEV). In that case,
the driver should continue to the next sensor index rather than treating
it as a fatal error.

Fix this by correctly handling -ENODEV and only returning on other
errors. Also add a final check to ensure at least one thermal zone was
registered.

Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/cover.1783670011.git.zhoubinbin@loongson.cn?part=2
Fixes: e7e3a7c35791 ("thermal/drivers/loongson-2: Add thermal management support")
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 drivers/thermal/loongson2_thermal.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c
index 4d40fc706a53..99b7392fc68f 100644
--- a/drivers/thermal/loongson2_thermal.c
+++ b/drivers/thermal/loongson2_thermal.c
@@ -160,16 +160,18 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
 
 	for (i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
 		tzd = devm_thermal_of_zone_register(dev, i, data, thermal_ops);
-
 		if (!IS_ERR(tzd))
 			break;
 
-		if (PTR_ERR(tzd) != -ENODEV)
+		if (PTR_ERR(tzd) == -ENODEV)
 			continue;
 
-		return dev_err_probe(dev, PTR_ERR(tzd), "failed to register");
+		return dev_err_probe(dev, PTR_ERR(tzd), "failed to register sensor %d\n", i);
 	}
 
+	if (IS_ERR(tzd))
+		return dev_err_probe(dev, -ENODEV, "No thermal sensor registered\n");
+
 	ret = devm_request_threaded_irq(dev, irq, NULL, loongson2_thermal_irq_thread,
 					IRQF_ONESHOT, "loongson2_thermal", tzd);
 	if (ret < 0)
-- 
2.52.0


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

* [PATCH v6 2/7] thermal/drivers/loongson2: Fix clamp() usage for thermal trip points
  2026-09-28  4:44 [PATCH v6 0/7] thermal: loongson2: Add support for Loongson-2K0300 SoC Binbin Zhou
  2026-09-28  4:44 ` [PATCH v6 1/7] thermal/drivers/loongson2: Correct thermal sensor registration loop Binbin Zhou
@ 2026-09-28  4:44 ` Binbin Zhou
  2026-09-28  4:44 ` [PATCH v6 3/7] thermal/drivers/loongson2: Fix Loongson-2K2000 trip point programming Binbin Zhou
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Binbin Zhou @ 2026-09-28  4:44 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Yinbo Zhu, Rafael J . Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-pm,
	Binbin Zhou, stable

clamp() takes the value to clamp as its first argument, followed by the
minimum and maximum bounds. The current code passes the -40 and 125
limits as the value instead, so the trip thresholds are not clamped to the
supported sensor range.

Correct the arguments so that low and high are clamped to [-40, 125].

Cc: stable@vger.kernel.org
Fixes: 734b5def91b5 ("thermal/drivers/loongson2: Add Loongson-2K2000 support")
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 drivers/thermal/loongson2_thermal.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c
index 99b7392fc68f..bcabca360157 100644
--- a/drivers/thermal/loongson2_thermal.c
+++ b/drivers/thermal/loongson2_thermal.c
@@ -62,10 +62,10 @@ static int loongson2_thermal_set(struct loongson2_thermal_data *data,
 				 int low, int high, bool enable)
 {
 	/* Set low temperature threshold */
-	loongson2_set_ctrl_regs(data, clamp(-40, low, high), true, enable);
+	loongson2_set_ctrl_regs(data, clamp(low, -40, 125), true, enable);
 
 	/* Set high temperature threshold */
-	loongson2_set_ctrl_regs(data, clamp(125, low, high), false, enable);
+	loongson2_set_ctrl_regs(data, clamp(high, -40, 125), false, enable);
 
 	return 0;
 }
-- 
2.52.0


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

* [PATCH v6 3/7] thermal/drivers/loongson2: Fix Loongson-2K2000 trip point programming
  2026-09-28  4:44 [PATCH v6 0/7] thermal: loongson2: Add support for Loongson-2K0300 SoC Binbin Zhou
  2026-09-28  4:44 ` [PATCH v6 1/7] thermal/drivers/loongson2: Correct thermal sensor registration loop Binbin Zhou
  2026-09-28  4:44 ` [PATCH v6 2/7] thermal/drivers/loongson2: Fix clamp() usage for thermal trip points Binbin Zhou
@ 2026-09-28  4:44 ` Binbin Zhou
  2026-09-28  4:44 ` [PATCH v6 4/7] thermal/drivers/loongson2: Use bitfields and per-SoC thermal ops Binbin Zhou
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Binbin Zhou @ 2026-09-28  4:44 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Yinbo Zhu, Rafael J . Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-pm,
	Binbin Zhou, stable

Loongson-2K2000 uses a different trip point layout than Loongson-2K1000:
the low 8 bits of the gate value are written to the control register,
while the high 8 bits are written to separate HI_GATE_HI/LOW registers.
The gate value is calculated as (temp + 311) * 0x4000 / 820.

Introduce a per-SoC set_trips_regs() callback. Keep the existing
Loongson-2K1000 logic and add the Loongson-2K2000 implementation.
Move the common clamping into loongson2_thermal_set_trips() and pass
Celsius values to the callback.

Cc: stable@vger.kernel.org
Fixes: 734b5def91b5 ("thermal/drivers/loongson2: Add Loongson-2K2000 support")
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 drivers/thermal/loongson2_thermal.c | 77 ++++++++++++++++++++---------
 1 file changed, 55 insertions(+), 22 deletions(-)

diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c
index bcabca360157..45fe6100134e 100644
--- a/drivers/thermal/loongson2_thermal.c
+++ b/drivers/thermal/loongson2_thermal.c
@@ -29,15 +29,23 @@
 					 LOONGSON2_THSENS_INT_HIGH)
 #define LOONGSON2_THSENS_OUT_MASK	0xFF
 
+/* Loongson-2K2000-Specific Registers */
+#define LS2K2000_THSENS_HI_GATE_HI_REG	0x18
+#define LS2K2000_THSENS_HI_GATE_LOW_REG	0x1c
+
 /*
  * This flag is used to indicate the temperature reading
  * method of the Loongson-2K2000
  */
 #define LS2K2000_THSENS_OUT_FLAG	BIT(0)
 
+struct loongson2_thermal_data;
+
 struct loongson2_thermal_chip_data {
 	unsigned int thermal_sensor_sel;
 	unsigned int flags;
+	void (*set_trips_regs)(struct loongson2_thermal_data *data,
+			       int temp, bool low, bool enable);
 };
 
 struct loongson2_thermal_data {
@@ -46,30 +54,40 @@ struct loongson2_thermal_data {
 	const struct loongson2_thermal_chip_data *chip_data;
 };
 
-static void loongson2_set_ctrl_regs(struct loongson2_thermal_data *data,
-				    int ctrl_data, bool low, bool enable)
+static void loongson2_thermal_set_trip_temp(struct loongson2_thermal_data *data,
+					    int low, int high, bool enable)
 {
-	int reg_ctrl = 0;
-	int reg_off  = data->chip_data->thermal_sensor_sel * 2;
-	int ctrl_reg = low ? LOONGSON2_THSENS_CTRL_LOW_REG : LOONGSON2_THSENS_CTRL_HI_REG;
+	/* Set low temperature threshold */
+	data->chip_data->set_trips_regs(data, low, true, enable);
 
-	reg_ctrl = ctrl_data + HECTO;
-	reg_ctrl |= enable ? 0x100 : 0;
-	writew(reg_ctrl, data->ctrl_reg + ctrl_reg + reg_off);
+	/* Set high temperature threshold */
+	data->chip_data->set_trips_regs(data, high, false, enable);
 }
 
-static int loongson2_thermal_set(struct loongson2_thermal_data *data,
-				 int low, int high, bool enable)
+static int loongson2_thermal_set_trips(struct thermal_zone_device *tz, int low, int high)
 {
-	/* Set low temperature threshold */
-	loongson2_set_ctrl_regs(data, clamp(low, -40, 125), true, enable);
+	struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);
 
-	/* Set high temperature threshold */
-	loongson2_set_ctrl_regs(data, clamp(high, -40, 125), false, enable);
+	low = clamp(low, -40000, 125000);
+	high = clamp(high, -40000, 125000);
+
+	loongson2_thermal_set_trip_temp(data, low / MILLI, high / MILLI, true);
 
 	return 0;
 }
 
+static void loongson2_2k1000_set_trips_regs(struct loongson2_thermal_data *data,
+					    int temp, bool low, bool enable)
+{
+	int reg_ctrl = 0;
+	int reg_off  = data->chip_data->thermal_sensor_sel * 2;
+	int ctrl_reg = low ? LOONGSON2_THSENS_CTRL_LOW_REG : LOONGSON2_THSENS_CTRL_HI_REG;
+
+	reg_ctrl = temp + HECTO;
+	reg_ctrl |= enable ? 0x100 : 0;
+	writew(reg_ctrl, data->ctrl_reg + ctrl_reg + reg_off);
+}
+
 static int loongson2_2k1000_get_temp(struct thermal_zone_device *tz, int *temp)
 {
 	int val;
@@ -81,6 +99,26 @@ static int loongson2_2k1000_get_temp(struct thermal_zone_device *tz, int *temp)
 	return 0;
 }
 
+static void loongson2_2k2000_set_trips_regs(struct loongson2_thermal_data *data,
+					    int temp, bool low, bool enable)
+{
+	int hi_reg, ctrl_reg;
+	int val = 0, gate;
+
+	ctrl_reg = low ? LOONGSON2_THSENS_CTRL_LOW_REG : LOONGSON2_THSENS_CTRL_HI_REG;
+	gate = (temp + 311) * 0x4000 / 820;
+
+	val = gate & 0xff;
+	val |= enable ? 0x100 : 0;
+	writel(val, data->ctrl_reg + ctrl_reg);
+
+	hi_reg = low ? LS2K2000_THSENS_HI_GATE_LOW_REG : LS2K2000_THSENS_HI_GATE_HI_REG;
+
+	val = readl(data->ctrl_reg + hi_reg);
+	val = (val & ~0xff) | ((gate >> 8) & 0xff);
+	writel(val, data->ctrl_reg + hi_reg);
+}
+
 static int loongson2_2k2000_get_temp(struct thermal_zone_device *tz, int *temp)
 {
 	int val;
@@ -104,13 +142,6 @@ static irqreturn_t loongson2_thermal_irq_thread(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
-static int loongson2_thermal_set_trips(struct thermal_zone_device *tz, int low, int high)
-{
-	struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);
-
-	return loongson2_thermal_set(data, low/MILLI, high/MILLI, true);
-}
-
 static const struct thermal_zone_device_ops loongson2_2k1000_of_thermal_ops = {
 	.get_temp = loongson2_2k1000_get_temp,
 	.set_trips = loongson2_thermal_set_trips,
@@ -156,7 +187,7 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
 
 	writeb(LOONGSON2_THSENS_INT_EN, data->ctrl_reg + LOONGSON2_THSENS_STATUS_REG);
 
-	loongson2_thermal_set(data, 0, 0, false);
+	loongson2_thermal_set_trip_temp(data, 0, 0, false);
 
 	for (i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
 		tzd = devm_thermal_of_zone_register(dev, i, data, thermal_ops);
@@ -185,11 +216,13 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
 static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k1000_data = {
 	.thermal_sensor_sel = 0,
 	.flags = 0,
+	.set_trips_regs = loongson2_2k1000_set_trips_regs,
 };
 
 static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k2000_data = {
 	.thermal_sensor_sel = 0,
 	.flags = LS2K2000_THSENS_OUT_FLAG,
+	.set_trips_regs = loongson2_2k2000_set_trips_regs,
 };
 
 static const struct of_device_id of_loongson2_thermal_match[] = {
-- 
2.52.0


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

* [PATCH v6 4/7] thermal/drivers/loongson2: Use bitfields and per-SoC thermal ops
  2026-09-28  4:44 [PATCH v6 0/7] thermal: loongson2: Add support for Loongson-2K0300 SoC Binbin Zhou
                   ` (2 preceding siblings ...)
  2026-09-28  4:44 ` [PATCH v6 3/7] thermal/drivers/loongson2: Fix Loongson-2K2000 trip point programming Binbin Zhou
@ 2026-09-28  4:44 ` Binbin Zhou
  2026-09-28  4:44 ` [PATCH v6 5/7] thermal/drivers/loongson2: Move per-SoC ops into chip data Binbin Zhou
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Binbin Zhou @ 2026-09-28  4:44 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Yinbo Zhu, Rafael J . Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-pm,
	Binbin Zhou

Replace open-coded masks and shifts with GENMASK()/FIELD_* helpers, and
define named constants for the Loongson-2K2000 temperature conversion
and trip gate calculations.

Split the temperature read and thermal zone ops into Loongson-2K1000 and
Loongson-2K2000 variants, and keep the chip-specific trip register
callback in the chip data. This prepares the driver for further SoC
support.

No functional change intended.

Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 drivers/thermal/loongson2_thermal.c | 123 ++++++++++++++++------------
 1 file changed, 72 insertions(+), 51 deletions(-)

diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c
index 45fe6100134e..0660a74fd922 100644
--- a/drivers/thermal/loongson2_thermal.c
+++ b/drivers/thermal/loongson2_thermal.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2022-2023 Loongson Technology Corporation Limited
  */
 
+#include <linux/bitfield.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/minmax.h>
@@ -27,11 +28,23 @@
 #define LOONGSON2_THSENS_INT_HIGH	BIT(1)
 #define LOONGSON2_THSENS_INT_EN		(LOONGSON2_THSENS_INT_LO | \
 					 LOONGSON2_THSENS_INT_HIGH)
-#define LOONGSON2_THSENS_OUT_MASK	0xFF
+#define LOONGSON2_THSENS_CTRL_INTEN	BIT(8)
+
+#define LOONGSON2_THSENS_OUT_8B_MASK	GENMASK(7, 0)
+#define LOONGSON2_THSENS_OUT_16B_MASK	GENMASK(15, 0)
+
+#define LOONGSON2_LOWEST_VALID_TEMP     (-40000)
+#define LOONGSON2_HIGHEST_VALID_TEMP    (125000)
 
 /* Loongson-2K2000-Specific Registers */
 #define LS2K2000_THSENS_HI_GATE_HI_REG	0x18
 #define LS2K2000_THSENS_HI_GATE_LOW_REG	0x1c
+#define LS2K2000_GATE0_VAL_MASK		GENMASK(7, 0)
+#define LS2K2000_THSENS_SEL_MASK	GENMASK(11, 10)
+
+#define LS2K2000_TEMP_MUL		(820)
+#define LS2K2000_TEMP_DIV		(0x4000)
+#define LS2K2000_TEMP_OFFSET		(311)
 
 /*
  * This flag is used to indicate the temperature reading
@@ -64,71 +77,101 @@ static void loongson2_thermal_set_trip_temp(struct loongson2_thermal_data *data,
 	data->chip_data->set_trips_regs(data, high, false, enable);
 }
 
-static int loongson2_thermal_set_trips(struct thermal_zone_device *tz, int low, int high)
+static int loognson2_thermal_set_trips(struct thermal_zone_device *tz, int low, int high)
 {
 	struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);
 
-	low = clamp(low, -40000, 125000);
-	high = clamp(high, -40000, 125000);
+	low = clamp(low, LOONGSON2_LOWEST_VALID_TEMP, LOONGSON2_HIGHEST_VALID_TEMP);
+	high = clamp(high, LOONGSON2_LOWEST_VALID_TEMP, LOONGSON2_HIGHEST_VALID_TEMP);
 
 	loongson2_thermal_set_trip_temp(data, low / MILLI, high / MILLI, true);
 
 	return 0;
 }
 
-static void loongson2_2k1000_set_trips_regs(struct loongson2_thermal_data *data,
+static int ls2k1000_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
+{
+	struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);
+	int val;
+
+	val = FIELD_GET(LOONGSON2_THSENS_OUT_8B_MASK,
+			readl(data->ctrl_reg + LOONGSON2_THSENS_OUT_REG));
+	*temp = (val - HECTO) * KILO;
+
+	return 0;
+}
+
+static void ls2k1000_thermal_set_trips_regs(struct loongson2_thermal_data *data,
 					    int temp, bool low, bool enable)
 {
-	int reg_ctrl = 0;
-	int reg_off  = data->chip_data->thermal_sensor_sel * 2;
 	int ctrl_reg = low ? LOONGSON2_THSENS_CTRL_LOW_REG : LOONGSON2_THSENS_CTRL_HI_REG;
+	int reg_off  = data->chip_data->thermal_sensor_sel * 2;
+	int reg_ctrl = 0;
 
 	reg_ctrl = temp + HECTO;
-	reg_ctrl |= enable ? 0x100 : 0;
+	if (enable)
+		reg_ctrl |= LOONGSON2_THSENS_CTRL_INTEN;
+
 	writew(reg_ctrl, data->ctrl_reg + ctrl_reg + reg_off);
 }
 
-static int loongson2_2k1000_get_temp(struct thermal_zone_device *tz, int *temp)
+static int ls2k2000_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
 {
-	int val;
 	struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);
+	int val;
 
-	val = readl(data->ctrl_reg + LOONGSON2_THSENS_OUT_REG);
-	*temp = ((val & LOONGSON2_THSENS_OUT_MASK) - HECTO) * KILO;
+	val = FIELD_GET(LOONGSON2_THSENS_OUT_16B_MASK, readl(data->temp_reg));
+	*temp = (val * LS2K2000_TEMP_MUL / LS2K2000_TEMP_DIV - LS2K2000_TEMP_OFFSET) * KILO;
 
 	return 0;
 }
 
-static void loongson2_2k2000_set_trips_regs(struct loongson2_thermal_data *data,
+static void ls2k2000_thermal_set_trips_regs(struct loongson2_thermal_data *data,
 					    int temp, bool low, bool enable)
 {
 	int hi_reg, ctrl_reg;
 	int val = 0, gate;
 
 	ctrl_reg = low ? LOONGSON2_THSENS_CTRL_LOW_REG : LOONGSON2_THSENS_CTRL_HI_REG;
-	gate = (temp + 311) * 0x4000 / 820;
+	gate = (temp + LS2K2000_TEMP_OFFSET) * LS2K2000_TEMP_DIV / LS2K2000_TEMP_MUL;
+
+	val = FIELD_PREP(LS2K2000_GATE0_VAL_MASK, FIELD_GET(GENMASK(7, 0), gate)) |
+	      FIELD_PREP(LS2K2000_THSENS_SEL_MASK, 0);
+	if (enable)
+		val |= LOONGSON2_THSENS_CTRL_INTEN;
 
-	val = gate & 0xff;
-	val |= enable ? 0x100 : 0;
 	writel(val, data->ctrl_reg + ctrl_reg);
 
 	hi_reg = low ? LS2K2000_THSENS_HI_GATE_LOW_REG : LS2K2000_THSENS_HI_GATE_HI_REG;
 
 	val = readl(data->ctrl_reg + hi_reg);
-	val = (val & ~0xff) | ((gate >> 8) & 0xff);
+	val &= ~LS2K2000_GATE0_VAL_MASK;
+	val |= FIELD_PREP(LS2K2000_GATE0_VAL_MASK, FIELD_GET(GENMASK(15, 8), gate));
+
 	writel(val, data->ctrl_reg + hi_reg);
 }
 
-static int loongson2_2k2000_get_temp(struct thermal_zone_device *tz, int *temp)
-{
-	int val;
-	struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);
+static const struct thermal_zone_device_ops ls2k1000_thermal_zone_ops = {
+	.get_temp = ls2k1000_thermal_get_temp,
+	.set_trips = loognson2_thermal_set_trips,
+};
 
-	val = readl(data->temp_reg);
-	*temp = ((val & 0xffff) * 820 / 0x4000 - 311) * KILO;
+static const struct thermal_zone_device_ops ls2k2000_thermal_zone_ops = {
+	.get_temp = ls2k2000_thermal_get_temp,
+	.set_trips = loognson2_thermal_set_trips,
+};
 
-	return 0;
-}
+static const struct loongson2_thermal_chip_data ls2k1000_thermal_chip_data = {
+	.thermal_sensor_sel = 0,
+	.flags = 0,
+	.set_trips_regs = ls2k1000_thermal_set_trips_regs,
+};
+
+static const struct loongson2_thermal_chip_data ls2k2000_thermal_chip_data = {
+	.thermal_sensor_sel = 0,
+	.flags = LS2K2000_THSENS_OUT_FLAG,
+	.set_trips_regs = ls2k2000_thermal_set_trips_regs,
+};
 
 static irqreturn_t loongson2_thermal_irq_thread(int irq, void *dev)
 {
@@ -142,16 +185,6 @@ static irqreturn_t loongson2_thermal_irq_thread(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
-static const struct thermal_zone_device_ops loongson2_2k1000_of_thermal_ops = {
-	.get_temp = loongson2_2k1000_get_temp,
-	.set_trips = loongson2_thermal_set_trips,
-};
-
-static const struct thermal_zone_device_ops loongson2_2k2000_of_thermal_ops = {
-	.get_temp = loongson2_2k2000_get_temp,
-	.set_trips = loongson2_thermal_set_trips,
-};
-
 static int loongson2_thermal_probe(struct platform_device *pdev)
 {
 	const struct thermal_zone_device_ops *thermal_ops;
@@ -176,9 +209,9 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
 		if (IS_ERR(data->temp_reg))
 			return PTR_ERR(data->temp_reg);
 
-		thermal_ops = &loongson2_2k2000_of_thermal_ops;
+		thermal_ops = &ls2k2000_thermal_zone_ops;
 	} else {
-		thermal_ops = &loongson2_2k1000_of_thermal_ops;
+		thermal_ops = &ls2k1000_thermal_zone_ops;
 	}
 
 	irq = platform_get_irq(pdev, 0);
@@ -213,26 +246,14 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k1000_data = {
-	.thermal_sensor_sel = 0,
-	.flags = 0,
-	.set_trips_regs = loongson2_2k1000_set_trips_regs,
-};
-
-static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k2000_data = {
-	.thermal_sensor_sel = 0,
-	.flags = LS2K2000_THSENS_OUT_FLAG,
-	.set_trips_regs = loongson2_2k2000_set_trips_regs,
-};
-
 static const struct of_device_id of_loongson2_thermal_match[] = {
 	{
 		.compatible = "loongson,ls2k1000-thermal",
-		.data = &loongson2_thermal_ls2k1000_data,
+		.data = &ls2k1000_thermal_chip_data,
 	},
 	{
 		.compatible = "loongson,ls2k2000-thermal",
-		.data = &loongson2_thermal_ls2k2000_data,
+		.data = &ls2k2000_thermal_chip_data,
 	},
 	{ /* end */ }
 };
-- 
2.52.0


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

* [PATCH v6 5/7] thermal/drivers/loongson2: Move per-SoC ops into chip data
  2026-09-28  4:44 [PATCH v6 0/7] thermal: loongson2: Add support for Loongson-2K0300 SoC Binbin Zhou
                   ` (3 preceding siblings ...)
  2026-09-28  4:44 ` [PATCH v6 4/7] thermal/drivers/loongson2: Use bitfields and per-SoC thermal ops Binbin Zhou
@ 2026-09-28  4:44 ` Binbin Zhou
  2026-09-28  4:44 ` [PATCH v6 6/7] dt-bindings: thermal: loongson,ls2k-thermal: Add compatible for Loongson-2K0300 Binbin Zhou
  2026-09-28  4:44 ` [PATCH v6 7/7] thermal/drivers/loongson2: Add Loongson-2K0300 support Binbin Zhou
  6 siblings, 0 replies; 15+ messages in thread
From: Binbin Zhou @ 2026-09-28  4:44 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Yinbo Zhu, Rafael J . Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-pm,
	Binbin Zhou

Store the thermal_zone_device_ops pointer and the optional extended
resource initializer in struct loongson2_thermal_chip_data instead of
selecting them through flags in probe.

Rename the second mapped resource from temp_reg to extend_reg, and let
Loongson-2K2000 initialize it from its own init_extend_resource()
callback. This makes adding new SoCs with different register layouts
easier.

Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 drivers/thermal/loongson2_thermal.c | 50 ++++++++++++++++-------------
 1 file changed, 27 insertions(+), 23 deletions(-)

diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c
index 0660a74fd922..17aa1d80a2e6 100644
--- a/drivers/thermal/loongson2_thermal.c
+++ b/drivers/thermal/loongson2_thermal.c
@@ -46,24 +46,20 @@
 #define LS2K2000_TEMP_DIV		(0x4000)
 #define LS2K2000_TEMP_OFFSET		(311)
 
-/*
- * This flag is used to indicate the temperature reading
- * method of the Loongson-2K2000
- */
-#define LS2K2000_THSENS_OUT_FLAG	BIT(0)
-
 struct loongson2_thermal_data;
 
 struct loongson2_thermal_chip_data {
 	unsigned int thermal_sensor_sel;
-	unsigned int flags;
+	const struct thermal_zone_device_ops *thermal_ops;
 	void (*set_trips_regs)(struct loongson2_thermal_data *data,
 			       int temp, bool low, bool enable);
+	int (*init_extend_resource)(struct platform_device *pdev,
+				    struct loongson2_thermal_data *data);
 };
 
 struct loongson2_thermal_data {
 	void __iomem *ctrl_reg;
-	void __iomem *temp_reg;
+	void __iomem *extend_reg;
 	const struct loongson2_thermal_chip_data *chip_data;
 };
 
@@ -120,7 +116,7 @@ static int ls2k2000_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
 	struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);
 	int val;
 
-	val = FIELD_GET(LOONGSON2_THSENS_OUT_16B_MASK, readl(data->temp_reg));
+	val = FIELD_GET(LOONGSON2_THSENS_OUT_16B_MASK, readl(data->extend_reg));
 	*temp = (val * LS2K2000_TEMP_MUL / LS2K2000_TEMP_DIV - LS2K2000_TEMP_OFFSET) * KILO;
 
 	return 0;
@@ -151,6 +147,17 @@ static void ls2k2000_thermal_set_trips_regs(struct loongson2_thermal_data *data,
 	writel(val, data->ctrl_reg + hi_reg);
 }
 
+static int ls2k2000_thermal_init_extend_resource(struct platform_device *pdev,
+						 struct loongson2_thermal_data *data)
+{
+	/* The temperature output register is separate for Loongson-2K2000 */
+	data->extend_reg = devm_platform_ioremap_resource(pdev, 1);
+	if (IS_ERR(data->extend_reg))
+		return PTR_ERR(data->extend_reg);
+
+	return 0;
+}
+
 static const struct thermal_zone_device_ops ls2k1000_thermal_zone_ops = {
 	.get_temp = ls2k1000_thermal_get_temp,
 	.set_trips = loognson2_thermal_set_trips,
@@ -163,14 +170,15 @@ static const struct thermal_zone_device_ops ls2k2000_thermal_zone_ops = {
 
 static const struct loongson2_thermal_chip_data ls2k1000_thermal_chip_data = {
 	.thermal_sensor_sel = 0,
-	.flags = 0,
+	.thermal_ops = &ls2k1000_thermal_zone_ops,
 	.set_trips_regs = ls2k1000_thermal_set_trips_regs,
 };
 
 static const struct loongson2_thermal_chip_data ls2k2000_thermal_chip_data = {
 	.thermal_sensor_sel = 0,
-	.flags = LS2K2000_THSENS_OUT_FLAG,
+	.thermal_ops = &ls2k2000_thermal_zone_ops,
 	.set_trips_regs = ls2k2000_thermal_set_trips_regs,
+	.init_extend_resource = ls2k2000_thermal_init_extend_resource,
 };
 
 static irqreturn_t loongson2_thermal_irq_thread(int irq, void *dev)
@@ -187,9 +195,8 @@ static irqreturn_t loongson2_thermal_irq_thread(int irq, void *dev)
 
 static int loongson2_thermal_probe(struct platform_device *pdev)
 {
-	const struct thermal_zone_device_ops *thermal_ops;
-	struct device *dev = &pdev->dev;
 	struct loongson2_thermal_data *data;
+	struct device *dev = &pdev->dev;
 	struct thermal_zone_device *tzd;
 	int ret, irq, i;
 
@@ -198,20 +205,17 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	data->chip_data = device_get_match_data(dev);
+	if (!data->chip_data)
+		return -EINVAL;
 
 	data->ctrl_reg = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(data->ctrl_reg))
 		return PTR_ERR(data->ctrl_reg);
 
-	/* The temperature output register is separate for Loongson-2K2000 */
-	if (data->chip_data->flags & LS2K2000_THSENS_OUT_FLAG) {
-		data->temp_reg = devm_platform_ioremap_resource(pdev, 1);
-		if (IS_ERR(data->temp_reg))
-			return PTR_ERR(data->temp_reg);
-
-		thermal_ops = &ls2k2000_thermal_zone_ops;
-	} else {
-		thermal_ops = &ls2k1000_thermal_zone_ops;
+	if (data->chip_data->init_extend_resource) {
+		ret = data->chip_data->init_extend_resource(pdev, data);
+		if (ret)
+			return ret;
 	}
 
 	irq = platform_get_irq(pdev, 0);
@@ -223,7 +227,7 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
 	loongson2_thermal_set_trip_temp(data, 0, 0, false);
 
 	for (i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
-		tzd = devm_thermal_of_zone_register(dev, i, data, thermal_ops);
+		tzd = devm_thermal_of_zone_register(dev, i, data, data->chip_data->thermal_ops);
 		if (!IS_ERR(tzd))
 			break;
 
-- 
2.52.0


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

* [PATCH v6 6/7] dt-bindings: thermal: loongson,ls2k-thermal: Add compatible for Loongson-2K0300
  2026-09-28  4:44 [PATCH v6 0/7] thermal: loongson2: Add support for Loongson-2K0300 SoC Binbin Zhou
                   ` (4 preceding siblings ...)
  2026-09-28  4:44 ` [PATCH v6 5/7] thermal/drivers/loongson2: Move per-SoC ops into chip data Binbin Zhou
@ 2026-09-28  4:44 ` Binbin Zhou
  2026-09-28  4:44 ` [PATCH v6 7/7] thermal/drivers/loongson2: Add Loongson-2K0300 support Binbin Zhou
  6 siblings, 0 replies; 15+ messages in thread
From: Binbin Zhou @ 2026-09-28  4:44 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Yinbo Zhu, Rafael J . Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-pm,
	Binbin Zhou, Conor Dooley

Add a new compatible string `loongson,ls2k0300-thermal` for the thermal
sensor found on the Loongson-2K0300 SoC.

The hardware differs from existing SoCs in that it requires a phandle to
a syscon node that provides the CHIP ID register, used as a compensation
source in the temperature calculation.

Update the binding to make `loongson,chipid` required for this new
compatible, and clarify the register region requirements for each
variant.

Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 .../thermal/loongson,ls2k-thermal.yaml        | 73 ++++++++++++++-----
 1 file changed, 55 insertions(+), 18 deletions(-)

diff --git a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
index 79e691b08341..d312e27737a2 100644
--- a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
+++ b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
@@ -10,13 +10,11 @@ maintainers:
   - zhanghongchen <zhanghongchen@loongson.cn>
   - Yinbo Zhu <zhuyinbo@loongson.cn>
 
-allOf:
-  - $ref: /schemas/thermal/thermal-sensor.yaml#
-
 properties:
   compatible:
     oneOf:
       - enum:
+          - loongson,ls2k0300-thermal
           - loongson,ls2k1000-thermal
           - loongson,ls2k2000-thermal
       - items:
@@ -34,28 +32,56 @@ properties:
   '#thermal-sensor-cells':
     const: 1
 
+  loongson,chipid:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to the syscon with the Loongson-2K0300 CHIP ID.
+
 required:
   - compatible
   - reg
   - interrupts
 
-if:
-  properties:
-    compatible:
-      contains:
-        enum:
-          - loongson,ls2k2000-thermal
+allOf:
+  - $ref: /schemas/thermal/thermal-sensor.yaml#
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: loongson,ls2k0300-thermal
+    then:
+      properties:
+        reg:
+          items:
+            - description: Thermal base register region
+      required:
+        - loongson,chipid
 
-then:
-  properties:
-    reg:
-      minItems: 2
-      maxItems: 2
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: loongson,ls2k1000-thermal
+    then:
+      properties:
+        loongson,chipid: false
+        reg:
+          items:
+            - description: Thermal base register region
 
-else:
-  properties:
-    reg:
-      maxItems: 1
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: loongson,ls2k2000-thermal
+    then:
+      properties:
+        loongson,chipid: false
+        reg:
+          items:
+            - description: Thermal base register region
+            - description: Thermal data output register region
 
 unevaluatedProperties: false
 
@@ -69,3 +95,14 @@ examples:
         interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
         #thermal-sensor-cells = <1>;
     };
+
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    thermal-sensor@16001500 {
+       compatible = "loongson,ls2k0300-thermal";
+       reg = <0x16001500 0x30>;
+       interrupt-parent = <&liointc1>;
+       interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
+       loongson,chipid = <&chipid>;
+       #thermal-sensor-cells = <1>;
+    };
-- 
2.52.0


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

* [PATCH v6 7/7] thermal/drivers/loongson2: Add Loongson-2K0300 support
  2026-09-28  4:44 [PATCH v6 0/7] thermal: loongson2: Add support for Loongson-2K0300 SoC Binbin Zhou
                   ` (5 preceding siblings ...)
  2026-09-28  4:44 ` [PATCH v6 6/7] dt-bindings: thermal: loongson,ls2k-thermal: Add compatible for Loongson-2K0300 Binbin Zhou
@ 2026-09-28  4:44 ` Binbin Zhou
  6 siblings, 0 replies; 15+ messages in thread
From: Binbin Zhou @ 2026-09-28  4:44 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Yinbo Zhu, Rafael J . Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-pm,
	Binbin Zhou

The Loongson-2K0300 sensor provides an 11-bit output and requires
calibration data from the CHIP ID registers. Read the calibration offset
throughthe `loongson,chipid` syscon phandle, initialize the sensor
configuration register, and calculate the temperature with the
calibrated slope and offset.

Early Loongson-2K0300 fuse revisions may provide unusable calibration
data. If the calibrated formula reports a temperature outside the valid
sensor range, fall back to the old-fuse slope with a zero calibration
offset.

The set_trips callback of Loongson-2K0300 will be added in the future.

Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 drivers/thermal/loongson2_thermal.c | 136 ++++++++++++++++++++++++++++
 1 file changed, 136 insertions(+)

diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c
index 17aa1d80a2e6..a53d70b824f3 100644
--- a/drivers/thermal/loongson2_thermal.c
+++ b/drivers/thermal/loongson2_thermal.c
@@ -8,10 +8,12 @@
 #include <linux/bitfield.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/mfd/syscon.h>
 #include <linux/minmax.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
+#include <linux/regmap.h>
 #include <linux/thermal.h>
 #include <linux/units.h>
 
@@ -31,11 +33,37 @@
 #define LOONGSON2_THSENS_CTRL_INTEN	BIT(8)
 
 #define LOONGSON2_THSENS_OUT_8B_MASK	GENMASK(7, 0)
+#define LOONGSON2_THSENS_OUT_11B_MASK	GENMASK(10, 0)
 #define LOONGSON2_THSENS_OUT_16B_MASK	GENMASK(15, 0)
 
 #define LOONGSON2_LOWEST_VALID_TEMP     (-40000)
 #define LOONGSON2_HIGHEST_VALID_TEMP    (125000)
 
+/* Loongson-2K0300-Specific Registers */
+#define LS2K0300_CHIP_ID0		0x10
+#define LS2K0300_CHIP_ID1		0x14
+
+#define LS2K0300_THSENS_CFG_REG		0x18
+#define LS2K0300_THSENS_INIT_MASK	0xff03
+
+#define LS2K0300_EXTERN_ID		BIT(4)
+#define LS2K0300_ID0_VAL_MASK		GENMASK(31, 20)
+#define LS2K0300_ID1_VAL_MASK		GENMASK(15, 0)
+
+#define LS2K0300_COMP_VAL_MASK		GENMASK(14, 0)
+#define LS2K0300_COMP_SIGN_BIT		BIT(15)
+
+#define LS2K0300_TEMP_SLOPE		(570)	/* m°C/LSB, calibrated */
+#define LS2K0300_TEMP_SLOPE_OLD		(569)	/* m°C/LSB, old fuse */
+#define LS2K0300_TEMP_OFFSET		(394700) /* m°C */
+
+/*
+ * Set when the on-chip calibration data is unusable (early 2K0300
+ * fuse revision). The driver then uses LS2K0300_TEMP_SLOPE_OLD with
+ * calib_offset = 0 instead of the calibrated formula.
+ */
+#define LS2K0300_OLD_FUSE_FLAG		BIT(0)
+
 /* Loongson-2K2000-Specific Registers */
 #define LS2K2000_THSENS_HI_GATE_HI_REG	0x18
 #define LS2K2000_THSENS_HI_GATE_LOW_REG	0x1c
@@ -60,12 +88,18 @@ struct loongson2_thermal_chip_data {
 struct loongson2_thermal_data {
 	void __iomem *ctrl_reg;
 	void __iomem *extend_reg;
+	struct regmap *regmap_cfg;
+	unsigned int flags;
+	int calib_offset;
 	const struct loongson2_thermal_chip_data *chip_data;
 };
 
 static void loongson2_thermal_set_trip_temp(struct loongson2_thermal_data *data,
 					    int low, int high, bool enable)
 {
+	if (!data->chip_data->set_trips_regs)
+		return;
+
 	/* Set low temperature threshold */
 	data->chip_data->set_trips_regs(data, low, true, enable);
 
@@ -85,6 +119,94 @@ static int loognson2_thermal_set_trips(struct thermal_zone_device *tz, int low,
 	return 0;
 }
 
+static int ls2k0300_adc_to_temp_mc(struct loongson2_thermal_data *data, int slope)
+{
+	int raw_adc;
+
+	raw_adc = FIELD_GET(LOONGSON2_THSENS_OUT_11B_MASK,
+			    readl(data->ctrl_reg + LOONGSON2_THSENS_OUT_REG));
+
+	return (raw_adc + data->calib_offset) * slope - LS2K0300_TEMP_OFFSET;
+}
+
+static int ls2k0300_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
+{
+	struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);
+	int slope = LS2K0300_TEMP_SLOPE;
+
+	if (data->flags & LS2K0300_OLD_FUSE_FLAG)
+		slope = LS2K0300_TEMP_SLOPE_OLD;
+
+	*temp = ls2k0300_adc_to_temp_mc(data, slope);
+
+	return 0;
+}
+
+static void ls2k0300_thermal_detect_old_fuse(struct device *dev,
+					     struct loongson2_thermal_data *data)
+{
+	int temp;
+
+	temp = ls2k0300_adc_to_temp_mc(data, LS2K0300_TEMP_SLOPE);
+
+	if (temp < LOONGSON2_LOWEST_VALID_TEMP ||
+	    temp > LOONGSON2_HIGHEST_VALID_TEMP) {
+		dev_warn(dev, "calibrated temperature %d m°C out of range [%d, %d], using old fuse formula\n",
+			 temp, LOONGSON2_LOWEST_VALID_TEMP, LOONGSON2_HIGHEST_VALID_TEMP);
+		data->flags = LS2K0300_OLD_FUSE_FLAG;
+		data->calib_offset = 0;
+	}
+}
+
+static int ls2k0300_thermal_read_calib(struct loongson2_thermal_data *data)
+{
+	u32 chip_id0, chip_id1;
+	int calib_data, calib_offset, ret;
+
+	ret = regmap_read(data->regmap_cfg, LS2K0300_CHIP_ID0, &chip_id0);
+	if (ret)
+		return ret;
+
+	ret = regmap_read(data->regmap_cfg, LS2K0300_CHIP_ID1, &chip_id1);
+	if (ret)
+		return ret;
+
+	if (chip_id0 & LS2K0300_EXTERN_ID) {
+		calib_data = FIELD_GET(LS2K0300_ID1_VAL_MASK, chip_id1);
+		calib_offset = FIELD_GET(LS2K0300_COMP_VAL_MASK, calib_data);
+		if (calib_data & LS2K0300_COMP_SIGN_BIT)
+			calib_offset = -calib_offset;
+	} else {
+		calib_data = FIELD_GET(LS2K0300_ID0_VAL_MASK, chip_id0);
+		calib_offset = FIELD_GET(LS2K0300_COMP_VAL_MASK, calib_data);
+	}
+
+	data->calib_offset = calib_offset;
+	return 0;
+}
+
+static int ls2k0300_thermal_init_extend_resource(struct platform_device *pdev,
+						 struct loongson2_thermal_data *data)
+{
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	data->regmap_cfg =
+		syscon_regmap_lookup_by_phandle(dev->of_node, "loongson,chipid");
+	if (IS_ERR(data->regmap_cfg))
+		return PTR_ERR(data->regmap_cfg);
+
+	ret = ls2k0300_thermal_read_calib(data);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to read calibration data\n");
+
+	writel(LS2K0300_THSENS_INIT_MASK, data->ctrl_reg + LS2K0300_THSENS_CFG_REG);
+
+	ls2k0300_thermal_detect_old_fuse(dev, data);
+
+	return 0;
+}
+
 static int ls2k1000_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
 {
 	struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);
@@ -158,6 +280,10 @@ static int ls2k2000_thermal_init_extend_resource(struct platform_device *pdev,
 	return 0;
 }
 
+static const struct thermal_zone_device_ops ls2k0300_thermal_zone_ops = {
+	.get_temp = ls2k0300_thermal_get_temp,
+};
+
 static const struct thermal_zone_device_ops ls2k1000_thermal_zone_ops = {
 	.get_temp = ls2k1000_thermal_get_temp,
 	.set_trips = loognson2_thermal_set_trips,
@@ -168,6 +294,12 @@ static const struct thermal_zone_device_ops ls2k2000_thermal_zone_ops = {
 	.set_trips = loognson2_thermal_set_trips,
 };
 
+static const struct loongson2_thermal_chip_data ls2k0300_thermal_chip_data = {
+	.thermal_sensor_sel = 0,
+	.thermal_ops = &ls2k0300_thermal_zone_ops,
+	.init_extend_resource = ls2k0300_thermal_init_extend_resource,
+};
+
 static const struct loongson2_thermal_chip_data ls2k1000_thermal_chip_data = {
 	.thermal_sensor_sel = 0,
 	.thermal_ops = &ls2k1000_thermal_zone_ops,
@@ -251,6 +383,10 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
 }
 
 static const struct of_device_id of_loongson2_thermal_match[] = {
+	{
+		.compatible = "loongson,ls2k0300-thermal",
+		.data = &ls2k0300_thermal_chip_data,
+	},
 	{
 		.compatible = "loongson,ls2k1000-thermal",
 		.data = &ls2k1000_thermal_chip_data,
-- 
2.52.0


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

* Re: [PATCH v6 1/7] thermal/drivers/loongson2: Correct thermal sensor registration loop
  2026-09-28  4:44 ` [PATCH v6 1/7] thermal/drivers/loongson2: Correct thermal sensor registration loop Binbin Zhou
@ 2026-09-28  7:15   ` Daniel Lezcano
  2026-09-28  8:17     ` Binbin Zhou
  0 siblings, 1 reply; 15+ messages in thread
From: Daniel Lezcano @ 2026-09-28  7:15 UTC (permalink / raw)
  To: Binbin Zhou, Binbin Zhou, Huacai Chen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Yinbo Zhu, Rafael J . Wysocki,
	Daniel Lezcano, Zhang Rui, Lukasz Luba
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-pm, stable,
	Sashiko

On 9/28/26 06:44, Binbin Zhou wrote:
> The registration loop in loongson2_thermal_probe() incorrectly uses
> dev_err_probe() when the sensor is not present (-ENODEV). In that case,
> the driver should continue to the next sensor index rather than treating
> it as a fatal error.
> 
> Fix this by correctly handling -ENODEV and only returning on other
> errors. Also add a final check to ensure at least one thermal zone was
> registered.
> 
> Cc: stable@vger.kernel.org
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Closes: https://sashiko.dev/#/patchset/cover.1783670011.git.zhoubinbin@loongson.cn?part=2
> Fixes: e7e3a7c35791 ("thermal/drivers/loongson-2: Add thermal management support")
> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> ---
>   drivers/thermal/loongson2_thermal.c | 8 +++++---
>   1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c
> index 4d40fc706a53..99b7392fc68f 100644
> --- a/drivers/thermal/loongson2_thermal.c
> +++ b/drivers/thermal/loongson2_thermal.c
> @@ -160,16 +160,18 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
>   
>   	for (i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
>   		tzd = devm_thermal_of_zone_register(dev, i, data, thermal_ops);
> -
>   		if (!IS_ERR(tzd))
>   			break;
>   
> -		if (PTR_ERR(tzd) != -ENODEV)
> +		if (PTR_ERR(tzd) == -ENODEV)
>   			continue;
>   
> -		return dev_err_probe(dev, PTR_ERR(tzd), "failed to register");
> +		return dev_err_probe(dev, PTR_ERR(tzd), "failed to register sensor %d\n", i);


>   	}
>   
> +	if (IS_ERR(tzd))
> +		return dev_err_probe(dev, -ENODEV, "No thermal sensor registered\n");
> +
>   	ret = devm_request_threaded_irq(dev, irq, NULL, loongson2_thermal_irq_thread,
>   					IRQF_ONESHOT, "loongson2_thermal", tzd);
>   	if (ret < 0)


The [no]error paths are confusing and prone to error, eg: 'if there is 
no error then check if there is an error', 'when exiting the loop 
without registering any sensor, then we assume tzd is -ENODEV'.

Please make a less cumbersome and implicit checks here. For example 
count the number of sensors and then do the check against.

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

* Re: [PATCH v6 1/7] thermal/drivers/loongson2: Correct thermal sensor registration loop
  2026-09-28  7:15   ` Daniel Lezcano
@ 2026-09-28  8:17     ` Binbin Zhou
  2026-09-28 13:23       ` Daniel Lezcano
  0 siblings, 1 reply; 15+ messages in thread
From: Binbin Zhou @ 2026-09-28  8:17 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Yinbo Zhu, Rafael J . Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba, Huacai Chen, Xuerui Wang, loongarch,
	devicetree, linux-pm, stable, Sashiko

Hi Daniel:

Thanks for your review.

On Mon, Sep 28, 2026 at 3:15 PM Daniel Lezcano
<daniel.lezcano@oss.qualcomm.com> wrote:
>
> On 9/28/26 06:44, Binbin Zhou wrote:
> > The registration loop in loongson2_thermal_probe() incorrectly uses
> > dev_err_probe() when the sensor is not present (-ENODEV). In that case,
> > the driver should continue to the next sensor index rather than treating
> > it as a fatal error.
> >
> > Fix this by correctly handling -ENODEV and only returning on other
> > errors. Also add a final check to ensure at least one thermal zone was
> > registered.
> >
> > Cc: stable@vger.kernel.org
> > Reported-by: Sashiko <sashiko-bot@kernel.org>
> > Closes: https://sashiko.dev/#/patchset/cover.1783670011.git.zhoubinbin@loongson.cn?part=2
> > Fixes: e7e3a7c35791 ("thermal/drivers/loongson-2: Add thermal management support")
> > Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> > ---
> >   drivers/thermal/loongson2_thermal.c | 8 +++++---
> >   1 file changed, 5 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c
> > index 4d40fc706a53..99b7392fc68f 100644
> > --- a/drivers/thermal/loongson2_thermal.c
> > +++ b/drivers/thermal/loongson2_thermal.c
> > @@ -160,16 +160,18 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
> >
> >       for (i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
> >               tzd = devm_thermal_of_zone_register(dev, i, data, thermal_ops);
> > -
> >               if (!IS_ERR(tzd))
> >                       break;
> >
> > -             if (PTR_ERR(tzd) != -ENODEV)
> > +             if (PTR_ERR(tzd) == -ENODEV)
> >                       continue;
> >
> > -             return dev_err_probe(dev, PTR_ERR(tzd), "failed to register");
> > +             return dev_err_probe(dev, PTR_ERR(tzd), "failed to register sensor %d\n", i);
>
>
> >       }
> >
> > +     if (IS_ERR(tzd))
> > +             return dev_err_probe(dev, -ENODEV, "No thermal sensor registered\n");
> > +
> >       ret = devm_request_threaded_irq(dev, irq, NULL, loongson2_thermal_irq_thread,
> >                                       IRQF_ONESHOT, "loongson2_thermal", tzd);
> >       if (ret < 0)
>
>
> The [no]error paths are confusing and prone to error, eg: 'if there is
> no error then check if there is an error', 'when exiting the loop
> without registering any sensor, then we assume tzd is -ENODEV'.
>
> Please make a less cumbersome and implicit checks here. For example
> count the number of sensors and then do the check against.

I thought about it, and you're right—I made the logic here too complicated.
Let's use `sensor_count` as the counter. Is the following check logic clearer?

        u32 sensor_count = 0;

        for (unsigned int i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
                tzd = devm_thermal_of_zone_register(dev, i, data,
data->chip_data->thermal_ops);
                if (IS_ERR(tzd)) {
                        if (PTR_ERR(tzd) == -ENODEV)
                                continue;

                        return dev_err_probe(dev, PTR_ERR(tzd),
                                             "failed to register sensor %d", i);
                }

                sensor_count++;
                break;
        }

        if (!sensor_count)
                return dev_err_probe(dev, -ENODEV, "no thermal sensor
registered");


-- 
Thanks.
Binbin

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

* Re: [PATCH v6 1/7] thermal/drivers/loongson2: Correct thermal sensor registration loop
  2026-09-28  8:17     ` Binbin Zhou
@ 2026-09-28 13:23       ` Daniel Lezcano
  2026-09-29  3:06         ` Binbin Zhou
  0 siblings, 1 reply; 15+ messages in thread
From: Daniel Lezcano @ 2026-09-28 13:23 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Yinbo Zhu, Rafael J . Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba, Huacai Chen, Xuerui Wang, loongarch,
	devicetree, linux-pm, stable, Sashiko

On 9/28/26 10:17, Binbin Zhou wrote:
> Hi Daniel:
> 
> Thanks for your review.
> 
> On Mon, Sep 28, 2026 at 3:15 PM Daniel Lezcano
> <daniel.lezcano@oss.qualcomm.com> wrote:
>>
>> On 9/28/26 06:44, Binbin Zhou wrote:
>>> The registration loop in loongson2_thermal_probe() incorrectly uses
>>> dev_err_probe() when the sensor is not present (-ENODEV). In that case,
>>> the driver should continue to the next sensor index rather than treating
>>> it as a fatal error.
>>>
>>> Fix this by correctly handling -ENODEV and only returning on other
>>> errors. Also add a final check to ensure at least one thermal zone was
>>> registered.
>>>
>>> Cc: stable@vger.kernel.org
>>> Reported-by: Sashiko <sashiko-bot@kernel.org>
>>> Closes: https://sashiko.dev/#/patchset/cover.1783670011.git.zhoubinbin@loongson.cn?part=2
>>> Fixes: e7e3a7c35791 ("thermal/drivers/loongson-2: Add thermal management support")
>>> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
>>> ---
>>>    drivers/thermal/loongson2_thermal.c | 8 +++++---
>>>    1 file changed, 5 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c
>>> index 4d40fc706a53..99b7392fc68f 100644
>>> --- a/drivers/thermal/loongson2_thermal.c
>>> +++ b/drivers/thermal/loongson2_thermal.c
>>> @@ -160,16 +160,18 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
>>>
>>>        for (i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
>>>                tzd = devm_thermal_of_zone_register(dev, i, data, thermal_ops);
>>> -
>>>                if (!IS_ERR(tzd))
>>>                        break;
>>>
>>> -             if (PTR_ERR(tzd) != -ENODEV)
>>> +             if (PTR_ERR(tzd) == -ENODEV)
>>>                        continue;
>>>
>>> -             return dev_err_probe(dev, PTR_ERR(tzd), "failed to register");
>>> +             return dev_err_probe(dev, PTR_ERR(tzd), "failed to register sensor %d\n", i);
>>
>>
>>>        }
>>>
>>> +     if (IS_ERR(tzd))
>>> +             return dev_err_probe(dev, -ENODEV, "No thermal sensor registered\n");
>>> +
>>>        ret = devm_request_threaded_irq(dev, irq, NULL, loongson2_thermal_irq_thread,
>>>                                        IRQF_ONESHOT, "loongson2_thermal", tzd);
>>>        if (ret < 0)
>>
>>
>> The [no]error paths are confusing and prone to error, eg: 'if there is
>> no error then check if there is an error', 'when exiting the loop
>> without registering any sensor, then we assume tzd is -ENODEV'.
>>
>> Please make a less cumbersome and implicit checks here. For example
>> count the number of sensors and then do the check against.
> 
> I thought about it, and you're right—I made the logic here too complicated.
> Let's use `sensor_count` as the counter. Is the following check logic clearer?
> 
>          u32 sensor_count = 0;
> 
>          for (unsigned int i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
>                  tzd = devm_thermal_of_zone_register(dev, i, data,
> data->chip_data->thermal_ops);
>                  if (IS_ERR(tzd)) {
>                          if (PTR_ERR(tzd) == -ENODEV)
>                                  continue;
> 
>                          return dev_err_probe(dev, PTR_ERR(tzd),
>                                               "failed to register sensor %d", i);
>                  }
> 
>                  sensor_count++;

If I'm not mistaken in the previous version, the loop exits at the first 
registered sensor

	if (!IS_ERR(tzd))
		break;

Here all the available sensors are registered

>                  break;
>          }
> 
>          if (!sensor_count)
>                  return dev_err_probe(dev, -ENODEV, "no thermal sensor
> registered");
> 
> 


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

* Re: [PATCH v6 1/7] thermal/drivers/loongson2: Correct thermal sensor registration loop
  2026-09-28 13:23       ` Daniel Lezcano
@ 2026-09-29  3:06         ` Binbin Zhou
  2026-09-29  5:46           ` Daniel Lezcano
  0 siblings, 1 reply; 15+ messages in thread
From: Binbin Zhou @ 2026-09-29  3:06 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Yinbo Zhu, Rafael J . Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba, Huacai Chen, Xuerui Wang, loongarch,
	devicetree, linux-pm, stable, Sashiko

Hi Daniel:

On Mon, Sep 28, 2026 at 9:23 PM Daniel Lezcano
<daniel.lezcano@oss.qualcomm.com> wrote:
>
> On 9/28/26 10:17, Binbin Zhou wrote:
> > Hi Daniel:
> >
> > Thanks for your review.
> >
> > On Mon, Sep 28, 2026 at 3:15 PM Daniel Lezcano
> > <daniel.lezcano@oss.qualcomm.com> wrote:
> >>
> >> On 9/28/26 06:44, Binbin Zhou wrote:
> >>> The registration loop in loongson2_thermal_probe() incorrectly uses
> >>> dev_err_probe() when the sensor is not present (-ENODEV). In that case,
> >>> the driver should continue to the next sensor index rather than treating
> >>> it as a fatal error.
> >>>
> >>> Fix this by correctly handling -ENODEV and only returning on other
> >>> errors. Also add a final check to ensure at least one thermal zone was
> >>> registered.
> >>>
> >>> Cc: stable@vger.kernel.org
> >>> Reported-by: Sashiko <sashiko-bot@kernel.org>
> >>> Closes: https://sashiko.dev/#/patchset/cover.1783670011.git.zhoubinbin@loongson.cn?part=2
> >>> Fixes: e7e3a7c35791 ("thermal/drivers/loongson-2: Add thermal management support")
> >>> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> >>> ---
> >>>    drivers/thermal/loongson2_thermal.c | 8 +++++---
> >>>    1 file changed, 5 insertions(+), 3 deletions(-)
> >>>
> >>> diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c
> >>> index 4d40fc706a53..99b7392fc68f 100644
> >>> --- a/drivers/thermal/loongson2_thermal.c
> >>> +++ b/drivers/thermal/loongson2_thermal.c
> >>> @@ -160,16 +160,18 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
> >>>
> >>>        for (i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
> >>>                tzd = devm_thermal_of_zone_register(dev, i, data, thermal_ops);
> >>> -
> >>>                if (!IS_ERR(tzd))
> >>>                        break;
> >>>
> >>> -             if (PTR_ERR(tzd) != -ENODEV)
> >>> +             if (PTR_ERR(tzd) == -ENODEV)
> >>>                        continue;
> >>>
> >>> -             return dev_err_probe(dev, PTR_ERR(tzd), "failed to register");
> >>> +             return dev_err_probe(dev, PTR_ERR(tzd), "failed to register sensor %d\n", i);
> >>
> >>
> >>>        }
> >>>
> >>> +     if (IS_ERR(tzd))
> >>> +             return dev_err_probe(dev, -ENODEV, "No thermal sensor registered\n");
> >>> +
> >>>        ret = devm_request_threaded_irq(dev, irq, NULL, loongson2_thermal_irq_thread,
> >>>                                        IRQF_ONESHOT, "loongson2_thermal", tzd);
> >>>        if (ret < 0)
> >>
> >>
> >> The [no]error paths are confusing and prone to error, eg: 'if there is
> >> no error then check if there is an error', 'when exiting the loop
> >> without registering any sensor, then we assume tzd is -ENODEV'.
> >>
> >> Please make a less cumbersome and implicit checks here. For example
> >> count the number of sensors and then do the check against.
> >
> > I thought about it, and you're right—I made the logic here too complicated.
> > Let's use `sensor_count` as the counter. Is the following check logic clearer?
> >
> >          u32 sensor_count = 0;
> >
> >          for (unsigned int i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
> >                  tzd = devm_thermal_of_zone_register(dev, i, data,
> > data->chip_data->thermal_ops);
> >                  if (IS_ERR(tzd)) {
> >                          if (PTR_ERR(tzd) == -ENODEV)
> >                                  continue;
> >
> >                          return dev_err_probe(dev, PTR_ERR(tzd),
> >                                               "failed to register sensor %d", i);
> >                  }
> >
> >                  sensor_count++;
>
> If I'm not mistaken in the previous version, the loop exits at the first
> registered sensor
>
>         if (!IS_ERR(tzd))
>                 break;
>
> Here all the available sensors are registered

The name `sensor_count` might be a bit misleading, but here the loop
exits after the first success:

                sensor_count++;
                break;

Let’s rename it:

bool registered = false;
...
for (...) {
    tzd = devm_thermal_of_zone_register(...);
    if (IS_ERR(tzd)) {
        if (PTR_ERR(tzd) == -ENODEV)
            continue;

        return dev_err_probe(dev, PTR_ERR(tzd),
                             "failed to register sensor %d", i);
    }

    registered = true;
    break;
}

if (!registered)
    return dev_err_probe(dev, -ENODEV, "no thermal sensor registered");
>
> >                  break;
> >          }
> >
> >          if (!sensor_count)
> >                  return dev_err_probe(dev, -ENODEV, "no thermal sensor
> > registered");
> >
> >
>

-- 
Thanks.
Binbin

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

* Re: [PATCH v6 1/7] thermal/drivers/loongson2: Correct thermal sensor registration loop
  2026-09-29  3:06         ` Binbin Zhou
@ 2026-09-29  5:46           ` Daniel Lezcano
  2026-09-29  8:23             ` Binbin Zhou
  0 siblings, 1 reply; 15+ messages in thread
From: Daniel Lezcano @ 2026-09-29  5:46 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Yinbo Zhu, Rafael J . Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba, Huacai Chen, Xuerui Wang, loongarch,
	devicetree, linux-pm, stable, Sashiko

On 9/29/26 05:06, Binbin Zhou wrote:
> Hi Daniel:

[ ... ]

>>>> Please make a less cumbersome and implicit checks here. For example
>>>> count the number of sensors and then do the check against.
>>>
>>> I thought about it, and you're right—I made the logic here too complicated.
>>> Let's use `sensor_count` as the counter. Is the following check logic clearer?
>>>
>>>           u32 sensor_count = 0;
>>>
>>>           for (unsigned int i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
>>>                   tzd = devm_thermal_of_zone_register(dev, i, data,
>>> data->chip_data->thermal_ops);
>>>                   if (IS_ERR(tzd)) {
>>>                           if (PTR_ERR(tzd) == -ENODEV)
>>>                                   continue;
>>>
>>>                           return dev_err_probe(dev, PTR_ERR(tzd),
>>>                                                "failed to register sensor %d", i);
>>>                   }
>>>
>>>                   sensor_count++;
>>
>> If I'm not mistaken in the previous version, the loop exits at the first
>> registered sensor
>>
>>          if (!IS_ERR(tzd))
>>                  break;
>>
>> Here all the available sensors are registered
> 
> The name `sensor_count` might be a bit misleading, but here the loop
> exits after the first success:
> 
>                  sensor_count++;
>                  break;
> 
> Let’s rename it:

Can you clarify why only the first sensor found stops the thermal zones 
registration ?

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

* Re: [PATCH v6 1/7] thermal/drivers/loongson2: Correct thermal sensor registration loop
  2026-09-29  5:46           ` Daniel Lezcano
@ 2026-09-29  8:23             ` Binbin Zhou
  2026-09-29  8:43               ` Daniel Lezcano
  0 siblings, 1 reply; 15+ messages in thread
From: Binbin Zhou @ 2026-09-29  8:23 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Yinbo Zhu, Rafael J . Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba, Huacai Chen, Xuerui Wang, loongarch,
	devicetree, linux-pm, stable, Sashiko

Hi Daniel:

On Tue, Sep 29, 2026 at 1:46 PM Daniel Lezcano
<daniel.lezcano@oss.qualcomm.com> wrote:
>
> On 9/29/26 05:06, Binbin Zhou wrote:
> > Hi Daniel:
>
> [ ... ]
>
> >>>> Please make a less cumbersome and implicit checks here. For example
> >>>> count the number of sensors and then do the check against.
> >>>
> >>> I thought about it, and you're right—I made the logic here too complicated.
> >>> Let's use `sensor_count` as the counter. Is the following check logic clearer?
> >>>
> >>>           u32 sensor_count = 0;
> >>>
> >>>           for (unsigned int i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
> >>>                   tzd = devm_thermal_of_zone_register(dev, i, data,
> >>> data->chip_data->thermal_ops);
> >>>                   if (IS_ERR(tzd)) {
> >>>                           if (PTR_ERR(tzd) == -ENODEV)
> >>>                                   continue;
> >>>
> >>>                           return dev_err_probe(dev, PTR_ERR(tzd),
> >>>                                                "failed to register sensor %d", i);
> >>>                   }
> >>>
> >>>                   sensor_count++;
> >>
> >> If I'm not mistaken in the previous version, the loop exits at the first
> >> registered sensor
> >>
> >>          if (!IS_ERR(tzd))
> >>                  break;
> >>
> >> Here all the available sensors are registered
> >
> > The name `sensor_count` might be a bit misleading, but here the loop
> > exits after the first success:
> >
> >                  sensor_count++;
> >                  break;
> >
> > Let’s rename it:
>
> Can you clarify why only the first sensor found stops the thermal zones
> registration ?

This section of code is based on the original version by zhuyinbo; I
noticed that you’ve had related discussions about it before[1][2].

I’ve reviewed all Loongson-2K CPUs that support thermal monitoring,
and they all have only one temperature sensor, with “SEL” set to 0.

As I understand it, given the current situation, the loop here doesn’t
seem necessary—physically, there is only one temperature sensor (even
though its SEL value might theoretically be non-zero).
`LOONGSON2_MAX_SENSOR_SEL_NUM` does not accurately reflect the number
of temperature sensors; it is merely an interrupt input selection, so
using it here does not seem entirely appropriate.

Therefore, I believe treating the Loongson-2K thermal driver as a
single thermal sensor better aligns with the current hardware
behavior.

Just use:
         devm_thermal_of_zone_register(dev, 0, data, thermal_ops);

[1]: https://lore.kernel.org/all/ac5b3982-a658-e05b-1b5c-3aeeda1585ed@loongson.cn/
[2]: https://lore.kernel.org/all/8ca44091-35fd-cc24-9896-0317772c5620@loongson.cn/

-- 
Thanks.
Binbin

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

* Re: [PATCH v6 1/7] thermal/drivers/loongson2: Correct thermal sensor registration loop
  2026-09-29  8:23             ` Binbin Zhou
@ 2026-09-29  8:43               ` Daniel Lezcano
  0 siblings, 0 replies; 15+ messages in thread
From: Daniel Lezcano @ 2026-09-29  8:43 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Yinbo Zhu, Rafael J . Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba, Huacai Chen, Xuerui Wang, loongarch,
	devicetree, linux-pm, stable, Sashiko

On 9/29/26 10:23, Binbin Zhou wrote:
> Hi Daniel:
> 
> On Tue, Sep 29, 2026 at 1:46 PM Daniel Lezcano
> <daniel.lezcano@oss.qualcomm.com> wrote:
>>
>> On 9/29/26 05:06, Binbin Zhou wrote:
>>> Hi Daniel:
>>
>> [ ... ]
>>
>>>>>> Please make a less cumbersome and implicit checks here. For example
>>>>>> count the number of sensors and then do the check against.
>>>>>
>>>>> I thought about it, and you're right—I made the logic here too complicated.
>>>>> Let's use `sensor_count` as the counter. Is the following check logic clearer?
>>>>>
>>>>>            u32 sensor_count = 0;
>>>>>
>>>>>            for (unsigned int i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
>>>>>                    tzd = devm_thermal_of_zone_register(dev, i, data,
>>>>> data->chip_data->thermal_ops);
>>>>>                    if (IS_ERR(tzd)) {
>>>>>                            if (PTR_ERR(tzd) == -ENODEV)
>>>>>                                    continue;
>>>>>
>>>>>                            return dev_err_probe(dev, PTR_ERR(tzd),
>>>>>                                                 "failed to register sensor %d", i);
>>>>>                    }
>>>>>
>>>>>                    sensor_count++;
>>>>
>>>> If I'm not mistaken in the previous version, the loop exits at the first
>>>> registered sensor
>>>>
>>>>           if (!IS_ERR(tzd))
>>>>                   break;
>>>>
>>>> Here all the available sensors are registered
>>>
>>> The name `sensor_count` might be a bit misleading, but here the loop
>>> exits after the first success:
>>>
>>>                   sensor_count++;
>>>                   break;
>>>
>>> Let’s rename it:
>>
>> Can you clarify why only the first sensor found stops the thermal zones
>> registration ?
> 
> This section of code is based on the original version by zhuyinbo; I
> noticed that you’ve had related discussions about it before[1][2].
> 
> I’ve reviewed all Loongson-2K CPUs that support thermal monitoring,
> and they all have only one temperature sensor, with “SEL” set to 0.
> 
> As I understand it, given the current situation, the loop here doesn’t
> seem necessary—physically, there is only one temperature sensor (even
> though its SEL value might theoretically be non-zero).
> `LOONGSON2_MAX_SENSOR_SEL_NUM` does not accurately reflect the number
> of temperature sensors; it is merely an interrupt input selection, so
> using it here does not seem entirely appropriate.
> 
> Therefore, I believe treating the Loongson-2K thermal driver as a
> single thermal sensor better aligns with the current hardware
> behavior.

Sure, if the Loongson-2K is only one sensor based board then no need to 
have this loop.

In the future, if there are more sensors coming with a new board, they 
can be described in platform private data



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

end of thread, other threads:[~2026-09-29  8:44 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-28  4:44 [PATCH v6 0/7] thermal: loongson2: Add support for Loongson-2K0300 SoC Binbin Zhou
2026-09-28  4:44 ` [PATCH v6 1/7] thermal/drivers/loongson2: Correct thermal sensor registration loop Binbin Zhou
2026-09-28  7:15   ` Daniel Lezcano
2026-09-28  8:17     ` Binbin Zhou
2026-09-28 13:23       ` Daniel Lezcano
2026-09-29  3:06         ` Binbin Zhou
2026-09-29  5:46           ` Daniel Lezcano
2026-09-29  8:23             ` Binbin Zhou
2026-09-29  8:43               ` Daniel Lezcano
2026-09-28  4:44 ` [PATCH v6 2/7] thermal/drivers/loongson2: Fix clamp() usage for thermal trip points Binbin Zhou
2026-09-28  4:44 ` [PATCH v6 3/7] thermal/drivers/loongson2: Fix Loongson-2K2000 trip point programming Binbin Zhou
2026-09-28  4:44 ` [PATCH v6 4/7] thermal/drivers/loongson2: Use bitfields and per-SoC thermal ops Binbin Zhou
2026-09-28  4:44 ` [PATCH v6 5/7] thermal/drivers/loongson2: Move per-SoC ops into chip data Binbin Zhou
2026-09-28  4:44 ` [PATCH v6 6/7] dt-bindings: thermal: loongson,ls2k-thermal: Add compatible for Loongson-2K0300 Binbin Zhou
2026-09-28  4:44 ` [PATCH v6 7/7] thermal/drivers/loongson2: Add Loongson-2K0300 support Binbin Zhou

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