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: Guenter Roeck <linux@roeck-us.net>
Cc: Andreas Mohr <andi@lisas.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Guenter Roeck 2014-06-21 08:08:10 -07:00 committed by Greg Kroah-Hartman
parent b12ce5f24d
commit 81474fc2fa

View File

@ -65,6 +65,8 @@ static char bios_version[4];
static struct device *i8k_hwmon_dev; static struct device *i8k_hwmon_dev;
static u32 i8k_hwmon_flags; static u32 i8k_hwmon_flags;
static int i8k_fan_mult; 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_TEMP1 (1 << 0)
#define I8K_HWMON_HAVE_TEMP2 (1 << 1) #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_param(fan_mult, int, 0);
MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with"); 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 int i8k_open_fs(struct inode *inode, struct file *file);
static long i8k_ioctl(struct file *, unsigned int, unsigned long); 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, }; 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); regs.ebx = (fan & 0xff) | (speed << 8);
return i8k_smm(&regs) ? : i8k_get_fan_status(fan); 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); status = i8k_get_fan_status(index);
if (status < 0) if (status < 0)
return -EIO; 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, 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); err = kstrtoul(buf, 10, &val);
if (err) if (err)
return 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); mutex_lock(&i8k_mutex);
err = i8k_set_fan(index, val); err = i8k_set_fan(index, val);
@ -636,6 +642,27 @@ static int __init i8k_init_hwmon(void)
return 0; 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 = { static struct dmi_system_id i8k_dmi_table[] __initdata = {
{ {
.ident = "Dell Inspiron", .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_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Studio"), 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", .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_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"), 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_mult = fan_mult;
i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */
id = dmi_first_match(i8k_dmi_table); id = dmi_first_match(i8k_dmi_table);
if (id && fan_mult == I8K_FAN_MULT && id->driver_data) if (id && id->driver_data) {
i8k_fan_mult = (unsigned long)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; return 0;
} }