mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:04:41 +01:00
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@weissschuh.net> Reviewed-by: Tzung-Bi Shih <tzungbi@kernel.org> Link: https://lore.kernel.org/r/20260118-cros_ec-hwmon-pwm-v2-4-77eb1709b031@weissschuh.net [groeck: Rearrange code to no longer use unreachable() since that causes a hiccup with some versions of gcc and objtool] Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
parent
11c5802d28
commit
afa7c56ec4
2 changed files with 57 additions and 3 deletions
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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,29 @@ 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;
|
||||
return EC_TEMP_THRESH_HALT; /* attr == hwmon_temp_emergency */
|
||||
}
|
||||
|
||||
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 +222,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 +333,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 +358,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 +569,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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue