diff options
author | Guenter Roeck <linux@roeck-us.net> | 2012-12-04 06:26:05 -0500 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2013-04-08 00:16:38 -0400 |
commit | aa136e5dad9fbec9e98867278555a81f2d75ea10 (patch) | |
tree | 10fff886d1ed302ac5561bc16b6fd2f89f753386 | |
parent | a6bd587842772cd3e63a689c7ff4d64cf25284a3 (diff) |
hwmon: (nct6775) Add support for temperature sensors
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r-- | drivers/hwmon/nct6775.c | 748 |
1 files changed, 745 insertions, 3 deletions
diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index 435691febe9b..fd0dd15ae4b6 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c | |||
@@ -57,6 +57,8 @@ | |||
57 | #include <linux/io.h> | 57 | #include <linux/io.h> |
58 | #include "lm75.h" | 58 | #include "lm75.h" |
59 | 59 | ||
60 | #define USE_ALTERNATE | ||
61 | |||
60 | enum kinds { nct6775, nct6776, nct6779 }; | 62 | enum kinds { nct6775, nct6776, nct6779 }; |
61 | 63 | ||
62 | /* used to set data->name = nct6775_device_names[data->sio_kind] */ | 64 | /* used to set data->name = nct6775_device_names[data->sio_kind] */ |
@@ -156,6 +158,9 @@ superio_exit(int ioreg) | |||
156 | * REG_CHIP_ID is at port 0x58 | 158 | * REG_CHIP_ID is at port 0x58 |
157 | */ | 159 | */ |
158 | 160 | ||
161 | #define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/ | ||
162 | #define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */ | ||
163 | |||
159 | #define NUM_REG_ALARM 4 /* Max number of alarm registers */ | 164 | #define NUM_REG_ALARM 4 /* Max number of alarm registers */ |
160 | 165 | ||
161 | /* Common and NCT6775 specific data */ | 166 | /* Common and NCT6775 specific data */ |
@@ -173,6 +178,7 @@ static const u16 NCT6775_REG_IN[] = { | |||
173 | }; | 178 | }; |
174 | 179 | ||
175 | #define NCT6775_REG_VBAT 0x5D | 180 | #define NCT6775_REG_VBAT 0x5D |
181 | #define NCT6775_REG_DIODE 0x5E | ||
176 | 182 | ||
177 | static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B }; | 183 | static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B }; |
178 | 184 | ||
@@ -187,11 +193,58 @@ static const s8 NCT6775_ALARM_BITS[] = { | |||
187 | 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ | 193 | 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ |
188 | 12, -1 }; /* intrusion0, intrusion1 */ | 194 | 12, -1 }; /* intrusion0, intrusion1 */ |
189 | 195 | ||
196 | #define TEMP_ALARM_BASE 24 | ||
190 | #define INTRUSION_ALARM_BASE 30 | 197 | #define INTRUSION_ALARM_BASE 30 |
191 | 198 | ||
192 | static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee }; | 199 | static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee }; |
193 | static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 }; | 200 | static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 }; |
194 | 201 | ||
202 | static const u16 NCT6775_REG_TEMP[] = { | ||
203 | 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d }; | ||
204 | |||
205 | static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = { | ||
206 | 0, 0x152, 0x252, 0x628, 0x629, 0x62A }; | ||
207 | static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = { | ||
208 | 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D }; | ||
209 | static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = { | ||
210 | 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C }; | ||
211 | |||
212 | static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = { | ||
213 | 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 }; | ||
214 | |||
215 | static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 }; | ||
216 | |||
217 | static const char *const nct6775_temp_label[] = { | ||
218 | "", | ||
219 | "SYSTIN", | ||
220 | "CPUTIN", | ||
221 | "AUXTIN", | ||
222 | "AMD SB-TSI", | ||
223 | "PECI Agent 0", | ||
224 | "PECI Agent 1", | ||
225 | "PECI Agent 2", | ||
226 | "PECI Agent 3", | ||
227 | "PECI Agent 4", | ||
228 | "PECI Agent 5", | ||
229 | "PECI Agent 6", | ||
230 | "PECI Agent 7", | ||
231 | "PCH_CHIP_CPU_MAX_TEMP", | ||
232 | "PCH_CHIP_TEMP", | ||
233 | "PCH_CPU_TEMP", | ||
234 | "PCH_MCH_TEMP", | ||
235 | "PCH_DIM0_TEMP", | ||
236 | "PCH_DIM1_TEMP", | ||
237 | "PCH_DIM2_TEMP", | ||
238 | "PCH_DIM3_TEMP" | ||
239 | }; | ||
240 | |||
241 | static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6775_temp_label) - 1] | ||
242 | = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 }; | ||
243 | |||
244 | static const u16 NCT6775_REG_TEMP_CRIT[ARRAY_SIZE(nct6775_temp_label) - 1] | ||
245 | = { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06, | ||
246 | 0xa07 }; | ||
247 | |||
195 | /* NCT6776 specific data */ | 248 | /* NCT6776 specific data */ |
196 | 249 | ||
197 | static const s8 NCT6776_ALARM_BITS[] = { | 250 | static const s8 NCT6776_ALARM_BITS[] = { |
@@ -203,6 +256,41 @@ static const s8 NCT6776_ALARM_BITS[] = { | |||
203 | 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ | 256 | 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ |
204 | 12, 9 }; /* intrusion0, intrusion1 */ | 257 | 12, 9 }; /* intrusion0, intrusion1 */ |
205 | 258 | ||
259 | static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = { | ||
260 | 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A }; | ||
261 | |||
262 | static const char *const nct6776_temp_label[] = { | ||
263 | "", | ||
264 | "SYSTIN", | ||
265 | "CPUTIN", | ||
266 | "AUXTIN", | ||
267 | "SMBUSMASTER 0", | ||
268 | "SMBUSMASTER 1", | ||
269 | "SMBUSMASTER 2", | ||
270 | "SMBUSMASTER 3", | ||
271 | "SMBUSMASTER 4", | ||
272 | "SMBUSMASTER 5", | ||
273 | "SMBUSMASTER 6", | ||
274 | "SMBUSMASTER 7", | ||
275 | "PECI Agent 0", | ||
276 | "PECI Agent 1", | ||
277 | "PCH_CHIP_CPU_MAX_TEMP", | ||
278 | "PCH_CHIP_TEMP", | ||
279 | "PCH_CPU_TEMP", | ||
280 | "PCH_MCH_TEMP", | ||
281 | "PCH_DIM0_TEMP", | ||
282 | "PCH_DIM1_TEMP", | ||
283 | "PCH_DIM2_TEMP", | ||
284 | "PCH_DIM3_TEMP", | ||
285 | "BYTE_TEMP" | ||
286 | }; | ||
287 | |||
288 | static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1] | ||
289 | = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 }; | ||
290 | |||
291 | static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1] | ||
292 | = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a }; | ||
293 | |||
206 | /* NCT6779 specific data */ | 294 | /* NCT6779 specific data */ |
207 | 295 | ||
208 | static const u16 NCT6779_REG_IN[] = { | 296 | static const u16 NCT6779_REG_IN[] = { |
@@ -221,6 +309,56 @@ static const s8 NCT6779_ALARM_BITS[] = { | |||
221 | 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ | 309 | 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ |
222 | 12, 9 }; /* intrusion0, intrusion1 */ | 310 | 12, 9 }; /* intrusion0, intrusion1 */ |
223 | 311 | ||
312 | static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 }; | ||
313 | static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = { | ||
314 | 0x18, 0x152 }; | ||
315 | static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = { | ||
316 | 0x3a, 0x153 }; | ||
317 | static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = { | ||
318 | 0x39, 0x155 }; | ||
319 | |||
320 | static const u16 NCT6779_REG_TEMP_OFFSET[] = { | ||
321 | 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c }; | ||
322 | |||
323 | static const char *const nct6779_temp_label[] = { | ||
324 | "", | ||
325 | "SYSTIN", | ||
326 | "CPUTIN", | ||
327 | "AUXTIN0", | ||
328 | "AUXTIN1", | ||
329 | "AUXTIN2", | ||
330 | "AUXTIN3", | ||
331 | "", | ||
332 | "SMBUSMASTER 0", | ||
333 | "SMBUSMASTER 1", | ||
334 | "SMBUSMASTER 2", | ||
335 | "SMBUSMASTER 3", | ||
336 | "SMBUSMASTER 4", | ||
337 | "SMBUSMASTER 5", | ||
338 | "SMBUSMASTER 6", | ||
339 | "SMBUSMASTER 7", | ||
340 | "PECI Agent 0", | ||
341 | "PECI Agent 1", | ||
342 | "PCH_CHIP_CPU_MAX_TEMP", | ||
343 | "PCH_CHIP_TEMP", | ||
344 | "PCH_CPU_TEMP", | ||
345 | "PCH_MCH_TEMP", | ||
346 | "PCH_DIM0_TEMP", | ||
347 | "PCH_DIM1_TEMP", | ||
348 | "PCH_DIM2_TEMP", | ||
349 | "PCH_DIM3_TEMP", | ||
350 | "BYTE_TEMP" | ||
351 | }; | ||
352 | |||
353 | static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 1] | ||
354 | = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0, | ||
355 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
356 | 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407, | ||
357 | 0x408, 0 }; | ||
358 | |||
359 | static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1] | ||
360 | = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a }; | ||
361 | |||
224 | /* | 362 | /* |
225 | * Conversions | 363 | * Conversions |
226 | */ | 364 | */ |
@@ -256,14 +394,27 @@ struct nct6775_data { | |||
256 | struct device *hwmon_dev; | 394 | struct device *hwmon_dev; |
257 | struct mutex lock; | 395 | struct mutex lock; |
258 | 396 | ||
397 | u16 reg_temp[4][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst, | ||
398 | * 3=temp_crit | ||
399 | */ | ||
400 | u8 temp_src[NUM_TEMP]; | ||
401 | u16 reg_temp_config[NUM_TEMP]; | ||
402 | const char * const *temp_label; | ||
403 | int temp_label_num; | ||
404 | |||
259 | u16 REG_CONFIG; | 405 | u16 REG_CONFIG; |
260 | u16 REG_VBAT; | 406 | u16 REG_VBAT; |
407 | u16 REG_DIODE; | ||
261 | 408 | ||
262 | const s8 *ALARM_BITS; | 409 | const s8 *ALARM_BITS; |
263 | 410 | ||
264 | const u16 *REG_VIN; | 411 | const u16 *REG_VIN; |
265 | const u16 *REG_IN_MINMAX[2]; | 412 | const u16 *REG_IN_MINMAX[2]; |
266 | 413 | ||
414 | const u16 *REG_TEMP_SOURCE; /* temp register sources */ | ||
415 | |||
416 | const u16 *REG_TEMP_OFFSET; | ||
417 | |||
267 | const u16 *REG_ALARM; | 418 | const u16 *REG_ALARM; |
268 | 419 | ||
269 | struct mutex update_lock; | 420 | struct mutex update_lock; |
@@ -275,11 +426,18 @@ struct nct6775_data { | |||
275 | u8 in_num; /* number of in inputs we have */ | 426 | u8 in_num; /* number of in inputs we have */ |
276 | u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */ | 427 | u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */ |
277 | 428 | ||
429 | u8 temp_fixed_num; /* 3 or 6 */ | ||
430 | u8 temp_type[NUM_TEMP_FIXED]; | ||
431 | s8 temp_offset[NUM_TEMP_FIXED]; | ||
432 | s16 temp[4][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst, | ||
433 | * 3=temp_crit */ | ||
278 | u64 alarms; | 434 | u64 alarms; |
279 | 435 | ||
280 | u8 vid; | 436 | u8 vid; |
281 | u8 vrm; | 437 | u8 vrm; |
282 | 438 | ||
439 | u16 have_temp; | ||
440 | u16 have_temp_fixed; | ||
283 | u16 have_in; | 441 | u16 have_in; |
284 | }; | 442 | }; |
285 | 443 | ||
@@ -379,10 +537,29 @@ static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value) | |||
379 | return 0; | 537 | return 0; |
380 | } | 538 | } |
381 | 539 | ||
540 | /* We left-align 8-bit temperature values to make the code simpler */ | ||
541 | static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg) | ||
542 | { | ||
543 | u16 res; | ||
544 | |||
545 | res = nct6775_read_value(data, reg); | ||
546 | if (!is_word_sized(data, reg)) | ||
547 | res <<= 8; | ||
548 | |||
549 | return res; | ||
550 | } | ||
551 | |||
552 | static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value) | ||
553 | { | ||
554 | if (!is_word_sized(data, reg)) | ||
555 | value >>= 8; | ||
556 | return nct6775_write_value(data, reg, value); | ||
557 | } | ||
558 | |||
382 | static struct nct6775_data *nct6775_update_device(struct device *dev) | 559 | static struct nct6775_data *nct6775_update_device(struct device *dev) |
383 | { | 560 | { |
384 | struct nct6775_data *data = dev_get_drvdata(dev); | 561 | struct nct6775_data *data = dev_get_drvdata(dev); |
385 | int i; | 562 | int i, j; |
386 | 563 | ||
387 | mutex_lock(&data->update_lock); | 564 | mutex_lock(&data->update_lock); |
388 | 565 | ||
@@ -401,6 +578,22 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) | |||
401 | data->REG_IN_MINMAX[1][i]); | 578 | data->REG_IN_MINMAX[1][i]); |
402 | } | 579 | } |
403 | 580 | ||
581 | /* Measured temperatures and limits */ | ||
582 | for (i = 0; i < NUM_TEMP; i++) { | ||
583 | if (!(data->have_temp & (1 << i))) | ||
584 | continue; | ||
585 | for (j = 0; j < 4; j++) { | ||
586 | if (data->reg_temp[j][i]) | ||
587 | data->temp[j][i] | ||
588 | = nct6775_read_temp(data, | ||
589 | data->reg_temp[j][i]); | ||
590 | } | ||
591 | if (!(data->have_temp_fixed & (1 << i))) | ||
592 | continue; | ||
593 | data->temp_offset[i] | ||
594 | = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]); | ||
595 | } | ||
596 | |||
404 | data->alarms = 0; | 597 | data->alarms = 0; |
405 | for (i = 0; i < NUM_REG_ALARM; i++) { | 598 | for (i = 0; i < NUM_REG_ALARM; i++) { |
406 | u8 alarm; | 599 | u8 alarm; |
@@ -682,6 +875,275 @@ static const struct attribute_group nct6775_group_in[15] = { | |||
682 | }; | 875 | }; |
683 | 876 | ||
684 | static ssize_t | 877 | static ssize_t |
878 | show_temp_label(struct device *dev, struct device_attribute *attr, char *buf) | ||
879 | { | ||
880 | struct nct6775_data *data = nct6775_update_device(dev); | ||
881 | struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); | ||
882 | int nr = sattr->index; | ||
883 | return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]); | ||
884 | } | ||
885 | |||
886 | static ssize_t | ||
887 | show_temp(struct device *dev, struct device_attribute *attr, char *buf) | ||
888 | { | ||
889 | struct nct6775_data *data = nct6775_update_device(dev); | ||
890 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
891 | int nr = sattr->nr; | ||
892 | int index = sattr->index; | ||
893 | |||
894 | return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr])); | ||
895 | } | ||
896 | |||
897 | static ssize_t | ||
898 | store_temp(struct device *dev, struct device_attribute *attr, const char *buf, | ||
899 | size_t count) | ||
900 | { | ||
901 | struct nct6775_data *data = dev_get_drvdata(dev); | ||
902 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
903 | int nr = sattr->nr; | ||
904 | int index = sattr->index; | ||
905 | int err; | ||
906 | long val; | ||
907 | |||
908 | err = kstrtol(buf, 10, &val); | ||
909 | if (err < 0) | ||
910 | return err; | ||
911 | |||
912 | mutex_lock(&data->update_lock); | ||
913 | data->temp[index][nr] = LM75_TEMP_TO_REG(val); | ||
914 | nct6775_write_temp(data, data->reg_temp[index][nr], | ||
915 | data->temp[index][nr]); | ||
916 | mutex_unlock(&data->update_lock); | ||
917 | return count; | ||
918 | } | ||
919 | |||
920 | static ssize_t | ||
921 | show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf) | ||
922 | { | ||
923 | struct nct6775_data *data = nct6775_update_device(dev); | ||
924 | struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); | ||
925 | |||
926 | return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000); | ||
927 | } | ||
928 | |||
929 | static ssize_t | ||
930 | store_temp_offset(struct device *dev, struct device_attribute *attr, | ||
931 | const char *buf, size_t count) | ||
932 | { | ||
933 | struct nct6775_data *data = dev_get_drvdata(dev); | ||
934 | struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); | ||
935 | int nr = sattr->index; | ||
936 | long val; | ||
937 | int err; | ||
938 | |||
939 | err = kstrtol(buf, 10, &val); | ||
940 | if (err < 0) | ||
941 | return err; | ||
942 | |||
943 | val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127); | ||
944 | |||
945 | mutex_lock(&data->update_lock); | ||
946 | data->temp_offset[nr] = val; | ||
947 | nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val); | ||
948 | mutex_unlock(&data->update_lock); | ||
949 | |||
950 | return count; | ||
951 | } | ||
952 | |||
953 | static ssize_t | ||
954 | show_temp_type(struct device *dev, struct device_attribute *attr, char *buf) | ||
955 | { | ||
956 | struct nct6775_data *data = nct6775_update_device(dev); | ||
957 | struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); | ||
958 | int nr = sattr->index; | ||
959 | return sprintf(buf, "%d\n", (int)data->temp_type[nr]); | ||
960 | } | ||
961 | |||
962 | static ssize_t | ||
963 | store_temp_type(struct device *dev, struct device_attribute *attr, | ||
964 | const char *buf, size_t count) | ||
965 | { | ||
966 | struct nct6775_data *data = nct6775_update_device(dev); | ||
967 | struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); | ||
968 | int nr = sattr->index; | ||
969 | unsigned long val; | ||
970 | int err; | ||
971 | u8 vbat, diode, bit; | ||
972 | |||
973 | err = kstrtoul(buf, 10, &val); | ||
974 | if (err < 0) | ||
975 | return err; | ||
976 | |||
977 | if (val != 1 && val != 3 && val != 4) | ||
978 | return -EINVAL; | ||
979 | |||
980 | mutex_lock(&data->update_lock); | ||
981 | |||
982 | data->temp_type[nr] = val; | ||
983 | vbat = nct6775_read_value(data, data->REG_VBAT) & ~(0x02 << nr); | ||
984 | diode = nct6775_read_value(data, data->REG_DIODE) & ~(0x02 << nr); | ||
985 | bit = 0x02 << nr; | ||
986 | switch (val) { | ||
987 | case 1: /* CPU diode (diode, current mode) */ | ||
988 | vbat |= bit; | ||
989 | diode |= bit; | ||
990 | break; | ||
991 | case 3: /* diode, voltage mode */ | ||
992 | vbat |= bit; | ||
993 | break; | ||
994 | case 4: /* thermistor */ | ||
995 | break; | ||
996 | } | ||
997 | nct6775_write_value(data, data->REG_VBAT, vbat); | ||
998 | nct6775_write_value(data, data->REG_DIODE, diode); | ||
999 | |||
1000 | mutex_unlock(&data->update_lock); | ||
1001 | return count; | ||
1002 | } | ||
1003 | |||
1004 | static struct sensor_device_attribute_2 sda_temp_input[] = { | ||
1005 | SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0), | ||
1006 | SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0), | ||
1007 | SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0), | ||
1008 | SENSOR_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0), | ||
1009 | SENSOR_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0), | ||
1010 | SENSOR_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0), | ||
1011 | SENSOR_ATTR_2(temp7_input, S_IRUGO, show_temp, NULL, 6, 0), | ||
1012 | SENSOR_ATTR_2(temp8_input, S_IRUGO, show_temp, NULL, 7, 0), | ||
1013 | SENSOR_ATTR_2(temp9_input, S_IRUGO, show_temp, NULL, 8, 0), | ||
1014 | SENSOR_ATTR_2(temp10_input, S_IRUGO, show_temp, NULL, 9, 0), | ||
1015 | }; | ||
1016 | |||
1017 | static struct sensor_device_attribute sda_temp_label[] = { | ||
1018 | SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0), | ||
1019 | SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1), | ||
1020 | SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2), | ||
1021 | SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3), | ||
1022 | SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4), | ||
1023 | SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5), | ||
1024 | SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6), | ||
1025 | SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7), | ||
1026 | SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8), | ||
1027 | SENSOR_ATTR(temp10_label, S_IRUGO, show_temp_label, NULL, 9), | ||
1028 | }; | ||
1029 | |||
1030 | static struct sensor_device_attribute_2 sda_temp_max[] = { | ||
1031 | SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1032 | 0, 1), | ||
1033 | SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1034 | 1, 1), | ||
1035 | SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1036 | 2, 1), | ||
1037 | SENSOR_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1038 | 3, 1), | ||
1039 | SENSOR_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1040 | 4, 1), | ||
1041 | SENSOR_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1042 | 5, 1), | ||
1043 | SENSOR_ATTR_2(temp7_max, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1044 | 6, 1), | ||
1045 | SENSOR_ATTR_2(temp8_max, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1046 | 7, 1), | ||
1047 | SENSOR_ATTR_2(temp9_max, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1048 | 8, 1), | ||
1049 | SENSOR_ATTR_2(temp10_max, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1050 | 9, 1), | ||
1051 | }; | ||
1052 | |||
1053 | static struct sensor_device_attribute_2 sda_temp_max_hyst[] = { | ||
1054 | SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1055 | 0, 2), | ||
1056 | SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1057 | 1, 2), | ||
1058 | SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1059 | 2, 2), | ||
1060 | SENSOR_ATTR_2(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1061 | 3, 2), | ||
1062 | SENSOR_ATTR_2(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1063 | 4, 2), | ||
1064 | SENSOR_ATTR_2(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1065 | 5, 2), | ||
1066 | SENSOR_ATTR_2(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1067 | 6, 2), | ||
1068 | SENSOR_ATTR_2(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1069 | 7, 2), | ||
1070 | SENSOR_ATTR_2(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1071 | 8, 2), | ||
1072 | SENSOR_ATTR_2(temp10_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1073 | 9, 2), | ||
1074 | }; | ||
1075 | |||
1076 | static struct sensor_device_attribute_2 sda_temp_crit[] = { | ||
1077 | SENSOR_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1078 | 0, 3), | ||
1079 | SENSOR_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1080 | 1, 3), | ||
1081 | SENSOR_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1082 | 2, 3), | ||
1083 | SENSOR_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1084 | 3, 3), | ||
1085 | SENSOR_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1086 | 4, 3), | ||
1087 | SENSOR_ATTR_2(temp6_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1088 | 5, 3), | ||
1089 | SENSOR_ATTR_2(temp7_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1090 | 6, 3), | ||
1091 | SENSOR_ATTR_2(temp8_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1092 | 7, 3), | ||
1093 | SENSOR_ATTR_2(temp9_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1094 | 8, 3), | ||
1095 | SENSOR_ATTR_2(temp10_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, | ||
1096 | 9, 3), | ||
1097 | }; | ||
1098 | |||
1099 | static struct sensor_device_attribute sda_temp_offset[] = { | ||
1100 | SENSOR_ATTR(temp1_offset, S_IRUGO | S_IWUSR, show_temp_offset, | ||
1101 | store_temp_offset, 0), | ||
1102 | SENSOR_ATTR(temp2_offset, S_IRUGO | S_IWUSR, show_temp_offset, | ||
1103 | store_temp_offset, 1), | ||
1104 | SENSOR_ATTR(temp3_offset, S_IRUGO | S_IWUSR, show_temp_offset, | ||
1105 | store_temp_offset, 2), | ||
1106 | SENSOR_ATTR(temp4_offset, S_IRUGO | S_IWUSR, show_temp_offset, | ||
1107 | store_temp_offset, 3), | ||
1108 | SENSOR_ATTR(temp5_offset, S_IRUGO | S_IWUSR, show_temp_offset, | ||
1109 | store_temp_offset, 4), | ||
1110 | SENSOR_ATTR(temp6_offset, S_IRUGO | S_IWUSR, show_temp_offset, | ||
1111 | store_temp_offset, 5), | ||
1112 | }; | ||
1113 | |||
1114 | static struct sensor_device_attribute sda_temp_type[] = { | ||
1115 | SENSOR_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type, | ||
1116 | store_temp_type, 0), | ||
1117 | SENSOR_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type, | ||
1118 | store_temp_type, 1), | ||
1119 | SENSOR_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type, | ||
1120 | store_temp_type, 2), | ||
1121 | SENSOR_ATTR(temp4_type, S_IRUGO | S_IWUSR, show_temp_type, | ||
1122 | store_temp_type, 3), | ||
1123 | SENSOR_ATTR(temp5_type, S_IRUGO | S_IWUSR, show_temp_type, | ||
1124 | store_temp_type, 4), | ||
1125 | SENSOR_ATTR(temp6_type, S_IRUGO | S_IWUSR, show_temp_type, | ||
1126 | store_temp_type, 5), | ||
1127 | }; | ||
1128 | |||
1129 | static struct sensor_device_attribute sda_temp_alarm[] = { | ||
1130 | SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, | ||
1131 | TEMP_ALARM_BASE), | ||
1132 | SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, | ||
1133 | TEMP_ALARM_BASE + 1), | ||
1134 | SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, | ||
1135 | TEMP_ALARM_BASE + 2), | ||
1136 | SENSOR_ATTR(temp4_alarm, S_IRUGO, show_alarm, NULL, | ||
1137 | TEMP_ALARM_BASE + 3), | ||
1138 | SENSOR_ATTR(temp5_alarm, S_IRUGO, show_alarm, NULL, | ||
1139 | TEMP_ALARM_BASE + 4), | ||
1140 | SENSOR_ATTR(temp6_alarm, S_IRUGO, show_alarm, NULL, | ||
1141 | TEMP_ALARM_BASE + 5), | ||
1142 | }; | ||
1143 | |||
1144 | #define NUM_TEMP_ALARM ARRAY_SIZE(sda_temp_alarm) | ||
1145 | |||
1146 | static ssize_t | ||
685 | show_name(struct device *dev, struct device_attribute *attr, char *buf) | 1147 | show_name(struct device *dev, struct device_attribute *attr, char *buf) |
686 | { | 1148 | { |
687 | struct nct6775_data *data = dev_get_drvdata(dev); | 1149 | struct nct6775_data *data = dev_get_drvdata(dev); |
@@ -766,6 +1228,23 @@ static void nct6775_device_remove_files(struct device *dev) | |||
766 | for (i = 0; i < data->in_num; i++) | 1228 | for (i = 0; i < data->in_num; i++) |
767 | sysfs_remove_group(&dev->kobj, &nct6775_group_in[i]); | 1229 | sysfs_remove_group(&dev->kobj, &nct6775_group_in[i]); |
768 | 1230 | ||
1231 | for (i = 0; i < NUM_TEMP; i++) { | ||
1232 | if (!(data->have_temp & (1 << i))) | ||
1233 | continue; | ||
1234 | device_remove_file(dev, &sda_temp_input[i].dev_attr); | ||
1235 | device_remove_file(dev, &sda_temp_label[i].dev_attr); | ||
1236 | device_remove_file(dev, &sda_temp_max[i].dev_attr); | ||
1237 | device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr); | ||
1238 | device_remove_file(dev, &sda_temp_crit[i].dev_attr); | ||
1239 | if (!(data->have_temp_fixed & (1 << i))) | ||
1240 | continue; | ||
1241 | device_remove_file(dev, &sda_temp_type[i].dev_attr); | ||
1242 | device_remove_file(dev, &sda_temp_offset[i].dev_attr); | ||
1243 | if (i >= NUM_TEMP_ALARM) | ||
1244 | continue; | ||
1245 | device_remove_file(dev, &sda_temp_alarm[i].dev_attr); | ||
1246 | } | ||
1247 | |||
769 | device_remove_file(dev, &sda_caseopen[0].dev_attr); | 1248 | device_remove_file(dev, &sda_caseopen[0].dev_attr); |
770 | device_remove_file(dev, &sda_caseopen[1].dev_attr); | 1249 | device_remove_file(dev, &sda_caseopen[1].dev_attr); |
771 | 1250 | ||
@@ -776,7 +1255,8 @@ static void nct6775_device_remove_files(struct device *dev) | |||
776 | /* Get the monitoring functions started */ | 1255 | /* Get the monitoring functions started */ |
777 | static inline void nct6775_init_device(struct nct6775_data *data) | 1256 | static inline void nct6775_init_device(struct nct6775_data *data) |
778 | { | 1257 | { |
779 | u8 tmp; | 1258 | int i; |
1259 | u8 tmp, diode; | ||
780 | 1260 | ||
781 | /* Start monitoring if needed */ | 1261 | /* Start monitoring if needed */ |
782 | if (data->REG_CONFIG) { | 1262 | if (data->REG_CONFIG) { |
@@ -785,10 +1265,33 @@ static inline void nct6775_init_device(struct nct6775_data *data) | |||
785 | nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01); | 1265 | nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01); |
786 | } | 1266 | } |
787 | 1267 | ||
1268 | /* Enable temperature sensors if needed */ | ||
1269 | for (i = 0; i < NUM_TEMP; i++) { | ||
1270 | if (!(data->have_temp & (1 << i))) | ||
1271 | continue; | ||
1272 | if (!data->reg_temp_config[i]) | ||
1273 | continue; | ||
1274 | tmp = nct6775_read_value(data, data->reg_temp_config[i]); | ||
1275 | if (tmp & 0x01) | ||
1276 | nct6775_write_value(data, data->reg_temp_config[i], | ||
1277 | tmp & 0xfe); | ||
1278 | } | ||
1279 | |||
788 | /* Enable VBAT monitoring if needed */ | 1280 | /* Enable VBAT monitoring if needed */ |
789 | tmp = nct6775_read_value(data, data->REG_VBAT); | 1281 | tmp = nct6775_read_value(data, data->REG_VBAT); |
790 | if (!(tmp & 0x01)) | 1282 | if (!(tmp & 0x01)) |
791 | nct6775_write_value(data, data->REG_VBAT, tmp | 0x01); | 1283 | nct6775_write_value(data, data->REG_VBAT, tmp | 0x01); |
1284 | |||
1285 | diode = nct6775_read_value(data, data->REG_DIODE); | ||
1286 | |||
1287 | for (i = 0; i < data->temp_fixed_num; i++) { | ||
1288 | if (!(data->have_temp_fixed & (1 << i))) | ||
1289 | continue; | ||
1290 | if ((tmp & (0x02 << i))) /* diode */ | ||
1291 | data->temp_type[i] = 3 - ((diode >> i) & 0x02); | ||
1292 | else /* thermistor */ | ||
1293 | data->temp_type[i] = 4; | ||
1294 | } | ||
792 | } | 1295 | } |
793 | 1296 | ||
794 | static int nct6775_probe(struct platform_device *pdev) | 1297 | static int nct6775_probe(struct platform_device *pdev) |
@@ -797,7 +1300,11 @@ static int nct6775_probe(struct platform_device *pdev) | |||
797 | struct nct6775_sio_data *sio_data = dev->platform_data; | 1300 | struct nct6775_sio_data *sio_data = dev->platform_data; |
798 | struct nct6775_data *data; | 1301 | struct nct6775_data *data; |
799 | struct resource *res; | 1302 | struct resource *res; |
800 | int i, err = 0; | 1303 | int i, s, err = 0; |
1304 | int src, mask, available; | ||
1305 | const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config; | ||
1306 | const u16 *reg_temp_alternate, *reg_temp_crit; | ||
1307 | int num_reg_temp; | ||
801 | 1308 | ||
802 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | 1309 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
803 | if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH, | 1310 | if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH, |
@@ -820,44 +1327,233 @@ static int nct6775_probe(struct platform_device *pdev) | |||
820 | switch (data->kind) { | 1327 | switch (data->kind) { |
821 | case nct6775: | 1328 | case nct6775: |
822 | data->in_num = 9; | 1329 | data->in_num = 9; |
1330 | data->temp_fixed_num = 3; | ||
823 | 1331 | ||
824 | data->ALARM_BITS = NCT6775_ALARM_BITS; | 1332 | data->ALARM_BITS = NCT6775_ALARM_BITS; |
825 | 1333 | ||
1334 | data->temp_label = nct6775_temp_label; | ||
1335 | data->temp_label_num = ARRAY_SIZE(nct6775_temp_label); | ||
1336 | |||
826 | data->REG_CONFIG = NCT6775_REG_CONFIG; | 1337 | data->REG_CONFIG = NCT6775_REG_CONFIG; |
827 | data->REG_VBAT = NCT6775_REG_VBAT; | 1338 | data->REG_VBAT = NCT6775_REG_VBAT; |
1339 | data->REG_DIODE = NCT6775_REG_DIODE; | ||
828 | data->REG_VIN = NCT6775_REG_IN; | 1340 | data->REG_VIN = NCT6775_REG_IN; |
829 | data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; | 1341 | data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; |
830 | data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; | 1342 | data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; |
1343 | data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET; | ||
1344 | data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE; | ||
831 | data->REG_ALARM = NCT6775_REG_ALARM; | 1345 | data->REG_ALARM = NCT6775_REG_ALARM; |
1346 | |||
1347 | reg_temp = NCT6775_REG_TEMP; | ||
1348 | num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP); | ||
1349 | reg_temp_over = NCT6775_REG_TEMP_OVER; | ||
1350 | reg_temp_hyst = NCT6775_REG_TEMP_HYST; | ||
1351 | reg_temp_config = NCT6775_REG_TEMP_CONFIG; | ||
1352 | reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE; | ||
1353 | reg_temp_crit = NCT6775_REG_TEMP_CRIT; | ||
1354 | |||
832 | break; | 1355 | break; |
833 | case nct6776: | 1356 | case nct6776: |
834 | data->in_num = 9; | 1357 | data->in_num = 9; |
1358 | data->temp_fixed_num = 3; | ||
835 | 1359 | ||
836 | data->ALARM_BITS = NCT6776_ALARM_BITS; | 1360 | data->ALARM_BITS = NCT6776_ALARM_BITS; |
837 | 1361 | ||
1362 | data->temp_label = nct6776_temp_label; | ||
1363 | data->temp_label_num = ARRAY_SIZE(nct6776_temp_label); | ||
1364 | |||
838 | data->REG_CONFIG = NCT6775_REG_CONFIG; | 1365 | data->REG_CONFIG = NCT6775_REG_CONFIG; |
839 | data->REG_VBAT = NCT6775_REG_VBAT; | 1366 | data->REG_VBAT = NCT6775_REG_VBAT; |
1367 | data->REG_DIODE = NCT6775_REG_DIODE; | ||
840 | data->REG_VIN = NCT6775_REG_IN; | 1368 | data->REG_VIN = NCT6775_REG_IN; |
841 | data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; | 1369 | data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; |
842 | data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; | 1370 | data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; |
1371 | data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET; | ||
1372 | data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE; | ||
843 | data->REG_ALARM = NCT6775_REG_ALARM; | 1373 | data->REG_ALARM = NCT6775_REG_ALARM; |
1374 | |||
1375 | reg_temp = NCT6775_REG_TEMP; | ||
1376 | num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP); | ||
1377 | reg_temp_over = NCT6775_REG_TEMP_OVER; | ||
1378 | reg_temp_hyst = NCT6775_REG_TEMP_HYST; | ||
1379 | reg_temp_config = NCT6776_REG_TEMP_CONFIG; | ||
1380 | reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE; | ||
1381 | reg_temp_crit = NCT6776_REG_TEMP_CRIT; | ||
1382 | |||
844 | break; | 1383 | break; |
845 | case nct6779: | 1384 | case nct6779: |
846 | data->in_num = 15; | 1385 | data->in_num = 15; |
1386 | data->temp_fixed_num = 6; | ||
847 | 1387 | ||
848 | data->ALARM_BITS = NCT6779_ALARM_BITS; | 1388 | data->ALARM_BITS = NCT6779_ALARM_BITS; |
849 | 1389 | ||
1390 | data->temp_label = nct6779_temp_label; | ||
1391 | data->temp_label_num = ARRAY_SIZE(nct6779_temp_label); | ||
1392 | |||
850 | data->REG_CONFIG = NCT6775_REG_CONFIG; | 1393 | data->REG_CONFIG = NCT6775_REG_CONFIG; |
851 | data->REG_VBAT = NCT6775_REG_VBAT; | 1394 | data->REG_VBAT = NCT6775_REG_VBAT; |
1395 | data->REG_DIODE = NCT6775_REG_DIODE; | ||
852 | data->REG_VIN = NCT6779_REG_IN; | 1396 | data->REG_VIN = NCT6779_REG_IN; |
853 | data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; | 1397 | data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; |
854 | data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; | 1398 | data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; |
1399 | data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET; | ||
1400 | data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE; | ||
855 | data->REG_ALARM = NCT6779_REG_ALARM; | 1401 | data->REG_ALARM = NCT6779_REG_ALARM; |
1402 | |||
1403 | reg_temp = NCT6779_REG_TEMP; | ||
1404 | num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP); | ||
1405 | reg_temp_over = NCT6779_REG_TEMP_OVER; | ||
1406 | reg_temp_hyst = NCT6779_REG_TEMP_HYST; | ||
1407 | reg_temp_config = NCT6779_REG_TEMP_CONFIG; | ||
1408 | reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE; | ||
1409 | reg_temp_crit = NCT6779_REG_TEMP_CRIT; | ||
1410 | |||
856 | break; | 1411 | break; |
857 | default: | 1412 | default: |
858 | return -ENODEV; | 1413 | return -ENODEV; |
859 | } | 1414 | } |
860 | data->have_in = (1 << data->in_num) - 1; | 1415 | data->have_in = (1 << data->in_num) - 1; |
1416 | data->have_temp = 0; | ||
1417 | |||
1418 | /* | ||
1419 | * On some boards, not all available temperature sources are monitored, | ||
1420 | * even though some of the monitoring registers are unused. | ||
1421 | * Get list of unused monitoring registers, then detect if any fan | ||
1422 | * controls are configured to use unmonitored temperature sources. | ||
1423 | * If so, assign the unmonitored temperature sources to available | ||
1424 | * monitoring registers. | ||
1425 | */ | ||
1426 | mask = 0; | ||
1427 | available = 0; | ||
1428 | for (i = 0; i < num_reg_temp; i++) { | ||
1429 | if (reg_temp[i] == 0) | ||
1430 | continue; | ||
1431 | |||
1432 | src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f; | ||
1433 | if (!src || (mask & (1 << src))) | ||
1434 | available |= 1 << i; | ||
1435 | |||
1436 | mask |= 1 << src; | ||
1437 | } | ||
1438 | |||
1439 | mask = 0; | ||
1440 | s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */ | ||
1441 | for (i = 0; i < num_reg_temp; i++) { | ||
1442 | if (reg_temp[i] == 0) | ||
1443 | continue; | ||
1444 | |||
1445 | src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f; | ||
1446 | if (!src || (mask & (1 << src))) | ||
1447 | continue; | ||
1448 | |||
1449 | if (src >= data->temp_label_num || | ||
1450 | !strlen(data->temp_label[src])) { | ||
1451 | dev_info(dev, | ||
1452 | "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n", | ||
1453 | src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]); | ||
1454 | continue; | ||
1455 | } | ||
1456 | |||
1457 | mask |= 1 << src; | ||
1458 | |||
1459 | /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */ | ||
1460 | if (src <= data->temp_fixed_num) { | ||
1461 | data->have_temp |= 1 << (src - 1); | ||
1462 | data->have_temp_fixed |= 1 << (src - 1); | ||
1463 | data->reg_temp[0][src - 1] = reg_temp[i]; | ||
1464 | data->reg_temp[1][src - 1] = reg_temp_over[i]; | ||
1465 | data->reg_temp[2][src - 1] = reg_temp_hyst[i]; | ||
1466 | data->reg_temp_config[src - 1] = reg_temp_config[i]; | ||
1467 | data->temp_src[src - 1] = src; | ||
1468 | continue; | ||
1469 | } | ||
1470 | |||
1471 | if (s >= NUM_TEMP) | ||
1472 | continue; | ||
1473 | |||
1474 | /* Use dynamic index for other sources */ | ||
1475 | data->have_temp |= 1 << s; | ||
1476 | data->reg_temp[0][s] = reg_temp[i]; | ||
1477 | data->reg_temp[1][s] = reg_temp_over[i]; | ||
1478 | data->reg_temp[2][s] = reg_temp_hyst[i]; | ||
1479 | data->reg_temp_config[s] = reg_temp_config[i]; | ||
1480 | if (reg_temp_crit[src - 1]) | ||
1481 | data->reg_temp[3][s] = reg_temp_crit[src - 1]; | ||
1482 | |||
1483 | data->temp_src[s] = src; | ||
1484 | s++; | ||
1485 | } | ||
1486 | |||
1487 | #ifdef USE_ALTERNATE | ||
1488 | /* | ||
1489 | * Go through the list of alternate temp registers and enable | ||
1490 | * if possible. | ||
1491 | * The temperature is already monitored if the respective bit in <mask> | ||
1492 | * is set. | ||
1493 | */ | ||
1494 | for (i = 0; i < data->temp_label_num - 1; i++) { | ||
1495 | if (!reg_temp_alternate[i]) | ||
1496 | continue; | ||
1497 | if (mask & (1 << (i + 1))) | ||
1498 | continue; | ||
1499 | if (i < data->temp_fixed_num) { | ||
1500 | if (data->have_temp & (1 << i)) | ||
1501 | continue; | ||
1502 | data->have_temp |= 1 << i; | ||
1503 | data->have_temp_fixed |= 1 << i; | ||
1504 | data->reg_temp[0][i] = reg_temp_alternate[i]; | ||
1505 | data->reg_temp[1][i] = reg_temp_over[i]; | ||
1506 | data->reg_temp[2][i] = reg_temp_hyst[i]; | ||
1507 | data->temp_src[i] = i + 1; | ||
1508 | continue; | ||
1509 | } | ||
1510 | |||
1511 | if (s >= NUM_TEMP) /* Abort if no more space */ | ||
1512 | break; | ||
1513 | |||
1514 | data->have_temp |= 1 << s; | ||
1515 | data->reg_temp[0][s] = reg_temp_alternate[i]; | ||
1516 | data->temp_src[s] = i + 1; | ||
1517 | s++; | ||
1518 | } | ||
1519 | #endif /* USE_ALTERNATE */ | ||
1520 | |||
1521 | switch (data->kind) { | ||
1522 | case nct6775: | ||
1523 | break; | ||
1524 | case nct6776: | ||
1525 | /* | ||
1526 | * On NCT6776, AUXTIN and VIN3 pins are shared. | ||
1527 | * Only way to detect it is to check if AUXTIN is used | ||
1528 | * as a temperature source, and if that source is | ||
1529 | * enabled. | ||
1530 | * | ||
1531 | * If that is the case, disable in6, which reports VIN3. | ||
1532 | * Otherwise disable temp3. | ||
1533 | */ | ||
1534 | if (data->have_temp & (1 << 2)) { | ||
1535 | u8 reg = nct6775_read_value(data, | ||
1536 | data->reg_temp_config[2]); | ||
1537 | if (reg & 0x01) | ||
1538 | data->have_temp &= ~(1 << 2); | ||
1539 | else | ||
1540 | data->have_in &= ~(1 << 6); | ||
1541 | } | ||
1542 | break; | ||
1543 | case nct6779: | ||
1544 | /* | ||
1545 | * Shared pins: | ||
1546 | * VIN4 / AUXTIN0 | ||
1547 | * VIN5 / AUXTIN1 | ||
1548 | * VIN6 / AUXTIN2 | ||
1549 | * VIN7 / AUXTIN3 | ||
1550 | * | ||
1551 | * There does not seem to be a clean way to detect if VINx or | ||
1552 | * AUXTINx is active, so for keep both sensor types enabled | ||
1553 | * for now. | ||
1554 | */ | ||
1555 | break; | ||
1556 | } | ||
861 | 1557 | ||
862 | /* Initialize the chip */ | 1558 | /* Initialize the chip */ |
863 | nct6775_init_device(data); | 1559 | nct6775_init_device(data); |
@@ -887,6 +1583,52 @@ static int nct6775_probe(struct platform_device *pdev) | |||
887 | goto exit_remove; | 1583 | goto exit_remove; |
888 | } | 1584 | } |
889 | 1585 | ||
1586 | for (i = 0; i < NUM_TEMP; i++) { | ||
1587 | if (!(data->have_temp & (1 << i))) | ||
1588 | continue; | ||
1589 | err = device_create_file(dev, &sda_temp_input[i].dev_attr); | ||
1590 | if (err) | ||
1591 | goto exit_remove; | ||
1592 | if (data->temp_label) { | ||
1593 | err = device_create_file(dev, | ||
1594 | &sda_temp_label[i].dev_attr); | ||
1595 | if (err) | ||
1596 | goto exit_remove; | ||
1597 | } | ||
1598 | if (data->reg_temp[1][i]) { | ||
1599 | err = device_create_file(dev, | ||
1600 | &sda_temp_max[i].dev_attr); | ||
1601 | if (err) | ||
1602 | goto exit_remove; | ||
1603 | } | ||
1604 | if (data->reg_temp[2][i]) { | ||
1605 | err = device_create_file(dev, | ||
1606 | &sda_temp_max_hyst[i].dev_attr); | ||
1607 | if (err) | ||
1608 | goto exit_remove; | ||
1609 | } | ||
1610 | if (data->reg_temp[3][i]) { | ||
1611 | err = device_create_file(dev, | ||
1612 | &sda_temp_crit[i].dev_attr); | ||
1613 | if (err) | ||
1614 | goto exit_remove; | ||
1615 | } | ||
1616 | if (!(data->have_temp_fixed & (1 << i))) | ||
1617 | continue; | ||
1618 | err = device_create_file(dev, &sda_temp_type[i].dev_attr); | ||
1619 | if (err) | ||
1620 | goto exit_remove; | ||
1621 | err = device_create_file(dev, &sda_temp_offset[i].dev_attr); | ||
1622 | if (err) | ||
1623 | goto exit_remove; | ||
1624 | if (i >= NUM_TEMP_ALARM || | ||
1625 | data->ALARM_BITS[TEMP_ALARM_BASE + i] < 0) | ||
1626 | continue; | ||
1627 | err = device_create_file(dev, &sda_temp_alarm[i].dev_attr); | ||
1628 | if (err) | ||
1629 | goto exit_remove; | ||
1630 | } | ||
1631 | |||
890 | for (i = 0; i < ARRAY_SIZE(sda_caseopen); i++) { | 1632 | for (i = 0; i < ARRAY_SIZE(sda_caseopen); i++) { |
891 | if (data->ALARM_BITS[INTRUSION_ALARM_BASE + i] < 0) | 1633 | if (data->ALARM_BITS[INTRUSION_ALARM_BASE + i] < 0) |
892 | continue; | 1634 | continue; |