Commit b1986c8e authored by Armin Wolf's avatar Armin Wolf Committed by Guenter Roeck
Browse files

hwmon: (dell-smm) Add support for fanX_min, fanX_max and fanX_target



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: default avatarArmin Wolf <W_Armin@gmx.de>
Reviewed-by: default avatarPali Rohár <pali@kernel.org>
Link: https://lore.kernel.org/r/20210926221044.14327-2-W_Armin@gmx.de


Signed-off-by: default avatarGuenter Roeck <linux@roeck-us.net>
parent 51369c0f
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -34,6 +34,9 @@ Name Perm Description
=============================== ======= =======================================
fan[1-3]_input                  RO      Fan speed in RPM.
fan[1-3]_label                  RO      Fan label.
fan[1-3]_min                    RO      Minimal Fan speed in RPM
fan[1-3]_max                    RO      Maximal Fan speed in RPM
fan[1-3]_target                 RO      Expected Fan speed in RPM
pwm[1-3]                        RW      Control the fan PWM duty-cycle.
pwm1_enable                     WO      Enable or disable automatic BIOS fan
                                        control (not supported on all laptops,
+55 −6
Original line number Diff line number Diff line
@@ -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)

		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,