diff options
author | Rudolf Marek <r.marek@sh.cvut.cz> | 2006-07-05 12:14:31 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-09-28 18:31:12 -0400 |
commit | 08c79950a047dbaccf05d70a203db2ee75ac3bd8 (patch) | |
tree | 4041fdd9899cde225c4ff64e3feadf1955bd8a77 | |
parent | 94c12cc7d196bab34aaa98d38521549fa1e5ef76 (diff) |
hwmon: Add fan speed control features to w83627ehf
This patch adds long-awaited support for automatic fan modes. Based on
the work of Yuan Mu from Winbond, I finished the support with the great
help of David Hubbard.
Signed-off-by: Yuan Mu <Ymu@Winbond.com.tw>
Signed-off-by: Rudolf Marek <r.marek@sh.cvut.cz>
Signed-off-by: David Hubbard <david.c.hubbard@gmail.com>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/hwmon/w83627ehf.c | 393 |
1 files changed, 382 insertions, 11 deletions
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index b21d6b9d7eac..23824183e02f 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c | |||
@@ -2,6 +2,8 @@ | |||
2 | w83627ehf - Driver for the hardware monitoring functionality of | 2 | w83627ehf - Driver for the hardware monitoring functionality of |
3 | the Winbond W83627EHF Super-I/O chip | 3 | the Winbond W83627EHF Super-I/O chip |
4 | Copyright (C) 2005 Jean Delvare <khali@linux-fr.org> | 4 | Copyright (C) 2005 Jean Delvare <khali@linux-fr.org> |
5 | Copyright (C) 2006 Yuan Mu <Ymu@Winbond.com.tw>, | ||
6 | Rudolf Marek <r.marek@sh.cvut.cz> | ||
5 | 7 | ||
6 | Shamelessly ripped from the w83627hf driver | 8 | Shamelessly ripped from the w83627hf driver |
7 | Copyright (C) 2003 Mark Studebaker | 9 | Copyright (C) 2003 Mark Studebaker |
@@ -29,8 +31,8 @@ | |||
29 | 31 | ||
30 | Supports the following chips: | 32 | Supports the following chips: |
31 | 33 | ||
32 | Chip #vin #fan #pwm #temp chip_id man_id | 34 | Chip #vin #fan #pwm #temp chip_id man_id |
33 | w83627ehf 10 5 - 3 0x88 0x5ca3 | 35 | w83627ehf 10 5 4 3 0x88,0xa1 0x5ca3 |
34 | */ | 36 | */ |
35 | 37 | ||
36 | #include <linux/module.h> | 38 | #include <linux/module.h> |
@@ -145,10 +147,44 @@ static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 }; | |||
145 | #define W83627EHF_REG_ALARM2 0x45A | 147 | #define W83627EHF_REG_ALARM2 0x45A |
146 | #define W83627EHF_REG_ALARM3 0x45B | 148 | #define W83627EHF_REG_ALARM3 0x45B |
147 | 149 | ||
150 | /* SmartFan registers */ | ||
151 | /* DC or PWM output fan configuration */ | ||
152 | static const u8 W83627EHF_REG_PWM_ENABLE[] = { | ||
153 | 0x04, /* SYS FAN0 output mode and PWM mode */ | ||
154 | 0x04, /* CPU FAN0 output mode and PWM mode */ | ||
155 | 0x12, /* AUX FAN mode */ | ||
156 | 0x62, /* CPU fan1 mode */ | ||
157 | }; | ||
158 | |||
159 | static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 }; | ||
160 | static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 }; | ||
161 | |||
162 | /* FAN Duty Cycle, be used to control */ | ||
163 | static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 }; | ||
164 | static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 }; | ||
165 | static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 }; | ||
166 | |||
167 | |||
168 | /* Advanced Fan control, some values are common for all fans */ | ||
169 | static const u8 W83627EHF_REG_FAN_MIN_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 }; | ||
170 | static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0C, 0x0D, 0x17, 0x66 }; | ||
171 | |||
148 | /* | 172 | /* |
149 | * Conversions | 173 | * Conversions |
150 | */ | 174 | */ |
151 | 175 | ||
176 | /* 1 is PWM mode, output in ms */ | ||
177 | static inline unsigned int step_time_from_reg(u8 reg, u8 mode) | ||
178 | { | ||
179 | return mode ? 100 * reg : 400 * reg; | ||
180 | } | ||
181 | |||
182 | static inline u8 step_time_to_reg(unsigned int msec, u8 mode) | ||
183 | { | ||
184 | return SENSORS_LIMIT((mode ? (msec + 50) / 100 : | ||
185 | (msec + 200) / 400), 1, 255); | ||
186 | } | ||
187 | |||
152 | static inline unsigned int | 188 | static inline unsigned int |
153 | fan_from_reg(u8 reg, unsigned int div) | 189 | fan_from_reg(u8 reg, unsigned int div) |
154 | { | 190 | { |
@@ -170,12 +206,12 @@ temp1_from_reg(s8 reg) | |||
170 | } | 206 | } |
171 | 207 | ||
172 | static inline s8 | 208 | static inline s8 |
173 | temp1_to_reg(int temp) | 209 | temp1_to_reg(int temp, int min, int max) |
174 | { | 210 | { |
175 | if (temp <= -128000) | 211 | if (temp <= min) |
176 | return -128; | 212 | return min / 1000; |
177 | if (temp >= 127000) | 213 | if (temp >= max) |
178 | return 127; | 214 | return max / 1000; |
179 | if (temp < 0) | 215 | if (temp < 0) |
180 | return (temp - 500) / 1000; | 216 | return (temp - 500) / 1000; |
181 | return (temp + 500) / 1000; | 217 | return (temp + 500) / 1000; |
@@ -223,6 +259,16 @@ struct w83627ehf_data { | |||
223 | s16 temp_max[2]; | 259 | s16 temp_max[2]; |
224 | s16 temp_max_hyst[2]; | 260 | s16 temp_max_hyst[2]; |
225 | u32 alarms; | 261 | u32 alarms; |
262 | |||
263 | u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ | ||
264 | u8 pwm_enable[4]; /* 1->manual | ||
265 | 2->thermal cruise (also called SmartFan I) */ | ||
266 | u8 pwm[4]; | ||
267 | u8 target_temp[4]; | ||
268 | u8 tolerance[4]; | ||
269 | |||
270 | u8 fan_min_output[4]; /* minimum fan speed */ | ||
271 | u8 fan_stop_time[4]; | ||
226 | }; | 272 | }; |
227 | 273 | ||
228 | static inline int is_word_sized(u16 reg) | 274 | static inline int is_word_sized(u16 reg) |
@@ -349,6 +395,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | |||
349 | { | 395 | { |
350 | struct i2c_client *client = to_i2c_client(dev); | 396 | struct i2c_client *client = to_i2c_client(dev); |
351 | struct w83627ehf_data *data = i2c_get_clientdata(client); | 397 | struct w83627ehf_data *data = i2c_get_clientdata(client); |
398 | int pwmcfg = 0, tolerance = 0; /* shut up the compiler */ | ||
352 | int i; | 399 | int i; |
353 | 400 | ||
354 | mutex_lock(&data->update_lock); | 401 | mutex_lock(&data->update_lock); |
@@ -416,6 +463,34 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | |||
416 | } | 463 | } |
417 | } | 464 | } |
418 | 465 | ||
466 | for (i = 0; i < 4; i++) { | ||
467 | /* pwmcfg, tolarance mapped for i=0, i=1 to same reg */ | ||
468 | if (i != 1) { | ||
469 | pwmcfg = w83627ehf_read_value(client, | ||
470 | W83627EHF_REG_PWM_ENABLE[i]); | ||
471 | tolerance = w83627ehf_read_value(client, | ||
472 | W83627EHF_REG_TOLERANCE[i]); | ||
473 | } | ||
474 | data->pwm_mode[i] = | ||
475 | ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) | ||
476 | ? 0 : 1; | ||
477 | data->pwm_enable[i] = | ||
478 | ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i]) | ||
479 | & 3) + 1; | ||
480 | data->pwm[i] = w83627ehf_read_value(client, | ||
481 | W83627EHF_REG_PWM[i]); | ||
482 | data->fan_min_output[i] = w83627ehf_read_value(client, | ||
483 | W83627EHF_REG_FAN_MIN_OUTPUT[i]); | ||
484 | data->fan_stop_time[i] = w83627ehf_read_value(client, | ||
485 | W83627EHF_REG_FAN_STOP_TIME[i]); | ||
486 | data->target_temp[i] = | ||
487 | w83627ehf_read_value(client, | ||
488 | W83627EHF_REG_TARGET[i]) & | ||
489 | (data->pwm_mode[i] == 1 ? 0x7f : 0xff); | ||
490 | data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0)) | ||
491 | & 0x0f; | ||
492 | } | ||
493 | |||
419 | /* Measured temperatures and limits */ | 494 | /* Measured temperatures and limits */ |
420 | data->temp1 = w83627ehf_read_value(client, | 495 | data->temp1 = w83627ehf_read_value(client, |
421 | W83627EHF_REG_TEMP1); | 496 | W83627EHF_REG_TEMP1); |
@@ -711,7 +786,7 @@ store_temp1_##reg(struct device *dev, struct device_attribute *attr, \ | |||
711 | u32 val = simple_strtoul(buf, NULL, 10); \ | 786 | u32 val = simple_strtoul(buf, NULL, 10); \ |
712 | \ | 787 | \ |
713 | mutex_lock(&data->update_lock); \ | 788 | mutex_lock(&data->update_lock); \ |
714 | data->temp1_##reg = temp1_to_reg(val); \ | 789 | data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \ |
715 | w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \ | 790 | w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \ |
716 | data->temp1_##reg); \ | 791 | data->temp1_##reg); \ |
717 | mutex_unlock(&data->update_lock); \ | 792 | mutex_unlock(&data->update_lock); \ |
@@ -777,6 +852,281 @@ static struct sensor_device_attribute sda_temp[] = { | |||
777 | SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), | 852 | SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), |
778 | }; | 853 | }; |
779 | 854 | ||
855 | #define show_pwm_reg(reg) \ | ||
856 | static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \ | ||
857 | char *buf) \ | ||
858 | { \ | ||
859 | struct w83627ehf_data *data = w83627ehf_update_device(dev); \ | ||
860 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ | ||
861 | int nr = sensor_attr->index; \ | ||
862 | return sprintf(buf, "%d\n", data->reg[nr]); \ | ||
863 | } | ||
864 | |||
865 | show_pwm_reg(pwm_mode) | ||
866 | show_pwm_reg(pwm_enable) | ||
867 | show_pwm_reg(pwm) | ||
868 | |||
869 | static ssize_t | ||
870 | store_pwm_mode(struct device *dev, struct device_attribute *attr, | ||
871 | const char *buf, size_t count) | ||
872 | { | ||
873 | struct i2c_client *client = to_i2c_client(dev); | ||
874 | struct w83627ehf_data *data = i2c_get_clientdata(client); | ||
875 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
876 | int nr = sensor_attr->index; | ||
877 | u32 val = simple_strtoul(buf, NULL, 10); | ||
878 | u16 reg; | ||
879 | |||
880 | if (val > 1) | ||
881 | return -EINVAL; | ||
882 | mutex_lock(&data->update_lock); | ||
883 | reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]); | ||
884 | data->pwm_mode[nr] = val; | ||
885 | reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]); | ||
886 | if (!val) | ||
887 | reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr]; | ||
888 | w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg); | ||
889 | mutex_unlock(&data->update_lock); | ||
890 | return count; | ||
891 | } | ||
892 | |||
893 | static ssize_t | ||
894 | store_pwm(struct device *dev, struct device_attribute *attr, | ||
895 | const char *buf, size_t count) | ||
896 | { | ||
897 | struct i2c_client *client = to_i2c_client(dev); | ||
898 | struct w83627ehf_data *data = i2c_get_clientdata(client); | ||
899 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
900 | int nr = sensor_attr->index; | ||
901 | u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255); | ||
902 | |||
903 | mutex_lock(&data->update_lock); | ||
904 | data->pwm[nr] = val; | ||
905 | w83627ehf_write_value(client, W83627EHF_REG_PWM[nr], val); | ||
906 | mutex_unlock(&data->update_lock); | ||
907 | return count; | ||
908 | } | ||
909 | |||
910 | static ssize_t | ||
911 | store_pwm_enable(struct device *dev, struct device_attribute *attr, | ||
912 | const char *buf, size_t count) | ||
913 | { | ||
914 | struct i2c_client *client = to_i2c_client(dev); | ||
915 | struct w83627ehf_data *data = i2c_get_clientdata(client); | ||
916 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
917 | int nr = sensor_attr->index; | ||
918 | u32 val = simple_strtoul(buf, NULL, 10); | ||
919 | u16 reg; | ||
920 | |||
921 | if (!val || (val > 2)) /* only modes 1 and 2 are supported */ | ||
922 | return -EINVAL; | ||
923 | mutex_lock(&data->update_lock); | ||
924 | reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]); | ||
925 | data->pwm_enable[nr] = val; | ||
926 | reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]); | ||
927 | reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr]; | ||
928 | w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg); | ||
929 | mutex_unlock(&data->update_lock); | ||
930 | return count; | ||
931 | } | ||
932 | |||
933 | |||
934 | #define show_tol_temp(reg) \ | ||
935 | static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ | ||
936 | char *buf) \ | ||
937 | { \ | ||
938 | struct w83627ehf_data *data = w83627ehf_update_device(dev); \ | ||
939 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ | ||
940 | int nr = sensor_attr->index; \ | ||
941 | return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \ | ||
942 | } | ||
943 | |||
944 | show_tol_temp(tolerance) | ||
945 | show_tol_temp(target_temp) | ||
946 | |||
947 | static ssize_t | ||
948 | store_target_temp(struct device *dev, struct device_attribute *attr, | ||
949 | const char *buf, size_t count) | ||
950 | { | ||
951 | struct i2c_client *client = to_i2c_client(dev); | ||
952 | struct w83627ehf_data *data = i2c_get_clientdata(client); | ||
953 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
954 | int nr = sensor_attr->index; | ||
955 | u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000); | ||
956 | |||
957 | mutex_lock(&data->update_lock); | ||
958 | data->target_temp[nr] = val; | ||
959 | w83627ehf_write_value(client, W83627EHF_REG_TARGET[nr], val); | ||
960 | mutex_unlock(&data->update_lock); | ||
961 | return count; | ||
962 | } | ||
963 | |||
964 | static ssize_t | ||
965 | store_tolerance(struct device *dev, struct device_attribute *attr, | ||
966 | const char *buf, size_t count) | ||
967 | { | ||
968 | struct i2c_client *client = to_i2c_client(dev); | ||
969 | struct w83627ehf_data *data = i2c_get_clientdata(client); | ||
970 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
971 | int nr = sensor_attr->index; | ||
972 | u16 reg; | ||
973 | /* Limit the temp to 0C - 15C */ | ||
974 | u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000); | ||
975 | |||
976 | mutex_lock(&data->update_lock); | ||
977 | reg = w83627ehf_read_value(client, W83627EHF_REG_TOLERANCE[nr]); | ||
978 | data->tolerance[nr] = val; | ||
979 | if (nr == 1) | ||
980 | reg = (reg & 0x0f) | (val << 4); | ||
981 | else | ||
982 | reg = (reg & 0xf0) | val; | ||
983 | w83627ehf_write_value(client, W83627EHF_REG_TOLERANCE[nr], reg); | ||
984 | mutex_unlock(&data->update_lock); | ||
985 | return count; | ||
986 | } | ||
987 | |||
988 | static struct sensor_device_attribute sda_pwm[] = { | ||
989 | SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0), | ||
990 | SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1), | ||
991 | SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2), | ||
992 | SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3), | ||
993 | }; | ||
994 | |||
995 | static struct sensor_device_attribute sda_pwm_mode[] = { | ||
996 | SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode, | ||
997 | store_pwm_mode, 0), | ||
998 | SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode, | ||
999 | store_pwm_mode, 1), | ||
1000 | SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode, | ||
1001 | store_pwm_mode, 2), | ||
1002 | SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode, | ||
1003 | store_pwm_mode, 3), | ||
1004 | }; | ||
1005 | |||
1006 | static struct sensor_device_attribute sda_pwm_enable[] = { | ||
1007 | SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable, | ||
1008 | store_pwm_enable, 0), | ||
1009 | SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable, | ||
1010 | store_pwm_enable, 1), | ||
1011 | SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable, | ||
1012 | store_pwm_enable, 2), | ||
1013 | SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable, | ||
1014 | store_pwm_enable, 3), | ||
1015 | }; | ||
1016 | |||
1017 | static struct sensor_device_attribute sda_target_temp[] = { | ||
1018 | SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp, | ||
1019 | store_target_temp, 0), | ||
1020 | SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp, | ||
1021 | store_target_temp, 1), | ||
1022 | SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp, | ||
1023 | store_target_temp, 2), | ||
1024 | SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp, | ||
1025 | store_target_temp, 3), | ||
1026 | }; | ||
1027 | |||
1028 | static struct sensor_device_attribute sda_tolerance[] = { | ||
1029 | SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance, | ||
1030 | store_tolerance, 0), | ||
1031 | SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance, | ||
1032 | store_tolerance, 1), | ||
1033 | SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance, | ||
1034 | store_tolerance, 2), | ||
1035 | SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance, | ||
1036 | store_tolerance, 3), | ||
1037 | }; | ||
1038 | |||
1039 | static void device_create_file_pwm(struct device *dev, int i) | ||
1040 | { | ||
1041 | device_create_file(dev, &sda_pwm[i].dev_attr); | ||
1042 | device_create_file(dev, &sda_pwm_mode[i].dev_attr); | ||
1043 | device_create_file(dev, &sda_pwm_enable[i].dev_attr); | ||
1044 | device_create_file(dev, &sda_target_temp[i].dev_attr); | ||
1045 | device_create_file(dev, &sda_tolerance[i].dev_attr); | ||
1046 | } | ||
1047 | |||
1048 | /* Smart Fan registers */ | ||
1049 | |||
1050 | #define fan_functions(reg, REG) \ | ||
1051 | static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ | ||
1052 | char *buf) \ | ||
1053 | { \ | ||
1054 | struct w83627ehf_data *data = w83627ehf_update_device(dev); \ | ||
1055 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ | ||
1056 | int nr = sensor_attr->index; \ | ||
1057 | return sprintf(buf, "%d\n", data->reg[nr]); \ | ||
1058 | }\ | ||
1059 | static ssize_t \ | ||
1060 | store_##reg(struct device *dev, struct device_attribute *attr, \ | ||
1061 | const char *buf, size_t count) \ | ||
1062 | {\ | ||
1063 | struct i2c_client *client = to_i2c_client(dev); \ | ||
1064 | struct w83627ehf_data *data = i2c_get_clientdata(client); \ | ||
1065 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ | ||
1066 | int nr = sensor_attr->index; \ | ||
1067 | u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \ | ||
1068 | mutex_lock(&data->update_lock); \ | ||
1069 | data->reg[nr] = val; \ | ||
1070 | w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \ | ||
1071 | mutex_unlock(&data->update_lock); \ | ||
1072 | return count; \ | ||
1073 | } | ||
1074 | |||
1075 | fan_functions(fan_min_output, FAN_MIN_OUTPUT) | ||
1076 | |||
1077 | #define fan_time_functions(reg, REG) \ | ||
1078 | static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ | ||
1079 | char *buf) \ | ||
1080 | { \ | ||
1081 | struct w83627ehf_data *data = w83627ehf_update_device(dev); \ | ||
1082 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ | ||
1083 | int nr = sensor_attr->index; \ | ||
1084 | return sprintf(buf, "%d\n", \ | ||
1085 | step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \ | ||
1086 | } \ | ||
1087 | \ | ||
1088 | static ssize_t \ | ||
1089 | store_##reg(struct device *dev, struct device_attribute *attr, \ | ||
1090 | const char *buf, size_t count) \ | ||
1091 | { \ | ||
1092 | struct i2c_client *client = to_i2c_client(dev); \ | ||
1093 | struct w83627ehf_data *data = i2c_get_clientdata(client); \ | ||
1094 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ | ||
1095 | int nr = sensor_attr->index; \ | ||
1096 | u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \ | ||
1097 | data->pwm_mode[nr]); \ | ||
1098 | mutex_lock(&data->update_lock); \ | ||
1099 | data->reg[nr] = val; \ | ||
1100 | w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \ | ||
1101 | mutex_unlock(&data->update_lock); \ | ||
1102 | return count; \ | ||
1103 | } \ | ||
1104 | |||
1105 | fan_time_functions(fan_stop_time, FAN_STOP_TIME) | ||
1106 | |||
1107 | |||
1108 | static struct sensor_device_attribute sda_sf3_arrays_fan4[] = { | ||
1109 | SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, | ||
1110 | store_fan_stop_time, 3), | ||
1111 | SENSOR_ATTR(pwm4_min_output, S_IWUSR | S_IRUGO, show_fan_min_output, | ||
1112 | store_fan_min_output, 3), | ||
1113 | }; | ||
1114 | |||
1115 | static struct sensor_device_attribute sda_sf3_arrays[] = { | ||
1116 | SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, | ||
1117 | store_fan_stop_time, 0), | ||
1118 | SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, | ||
1119 | store_fan_stop_time, 1), | ||
1120 | SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, | ||
1121 | store_fan_stop_time, 2), | ||
1122 | SENSOR_ATTR(pwm1_min_output, S_IWUSR | S_IRUGO, show_fan_min_output, | ||
1123 | store_fan_min_output, 0), | ||
1124 | SENSOR_ATTR(pwm2_min_output, S_IWUSR | S_IRUGO, show_fan_min_output, | ||
1125 | store_fan_min_output, 1), | ||
1126 | SENSOR_ATTR(pwm3_min_output, S_IWUSR | S_IRUGO, show_fan_min_output, | ||
1127 | store_fan_min_output, 2), | ||
1128 | }; | ||
1129 | |||
780 | /* | 1130 | /* |
781 | * Driver and client management | 1131 | * Driver and client management |
782 | */ | 1132 | */ |
@@ -810,6 +1160,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) | |||
810 | struct i2c_client *client; | 1160 | struct i2c_client *client; |
811 | struct w83627ehf_data *data; | 1161 | struct w83627ehf_data *data; |
812 | struct device *dev; | 1162 | struct device *dev; |
1163 | u8 fan4pin, fan5pin; | ||
813 | int i, err = 0; | 1164 | int i, err = 0; |
814 | 1165 | ||
815 | if (!request_region(address + REGION_OFFSET, REGION_LENGTH, | 1166 | if (!request_region(address + REGION_OFFSET, REGION_LENGTH, |
@@ -848,13 +1199,21 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) | |||
848 | data->fan_min[i] = w83627ehf_read_value(client, | 1199 | data->fan_min[i] = w83627ehf_read_value(client, |
849 | W83627EHF_REG_FAN_MIN[i]); | 1200 | W83627EHF_REG_FAN_MIN[i]); |
850 | 1201 | ||
1202 | /* fan4 and fan5 share some pins with the GPIO and serial flash */ | ||
1203 | |||
1204 | superio_enter(); | ||
1205 | fan5pin = superio_inb(0x24) & 0x2; | ||
1206 | fan4pin = superio_inb(0x29) & 0x6; | ||
1207 | superio_exit(); | ||
1208 | |||
851 | /* It looks like fan4 and fan5 pins can be alternatively used | 1209 | /* It looks like fan4 and fan5 pins can be alternatively used |
852 | as fan on/off switches */ | 1210 | as fan on/off switches */ |
1211 | |||
853 | data->has_fan = 0x07; /* fan1, fan2 and fan3 */ | 1212 | data->has_fan = 0x07; /* fan1, fan2 and fan3 */ |
854 | i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); | 1213 | i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); |
855 | if (i & (1 << 2)) | 1214 | if ((i & (1 << 2)) && (!fan4pin)) |
856 | data->has_fan |= (1 << 3); | 1215 | data->has_fan |= (1 << 3); |
857 | if (i & (1 << 0)) | 1216 | if ((i & (1 << 0)) && (!fan5pin)) |
858 | data->has_fan |= (1 << 4); | 1217 | data->has_fan |= (1 << 4); |
859 | 1218 | ||
860 | /* Register sysfs hooks */ | 1219 | /* Register sysfs hooks */ |
@@ -864,13 +1223,25 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) | |||
864 | goto exit_detach; | 1223 | goto exit_detach; |
865 | } | 1224 | } |
866 | 1225 | ||
1226 | for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) | ||
1227 | device_create_file(dev, &sda_sf3_arrays[i].dev_attr); | ||
1228 | |||
1229 | /* if fan4 is enabled create the sf3 files for it */ | ||
1230 | if (data->has_fan & (1 << 3)) | ||
1231 | for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) | ||
1232 | device_create_file(dev, &sda_sf3_arrays_fan4[i].dev_attr); | ||
1233 | |||
867 | for (i = 0; i < 10; i++) | 1234 | for (i = 0; i < 10; i++) |
868 | device_create_file_in(dev, i); | 1235 | device_create_file_in(dev, i); |
869 | 1236 | ||
870 | for (i = 0; i < 5; i++) { | 1237 | for (i = 0; i < 5; i++) { |
871 | if (data->has_fan & (1 << i)) | 1238 | if (data->has_fan & (1 << i)) { |
872 | device_create_file_fan(dev, i); | 1239 | device_create_file_fan(dev, i); |
1240 | if (i != 4) /* we have only 4 pwm */ | ||
1241 | device_create_file_pwm(dev, i); | ||
1242 | } | ||
873 | } | 1243 | } |
1244 | |||
874 | for (i = 0; i < ARRAY_SIZE(sda_temp); i++) | 1245 | for (i = 0; i < ARRAY_SIZE(sda_temp); i++) |
875 | device_create_file(dev, &sda_temp[i].dev_attr); | 1246 | device_create_file(dev, &sda_temp[i].dev_attr); |
876 | 1247 | ||