aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2014-06-21 11:08:10 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-07-09 19:41:36 -0400
commit81474fc2fae9397ade2577398e5d03ab2b24af95 (patch)
tree0a2988c0215bb14d12e3a14bcb80767cd5395e5c /drivers/char
parentb12ce5f24da12fbd4d9e903e5f8f5236eae8707a (diff)
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>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/i8k.c49
1 files changed, 42 insertions, 7 deletions
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 3dc1a724ecc2..6a6c085efa69 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -65,6 +65,8 @@ static char bios_version[4];
65static struct device *i8k_hwmon_dev; 65static struct device *i8k_hwmon_dev;
66static u32 i8k_hwmon_flags; 66static u32 i8k_hwmon_flags;
67static int i8k_fan_mult; 67static int i8k_fan_mult;
68static int i8k_pwm_mult;
69static int i8k_fan_max = I8K_FAN_HIGH;
68 70
69#define I8K_HWMON_HAVE_TEMP1 (1 << 0) 71#define I8K_HWMON_HAVE_TEMP1 (1 << 0)
70#define I8K_HWMON_HAVE_TEMP2 (1 << 1) 72#define I8K_HWMON_HAVE_TEMP2 (1 << 1)
@@ -97,6 +99,10 @@ static int fan_mult = I8K_FAN_MULT;
97module_param(fan_mult, int, 0); 99module_param(fan_mult, int, 0);
98MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with"); 100MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with");
99 101
102static int fan_max = I8K_FAN_HIGH;
103module_param(fan_max, int, 0);
104MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed");
105
100static int i8k_open_fs(struct inode *inode, struct file *file); 106static int i8k_open_fs(struct inode *inode, struct file *file);
101static long i8k_ioctl(struct file *, unsigned int, unsigned long); 107static long i8k_ioctl(struct file *, unsigned int, unsigned long);
102 108
@@ -274,7 +280,7 @@ static int i8k_set_fan(int fan, int speed)
274{ 280{
275 struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, }; 281 struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, };
276 282
277 speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed); 283 speed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed);
278 regs.ebx = (fan & 0xff) | (speed << 8); 284 regs.ebx = (fan & 0xff) | (speed << 8);
279 285
280 return i8k_smm(&regs) ? : i8k_get_fan_status(fan); 286 return i8k_smm(&regs) ? : i8k_get_fan_status(fan);
@@ -519,7 +525,7 @@ static ssize_t i8k_hwmon_show_pwm(struct device *dev,
519 status = i8k_get_fan_status(index); 525 status = i8k_get_fan_status(index);
520 if (status < 0) 526 if (status < 0)
521 return -EIO; 527 return -EIO;
522 return sprintf(buf, "%d\n", clamp_val(status * 128, 0, 255)); 528 return sprintf(buf, "%d\n", clamp_val(status * i8k_pwm_mult, 0, 255));
523} 529}
524 530
525static ssize_t i8k_hwmon_set_pwm(struct device *dev, 531static ssize_t i8k_hwmon_set_pwm(struct device *dev,
@@ -533,7 +539,7 @@ static ssize_t i8k_hwmon_set_pwm(struct device *dev,
533 err = kstrtoul(buf, 10, &val); 539 err = kstrtoul(buf, 10, &val);
534 if (err) 540 if (err)
535 return err; 541 return err;
536 val = clamp_val(DIV_ROUND_CLOSEST(val, 128), 0, 2); 542 val = clamp_val(DIV_ROUND_CLOSEST(val, i8k_pwm_mult), 0, i8k_fan_max);
537 543
538 mutex_lock(&i8k_mutex); 544 mutex_lock(&i8k_mutex);
539 err = i8k_set_fan(index, val); 545 err = i8k_set_fan(index, val);
@@ -636,6 +642,27 @@ static int __init i8k_init_hwmon(void)
636 return 0; 642 return 0;
637} 643}
638 644
645struct i8k_config_data {
646 int fan_mult;
647 int fan_max;
648};
649
650enum i8k_configs {
651 DELL_STUDIO,
652 DELL_XPS_M140,
653};
654
655static const struct i8k_config_data i8k_config_data[] = {
656 [DELL_STUDIO] = {
657 .fan_mult = 1,
658 .fan_max = I8K_FAN_HIGH,
659 },
660 [DELL_XPS_M140] = {
661 .fan_mult = 1,
662 .fan_max = I8K_FAN_HIGH,
663 },
664};
665
639static struct dmi_system_id i8k_dmi_table[] __initdata = { 666static struct dmi_system_id i8k_dmi_table[] __initdata = {
640 { 667 {
641 .ident = "Dell Inspiron", 668 .ident = "Dell Inspiron",
@@ -706,7 +733,7 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
706 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 733 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
707 DMI_MATCH(DMI_PRODUCT_NAME, "Studio"), 734 DMI_MATCH(DMI_PRODUCT_NAME, "Studio"),
708 }, 735 },
709 .driver_data = (void *)1, /* fan multiplier override */ 736 .driver_data = (void *)&i8k_config_data[DELL_STUDIO],
710 }, 737 },
711 { 738 {
712 .ident = "Dell XPS M140", 739 .ident = "Dell XPS M140",
@@ -714,7 +741,7 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
714 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 741 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
715 DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"), 742 DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"),
716 }, 743 },
717 .driver_data = (void *)1, /* fan multiplier override */ 744 .driver_data = (void *)&i8k_config_data[DELL_XPS_M140],
718 }, 745 },
719 { } 746 { }
720}; 747};
@@ -754,9 +781,17 @@ static int __init i8k_probe(void)
754 } 781 }
755 782
756 i8k_fan_mult = fan_mult; 783 i8k_fan_mult = fan_mult;
784 i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */
757 id = dmi_first_match(i8k_dmi_table); 785 id = dmi_first_match(i8k_dmi_table);
758 if (id && fan_mult == I8K_FAN_MULT && id->driver_data) 786 if (id && id->driver_data) {
759 i8k_fan_mult = (unsigned long)id->driver_data; 787 const struct i8k_config_data *conf = id->driver_data;
788
789 if (fan_mult == I8K_FAN_MULT && conf->fan_mult)
790 i8k_fan_mult = conf->fan_mult;
791 if (fan_max == I8K_FAN_HIGH && conf->fan_max)
792 i8k_fan_max = conf->fan_max;
793 }
794 i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max);
760 795
761 return 0; 796 return 0;
762} 797}