Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Guenter Roeck and committed by
Greg Kroah-Hartman
81474fc2 b12ce5f2

+42 -7
+42 -7
drivers/char/i8k.c
··· 65 65 static struct device *i8k_hwmon_dev; 66 66 static u32 i8k_hwmon_flags; 67 67 static int i8k_fan_mult; 68 + static int i8k_pwm_mult; 69 + static int i8k_fan_max = I8K_FAN_HIGH; 68 70 69 71 #define I8K_HWMON_HAVE_TEMP1 (1 << 0) 70 72 #define I8K_HWMON_HAVE_TEMP2 (1 << 1) ··· 98 96 static int fan_mult = I8K_FAN_MULT; 99 97 module_param(fan_mult, int, 0); 100 98 MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with"); 99 + 100 + static int fan_max = I8K_FAN_HIGH; 101 + module_param(fan_max, int, 0); 102 + MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed"); 101 103 102 104 static int i8k_open_fs(struct inode *inode, struct file *file); 103 105 static long i8k_ioctl(struct file *, unsigned int, unsigned long); ··· 280 274 { 281 275 struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, }; 282 276 283 - speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed); 277 + speed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed); 284 278 regs.ebx = (fan & 0xff) | (speed << 8); 285 279 286 280 return i8k_smm(&regs) ? : i8k_get_fan_status(fan); ··· 525 519 status = i8k_get_fan_status(index); 526 520 if (status < 0) 527 521 return -EIO; 528 - return sprintf(buf, "%d\n", clamp_val(status * 128, 0, 255)); 522 + return sprintf(buf, "%d\n", clamp_val(status * i8k_pwm_mult, 0, 255)); 529 523 } 530 524 531 525 static ssize_t i8k_hwmon_set_pwm(struct device *dev, ··· 539 533 err = kstrtoul(buf, 10, &val); 540 534 if (err) 541 535 return err; 542 - val = clamp_val(DIV_ROUND_CLOSEST(val, 128), 0, 2); 536 + val = clamp_val(DIV_ROUND_CLOSEST(val, i8k_pwm_mult), 0, i8k_fan_max); 543 537 544 538 mutex_lock(&i8k_mutex); 545 539 err = i8k_set_fan(index, val); ··· 642 636 return 0; 643 637 } 644 638 639 + struct i8k_config_data { 640 + int fan_mult; 641 + int fan_max; 642 + }; 643 + 644 + enum i8k_configs { 645 + DELL_STUDIO, 646 + DELL_XPS_M140, 647 + }; 648 + 649 + static const struct i8k_config_data i8k_config_data[] = { 650 + [DELL_STUDIO] = { 651 + .fan_mult = 1, 652 + .fan_max = I8K_FAN_HIGH, 653 + }, 654 + [DELL_XPS_M140] = { 655 + .fan_mult = 1, 656 + .fan_max = I8K_FAN_HIGH, 657 + }, 658 + }; 659 + 645 660 static struct dmi_system_id i8k_dmi_table[] __initdata = { 646 661 { 647 662 .ident = "Dell Inspiron", ··· 733 706 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 734 707 DMI_MATCH(DMI_PRODUCT_NAME, "Studio"), 735 708 }, 736 - .driver_data = (void *)1, /* fan multiplier override */ 709 + .driver_data = (void *)&i8k_config_data[DELL_STUDIO], 737 710 }, 738 711 { 739 712 .ident = "Dell XPS M140", ··· 741 714 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 742 715 DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"), 743 716 }, 744 - .driver_data = (void *)1, /* fan multiplier override */ 717 + .driver_data = (void *)&i8k_config_data[DELL_XPS_M140], 745 718 }, 746 719 { } 747 720 }; ··· 781 754 } 782 755 783 756 i8k_fan_mult = fan_mult; 757 + i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */ 784 758 id = dmi_first_match(i8k_dmi_table); 785 - if (id && fan_mult == I8K_FAN_MULT && id->driver_data) 786 - i8k_fan_mult = (unsigned long)id->driver_data; 759 + if (id && id->driver_data) { 760 + const struct i8k_config_data *conf = id->driver_data; 761 + 762 + if (fan_mult == I8K_FAN_MULT && conf->fan_mult) 763 + i8k_fan_mult = conf->fan_mult; 764 + if (fan_max == I8K_FAN_HIGH && conf->fan_max) 765 + i8k_fan_max = conf->fan_max; 766 + } 767 + i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max); 787 768 788 769 return 0; 789 770 }