diff options
author | Jean Delvare <khali@linux-fr.org> | 2006-12-12 12:18:27 -0500 |
---|---|---|
committer | Jean Delvare <khali@arrakis.delvare> | 2006-12-12 12:18:27 -0500 |
commit | 315c7113b5580a5f88169b62f597aacd64ef3717 (patch) | |
tree | 9d5ea8ddd2e471e7a3e8f0fcb64fbe76e44ca338 /drivers/hwmon/f71805f.c | |
parent | e196783d54a75bea05580ce692126532ac54ee24 (diff) |
hwmon/f71805f: Add support for "speed mode" fan speed control
In "speed mode", the user specifies a target fan speed (in RPM) and the
chip automatically adjusts the PWM duty cycle (or DC output level) to
reach this target.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/hwmon/f71805f.c')
-rw-r--r-- | drivers/hwmon/f71805f.c | 50 |
1 files changed, 49 insertions, 1 deletions
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 29a3984af73..975c1cc2acf 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c | |||
@@ -111,6 +111,7 @@ superio_exit(int base) | |||
111 | /* fan nr from 0 to 2 (12-bit values, two registers) */ | 111 | /* fan nr from 0 to 2 (12-bit values, two registers) */ |
112 | #define F71805F_REG_FAN(nr) (0x20 + 2 * (nr)) | 112 | #define F71805F_REG_FAN(nr) (0x20 + 2 * (nr)) |
113 | #define F71805F_REG_FAN_LOW(nr) (0x28 + 2 * (nr)) | 113 | #define F71805F_REG_FAN_LOW(nr) (0x28 + 2 * (nr)) |
114 | #define F71805F_REG_FAN_TARGET(nr) (0x69 + 16 * (nr)) | ||
114 | #define F71805F_REG_FAN_CTRL(nr) (0x60 + 16 * (nr)) | 115 | #define F71805F_REG_FAN_CTRL(nr) (0x60 + 16 * (nr)) |
115 | #define F71805F_REG_PWM_FREQ(nr) (0x63 + 16 * (nr)) | 116 | #define F71805F_REG_PWM_FREQ(nr) (0x63 + 16 * (nr)) |
116 | #define F71805F_REG_PWM_DUTY(nr) (0x6B + 16 * (nr)) | 117 | #define F71805F_REG_PWM_DUTY(nr) (0x6B + 16 * (nr)) |
@@ -127,6 +128,7 @@ superio_exit(int base) | |||
127 | /* individual register bits */ | 128 | /* individual register bits */ |
128 | #define FAN_CTRL_SKIP 0x80 | 129 | #define FAN_CTRL_SKIP 0x80 |
129 | #define FAN_CTRL_DC_MODE 0x10 | 130 | #define FAN_CTRL_DC_MODE 0x10 |
131 | #define FAN_CTRL_LATCH_FULL 0x08 | ||
130 | #define FAN_CTRL_MODE_MASK 0x03 | 132 | #define FAN_CTRL_MODE_MASK 0x03 |
131 | #define FAN_CTRL_MODE_SPEED 0x00 | 133 | #define FAN_CTRL_MODE_SPEED 0x00 |
132 | #define FAN_CTRL_MODE_TEMPERATURE 0x01 | 134 | #define FAN_CTRL_MODE_TEMPERATURE 0x01 |
@@ -153,6 +155,7 @@ struct f71805f_data { | |||
153 | u8 in_low[9]; | 155 | u8 in_low[9]; |
154 | u16 fan[3]; | 156 | u16 fan[3]; |
155 | u16 fan_low[3]; | 157 | u16 fan_low[3]; |
158 | u16 fan_target[3]; | ||
156 | u8 fan_ctrl[3]; | 159 | u8 fan_ctrl[3]; |
157 | u8 pwm[3]; | 160 | u8 pwm[3]; |
158 | u8 pwm_freq[3]; | 161 | u8 pwm_freq[3]; |
@@ -324,6 +327,8 @@ static struct f71805f_data *f71805f_update_device(struct device *dev) | |||
324 | continue; | 327 | continue; |
325 | data->fan_low[nr] = f71805f_read16(data, | 328 | data->fan_low[nr] = f71805f_read16(data, |
326 | F71805F_REG_FAN_LOW(nr)); | 329 | F71805F_REG_FAN_LOW(nr)); |
330 | data->fan_target[nr] = f71805f_read16(data, | ||
331 | F71805F_REG_FAN_TARGET(nr)); | ||
327 | data->pwm_freq[nr] = f71805f_read8(data, | 332 | data->pwm_freq[nr] = f71805f_read8(data, |
328 | F71805F_REG_PWM_FREQ(nr)); | 333 | F71805F_REG_PWM_FREQ(nr)); |
329 | } | 334 | } |
@@ -510,6 +515,16 @@ static ssize_t show_fan_min(struct device *dev, struct device_attribute | |||
510 | return sprintf(buf, "%ld\n", fan_from_reg(data->fan_low[nr])); | 515 | return sprintf(buf, "%ld\n", fan_from_reg(data->fan_low[nr])); |
511 | } | 516 | } |
512 | 517 | ||
518 | static ssize_t show_fan_target(struct device *dev, struct device_attribute | ||
519 | *devattr, char *buf) | ||
520 | { | ||
521 | struct f71805f_data *data = f71805f_update_device(dev); | ||
522 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
523 | int nr = attr->index; | ||
524 | |||
525 | return sprintf(buf, "%ld\n", fan_from_reg(data->fan_target[nr])); | ||
526 | } | ||
527 | |||
513 | static ssize_t set_fan_min(struct device *dev, struct device_attribute | 528 | static ssize_t set_fan_min(struct device *dev, struct device_attribute |
514 | *devattr, const char *buf, size_t count) | 529 | *devattr, const char *buf, size_t count) |
515 | { | 530 | { |
@@ -526,6 +541,23 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute | |||
526 | return count; | 541 | return count; |
527 | } | 542 | } |
528 | 543 | ||
544 | static ssize_t set_fan_target(struct device *dev, struct device_attribute | ||
545 | *devattr, const char *buf, size_t count) | ||
546 | { | ||
547 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
548 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
549 | int nr = attr->index; | ||
550 | long val = simple_strtol(buf, NULL, 10); | ||
551 | |||
552 | mutex_lock(&data->update_lock); | ||
553 | data->fan_target[nr] = fan_to_reg(val); | ||
554 | f71805f_write16(data, F71805F_REG_FAN_TARGET(nr), | ||
555 | data->fan_target[nr]); | ||
556 | mutex_unlock(&data->update_lock); | ||
557 | |||
558 | return count; | ||
559 | } | ||
560 | |||
529 | static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, | 561 | static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, |
530 | char *buf) | 562 | char *buf) |
531 | { | 563 | { |
@@ -822,12 +854,18 @@ static SENSOR_DEVICE_ATTR(in8_min, S_IRUGO | S_IWUSR, | |||
822 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); | 854 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); |
823 | static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR, | 855 | static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR, |
824 | show_fan_min, set_fan_min, 0); | 856 | show_fan_min, set_fan_min, 0); |
857 | static SENSOR_DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, | ||
858 | show_fan_target, set_fan_target, 0); | ||
825 | static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); | 859 | static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); |
826 | static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR, | 860 | static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR, |
827 | show_fan_min, set_fan_min, 1); | 861 | show_fan_min, set_fan_min, 1); |
862 | static SENSOR_DEVICE_ATTR(fan2_target, S_IRUGO | S_IWUSR, | ||
863 | show_fan_target, set_fan_target, 1); | ||
828 | static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); | 864 | static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); |
829 | static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR, | 865 | static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR, |
830 | show_fan_min, set_fan_min, 2); | 866 | show_fan_min, set_fan_min, 2); |
867 | static SENSOR_DEVICE_ATTR(fan3_target, S_IRUGO | S_IWUSR, | ||
868 | show_fan_target, set_fan_target, 2); | ||
831 | 869 | ||
832 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); | 870 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); |
833 | static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, | 871 | static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, |
@@ -956,11 +994,12 @@ static const struct attribute_group f71805f_group = { | |||
956 | .attrs = f71805f_attributes, | 994 | .attrs = f71805f_attributes, |
957 | }; | 995 | }; |
958 | 996 | ||
959 | static struct attribute *f71805f_attributes_fan[3][7] = { | 997 | static struct attribute *f71805f_attributes_fan[3][8] = { |
960 | { | 998 | { |
961 | &sensor_dev_attr_fan1_input.dev_attr.attr, | 999 | &sensor_dev_attr_fan1_input.dev_attr.attr, |
962 | &sensor_dev_attr_fan1_min.dev_attr.attr, | 1000 | &sensor_dev_attr_fan1_min.dev_attr.attr, |
963 | &sensor_dev_attr_fan1_alarm.dev_attr.attr, | 1001 | &sensor_dev_attr_fan1_alarm.dev_attr.attr, |
1002 | &sensor_dev_attr_fan1_target.dev_attr.attr, | ||
964 | &sensor_dev_attr_pwm1.dev_attr.attr, | 1003 | &sensor_dev_attr_pwm1.dev_attr.attr, |
965 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, | 1004 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, |
966 | &sensor_dev_attr_pwm1_mode.dev_attr.attr, | 1005 | &sensor_dev_attr_pwm1_mode.dev_attr.attr, |
@@ -969,6 +1008,7 @@ static struct attribute *f71805f_attributes_fan[3][7] = { | |||
969 | &sensor_dev_attr_fan2_input.dev_attr.attr, | 1008 | &sensor_dev_attr_fan2_input.dev_attr.attr, |
970 | &sensor_dev_attr_fan2_min.dev_attr.attr, | 1009 | &sensor_dev_attr_fan2_min.dev_attr.attr, |
971 | &sensor_dev_attr_fan2_alarm.dev_attr.attr, | 1010 | &sensor_dev_attr_fan2_alarm.dev_attr.attr, |
1011 | &sensor_dev_attr_fan2_target.dev_attr.attr, | ||
972 | &sensor_dev_attr_pwm2.dev_attr.attr, | 1012 | &sensor_dev_attr_pwm2.dev_attr.attr, |
973 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, | 1013 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, |
974 | &sensor_dev_attr_pwm2_mode.dev_attr.attr, | 1014 | &sensor_dev_attr_pwm2_mode.dev_attr.attr, |
@@ -977,6 +1017,7 @@ static struct attribute *f71805f_attributes_fan[3][7] = { | |||
977 | &sensor_dev_attr_fan3_input.dev_attr.attr, | 1017 | &sensor_dev_attr_fan3_input.dev_attr.attr, |
978 | &sensor_dev_attr_fan3_min.dev_attr.attr, | 1018 | &sensor_dev_attr_fan3_min.dev_attr.attr, |
979 | &sensor_dev_attr_fan3_alarm.dev_attr.attr, | 1019 | &sensor_dev_attr_fan3_alarm.dev_attr.attr, |
1020 | &sensor_dev_attr_fan3_target.dev_attr.attr, | ||
980 | &sensor_dev_attr_pwm3.dev_attr.attr, | 1021 | &sensor_dev_attr_pwm3.dev_attr.attr, |
981 | &sensor_dev_attr_pwm3_enable.dev_attr.attr, | 1022 | &sensor_dev_attr_pwm3_enable.dev_attr.attr, |
982 | &sensor_dev_attr_pwm3_mode.dev_attr.attr, | 1023 | &sensor_dev_attr_pwm3_mode.dev_attr.attr, |
@@ -1031,6 +1072,13 @@ static void __devinit f71805f_init_device(struct f71805f_data *data) | |||
1031 | for (i = 0; i < 3; i++) { | 1072 | for (i = 0; i < 3; i++) { |
1032 | data->fan_ctrl[i] = f71805f_read8(data, | 1073 | data->fan_ctrl[i] = f71805f_read8(data, |
1033 | F71805F_REG_FAN_CTRL(i)); | 1074 | F71805F_REG_FAN_CTRL(i)); |
1075 | /* Clear latch full bit, else "speed mode" fan speed control | ||
1076 | doesn't work */ | ||
1077 | if (data->fan_ctrl[i] & FAN_CTRL_LATCH_FULL) { | ||
1078 | data->fan_ctrl[i] &= ~FAN_CTRL_LATCH_FULL; | ||
1079 | f71805f_write8(data, F71805F_REG_FAN_CTRL(i), | ||
1080 | data->fan_ctrl[i]); | ||
1081 | } | ||
1034 | } | 1082 | } |
1035 | } | 1083 | } |
1036 | 1084 | ||