Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 81474fc2 authored by Guenter Roeck's avatar Guenter Roeck Committed by Greg Kroah-Hartman
Browse files

i8k: Add support for configurable maximum fan speed value



Newer Dell systems provide more granular fan speed selection.
Add support for it.

Signed-off-by: default avatarGuenter Roeck <linux@roeck-us.net>
Cc: Andreas Mohr <andi@lisas.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent b12ce5f2
Loading
Loading
Loading
Loading
+42 −7
Original line number Diff line number Diff line
@@ -65,6 +65,8 @@ static char bios_version[4];
static struct device *i8k_hwmon_dev;
static u32 i8k_hwmon_flags;
static int i8k_fan_mult;
static int i8k_pwm_mult;
static int i8k_fan_max = I8K_FAN_HIGH;

#define I8K_HWMON_HAVE_TEMP1	(1 << 0)
#define I8K_HWMON_HAVE_TEMP2	(1 << 1)
@@ -97,6 +99,10 @@ static int fan_mult = I8K_FAN_MULT;
module_param(fan_mult, int, 0);
MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with");

static int fan_max = I8K_FAN_HIGH;
module_param(fan_max, int, 0);
MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed");

static int i8k_open_fs(struct inode *inode, struct file *file);
static long i8k_ioctl(struct file *, unsigned int, unsigned long);

@@ -274,7 +280,7 @@ static int i8k_set_fan(int fan, int speed)
{
	struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, };

	speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed);
	speed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed);
	regs.ebx = (fan & 0xff) | (speed << 8);

	return i8k_smm(&regs) ? : i8k_get_fan_status(fan);
@@ -519,7 +525,7 @@ static ssize_t i8k_hwmon_show_pwm(struct device *dev,
	status = i8k_get_fan_status(index);
	if (status < 0)
		return -EIO;
	return sprintf(buf, "%d\n", clamp_val(status * 128, 0, 255));
	return sprintf(buf, "%d\n", clamp_val(status * i8k_pwm_mult, 0, 255));
}

static ssize_t i8k_hwmon_set_pwm(struct device *dev,
@@ -533,7 +539,7 @@ static ssize_t i8k_hwmon_set_pwm(struct device *dev,
	err = kstrtoul(buf, 10, &val);
	if (err)
		return err;
	val = clamp_val(DIV_ROUND_CLOSEST(val, 128), 0, 2);
	val = clamp_val(DIV_ROUND_CLOSEST(val, i8k_pwm_mult), 0, i8k_fan_max);

	mutex_lock(&i8k_mutex);
	err = i8k_set_fan(index, val);
@@ -636,6 +642,27 @@ static int __init i8k_init_hwmon(void)
	return 0;
}

struct i8k_config_data {
	int fan_mult;
	int fan_max;
};

enum i8k_configs {
	DELL_STUDIO,
	DELL_XPS_M140,
};

static const struct i8k_config_data i8k_config_data[] = {
	[DELL_STUDIO] = {
		.fan_mult = 1,
		.fan_max = I8K_FAN_HIGH,
	},
	[DELL_XPS_M140] = {
		.fan_mult = 1,
		.fan_max = I8K_FAN_HIGH,
	},
};

static struct dmi_system_id i8k_dmi_table[] __initdata = {
	{
		.ident = "Dell Inspiron",
@@ -706,7 +733,7 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "Studio"),
		},
		.driver_data = (void *)1,	/* fan multiplier override */
		.driver_data = (void *)&i8k_config_data[DELL_STUDIO],
	},
	{
		.ident = "Dell XPS M140",
@@ -714,7 +741,7 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"),
		},
		.driver_data = (void *)1,	/* fan multiplier override */
		.driver_data = (void *)&i8k_config_data[DELL_XPS_M140],
	},
	{ }
};
@@ -754,9 +781,17 @@ static int __init i8k_probe(void)
	}

	i8k_fan_mult = fan_mult;
	i8k_fan_max = fan_max ? : I8K_FAN_HIGH;	/* Must not be 0 */
	id = dmi_first_match(i8k_dmi_table);
	if (id && fan_mult == I8K_FAN_MULT && id->driver_data)
		i8k_fan_mult = (unsigned long)id->driver_data;
	if (id && id->driver_data) {
		const struct i8k_config_data *conf = id->driver_data;

		if (fan_mult == I8K_FAN_MULT && conf->fan_mult)
			i8k_fan_mult = conf->fan_mult;
		if (fan_max == I8K_FAN_HIGH && conf->fan_max)
			i8k_fan_max = conf->fan_max;
	}
	i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max);

	return 0;
}