hc
2023-12-06 08f87f769b595151be1afeff53e144f543faa614
kernel/drivers/hwmon/dell-smm-hwmon.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * dell-smm-hwmon.c -- Linux driver for accessing the SMM BIOS on Dell laptops.
34 *
....@@ -6,17 +7,7 @@
67 * Hwmon integration:
78 * Copyright (C) 2011 Jean Delvare <jdelvare@suse.de>
89 * 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>
2011 */
2112
2213 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
....@@ -77,17 +68,25 @@
7768 static uint i8k_fan_max = I8K_FAN_HIGH;
7869 static bool disallow_fan_type_call;
7970 static bool disallow_fan_support;
71
+static unsigned int manual_fan;
72
+static unsigned int auto_fan;
8073
8174 #define I8K_HWMON_HAVE_TEMP1 (1 << 0)
8275 #define I8K_HWMON_HAVE_TEMP2 (1 << 1)
8376 #define I8K_HWMON_HAVE_TEMP3 (1 << 2)
8477 #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)
8887
8988 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>");
9190 MODULE_DESCRIPTION("Dell laptop SMM BIOS hwmon driver");
9291 MODULE_LICENSE("GPL");
9392 MODULE_ALIAS("i8k");
....@@ -301,6 +300,20 @@
301300
302301 regs.ebx = (fan & 0xff) | (speed << 8);
303302 return i8k_smm(&regs) ? : (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(&regs);
304317 }
305318
306319 /*
....@@ -586,13 +599,12 @@
586599 return single_open(file, i8k_proc_show, NULL);
587600 }
588601
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,
596608 };
597609
598610 static struct proc_dir_entry *entry;
....@@ -600,7 +612,7 @@
600612 static void __init i8k_init_procfs(void)
601613 {
602614 /* Register the proc entry */
603
- entry = proc_create("i8k", 0, NULL, &i8k_fops);
615
+ entry = proc_create("i8k", 0, NULL, &i8k_proc_ops);
604616 }
605617
606618 static void __exit i8k_exit_procfs(void)
....@@ -625,7 +637,7 @@
625637 * Hwmon interface
626638 */
627639
628
-static ssize_t i8k_hwmon_show_temp_label(struct device *dev,
640
+static ssize_t i8k_hwmon_temp_label_show(struct device *dev,
629641 struct device_attribute *devattr,
630642 char *buf)
631643 {
....@@ -648,7 +660,7 @@
648660 return sprintf(buf, "%s\n", labels[type]);
649661 }
650662
651
-static ssize_t i8k_hwmon_show_temp(struct device *dev,
663
+static ssize_t i8k_hwmon_temp_show(struct device *dev,
652664 struct device_attribute *devattr,
653665 char *buf)
654666 {
....@@ -661,7 +673,7 @@
661673 return sprintf(buf, "%d\n", temp * 1000);
662674 }
663675
664
-static ssize_t i8k_hwmon_show_fan_label(struct device *dev,
676
+static ssize_t i8k_hwmon_fan_label_show(struct device *dev,
665677 struct device_attribute *devattr,
666678 char *buf)
667679 {
....@@ -692,9 +704,8 @@
692704 return sprintf(buf, "%s%s\n", (dock ? "Docking " : ""), labels[type]);
693705 }
694706
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)
698709 {
699710 int index = to_sensor_dev_attr(devattr)->index;
700711 int fan_speed;
....@@ -705,9 +716,8 @@
705716 return sprintf(buf, "%d\n", fan_speed);
706717 }
707718
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)
711721 {
712722 int index = to_sensor_dev_attr(devattr)->index;
713723 int status;
....@@ -718,9 +728,9 @@
718728 return sprintf(buf, "%d\n", clamp_val(status * i8k_pwm_mult, 0, 255));
719729 }
720730
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)
724734 {
725735 int index = to_sensor_dev_attr(attr)->index;
726736 unsigned long val;
....@@ -738,35 +748,65 @@
738748 return err < 0 ? -EIO : count;
739749 }
740750
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);
770810
771811 static struct attribute *i8k_attrs[] = {
772812 &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */
....@@ -777,25 +817,38 @@
777817 &sensor_dev_attr_temp3_label.dev_attr.attr, /* 5 */
778818 &sensor_dev_attr_temp4_input.dev_attr.attr, /* 6 */
779819 &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 */
789842 NULL
790843 };
791844
792845 static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
793846 int index)
794847 {
795
- if (disallow_fan_support && index >= 8)
848
+ if (disallow_fan_support && index >= 20)
796849 return 0;
797850 if (disallow_fan_type_call &&
798
- (index == 9 || index == 12 || index == 15))
851
+ (index == 21 || index == 25 || index == 28))
799852 return 0;
800853 if (index >= 0 && index <= 1 &&
801854 !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
....@@ -809,14 +862,36 @@
809862 if (index >= 6 && index <= 7 &&
810863 !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4))
811864 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 &&
813885 !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1))
814886 return 0;
815
- if (index >= 11 && index <= 13 &&
887
+ if (index >= 24 && index <= 26 &&
816888 !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2))
817889 return 0;
818
- if (index >= 14 && index <= 16 &&
890
+ if (index >= 27 && index <= 29 &&
819891 !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN3))
892
+ return 0;
893
+
894
+ if (index == 23 && !auto_fan)
820895 return 0;
821896
822897 return attr->mode;
....@@ -848,6 +923,24 @@
848923 err = i8k_get_temp_type(3);
849924 if (err >= 0)
850925 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;
851944
852945 /* First fan attributes, if fan status or type is OK */
853946 err = i8k_get_fan_status(0);
....@@ -987,27 +1080,12 @@
9871080 },
9881081 },
9891082 {
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
- {
9971083 .ident = "Dell Studio",
9981084 .matches = {
9991085 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
10001086 DMI_MATCH(DMI_PRODUCT_NAME, "Studio"),
10011087 },
10021088 .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],
10111089 },
10121090 {
10131091 .ident = "Dell XPS M140",
....@@ -1018,10 +1096,10 @@
10181096 .driver_data = (void *)&i8k_config_data[DELL_XPS],
10191097 },
10201098 {
1021
- .ident = "Dell XPS 15 9560",
1099
+ .ident = "Dell XPS",
10221100 .matches = {
10231101 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
1024
- DMI_MATCH(DMI_PRODUCT_NAME, "XPS 15 9560"),
1102
+ DMI_MATCH(DMI_PRODUCT_NAME, "XPS"),
10251103 },
10261104 },
10271105 { }
....@@ -1088,6 +1166,57 @@
10881166 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "XPS13 9333"),
10891167 },
10901168 },
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
+ },
10911220 { }
10921221 };
10931222
....@@ -1096,7 +1225,7 @@
10961225 */
10971226 static int __init i8k_probe(void)
10981227 {
1099
- const struct dmi_system_id *id;
1228
+ const struct dmi_system_id *id, *fan_control;
11001229 int fan, ret;
11011230
11021231 /*
....@@ -1156,6 +1285,15 @@
11561285 i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */
11571286 i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max);
11581287
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
+
11591297 if (!fan_mult) {
11601298 /*
11611299 * Autodetect fan multiplier based on nominal rpm