* [PATCH v2 01/12] thermal/driver/tegra/soctherm: Use devm_ variant when registering a cooling device
2026-04-22 17:42 [PATCH v2 00/12] Support cooling device with ID in the OF Daniel Lezcano
@ 2026-04-22 17:42 ` Daniel Lezcano
2026-04-22 17:42 ` [PATCH v2 02/12] thermal/of: Move OF code where it belongs to Daniel Lezcano
` (10 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Daniel Lezcano @ 2026-04-22 17:42 UTC (permalink / raw)
To: rafael, daniel.lezcano
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon, Jiri Slaby (SUSE),
Mikko Perttunen, Svyatoslav Ryhel, Thomas Gleixner,
open list:TEGRA ARCHITECTURE SUPPORT
The driver invokes thermal_of_cooling_device_register() at probe time
but without unregistering it at remove time.
As we have a devm_ variant, use it and the cooling device should be
automatically removed.
While this prevents the cooling device from leaking, the unregistration is now
deferred until devres_release_all() runs (after probe() returns an error or
remove() completes).
A bug can be subtly introduced by this change because the driver still
manually disables the hardware clocks during the probe error path and
in tegra_soctherm_remove(). This creates a window where the cooling
device remains registered and exposed to the thermal core and sysfs
while the underlying hardware is powered down.
In order to prevent this potential issue, use the devm_ variant for the
clk.
Compiled-tested only.
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
drivers/thermal/tegra/soctherm.c | 29 +++++++++--------------------
1 file changed, 9 insertions(+), 20 deletions(-)
diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c
index 5d26b52beaba..790c4c96a9b5 100644
--- a/drivers/thermal/tegra/soctherm.c
+++ b/drivers/thermal/tegra/soctherm.c
@@ -1700,9 +1700,9 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
stc->init = true;
} else {
- tcd = thermal_of_cooling_device_register(np_stcc,
- (char *)name, ts,
- &throt_cooling_ops);
+ tcd = devm_thermal_of_cooling_device_register(dev, np_stcc,
+ (char *)name, ts,
+ &throt_cooling_ops);
if (IS_ERR_OR_NULL(tcd)) {
dev_err(dev,
"throttle-cfg: %s: failed to register cooling device\n",
@@ -2133,13 +2133,13 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
return PTR_ERR(tegra->reset);
}
- tegra->clock_tsensor = devm_clk_get(&pdev->dev, "tsensor");
+ tegra->clock_tsensor = devm_clk_get_enabled(&pdev->dev, "tsensor");
if (IS_ERR(tegra->clock_tsensor)) {
dev_err(&pdev->dev, "can't get tsensor clock\n");
return PTR_ERR(tegra->clock_tsensor);
}
- tegra->clock_soctherm = devm_clk_get(&pdev->dev, "soctherm");
+ tegra->clock_soctherm = devm_clk_get_enabled(&pdev->dev, "soctherm");
if (IS_ERR(tegra->clock_soctherm)) {
dev_err(&pdev->dev, "can't get soctherm clock\n");
return PTR_ERR(tegra->clock_soctherm);
@@ -2171,10 +2171,6 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
if (!tegra->thermctl_tzs)
return -ENOMEM;
- err = soctherm_clk_enable(pdev, true);
- if (err)
- return err;
-
soctherm_thermtrips_parse(pdev);
soctherm_init_hw_throt_cdev(pdev);
@@ -2184,10 +2180,8 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
for (i = 0; i < soc->num_ttgs; ++i) {
struct tegra_thermctl_zone *zone =
devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL);
- if (!zone) {
- err = -ENOMEM;
- goto disable_clocks;
- }
+ if (!zone)
+ return -ENOMEM;
zone->reg = tegra->regs + soc->ttgs[i]->sensor_temp_offset;
zone->dev = &pdev->dev;
@@ -2201,7 +2195,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
err = PTR_ERR(z);
dev_err(&pdev->dev, "failed to register sensor: %d\n",
err);
- goto disable_clocks;
+ return err;
}
zone->tz = z;
@@ -2210,7 +2204,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
/* Configure hw trip points */
err = tegra_soctherm_set_hwtrips(&pdev->dev, soc->ttgs[i], z);
if (err)
- goto disable_clocks;
+ return err;
}
err = soctherm_interrupts_init(pdev, tegra);
@@ -2218,11 +2212,6 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
soctherm_debug_init(pdev);
return 0;
-
-disable_clocks:
- soctherm_clk_enable(pdev, false);
-
- return err;
}
static void tegra_soctherm_remove(struct platform_device *pdev)
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v2 02/12] thermal/of: Move OF code where it belongs to
2026-04-22 17:42 [PATCH v2 00/12] Support cooling device with ID in the OF Daniel Lezcano
2026-04-22 17:42 ` [PATCH v2 01/12] thermal/driver/tegra/soctherm: Use devm_ variant when registering a cooling device Daniel Lezcano
@ 2026-04-22 17:42 ` Daniel Lezcano
2026-04-22 17:42 ` [PATCH v2 03/12] thermal/core: Make thermal_cooling_device_init_complete() non static Daniel Lezcano
` (9 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Daniel Lezcano @ 2026-04-22 17:42 UTC (permalink / raw)
To: rafael, daniel.lezcano
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon
The functions:
- thermal_of_cooling_device_register()
- devm_thermal_of_cooling_device_register()
are related to thermal-of but they are implemented in
thermal-core. Move these functions to the right file.
As the thermal-of file depends on CONFIG_THERMAL_OF=y, by moving these
two functions in it, when non-OF drivers are using this API that
results in a link issue. In order to prevent unnecessary
circumvolutions with the changes, the stubs have been added in the
header file resulting in having the non-OF drivers compiled without
the CONFIG_THERMAL_OF=y using these stubs and failing to register
their cooling devices.
This is temporary as the next changes introduces the functions for
non-OF drivers and returning to the initial state.
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
drivers/thermal/thermal_core.c | 75 +---------------------------------
drivers/thermal/thermal_core.h | 5 +++
drivers/thermal/thermal_of.c | 72 ++++++++++++++++++++++++++++++++
include/linux/thermal.h | 47 ++++++++++++---------
4 files changed, 105 insertions(+), 94 deletions(-)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 2f4e2dc46b8f..8a70768b46dd 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1056,7 +1056,7 @@ static void thermal_cooling_device_init_complete(struct thermal_cooling_device *
* Return: a pointer to the created struct thermal_cooling_device or an
* ERR_PTR. Caller must check return value with IS_ERR*() helpers.
*/
-static struct thermal_cooling_device *
+struct thermal_cooling_device *
__thermal_cooling_device_register(struct device_node *np,
const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
@@ -1163,79 +1163,6 @@ thermal_cooling_device_register(const char *type, void *devdata,
}
EXPORT_SYMBOL_GPL(thermal_cooling_device_register);
-/**
- * thermal_of_cooling_device_register() - register an OF thermal cooling device
- * @np: a pointer to a device tree node.
- * @type: the thermal cooling device type.
- * @devdata: device private data.
- * @ops: standard thermal cooling devices callbacks.
- *
- * This function will register a cooling device with device tree node reference.
- * This interface function adds a new thermal cooling device (fan/processor/...)
- * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
- * to all the thermal zone devices registered at the same time.
- *
- * Return: a pointer to the created struct thermal_cooling_device or an
- * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
- */
-struct thermal_cooling_device *
-thermal_of_cooling_device_register(struct device_node *np,
- const char *type, void *devdata,
- const struct thermal_cooling_device_ops *ops)
-{
- return __thermal_cooling_device_register(np, type, devdata, ops);
-}
-EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register);
-
-static void thermal_cooling_device_release(struct device *dev, void *res)
-{
- thermal_cooling_device_unregister(
- *(struct thermal_cooling_device **)res);
-}
-
-/**
- * devm_thermal_of_cooling_device_register() - register an OF thermal cooling
- * device
- * @dev: a valid struct device pointer of a sensor device.
- * @np: a pointer to a device tree node.
- * @type: the thermal cooling device type.
- * @devdata: device private data.
- * @ops: standard thermal cooling devices callbacks.
- *
- * This function will register a cooling device with device tree node reference.
- * This interface function adds a new thermal cooling device (fan/processor/...)
- * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
- * to all the thermal zone devices registered at the same time.
- *
- * Return: a pointer to the created struct thermal_cooling_device or an
- * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
- */
-struct thermal_cooling_device *
-devm_thermal_of_cooling_device_register(struct device *dev,
- struct device_node *np,
- const char *type, void *devdata,
- const struct thermal_cooling_device_ops *ops)
-{
- struct thermal_cooling_device **ptr, *tcd;
-
- ptr = devres_alloc(thermal_cooling_device_release, sizeof(*ptr),
- GFP_KERNEL);
- if (!ptr)
- return ERR_PTR(-ENOMEM);
-
- tcd = __thermal_cooling_device_register(np, type, devdata, ops);
- if (IS_ERR(tcd)) {
- devres_free(ptr);
- return tcd;
- }
-
- *ptr = tcd;
- devres_add(dev, ptr);
-
- return tcd;
-}
-EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register);
-
static bool thermal_cooling_device_present(struct thermal_cooling_device *cdev)
{
struct thermal_cooling_device *pos = NULL;
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index d3acff602f9c..bdd59947b24f 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -269,6 +269,11 @@ void thermal_zone_device_critical_shutdown(struct thermal_zone_device *tz);
void thermal_governor_update_tz(struct thermal_zone_device *tz,
enum thermal_notify_event reason);
+struct thermal_cooling_device *
+__thermal_cooling_device_register(struct device_node *np,
+ const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops);
+
/* Helpers */
#define for_each_trip_desc(__tz, __td) \
for (__td = __tz->trips; __td - __tz->trips < __tz->num_trips; __td++)
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index 99085c806a1f..398157e740fc 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -510,3 +510,75 @@ void devm_thermal_of_zone_unregister(struct device *dev, struct thermal_zone_dev
devm_thermal_of_zone_match, tz));
}
EXPORT_SYMBOL_GPL(devm_thermal_of_zone_unregister);
+
+/**
+ * thermal_of_cooling_device_register() - register an OF thermal cooling device
+ * @np: a pointer to a device tree node.
+ * @type: the thermal cooling device type.
+ * @devdata: device private data.
+ * @ops: standard thermal cooling devices callbacks.
+ *
+ * This function will register a cooling device with device tree node reference.
+ * This interface function adds a new thermal cooling device (fan/processor/...)
+ * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
+ * to all the thermal zone devices registered at the same time.
+ *
+ * Return: a pointer to the created struct thermal_cooling_device or an
+ * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
+ */
+struct thermal_cooling_device *
+thermal_of_cooling_device_register(struct device_node *np,
+ const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops)
+{
+ return __thermal_cooling_device_register(np, type, devdata, ops);
+}
+EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register);
+
+static void thermal_cooling_device_release(struct device *dev, void *res)
+{
+ thermal_cooling_device_unregister(*(struct thermal_cooling_device **)res);
+}
+
+/**
+ * devm_thermal_of_cooling_device_register() - register an OF thermal cooling
+ * device
+ * @dev: a valid struct device pointer of a sensor device.
+ * @np: a pointer to a device tree node.
+ * @type: the thermal cooling device type.
+ * @devdata: device private data.
+ * @ops: standard thermal cooling devices callbacks.
+ *
+ * This function will register a cooling device with device tree node reference.
+ * This interface function adds a new thermal cooling device (fan/processor/...)
+ * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
+ * to all the thermal zone devices registered at the same time.
+ *
+ * Return: a pointer to the created struct thermal_cooling_device or an
+ * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
+ */
+struct thermal_cooling_device *
+devm_thermal_of_cooling_device_register(struct device *dev,
+ struct device_node *np,
+ const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops)
+{
+ struct thermal_cooling_device **ptr, *tcd;
+
+ ptr = devres_alloc(thermal_cooling_device_release, sizeof(*ptr),
+ GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ tcd = __thermal_cooling_device_register(np, type, devdata, ops);
+ if (IS_ERR(tcd)) {
+ devres_free(ptr);
+ return tcd;
+ }
+
+ *ptr = tcd;
+ devres_add(dev, ptr);
+
+ return tcd;
+}
+EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 0ddc77aeeca2..d9ad860cee87 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -198,6 +198,15 @@ struct thermal_zone_device *devm_thermal_of_zone_register(struct device *dev, in
void devm_thermal_of_zone_unregister(struct device *dev, struct thermal_zone_device *tz);
+struct thermal_cooling_device *
+thermal_of_cooling_device_register(struct device_node *np, const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops);
+
+struct thermal_cooling_device *
+devm_thermal_of_cooling_device_register(struct device *dev,
+ struct device_node *np,
+ const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops);
#else
static inline
@@ -211,6 +220,23 @@ static inline void devm_thermal_of_zone_unregister(struct device *dev,
struct thermal_zone_device *tz)
{
}
+
+static inline struct thermal_cooling_device *
+thermal_of_cooling_device_register(struct device_node *np,
+ const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline struct thermal_cooling_device *
+devm_thermal_of_cooling_device_register(struct device *dev,
+ struct device_node *np,
+ const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops)
+{
+ return ERR_PTR(-ENODEV);
+}
#endif
int for_each_thermal_trip(struct thermal_zone_device *tz,
@@ -252,14 +278,6 @@ void thermal_zone_device_update(struct thermal_zone_device *,
struct thermal_cooling_device *thermal_cooling_device_register(const char *,
void *, const struct thermal_cooling_device_ops *);
-struct thermal_cooling_device *
-thermal_of_cooling_device_register(struct device_node *np, const char *, void *,
- const struct thermal_cooling_device_ops *);
-struct thermal_cooling_device *
-devm_thermal_of_cooling_device_register(struct device *dev,
- struct device_node *np,
- const char *type, void *devdata,
- const struct thermal_cooling_device_ops *ops);
void thermal_cooling_device_update(struct thermal_cooling_device *);
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name);
@@ -305,18 +323,7 @@ thermal_cooling_device_register(const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{ return ERR_PTR(-ENODEV); }
static inline struct thermal_cooling_device *
-thermal_of_cooling_device_register(struct device_node *np,
- const char *type, void *devdata,
- const struct thermal_cooling_device_ops *ops)
-{ return ERR_PTR(-ENODEV); }
-static inline struct thermal_cooling_device *
-devm_thermal_of_cooling_device_register(struct device *dev,
- struct device_node *np,
- const char *type, void *devdata,
- const struct thermal_cooling_device_ops *ops)
-{
- return ERR_PTR(-ENODEV);
-}
+
static inline void thermal_cooling_device_unregister(
struct thermal_cooling_device *cdev)
{ }
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v2 03/12] thermal/core: Make thermal_cooling_device_init_complete() non static
2026-04-22 17:42 [PATCH v2 00/12] Support cooling device with ID in the OF Daniel Lezcano
2026-04-22 17:42 ` [PATCH v2 01/12] thermal/driver/tegra/soctherm: Use devm_ variant when registering a cooling device Daniel Lezcano
2026-04-22 17:42 ` [PATCH v2 02/12] thermal/of: Move OF code where it belongs to Daniel Lezcano
@ 2026-04-22 17:42 ` Daniel Lezcano
2026-04-22 17:42 ` [PATCH v2 04/12] thermal/core: Remove node pointer parameter when registering a tz Daniel Lezcano
` (8 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Daniel Lezcano @ 2026-04-22 17:42 UTC (permalink / raw)
To: rafael, daniel.lezcano
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon
In the process of separating clearly the OF code and the thermal core
code, let's split and export the
thermal_cooling_device_init_complete() function so it can be used by
an implementation inside the thermal OF code.
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
drivers/thermal/thermal_core.c | 12 ++++++++----
drivers/thermal/thermal_core.h | 2 ++
drivers/thermal/thermal_of.c | 12 +++++++++++-
3 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 8a70768b46dd..35cf170f3fa1 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1028,7 +1028,7 @@ static void thermal_zone_cdev_bind(struct thermal_zone_device *tz,
__thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
}
-static void thermal_cooling_device_init_complete(struct thermal_cooling_device *cdev)
+void thermal_cooling_device_init_complete(struct thermal_cooling_device *cdev)
{
struct thermal_zone_device *tz;
@@ -1127,8 +1127,6 @@ __thermal_cooling_device_register(struct device_node *np,
if (current_state <= cdev->max_state)
thermal_debug_cdev_add(cdev, current_state);
- thermal_cooling_device_init_complete(cdev);
-
return cdev;
out_cooling_dev:
@@ -1159,7 +1157,13 @@ struct thermal_cooling_device *
thermal_cooling_device_register(const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{
- return __thermal_cooling_device_register(NULL, type, devdata, ops);
+ struct thermal_cooling_device *cdev;
+
+ cdev = __thermal_cooling_device_register(NULL, type, devdata, ops);
+ if (!IS_ERR(cdev))
+ thermal_cooling_device_init_complete(cdev);
+
+ return cdev;
}
EXPORT_SYMBOL_GPL(thermal_cooling_device_register);
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index bdd59947b24f..6e44bcf37b00 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -269,6 +269,8 @@ void thermal_zone_device_critical_shutdown(struct thermal_zone_device *tz);
void thermal_governor_update_tz(struct thermal_zone_device *tz,
enum thermal_notify_event reason);
+void thermal_cooling_device_init_complete(struct thermal_cooling_device *cdev);
+
struct thermal_cooling_device *
__thermal_cooling_device_register(struct device_node *np,
const char *type, void *devdata,
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index 398157e740fc..c4b67554df44 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -531,7 +531,15 @@ thermal_of_cooling_device_register(struct device_node *np,
const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{
- return __thermal_cooling_device_register(np, type, devdata, ops);
+ struct thermal_cooling_device *cdev;
+
+ cdev = __thermal_cooling_device_register(np, type, devdata, ops);
+ if (IS_ERR(cdev))
+ return cdev;
+
+ thermal_cooling_device_init_complete(cdev);
+
+ return cdev;
}
EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register);
@@ -579,6 +587,8 @@ devm_thermal_of_cooling_device_register(struct device *dev,
*ptr = tcd;
devres_add(dev, ptr);
+ thermal_cooling_device_init_complete(tcd);
+
return tcd;
}
EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register);
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v2 04/12] thermal/core: Remove node pointer parameter when registering a tz
2026-04-22 17:42 [PATCH v2 00/12] Support cooling device with ID in the OF Daniel Lezcano
` (2 preceding siblings ...)
2026-04-22 17:42 ` [PATCH v2 03/12] thermal/core: Make thermal_cooling_device_init_complete() non static Daniel Lezcano
@ 2026-04-22 17:42 ` Daniel Lezcano
2026-04-22 17:42 ` [PATCH v2 05/12] thermal/of: Move the node pointer assignation in the OF code file Daniel Lezcano
` (7 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Daniel Lezcano @ 2026-04-22 17:42 UTC (permalink / raw)
To: rafael, daniel.lezcano
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon
Now we have a OF version for all functions registering a thermal zone
or a cooling device. Let's remove the device_node pointer parameter in
the core function which is inconsistent with non-OF code.
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
drivers/thermal/thermal_core.c | 52 ++++++++++++++++++++++++++++++----
drivers/thermal/thermal_core.h | 3 +-
drivers/thermal/thermal_of.c | 2 +-
include/linux/thermal.h | 11 +++++++
4 files changed, 59 insertions(+), 9 deletions(-)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 35cf170f3fa1..113719466dc2 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1042,7 +1042,6 @@ void thermal_cooling_device_init_complete(struct thermal_cooling_device *cdev)
/**
* __thermal_cooling_device_register() - register a new thermal cooling device
- * @np: a pointer to a device tree node.
* @type: the thermal cooling device type.
* @devdata: device private data.
* @ops: standard thermal cooling devices callbacks.
@@ -1050,15 +1049,12 @@ void thermal_cooling_device_init_complete(struct thermal_cooling_device *cdev)
* This interface function adds a new thermal cooling device (fan/processor/...)
* to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
* to all the thermal zone devices registered at the same time.
- * It also gives the opportunity to link the cooling device to a device tree
- * node, so that it can be bound to a thermal zone created out of device tree.
*
* Return: a pointer to the created struct thermal_cooling_device or an
* ERR_PTR. Caller must check return value with IS_ERR*() helpers.
*/
struct thermal_cooling_device *
-__thermal_cooling_device_register(struct device_node *np,
- const char *type, void *devdata,
+__thermal_cooling_device_register(const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{
struct thermal_cooling_device *cdev;
@@ -1159,7 +1155,7 @@ thermal_cooling_device_register(const char *type, void *devdata,
{
struct thermal_cooling_device *cdev;
- cdev = __thermal_cooling_device_register(NULL, type, devdata, ops);
+ cdev = __thermal_cooling_device_register(type, devdata, ops);
if (!IS_ERR(cdev))
thermal_cooling_device_init_complete(cdev);
@@ -1167,6 +1163,50 @@ thermal_cooling_device_register(const char *type, void *devdata,
}
EXPORT_SYMBOL_GPL(thermal_cooling_device_register);
+static void thermal_cooling_device_release(struct device *dev, void *res)
+{
+ thermal_cooling_device_unregister(*(struct thermal_cooling_device **)res);
+}
+
+/**
+ * devm_thermal_cooling_device_register() - register a thermal cooling device
+ * @dev: a valid struct device pointer of a sensor device.
+ * @type: the thermal cooling device type.
+ * @devdata: device private data.
+ * @ops: standard thermal cooling devices callbacks.
+ *
+ * This function will register a cooling device with device tree node reference.
+ * This interface function adds a new thermal cooling device (fan/processor/...)
+ * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
+ * to all the thermal zone devices registered at the same time.
+ *
+ * Return: a pointer to the created struct thermal_cooling_device or an
+ * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
+ */
+struct thermal_cooling_device *
+devm_thermal_cooling_device_register(struct device *dev, const char *type,
+ void *devdata, const struct thermal_cooling_device_ops *ops)
+{
+ struct thermal_cooling_device **ptr, *tcd;
+
+ ptr = devres_alloc(thermal_cooling_device_release, sizeof(*ptr),
+ GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ tcd = thermal_cooling_device_register(type, devdata, ops);
+ if (IS_ERR(tcd)) {
+ devres_free(ptr);
+ return tcd;
+ }
+
+ *ptr = tcd;
+ devres_add(dev, ptr);
+
+ return tcd;
+}
+EXPORT_SYMBOL_GPL(devm_thermal_cooling_device_register);
+
static bool thermal_cooling_device_present(struct thermal_cooling_device *cdev)
{
struct thermal_cooling_device *pos = NULL;
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index 6e44bcf37b00..d45455bb9e9e 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -272,8 +272,7 @@ void thermal_governor_update_tz(struct thermal_zone_device *tz,
void thermal_cooling_device_init_complete(struct thermal_cooling_device *cdev);
struct thermal_cooling_device *
-__thermal_cooling_device_register(struct device_node *np,
- const char *type, void *devdata,
+__thermal_cooling_device_register(const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops);
/* Helpers */
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index c4b67554df44..3ba8c970f11f 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -533,7 +533,7 @@ thermal_of_cooling_device_register(struct device_node *np,
{
struct thermal_cooling_device *cdev;
- cdev = __thermal_cooling_device_register(np, type, devdata, ops);
+ cdev = __thermal_cooling_device_register(type, devdata, ops);
if (IS_ERR(cdev))
return cdev;
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index d9ad860cee87..ba2c8b4dda87 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -278,6 +278,11 @@ void thermal_zone_device_update(struct thermal_zone_device *,
struct thermal_cooling_device *thermal_cooling_device_register(const char *,
void *, const struct thermal_cooling_device_ops *);
+
+struct thermal_cooling_device *
+devm_thermal_cooling_device_register(struct device *dev, const char *type,
+ void *devdata, const struct thermal_cooling_device_ops *ops);
+
void thermal_cooling_device_update(struct thermal_cooling_device *);
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name);
@@ -322,7 +327,13 @@ static inline struct thermal_cooling_device *
thermal_cooling_device_register(const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{ return ERR_PTR(-ENODEV); }
+
static inline struct thermal_cooling_device *
+devm_thermal_cooling_device_register(struct device *dev, const char *type,
+ void *devdata, const struct thermal_cooling_device_ops *ops)
+{
+ return ERR_PTR(-ENODEV);
+}
static inline void thermal_cooling_device_unregister(
struct thermal_cooling_device *cdev)
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v2 05/12] thermal/of: Move the node pointer assignation in the OF code file
2026-04-22 17:42 [PATCH v2 00/12] Support cooling device with ID in the OF Daniel Lezcano
` (3 preceding siblings ...)
2026-04-22 17:42 ` [PATCH v2 04/12] thermal/core: Remove node pointer parameter when registering a tz Daniel Lezcano
@ 2026-04-22 17:42 ` Daniel Lezcano
2026-04-22 17:42 ` [PATCH v2 06/12] hwmon:: Use non-OF thermal cooling device register function Daniel Lezcano
` (6 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Daniel Lezcano @ 2026-04-22 17:42 UTC (permalink / raw)
To: rafael, daniel.lezcano
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon
The node pointer being assigned to the cooling device structure is an
action done by the thermal OF only and does not belong to the core
framework code. Move the node pointer assignation in the thermal OF
code. Consequently, the devm_thermal_of_cooling_device_register() can
call its non-devm version resulting in a more intuitive design of the
API.
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
drivers/thermal/thermal_core.c | 1 -
drivers/thermal/thermal_of.c | 3 ++-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 113719466dc2..9c4081d58972 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1085,7 +1085,6 @@ __thermal_cooling_device_register(const char *type, void *devdata,
mutex_init(&cdev->lock);
INIT_LIST_HEAD(&cdev->thermal_instances);
- cdev->np = np;
cdev->ops = ops;
cdev->updated = false;
cdev->device.class = &thermal_class;
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index 3ba8c970f11f..ee9776d0e5be 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -537,6 +537,7 @@ thermal_of_cooling_device_register(struct device_node *np,
if (IS_ERR(cdev))
return cdev;
+ cdev->np = np;
thermal_cooling_device_init_complete(cdev);
return cdev;
@@ -578,7 +579,7 @@ devm_thermal_of_cooling_device_register(struct device *dev,
if (!ptr)
return ERR_PTR(-ENOMEM);
- tcd = __thermal_cooling_device_register(np, type, devdata, ops);
+ tcd = thermal_of_cooling_device_register(np, type, devdata, ops);
if (IS_ERR(tcd)) {
devres_free(ptr);
return tcd;
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v2 06/12] hwmon:: Use non-OF thermal cooling device register function
2026-04-22 17:42 [PATCH v2 00/12] Support cooling device with ID in the OF Daniel Lezcano
` (4 preceding siblings ...)
2026-04-22 17:42 ` [PATCH v2 05/12] thermal/of: Move the node pointer assignation in the OF code file Daniel Lezcano
@ 2026-04-22 17:42 ` Daniel Lezcano
2026-04-22 17:42 ` [PATCH v2 07/12] thermal/core: Put of_node field cooling device structure under Kconfig option Daniel Lezcano
` (5 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Daniel Lezcano @ 2026-04-22 17:42 UTC (permalink / raw)
To: rafael, daniel.lezcano
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon,
open list:CHROMEOS EC HARDWARE MONITORING
Make HWMON drivers which are not based on device tree to use the
corresponding non-OF functions.
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
---
drivers/hwmon/cros_ec_hwmon.c | 4 ++--
drivers/hwmon/dell-smm-hwmon.c | 4 ++--
drivers/hwmon/mlxreg-fan.c | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/hwmon/cros_ec_hwmon.c b/drivers/hwmon/cros_ec_hwmon.c
index 6cf5ab0f4b73..77dd9f28962d 100644
--- a/drivers/hwmon/cros_ec_hwmon.c
+++ b/drivers/hwmon/cros_ec_hwmon.c
@@ -532,8 +532,8 @@ static void cros_ec_hwmon_register_fan_cooling_devices(struct device *dev,
cpriv->hwmon_priv = priv;
cpriv->index = i;
- cdev = devm_thermal_of_cooling_device_register(dev, NULL, type, cpriv,
- &cros_ec_thermal_cooling_ops);
+ cdev = devm_thermal_cooling_device_register(dev, type, cpriv,
+ &cros_ec_thermal_cooling_ops);
if (IS_ERR(cdev)) {
dev_warn(dev, "failed to register fan %zu as a cooling device: %pe\n", i,
cdev);
diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
index 038edffc1ac7..47b373ea6db4 100644
--- a/drivers/hwmon/dell-smm-hwmon.c
+++ b/drivers/hwmon/dell-smm-hwmon.c
@@ -1161,8 +1161,8 @@ static int dell_smm_init_cdev(struct device *dev, u8 fan_num)
if (cdata) {
cdata->fan_num = fan_num;
cdata->data = data;
- cdev = devm_thermal_of_cooling_device_register(dev, NULL, name, cdata,
- &dell_smm_cooling_ops);
+ cdev = devm_thermal_cooling_device_register(dev, name, cdata,
+ &dell_smm_cooling_ops);
if (IS_ERR(cdev)) {
devm_kfree(dev, cdata);
ret = PTR_ERR(cdev);
diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c
index 137a90dd2075..860de6cfd8a4 100644
--- a/drivers/hwmon/mlxreg-fan.c
+++ b/drivers/hwmon/mlxreg-fan.c
@@ -583,8 +583,8 @@ static int mlxreg_fan_cooling_config(struct device *dev, struct mlxreg_fan *fan)
pwm->fan = fan;
/* Set minimal PWM speed. */
pwm->last_hwmon_state = MLXREG_FAN_PWM_DUTY2STATE(MLXREG_FAN_MIN_DUTY);
- pwm->cdev = devm_thermal_of_cooling_device_register(dev, NULL, mlxreg_fan_name[i],
- pwm, &mlxreg_fan_cooling_ops);
+ pwm->cdev = devm_thermal_cooling_device_register(dev, mlxreg_fan_name[i],
+ pwm, &mlxreg_fan_cooling_ops);
if (IS_ERR(pwm->cdev)) {
dev_err(dev, "Failed to register cooling device\n");
return PTR_ERR(pwm->cdev);
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v2 07/12] thermal/core: Put of_node field cooling device structure under Kconfig option
2026-04-22 17:42 [PATCH v2 00/12] Support cooling device with ID in the OF Daniel Lezcano
` (5 preceding siblings ...)
2026-04-22 17:42 ` [PATCH v2 06/12] hwmon:: Use non-OF thermal cooling device register function Daniel Lezcano
@ 2026-04-22 17:42 ` Daniel Lezcano
2026-04-22 17:42 ` [PATCH v2 08/12] thermal/of: Rename the devm_thermal_of_cooling_device_register() function Daniel Lezcano
` (4 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Daniel Lezcano @ 2026-04-22 17:42 UTC (permalink / raw)
To: rafael, daniel.lezcano
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon
The device node pointer in the cooling device structure is only needed
by the thermal OF in order to bind a thermal zone with a cooling
device. Now only the OF based drivers are using the thermal OF
functions and do not call the function with a NULL device_node
parameter as before. We can put this field under the CONFIG_THERMAL_OF
condition and make it go away if the device tree is not used.
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
include/linux/thermal.h | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index ba2c8b4dda87..0a95cfeffa74 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -125,7 +125,6 @@ struct thermal_cooling_device {
const char *type;
unsigned long max_state;
struct device device;
- struct device_node *np;
void *devdata;
void *stats;
const struct thermal_cooling_device_ops *ops;
@@ -133,6 +132,9 @@ struct thermal_cooling_device {
struct mutex lock; /* protect thermal_instances list */
struct list_head thermal_instances;
struct list_head node;
+#ifdef CONFIG_THERMAL_OF
+ struct device_node *np;
+#endif
#ifdef CONFIG_THERMAL_DEBUGFS
struct thermal_debugfs *debugfs;
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v2 08/12] thermal/of: Rename the devm_thermal_of_cooling_device_register() function
2026-04-22 17:42 [PATCH v2 00/12] Support cooling device with ID in the OF Daniel Lezcano
` (6 preceding siblings ...)
2026-04-22 17:42 ` [PATCH v2 07/12] thermal/core: Put of_node field cooling device structure under Kconfig option Daniel Lezcano
@ 2026-04-22 17:42 ` Daniel Lezcano
2026-04-22 17:42 ` [PATCH v2 09/12] thermal/of: Introduce cooling device of_index Daniel Lezcano
` (3 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Daniel Lezcano @ 2026-04-22 17:42 UTC (permalink / raw)
To: rafael, daniel.lezcano
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon, Krzysztof Kozlowski,
Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
Thomas Gleixner, Ingo Molnar, Jiri Slaby (SUSE), Svyatoslav Ryhel,
Mikko Perttunen, moderated list:ARM/ASPEED MACHINE SUPPORT,
moderated list:ARM/ASPEED MACHINE SUPPORT,
moderated list:ARM/NUVOTON NPCM ARCHITECTURE,
open list:TEGRA ARCHITECTURE SUPPORT,
open list:ARM/QUALCOMM MAILING LIST,
open list:KHADAS MCU MFD DRIVER,
open list:CLANG/LLVM BUILD SUPPORT
The cooling devices can be composed with a cooling device controller
and a set of cooling devices attached to it. Until now, the DT
bindings were described using a node for the cooling device controller
and child nodes for all the cooling devices.
Recently, a new set of cooling devices were proposed with the same
bindings. Those were rejected because DT maintainers do not want this
format anymore. In place, a cooling device will be created with an
id. Whatever its meaning, the thermal OF will bind a thermal zone and
a cooling device by checking the device node pointer + the id are
matching the cooling map with the cooling device.
Actually this approach is consistent with the thermal which are also
registered with a device and an id.
In order to do a distinction between the old binding with child nodes
and the incoming new binding, let's rename the registering function
with a self-explanatory name.
Rename the functions:
devm_thermal_of_cooling_device_register() -> devm_thermal_of_child_cooling_device_register()
Used the command:
find . -type f -name '*.[ch]' -exec \
sed -i 's/devm_thermal_of_cooling_device_register/\
devm_thermal_of_child_cooling_device_register/g' {} \;
Did not used clang-format-diff because it does not indent correctly
and checkpatch complained. Manually reindented to make checkpatch
happy
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
drivers/hwmon/amc6821.c | 2 +-
drivers/hwmon/aspeed-pwm-tacho.c | 5 +++--
drivers/hwmon/emc2305.c | 6 +++---
drivers/hwmon/gpio-fan.c | 6 ++++--
drivers/hwmon/max6650.c | 6 +++---
drivers/hwmon/npcm750-pwm-fan.c | 6 ++++--
drivers/hwmon/pwm-fan.c | 5 +++--
drivers/hwmon/qnap-mcu-hwmon.c | 6 +++---
drivers/hwmon/tc654.c | 5 +++--
drivers/memory/tegra/tegra210-emc-core.c | 4 ++--
drivers/soc/qcom/qcom_aoss.c | 2 +-
drivers/thermal/khadas_mcu_fan.c | 7 ++++---
drivers/thermal/tegra/soctherm.c | 6 +++---
drivers/thermal/thermal_of.c | 15 +++++++++------
include/linux/thermal.h | 16 ++++++++--------
15 files changed, 54 insertions(+), 43 deletions(-)
diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c
index d5f864b360b0..8e5926b06070 100644
--- a/drivers/hwmon/amc6821.c
+++ b/drivers/hwmon/amc6821.c
@@ -1076,7 +1076,7 @@ static int amc6821_probe(struct i2c_client *client)
"Failed to initialize hwmon\n");
if (IS_ENABLED(CONFIG_THERMAL) && fan_np && data->fan_cooling_levels)
- return PTR_ERR_OR_ZERO(devm_thermal_of_cooling_device_register(dev,
+ return PTR_ERR_OR_ZERO(devm_thermal_of_child_cooling_device_register(dev,
fan_np, client->name, data, &amc6821_cooling_ops));
return 0;
diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c
index aa159bf158a3..1c5945d4ba37 100644
--- a/drivers/hwmon/aspeed-pwm-tacho.c
+++ b/drivers/hwmon/aspeed-pwm-tacho.c
@@ -841,8 +841,9 @@ static int aspeed_create_pwm_cooling(struct device *dev,
}
snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%pOFn%d", child, pwm_port);
- cdev->tcdev = devm_thermal_of_cooling_device_register(dev, child,
- cdev->name, cdev, &aspeed_pwm_cool_ops);
+ cdev->tcdev = devm_thermal_of_child_cooling_device_register(dev, child,
+ cdev->name, cdev,
+ &aspeed_pwm_cool_ops);
if (IS_ERR(cdev->tcdev))
return PTR_ERR(cdev->tcdev);
diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c
index 64b213e1451e..2505e9fac499 100644
--- a/drivers/hwmon/emc2305.c
+++ b/drivers/hwmon/emc2305.c
@@ -309,9 +309,9 @@ static int emc2305_set_single_tz(struct device *dev, struct device_node *fan_nod
pwm = data->pwm_min[cdev_idx];
data->cdev_data[cdev_idx].cdev =
- devm_thermal_of_cooling_device_register(dev, fan_node,
- emc2305_fan_name[idx], data,
- &emc2305_cooling_ops);
+ devm_thermal_of_child_cooling_device_register(dev, fan_node,
+ emc2305_fan_name[idx], data,
+ &emc2305_cooling_ops);
if (IS_ERR(data->cdev_data[cdev_idx].cdev)) {
dev_err(dev, "Failed to register cooling device %s\n", emc2305_fan_name[idx]);
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
index a8892ced1e54..084828e1e281 100644
--- a/drivers/hwmon/gpio-fan.c
+++ b/drivers/hwmon/gpio-fan.c
@@ -592,8 +592,10 @@ static int gpio_fan_probe(struct platform_device *pdev)
}
/* Optional cooling device register for Device tree platforms */
- fan_data->cdev = devm_thermal_of_cooling_device_register(dev, np,
- "gpio-fan", fan_data, &gpio_fan_cool_ops);
+ fan_data->cdev = devm_thermal_of_child_cooling_device_register(dev, np,
+ "gpio-fan",
+ fan_data,
+ &gpio_fan_cool_ops);
dev_info(dev, "GPIO fan initialized\n");
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
index 9649c6611d5f..a50b1b0f1f48 100644
--- a/drivers/hwmon/max6650.c
+++ b/drivers/hwmon/max6650.c
@@ -793,9 +793,9 @@ static int max6650_probe(struct i2c_client *client)
return err;
if (IS_ENABLED(CONFIG_THERMAL)) {
- cooling_dev = devm_thermal_of_cooling_device_register(dev,
- dev->of_node, client->name,
- data, &max6650_cooling_ops);
+ cooling_dev = devm_thermal_of_child_cooling_device_register(dev, dev->of_node,
+ client->name, data,
+ &max6650_cooling_ops);
if (IS_ERR(cooling_dev)) {
dev_warn(dev, "thermal cooling device register failed: %ld\n",
PTR_ERR(cooling_dev));
diff --git a/drivers/hwmon/npcm750-pwm-fan.c b/drivers/hwmon/npcm750-pwm-fan.c
index c8f5e695fb6d..aea0b8659f5f 100644
--- a/drivers/hwmon/npcm750-pwm-fan.c
+++ b/drivers/hwmon/npcm750-pwm-fan.c
@@ -857,8 +857,10 @@ static int npcm7xx_create_pwm_cooling(struct device *dev,
snprintf(cdev->name, THERMAL_NAME_LENGTH, "%pOFn%d", child,
pwm_port);
- cdev->tcdev = devm_thermal_of_cooling_device_register(dev, child,
- cdev->name, cdev, &npcm7xx_pwm_cool_ops);
+ cdev->tcdev = devm_thermal_of_child_cooling_device_register(dev, child,
+ cdev->name,
+ cdev,
+ &npcm7xx_pwm_cool_ops);
if (IS_ERR(cdev->tcdev))
return PTR_ERR(cdev->tcdev);
diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c
index 37269db2de84..e6a567d58579 100644
--- a/drivers/hwmon/pwm-fan.c
+++ b/drivers/hwmon/pwm-fan.c
@@ -685,8 +685,9 @@ static int pwm_fan_probe(struct platform_device *pdev)
ctx->pwm_fan_state = ctx->pwm_fan_max_state;
if (IS_ENABLED(CONFIG_THERMAL)) {
- cdev = devm_thermal_of_cooling_device_register(dev,
- dev->of_node, "pwm-fan", ctx, &pwm_fan_cooling_ops);
+ cdev = devm_thermal_of_child_cooling_device_register(dev, dev->of_node,
+ "pwm-fan", ctx,
+ &pwm_fan_cooling_ops);
if (IS_ERR(cdev)) {
ret = PTR_ERR(cdev);
dev_err(dev,
diff --git a/drivers/hwmon/qnap-mcu-hwmon.c b/drivers/hwmon/qnap-mcu-hwmon.c
index e86e64c4d391..c1c1e9d6f340 100644
--- a/drivers/hwmon/qnap-mcu-hwmon.c
+++ b/drivers/hwmon/qnap-mcu-hwmon.c
@@ -337,9 +337,9 @@ static int qnap_mcu_hwmon_probe(struct platform_device *pdev)
* levels and only succeed with either no or correct cooling levels.
*/
if (IS_ENABLED(CONFIG_THERMAL) && hwm->fan_cooling_levels) {
- cdev = devm_thermal_of_cooling_device_register(dev,
- to_of_node(hwm->fan_node), "qnap-mcu-hwmon",
- hwm, &qnap_mcu_hwmon_cooling_ops);
+ cdev = devm_thermal_of_child_cooling_device_register(dev, to_of_node(hwm->fan_node),
+ "qnap-mcu-hwmon", hwm,
+ &qnap_mcu_hwmon_cooling_ops);
if (IS_ERR(cdev))
return dev_err_probe(dev, PTR_ERR(cdev),
"Failed to register qnap-mcu-hwmon as cooling device\n");
diff --git a/drivers/hwmon/tc654.c b/drivers/hwmon/tc654.c
index 39fe5836f237..ba18b442b81e 100644
--- a/drivers/hwmon/tc654.c
+++ b/drivers/hwmon/tc654.c
@@ -541,8 +541,9 @@ static int tc654_probe(struct i2c_client *client)
if (IS_ENABLED(CONFIG_THERMAL)) {
struct thermal_cooling_device *cdev;
- cdev = devm_thermal_of_cooling_device_register(dev, dev->of_node, client->name,
- hwmon_dev, &tc654_fan_cool_ops);
+ cdev = devm_thermal_of_child_cooling_device_register(dev, dev->of_node,
+ client->name, hwmon_dev,
+ &tc654_fan_cool_ops);
return PTR_ERR_OR_ZERO(cdev);
}
diff --git a/drivers/memory/tegra/tegra210-emc-core.c b/drivers/memory/tegra/tegra210-emc-core.c
index e96ca4157d48..065ae8bc2830 100644
--- a/drivers/memory/tegra/tegra210-emc-core.c
+++ b/drivers/memory/tegra/tegra210-emc-core.c
@@ -1966,8 +1966,8 @@ static int tegra210_emc_probe(struct platform_device *pdev)
tegra210_emc_debugfs_init(emc);
- cd = devm_thermal_of_cooling_device_register(emc->dev, np, "emc", emc,
- &tegra210_emc_cd_ops);
+ cd = devm_thermal_of_child_cooling_device_register(emc->dev, np, "emc", emc,
+ &tegra210_emc_cd_ops);
if (IS_ERR(cd)) {
err = PTR_ERR(cd);
dev_err(emc->dev, "failed to register cooling device: %d\n",
diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c
index a543ab9bee6c..742f571200fa 100644
--- a/drivers/soc/qcom/qcom_aoss.c
+++ b/drivers/soc/qcom/qcom_aoss.c
@@ -381,7 +381,7 @@ static int qmp_cooling_device_add(struct qmp *qmp,
qmp_cdev->qmp = qmp;
qmp_cdev->state = !qmp_cdev_max_state;
qmp_cdev->name = cdev_name;
- qmp_cdev->cdev = devm_thermal_of_cooling_device_register
+ qmp_cdev->cdev = devm_thermal_of_child_cooling_device_register
(qmp->dev, node,
cdev_name,
qmp_cdev, &qmp_cooling_device_ops);
diff --git a/drivers/thermal/khadas_mcu_fan.c b/drivers/thermal/khadas_mcu_fan.c
index d35e5313bea4..21b3d0a71bd0 100644
--- a/drivers/thermal/khadas_mcu_fan.c
+++ b/drivers/thermal/khadas_mcu_fan.c
@@ -90,9 +90,10 @@ static int khadas_mcu_fan_probe(struct platform_device *pdev)
ctx->mcu = mcu;
platform_set_drvdata(pdev, ctx);
- cdev = devm_thermal_of_cooling_device_register(dev->parent,
- dev->parent->of_node, "khadas-mcu-fan", ctx,
- &khadas_mcu_fan_cooling_ops);
+ cdev = devm_thermal_of_child_cooling_device_register(dev->parent,
+ dev->parent->of_node,
+ "khadas-mcu-fan", ctx,
+ &khadas_mcu_fan_cooling_ops);
if (IS_ERR(cdev)) {
ret = PTR_ERR(cdev);
dev_err(dev, "Failed to register khadas-mcu-fan as cooling device: %d\n",
diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c
index 790c4c96a9b5..f58430ed8f11 100644
--- a/drivers/thermal/tegra/soctherm.c
+++ b/drivers/thermal/tegra/soctherm.c
@@ -1700,9 +1700,9 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
stc->init = true;
} else {
- tcd = devm_thermal_of_cooling_device_register(dev, np_stcc,
- (char *)name, ts,
- &throt_cooling_ops);
+ tcd = devm_thermal_of_child_cooling_device_register(dev, np_stcc,
+ (char *)name, ts,
+ &throt_cooling_ops);
if (IS_ERR_OR_NULL(tcd)) {
dev_err(dev,
"throttle-cfg: %s: failed to register cooling device\n",
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index ee9776d0e5be..d06487bb5e67 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -550,7 +550,7 @@ static void thermal_cooling_device_release(struct device *dev, void *res)
}
/**
- * devm_thermal_of_cooling_device_register() - register an OF thermal cooling
+ * devm_thermal_of_child_cooling_device_register() - register an OF thermal cooling
* device
* @dev: a valid struct device pointer of a sensor device.
* @np: a pointer to a device tree node.
@@ -563,14 +563,17 @@ static void thermal_cooling_device_release(struct device *dev, void *res)
* to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
* to all the thermal zone devices registered at the same time.
*
+ * This function should be used when a cooling controller has child
+ * nodes which are referenced in the thermal zone cooling map.
+ *
* Return: a pointer to the created struct thermal_cooling_device or an
* ERR_PTR. Caller must check return value with IS_ERR*() helpers.
*/
struct thermal_cooling_device *
-devm_thermal_of_cooling_device_register(struct device *dev,
- struct device_node *np,
- const char *type, void *devdata,
- const struct thermal_cooling_device_ops *ops)
+devm_thermal_of_child_cooling_device_register(struct device *dev,
+ struct device_node *np,
+ const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops)
{
struct thermal_cooling_device **ptr, *tcd;
@@ -592,4 +595,4 @@ devm_thermal_of_cooling_device_register(struct device *dev,
return tcd;
}
-EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register);
+EXPORT_SYMBOL_GPL(devm_thermal_of_child_cooling_device_register);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 0a95cfeffa74..b3c448f7d919 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -205,10 +205,10 @@ thermal_of_cooling_device_register(struct device_node *np, const char *type, voi
const struct thermal_cooling_device_ops *ops);
struct thermal_cooling_device *
-devm_thermal_of_cooling_device_register(struct device *dev,
- struct device_node *np,
- const char *type, void *devdata,
- const struct thermal_cooling_device_ops *ops);
+devm_thermal_of_child_cooling_device_register(struct device *dev,
+ struct device_node *np,
+ const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops);
#else
static inline
@@ -232,10 +232,10 @@ thermal_of_cooling_device_register(struct device_node *np,
}
static inline struct thermal_cooling_device *
-devm_thermal_of_cooling_device_register(struct device *dev,
- struct device_node *np,
- const char *type, void *devdata,
- const struct thermal_cooling_device_ops *ops)
+devm_thermal_of_child_cooling_device_register(struct device *dev,
+ struct device_node *np,
+ const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops)
{
return ERR_PTR(-ENODEV);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v2 09/12] thermal/of: Introduce cooling device of_index
2026-04-22 17:42 [PATCH v2 00/12] Support cooling device with ID in the OF Daniel Lezcano
` (7 preceding siblings ...)
2026-04-22 17:42 ` [PATCH v2 08/12] thermal/of: Rename the devm_thermal_of_cooling_device_register() function Daniel Lezcano
@ 2026-04-22 17:42 ` Daniel Lezcano
2026-04-22 17:42 ` [PATCH v2 10/12] thermal/of: Pass the of_index and add a function to register with an index Daniel Lezcano
` (2 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Daniel Lezcano @ 2026-04-22 17:42 UTC (permalink / raw)
To: rafael, daniel.lezcano
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon,
moderated list:DRM DRIVERS FOR VIVANTE GPU IP,
open list:DRM DRIVERS FOR VIVANTE GPU IP
As described in the previous change, the new incoming DT binding will
describe a tuple device_node + cooling device id, instead of child
nodes.
Let's augment thermal_of_cooling_device_register() to receive the
cooling device id and propagate the changes to the four remaining
drivers using the non-devm version of the cooling device registering
function.
Add the id in the cooling device structure and store the value when
registering it.
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 5 +++--
drivers/thermal/cpufreq_cooling.c | 2 +-
drivers/thermal/cpuidle_cooling.c | 2 +-
drivers/thermal/devfreq_cooling.c | 2 +-
drivers/thermal/thermal_of.c | 6 ++++--
include/linux/thermal.h | 6 ++++--
6 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index a891d4f1f843..552631c3554a 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1791,8 +1791,9 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
int ret;
if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL)) {
- gpu->cooling = thermal_of_cooling_device_register(dev->of_node,
- (char *)dev_name(dev), gpu, &cooling_ops);
+ gpu->cooling = thermal_of_cooling_device_register(dev->of_node, 0,
+ dev_name(dev),
+ gpu, &cooling_ops);
if (IS_ERR(gpu->cooling))
return PTR_ERR(gpu->cooling);
}
diff --git a/drivers/thermal/cpufreq_cooling.c b/drivers/thermal/cpufreq_cooling.c
index 32bf5ab44f4a..768859a7aed0 100644
--- a/drivers/thermal/cpufreq_cooling.c
+++ b/drivers/thermal/cpufreq_cooling.c
@@ -592,7 +592,7 @@ __cpufreq_cooling_register(struct device_node *np,
if (!name)
goto remove_qos_req;
- cdev = thermal_of_cooling_device_register(np, name, cpufreq_cdev,
+ cdev = thermal_of_cooling_device_register(np, 0, name, cpufreq_cdev,
cooling_ops);
kfree(name);
diff --git a/drivers/thermal/cpuidle_cooling.c b/drivers/thermal/cpuidle_cooling.c
index 425f596614e8..bbd2e91cf5ab 100644
--- a/drivers/thermal/cpuidle_cooling.c
+++ b/drivers/thermal/cpuidle_cooling.c
@@ -207,7 +207,7 @@ static int __cpuidle_cooling_register(struct device_node *np,
goto out_unregister;
}
- cdev = thermal_of_cooling_device_register(np, name, idle_cdev,
+ cdev = thermal_of_cooling_device_register(np, 0, name, idle_cdev,
&cpuidle_cooling_ops);
if (IS_ERR(cdev)) {
ret = PTR_ERR(cdev);
diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c
index 1c7dffc8d45f..0330a8112832 100644
--- a/drivers/thermal/devfreq_cooling.c
+++ b/drivers/thermal/devfreq_cooling.c
@@ -454,7 +454,7 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
if (!name)
goto remove_qos_req;
- cdev = thermal_of_cooling_device_register(np, name, dfc, ops);
+ cdev = thermal_of_cooling_device_register(np, 0, name, dfc, ops);
kfree(name);
if (IS_ERR(cdev)) {
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index d06487bb5e67..a9319ff81d1d 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -514,6 +514,7 @@ EXPORT_SYMBOL_GPL(devm_thermal_of_zone_unregister);
/**
* thermal_of_cooling_device_register() - register an OF thermal cooling device
* @np: a pointer to a device tree node.
+ * @of_index: a cooling device index in the cooling controller
* @type: the thermal cooling device type.
* @devdata: device private data.
* @ops: standard thermal cooling devices callbacks.
@@ -527,7 +528,7 @@ EXPORT_SYMBOL_GPL(devm_thermal_of_zone_unregister);
* ERR_PTR. Caller must check return value with IS_ERR*() helpers.
*/
struct thermal_cooling_device *
-thermal_of_cooling_device_register(struct device_node *np,
+thermal_of_cooling_device_register(struct device_node *np, int of_index,
const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{
@@ -538,6 +539,7 @@ thermal_of_cooling_device_register(struct device_node *np,
return cdev;
cdev->np = np;
+ cdev->of_index = of_index;
thermal_cooling_device_init_complete(cdev);
return cdev;
@@ -582,7 +584,7 @@ devm_thermal_of_child_cooling_device_register(struct device *dev,
if (!ptr)
return ERR_PTR(-ENOMEM);
- tcd = thermal_of_cooling_device_register(np, type, devdata, ops);
+ tcd = thermal_of_cooling_device_register(np, 0, type, devdata, ops);
if (IS_ERR(tcd)) {
devres_free(ptr);
return tcd;
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index b3c448f7d919..070dcf7f77b6 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -134,6 +134,7 @@ struct thermal_cooling_device {
struct list_head node;
#ifdef CONFIG_THERMAL_OF
struct device_node *np;
+ int of_index;
#endif
#ifdef CONFIG_THERMAL_DEBUGFS
struct thermal_debugfs *debugfs;
@@ -201,7 +202,8 @@ struct thermal_zone_device *devm_thermal_of_zone_register(struct device *dev, in
void devm_thermal_of_zone_unregister(struct device *dev, struct thermal_zone_device *tz);
struct thermal_cooling_device *
-thermal_of_cooling_device_register(struct device_node *np, const char *type, void *devdata,
+thermal_of_cooling_device_register(struct device_node *np, int of_index,
+ const char *type, void *data,
const struct thermal_cooling_device_ops *ops);
struct thermal_cooling_device *
@@ -224,7 +226,7 @@ static inline void devm_thermal_of_zone_unregister(struct device *dev,
}
static inline struct thermal_cooling_device *
-thermal_of_cooling_device_register(struct device_node *np,
+thermal_of_cooling_device_register(struct device_node *np, int of_index,
const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v2 10/12] thermal/of: Pass the of_index and add a function to register with an index
2026-04-22 17:42 [PATCH v2 00/12] Support cooling device with ID in the OF Daniel Lezcano
` (8 preceding siblings ...)
2026-04-22 17:42 ` [PATCH v2 09/12] thermal/of: Introduce cooling device of_index Daniel Lezcano
@ 2026-04-22 17:42 ` Daniel Lezcano
2026-04-22 17:43 ` [PATCH v2 11/12] thermal/of: Process cooling device index in cooling-spec Daniel Lezcano
2026-04-22 17:43 ` [PATCH v2 12/12] dt-bindings: thermal: cooling-devices: Update support for 3 cells cooling device Daniel Lezcano
11 siblings, 0 replies; 14+ messages in thread
From: Daniel Lezcano @ 2026-04-22 17:42 UTC (permalink / raw)
To: rafael, daniel.lezcano
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon
Introduce a new function devm_thermal_of_cooling_device_register()
which will register a cooling device and its id.
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
drivers/thermal/thermal_of.c | 70 ++++++++++++++++++++++++++----------
include/linux/thermal.h | 13 +++++++
2 files changed, 64 insertions(+), 19 deletions(-)
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index a9319ff81d1d..d0d6d6b82d5a 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -551,6 +551,56 @@ static void thermal_cooling_device_release(struct device *dev, void *res)
thermal_cooling_device_unregister(*(struct thermal_cooling_device **)res);
}
+static struct thermal_cooling_device *
+__devm_thermal_of_cooling_device_register(struct device *dev, struct device_node *np,
+ int of_index, const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops)
+{
+ struct thermal_cooling_device **ptr, *tcd;
+
+ ptr = devres_alloc(thermal_cooling_device_release, sizeof(*ptr),
+ GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ tcd = thermal_of_cooling_device_register(np, of_index, type, devdata, ops);
+ if (IS_ERR(tcd)) {
+ devres_free(ptr);
+ return tcd;
+ }
+
+ *ptr = tcd;
+ devres_add(dev, ptr);
+
+ return tcd;
+}
+
+/**
+ * devm_thermal_of_cooling_device_register() - register an OF thermal cooling device
+ * @dev: a valid struct device pointer of a sensor device.
+ * @of_index: a cooling device index in the cooling controller
+ * @type: the thermal cooling device type.
+ * @devdata: device private data.
+ * @ops: standard thermal cooling devices callbacks.
+ *
+ * This function will register a cooling device with device tree node reference.
+ * This interface function adds a new thermal cooling device (fan/processor/...)
+ * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
+ * to all the thermal zone devices registered at the same time.
+ *
+ * Return: a pointer to the created struct thermal_cooling_device or an
+ * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
+ */
+struct thermal_cooling_device *
+devm_thermal_of_cooling_device_register(struct device *dev, int of_index,
+ const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops)
+{
+ return __devm_thermal_of_cooling_device_register(dev, dev->of_node, of_index,
+ type, devdata, ops);
+}
+EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register);
+
/**
* devm_thermal_of_child_cooling_device_register() - register an OF thermal cooling
* device
@@ -577,24 +627,6 @@ devm_thermal_of_child_cooling_device_register(struct device *dev,
const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{
- struct thermal_cooling_device **ptr, *tcd;
-
- ptr = devres_alloc(thermal_cooling_device_release, sizeof(*ptr),
- GFP_KERNEL);
- if (!ptr)
- return ERR_PTR(-ENOMEM);
-
- tcd = thermal_of_cooling_device_register(np, 0, type, devdata, ops);
- if (IS_ERR(tcd)) {
- devres_free(ptr);
- return tcd;
- }
-
- *ptr = tcd;
- devres_add(dev, ptr);
-
- thermal_cooling_device_init_complete(tcd);
-
- return tcd;
+ return __devm_thermal_of_cooling_device_register(dev, np, 0, type, devdata, ops);
}
EXPORT_SYMBOL_GPL(devm_thermal_of_child_cooling_device_register);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 070dcf7f77b6..55ac0390da8d 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -206,6 +206,11 @@ thermal_of_cooling_device_register(struct device_node *np, int of_index,
const char *type, void *data,
const struct thermal_cooling_device_ops *ops);
+struct thermal_cooling_device *
+devm_thermal_of_cooling_device_register(struct device *dev, int of_index,
+ const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops);
+
struct thermal_cooling_device *
devm_thermal_of_child_cooling_device_register(struct device *dev,
struct device_node *np,
@@ -233,6 +238,14 @@ thermal_of_cooling_device_register(struct device_node *np, int of_index,
return ERR_PTR(-ENODEV);
}
+static inline struct thermal_cooling_device *
+devm_thermal_of_cooling_device_register(struct device *dev, int of_index,
+ const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops)
+{
+ return ERR_PTR(-ENODEV);
+}
+
static inline struct thermal_cooling_device *
devm_thermal_of_child_cooling_device_register(struct device *dev,
struct device_node *np,
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v2 11/12] thermal/of: Process cooling device index in cooling-spec
2026-04-22 17:42 [PATCH v2 00/12] Support cooling device with ID in the OF Daniel Lezcano
` (9 preceding siblings ...)
2026-04-22 17:42 ` [PATCH v2 10/12] thermal/of: Pass the of_index and add a function to register with an index Daniel Lezcano
@ 2026-04-22 17:43 ` Daniel Lezcano
2026-04-22 17:43 ` [PATCH v2 12/12] dt-bindings: thermal: cooling-devices: Update support for 3 cells cooling device Daniel Lezcano
11 siblings, 0 replies; 14+ messages in thread
From: Daniel Lezcano @ 2026-04-22 17:43 UTC (permalink / raw)
To: rafael, daniel.lezcano
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon
The new DT bindings format describes a cooling device spec with the
cooling device node, the id and the mitigation limits.
Depending on the version of the DT bindings, in order to bind, check
with the device node pointer only or, in addition, the cooling device
id.
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
drivers/thermal/thermal_of.c | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index d0d6d6b82d5a..f4628300972e 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -259,16 +259,34 @@ static bool thermal_of_get_cooling_spec(struct device_node *map_np, int index,
of_node_put(cooling_spec.np);
- if (cooling_spec.args_count < 2) {
- pr_err("wrong reference to cooling device, missing limits\n");
+ /*
+ * There are two formats:
+ * - Legacy format : <&cdev lower upper>
+ * - New format : <&cdev of_index lower upper>
+ *
+ * With the new format, along with the device node pointer,
+ * the of_index must match with the cooling device of_index in
+ * order to bind
+ */
+ if (cooling_spec.args_count < 2 || cooling_spec.args_count > 3) {
+ pr_err("Invalid number of cooling device parameters\n");
return false;
}
+ if (cooling_spec.args_count == 3 &&
+ cooling_spec.args[0] != cdev->of_index)
+ return false;
+
if (cooling_spec.np != cdev->np)
return false;
- c->lower = cooling_spec.args[0];
- c->upper = cooling_spec.args[1];
+ if (cooling_spec.args_count != 3) {
+ c->lower = cooling_spec.args[0];
+ c->upper = cooling_spec.args[1];
+ } else {
+ c->lower = cooling_spec.args[1];
+ c->upper = cooling_spec.args[2];
+ }
c->weight = weight;
return true;
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v2 12/12] dt-bindings: thermal: cooling-devices: Update support for 3 cells cooling device
2026-04-22 17:42 [PATCH v2 00/12] Support cooling device with ID in the OF Daniel Lezcano
` (10 preceding siblings ...)
2026-04-22 17:43 ` [PATCH v2 11/12] thermal/of: Process cooling device index in cooling-spec Daniel Lezcano
@ 2026-04-22 17:43 ` Daniel Lezcano
2026-04-23 8:33 ` Krzysztof Kozlowski
11 siblings, 1 reply; 14+ messages in thread
From: Daniel Lezcano @ 2026-04-22 17:43 UTC (permalink / raw)
To: rafael, daniel.lezcano
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
From: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
Extend the thermal cooling device binding to support a 3 cells specifier
along with the 2 cells format.
Update #cooling-cells property to enum to support both 2 and 3 arguments.
Fix pwm-fan.yaml to restrict the number of cells to 'const: 2'
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
Documentation/devicetree/bindings/hwmon/pwm-fan.yaml | 3 ++-
.../bindings/thermal/thermal-cooling-devices.yaml | 8 ++++++--
.../devicetree/bindings/thermal/thermal-zones.yaml | 3 ++-
3 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml b/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml
index a84cc3a4cfdc..6a24851fd80d 100644
--- a/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml
+++ b/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml
@@ -63,7 +63,8 @@ properties:
description: The PWM that is used to control the fan.
maxItems: 1
- "#cooling-cells": true
+ "#cooling-cells":
+ const: 2
required:
- compatible
diff --git a/Documentation/devicetree/bindings/thermal/thermal-cooling-devices.yaml b/Documentation/devicetree/bindings/thermal/thermal-cooling-devices.yaml
index b9022f1613d8..28f5818f1e60 100644
--- a/Documentation/devicetree/bindings/thermal/thermal-cooling-devices.yaml
+++ b/Documentation/devicetree/bindings/thermal/thermal-cooling-devices.yaml
@@ -44,10 +44,14 @@ select: true
properties:
"#cooling-cells":
description:
- Must be 2, in order to specify minimum and maximum cooling state used in
+ Must be 2 or 3. If 2, specifies minimum and maximum cooling state used in
the cooling-maps reference. The first cell is the minimum cooling state
and the second cell is the maximum cooling state requested.
- const: 2
+ If 3, the first cell specifies the thermal mitigation device specifier
+ index for devices that support multiple thermal mitigation mechanisms.
+ The two other cells are respectively the minimum cooling state and the
+ maximum cooling state.
+ enum: [2, 3]
additionalProperties: true
diff --git a/Documentation/devicetree/bindings/thermal/thermal-zones.yaml b/Documentation/devicetree/bindings/thermal/thermal-zones.yaml
index 0de0a9757ccc..1261ba0e802e 100644
--- a/Documentation/devicetree/bindings/thermal/thermal-zones.yaml
+++ b/Documentation/devicetree/bindings/thermal/thermal-zones.yaml
@@ -214,7 +214,8 @@ patternProperties:
device. Using the THERMAL_NO_LIMIT (-1UL) constant in the
cooling-device phandle limit specifier lets the framework
use the minimum and maximum cooling state for that cooling
- device automatically.
+ device automatically. If three arguments are specified,
+ the first argument is the cooling device specifier.
contribution:
$ref: /schemas/types.yaml#/definitions/uint32
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v2 12/12] dt-bindings: thermal: cooling-devices: Update support for 3 cells cooling device
2026-04-22 17:43 ` [PATCH v2 12/12] dt-bindings: thermal: cooling-devices: Update support for 3 cells cooling device Daniel Lezcano
@ 2026-04-23 8:33 ` Krzysztof Kozlowski
0 siblings, 0 replies; 14+ messages in thread
From: Krzysztof Kozlowski @ 2026-04-23 8:33 UTC (permalink / raw)
To: Daniel Lezcano
Cc: rafael, daniel.lezcano, gaurav.kohli, Zhang Rui, Lukasz Luba,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Lucas Stach,
Russell King, Christian Gmeiner, David Airlie, Simona Vetter,
Guenter Roeck, Joel Stanley, Andrew Jeffery,
Thomas Weißschuh, Benson Leung, Pali Rohár, Avi Fishman,
Tomer Maimon, Tali Perry, Patrick Venture, Nancy Yuen,
Benjamin Fair, Heiko Stuebner, Thierry Reding, Jonathan Hunter,
Bjorn Andersson, Konrad Dybcio, Amit Daniel Kachhap, Viresh Kumar,
Neil Armstrong, Amit Kucheria, linux-pm, linux-kernel,
linux-hwmon,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
On Wed, Apr 22, 2026 at 07:43:01PM +0200, Daniel Lezcano wrote:
> From: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>
> Extend the thermal cooling device binding to support a 3 cells specifier
> along with the 2 cells format.
>
> Update #cooling-cells property to enum to support both 2 and 3 arguments.
>
> Fix pwm-fan.yaml to restrict the number of cells to 'const: 2'
>
> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 14+ messages in thread