diff options
author | Guenter Roeck <linux@roeck-us.net> | 2014-06-21 11:08:10 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-07-09 19:41:36 -0400 |
commit | 81474fc2fae9397ade2577398e5d03ab2b24af95 (patch) | |
tree | 0a2988c0215bb14d12e3a14bcb80767cd5395e5c /drivers/char | |
parent | b12ce5f24da12fbd4d9e903e5f8f5236eae8707a (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.c | 49 |
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]; | |||
65 | static struct device *i8k_hwmon_dev; | 65 | static struct device *i8k_hwmon_dev; |
66 | static u32 i8k_hwmon_flags; | 66 | static u32 i8k_hwmon_flags; |
67 | static int i8k_fan_mult; | 67 | static int i8k_fan_mult; |
68 | static int i8k_pwm_mult; | ||
69 | static 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; | |||
97 | module_param(fan_mult, int, 0); | 99 | module_param(fan_mult, int, 0); |
98 | MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with"); | 100 | MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with"); |
99 | 101 | ||
102 | static int fan_max = I8K_FAN_HIGH; | ||
103 | module_param(fan_max, int, 0); | ||
104 | MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed"); | ||
105 | |||
100 | static int i8k_open_fs(struct inode *inode, struct file *file); | 106 | static int i8k_open_fs(struct inode *inode, struct file *file); |
101 | static long i8k_ioctl(struct file *, unsigned int, unsigned long); | 107 | static 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(®s) ? : i8k_get_fan_status(fan); | 286 | return i8k_smm(®s) ? : 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 | ||
525 | static ssize_t i8k_hwmon_set_pwm(struct device *dev, | 531 | static 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 | ||
645 | struct i8k_config_data { | ||
646 | int fan_mult; | ||
647 | int fan_max; | ||
648 | }; | ||
649 | |||
650 | enum i8k_configs { | ||
651 | DELL_STUDIO, | ||
652 | DELL_XPS_M140, | ||
653 | }; | ||
654 | |||
655 | static 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 | |||
639 | static struct dmi_system_id i8k_dmi_table[] __initdata = { | 666 | static 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 | } |