diff options
author | Phil Endecott <kernel@chezphil.org> | 2007-06-29 03:19:14 -0400 |
---|---|---|
committer | Mark M. Hoffman <mhoffman@lightlink.com> | 2007-07-19 14:22:15 -0400 |
commit | aba5073d3f4c928c89c483d85f8cff7cc9aa3312 (patch) | |
tree | c966ca4de6e14d4edbb7232b3dcef3fb7e114b7f | |
parent | 158ce07564b68d4215b9560213a089d6f7c5a4ea (diff) |
hwmon/f71805f: Add temperature-tracking fan control mode
Add support for the "temperature mode" fan speed control. In this mode,
the user can define 3 temperature/speed trip points, and the chip will
set the speed automatically according to the temperature changes.
Signed-off-by: Phil Endecott <kernel@chezphil.org>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Mark M. Hoffman <mhoffman@lightlink.com>
-rw-r--r-- | Documentation/hwmon/f71805f | 35 | ||||
-rw-r--r-- | drivers/hwmon/f71805f.c | 167 |
2 files changed, 188 insertions, 14 deletions
diff --git a/Documentation/hwmon/f71805f b/Documentation/hwmon/f71805f index bfd0f154959c..94e0d2cbd3d2 100644 --- a/Documentation/hwmon/f71805f +++ b/Documentation/hwmon/f71805f | |||
@@ -5,11 +5,11 @@ Supported chips: | |||
5 | * Fintek F71805F/FG | 5 | * Fintek F71805F/FG |
6 | Prefix: 'f71805f' | 6 | Prefix: 'f71805f' |
7 | Addresses scanned: none, address read from Super I/O config space | 7 | Addresses scanned: none, address read from Super I/O config space |
8 | Datasheet: Provided by Fintek on request | 8 | Datasheet: Available from the Fintek website |
9 | * Fintek F71872F/FG | 9 | * Fintek F71872F/FG |
10 | Prefix: 'f71872f' | 10 | Prefix: 'f71872f' |
11 | Addresses scanned: none, address read from Super I/O config space | 11 | Addresses scanned: none, address read from Super I/O config space |
12 | Datasheet: Provided by Fintek on request | 12 | Datasheet: Available from the Fintek website |
13 | 13 | ||
14 | Author: Jean Delvare <khali@linux-fr.org> | 14 | Author: Jean Delvare <khali@linux-fr.org> |
15 | 15 | ||
@@ -128,7 +128,9 @@ it. | |||
128 | When the PWM method is used, you can select the operating frequency, | 128 | When the PWM method is used, you can select the operating frequency, |
129 | from 187.5 kHz (default) to 31 Hz. The best frequency depends on the | 129 | from 187.5 kHz (default) to 31 Hz. The best frequency depends on the |
130 | fan model. As a rule of thumb, lower frequencies seem to give better | 130 | fan model. As a rule of thumb, lower frequencies seem to give better |
131 | control, but may generate annoying high-pitch noise. Fintek recommends | 131 | control, but may generate annoying high-pitch noise. So a frequency just |
132 | above the audible range, such as 25 kHz, may be a good choice; if this | ||
133 | doesn't give you good linear control, try reducing it. Fintek recommends | ||
132 | not going below 1 kHz, as the fan tachometers get confused by lower | 134 | not going below 1 kHz, as the fan tachometers get confused by lower |
133 | frequencies as well. | 135 | frequencies as well. |
134 | 136 | ||
@@ -136,16 +138,23 @@ When the DC method is used, Fintek recommends not going below 5 V, which | |||
136 | corresponds to a pwm value of 106 for the driver. The driver doesn't | 138 | corresponds to a pwm value of 106 for the driver. The driver doesn't |
137 | enforce this limit though. | 139 | enforce this limit though. |
138 | 140 | ||
139 | Three different fan control modes are supported: | 141 | Three different fan control modes are supported; the mode number is written |
142 | to the pwm<n>_enable file. | ||
140 | 143 | ||
141 | * Manual mode | 144 | * 1: Manual mode |
142 | You ask for a specific PWM duty cycle or DC voltage. | 145 | You ask for a specific PWM duty cycle or DC voltage by writing to the |
146 | pwm<n> file. | ||
143 | 147 | ||
144 | * Fan speed mode | 148 | * 2: Temperature mode |
145 | You ask for a specific fan speed. This mode assumes that pwm1 | 149 | You define 3 temperature/fan speed trip points using the |
146 | corresponds to fan1, pwm2 to fan2 and pwm3 to fan3. | 150 | pwm<n>_auto_point<m>_temp and _fan files. These define a staircase |
151 | relationship between temperature and fan speed with two additional points | ||
152 | interpolated between the values that you define. When the temperature | ||
153 | is below auto_point1_temp the fan is switched off. | ||
147 | 154 | ||
148 | * Temperature mode | 155 | * 3: Fan speed mode |
149 | You define 3 temperature/fan speed trip points, and the fan speed is | 156 | You ask for a specific fan speed by writing to the fan<n>_target file. |
150 | adjusted depending on the measured temperature, using interpolation. | 157 | |
151 | This mode is not yet supported by the driver. | 158 | Both of the automatic modes require that pwm1 corresponds to fan1, pwm2 to |
159 | fan2 and pwm3 to fan3. Temperature mode also requires that temp1 corresponds | ||
160 | to pwm1 and fan1, etc. | ||
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 8fe4d70d8f51..6f60715f34f8 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c | |||
@@ -127,6 +127,13 @@ superio_exit(int base) | |||
127 | #define F71805F_REG_TEMP_HIGH(nr) (0x54 + 2 * (nr)) | 127 | #define F71805F_REG_TEMP_HIGH(nr) (0x54 + 2 * (nr)) |
128 | #define F71805F_REG_TEMP_HYST(nr) (0x55 + 2 * (nr)) | 128 | #define F71805F_REG_TEMP_HYST(nr) (0x55 + 2 * (nr)) |
129 | #define F71805F_REG_TEMP_MODE 0x01 | 129 | #define F71805F_REG_TEMP_MODE 0x01 |
130 | /* pwm/fan pwmnr from 0 to 2, auto point apnr from 0 to 2 */ | ||
131 | /* map Fintek numbers to our numbers as follows: 9->0, 5->1, 1->2 */ | ||
132 | #define F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr) \ | ||
133 | (0xA0 + 0x10 * (pwmnr) + (2 - (apnr))) | ||
134 | #define F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr) \ | ||
135 | (0xA4 + 0x10 * (pwmnr) + \ | ||
136 | 2 * (2 - (apnr))) | ||
130 | 137 | ||
131 | #define F71805F_REG_START 0x00 | 138 | #define F71805F_REG_START 0x00 |
132 | /* status nr from 0 to 2 */ | 139 | /* status nr from 0 to 2 */ |
@@ -144,6 +151,11 @@ superio_exit(int base) | |||
144 | * Data structures and manipulation thereof | 151 | * Data structures and manipulation thereof |
145 | */ | 152 | */ |
146 | 153 | ||
154 | struct f71805f_auto_point { | ||
155 | u8 temp[3]; | ||
156 | u16 fan[3]; | ||
157 | }; | ||
158 | |||
147 | struct f71805f_data { | 159 | struct f71805f_data { |
148 | unsigned short addr; | 160 | unsigned short addr; |
149 | const char *name; | 161 | const char *name; |
@@ -170,6 +182,7 @@ struct f71805f_data { | |||
170 | u8 temp_hyst[3]; | 182 | u8 temp_hyst[3]; |
171 | u8 temp_mode; | 183 | u8 temp_mode; |
172 | unsigned long alarms; | 184 | unsigned long alarms; |
185 | struct f71805f_auto_point auto_points[3]; | ||
173 | }; | 186 | }; |
174 | 187 | ||
175 | struct f71805f_sio_data { | 188 | struct f71805f_sio_data { |
@@ -312,7 +325,7 @@ static void f71805f_write16(struct f71805f_data *data, u8 reg, u16 val) | |||
312 | static struct f71805f_data *f71805f_update_device(struct device *dev) | 325 | static struct f71805f_data *f71805f_update_device(struct device *dev) |
313 | { | 326 | { |
314 | struct f71805f_data *data = dev_get_drvdata(dev); | 327 | struct f71805f_data *data = dev_get_drvdata(dev); |
315 | int nr; | 328 | int nr, apnr; |
316 | 329 | ||
317 | mutex_lock(&data->update_lock); | 330 | mutex_lock(&data->update_lock); |
318 | 331 | ||
@@ -342,6 +355,18 @@ static struct f71805f_data *f71805f_update_device(struct device *dev) | |||
342 | F71805F_REG_TEMP_HYST(nr)); | 355 | F71805F_REG_TEMP_HYST(nr)); |
343 | } | 356 | } |
344 | data->temp_mode = f71805f_read8(data, F71805F_REG_TEMP_MODE); | 357 | data->temp_mode = f71805f_read8(data, F71805F_REG_TEMP_MODE); |
358 | for (nr = 0; nr < 3; nr++) { | ||
359 | for (apnr = 0; apnr < 3; apnr++) { | ||
360 | data->auto_points[nr].temp[apnr] = | ||
361 | f71805f_read8(data, | ||
362 | F71805F_REG_PWM_AUTO_POINT_TEMP(nr, | ||
363 | apnr)); | ||
364 | data->auto_points[nr].fan[apnr] = | ||
365 | f71805f_read16(data, | ||
366 | F71805F_REG_PWM_AUTO_POINT_FAN(nr, | ||
367 | apnr)); | ||
368 | } | ||
369 | } | ||
345 | 370 | ||
346 | data->last_limits = jiffies; | 371 | data->last_limits = jiffies; |
347 | } | 372 | } |
@@ -705,6 +730,70 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute | |||
705 | return count; | 730 | return count; |
706 | } | 731 | } |
707 | 732 | ||
733 | static ssize_t show_pwm_auto_point_temp(struct device *dev, | ||
734 | struct device_attribute *devattr, | ||
735 | char* buf) | ||
736 | { | ||
737 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
738 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
739 | int pwmnr = attr->nr; | ||
740 | int apnr = attr->index; | ||
741 | |||
742 | return sprintf(buf, "%ld\n", | ||
743 | temp_from_reg(data->auto_points[pwmnr].temp[apnr])); | ||
744 | } | ||
745 | |||
746 | static ssize_t set_pwm_auto_point_temp(struct device *dev, | ||
747 | struct device_attribute *devattr, | ||
748 | const char* buf, size_t count) | ||
749 | { | ||
750 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
751 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
752 | int pwmnr = attr->nr; | ||
753 | int apnr = attr->index; | ||
754 | unsigned long val = simple_strtol(buf, NULL, 10); | ||
755 | |||
756 | mutex_lock(&data->update_lock); | ||
757 | data->auto_points[pwmnr].temp[apnr] = temp_to_reg(val); | ||
758 | f71805f_write8(data, F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr), | ||
759 | data->auto_points[pwmnr].temp[apnr]); | ||
760 | mutex_unlock(&data->update_lock); | ||
761 | |||
762 | return count; | ||
763 | } | ||
764 | |||
765 | static ssize_t show_pwm_auto_point_fan(struct device *dev, | ||
766 | struct device_attribute *devattr, | ||
767 | char* buf) | ||
768 | { | ||
769 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
770 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
771 | int pwmnr = attr->nr; | ||
772 | int apnr = attr->index; | ||
773 | |||
774 | return sprintf(buf, "%ld\n", | ||
775 | fan_from_reg(data->auto_points[pwmnr].fan[apnr])); | ||
776 | } | ||
777 | |||
778 | static ssize_t set_pwm_auto_point_fan(struct device *dev, | ||
779 | struct device_attribute *devattr, | ||
780 | const char* buf, size_t count) | ||
781 | { | ||
782 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
783 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
784 | int pwmnr = attr->nr; | ||
785 | int apnr = attr->index; | ||
786 | unsigned long val = simple_strtoul(buf, NULL, 10); | ||
787 | |||
788 | mutex_lock(&data->update_lock); | ||
789 | data->auto_points[pwmnr].fan[apnr] = fan_to_reg(val); | ||
790 | f71805f_write16(data, F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr), | ||
791 | data->auto_points[pwmnr].fan[apnr]); | ||
792 | mutex_unlock(&data->update_lock); | ||
793 | |||
794 | return count; | ||
795 | } | ||
796 | |||
708 | static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, | 797 | static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, |
709 | char *buf) | 798 | char *buf) |
710 | { | 799 | { |
@@ -932,6 +1021,63 @@ static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO | S_IWUSR, | |||
932 | show_pwm_freq, set_pwm_freq, 2); | 1021 | show_pwm_freq, set_pwm_freq, 2); |
933 | static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2); | 1022 | static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2); |
934 | 1023 | ||
1024 | static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR, | ||
1025 | show_pwm_auto_point_temp, set_pwm_auto_point_temp, | ||
1026 | 0, 0); | ||
1027 | static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_fan, S_IRUGO | S_IWUSR, | ||
1028 | show_pwm_auto_point_fan, set_pwm_auto_point_fan, | ||
1029 | 0, 0); | ||
1030 | static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR, | ||
1031 | show_pwm_auto_point_temp, set_pwm_auto_point_temp, | ||
1032 | 0, 1); | ||
1033 | static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_fan, S_IRUGO | S_IWUSR, | ||
1034 | show_pwm_auto_point_fan, set_pwm_auto_point_fan, | ||
1035 | 0, 1); | ||
1036 | static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR, | ||
1037 | show_pwm_auto_point_temp, set_pwm_auto_point_temp, | ||
1038 | 0, 2); | ||
1039 | static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_fan, S_IRUGO | S_IWUSR, | ||
1040 | show_pwm_auto_point_fan, set_pwm_auto_point_fan, | ||
1041 | 0, 2); | ||
1042 | |||
1043 | static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR, | ||
1044 | show_pwm_auto_point_temp, set_pwm_auto_point_temp, | ||
1045 | 1, 0); | ||
1046 | static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_fan, S_IRUGO | S_IWUSR, | ||
1047 | show_pwm_auto_point_fan, set_pwm_auto_point_fan, | ||
1048 | 1, 0); | ||
1049 | static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR, | ||
1050 | show_pwm_auto_point_temp, set_pwm_auto_point_temp, | ||
1051 | 1, 1); | ||
1052 | static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_fan, S_IRUGO | S_IWUSR, | ||
1053 | show_pwm_auto_point_fan, set_pwm_auto_point_fan, | ||
1054 | 1, 1); | ||
1055 | static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR, | ||
1056 | show_pwm_auto_point_temp, set_pwm_auto_point_temp, | ||
1057 | 1, 2); | ||
1058 | static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_fan, S_IRUGO | S_IWUSR, | ||
1059 | show_pwm_auto_point_fan, set_pwm_auto_point_fan, | ||
1060 | 1, 2); | ||
1061 | |||
1062 | static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR, | ||
1063 | show_pwm_auto_point_temp, set_pwm_auto_point_temp, | ||
1064 | 2, 0); | ||
1065 | static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_fan, S_IRUGO | S_IWUSR, | ||
1066 | show_pwm_auto_point_fan, set_pwm_auto_point_fan, | ||
1067 | 2, 0); | ||
1068 | static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR, | ||
1069 | show_pwm_auto_point_temp, set_pwm_auto_point_temp, | ||
1070 | 2, 1); | ||
1071 | static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_fan, S_IRUGO | S_IWUSR, | ||
1072 | show_pwm_auto_point_fan, set_pwm_auto_point_fan, | ||
1073 | 2, 1); | ||
1074 | static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR, | ||
1075 | show_pwm_auto_point_temp, set_pwm_auto_point_temp, | ||
1076 | 2, 2); | ||
1077 | static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_fan, S_IRUGO | S_IWUSR, | ||
1078 | show_pwm_auto_point_fan, set_pwm_auto_point_fan, | ||
1079 | 2, 2); | ||
1080 | |||
935 | static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); | 1081 | static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); |
936 | static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); | 1082 | static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); |
937 | static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); | 1083 | static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); |
@@ -1014,6 +1160,25 @@ static struct attribute *f71805f_attributes[] = { | |||
1014 | &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, | 1160 | &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, |
1015 | &sensor_dev_attr_temp3_type.dev_attr.attr, | 1161 | &sensor_dev_attr_temp3_type.dev_attr.attr, |
1016 | 1162 | ||
1163 | &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, | ||
1164 | &sensor_dev_attr_pwm1_auto_point1_fan.dev_attr.attr, | ||
1165 | &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, | ||
1166 | &sensor_dev_attr_pwm1_auto_point2_fan.dev_attr.attr, | ||
1167 | &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, | ||
1168 | &sensor_dev_attr_pwm1_auto_point3_fan.dev_attr.attr, | ||
1169 | &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr, | ||
1170 | &sensor_dev_attr_pwm2_auto_point1_fan.dev_attr.attr, | ||
1171 | &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr, | ||
1172 | &sensor_dev_attr_pwm2_auto_point2_fan.dev_attr.attr, | ||
1173 | &sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr, | ||
1174 | &sensor_dev_attr_pwm2_auto_point3_fan.dev_attr.attr, | ||
1175 | &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr, | ||
1176 | &sensor_dev_attr_pwm3_auto_point1_fan.dev_attr.attr, | ||
1177 | &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr, | ||
1178 | &sensor_dev_attr_pwm3_auto_point2_fan.dev_attr.attr, | ||
1179 | &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr, | ||
1180 | &sensor_dev_attr_pwm3_auto_point3_fan.dev_attr.attr, | ||
1181 | |||
1017 | &sensor_dev_attr_in0_alarm.dev_attr.attr, | 1182 | &sensor_dev_attr_in0_alarm.dev_attr.attr, |
1018 | &sensor_dev_attr_in1_alarm.dev_attr.attr, | 1183 | &sensor_dev_attr_in1_alarm.dev_attr.attr, |
1019 | &sensor_dev_attr_in2_alarm.dev_attr.attr, | 1184 | &sensor_dev_attr_in2_alarm.dev_attr.attr, |