From 151fecfb72a0d602dfe79790602ef64b4e241574 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 19 Feb 2024 01:51:07 +0000
Subject: [PATCH] export RK_PA3
---
kernel/drivers/hwmon/dell-smm-hwmon.c | 330 +++++++++++++++++++++++++++++++++++++++----------------
1 files changed, 234 insertions(+), 96 deletions(-)
diff --git a/kernel/drivers/hwmon/dell-smm-hwmon.c b/kernel/drivers/hwmon/dell-smm-hwmon.c
index a5bca3b..10c7b62 100644
--- a/kernel/drivers/hwmon/dell-smm-hwmon.c
+++ b/kernel/drivers/hwmon/dell-smm-hwmon.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* dell-smm-hwmon.c -- Linux driver for accessing the SMM BIOS on Dell laptops.
*
@@ -6,17 +7,7 @@
* Hwmon integration:
* Copyright (C) 2011 Jean Delvare <jdelvare@suse.de>
* Copyright (C) 2013, 2014 Guenter Roeck <linux@roeck-us.net>
- * Copyright (C) 2014, 2015 Pali Rohár <pali.rohar@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
+ * Copyright (C) 2014, 2015 Pali Rohár <pali@kernel.org>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -77,17 +68,25 @@
static uint i8k_fan_max = I8K_FAN_HIGH;
static bool disallow_fan_type_call;
static bool disallow_fan_support;
+static unsigned int manual_fan;
+static unsigned int auto_fan;
#define I8K_HWMON_HAVE_TEMP1 (1 << 0)
#define I8K_HWMON_HAVE_TEMP2 (1 << 1)
#define I8K_HWMON_HAVE_TEMP3 (1 << 2)
#define I8K_HWMON_HAVE_TEMP4 (1 << 3)
-#define I8K_HWMON_HAVE_FAN1 (1 << 4)
-#define I8K_HWMON_HAVE_FAN2 (1 << 5)
-#define I8K_HWMON_HAVE_FAN3 (1 << 6)
+#define I8K_HWMON_HAVE_TEMP5 (1 << 4)
+#define I8K_HWMON_HAVE_TEMP6 (1 << 5)
+#define I8K_HWMON_HAVE_TEMP7 (1 << 6)
+#define I8K_HWMON_HAVE_TEMP8 (1 << 7)
+#define I8K_HWMON_HAVE_TEMP9 (1 << 8)
+#define I8K_HWMON_HAVE_TEMP10 (1 << 9)
+#define I8K_HWMON_HAVE_FAN1 (1 << 10)
+#define I8K_HWMON_HAVE_FAN2 (1 << 11)
+#define I8K_HWMON_HAVE_FAN3 (1 << 12)
MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
-MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
+MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
MODULE_DESCRIPTION("Dell laptop SMM BIOS hwmon driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("i8k");
@@ -301,6 +300,20 @@
regs.ebx = (fan & 0xff) | (speed << 8);
return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult;
+}
+
+/*
+ * Enable or disable automatic BIOS fan control support
+ */
+static int i8k_enable_fan_auto_mode(bool enable)
+{
+ struct smm_regs regs = { };
+
+ if (disallow_fan_support)
+ return -EINVAL;
+
+ regs.eax = enable ? auto_fan : manual_fan;
+ return i8k_smm(®s);
}
/*
@@ -586,13 +599,12 @@
return single_open(file, i8k_proc_show, NULL);
}
-static const struct file_operations i8k_fops = {
- .owner = THIS_MODULE,
- .open = i8k_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .unlocked_ioctl = i8k_ioctl,
+static const struct proc_ops i8k_proc_ops = {
+ .proc_open = i8k_open_fs,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+ .proc_ioctl = i8k_ioctl,
};
static struct proc_dir_entry *entry;
@@ -600,7 +612,7 @@
static void __init i8k_init_procfs(void)
{
/* Register the proc entry */
- entry = proc_create("i8k", 0, NULL, &i8k_fops);
+ entry = proc_create("i8k", 0, NULL, &i8k_proc_ops);
}
static void __exit i8k_exit_procfs(void)
@@ -625,7 +637,7 @@
* Hwmon interface
*/
-static ssize_t i8k_hwmon_show_temp_label(struct device *dev,
+static ssize_t i8k_hwmon_temp_label_show(struct device *dev,
struct device_attribute *devattr,
char *buf)
{
@@ -648,7 +660,7 @@
return sprintf(buf, "%s\n", labels[type]);
}
-static ssize_t i8k_hwmon_show_temp(struct device *dev,
+static ssize_t i8k_hwmon_temp_show(struct device *dev,
struct device_attribute *devattr,
char *buf)
{
@@ -661,7 +673,7 @@
return sprintf(buf, "%d\n", temp * 1000);
}
-static ssize_t i8k_hwmon_show_fan_label(struct device *dev,
+static ssize_t i8k_hwmon_fan_label_show(struct device *dev,
struct device_attribute *devattr,
char *buf)
{
@@ -692,9 +704,8 @@
return sprintf(buf, "%s%s\n", (dock ? "Docking " : ""), labels[type]);
}
-static ssize_t i8k_hwmon_show_fan(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
+static ssize_t i8k_hwmon_fan_show(struct device *dev,
+ struct device_attribute *devattr, char *buf)
{
int index = to_sensor_dev_attr(devattr)->index;
int fan_speed;
@@ -705,9 +716,8 @@
return sprintf(buf, "%d\n", fan_speed);
}
-static ssize_t i8k_hwmon_show_pwm(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
+static ssize_t i8k_hwmon_pwm_show(struct device *dev,
+ struct device_attribute *devattr, char *buf)
{
int index = to_sensor_dev_attr(devattr)->index;
int status;
@@ -718,9 +728,9 @@
return sprintf(buf, "%d\n", clamp_val(status * i8k_pwm_mult, 0, 255));
}
-static ssize_t i8k_hwmon_set_pwm(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t i8k_hwmon_pwm_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int index = to_sensor_dev_attr(attr)->index;
unsigned long val;
@@ -738,35 +748,65 @@
return err < 0 ? -EIO : count;
}
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
- 0);
-static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
- 1);
-static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
- 2);
-static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3);
-static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
- 3);
-static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 0);
-static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,
- 0);
-static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
- i8k_hwmon_set_pwm, 0);
-static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
- 1);
-static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,
- 1);
-static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
- i8k_hwmon_set_pwm, 1);
-static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
- 2);
-static SENSOR_DEVICE_ATTR(fan3_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,
- 2);
-static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
- i8k_hwmon_set_pwm, 2);
+static ssize_t i8k_hwmon_pwm_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err;
+ bool enable;
+ unsigned long val;
+
+ if (!auto_fan)
+ return -ENODEV;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err)
+ return err;
+
+ if (val == 1)
+ enable = false;
+ else if (val == 2)
+ enable = true;
+ else
+ return -EINVAL;
+
+ mutex_lock(&i8k_mutex);
+ err = i8k_enable_fan_auto_mode(enable);
+ mutex_unlock(&i8k_mutex);
+
+ return err ? err : count;
+}
+
+static SENSOR_DEVICE_ATTR_RO(temp1_input, i8k_hwmon_temp, 0);
+static SENSOR_DEVICE_ATTR_RO(temp1_label, i8k_hwmon_temp_label, 0);
+static SENSOR_DEVICE_ATTR_RO(temp2_input, i8k_hwmon_temp, 1);
+static SENSOR_DEVICE_ATTR_RO(temp2_label, i8k_hwmon_temp_label, 1);
+static SENSOR_DEVICE_ATTR_RO(temp3_input, i8k_hwmon_temp, 2);
+static SENSOR_DEVICE_ATTR_RO(temp3_label, i8k_hwmon_temp_label, 2);
+static SENSOR_DEVICE_ATTR_RO(temp4_input, i8k_hwmon_temp, 3);
+static SENSOR_DEVICE_ATTR_RO(temp4_label, i8k_hwmon_temp_label, 3);
+static SENSOR_DEVICE_ATTR_RO(temp5_input, i8k_hwmon_temp, 4);
+static SENSOR_DEVICE_ATTR_RO(temp5_label, i8k_hwmon_temp_label, 4);
+static SENSOR_DEVICE_ATTR_RO(temp6_input, i8k_hwmon_temp, 5);
+static SENSOR_DEVICE_ATTR_RO(temp6_label, i8k_hwmon_temp_label, 5);
+static SENSOR_DEVICE_ATTR_RO(temp7_input, i8k_hwmon_temp, 6);
+static SENSOR_DEVICE_ATTR_RO(temp7_label, i8k_hwmon_temp_label, 6);
+static SENSOR_DEVICE_ATTR_RO(temp8_input, i8k_hwmon_temp, 7);
+static SENSOR_DEVICE_ATTR_RO(temp8_label, i8k_hwmon_temp_label, 7);
+static SENSOR_DEVICE_ATTR_RO(temp9_input, i8k_hwmon_temp, 8);
+static SENSOR_DEVICE_ATTR_RO(temp9_label, i8k_hwmon_temp_label, 8);
+static SENSOR_DEVICE_ATTR_RO(temp10_input, i8k_hwmon_temp, 9);
+static SENSOR_DEVICE_ATTR_RO(temp10_label, i8k_hwmon_temp_label, 9);
+static SENSOR_DEVICE_ATTR_RO(fan1_input, i8k_hwmon_fan, 0);
+static SENSOR_DEVICE_ATTR_RO(fan1_label, i8k_hwmon_fan_label, 0);
+static SENSOR_DEVICE_ATTR_RW(pwm1, i8k_hwmon_pwm, 0);
+static SENSOR_DEVICE_ATTR_WO(pwm1_enable, i8k_hwmon_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR_RO(fan2_input, i8k_hwmon_fan, 1);
+static SENSOR_DEVICE_ATTR_RO(fan2_label, i8k_hwmon_fan_label, 1);
+static SENSOR_DEVICE_ATTR_RW(pwm2, i8k_hwmon_pwm, 1);
+static SENSOR_DEVICE_ATTR_RO(fan3_input, i8k_hwmon_fan, 2);
+static SENSOR_DEVICE_ATTR_RO(fan3_label, i8k_hwmon_fan_label, 2);
+static SENSOR_DEVICE_ATTR_RW(pwm3, i8k_hwmon_pwm, 2);
static struct attribute *i8k_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */
@@ -777,25 +817,38 @@
&sensor_dev_attr_temp3_label.dev_attr.attr, /* 5 */
&sensor_dev_attr_temp4_input.dev_attr.attr, /* 6 */
&sensor_dev_attr_temp4_label.dev_attr.attr, /* 7 */
- &sensor_dev_attr_fan1_input.dev_attr.attr, /* 8 */
- &sensor_dev_attr_fan1_label.dev_attr.attr, /* 9 */
- &sensor_dev_attr_pwm1.dev_attr.attr, /* 10 */
- &sensor_dev_attr_fan2_input.dev_attr.attr, /* 11 */
- &sensor_dev_attr_fan2_label.dev_attr.attr, /* 12 */
- &sensor_dev_attr_pwm2.dev_attr.attr, /* 13 */
- &sensor_dev_attr_fan3_input.dev_attr.attr, /* 14 */
- &sensor_dev_attr_fan3_label.dev_attr.attr, /* 15 */
- &sensor_dev_attr_pwm3.dev_attr.attr, /* 16 */
+ &sensor_dev_attr_temp5_input.dev_attr.attr, /* 8 */
+ &sensor_dev_attr_temp5_label.dev_attr.attr, /* 9 */
+ &sensor_dev_attr_temp6_input.dev_attr.attr, /* 10 */
+ &sensor_dev_attr_temp6_label.dev_attr.attr, /* 11 */
+ &sensor_dev_attr_temp7_input.dev_attr.attr, /* 12 */
+ &sensor_dev_attr_temp7_label.dev_attr.attr, /* 13 */
+ &sensor_dev_attr_temp8_input.dev_attr.attr, /* 14 */
+ &sensor_dev_attr_temp8_label.dev_attr.attr, /* 15 */
+ &sensor_dev_attr_temp9_input.dev_attr.attr, /* 16 */
+ &sensor_dev_attr_temp9_label.dev_attr.attr, /* 17 */
+ &sensor_dev_attr_temp10_input.dev_attr.attr, /* 18 */
+ &sensor_dev_attr_temp10_label.dev_attr.attr, /* 19 */
+ &sensor_dev_attr_fan1_input.dev_attr.attr, /* 20 */
+ &sensor_dev_attr_fan1_label.dev_attr.attr, /* 21 */
+ &sensor_dev_attr_pwm1.dev_attr.attr, /* 22 */
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr, /* 23 */
+ &sensor_dev_attr_fan2_input.dev_attr.attr, /* 24 */
+ &sensor_dev_attr_fan2_label.dev_attr.attr, /* 25 */
+ &sensor_dev_attr_pwm2.dev_attr.attr, /* 26 */
+ &sensor_dev_attr_fan3_input.dev_attr.attr, /* 27 */
+ &sensor_dev_attr_fan3_label.dev_attr.attr, /* 28 */
+ &sensor_dev_attr_pwm3.dev_attr.attr, /* 29 */
NULL
};
static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
int index)
{
- if (disallow_fan_support && index >= 8)
+ if (disallow_fan_support && index >= 20)
return 0;
if (disallow_fan_type_call &&
- (index == 9 || index == 12 || index == 15))
+ (index == 21 || index == 25 || index == 28))
return 0;
if (index >= 0 && index <= 1 &&
!(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
@@ -809,14 +862,36 @@
if (index >= 6 && index <= 7 &&
!(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4))
return 0;
- if (index >= 8 && index <= 10 &&
+ if (index >= 8 && index <= 9 &&
+ !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP5))
+ return 0;
+ if (index >= 10 && index <= 11 &&
+ !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP6))
+ return 0;
+ if (index >= 12 && index <= 13 &&
+ !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP7))
+ return 0;
+ if (index >= 14 && index <= 15 &&
+ !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP8))
+ return 0;
+ if (index >= 16 && index <= 17 &&
+ !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP9))
+ return 0;
+ if (index >= 18 && index <= 19 &&
+ !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP10))
+ return 0;
+
+ if (index >= 20 && index <= 23 &&
!(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1))
return 0;
- if (index >= 11 && index <= 13 &&
+ if (index >= 24 && index <= 26 &&
!(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2))
return 0;
- if (index >= 14 && index <= 16 &&
+ if (index >= 27 && index <= 29 &&
!(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN3))
+ return 0;
+
+ if (index == 23 && !auto_fan)
return 0;
return attr->mode;
@@ -848,6 +923,24 @@
err = i8k_get_temp_type(3);
if (err >= 0)
i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4;
+ err = i8k_get_temp_type(4);
+ if (err >= 0)
+ i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP5;
+ err = i8k_get_temp_type(5);
+ if (err >= 0)
+ i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP6;
+ err = i8k_get_temp_type(6);
+ if (err >= 0)
+ i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP7;
+ err = i8k_get_temp_type(7);
+ if (err >= 0)
+ i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP8;
+ err = i8k_get_temp_type(8);
+ if (err >= 0)
+ i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP9;
+ err = i8k_get_temp_type(9);
+ if (err >= 0)
+ i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP10;
/* First fan attributes, if fan status or type is OK */
err = i8k_get_fan_status(0);
@@ -987,27 +1080,12 @@
},
},
{
- .ident = "Dell XPS421",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"),
- },
- },
- {
.ident = "Dell Studio",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Studio"),
},
.driver_data = (void *)&i8k_config_data[DELL_STUDIO],
- },
- {
- .ident = "Dell XPS 13",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "XPS13"),
- },
- .driver_data = (void *)&i8k_config_data[DELL_XPS],
},
{
.ident = "Dell XPS M140",
@@ -1018,10 +1096,10 @@
.driver_data = (void *)&i8k_config_data[DELL_XPS],
},
{
- .ident = "Dell XPS 15 9560",
+ .ident = "Dell XPS",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "XPS 15 9560"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "XPS"),
},
},
{ }
@@ -1088,6 +1166,57 @@
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "XPS13 9333"),
},
},
+ {
+ .ident = "Dell XPS 15 L502X",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Dell System XPS L502X"),
+ },
+ },
+ { }
+};
+
+struct i8k_fan_control_data {
+ unsigned int manual_fan;
+ unsigned int auto_fan;
+};
+
+enum i8k_fan_controls {
+ I8K_FAN_34A3_35A3,
+};
+
+static const struct i8k_fan_control_data i8k_fan_control_data[] = {
+ [I8K_FAN_34A3_35A3] = {
+ .manual_fan = 0x34a3,
+ .auto_fan = 0x35a3,
+ },
+};
+
+static struct dmi_system_id i8k_whitelist_fan_control[] __initdata = {
+ {
+ .ident = "Dell Precision 5530",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Precision 5530"),
+ },
+ .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
+ },
+ {
+ .ident = "Dell Latitude 5480",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Latitude 5480"),
+ },
+ .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
+ },
+ {
+ .ident = "Dell Latitude E6440",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Latitude E6440"),
+ },
+ .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
+ },
{ }
};
@@ -1096,7 +1225,7 @@
*/
static int __init i8k_probe(void)
{
- const struct dmi_system_id *id;
+ const struct dmi_system_id *id, *fan_control;
int fan, ret;
/*
@@ -1156,6 +1285,15 @@
i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */
i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max);
+ fan_control = dmi_first_match(i8k_whitelist_fan_control);
+ if (fan_control && fan_control->driver_data) {
+ const struct i8k_fan_control_data *data = fan_control->driver_data;
+
+ manual_fan = data->manual_fan;
+ auto_fan = data->auto_fan;
+ pr_info("enabling support for setting automatic/manual fan control\n");
+ }
+
if (!fan_mult) {
/*
* Autodetect fan multiplier based on nominal rpm
--
Gitblit v1.6.2