[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20260118-cros_ec-hwmon-pwm-v2-4-77eb1709b031@weissschuh.net>
Date: Sun, 18 Jan 2026 10:45:58 +0100
From: Thomas Weißschuh <linux@...ssschuh.net>
To: Benson Leung <bleung@...omium.org>, Tzung-Bi Shih <tzungbi@...nel.org>,
Guenter Roeck <groeck@...omium.org>,
Thomas Weißschuh <thomas@...ssschuh.net>,
Jean Delvare <jdelvare@...e.com>, Guenter Roeck <linux@...ck-us.net>,
Jonathan Corbet <corbet@....net>
Cc: Dustin Howett <dustin@...ett.net>,
Mario Limonciello <mario.limonciello@....com>,
Stephen Horvath <s.horvath@...look.com.au>, chrome-platform@...ts.linux.dev,
linux-kernel@...r.kernel.org, linux-hwmon@...r.kernel.org,
Sung-Chi Li <lschyi@...omium.org>, linux-doc@...r.kernel.org,
Thomas Weißschuh <linux@...ssschuh.net>
Subject: [PATCH v2 4/4] hwmon: (cros_ec) Add support for temperature
thresholds
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@...ssschuh.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
Powered by blists - more mailing lists