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 | 6e2bc17b0793297b38aef1bba39f2cb634d66208 (patch) | |
tree | a0e1f9391c3347072bbd4eb1ba05fafc1e3b6031 | |
parent | 95e353127dfcd86df56a742a96ccf56369929b95 (diff) |
hwmon/f71805f: Let the user adjust the PWM base frequency
Different frequencies can give better results depending on the exact fan
model used.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
-rw-r--r-- | drivers/hwmon/f71805f.c | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 6e6542036c6a..173e2d2cb49c 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c | |||
@@ -112,6 +112,7 @@ superio_exit(int base) | |||
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_CTRL(nr) (0x60 + 16 * (nr)) | 114 | #define F71805F_REG_FAN_CTRL(nr) (0x60 + 16 * (nr)) |
115 | #define F71805F_REG_PWM_FREQ(nr) (0x63 + 16 * (nr)) | ||
115 | #define F71805F_REG_PWM_DUTY(nr) (0x6B + 16 * (nr)) | 116 | #define F71805F_REG_PWM_DUTY(nr) (0x6B + 16 * (nr)) |
116 | /* temp nr from 0 to 2 (8-bit values) */ | 117 | /* temp nr from 0 to 2 (8-bit values) */ |
117 | #define F71805F_REG_TEMP(nr) (0x1B + (nr)) | 118 | #define F71805F_REG_TEMP(nr) (0x1B + (nr)) |
@@ -153,6 +154,7 @@ struct f71805f_data { | |||
153 | u16 fan_low[3]; | 154 | u16 fan_low[3]; |
154 | u8 fan_ctrl[3]; | 155 | u8 fan_ctrl[3]; |
155 | u8 pwm[3]; | 156 | u8 pwm[3]; |
157 | u8 pwm_freq[3]; | ||
156 | u8 temp[3]; | 158 | u8 temp[3]; |
157 | u8 temp_high[3]; | 159 | u8 temp_high[3]; |
158 | u8 temp_hyst[3]; | 160 | u8 temp_hyst[3]; |
@@ -209,6 +211,28 @@ static inline u16 fan_to_reg(long rpm) | |||
209 | return (1500000 / rpm); | 211 | return (1500000 / rpm); |
210 | } | 212 | } |
211 | 213 | ||
214 | static inline unsigned long pwm_freq_from_reg(u8 reg) | ||
215 | { | ||
216 | unsigned long clock = (reg & 0x80) ? 48000000UL : 1000000UL; | ||
217 | |||
218 | reg &= 0x7f; | ||
219 | if (reg == 0) | ||
220 | reg++; | ||
221 | return clock / (reg << 8); | ||
222 | } | ||
223 | |||
224 | static inline u8 pwm_freq_to_reg(unsigned long val) | ||
225 | { | ||
226 | if (val >= 187500) /* The highest we can do */ | ||
227 | return 0x80; | ||
228 | if (val >= 1475) /* Use 48 MHz clock */ | ||
229 | return 0x80 | (48000000UL / (val << 8)); | ||
230 | if (val < 31) /* The lowest we can do */ | ||
231 | return 0x7f; | ||
232 | else /* Use 1 MHz clock */ | ||
233 | return 1000000UL / (val << 8); | ||
234 | } | ||
235 | |||
212 | static inline long temp_from_reg(u8 reg) | 236 | static inline long temp_from_reg(u8 reg) |
213 | { | 237 | { |
214 | return (reg * 1000); | 238 | return (reg * 1000); |
@@ -294,6 +318,8 @@ static struct f71805f_data *f71805f_update_device(struct device *dev) | |||
294 | continue; | 318 | continue; |
295 | data->fan_low[nr] = f71805f_read16(data, | 319 | data->fan_low[nr] = f71805f_read16(data, |
296 | F71805F_REG_FAN_LOW(nr)); | 320 | F71805F_REG_FAN_LOW(nr)); |
321 | data->pwm_freq[nr] = f71805f_read8(data, | ||
322 | F71805F_REG_PWM_FREQ(nr)); | ||
297 | } | 323 | } |
298 | for (nr = 0; nr < 3; nr++) { | 324 | for (nr = 0; nr < 3; nr++) { |
299 | data->temp_high[nr] = f71805f_read8(data, | 325 | data->temp_high[nr] = f71805f_read8(data, |
@@ -526,6 +552,16 @@ static ssize_t show_pwm_enable(struct device *dev, struct device_attribute | |||
526 | return sprintf(buf, "%d\n", mode); | 552 | return sprintf(buf, "%d\n", mode); |
527 | } | 553 | } |
528 | 554 | ||
555 | static ssize_t show_pwm_freq(struct device *dev, struct device_attribute | ||
556 | *devattr, char *buf) | ||
557 | { | ||
558 | struct f71805f_data *data = f71805f_update_device(dev); | ||
559 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
560 | int nr = attr->index; | ||
561 | |||
562 | return sprintf(buf, "%lu\n", pwm_freq_from_reg(data->pwm_freq[nr])); | ||
563 | } | ||
564 | |||
529 | static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, | 565 | static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, |
530 | const char *buf, size_t count) | 566 | const char *buf, size_t count) |
531 | { | 567 | { |
@@ -592,6 +628,22 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute | |||
592 | return count; | 628 | return count; |
593 | } | 629 | } |
594 | 630 | ||
631 | static ssize_t set_pwm_freq(struct device *dev, struct device_attribute | ||
632 | *devattr, const char *buf, size_t count) | ||
633 | { | ||
634 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
635 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
636 | int nr = attr->index; | ||
637 | unsigned long val = simple_strtoul(buf, NULL, 10); | ||
638 | |||
639 | mutex_lock(&data->update_lock); | ||
640 | data->pwm_freq[nr] = pwm_freq_to_reg(val); | ||
641 | f71805f_write8(data, F71805F_REG_PWM_FREQ(nr), data->pwm_freq[nr]); | ||
642 | mutex_unlock(&data->update_lock); | ||
643 | |||
644 | return count; | ||
645 | } | ||
646 | |||
595 | static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, | 647 | static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, |
596 | char *buf) | 648 | char *buf) |
597 | { | 649 | { |
@@ -785,12 +837,18 @@ static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2); | |||
785 | static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, show_pwm, set_pwm, 0); | 837 | static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, show_pwm, set_pwm, 0); |
786 | static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, | 838 | static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, |
787 | show_pwm_enable, set_pwm_enable, 0); | 839 | show_pwm_enable, set_pwm_enable, 0); |
840 | static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR, | ||
841 | show_pwm_freq, set_pwm_freq, 0); | ||
788 | static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO, show_pwm, set_pwm, 1); | 842 | static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO, show_pwm, set_pwm, 1); |
789 | static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, | 843 | static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, |
790 | show_pwm_enable, set_pwm_enable, 1); | 844 | show_pwm_enable, set_pwm_enable, 1); |
845 | static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO | S_IWUSR, | ||
846 | show_pwm_freq, set_pwm_freq, 1); | ||
791 | static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO, show_pwm, set_pwm, 2); | 847 | static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO, show_pwm, set_pwm, 2); |
792 | static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, | 848 | static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, |
793 | show_pwm_enable, set_pwm_enable, 2); | 849 | show_pwm_enable, set_pwm_enable, 2); |
850 | static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO | S_IWUSR, | ||
851 | show_pwm_freq, set_pwm_freq, 2); | ||
794 | 852 | ||
795 | static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); | 853 | static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); |
796 | static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); | 854 | static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); |
@@ -879,13 +937,14 @@ static const struct attribute_group f71805f_group = { | |||
879 | .attrs = f71805f_attributes, | 937 | .attrs = f71805f_attributes, |
880 | }; | 938 | }; |
881 | 939 | ||
882 | static struct attribute *f71805f_attributes_fan[3][6] = { | 940 | static struct attribute *f71805f_attributes_fan[3][7] = { |
883 | { | 941 | { |
884 | &sensor_dev_attr_fan1_input.dev_attr.attr, | 942 | &sensor_dev_attr_fan1_input.dev_attr.attr, |
885 | &sensor_dev_attr_fan1_min.dev_attr.attr, | 943 | &sensor_dev_attr_fan1_min.dev_attr.attr, |
886 | &sensor_dev_attr_fan1_alarm.dev_attr.attr, | 944 | &sensor_dev_attr_fan1_alarm.dev_attr.attr, |
887 | &sensor_dev_attr_pwm1.dev_attr.attr, | 945 | &sensor_dev_attr_pwm1.dev_attr.attr, |
888 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, | 946 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, |
947 | &sensor_dev_attr_pwm1_freq.dev_attr.attr, | ||
889 | NULL | 948 | NULL |
890 | }, { | 949 | }, { |
891 | &sensor_dev_attr_fan2_input.dev_attr.attr, | 950 | &sensor_dev_attr_fan2_input.dev_attr.attr, |
@@ -893,6 +952,7 @@ static struct attribute *f71805f_attributes_fan[3][6] = { | |||
893 | &sensor_dev_attr_fan2_alarm.dev_attr.attr, | 952 | &sensor_dev_attr_fan2_alarm.dev_attr.attr, |
894 | &sensor_dev_attr_pwm2.dev_attr.attr, | 953 | &sensor_dev_attr_pwm2.dev_attr.attr, |
895 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, | 954 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, |
955 | &sensor_dev_attr_pwm2_freq.dev_attr.attr, | ||
896 | NULL | 956 | NULL |
897 | }, { | 957 | }, { |
898 | &sensor_dev_attr_fan3_input.dev_attr.attr, | 958 | &sensor_dev_attr_fan3_input.dev_attr.attr, |
@@ -900,6 +960,7 @@ static struct attribute *f71805f_attributes_fan[3][6] = { | |||
900 | &sensor_dev_attr_fan3_alarm.dev_attr.attr, | 960 | &sensor_dev_attr_fan3_alarm.dev_attr.attr, |
901 | &sensor_dev_attr_pwm3.dev_attr.attr, | 961 | &sensor_dev_attr_pwm3.dev_attr.attr, |
902 | &sensor_dev_attr_pwm3_enable.dev_attr.attr, | 962 | &sensor_dev_attr_pwm3_enable.dev_attr.attr, |
963 | &sensor_dev_attr_pwm3_freq.dev_attr.attr, | ||
903 | NULL | 964 | NULL |
904 | } | 965 | } |
905 | }; | 966 | }; |