From b1986c8e31a3e5f119a52aab50234fc65cf01f30 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Mon, 27 Sep 2021 00:10:43 +0200 Subject: hwmon: (dell-smm) Add support for fanX_min, fanX_max and fanX_target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The nominal speed of each fan can be obtained with i8k_get_fan_nominal_speed(), however the result is not available from userspace. Change that by adding fanX_min, fanX_max and fanX_target attributes. All are RO since fan control happens over pwm. Tested on a Dell Inspiron 3505 and a Dell Latitude C600. Signed-off-by: Armin Wolf Reviewed-by: Pali Rohár Link: https://lore.kernel.org/r/20210926221044.14327-2-W_Armin@gmx.de Signed-off-by: Guenter Roeck --- drivers/hwmon/dell-smm-hwmon.c | 61 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 6 deletions(-) (limited to 'drivers/hwmon/dell-smm-hwmon.c') diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index 5936f2f812d4..af0d0d2b6e99 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -74,6 +74,7 @@ struct dell_smm_data { int temp_type[DELL_SMM_NO_TEMP]; bool fan[DELL_SMM_NO_FANS]; int fan_type[DELL_SMM_NO_FANS]; + int *fan_nominal_speed[DELL_SMM_NO_FANS]; }; MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); @@ -671,6 +672,13 @@ static umode_t dell_smm_is_visible(const void *drvdata, enum hwmon_sensor_types if (data->fan[channel] && !data->disallow_fan_type_call) return 0444; + break; + case hwmon_fan_min: + case hwmon_fan_max: + case hwmon_fan_target: + if (data->fan_nominal_speed[channel]) + return 0444; + break; default: break; @@ -738,6 +746,25 @@ static int dell_smm_read(struct device *dev, enum hwmon_sensor_types type, u32 a *val = ret; + return 0; + case hwmon_fan_min: + *val = data->fan_nominal_speed[channel][0]; + + return 0; + case hwmon_fan_max: + *val = data->fan_nominal_speed[channel][data->i8k_fan_max]; + + return 0; + case hwmon_fan_target: + ret = i8k_get_fan_status(data, channel); + if (ret < 0) + return ret; + + if (ret > data->i8k_fan_max) + ret = data->i8k_fan_max; + + *val = data->fan_nominal_speed[channel][ret]; + return 0; default: break; @@ -887,9 +914,12 @@ static const struct hwmon_channel_info *dell_smm_info[] = { HWMON_T_INPUT | HWMON_T_LABEL ), HWMON_CHANNEL_INFO(fan, - HWMON_F_INPUT | HWMON_F_LABEL, - HWMON_F_INPUT | HWMON_F_LABEL, - HWMON_F_INPUT | HWMON_F_LABEL + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX | + HWMON_F_TARGET, + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX | + HWMON_F_TARGET, + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX | + HWMON_F_TARGET ), HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE, @@ -908,7 +938,7 @@ static int __init dell_smm_init_hwmon(struct device *dev) { struct dell_smm_data *data = dev_get_drvdata(dev); struct device *dell_smm_hwmon_dev; - int i, err; + int i, state, err; for (i = 0; i < DELL_SMM_NO_TEMP; i++) { data->temp_type[i] = i8k_get_temp_type(i); @@ -924,8 +954,27 @@ static int __init dell_smm_init_hwmon(struct device *dev) err = i8k_get_fan_status(data, i); if (err < 0) err = i8k_get_fan_type(data, i); - if (err >= 0) - data->fan[i] = true; + + if (err < 0) + continue; + + data->fan[i] = true; + data->fan_nominal_speed[i] = devm_kmalloc_array(dev, data->i8k_fan_max + 1, + sizeof(*data->fan_nominal_speed[i]), + GFP_KERNEL); + if (!data->fan_nominal_speed[i]) + continue; + + for (state = 0; state <= data->i8k_fan_max; state++) { + err = i8k_get_fan_nominal_speed(data, i, state); + if (err < 0) { + /* Mark nominal speed table as invalid in case of error */ + devm_kfree(dev, data->fan_nominal_speed[i]); + data->fan_nominal_speed[i] = NULL; + break; + } + data->fan_nominal_speed[i][state] = err; + } } dell_smm_hwmon_dev = devm_hwmon_device_register_with_info(dev, "dell_smm", data, -- cgit v1.2.3