diff mbox series

[1/2] hwmon: (dell-smm) Add support for fanX_min, fanX_max and fanX_target

Message ID 20210923165933.24132-2-W_Armin@gmx.de (mailing list archive)
State Superseded
Headers show
Series hwmon: (dell-smm) Support additional attributes | expand

Commit Message

Armin Wolf Sept. 23, 2021, 4:59 p.m. UTC
From: Armin Wolf <W_Armin@gmx.de>

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 <W_Armin@gmx.de>
---
 drivers/hwmon/dell-smm-hwmon.c | 52 ++++++++++++++++++++++++++++++----
 1 file changed, 47 insertions(+), 5 deletions(-)

--
2.20.1
diff mbox series

Patch

diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
index 774c1b0715d9..a10503a9f80a 100644
--- a/drivers/hwmon/dell-smm-hwmon.c
+++ b/drivers/hwmon/dell-smm-hwmon.c
@@ -76,6 +76,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][I8K_FAN_MAX + 1];
 };

 MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
@@ -673,6 +674,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[channel] && data->fan_nominal_speed[channel][0] != INT_MIN)
+				return 0444;
+
 			break;
 		default:
 			break;
@@ -740,6 +748,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;
@@ -889,9 +916,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,
@@ -910,7 +940,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);
@@ -926,8 +956,20 @@  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)
+
+		if (err >= 0) {
 			data->fan[i] = true;
+			for (state = 0; state <= data->i8k_fan_max; state++) {
+				err = i8k_get_fan_nominal_speed(data, i, state);
+				if (err < 0)
+					break;
+
+				data->fan_nominal_speed[i][state] = err;
+			}
+			/* Mark nominal speed table as invalid in case of error */
+			if (state <= data->i8k_fan_max)
+				data->fan_nominal_speed[i][0] = INT_MIN;
+		}
 	}

 	dell_smm_hwmon_dev = devm_hwmon_device_register_with_info(dev, "dell_smm", data,