blob: b6803265a1b1248f1a91f02f0c7cba9d0052e91f [file] [log] [blame]
developer8eb72a32023-03-30 08:32:07 +08001From a0190f9cb1bc65c5dced813fa1929de9bb714d9f Mon Sep 17 00:00:00 2001
developer483388c2023-03-08 13:52:15 +08002From: Howard Hsu <howard-yh.hsu@mediatek.com>
3Date: Thu, 2 Feb 2023 20:53:42 +0800
developer1bc2ce22023-03-25 00:47:41 +08004Subject: [PATCH 13/29] wifi: mt76: mt7996: add thermal sensor device support
developer483388c2023-03-08 13:52:15 +08005
6---
7 mt7996/init.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++
8 mt7996/mcu.c | 41 ++++++++++++++++++++++++
9 2 files changed, 128 insertions(+)
10
11diff --git a/mt7996/init.c b/mt7996/init.c
developer8eb72a32023-03-30 08:32:07 +080012index 44165a3..7350194 100644
developer483388c2023-03-08 13:52:15 +080013--- a/mt7996/init.c
14+++ b/mt7996/init.c
15@@ -4,6 +4,8 @@
16 */
17
18 #include <linux/etherdevice.h>
19+#include <linux/hwmon.h>
20+#include <linux/hwmon-sysfs.h>
21 #include <linux/thermal.h>
22 #include "mt7996.h"
23 #include "mac.h"
24@@ -41,6 +43,81 @@ static const struct ieee80211_iface_combination if_comb[] = {
25 }
26 };
27
28+static ssize_t mt7996_thermal_temp_show(struct device *dev,
29+ struct device_attribute *attr,
30+ char *buf)
31+{
32+ struct mt7996_phy *phy = dev_get_drvdata(dev);
33+ int i = to_sensor_dev_attr(attr)->index;
34+ int temperature;
35+
36+ switch (i) {
37+ case 0:
38+ temperature = mt7996_mcu_get_temperature(phy);
39+ if (temperature < 0)
40+ return temperature;
41+ /* display in millidegree celcius */
42+ return sprintf(buf, "%u\n", temperature * 1000);
43+ case 1:
44+ case 2:
45+ return sprintf(buf, "%u\n",
46+ phy->throttle_temp[i - 1] * 1000);
47+ case 3:
48+ return sprintf(buf, "%hhu\n", phy->throttle_state);
49+ default:
50+ return -EINVAL;
51+ }
52+}
53+
54+static ssize_t mt7996_thermal_temp_store(struct device *dev,
55+ struct device_attribute *attr,
56+ const char *buf, size_t count)
57+{
58+ struct mt7996_phy *phy = dev_get_drvdata(dev);
59+ int ret, i = to_sensor_dev_attr(attr)->index;
60+ long val;
61+
62+ ret = kstrtol(buf, 10, &val);
63+ if (ret < 0)
64+ return ret;
65+
66+ mutex_lock(&phy->dev->mt76.mutex);
67+ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 40, 130);
68+
69+ if ((i - 1 == MT7996_CRIT_TEMP_IDX &&
70+ val > phy->throttle_temp[MT7996_MAX_TEMP_IDX]) ||
71+ (i - 1 == MT7996_MAX_TEMP_IDX &&
72+ val < phy->throttle_temp[MT7996_CRIT_TEMP_IDX])) {
73+ dev_err(phy->dev->mt76.dev,
74+ "temp1_max shall be greater than temp1_crit.");
75+ mutex_unlock(&phy->dev->mt76.mutex);
76+ return -EINVAL;
77+ }
78+
79+ phy->throttle_temp[i - 1] = val;
80+ mutex_unlock(&phy->dev->mt76.mutex);
81+
82+ ret = mt7996_mcu_set_thermal_protect(phy);
83+ if (ret)
84+ return ret;
85+
86+ return count;
87+}
88+
89+static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7996_thermal_temp, 0);
90+static SENSOR_DEVICE_ATTR_RW(temp1_crit, mt7996_thermal_temp, 1);
91+static SENSOR_DEVICE_ATTR_RW(temp1_max, mt7996_thermal_temp, 2);
92+static SENSOR_DEVICE_ATTR_RO(throttle1, mt7996_thermal_temp, 3);
93+
94+static struct attribute *mt7996_hwmon_attrs[] = {
95+ &sensor_dev_attr_temp1_input.dev_attr.attr,
96+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
97+ &sensor_dev_attr_temp1_max.dev_attr.attr,
98+ &sensor_dev_attr_throttle1.dev_attr.attr,
99+ NULL,
100+};
101+ATTRIBUTE_GROUPS(mt7996_hwmon);
102+
103 static int
104 mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
105 unsigned long *state)
106@@ -112,6 +189,7 @@ static int mt7996_thermal_init(struct mt7996_phy *phy)
107 {
108 struct wiphy *wiphy = phy->mt76->hw->wiphy;
109 struct thermal_cooling_device *cdev;
110+ struct device *hwmon;
111 const char *name;
112
113 name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s",
114@@ -130,6 +208,15 @@ static int mt7996_thermal_init(struct mt7996_phy *phy)
115 phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP;
116 phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP;
117
118+ if (!IS_REACHABLE(CONFIG_HWMON))
119+ return 0;
120+
121+ hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy,
122+ mt7996_hwmon_groups);
123+
124+ if (IS_ERR(hwmon))
125+ return PTR_ERR(hwmon);
126+
127 return 0;
128 }
129
130diff --git a/mt7996/mcu.c b/mt7996/mcu.c
developer8eb72a32023-03-30 08:32:07 +0800131index 3820a63..b332658 100644
developer483388c2023-03-08 13:52:15 +0800132--- a/mt7996/mcu.c
133+++ b/mt7996/mcu.c
134@@ -3308,6 +3308,47 @@ out:
135 return 0;
136 }
137
138+int mt7996_mcu_get_temperature(struct mt7996_phy *phy)
139+{
140+#define TEMPERATURE_QUERY 0
141+#define GET_TEMPERATURE 0
142+ struct {
143+ u8 _rsv[4];
144+
145+ __le16 tag;
146+ __le16 len;
147+
148+ u8 rsv1;
149+ u8 action;
150+ u8 band_idx;
151+ u8 rsv2;
152+ } req = {
153+ .tag = cpu_to_le16(TEMPERATURE_QUERY),
154+ .len = cpu_to_le16(sizeof(req) - 4),
155+ .action = GET_TEMPERATURE,
156+ .band_idx = phy->mt76->band_idx,
157+ };
158+ struct mt7996_mcu_thermal {
159+ u8 _rsv[4];
160+
161+ __le16 tag;
162+ __le16 len;
163+
164+ __le32 rsv;
165+ __le32 temperature;
166+ } __packed *res;
167+ struct sk_buff *skb;
168+ int ret;
169+
170+ ret = mt76_mcu_send_and_get_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
171+ &req, sizeof(req), true, &skb);
172+ if (ret)
173+ return ret;
174+
175+ res = (void *)skb->data;
176+
177+ return le32_to_cpu(res->temperature);
178+}
179
180 int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state)
181 {
182--
developer8eb72a32023-03-30 08:32:07 +08001832.18.0
developer483388c2023-03-08 13:52:15 +0800184