| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * dell-smm-hwmon.c -- Linux driver for accessing the SMM BIOS on Dell laptops. |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 6 | 7 | * Hwmon integration: |
|---|
| 7 | 8 | * Copyright (C) 2011 Jean Delvare <jdelvare@suse.de> |
|---|
| 8 | 9 | * Copyright (C) 2013, 2014 Guenter Roeck <linux@roeck-us.net> |
|---|
| 9 | | - * Copyright (C) 2014, 2015 Pali Rohár <pali.rohar@gmail.com> |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 12 | | - * under the terms of the GNU General Public License as published by the |
|---|
| 13 | | - * Free Software Foundation; either version 2, or (at your option) any |
|---|
| 14 | | - * later version. |
|---|
| 15 | | - * |
|---|
| 16 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 17 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 18 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 19 | | - * General Public License for more details. |
|---|
| 10 | + * Copyright (C) 2014, 2015 Pali Rohár <pali@kernel.org> |
|---|
| 20 | 11 | */ |
|---|
| 21 | 12 | |
|---|
| 22 | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| .. | .. |
|---|
| 77 | 68 | static uint i8k_fan_max = I8K_FAN_HIGH; |
|---|
| 78 | 69 | static bool disallow_fan_type_call; |
|---|
| 79 | 70 | static bool disallow_fan_support; |
|---|
| 71 | +static unsigned int manual_fan; |
|---|
| 72 | +static unsigned int auto_fan; |
|---|
| 80 | 73 | |
|---|
| 81 | 74 | #define I8K_HWMON_HAVE_TEMP1 (1 << 0) |
|---|
| 82 | 75 | #define I8K_HWMON_HAVE_TEMP2 (1 << 1) |
|---|
| 83 | 76 | #define I8K_HWMON_HAVE_TEMP3 (1 << 2) |
|---|
| 84 | 77 | #define I8K_HWMON_HAVE_TEMP4 (1 << 3) |
|---|
| 85 | | -#define I8K_HWMON_HAVE_FAN1 (1 << 4) |
|---|
| 86 | | -#define I8K_HWMON_HAVE_FAN2 (1 << 5) |
|---|
| 87 | | -#define I8K_HWMON_HAVE_FAN3 (1 << 6) |
|---|
| 78 | +#define I8K_HWMON_HAVE_TEMP5 (1 << 4) |
|---|
| 79 | +#define I8K_HWMON_HAVE_TEMP6 (1 << 5) |
|---|
| 80 | +#define I8K_HWMON_HAVE_TEMP7 (1 << 6) |
|---|
| 81 | +#define I8K_HWMON_HAVE_TEMP8 (1 << 7) |
|---|
| 82 | +#define I8K_HWMON_HAVE_TEMP9 (1 << 8) |
|---|
| 83 | +#define I8K_HWMON_HAVE_TEMP10 (1 << 9) |
|---|
| 84 | +#define I8K_HWMON_HAVE_FAN1 (1 << 10) |
|---|
| 85 | +#define I8K_HWMON_HAVE_FAN2 (1 << 11) |
|---|
| 86 | +#define I8K_HWMON_HAVE_FAN3 (1 << 12) |
|---|
| 88 | 87 | |
|---|
| 89 | 88 | MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); |
|---|
| 90 | | -MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>"); |
|---|
| 89 | +MODULE_AUTHOR("Pali Rohár <pali@kernel.org>"); |
|---|
| 91 | 90 | MODULE_DESCRIPTION("Dell laptop SMM BIOS hwmon driver"); |
|---|
| 92 | 91 | MODULE_LICENSE("GPL"); |
|---|
| 93 | 92 | MODULE_ALIAS("i8k"); |
|---|
| .. | .. |
|---|
| 301 | 300 | |
|---|
| 302 | 301 | regs.ebx = (fan & 0xff) | (speed << 8); |
|---|
| 303 | 302 | return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult; |
|---|
| 303 | +} |
|---|
| 304 | + |
|---|
| 305 | +/* |
|---|
| 306 | + * Enable or disable automatic BIOS fan control support |
|---|
| 307 | + */ |
|---|
| 308 | +static int i8k_enable_fan_auto_mode(bool enable) |
|---|
| 309 | +{ |
|---|
| 310 | + struct smm_regs regs = { }; |
|---|
| 311 | + |
|---|
| 312 | + if (disallow_fan_support) |
|---|
| 313 | + return -EINVAL; |
|---|
| 314 | + |
|---|
| 315 | + regs.eax = enable ? auto_fan : manual_fan; |
|---|
| 316 | + return i8k_smm(®s); |
|---|
| 304 | 317 | } |
|---|
| 305 | 318 | |
|---|
| 306 | 319 | /* |
|---|
| .. | .. |
|---|
| 586 | 599 | return single_open(file, i8k_proc_show, NULL); |
|---|
| 587 | 600 | } |
|---|
| 588 | 601 | |
|---|
| 589 | | -static const struct file_operations i8k_fops = { |
|---|
| 590 | | - .owner = THIS_MODULE, |
|---|
| 591 | | - .open = i8k_open_fs, |
|---|
| 592 | | - .read = seq_read, |
|---|
| 593 | | - .llseek = seq_lseek, |
|---|
| 594 | | - .release = single_release, |
|---|
| 595 | | - .unlocked_ioctl = i8k_ioctl, |
|---|
| 602 | +static const struct proc_ops i8k_proc_ops = { |
|---|
| 603 | + .proc_open = i8k_open_fs, |
|---|
| 604 | + .proc_read = seq_read, |
|---|
| 605 | + .proc_lseek = seq_lseek, |
|---|
| 606 | + .proc_release = single_release, |
|---|
| 607 | + .proc_ioctl = i8k_ioctl, |
|---|
| 596 | 608 | }; |
|---|
| 597 | 609 | |
|---|
| 598 | 610 | static struct proc_dir_entry *entry; |
|---|
| .. | .. |
|---|
| 600 | 612 | static void __init i8k_init_procfs(void) |
|---|
| 601 | 613 | { |
|---|
| 602 | 614 | /* Register the proc entry */ |
|---|
| 603 | | - entry = proc_create("i8k", 0, NULL, &i8k_fops); |
|---|
| 615 | + entry = proc_create("i8k", 0, NULL, &i8k_proc_ops); |
|---|
| 604 | 616 | } |
|---|
| 605 | 617 | |
|---|
| 606 | 618 | static void __exit i8k_exit_procfs(void) |
|---|
| .. | .. |
|---|
| 625 | 637 | * Hwmon interface |
|---|
| 626 | 638 | */ |
|---|
| 627 | 639 | |
|---|
| 628 | | -static ssize_t i8k_hwmon_show_temp_label(struct device *dev, |
|---|
| 640 | +static ssize_t i8k_hwmon_temp_label_show(struct device *dev, |
|---|
| 629 | 641 | struct device_attribute *devattr, |
|---|
| 630 | 642 | char *buf) |
|---|
| 631 | 643 | { |
|---|
| .. | .. |
|---|
| 648 | 660 | return sprintf(buf, "%s\n", labels[type]); |
|---|
| 649 | 661 | } |
|---|
| 650 | 662 | |
|---|
| 651 | | -static ssize_t i8k_hwmon_show_temp(struct device *dev, |
|---|
| 663 | +static ssize_t i8k_hwmon_temp_show(struct device *dev, |
|---|
| 652 | 664 | struct device_attribute *devattr, |
|---|
| 653 | 665 | char *buf) |
|---|
| 654 | 666 | { |
|---|
| .. | .. |
|---|
| 661 | 673 | return sprintf(buf, "%d\n", temp * 1000); |
|---|
| 662 | 674 | } |
|---|
| 663 | 675 | |
|---|
| 664 | | -static ssize_t i8k_hwmon_show_fan_label(struct device *dev, |
|---|
| 676 | +static ssize_t i8k_hwmon_fan_label_show(struct device *dev, |
|---|
| 665 | 677 | struct device_attribute *devattr, |
|---|
| 666 | 678 | char *buf) |
|---|
| 667 | 679 | { |
|---|
| .. | .. |
|---|
| 692 | 704 | return sprintf(buf, "%s%s\n", (dock ? "Docking " : ""), labels[type]); |
|---|
| 693 | 705 | } |
|---|
| 694 | 706 | |
|---|
| 695 | | -static ssize_t i8k_hwmon_show_fan(struct device *dev, |
|---|
| 696 | | - struct device_attribute *devattr, |
|---|
| 697 | | - char *buf) |
|---|
| 707 | +static ssize_t i8k_hwmon_fan_show(struct device *dev, |
|---|
| 708 | + struct device_attribute *devattr, char *buf) |
|---|
| 698 | 709 | { |
|---|
| 699 | 710 | int index = to_sensor_dev_attr(devattr)->index; |
|---|
| 700 | 711 | int fan_speed; |
|---|
| .. | .. |
|---|
| 705 | 716 | return sprintf(buf, "%d\n", fan_speed); |
|---|
| 706 | 717 | } |
|---|
| 707 | 718 | |
|---|
| 708 | | -static ssize_t i8k_hwmon_show_pwm(struct device *dev, |
|---|
| 709 | | - struct device_attribute *devattr, |
|---|
| 710 | | - char *buf) |
|---|
| 719 | +static ssize_t i8k_hwmon_pwm_show(struct device *dev, |
|---|
| 720 | + struct device_attribute *devattr, char *buf) |
|---|
| 711 | 721 | { |
|---|
| 712 | 722 | int index = to_sensor_dev_attr(devattr)->index; |
|---|
| 713 | 723 | int status; |
|---|
| .. | .. |
|---|
| 718 | 728 | return sprintf(buf, "%d\n", clamp_val(status * i8k_pwm_mult, 0, 255)); |
|---|
| 719 | 729 | } |
|---|
| 720 | 730 | |
|---|
| 721 | | -static ssize_t i8k_hwmon_set_pwm(struct device *dev, |
|---|
| 722 | | - struct device_attribute *attr, |
|---|
| 723 | | - const char *buf, size_t count) |
|---|
| 731 | +static ssize_t i8k_hwmon_pwm_store(struct device *dev, |
|---|
| 732 | + struct device_attribute *attr, |
|---|
| 733 | + const char *buf, size_t count) |
|---|
| 724 | 734 | { |
|---|
| 725 | 735 | int index = to_sensor_dev_attr(attr)->index; |
|---|
| 726 | 736 | unsigned long val; |
|---|
| .. | .. |
|---|
| 738 | 748 | return err < 0 ? -EIO : count; |
|---|
| 739 | 749 | } |
|---|
| 740 | 750 | |
|---|
| 741 | | -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0); |
|---|
| 742 | | -static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, |
|---|
| 743 | | - 0); |
|---|
| 744 | | -static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1); |
|---|
| 745 | | -static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, |
|---|
| 746 | | - 1); |
|---|
| 747 | | -static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2); |
|---|
| 748 | | -static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, |
|---|
| 749 | | - 2); |
|---|
| 750 | | -static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3); |
|---|
| 751 | | -static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, |
|---|
| 752 | | - 3); |
|---|
| 753 | | -static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 0); |
|---|
| 754 | | -static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, |
|---|
| 755 | | - 0); |
|---|
| 756 | | -static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, |
|---|
| 757 | | - i8k_hwmon_set_pwm, 0); |
|---|
| 758 | | -static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL, |
|---|
| 759 | | - 1); |
|---|
| 760 | | -static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, |
|---|
| 761 | | - 1); |
|---|
| 762 | | -static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, |
|---|
| 763 | | - i8k_hwmon_set_pwm, 1); |
|---|
| 764 | | -static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, i8k_hwmon_show_fan, NULL, |
|---|
| 765 | | - 2); |
|---|
| 766 | | -static SENSOR_DEVICE_ATTR(fan3_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, |
|---|
| 767 | | - 2); |
|---|
| 768 | | -static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, |
|---|
| 769 | | - i8k_hwmon_set_pwm, 2); |
|---|
| 751 | +static ssize_t i8k_hwmon_pwm_enable_store(struct device *dev, |
|---|
| 752 | + struct device_attribute *attr, |
|---|
| 753 | + const char *buf, size_t count) |
|---|
| 754 | +{ |
|---|
| 755 | + int err; |
|---|
| 756 | + bool enable; |
|---|
| 757 | + unsigned long val; |
|---|
| 758 | + |
|---|
| 759 | + if (!auto_fan) |
|---|
| 760 | + return -ENODEV; |
|---|
| 761 | + |
|---|
| 762 | + err = kstrtoul(buf, 10, &val); |
|---|
| 763 | + if (err) |
|---|
| 764 | + return err; |
|---|
| 765 | + |
|---|
| 766 | + if (val == 1) |
|---|
| 767 | + enable = false; |
|---|
| 768 | + else if (val == 2) |
|---|
| 769 | + enable = true; |
|---|
| 770 | + else |
|---|
| 771 | + return -EINVAL; |
|---|
| 772 | + |
|---|
| 773 | + mutex_lock(&i8k_mutex); |
|---|
| 774 | + err = i8k_enable_fan_auto_mode(enable); |
|---|
| 775 | + mutex_unlock(&i8k_mutex); |
|---|
| 776 | + |
|---|
| 777 | + return err ? err : count; |
|---|
| 778 | +} |
|---|
| 779 | + |
|---|
| 780 | +static SENSOR_DEVICE_ATTR_RO(temp1_input, i8k_hwmon_temp, 0); |
|---|
| 781 | +static SENSOR_DEVICE_ATTR_RO(temp1_label, i8k_hwmon_temp_label, 0); |
|---|
| 782 | +static SENSOR_DEVICE_ATTR_RO(temp2_input, i8k_hwmon_temp, 1); |
|---|
| 783 | +static SENSOR_DEVICE_ATTR_RO(temp2_label, i8k_hwmon_temp_label, 1); |
|---|
| 784 | +static SENSOR_DEVICE_ATTR_RO(temp3_input, i8k_hwmon_temp, 2); |
|---|
| 785 | +static SENSOR_DEVICE_ATTR_RO(temp3_label, i8k_hwmon_temp_label, 2); |
|---|
| 786 | +static SENSOR_DEVICE_ATTR_RO(temp4_input, i8k_hwmon_temp, 3); |
|---|
| 787 | +static SENSOR_DEVICE_ATTR_RO(temp4_label, i8k_hwmon_temp_label, 3); |
|---|
| 788 | +static SENSOR_DEVICE_ATTR_RO(temp5_input, i8k_hwmon_temp, 4); |
|---|
| 789 | +static SENSOR_DEVICE_ATTR_RO(temp5_label, i8k_hwmon_temp_label, 4); |
|---|
| 790 | +static SENSOR_DEVICE_ATTR_RO(temp6_input, i8k_hwmon_temp, 5); |
|---|
| 791 | +static SENSOR_DEVICE_ATTR_RO(temp6_label, i8k_hwmon_temp_label, 5); |
|---|
| 792 | +static SENSOR_DEVICE_ATTR_RO(temp7_input, i8k_hwmon_temp, 6); |
|---|
| 793 | +static SENSOR_DEVICE_ATTR_RO(temp7_label, i8k_hwmon_temp_label, 6); |
|---|
| 794 | +static SENSOR_DEVICE_ATTR_RO(temp8_input, i8k_hwmon_temp, 7); |
|---|
| 795 | +static SENSOR_DEVICE_ATTR_RO(temp8_label, i8k_hwmon_temp_label, 7); |
|---|
| 796 | +static SENSOR_DEVICE_ATTR_RO(temp9_input, i8k_hwmon_temp, 8); |
|---|
| 797 | +static SENSOR_DEVICE_ATTR_RO(temp9_label, i8k_hwmon_temp_label, 8); |
|---|
| 798 | +static SENSOR_DEVICE_ATTR_RO(temp10_input, i8k_hwmon_temp, 9); |
|---|
| 799 | +static SENSOR_DEVICE_ATTR_RO(temp10_label, i8k_hwmon_temp_label, 9); |
|---|
| 800 | +static SENSOR_DEVICE_ATTR_RO(fan1_input, i8k_hwmon_fan, 0); |
|---|
| 801 | +static SENSOR_DEVICE_ATTR_RO(fan1_label, i8k_hwmon_fan_label, 0); |
|---|
| 802 | +static SENSOR_DEVICE_ATTR_RW(pwm1, i8k_hwmon_pwm, 0); |
|---|
| 803 | +static SENSOR_DEVICE_ATTR_WO(pwm1_enable, i8k_hwmon_pwm_enable, 0); |
|---|
| 804 | +static SENSOR_DEVICE_ATTR_RO(fan2_input, i8k_hwmon_fan, 1); |
|---|
| 805 | +static SENSOR_DEVICE_ATTR_RO(fan2_label, i8k_hwmon_fan_label, 1); |
|---|
| 806 | +static SENSOR_DEVICE_ATTR_RW(pwm2, i8k_hwmon_pwm, 1); |
|---|
| 807 | +static SENSOR_DEVICE_ATTR_RO(fan3_input, i8k_hwmon_fan, 2); |
|---|
| 808 | +static SENSOR_DEVICE_ATTR_RO(fan3_label, i8k_hwmon_fan_label, 2); |
|---|
| 809 | +static SENSOR_DEVICE_ATTR_RW(pwm3, i8k_hwmon_pwm, 2); |
|---|
| 770 | 810 | |
|---|
| 771 | 811 | static struct attribute *i8k_attrs[] = { |
|---|
| 772 | 812 | &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */ |
|---|
| .. | .. |
|---|
| 777 | 817 | &sensor_dev_attr_temp3_label.dev_attr.attr, /* 5 */ |
|---|
| 778 | 818 | &sensor_dev_attr_temp4_input.dev_attr.attr, /* 6 */ |
|---|
| 779 | 819 | &sensor_dev_attr_temp4_label.dev_attr.attr, /* 7 */ |
|---|
| 780 | | - &sensor_dev_attr_fan1_input.dev_attr.attr, /* 8 */ |
|---|
| 781 | | - &sensor_dev_attr_fan1_label.dev_attr.attr, /* 9 */ |
|---|
| 782 | | - &sensor_dev_attr_pwm1.dev_attr.attr, /* 10 */ |
|---|
| 783 | | - &sensor_dev_attr_fan2_input.dev_attr.attr, /* 11 */ |
|---|
| 784 | | - &sensor_dev_attr_fan2_label.dev_attr.attr, /* 12 */ |
|---|
| 785 | | - &sensor_dev_attr_pwm2.dev_attr.attr, /* 13 */ |
|---|
| 786 | | - &sensor_dev_attr_fan3_input.dev_attr.attr, /* 14 */ |
|---|
| 787 | | - &sensor_dev_attr_fan3_label.dev_attr.attr, /* 15 */ |
|---|
| 788 | | - &sensor_dev_attr_pwm3.dev_attr.attr, /* 16 */ |
|---|
| 820 | + &sensor_dev_attr_temp5_input.dev_attr.attr, /* 8 */ |
|---|
| 821 | + &sensor_dev_attr_temp5_label.dev_attr.attr, /* 9 */ |
|---|
| 822 | + &sensor_dev_attr_temp6_input.dev_attr.attr, /* 10 */ |
|---|
| 823 | + &sensor_dev_attr_temp6_label.dev_attr.attr, /* 11 */ |
|---|
| 824 | + &sensor_dev_attr_temp7_input.dev_attr.attr, /* 12 */ |
|---|
| 825 | + &sensor_dev_attr_temp7_label.dev_attr.attr, /* 13 */ |
|---|
| 826 | + &sensor_dev_attr_temp8_input.dev_attr.attr, /* 14 */ |
|---|
| 827 | + &sensor_dev_attr_temp8_label.dev_attr.attr, /* 15 */ |
|---|
| 828 | + &sensor_dev_attr_temp9_input.dev_attr.attr, /* 16 */ |
|---|
| 829 | + &sensor_dev_attr_temp9_label.dev_attr.attr, /* 17 */ |
|---|
| 830 | + &sensor_dev_attr_temp10_input.dev_attr.attr, /* 18 */ |
|---|
| 831 | + &sensor_dev_attr_temp10_label.dev_attr.attr, /* 19 */ |
|---|
| 832 | + &sensor_dev_attr_fan1_input.dev_attr.attr, /* 20 */ |
|---|
| 833 | + &sensor_dev_attr_fan1_label.dev_attr.attr, /* 21 */ |
|---|
| 834 | + &sensor_dev_attr_pwm1.dev_attr.attr, /* 22 */ |
|---|
| 835 | + &sensor_dev_attr_pwm1_enable.dev_attr.attr, /* 23 */ |
|---|
| 836 | + &sensor_dev_attr_fan2_input.dev_attr.attr, /* 24 */ |
|---|
| 837 | + &sensor_dev_attr_fan2_label.dev_attr.attr, /* 25 */ |
|---|
| 838 | + &sensor_dev_attr_pwm2.dev_attr.attr, /* 26 */ |
|---|
| 839 | + &sensor_dev_attr_fan3_input.dev_attr.attr, /* 27 */ |
|---|
| 840 | + &sensor_dev_attr_fan3_label.dev_attr.attr, /* 28 */ |
|---|
| 841 | + &sensor_dev_attr_pwm3.dev_attr.attr, /* 29 */ |
|---|
| 789 | 842 | NULL |
|---|
| 790 | 843 | }; |
|---|
| 791 | 844 | |
|---|
| 792 | 845 | static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, |
|---|
| 793 | 846 | int index) |
|---|
| 794 | 847 | { |
|---|
| 795 | | - if (disallow_fan_support && index >= 8) |
|---|
| 848 | + if (disallow_fan_support && index >= 20) |
|---|
| 796 | 849 | return 0; |
|---|
| 797 | 850 | if (disallow_fan_type_call && |
|---|
| 798 | | - (index == 9 || index == 12 || index == 15)) |
|---|
| 851 | + (index == 21 || index == 25 || index == 28)) |
|---|
| 799 | 852 | return 0; |
|---|
| 800 | 853 | if (index >= 0 && index <= 1 && |
|---|
| 801 | 854 | !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1)) |
|---|
| .. | .. |
|---|
| 809 | 862 | if (index >= 6 && index <= 7 && |
|---|
| 810 | 863 | !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) |
|---|
| 811 | 864 | return 0; |
|---|
| 812 | | - if (index >= 8 && index <= 10 && |
|---|
| 865 | + if (index >= 8 && index <= 9 && |
|---|
| 866 | + !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP5)) |
|---|
| 867 | + return 0; |
|---|
| 868 | + if (index >= 10 && index <= 11 && |
|---|
| 869 | + !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP6)) |
|---|
| 870 | + return 0; |
|---|
| 871 | + if (index >= 12 && index <= 13 && |
|---|
| 872 | + !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP7)) |
|---|
| 873 | + return 0; |
|---|
| 874 | + if (index >= 14 && index <= 15 && |
|---|
| 875 | + !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP8)) |
|---|
| 876 | + return 0; |
|---|
| 877 | + if (index >= 16 && index <= 17 && |
|---|
| 878 | + !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP9)) |
|---|
| 879 | + return 0; |
|---|
| 880 | + if (index >= 18 && index <= 19 && |
|---|
| 881 | + !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP10)) |
|---|
| 882 | + return 0; |
|---|
| 883 | + |
|---|
| 884 | + if (index >= 20 && index <= 23 && |
|---|
| 813 | 885 | !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) |
|---|
| 814 | 886 | return 0; |
|---|
| 815 | | - if (index >= 11 && index <= 13 && |
|---|
| 887 | + if (index >= 24 && index <= 26 && |
|---|
| 816 | 888 | !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) |
|---|
| 817 | 889 | return 0; |
|---|
| 818 | | - if (index >= 14 && index <= 16 && |
|---|
| 890 | + if (index >= 27 && index <= 29 && |
|---|
| 819 | 891 | !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN3)) |
|---|
| 892 | + return 0; |
|---|
| 893 | + |
|---|
| 894 | + if (index == 23 && !auto_fan) |
|---|
| 820 | 895 | return 0; |
|---|
| 821 | 896 | |
|---|
| 822 | 897 | return attr->mode; |
|---|
| .. | .. |
|---|
| 848 | 923 | err = i8k_get_temp_type(3); |
|---|
| 849 | 924 | if (err >= 0) |
|---|
| 850 | 925 | i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4; |
|---|
| 926 | + err = i8k_get_temp_type(4); |
|---|
| 927 | + if (err >= 0) |
|---|
| 928 | + i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP5; |
|---|
| 929 | + err = i8k_get_temp_type(5); |
|---|
| 930 | + if (err >= 0) |
|---|
| 931 | + i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP6; |
|---|
| 932 | + err = i8k_get_temp_type(6); |
|---|
| 933 | + if (err >= 0) |
|---|
| 934 | + i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP7; |
|---|
| 935 | + err = i8k_get_temp_type(7); |
|---|
| 936 | + if (err >= 0) |
|---|
| 937 | + i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP8; |
|---|
| 938 | + err = i8k_get_temp_type(8); |
|---|
| 939 | + if (err >= 0) |
|---|
| 940 | + i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP9; |
|---|
| 941 | + err = i8k_get_temp_type(9); |
|---|
| 942 | + if (err >= 0) |
|---|
| 943 | + i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP10; |
|---|
| 851 | 944 | |
|---|
| 852 | 945 | /* First fan attributes, if fan status or type is OK */ |
|---|
| 853 | 946 | err = i8k_get_fan_status(0); |
|---|
| .. | .. |
|---|
| 987 | 1080 | }, |
|---|
| 988 | 1081 | }, |
|---|
| 989 | 1082 | { |
|---|
| 990 | | - .ident = "Dell XPS421", |
|---|
| 991 | | - .matches = { |
|---|
| 992 | | - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
|---|
| 993 | | - DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"), |
|---|
| 994 | | - }, |
|---|
| 995 | | - }, |
|---|
| 996 | | - { |
|---|
| 997 | 1083 | .ident = "Dell Studio", |
|---|
| 998 | 1084 | .matches = { |
|---|
| 999 | 1085 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
|---|
| 1000 | 1086 | DMI_MATCH(DMI_PRODUCT_NAME, "Studio"), |
|---|
| 1001 | 1087 | }, |
|---|
| 1002 | 1088 | .driver_data = (void *)&i8k_config_data[DELL_STUDIO], |
|---|
| 1003 | | - }, |
|---|
| 1004 | | - { |
|---|
| 1005 | | - .ident = "Dell XPS 13", |
|---|
| 1006 | | - .matches = { |
|---|
| 1007 | | - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
|---|
| 1008 | | - DMI_MATCH(DMI_PRODUCT_NAME, "XPS13"), |
|---|
| 1009 | | - }, |
|---|
| 1010 | | - .driver_data = (void *)&i8k_config_data[DELL_XPS], |
|---|
| 1011 | 1089 | }, |
|---|
| 1012 | 1090 | { |
|---|
| 1013 | 1091 | .ident = "Dell XPS M140", |
|---|
| .. | .. |
|---|
| 1018 | 1096 | .driver_data = (void *)&i8k_config_data[DELL_XPS], |
|---|
| 1019 | 1097 | }, |
|---|
| 1020 | 1098 | { |
|---|
| 1021 | | - .ident = "Dell XPS 15 9560", |
|---|
| 1099 | + .ident = "Dell XPS", |
|---|
| 1022 | 1100 | .matches = { |
|---|
| 1023 | 1101 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
|---|
| 1024 | | - DMI_MATCH(DMI_PRODUCT_NAME, "XPS 15 9560"), |
|---|
| 1102 | + DMI_MATCH(DMI_PRODUCT_NAME, "XPS"), |
|---|
| 1025 | 1103 | }, |
|---|
| 1026 | 1104 | }, |
|---|
| 1027 | 1105 | { } |
|---|
| .. | .. |
|---|
| 1088 | 1166 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "XPS13 9333"), |
|---|
| 1089 | 1167 | }, |
|---|
| 1090 | 1168 | }, |
|---|
| 1169 | + { |
|---|
| 1170 | + .ident = "Dell XPS 15 L502X", |
|---|
| 1171 | + .matches = { |
|---|
| 1172 | + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
|---|
| 1173 | + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Dell System XPS L502X"), |
|---|
| 1174 | + }, |
|---|
| 1175 | + }, |
|---|
| 1176 | + { } |
|---|
| 1177 | +}; |
|---|
| 1178 | + |
|---|
| 1179 | +struct i8k_fan_control_data { |
|---|
| 1180 | + unsigned int manual_fan; |
|---|
| 1181 | + unsigned int auto_fan; |
|---|
| 1182 | +}; |
|---|
| 1183 | + |
|---|
| 1184 | +enum i8k_fan_controls { |
|---|
| 1185 | + I8K_FAN_34A3_35A3, |
|---|
| 1186 | +}; |
|---|
| 1187 | + |
|---|
| 1188 | +static const struct i8k_fan_control_data i8k_fan_control_data[] = { |
|---|
| 1189 | + [I8K_FAN_34A3_35A3] = { |
|---|
| 1190 | + .manual_fan = 0x34a3, |
|---|
| 1191 | + .auto_fan = 0x35a3, |
|---|
| 1192 | + }, |
|---|
| 1193 | +}; |
|---|
| 1194 | + |
|---|
| 1195 | +static struct dmi_system_id i8k_whitelist_fan_control[] __initdata = { |
|---|
| 1196 | + { |
|---|
| 1197 | + .ident = "Dell Precision 5530", |
|---|
| 1198 | + .matches = { |
|---|
| 1199 | + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
|---|
| 1200 | + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Precision 5530"), |
|---|
| 1201 | + }, |
|---|
| 1202 | + .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3], |
|---|
| 1203 | + }, |
|---|
| 1204 | + { |
|---|
| 1205 | + .ident = "Dell Latitude 5480", |
|---|
| 1206 | + .matches = { |
|---|
| 1207 | + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
|---|
| 1208 | + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Latitude 5480"), |
|---|
| 1209 | + }, |
|---|
| 1210 | + .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3], |
|---|
| 1211 | + }, |
|---|
| 1212 | + { |
|---|
| 1213 | + .ident = "Dell Latitude E6440", |
|---|
| 1214 | + .matches = { |
|---|
| 1215 | + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
|---|
| 1216 | + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Latitude E6440"), |
|---|
| 1217 | + }, |
|---|
| 1218 | + .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3], |
|---|
| 1219 | + }, |
|---|
| 1091 | 1220 | { } |
|---|
| 1092 | 1221 | }; |
|---|
| 1093 | 1222 | |
|---|
| .. | .. |
|---|
| 1096 | 1225 | */ |
|---|
| 1097 | 1226 | static int __init i8k_probe(void) |
|---|
| 1098 | 1227 | { |
|---|
| 1099 | | - const struct dmi_system_id *id; |
|---|
| 1228 | + const struct dmi_system_id *id, *fan_control; |
|---|
| 1100 | 1229 | int fan, ret; |
|---|
| 1101 | 1230 | |
|---|
| 1102 | 1231 | /* |
|---|
| .. | .. |
|---|
| 1156 | 1285 | i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */ |
|---|
| 1157 | 1286 | i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max); |
|---|
| 1158 | 1287 | |
|---|
| 1288 | + fan_control = dmi_first_match(i8k_whitelist_fan_control); |
|---|
| 1289 | + if (fan_control && fan_control->driver_data) { |
|---|
| 1290 | + const struct i8k_fan_control_data *data = fan_control->driver_data; |
|---|
| 1291 | + |
|---|
| 1292 | + manual_fan = data->manual_fan; |
|---|
| 1293 | + auto_fan = data->auto_fan; |
|---|
| 1294 | + pr_info("enabling support for setting automatic/manual fan control\n"); |
|---|
| 1295 | + } |
|---|
| 1296 | + |
|---|
| 1159 | 1297 | if (!fan_mult) { |
|---|
| 1160 | 1298 | /* |
|---|
| 1161 | 1299 | * Autodetect fan multiplier based on nominal rpm |
|---|