[PATCH v4] wifi: mt76: mt7996: add thermal zone device registration
Ryan Leung
untilscour at protonmail.com
Tue Aug 11 01:50:03 PDT 2026
Register the mt7996 phy as a thermal zone sensor using
devm_thermal_of_zone_register() so that device tree thermal-zones
nodes can reference the Wi-Fi chip as a temperature source. This
allows the kernel thermal governor to control external cooling
devices such as PWM fans based on Wi-Fi chip temperature.
Registration is non-fatal: -ENODEV is returned when no
thermal-sensors DT property references this device, which is the
expected case on platforms without a thermal zone configured.
Unregister the thermal zone together with the existing cooling device
when the phy is torn down, and on the hwmon registration failure path
in the same init routine, so neither is left registered against a phy
that is about to be freed. Clear both pointers after unregistering,
since this init-time failure path can now run before the normal
teardown path also unregisters the same phy, and without clearing them,
that second call would unregister already-freed objects.
Signed-off-by: Ryan Leung <untilscour at protonmail.com>
---
Changes in v4:
- Clear phy->tzone/phy->cdev in mt7996_unregister_thermal() after
unregistering, making it idempotent.
- Link to v3: https://patch.msgid.link/20260810-mt7996-thermal-zone-v3-1-ae9d7cd6cde1@protonmail.com
Changes in v3:
- Unwind cdev/tzone registration in mt7996_thermal_init() on hwmon registration failure.
- Link to v2: https://patch.msgid.link/20260810-mt7996-thermal-zone-v2-1-563dfbbf9175@protonmail.com
Changes in v2:
- Take phy->dev->mt76.mutex around mt7996_mcu_get_temperature()
- Unregister phy->tzone explicitly in mt7996_unregister_thermal() before the phy is freed
- Link to v1: https://patch.msgid.link/20260722-mt7996-thermal-zone-v1-1-88896e6e9985@protonmail.com
---
drivers/net/wireless/mediatek/mt76/mt7996/init.c | 40 +++++++++++++++++++++-
drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 1 +
2 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
index fb635a092584..0ac8424a7d99 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
@@ -234,17 +234,42 @@ static const struct thermal_cooling_device_ops mt7996_thermal_ops = {
.set_cur_state = mt7996_thermal_set_cur_throttle_state,
};
+static int mt7996_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
+{
+ struct mt7996_phy *phy = thermal_zone_device_priv(tz);
+ int val;
+
+ mutex_lock(&phy->dev->mt76.mutex);
+ val = mt7996_mcu_get_temperature(phy);
+ mutex_unlock(&phy->dev->mt76.mutex);
+ if (val < 0)
+ return val;
+
+ *temp = val * 1000;
+ return 0;
+}
+
+static const struct thermal_zone_device_ops mt7996_tz_ops = {
+ .get_temp = mt7996_thermal_get_temp,
+};
+
static void mt7996_unregister_thermal(struct mt7996_phy *phy)
{
struct wiphy *wiphy = phy->mt76->hw->wiphy;
char name[sizeof("cooling_deviceXXX")];
+ if (phy->tzone) {
+ devm_thermal_of_zone_unregister(phy->dev->mt76.dev, phy->tzone);
+ phy->tzone = NULL;
+ }
+
if (!phy->cdev)
return;
snprintf(name, sizeof(name), "cooling_device%d", phy->mt76->band_idx);
sysfs_remove_link(&wiphy->dev.kobj, name);
thermal_cooling_device_unregister(phy->cdev);
+ phy->cdev = NULL;
}
static int mt7996_thermal_init(struct mt7996_phy *phy)
@@ -275,14 +300,27 @@ static int mt7996_thermal_init(struct mt7996_phy *phy)
phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP;
phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP;
+ phy->tzone = devm_thermal_of_zone_register(phy->dev->mt76.dev,
+ phy->mt76->band_idx, phy,
+ &mt7996_tz_ops);
+ if (IS_ERR(phy->tzone)) {
+ if (PTR_ERR(phy->tzone) != -ENODEV)
+ dev_warn(phy->dev->mt76.dev,
+ "failed to register thermal zone %d: %ld\n",
+ phy->mt76->band_idx, PTR_ERR(phy->tzone));
+ phy->tzone = NULL;
+ }
+
if (!IS_REACHABLE(CONFIG_HWMON))
return 0;
hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy,
mt7996_hwmon_groups);
- if (IS_ERR(hwmon))
+ if (IS_ERR(hwmon)) {
+ mt7996_unregister_thermal(phy);
return PTR_ERR(hwmon);
+ }
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index 2a0cdb56f822..39fa25a562e5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -372,6 +372,7 @@ struct mt7996_phy {
struct ieee80211_sband_iftype_data iftype[NUM_NL80211_BANDS][NUM_NL80211_IFTYPES];
+ struct thermal_zone_device *tzone;
struct thermal_cooling_device *cdev;
u8 cdev_state;
u8 throttle_state;
---
base-commit: ca800a9302764c445de0da0e84d2252400a770ee
change-id: 20260722-mt7996-thermal-zone-a1de7cb1d728
Best regards,
--
Ryan Leung <untilscour at protonmail.com>
More information about the linux-arm-kernel
mailing list