.. | .. |
---|
| 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 |
---|