wifi: mt76: mt7996: add thermal sensor device support
This patch adds support for thermal sensor device, including the following features: - Support to read current chip temperature. - Support to set/get the trigger/restore temperature for thermal service. - Support to read current chip tx cycle. Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com> Signed-off-by: Shayne Chen <shayne.chen@mediatek.com> Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
21f290884b
commit
6879b2e941
2 changed files with 130 additions and 0 deletions
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
#include <linux/hwmon.h>
|
||||||
|
#include <linux/hwmon-sysfs.h>
|
||||||
#include <linux/thermal.h>
|
#include <linux/thermal.h>
|
||||||
#include "mt7996.h"
|
#include "mt7996.h"
|
||||||
#include "mac.h"
|
#include "mac.h"
|
||||||
|
@ -43,6 +45,82 @@ static const struct ieee80211_iface_combination if_comb[] = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static ssize_t mt7996_thermal_temp_show(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct mt7996_phy *phy = dev_get_drvdata(dev);
|
||||||
|
int i = to_sensor_dev_attr(attr)->index;
|
||||||
|
int temperature;
|
||||||
|
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
temperature = mt7996_mcu_get_temperature(phy);
|
||||||
|
if (temperature < 0)
|
||||||
|
return temperature;
|
||||||
|
/* display in millidegree celcius */
|
||||||
|
return sprintf(buf, "%u\n", temperature * 1000);
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
return sprintf(buf, "%u\n",
|
||||||
|
phy->throttle_temp[i - 1] * 1000);
|
||||||
|
case 3:
|
||||||
|
return sprintf(buf, "%hhu\n", phy->throttle_state);
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t mt7996_thermal_temp_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct mt7996_phy *phy = dev_get_drvdata(dev);
|
||||||
|
int ret, i = to_sensor_dev_attr(attr)->index;
|
||||||
|
long val;
|
||||||
|
|
||||||
|
ret = kstrtol(buf, 10, &val);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
mutex_lock(&phy->dev->mt76.mutex);
|
||||||
|
val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 40, 130);
|
||||||
|
|
||||||
|
/* add a safety margin ~10 */
|
||||||
|
if ((i - 1 == MT7996_CRIT_TEMP_IDX &&
|
||||||
|
val > phy->throttle_temp[MT7996_MAX_TEMP_IDX] - 10) ||
|
||||||
|
(i - 1 == MT7996_MAX_TEMP_IDX &&
|
||||||
|
val - 10 < phy->throttle_temp[MT7996_CRIT_TEMP_IDX])) {
|
||||||
|
dev_err(phy->dev->mt76.dev,
|
||||||
|
"temp1_max shall be 10 degrees higher than temp1_crit.");
|
||||||
|
mutex_unlock(&phy->dev->mt76.mutex);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
phy->throttle_temp[i - 1] = val;
|
||||||
|
mutex_unlock(&phy->dev->mt76.mutex);
|
||||||
|
|
||||||
|
ret = mt7996_mcu_set_thermal_protect(phy, true);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7996_thermal_temp, 0);
|
||||||
|
static SENSOR_DEVICE_ATTR_RW(temp1_crit, mt7996_thermal_temp, 1);
|
||||||
|
static SENSOR_DEVICE_ATTR_RW(temp1_max, mt7996_thermal_temp, 2);
|
||||||
|
static SENSOR_DEVICE_ATTR_RO(throttle1, mt7996_thermal_temp, 3);
|
||||||
|
|
||||||
|
static struct attribute *mt7996_hwmon_attrs[] = {
|
||||||
|
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_temp1_crit.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_throttle1.dev_attr.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
ATTRIBUTE_GROUPS(mt7996_hwmon);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
|
mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
|
||||||
unsigned long *state)
|
unsigned long *state)
|
||||||
|
@ -113,6 +191,7 @@ static int mt7996_thermal_init(struct mt7996_phy *phy)
|
||||||
{
|
{
|
||||||
struct wiphy *wiphy = phy->mt76->hw->wiphy;
|
struct wiphy *wiphy = phy->mt76->hw->wiphy;
|
||||||
struct thermal_cooling_device *cdev;
|
struct thermal_cooling_device *cdev;
|
||||||
|
struct device *hwmon;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s",
|
name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s",
|
||||||
|
@ -131,6 +210,15 @@ static int mt7996_thermal_init(struct mt7996_phy *phy)
|
||||||
phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP;
|
phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP;
|
||||||
phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP;
|
phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP;
|
||||||
|
|
||||||
|
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))
|
||||||
|
return PTR_ERR(hwmon);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3602,6 +3602,48 @@ out:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mt7996_mcu_get_temperature(struct mt7996_phy *phy)
|
||||||
|
{
|
||||||
|
#define TEMPERATURE_QUERY 0
|
||||||
|
#define GET_TEMPERATURE 0
|
||||||
|
struct {
|
||||||
|
u8 _rsv[4];
|
||||||
|
|
||||||
|
__le16 tag;
|
||||||
|
__le16 len;
|
||||||
|
|
||||||
|
u8 rsv1;
|
||||||
|
u8 action;
|
||||||
|
u8 band_idx;
|
||||||
|
u8 rsv2;
|
||||||
|
} req = {
|
||||||
|
.tag = cpu_to_le16(TEMPERATURE_QUERY),
|
||||||
|
.len = cpu_to_le16(sizeof(req) - 4),
|
||||||
|
.action = GET_TEMPERATURE,
|
||||||
|
.band_idx = phy->mt76->band_idx,
|
||||||
|
};
|
||||||
|
struct mt7996_mcu_thermal {
|
||||||
|
u8 _rsv[4];
|
||||||
|
|
||||||
|
__le16 tag;
|
||||||
|
__le16 len;
|
||||||
|
|
||||||
|
__le32 rsv;
|
||||||
|
__le32 temperature;
|
||||||
|
} __packed * res;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = mt76_mcu_send_and_get_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
|
||||||
|
&req, sizeof(req), true, &skb);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
res = (void *)skb->data;
|
||||||
|
|
||||||
|
return le32_to_cpu(res->temperature);
|
||||||
|
}
|
||||||
|
|
||||||
int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state)
|
int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state)
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
|
|
Loading…
Add table
Reference in a new issue