[PATCH v2 4/4] hwmon: (cros_ec) Add support for temperature thresholds
From: Thomas Weißschuh <linux@weissschuh.net>
Date: 2026-01-18 09:46:05
Also in:
chrome-platform, linux-hwmon, lkml
Subsystem:
chromeos ec hardware monitoring, documentation, hardware monitoring, the rest · Maintainers:
Thomas Weißschuh, Jonathan Corbet, Guenter Roeck, Linus Torvalds
Implement reading temperature thresholds through EC_CMD_THERMAL_GET_THRESHOLD/EC_CMD_THERMAL_SET_THRESHOLD. Thresholds are mapped as follows between the EC and hwmon: hwmon_temp_max - EC_TEMP_THRESH_WARN hwmon_temp_crit - EC_TEMP_THRESH_HIGH hwmon_temp_emergency - EC_TEMP_THRESH_HALT Signed-off-by: Thomas Weißschuh <linux@weissschuh.net> --- The following checkpatch.pl complaint is a false positive: WARNING: else is not generally useful after a break or return #75: FILE: drivers/hwmon/cros_ec_hwmon.c:170: + return EC_TEMP_THRESH_HALT; + else --- Documentation/hwmon/cros_ec_hwmon.rst | 3 ++ drivers/hwmon/cros_ec_hwmon.c | 60 +++++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 3 deletions(-)
diff --git a/Documentation/hwmon/cros_ec_hwmon.rst b/Documentation/hwmon/cros_ec_hwmon.rst
index ebc8da48fa8a..9ccab721e7c2 100644
--- a/Documentation/hwmon/cros_ec_hwmon.rst
+++ b/Documentation/hwmon/cros_ec_hwmon.rst@@ -35,6 +35,9 @@ Fan target speed Temperature readings Always supported. +Temperature thresholds + If supported by the EC. + PWM fan control If the EC also supports setting fan PWM values and fan mode.
diff --git a/drivers/hwmon/cros_ec_hwmon.c b/drivers/hwmon/cros_ec_hwmon.c
index f5be293fdaa6..5b998cd5e506 100644
--- a/drivers/hwmon/cros_ec_hwmon.c
+++ b/drivers/hwmon/cros_ec_hwmon.c@@ -28,6 +28,7 @@ struct cros_ec_hwmon_priv { const char *temp_sensor_names[EC_TEMP_SENSOR_ENTRIES + EC_TEMP_SENSOR_B_ENTRIES]; u8 usable_fans; bool fan_control_supported; + bool temp_threshold_supported; u8 manual_fans; /* bits to indicate whether the fan is set to manual */ u8 manual_fan_pwm[EC_FAN_SPEED_ENTRIES]; };
@@ -116,6 +117,23 @@ static int cros_ec_hwmon_read_temp(struct cros_ec_device *cros_ec, u8 index, u8 return 0; } +static int cros_ec_hwmon_read_temp_threshold(struct cros_ec_device *cros_ec, u8 index, + enum ec_temp_thresholds threshold, u32 *temp) +{ + struct ec_params_thermal_get_threshold_v1 req = {}; + struct ec_thermal_config resp; + int ret; + + req.sensor_num = index; + ret = cros_ec_cmd(cros_ec, 1, EC_CMD_THERMAL_GET_THRESHOLD, + &req, sizeof(req), &resp, sizeof(resp)); + if (ret < 0) + return ret; + + *temp = resp.temp_host[threshold]; + return 0; +} + static bool cros_ec_hwmon_is_error_fan(u16 speed) { return speed == EC_FAN_SPEED_NOT_PRESENT || speed == EC_FAN_SPEED_STALLED;
@@ -134,12 +152,32 @@ static long cros_ec_hwmon_temp_to_millicelsius(u8 temp) return kelvin_to_millicelsius((((long)temp) + EC_TEMP_SENSOR_OFFSET)); } +static bool cros_ec_hwmon_attr_is_temp_threshold(u32 attr) +{ + return attr == hwmon_temp_max || + attr == hwmon_temp_crit || + attr == hwmon_temp_emergency; +} + +static enum ec_temp_thresholds cros_ec_hwmon_attr_to_thres(u32 attr) +{ + if (attr == hwmon_temp_max) + return EC_TEMP_THRESH_WARN; + else if (attr == hwmon_temp_crit) + return EC_TEMP_THRESH_HIGH; + else if (attr == hwmon_temp_emergency) + return EC_TEMP_THRESH_HALT; + else + unreachable(); +} + static int cros_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { struct cros_ec_hwmon_priv *priv = dev_get_drvdata(dev); int ret = -EOPNOTSUPP; u8 control_method; + u32 threshold; u8 pwm_value; u16 speed; u8 temp;
@@ -187,6 +225,13 @@ static int cros_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type, ret = cros_ec_hwmon_read_temp(priv->cros_ec, channel, &temp); if (ret == 0) *val = cros_ec_hwmon_is_error_temp(temp); + + } else if (cros_ec_hwmon_attr_is_temp_threshold(attr)) { + ret = cros_ec_hwmon_read_temp_threshold(priv->cros_ec, channel, + cros_ec_hwmon_attr_to_thres(attr), + &threshold); + if (ret == 0) + *val = kelvin_to_millicelsius(threshold); } }
@@ -291,8 +336,14 @@ static umode_t cros_ec_hwmon_is_visible(const void *data, enum hwmon_sensor_type if (priv->fan_control_supported && priv->usable_fans & BIT(channel)) return 0644; } else if (type == hwmon_temp) { - if (priv->temp_sensor_names[channel]) - return 0444; + if (priv->temp_sensor_names[channel]) { + if (cros_ec_hwmon_attr_is_temp_threshold(attr)) { + if (priv->temp_threshold_supported) + return 0444; + } else { + return 0444; + } + } } return 0;
@@ -310,7 +361,8 @@ static const struct hwmon_channel_info * const cros_ec_hwmon_info[] = { HWMON_PWM_INPUT | HWMON_PWM_ENABLE, HWMON_PWM_INPUT | HWMON_PWM_ENABLE, HWMON_PWM_INPUT | HWMON_PWM_ENABLE), -#define CROS_EC_HWMON_TEMP_PARAMS (HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL) +#define CROS_EC_HWMON_TEMP_PARAMS (HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL | \ + HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_EMERGENCY) HWMON_CHANNEL_INFO(temp, CROS_EC_HWMON_TEMP_PARAMS, CROS_EC_HWMON_TEMP_PARAMS,
@@ -520,6 +572,8 @@ static int cros_ec_hwmon_probe(struct platform_device *pdev) cros_ec_hwmon_probe_temp_sensors(dev, priv, thermal_version); cros_ec_hwmon_probe_fans(priv); priv->fan_control_supported = cros_ec_hwmon_probe_fan_control_supported(priv->cros_ec); + priv->temp_threshold_supported = is_cros_ec_cmd_available(priv->cros_ec, + EC_CMD_THERMAL_GET_THRESHOLD, 1); cros_ec_hwmon_register_fan_cooling_devices(dev, priv); hwmon_dev = devm_hwmon_device_register_with_info(dev, "cros_ec", priv,
--
2.52.0