diff options
author | Guenter Roeck <guenter.roeck@ericsson.com> | 2011-02-02 11:46:49 -0500 |
---|---|---|
committer | Guenter Roeck <guenter.roeck@ericsson.com> | 2011-03-15 01:39:17 -0400 |
commit | ec3e5a16446fef1891611fe3bdfa5954d1ddf5e4 (patch) | |
tree | dcf2c4ef1a1f6245930bb47cf1babff7db75b507 /drivers/hwmon/w83627ehf.c | |
parent | b84bb5186297d181075d917e9049da3a3b78d10d (diff) |
hwmon: (w83627ehf) Add support for Nuvoton NCT6775F and NCT6776F
This patch adds support for NCT6775F and NCT6776F to the w83627ehf driver.
Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
Tested-by: Ian Dobson <i.dobson@planet-ian.com> (NCT6776F)
Tested-by: Zachary Marzec <zmarzec@gmail.com> (ASUS P8P67 PRO/NCT6776F)
Acked-by: Ian Dobson <i.dobson@planet-ian.com>
Diffstat (limited to 'drivers/hwmon/w83627ehf.c')
-rw-r--r-- | drivers/hwmon/w83627ehf.c | 791 |
1 files changed, 652 insertions, 139 deletions
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 2f17f99e0ae1..b3b4f2b41dcf 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c | |||
@@ -6,6 +6,7 @@ | |||
6 | Rudolf Marek <r.marek@assembler.cz> | 6 | Rudolf Marek <r.marek@assembler.cz> |
7 | David Hubbard <david.c.hubbard@gmail.com> | 7 | David Hubbard <david.c.hubbard@gmail.com> |
8 | Daniel J Blueman <daniel.blueman@gmail.com> | 8 | Daniel J Blueman <daniel.blueman@gmail.com> |
9 | Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00) | ||
9 | 10 | ||
10 | Shamelessly ripped from the w83627hf driver | 11 | Shamelessly ripped from the w83627hf driver |
11 | Copyright (C) 2003 Mark Studebaker | 12 | Copyright (C) 2003 Mark Studebaker |
@@ -40,6 +41,8 @@ | |||
40 | w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3 | 41 | w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3 |
41 | w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 | 42 | w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 |
42 | w83667hg-b 9 5 3 4 0xb350 0xc1 0x5ca3 | 43 | w83667hg-b 9 5 3 4 0xb350 0xc1 0x5ca3 |
44 | nct6775f 9 4 3 9 0xb470 0xc1 0x5ca3 | ||
45 | nct6776f 9 5 3 9 0xC330 0xc1 0x5ca3 | ||
43 | */ | 46 | */ |
44 | 47 | ||
45 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 48 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
@@ -58,7 +61,8 @@ | |||
58 | #include <linux/io.h> | 61 | #include <linux/io.h> |
59 | #include "lm75.h" | 62 | #include "lm75.h" |
60 | 63 | ||
61 | enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b }; | 64 | enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b, nct6775, |
65 | nct6776 }; | ||
62 | 66 | ||
63 | /* used to set data->name = w83627ehf_device_names[data->sio_kind] */ | 67 | /* used to set data->name = w83627ehf_device_names[data->sio_kind] */ |
64 | static const char * const w83627ehf_device_names[] = { | 68 | static const char * const w83627ehf_device_names[] = { |
@@ -67,6 +71,8 @@ static const char * const w83627ehf_device_names[] = { | |||
67 | "w83627dhg", | 71 | "w83627dhg", |
68 | "w83667hg", | 72 | "w83667hg", |
69 | "w83667hg", | 73 | "w83667hg", |
74 | "nct6775", | ||
75 | "nct6776", | ||
70 | }; | 76 | }; |
71 | 77 | ||
72 | static unsigned short force_id; | 78 | static unsigned short force_id; |
@@ -96,6 +102,8 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID"); | |||
96 | #define SIO_W83627DHG_P_ID 0xb070 | 102 | #define SIO_W83627DHG_P_ID 0xb070 |
97 | #define SIO_W83667HG_ID 0xa510 | 103 | #define SIO_W83667HG_ID 0xa510 |
98 | #define SIO_W83667HG_B_ID 0xb350 | 104 | #define SIO_W83667HG_B_ID 0xb350 |
105 | #define SIO_NCT6775_ID 0xb470 | ||
106 | #define SIO_NCT6776_ID 0xc330 | ||
99 | #define SIO_ID_MASK 0xFFF0 | 107 | #define SIO_ID_MASK 0xFFF0 |
100 | 108 | ||
101 | static inline void | 109 | static inline void |
@@ -176,6 +184,10 @@ static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 }; | |||
176 | #define W83627EHF_REG_DIODE 0x59 | 184 | #define W83627EHF_REG_DIODE 0x59 |
177 | #define W83627EHF_REG_SMI_OVT 0x4C | 185 | #define W83627EHF_REG_SMI_OVT 0x4C |
178 | 186 | ||
187 | /* NCT6775F has its own fan divider registers */ | ||
188 | #define NCT6775_REG_FANDIV1 0x506 | ||
189 | #define NCT6775_REG_FANDIV2 0x507 | ||
190 | |||
179 | #define W83627EHF_REG_ALARM1 0x459 | 191 | #define W83627EHF_REG_ALARM1 0x459 |
180 | #define W83627EHF_REG_ALARM2 0x45A | 192 | #define W83627EHF_REG_ALARM2 0x45A |
181 | #define W83627EHF_REG_ALARM3 0x45B | 193 | #define W83627EHF_REG_ALARM3 0x45B |
@@ -214,6 +226,28 @@ static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b }; | |||
214 | static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] | 226 | static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] |
215 | = { 0x68, 0x6a, 0x6c }; | 227 | = { 0x68, 0x6a, 0x6c }; |
216 | 228 | ||
229 | static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301 }; | ||
230 | static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302 }; | ||
231 | static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = { 0x105, 0x205, 0x305 }; | ||
232 | static const u16 NCT6775_REG_FAN_START_OUTPUT[] = { 0x106, 0x206, 0x306 }; | ||
233 | static const u16 NCT6775_REG_FAN_STOP_TIME[] = { 0x107, 0x207, 0x307 }; | ||
234 | static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309 }; | ||
235 | static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a }; | ||
236 | static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b }; | ||
237 | static const u16 NCT6776_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 }; | ||
238 | static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642}; | ||
239 | |||
240 | static const u16 NCT6775_REG_TEMP[] | ||
241 | = { 0x27, 0x150, 0x250, 0x73, 0x75, 0x77, 0x62b, 0x62c, 0x62d }; | ||
242 | static const u16 NCT6775_REG_TEMP_CONFIG[] | ||
243 | = { 0, 0x152, 0x252, 0, 0, 0, 0x628, 0x629, 0x62A }; | ||
244 | static const u16 NCT6775_REG_TEMP_HYST[] | ||
245 | = { 0x3a, 0x153, 0x253, 0, 0, 0, 0x673, 0x678, 0x67D }; | ||
246 | static const u16 NCT6775_REG_TEMP_OVER[] | ||
247 | = { 0x39, 0x155, 0x255, 0, 0, 0, 0x672, 0x677, 0x67C }; | ||
248 | static const u16 NCT6775_REG_TEMP_SOURCE[] | ||
249 | = { 0x621, 0x622, 0x623, 0x100, 0x200, 0x300, 0x624, 0x625, 0x626 }; | ||
250 | |||
217 | static const char *const w83667hg_b_temp_label[] = { | 251 | static const char *const w83667hg_b_temp_label[] = { |
218 | "SYSTIN", | 252 | "SYSTIN", |
219 | "CPUTIN", | 253 | "CPUTIN", |
@@ -225,15 +259,71 @@ static const char *const w83667hg_b_temp_label[] = { | |||
225 | "PECI Agent 4" | 259 | "PECI Agent 4" |
226 | }; | 260 | }; |
227 | 261 | ||
228 | #define NUM_REG_TEMP 4 | 262 | static const char *const nct6775_temp_label[] = { |
263 | "", | ||
264 | "SYSTIN", | ||
265 | "CPUTIN", | ||
266 | "AUXTIN", | ||
267 | "AMD SB-TSI", | ||
268 | "PECI Agent 0", | ||
269 | "PECI Agent 1", | ||
270 | "PECI Agent 2", | ||
271 | "PECI Agent 3", | ||
272 | "PECI Agent 4", | ||
273 | "PECI Agent 5", | ||
274 | "PECI Agent 6", | ||
275 | "PECI Agent 7", | ||
276 | "PCH_CHIP_CPU_MAX_TEMP", | ||
277 | "PCH_CHIP_TEMP", | ||
278 | "PCH_CPU_TEMP", | ||
279 | "PCH_MCH_TEMP", | ||
280 | "PCH_DIM0_TEMP", | ||
281 | "PCH_DIM1_TEMP", | ||
282 | "PCH_DIM2_TEMP", | ||
283 | "PCH_DIM3_TEMP" | ||
284 | }; | ||
285 | |||
286 | static const char *const nct6776_temp_label[] = { | ||
287 | "", | ||
288 | "SYSTIN", | ||
289 | "CPUTIN", | ||
290 | "AUXTIN", | ||
291 | "SMBUSMASTER 0", | ||
292 | "SMBUSMASTER 1", | ||
293 | "SMBUSMASTER 2", | ||
294 | "SMBUSMASTER 3", | ||
295 | "SMBUSMASTER 4", | ||
296 | "SMBUSMASTER 5", | ||
297 | "SMBUSMASTER 6", | ||
298 | "SMBUSMASTER 7", | ||
299 | "PECI Agent 0", | ||
300 | "PECI Agent 1", | ||
301 | "PCH_CHIP_CPU_MAX_TEMP", | ||
302 | "PCH_CHIP_TEMP", | ||
303 | "PCH_CPU_TEMP", | ||
304 | "PCH_MCH_TEMP", | ||
305 | "PCH_DIM0_TEMP", | ||
306 | "PCH_DIM1_TEMP", | ||
307 | "PCH_DIM2_TEMP", | ||
308 | "PCH_DIM3_TEMP", | ||
309 | "BYTE_TEMP" | ||
310 | }; | ||
311 | |||
312 | #define NUM_REG_TEMP ARRAY_SIZE(NCT6775_REG_TEMP) | ||
229 | 313 | ||
230 | static inline int is_word_sized(u16 reg) | 314 | static inline int is_word_sized(u16 reg) |
231 | { | 315 | { |
232 | return (((reg & 0xff00) == 0x100 | 316 | return ((((reg & 0xff00) == 0x100 |
233 | || (reg & 0xff00) == 0x200) | 317 | || (reg & 0xff00) == 0x200) |
234 | && ((reg & 0x00ff) == 0x50 | 318 | && ((reg & 0x00ff) == 0x50 |
235 | || (reg & 0x00ff) == 0x53 | 319 | || (reg & 0x00ff) == 0x53 |
236 | || (reg & 0x00ff) == 0x55)); | 320 | || (reg & 0x00ff) == 0x55)) |
321 | || (reg & 0xfff0) == 0x630 | ||
322 | || reg == 0x640 || reg == 0x642 | ||
323 | || ((reg & 0xfff0) == 0x650 | ||
324 | && (reg & 0x000f) >= 0x06) | ||
325 | || reg == 0x73 || reg == 0x75 || reg == 0x77 | ||
326 | ); | ||
237 | } | 327 | } |
238 | 328 | ||
239 | /* | 329 | /* |
@@ -253,11 +343,20 @@ static inline u8 step_time_to_reg(unsigned int msec, u8 mode) | |||
253 | } | 343 | } |
254 | 344 | ||
255 | static inline unsigned int | 345 | static inline unsigned int |
256 | fan_from_reg(u8 reg, unsigned int div) | 346 | fan_from_reg(int reg, u16 val, unsigned int div) |
257 | { | 347 | { |
258 | if (reg == 0 || reg == 255) | 348 | if (val == 0) |
259 | return 0; | 349 | return 0; |
260 | return 1350000U / (reg * div); | 350 | if (is_word_sized(reg)) { |
351 | if ((val & 0xff1f) == 0xff1f) | ||
352 | return 0; | ||
353 | val = (val & 0x1f) | ((val & 0xff00) >> 3); | ||
354 | } else { | ||
355 | if (val == 255 || div == 0) | ||
356 | return 0; | ||
357 | val *= div; | ||
358 | } | ||
359 | return 1350000U / val; | ||
261 | } | 360 | } |
262 | 361 | ||
263 | static inline unsigned int | 362 | static inline unsigned int |
@@ -274,7 +373,7 @@ temp_from_reg(u16 reg, s16 regval) | |||
274 | return regval * 1000; | 373 | return regval * 1000; |
275 | } | 374 | } |
276 | 375 | ||
277 | static inline s16 | 376 | static inline u16 |
278 | temp_to_reg(u16 reg, long temp) | 377 | temp_to_reg(u16 reg, long temp) |
279 | { | 378 | { |
280 | if (is_word_sized(reg)) | 379 | if (is_word_sized(reg)) |
@@ -308,6 +407,10 @@ struct w83627ehf_data { | |||
308 | struct device *hwmon_dev; | 407 | struct device *hwmon_dev; |
309 | struct mutex lock; | 408 | struct mutex lock; |
310 | 409 | ||
410 | u16 reg_temp[NUM_REG_TEMP]; | ||
411 | u16 reg_temp_over[NUM_REG_TEMP]; | ||
412 | u16 reg_temp_hyst[NUM_REG_TEMP]; | ||
413 | u16 reg_temp_config[NUM_REG_TEMP]; | ||
311 | u8 temp_src[NUM_REG_TEMP]; | 414 | u8 temp_src[NUM_REG_TEMP]; |
312 | const char * const *temp_label; | 415 | const char * const *temp_label; |
313 | 416 | ||
@@ -331,14 +434,15 @@ struct w83627ehf_data { | |||
331 | u8 in[10]; /* Register value */ | 434 | u8 in[10]; /* Register value */ |
332 | u8 in_max[10]; /* Register value */ | 435 | u8 in_max[10]; /* Register value */ |
333 | u8 in_min[10]; /* Register value */ | 436 | u8 in_min[10]; /* Register value */ |
334 | u8 fan[5]; | 437 | u16 fan[5]; |
335 | u8 fan_min[5]; | 438 | u16 fan_min[5]; |
336 | u8 fan_div[5]; | 439 | u8 fan_div[5]; |
337 | u8 has_fan; /* some fan inputs can be disabled */ | 440 | u8 has_fan; /* some fan inputs can be disabled */ |
441 | u8 has_fan_min; /* some fans don't have min register */ | ||
338 | u8 temp_type[3]; | 442 | u8 temp_type[3]; |
339 | s16 temp[4]; | 443 | s16 temp[9]; |
340 | s16 temp_max[4]; | 444 | s16 temp_max[9]; |
341 | s16 temp_max_hyst[4]; | 445 | s16 temp_max_hyst[9]; |
342 | u32 alarms; | 446 | u32 alarms; |
343 | 447 | ||
344 | u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ | 448 | u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ |
@@ -364,7 +468,7 @@ struct w83627ehf_data { | |||
364 | u8 vid; | 468 | u8 vid; |
365 | u8 vrm; | 469 | u8 vrm; |
366 | 470 | ||
367 | u8 have_temp; | 471 | u16 have_temp; |
368 | u8 in6_skip; | 472 | u8 in6_skip; |
369 | }; | 473 | }; |
370 | 474 | ||
@@ -429,6 +533,34 @@ static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, | |||
429 | } | 533 | } |
430 | 534 | ||
431 | /* This function assumes that the caller holds data->update_lock */ | 535 | /* This function assumes that the caller holds data->update_lock */ |
536 | static void nct6775_write_fan_div(struct w83627ehf_data *data, int nr) | ||
537 | { | ||
538 | u8 reg; | ||
539 | |||
540 | switch (nr) { | ||
541 | case 0: | ||
542 | reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x70) | ||
543 | | (data->fan_div[0] & 0x7); | ||
544 | w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg); | ||
545 | break; | ||
546 | case 1: | ||
547 | reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x7) | ||
548 | | ((data->fan_div[1] << 4) & 0x70); | ||
549 | w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg); | ||
550 | case 2: | ||
551 | reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x70) | ||
552 | | (data->fan_div[2] & 0x7); | ||
553 | w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg); | ||
554 | break; | ||
555 | case 3: | ||
556 | reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x7) | ||
557 | | ((data->fan_div[3] << 4) & 0x70); | ||
558 | w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg); | ||
559 | break; | ||
560 | } | ||
561 | } | ||
562 | |||
563 | /* This function assumes that the caller holds data->update_lock */ | ||
432 | static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr) | 564 | static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr) |
433 | { | 565 | { |
434 | u8 reg; | 566 | u8 reg; |
@@ -479,6 +611,32 @@ static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr) | |||
479 | } | 611 | } |
480 | } | 612 | } |
481 | 613 | ||
614 | static void w83627ehf_write_fan_div_common(struct device *dev, | ||
615 | struct w83627ehf_data *data, int nr) | ||
616 | { | ||
617 | struct w83627ehf_sio_data *sio_data = dev->platform_data; | ||
618 | |||
619 | if (sio_data->kind == nct6776) | ||
620 | ; /* no dividers, do nothing */ | ||
621 | else if (sio_data->kind == nct6775) | ||
622 | nct6775_write_fan_div(data, nr); | ||
623 | else | ||
624 | w83627ehf_write_fan_div(data, nr); | ||
625 | } | ||
626 | |||
627 | static void nct6775_update_fan_div(struct w83627ehf_data *data) | ||
628 | { | ||
629 | u8 i; | ||
630 | |||
631 | i = w83627ehf_read_value(data, NCT6775_REG_FANDIV1); | ||
632 | data->fan_div[0] = i & 0x7; | ||
633 | data->fan_div[1] = (i & 0x70) >> 4; | ||
634 | i = w83627ehf_read_value(data, NCT6775_REG_FANDIV2); | ||
635 | data->fan_div[2] = i & 0x7; | ||
636 | if (data->has_fan & (1<<3)) | ||
637 | data->fan_div[3] = (i & 0x70) >> 4; | ||
638 | } | ||
639 | |||
482 | static void w83627ehf_update_fan_div(struct w83627ehf_data *data) | 640 | static void w83627ehf_update_fan_div(struct w83627ehf_data *data) |
483 | { | 641 | { |
484 | int i; | 642 | int i; |
@@ -504,10 +662,79 @@ static void w83627ehf_update_fan_div(struct w83627ehf_data *data) | |||
504 | } | 662 | } |
505 | } | 663 | } |
506 | 664 | ||
665 | static void w83627ehf_update_fan_div_common(struct device *dev, | ||
666 | struct w83627ehf_data *data) | ||
667 | { | ||
668 | struct w83627ehf_sio_data *sio_data = dev->platform_data; | ||
669 | |||
670 | if (sio_data->kind == nct6776) | ||
671 | ; /* no dividers, do nothing */ | ||
672 | else if (sio_data->kind == nct6775) | ||
673 | nct6775_update_fan_div(data); | ||
674 | else | ||
675 | w83627ehf_update_fan_div(data); | ||
676 | } | ||
677 | |||
678 | static void nct6775_update_pwm(struct w83627ehf_data *data) | ||
679 | { | ||
680 | int i; | ||
681 | int pwmcfg, fanmodecfg; | ||
682 | |||
683 | for (i = 0; i < data->pwm_num; i++) { | ||
684 | pwmcfg = w83627ehf_read_value(data, | ||
685 | W83627EHF_REG_PWM_ENABLE[i]); | ||
686 | fanmodecfg = w83627ehf_read_value(data, | ||
687 | NCT6775_REG_FAN_MODE[i]); | ||
688 | data->pwm_mode[i] = | ||
689 | ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1; | ||
690 | data->pwm_enable[i] = ((fanmodecfg >> 4) & 7) + 1; | ||
691 | data->tolerance[i] = fanmodecfg & 0x0f; | ||
692 | data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]); | ||
693 | } | ||
694 | } | ||
695 | |||
696 | static void w83627ehf_update_pwm(struct w83627ehf_data *data) | ||
697 | { | ||
698 | int i; | ||
699 | int pwmcfg = 0, tolerance = 0; /* shut up the compiler */ | ||
700 | |||
701 | for (i = 0; i < data->pwm_num; i++) { | ||
702 | if (!(data->has_fan & (1 << i))) | ||
703 | continue; | ||
704 | |||
705 | /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */ | ||
706 | if (i != 1) { | ||
707 | pwmcfg = w83627ehf_read_value(data, | ||
708 | W83627EHF_REG_PWM_ENABLE[i]); | ||
709 | tolerance = w83627ehf_read_value(data, | ||
710 | W83627EHF_REG_TOLERANCE[i]); | ||
711 | } | ||
712 | data->pwm_mode[i] = | ||
713 | ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1; | ||
714 | data->pwm_enable[i] = ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i]) | ||
715 | & 3) + 1; | ||
716 | data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]); | ||
717 | |||
718 | data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0)) & 0x0f; | ||
719 | } | ||
720 | } | ||
721 | |||
722 | static void w83627ehf_update_pwm_common(struct device *dev, | ||
723 | struct w83627ehf_data *data) | ||
724 | { | ||
725 | struct w83627ehf_sio_data *sio_data = dev->platform_data; | ||
726 | |||
727 | if (sio_data->kind == nct6775 || sio_data->kind == nct6776) | ||
728 | nct6775_update_pwm(data); | ||
729 | else | ||
730 | w83627ehf_update_pwm(data); | ||
731 | } | ||
732 | |||
507 | static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | 733 | static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) |
508 | { | 734 | { |
509 | struct w83627ehf_data *data = dev_get_drvdata(dev); | 735 | struct w83627ehf_data *data = dev_get_drvdata(dev); |
510 | int pwmcfg = 0, tolerance = 0; /* shut up the compiler */ | 736 | struct w83627ehf_sio_data *sio_data = dev->platform_data; |
737 | |||
511 | int i; | 738 | int i; |
512 | 739 | ||
513 | mutex_lock(&data->update_lock); | 740 | mutex_lock(&data->update_lock); |
@@ -515,7 +742,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | |||
515 | if (time_after(jiffies, data->last_updated + HZ + HZ/2) | 742 | if (time_after(jiffies, data->last_updated + HZ + HZ/2) |
516 | || !data->valid) { | 743 | || !data->valid) { |
517 | /* Fan clock dividers */ | 744 | /* Fan clock dividers */ |
518 | w83627ehf_update_fan_div(data); | 745 | w83627ehf_update_fan_div_common(dev, data); |
519 | 746 | ||
520 | /* Measured voltages and limits */ | 747 | /* Measured voltages and limits */ |
521 | for (i = 0; i < data->in_num; i++) { | 748 | for (i = 0; i < data->in_num; i++) { |
@@ -533,23 +760,29 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | |||
533 | continue; | 760 | continue; |
534 | 761 | ||
535 | data->fan[i] = w83627ehf_read_value(data, | 762 | data->fan[i] = w83627ehf_read_value(data, |
536 | data->REG_FAN[i]); | 763 | data->REG_FAN[i]); |
537 | data->fan_min[i] = w83627ehf_read_value(data, | 764 | |
765 | if (data->has_fan_min & (1 << i)) | ||
766 | data->fan_min[i] = w83627ehf_read_value(data, | ||
538 | data->REG_FAN_MIN[i]); | 767 | data->REG_FAN_MIN[i]); |
539 | 768 | ||
540 | /* If we failed to measure the fan speed and clock | 769 | /* If we failed to measure the fan speed and clock |
541 | divider can be increased, let's try that for next | 770 | divider can be increased, let's try that for next |
542 | time */ | 771 | time */ |
543 | if (data->fan[i] == 0xff | 772 | if (!is_word_sized(data->REG_FAN[i]) |
544 | && data->fan_div[i] < 0x07) { | 773 | && (data->fan[i] == 0xff |
774 | || (sio_data->kind == nct6775 | ||
775 | && data->fan[i] == 0x00)) | ||
776 | && data->fan_div[i] < 0x07) { | ||
545 | dev_dbg(dev, "Increasing fan%d " | 777 | dev_dbg(dev, "Increasing fan%d " |
546 | "clock divider from %u to %u\n", | 778 | "clock divider from %u to %u\n", |
547 | i + 1, div_from_reg(data->fan_div[i]), | 779 | i + 1, div_from_reg(data->fan_div[i]), |
548 | div_from_reg(data->fan_div[i] + 1)); | 780 | div_from_reg(data->fan_div[i] + 1)); |
549 | data->fan_div[i]++; | 781 | data->fan_div[i]++; |
550 | w83627ehf_write_fan_div(data, i); | 782 | w83627ehf_write_fan_div_common(dev, data, i); |
551 | /* Preserve min limit if possible */ | 783 | /* Preserve min limit if possible */ |
552 | if (data->fan_min[i] >= 2 | 784 | if ((data->has_fan_min & (1 << i)) |
785 | && data->fan_min[i] >= 2 | ||
553 | && data->fan_min[i] != 255) | 786 | && data->fan_min[i] != 255) |
554 | w83627ehf_write_value(data, | 787 | w83627ehf_write_value(data, |
555 | data->REG_FAN_MIN[i], | 788 | data->REG_FAN_MIN[i], |
@@ -557,64 +790,54 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | |||
557 | } | 790 | } |
558 | } | 791 | } |
559 | 792 | ||
793 | w83627ehf_update_pwm_common(dev, data); | ||
794 | |||
560 | for (i = 0; i < data->pwm_num; i++) { | 795 | for (i = 0; i < data->pwm_num; i++) { |
561 | if (!(data->has_fan & (1 << i))) | 796 | if (!(data->has_fan & (1 << i))) |
562 | continue; | 797 | continue; |
563 | 798 | ||
564 | /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */ | 799 | data->fan_start_output[i] = |
565 | if (i != 1) { | 800 | w83627ehf_read_value(data, |
566 | pwmcfg = w83627ehf_read_value(data, | 801 | data->REG_FAN_START_OUTPUT[i]); |
567 | W83627EHF_REG_PWM_ENABLE[i]); | 802 | data->fan_stop_output[i] = |
568 | tolerance = w83627ehf_read_value(data, | 803 | w83627ehf_read_value(data, |
569 | W83627EHF_REG_TOLERANCE[i]); | 804 | data->REG_FAN_STOP_OUTPUT[i]); |
570 | } | 805 | data->fan_stop_time[i] = |
571 | data->pwm_mode[i] = | 806 | w83627ehf_read_value(data, |
572 | ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) | 807 | data->REG_FAN_STOP_TIME[i]); |
573 | ? 0 : 1; | 808 | |
574 | data->pwm_enable[i] = | 809 | if (data->REG_FAN_MAX_OUTPUT && |
575 | ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i]) | 810 | data->REG_FAN_MAX_OUTPUT[i] != 0xff) |
576 | & 3) + 1; | ||
577 | data->pwm[i] = w83627ehf_read_value(data, | ||
578 | data->REG_PWM[i]); | ||
579 | data->fan_start_output[i] = w83627ehf_read_value(data, | ||
580 | data->REG_FAN_START_OUTPUT[i]); | ||
581 | data->fan_stop_output[i] = w83627ehf_read_value(data, | ||
582 | data->REG_FAN_STOP_OUTPUT[i]); | ||
583 | data->fan_stop_time[i] = w83627ehf_read_value(data, | ||
584 | data->REG_FAN_STOP_TIME[i]); | ||
585 | |||
586 | if (data->REG_FAN_MAX_OUTPUT[i] != 0xff) | ||
587 | data->fan_max_output[i] = | 811 | data->fan_max_output[i] = |
588 | w83627ehf_read_value(data, | 812 | w83627ehf_read_value(data, |
589 | data->REG_FAN_MAX_OUTPUT[i]); | 813 | data->REG_FAN_MAX_OUTPUT[i]); |
590 | 814 | ||
591 | if (data->REG_FAN_STEP_OUTPUT[i] != 0xff) | 815 | if (data->REG_FAN_STEP_OUTPUT && |
816 | data->REG_FAN_STEP_OUTPUT[i] != 0xff) | ||
592 | data->fan_step_output[i] = | 817 | data->fan_step_output[i] = |
593 | w83627ehf_read_value(data, | 818 | w83627ehf_read_value(data, |
594 | data->REG_FAN_STEP_OUTPUT[i]); | 819 | data->REG_FAN_STEP_OUTPUT[i]); |
595 | 820 | ||
596 | data->target_temp[i] = | 821 | data->target_temp[i] = |
597 | w83627ehf_read_value(data, | 822 | w83627ehf_read_value(data, |
598 | data->REG_TARGET[i]) & | 823 | data->REG_TARGET[i]) & |
599 | (data->pwm_mode[i] == 1 ? 0x7f : 0xff); | 824 | (data->pwm_mode[i] == 1 ? 0x7f : 0xff); |
600 | data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0)) | ||
601 | & 0x0f; | ||
602 | } | 825 | } |
603 | 826 | ||
604 | /* Measured temperatures and limits */ | 827 | /* Measured temperatures and limits */ |
605 | for (i = 0; i < NUM_REG_TEMP; i++) { | 828 | for (i = 0; i < NUM_REG_TEMP; i++) { |
606 | if (!(data->have_temp & (1 << i))) | 829 | if (!(data->have_temp & (1 << i))) |
607 | continue; | 830 | continue; |
608 | data->temp[i] | 831 | data->temp[i] = w83627ehf_read_value(data, |
609 | = w83627ehf_read_value(data, W83627EHF_REG_TEMP[i]); | 832 | data->reg_temp[i]); |
610 | if (i > 2) | 833 | if (data->reg_temp_over[i]) |
611 | break; | 834 | data->temp_max[i] |
612 | data->temp_max[i] | 835 | = w83627ehf_read_value(data, |
613 | = w83627ehf_read_value(data, | 836 | data->reg_temp_over[i]); |
614 | W83627EHF_REG_TEMP_OVER[i]); | 837 | if (data->reg_temp_hyst[i]) |
615 | data->temp_max_hyst[i] | 838 | data->temp_max_hyst[i] |
616 | = w83627ehf_read_value(data, | 839 | = w83627ehf_read_value(data, |
617 | W83627EHF_REG_TEMP_HYST[i]); | 840 | data->reg_temp_hyst[i]); |
618 | } | 841 | } |
619 | 842 | ||
620 | data->alarms = w83627ehf_read_value(data, | 843 | data->alarms = w83627ehf_read_value(data, |
@@ -736,21 +959,29 @@ static struct sensor_device_attribute sda_in_max[] = { | |||
736 | SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9), | 959 | SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9), |
737 | }; | 960 | }; |
738 | 961 | ||
739 | #define show_fan_reg(reg) \ | 962 | static ssize_t |
740 | static ssize_t \ | 963 | show_fan(struct device *dev, struct device_attribute *attr, char *buf) |
741 | show_##reg(struct device *dev, struct device_attribute *attr, \ | 964 | { |
742 | char *buf) \ | 965 | struct w83627ehf_data *data = w83627ehf_update_device(dev); |
743 | { \ | 966 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); |
744 | struct w83627ehf_data *data = w83627ehf_update_device(dev); \ | 967 | int nr = sensor_attr->index; |
745 | struct sensor_device_attribute *sensor_attr = \ | 968 | return sprintf(buf, "%d\n", |
746 | to_sensor_dev_attr(attr); \ | 969 | fan_from_reg(data->REG_FAN[nr], |
747 | int nr = sensor_attr->index; \ | 970 | data->fan[nr], |
748 | return sprintf(buf, "%d\n", \ | 971 | div_from_reg(data->fan_div[nr]))); |
749 | fan_from_reg(data->reg[nr], \ | 972 | } |
750 | div_from_reg(data->fan_div[nr]))); \ | 973 | |
974 | static ssize_t | ||
975 | show_fan_min(struct device *dev, struct device_attribute *attr, char *buf) | ||
976 | { | ||
977 | struct w83627ehf_data *data = w83627ehf_update_device(dev); | ||
978 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
979 | int nr = sensor_attr->index; | ||
980 | return sprintf(buf, "%d\n", | ||
981 | fan_from_reg(data->REG_FAN_MIN[nr], | ||
982 | data->fan_min[nr], | ||
983 | div_from_reg(data->fan_div[nr]))); | ||
751 | } | 984 | } |
752 | show_fan_reg(fan); | ||
753 | show_fan_reg(fan_min); | ||
754 | 985 | ||
755 | static ssize_t | 986 | static ssize_t |
756 | show_fan_div(struct device *dev, struct device_attribute *attr, | 987 | show_fan_div(struct device *dev, struct device_attribute *attr, |
@@ -779,6 +1010,18 @@ store_fan_min(struct device *dev, struct device_attribute *attr, | |||
779 | return err; | 1010 | return err; |
780 | 1011 | ||
781 | mutex_lock(&data->update_lock); | 1012 | mutex_lock(&data->update_lock); |
1013 | if (is_word_sized(data->REG_FAN_MIN[nr])) { | ||
1014 | if (!val) { | ||
1015 | val = 0xff1f; | ||
1016 | } else { | ||
1017 | if (val > 1350000U) | ||
1018 | val = 135000U; | ||
1019 | val = 1350000U / val; | ||
1020 | val = (val & 0x1f) | ((val << 3) & 0xff00); | ||
1021 | } | ||
1022 | data->fan_min[nr] = val; | ||
1023 | goto done; /* Leave fan divider alone */ | ||
1024 | } | ||
782 | if (!val) { | 1025 | if (!val) { |
783 | /* No min limit, alarm disabled */ | 1026 | /* No min limit, alarm disabled */ |
784 | data->fan_min[nr] = 255; | 1027 | data->fan_min[nr] = 255; |
@@ -790,14 +1033,16 @@ store_fan_min(struct device *dev, struct device_attribute *attr, | |||
790 | data->fan_min[nr] = 254; | 1033 | data->fan_min[nr] = 254; |
791 | new_div = 7; /* 128 == (1 << 7) */ | 1034 | new_div = 7; /* 128 == (1 << 7) */ |
792 | dev_warn(dev, "fan%u low limit %lu below minimum %u, set to " | 1035 | dev_warn(dev, "fan%u low limit %lu below minimum %u, set to " |
793 | "minimum\n", nr + 1, val, fan_from_reg(254, 128)); | 1036 | "minimum\n", nr + 1, val, |
1037 | fan_from_reg(data->REG_FAN_MIN[nr], 254, 128)); | ||
794 | } else if (!reg) { | 1038 | } else if (!reg) { |
795 | /* Speed above this value cannot possibly be represented, | 1039 | /* Speed above this value cannot possibly be represented, |
796 | even with the lowest divider (1) */ | 1040 | even with the lowest divider (1) */ |
797 | data->fan_min[nr] = 1; | 1041 | data->fan_min[nr] = 1; |
798 | new_div = 0; /* 1 == (1 << 0) */ | 1042 | new_div = 0; /* 1 == (1 << 0) */ |
799 | dev_warn(dev, "fan%u low limit %lu above maximum %u, set to " | 1043 | dev_warn(dev, "fan%u low limit %lu above maximum %u, set to " |
800 | "maximum\n", nr + 1, val, fan_from_reg(1, 1)); | 1044 | "maximum\n", nr + 1, val, |
1045 | fan_from_reg(data->REG_FAN_MIN[nr], 1, 1)); | ||
801 | } else { | 1046 | } else { |
802 | /* Automatically pick the best divider, i.e. the one such | 1047 | /* Automatically pick the best divider, i.e. the one such |
803 | that the min limit will correspond to a register value | 1048 | that the min limit will correspond to a register value |
@@ -827,10 +1072,11 @@ store_fan_min(struct device *dev, struct device_attribute *attr, | |||
827 | nr + 1, div_from_reg(data->fan_div[nr]), | 1072 | nr + 1, div_from_reg(data->fan_div[nr]), |
828 | div_from_reg(new_div)); | 1073 | div_from_reg(new_div)); |
829 | data->fan_div[nr] = new_div; | 1074 | data->fan_div[nr] = new_div; |
830 | w83627ehf_write_fan_div(data, nr); | 1075 | w83627ehf_write_fan_div_common(dev, data, nr); |
831 | /* Give the chip time to sample a new speed value */ | 1076 | /* Give the chip time to sample a new speed value */ |
832 | data->last_updated = jiffies; | 1077 | data->last_updated = jiffies; |
833 | } | 1078 | } |
1079 | done: | ||
834 | w83627ehf_write_value(data, data->REG_FAN_MIN[nr], | 1080 | w83627ehf_write_value(data, data->REG_FAN_MIN[nr], |
835 | data->fan_min[nr]); | 1081 | data->fan_min[nr]); |
836 | mutex_unlock(&data->update_lock); | 1082 | mutex_unlock(&data->update_lock); |
@@ -884,7 +1130,7 @@ show_temp_label(struct device *dev, struct device_attribute *attr, char *buf) | |||
884 | return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]); | 1130 | return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]); |
885 | } | 1131 | } |
886 | 1132 | ||
887 | #define show_temp_reg(REG, reg) \ | 1133 | #define show_temp_reg(addr, reg) \ |
888 | static ssize_t \ | 1134 | static ssize_t \ |
889 | show_##reg(struct device *dev, struct device_attribute *attr, \ | 1135 | show_##reg(struct device *dev, struct device_attribute *attr, \ |
890 | char *buf) \ | 1136 | char *buf) \ |
@@ -894,13 +1140,13 @@ show_##reg(struct device *dev, struct device_attribute *attr, \ | |||
894 | to_sensor_dev_attr(attr); \ | 1140 | to_sensor_dev_attr(attr); \ |
895 | int nr = sensor_attr->index; \ | 1141 | int nr = sensor_attr->index; \ |
896 | return sprintf(buf, "%d\n", \ | 1142 | return sprintf(buf, "%d\n", \ |
897 | temp_from_reg(W83627EHF_REG_##REG[nr], data->reg[nr])); \ | 1143 | temp_from_reg(data->addr[nr], data->reg[nr])); \ |
898 | } | 1144 | } |
899 | show_temp_reg(TEMP, temp); | 1145 | show_temp_reg(reg_temp, temp); |
900 | show_temp_reg(TEMP_OVER, temp_max); | 1146 | show_temp_reg(reg_temp_over, temp_max); |
901 | show_temp_reg(TEMP_HYST, temp_max_hyst); | 1147 | show_temp_reg(reg_temp_hyst, temp_max_hyst); |
902 | 1148 | ||
903 | #define store_temp_reg(REG, reg) \ | 1149 | #define store_temp_reg(addr, reg) \ |
904 | static ssize_t \ | 1150 | static ssize_t \ |
905 | store_##reg(struct device *dev, struct device_attribute *attr, \ | 1151 | store_##reg(struct device *dev, struct device_attribute *attr, \ |
906 | const char *buf, size_t count) \ | 1152 | const char *buf, size_t count) \ |
@@ -915,14 +1161,14 @@ store_##reg(struct device *dev, struct device_attribute *attr, \ | |||
915 | if (err < 0) \ | 1161 | if (err < 0) \ |
916 | return err; \ | 1162 | return err; \ |
917 | mutex_lock(&data->update_lock); \ | 1163 | mutex_lock(&data->update_lock); \ |
918 | data->reg[nr] = temp_to_reg(W83627EHF_REG_TEMP_##REG[nr], val); \ | 1164 | data->reg[nr] = temp_to_reg(data->addr[nr], val); \ |
919 | w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \ | 1165 | w83627ehf_write_value(data, data->addr[nr], \ |
920 | data->reg[nr]); \ | 1166 | data->reg[nr]); \ |
921 | mutex_unlock(&data->update_lock); \ | 1167 | mutex_unlock(&data->update_lock); \ |
922 | return count; \ | 1168 | return count; \ |
923 | } | 1169 | } |
924 | store_temp_reg(OVER, temp_max); | 1170 | store_temp_reg(reg_temp_over, temp_max); |
925 | store_temp_reg(HYST, temp_max_hyst); | 1171 | store_temp_reg(reg_temp_hyst, temp_max_hyst); |
926 | 1172 | ||
927 | static ssize_t | 1173 | static ssize_t |
928 | show_temp_type(struct device *dev, struct device_attribute *attr, char *buf) | 1174 | show_temp_type(struct device *dev, struct device_attribute *attr, char *buf) |
@@ -938,6 +1184,11 @@ static struct sensor_device_attribute sda_temp_input[] = { | |||
938 | SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1), | 1184 | SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1), |
939 | SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2), | 1185 | SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2), |
940 | SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3), | 1186 | SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3), |
1187 | SENSOR_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4), | ||
1188 | SENSOR_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5), | ||
1189 | SENSOR_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6), | ||
1190 | SENSOR_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7), | ||
1191 | SENSOR_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8), | ||
941 | }; | 1192 | }; |
942 | 1193 | ||
943 | static struct sensor_device_attribute sda_temp_label[] = { | 1194 | static struct sensor_device_attribute sda_temp_label[] = { |
@@ -945,6 +1196,11 @@ static struct sensor_device_attribute sda_temp_label[] = { | |||
945 | SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1), | 1196 | SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1), |
946 | SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2), | 1197 | SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2), |
947 | SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3), | 1198 | SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3), |
1199 | SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4), | ||
1200 | SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5), | ||
1201 | SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6), | ||
1202 | SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7), | ||
1203 | SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8), | ||
948 | }; | 1204 | }; |
949 | 1205 | ||
950 | static struct sensor_device_attribute sda_temp_max[] = { | 1206 | static struct sensor_device_attribute sda_temp_max[] = { |
@@ -954,6 +1210,18 @@ static struct sensor_device_attribute sda_temp_max[] = { | |||
954 | store_temp_max, 1), | 1210 | store_temp_max, 1), |
955 | SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max, | 1211 | SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max, |
956 | store_temp_max, 2), | 1212 | store_temp_max, 2), |
1213 | SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR, show_temp_max, | ||
1214 | store_temp_max, 3), | ||
1215 | SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR, show_temp_max, | ||
1216 | store_temp_max, 4), | ||
1217 | SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR, show_temp_max, | ||
1218 | store_temp_max, 5), | ||
1219 | SENSOR_ATTR(temp7_max, S_IRUGO | S_IWUSR, show_temp_max, | ||
1220 | store_temp_max, 6), | ||
1221 | SENSOR_ATTR(temp8_max, S_IRUGO | S_IWUSR, show_temp_max, | ||
1222 | store_temp_max, 7), | ||
1223 | SENSOR_ATTR(temp9_max, S_IRUGO | S_IWUSR, show_temp_max, | ||
1224 | store_temp_max, 8), | ||
957 | }; | 1225 | }; |
958 | 1226 | ||
959 | static struct sensor_device_attribute sda_temp_max_hyst[] = { | 1227 | static struct sensor_device_attribute sda_temp_max_hyst[] = { |
@@ -963,6 +1231,18 @@ static struct sensor_device_attribute sda_temp_max_hyst[] = { | |||
963 | store_temp_max_hyst, 1), | 1231 | store_temp_max_hyst, 1), |
964 | SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, | 1232 | SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, |
965 | store_temp_max_hyst, 2), | 1233 | store_temp_max_hyst, 2), |
1234 | SENSOR_ATTR(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, | ||
1235 | store_temp_max_hyst, 3), | ||
1236 | SENSOR_ATTR(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, | ||
1237 | store_temp_max_hyst, 4), | ||
1238 | SENSOR_ATTR(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, | ||
1239 | store_temp_max_hyst, 5), | ||
1240 | SENSOR_ATTR(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, | ||
1241 | store_temp_max_hyst, 6), | ||
1242 | SENSOR_ATTR(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, | ||
1243 | store_temp_max_hyst, 7), | ||
1244 | SENSOR_ATTR(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, | ||
1245 | store_temp_max_hyst, 8), | ||
966 | }; | 1246 | }; |
967 | 1247 | ||
968 | static struct sensor_device_attribute sda_temp_alarm[] = { | 1248 | static struct sensor_device_attribute sda_temp_alarm[] = { |
@@ -1048,6 +1328,7 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr, | |||
1048 | const char *buf, size_t count) | 1328 | const char *buf, size_t count) |
1049 | { | 1329 | { |
1050 | struct w83627ehf_data *data = dev_get_drvdata(dev); | 1330 | struct w83627ehf_data *data = dev_get_drvdata(dev); |
1331 | struct w83627ehf_sio_data *sio_data = dev->platform_data; | ||
1051 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | 1332 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); |
1052 | int nr = sensor_attr->index; | 1333 | int nr = sensor_attr->index; |
1053 | unsigned long val; | 1334 | unsigned long val; |
@@ -1060,12 +1341,25 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr, | |||
1060 | 1341 | ||
1061 | if (!val || (val > 4 && val != data->pwm_enable_orig[nr])) | 1342 | if (!val || (val > 4 && val != data->pwm_enable_orig[nr])) |
1062 | return -EINVAL; | 1343 | return -EINVAL; |
1344 | /* SmartFan III mode is not supported on NCT6776F */ | ||
1345 | if (sio_data->kind == nct6776 && val == 4) | ||
1346 | return -EINVAL; | ||
1347 | |||
1063 | mutex_lock(&data->update_lock); | 1348 | mutex_lock(&data->update_lock); |
1064 | reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]); | ||
1065 | data->pwm_enable[nr] = val; | 1349 | data->pwm_enable[nr] = val; |
1066 | reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]); | 1350 | if (sio_data->kind == nct6775 || sio_data->kind == nct6776) { |
1067 | reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr]; | 1351 | reg = w83627ehf_read_value(data, |
1068 | w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg); | 1352 | NCT6775_REG_FAN_MODE[nr]); |
1353 | reg &= 0x0f; | ||
1354 | reg |= (val - 1) << 4; | ||
1355 | w83627ehf_write_value(data, | ||
1356 | NCT6775_REG_FAN_MODE[nr], reg); | ||
1357 | } else { | ||
1358 | reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]); | ||
1359 | reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]); | ||
1360 | reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr]; | ||
1361 | w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg); | ||
1362 | } | ||
1069 | mutex_unlock(&data->update_lock); | 1363 | mutex_unlock(&data->update_lock); |
1070 | return count; | 1364 | return count; |
1071 | } | 1365 | } |
@@ -1113,6 +1407,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr, | |||
1113 | const char *buf, size_t count) | 1407 | const char *buf, size_t count) |
1114 | { | 1408 | { |
1115 | struct w83627ehf_data *data = dev_get_drvdata(dev); | 1409 | struct w83627ehf_data *data = dev_get_drvdata(dev); |
1410 | struct w83627ehf_sio_data *sio_data = dev->platform_data; | ||
1116 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | 1411 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); |
1117 | int nr = sensor_attr->index; | 1412 | int nr = sensor_attr->index; |
1118 | u16 reg; | 1413 | u16 reg; |
@@ -1127,13 +1422,22 @@ store_tolerance(struct device *dev, struct device_attribute *attr, | |||
1127 | val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15); | 1422 | val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15); |
1128 | 1423 | ||
1129 | mutex_lock(&data->update_lock); | 1424 | mutex_lock(&data->update_lock); |
1130 | reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]); | 1425 | if (sio_data->kind == nct6775 || sio_data->kind == nct6776) { |
1131 | data->tolerance[nr] = val; | 1426 | /* Limit tolerance further for NCT6776F */ |
1132 | if (nr == 1) | 1427 | if (sio_data->kind == nct6776 && val > 7) |
1133 | reg = (reg & 0x0f) | (val << 4); | 1428 | val = 7; |
1134 | else | 1429 | reg = w83627ehf_read_value(data, NCT6775_REG_FAN_MODE[nr]); |
1135 | reg = (reg & 0xf0) | val; | 1430 | reg = (reg & 0xf0) | val; |
1136 | w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg); | 1431 | w83627ehf_write_value(data, NCT6775_REG_FAN_MODE[nr], reg); |
1432 | } else { | ||
1433 | reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]); | ||
1434 | if (nr == 1) | ||
1435 | reg = (reg & 0x0f) | (val << 4); | ||
1436 | else | ||
1437 | reg = (reg & 0xf0) | val; | ||
1438 | w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg); | ||
1439 | } | ||
1440 | data->tolerance[nr] = val; | ||
1137 | mutex_unlock(&data->update_lock); | 1441 | mutex_unlock(&data->update_lock); |
1138 | return count; | 1442 | return count; |
1139 | } | 1443 | } |
@@ -1350,7 +1654,8 @@ static void w83627ehf_device_remove_files(struct device *dev) | |||
1350 | for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) { | 1654 | for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) { |
1351 | struct sensor_device_attribute *attr = | 1655 | struct sensor_device_attribute *attr = |
1352 | &sda_sf3_max_step_arrays[i]; | 1656 | &sda_sf3_max_step_arrays[i]; |
1353 | if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) | 1657 | if (data->REG_FAN_STEP_OUTPUT && |
1658 | data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) | ||
1354 | device_remove_file(dev, &attr->dev_attr); | 1659 | device_remove_file(dev, &attr->dev_attr); |
1355 | } | 1660 | } |
1356 | for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) | 1661 | for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) |
@@ -1381,10 +1686,10 @@ static void w83627ehf_device_remove_files(struct device *dev) | |||
1381 | continue; | 1686 | continue; |
1382 | device_remove_file(dev, &sda_temp_input[i].dev_attr); | 1687 | device_remove_file(dev, &sda_temp_input[i].dev_attr); |
1383 | device_remove_file(dev, &sda_temp_label[i].dev_attr); | 1688 | device_remove_file(dev, &sda_temp_label[i].dev_attr); |
1384 | if (i > 2) | ||
1385 | break; | ||
1386 | device_remove_file(dev, &sda_temp_max[i].dev_attr); | 1689 | device_remove_file(dev, &sda_temp_max[i].dev_attr); |
1387 | device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr); | 1690 | device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr); |
1691 | if (i > 2) | ||
1692 | continue; | ||
1388 | device_remove_file(dev, &sda_temp_alarm[i].dev_attr); | 1693 | device_remove_file(dev, &sda_temp_alarm[i].dev_attr); |
1389 | device_remove_file(dev, &sda_temp_type[i].dev_attr); | 1694 | device_remove_file(dev, &sda_temp_type[i].dev_attr); |
1390 | } | 1695 | } |
@@ -1409,13 +1714,13 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data) | |||
1409 | for (i = 0; i < NUM_REG_TEMP; i++) { | 1714 | for (i = 0; i < NUM_REG_TEMP; i++) { |
1410 | if (!(data->have_temp & (1 << i))) | 1715 | if (!(data->have_temp & (1 << i))) |
1411 | continue; | 1716 | continue; |
1412 | if (!W83627EHF_REG_TEMP_CONFIG[i]) | 1717 | if (!data->reg_temp_config[i]) |
1413 | continue; | 1718 | continue; |
1414 | tmp = w83627ehf_read_value(data, | 1719 | tmp = w83627ehf_read_value(data, |
1415 | W83627EHF_REG_TEMP_CONFIG[i]); | 1720 | data->reg_temp_config[i]); |
1416 | if (tmp & 0x01) | 1721 | if (tmp & 0x01) |
1417 | w83627ehf_write_value(data, | 1722 | w83627ehf_write_value(data, |
1418 | W83627EHF_REG_TEMP_CONFIG[i], | 1723 | data->reg_temp_config[i], |
1419 | tmp & 0xfe); | 1724 | tmp & 0xfe); |
1420 | } | 1725 | } |
1421 | 1726 | ||
@@ -1434,13 +1739,39 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data) | |||
1434 | } | 1739 | } |
1435 | } | 1740 | } |
1436 | 1741 | ||
1742 | static void w82627ehf_swap_tempreg(struct w83627ehf_data *data, | ||
1743 | int r1, int r2) | ||
1744 | { | ||
1745 | u16 tmp; | ||
1746 | |||
1747 | tmp = data->temp_src[r1]; | ||
1748 | data->temp_src[r1] = data->temp_src[r2]; | ||
1749 | data->temp_src[r2] = tmp; | ||
1750 | |||
1751 | tmp = data->reg_temp[r1]; | ||
1752 | data->reg_temp[r1] = data->reg_temp[r2]; | ||
1753 | data->reg_temp[r2] = tmp; | ||
1754 | |||
1755 | tmp = data->reg_temp_over[r1]; | ||
1756 | data->reg_temp_over[r1] = data->reg_temp_over[r2]; | ||
1757 | data->reg_temp_over[r2] = tmp; | ||
1758 | |||
1759 | tmp = data->reg_temp_hyst[r1]; | ||
1760 | data->reg_temp_hyst[r1] = data->reg_temp_hyst[r2]; | ||
1761 | data->reg_temp_hyst[r2] = tmp; | ||
1762 | |||
1763 | tmp = data->reg_temp_config[r1]; | ||
1764 | data->reg_temp_config[r1] = data->reg_temp_config[r2]; | ||
1765 | data->reg_temp_config[r2] = tmp; | ||
1766 | } | ||
1767 | |||
1437 | static int __devinit w83627ehf_probe(struct platform_device *pdev) | 1768 | static int __devinit w83627ehf_probe(struct platform_device *pdev) |
1438 | { | 1769 | { |
1439 | struct device *dev = &pdev->dev; | 1770 | struct device *dev = &pdev->dev; |
1440 | struct w83627ehf_sio_data *sio_data = dev->platform_data; | 1771 | struct w83627ehf_sio_data *sio_data = dev->platform_data; |
1441 | struct w83627ehf_data *data; | 1772 | struct w83627ehf_data *data; |
1442 | struct resource *res; | 1773 | struct resource *res; |
1443 | u8 fan4pin, fan5pin, en_vrm10; | 1774 | u8 fan3pin, fan4pin, fan4min, fan5pin, en_vrm10; |
1444 | int i, err = 0; | 1775 | int i, err = 0; |
1445 | 1776 | ||
1446 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | 1777 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
@@ -1466,9 +1797,11 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1466 | 1797 | ||
1467 | /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */ | 1798 | /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */ |
1468 | data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9; | 1799 | data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9; |
1469 | /* 667HG has 3 pwms */ | 1800 | /* 667HG, NCT6775F, and NCT6776F have 3 pwms */ |
1470 | data->pwm_num = (sio_data->kind == w83667hg | 1801 | data->pwm_num = (sio_data->kind == w83667hg |
1471 | || sio_data->kind == w83667hg_b) ? 3 : 4; | 1802 | || sio_data->kind == w83667hg_b |
1803 | || sio_data->kind == nct6775 | ||
1804 | || sio_data->kind == nct6776) ? 3 : 4; | ||
1472 | 1805 | ||
1473 | data->have_temp = 0x07; | 1806 | data->have_temp = 0x07; |
1474 | /* Check temp3 configuration bit for 667HG */ | 1807 | /* Check temp3 configuration bit for 667HG */ |
@@ -1479,15 +1812,98 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1479 | if (reg & 0x01) | 1812 | if (reg & 0x01) |
1480 | data->have_temp &= ~(1 << 2); | 1813 | data->have_temp &= ~(1 << 2); |
1481 | else | 1814 | else |
1482 | data->in6_skip = 1; /* Either temp3 or in6 */ | 1815 | data->in6_skip = 1; /* either temp3 or in6 */ |
1816 | } | ||
1817 | |||
1818 | /* Deal with temperature register setup first. */ | ||
1819 | if (sio_data->kind == nct6775 || sio_data->kind == nct6776) { | ||
1820 | int mask = 0; | ||
1821 | |||
1822 | /* | ||
1823 | * Display temperature sensor output only if it monitors | ||
1824 | * a source other than one already reported. Always display | ||
1825 | * first three temperature registers, though. | ||
1826 | */ | ||
1827 | for (i = 0; i < NUM_REG_TEMP; i++) { | ||
1828 | u8 src; | ||
1829 | |||
1830 | data->reg_temp[i] = NCT6775_REG_TEMP[i]; | ||
1831 | data->reg_temp_over[i] = NCT6775_REG_TEMP_OVER[i]; | ||
1832 | data->reg_temp_hyst[i] = NCT6775_REG_TEMP_HYST[i]; | ||
1833 | data->reg_temp_config[i] = NCT6775_REG_TEMP_CONFIG[i]; | ||
1834 | |||
1835 | src = w83627ehf_read_value(data, | ||
1836 | NCT6775_REG_TEMP_SOURCE[i]); | ||
1837 | src &= 0x1f; | ||
1838 | if (src && !(mask & (1 << src))) { | ||
1839 | data->have_temp |= 1 << i; | ||
1840 | mask |= 1 << src; | ||
1841 | } | ||
1842 | |||
1843 | data->temp_src[i] = src; | ||
1844 | |||
1845 | /* | ||
1846 | * Now do some register swapping if index 0..2 don't | ||
1847 | * point to SYSTIN(1), CPUIN(2), and AUXIN(3). | ||
1848 | * Idea is to have the first three attributes | ||
1849 | * report SYSTIN, CPUIN, and AUXIN if possible | ||
1850 | * without overriding the basic system configuration. | ||
1851 | */ | ||
1852 | if (i > 0 && data->temp_src[0] != 1 | ||
1853 | && data->temp_src[i] == 1) | ||
1854 | w82627ehf_swap_tempreg(data, 0, i); | ||
1855 | if (i > 1 && data->temp_src[1] != 2 | ||
1856 | && data->temp_src[i] == 2) | ||
1857 | w82627ehf_swap_tempreg(data, 1, i); | ||
1858 | if (i > 2 && data->temp_src[2] != 3 | ||
1859 | && data->temp_src[i] == 3) | ||
1860 | w82627ehf_swap_tempreg(data, 2, i); | ||
1861 | } | ||
1862 | if (sio_data->kind == nct6776) { | ||
1863 | /* | ||
1864 | * On NCT6776, AUXTIN and VIN3 pins are shared. | ||
1865 | * Only way to detect it is to check if AUXTIN is used | ||
1866 | * as a temperature source, and if that source is | ||
1867 | * enabled. | ||
1868 | * | ||
1869 | * If that is the case, disable in6, which reports VIN3. | ||
1870 | * Otherwise disable temp3. | ||
1871 | */ | ||
1872 | if (data->temp_src[2] == 3) { | ||
1873 | u8 reg; | ||
1874 | |||
1875 | if (data->reg_temp_config[2]) | ||
1876 | reg = w83627ehf_read_value(data, | ||
1877 | data->reg_temp_config[2]); | ||
1878 | else | ||
1879 | reg = 0; /* Assume AUXTIN is used */ | ||
1880 | |||
1881 | if (reg & 0x01) | ||
1882 | data->have_temp &= ~(1 << 2); | ||
1883 | else | ||
1884 | data->in6_skip = 1; | ||
1885 | } | ||
1886 | } | ||
1887 | |||
1888 | data->temp_label = nct6776_temp_label; | ||
1483 | } else if (sio_data->kind == w83667hg_b) { | 1889 | } else if (sio_data->kind == w83667hg_b) { |
1484 | u8 reg; | 1890 | u8 reg; |
1485 | 1891 | ||
1892 | /* | ||
1893 | * Temperature sources are selected with bank 0, registers 0x49 | ||
1894 | * and 0x4a. | ||
1895 | */ | ||
1896 | for (i = 0; i < ARRAY_SIZE(W83627EHF_REG_TEMP); i++) { | ||
1897 | data->reg_temp[i] = W83627EHF_REG_TEMP[i]; | ||
1898 | data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i]; | ||
1899 | data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i]; | ||
1900 | data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i]; | ||
1901 | } | ||
1486 | reg = w83627ehf_read_value(data, 0x4a); | 1902 | reg = w83627ehf_read_value(data, 0x4a); |
1487 | data->temp_src[0] = reg >> 5; | 1903 | data->temp_src[0] = reg >> 5; |
1488 | reg = w83627ehf_read_value(data, 0x49); | 1904 | reg = w83627ehf_read_value(data, 0x49); |
1489 | data->temp_src[1] = reg & 0x07; | 1905 | data->temp_src[1] = reg & 0x07; |
1490 | data->temp_src[2] = (reg >> 4) & 0x07; | 1906 | data->temp_src[2] = (reg >> 4) & 0x07; |
1491 | 1907 | ||
1492 | /* | 1908 | /* |
1493 | * W83667HG-B has another temperature register at 0x7e. | 1909 | * W83667HG-B has another temperature register at 0x7e. |
@@ -1516,22 +1932,54 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1516 | data->in6_skip = 1; | 1932 | data->in6_skip = 1; |
1517 | 1933 | ||
1518 | data->temp_label = w83667hg_b_temp_label; | 1934 | data->temp_label = w83667hg_b_temp_label; |
1935 | } else { | ||
1936 | /* Temperature sources are fixed */ | ||
1937 | for (i = 0; i < 3; i++) { | ||
1938 | data->reg_temp[i] = W83627EHF_REG_TEMP[i]; | ||
1939 | data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i]; | ||
1940 | data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i]; | ||
1941 | data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i]; | ||
1942 | } | ||
1519 | } | 1943 | } |
1520 | 1944 | ||
1521 | data->REG_PWM = W83627EHF_REG_PWM; | 1945 | if (sio_data->kind == nct6775) { |
1522 | data->REG_TARGET = W83627EHF_REG_TARGET; | 1946 | data->REG_PWM = NCT6775_REG_PWM; |
1523 | data->REG_FAN = W83627EHF_REG_FAN; | 1947 | data->REG_TARGET = NCT6775_REG_TARGET; |
1524 | data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN; | 1948 | data->REG_FAN = W83627EHF_REG_FAN; |
1525 | data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT; | 1949 | data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN; |
1526 | data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT; | 1950 | data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT; |
1527 | data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME; | 1951 | data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT; |
1528 | data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT; | 1952 | data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME; |
1529 | if (sio_data->kind == w83667hg_b) { | 1953 | data->REG_FAN_MAX_OUTPUT = NCT6775_REG_FAN_MAX_OUTPUT; |
1954 | data->REG_FAN_STEP_OUTPUT = NCT6775_REG_FAN_STEP_OUTPUT; | ||
1955 | } else if (sio_data->kind == nct6776) { | ||
1956 | data->REG_PWM = NCT6775_REG_PWM; | ||
1957 | data->REG_TARGET = NCT6775_REG_TARGET; | ||
1958 | data->REG_FAN = NCT6776_REG_FAN; | ||
1959 | data->REG_FAN_MIN = NCT6776_REG_FAN_MIN; | ||
1960 | data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT; | ||
1961 | data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT; | ||
1962 | data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME; | ||
1963 | } else if (sio_data->kind == w83667hg_b) { | ||
1964 | data->REG_PWM = W83627EHF_REG_PWM; | ||
1965 | data->REG_TARGET = W83627EHF_REG_TARGET; | ||
1966 | data->REG_FAN = W83627EHF_REG_FAN; | ||
1967 | data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN; | ||
1968 | data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT; | ||
1969 | data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT; | ||
1970 | data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME; | ||
1530 | data->REG_FAN_MAX_OUTPUT = | 1971 | data->REG_FAN_MAX_OUTPUT = |
1531 | W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B; | 1972 | W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B; |
1532 | data->REG_FAN_STEP_OUTPUT = | 1973 | data->REG_FAN_STEP_OUTPUT = |
1533 | W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B; | 1974 | W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B; |
1534 | } else { | 1975 | } else { |
1976 | data->REG_PWM = W83627EHF_REG_PWM; | ||
1977 | data->REG_TARGET = W83627EHF_REG_TARGET; | ||
1978 | data->REG_FAN = W83627EHF_REG_FAN; | ||
1979 | data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN; | ||
1980 | data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT; | ||
1981 | data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT; | ||
1982 | data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME; | ||
1535 | data->REG_FAN_MAX_OUTPUT = | 1983 | data->REG_FAN_MAX_OUTPUT = |
1536 | W83627EHF_REG_FAN_MAX_OUTPUT_COMMON; | 1984 | W83627EHF_REG_FAN_MAX_OUTPUT_COMMON; |
1537 | data->REG_FAN_STEP_OUTPUT = | 1985 | data->REG_FAN_STEP_OUTPUT = |
@@ -1544,7 +1992,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1544 | data->vrm = vid_which_vrm(); | 1992 | data->vrm = vid_which_vrm(); |
1545 | superio_enter(sio_data->sioreg); | 1993 | superio_enter(sio_data->sioreg); |
1546 | /* Read VID value */ | 1994 | /* Read VID value */ |
1547 | if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) { | 1995 | if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b || |
1996 | sio_data->kind == nct6775 || sio_data->kind == nct6776) { | ||
1548 | /* W83667HG has different pins for VID input and output, so | 1997 | /* W83667HG has different pins for VID input and output, so |
1549 | we can get the VID input values directly at logical device D | 1998 | we can get the VID input values directly at logical device D |
1550 | 0xe3. */ | 1999 | 0xe3. */ |
@@ -1595,12 +2044,27 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1595 | } | 2044 | } |
1596 | 2045 | ||
1597 | /* fan4 and fan5 share some pins with the GPIO and serial flash */ | 2046 | /* fan4 and fan5 share some pins with the GPIO and serial flash */ |
1598 | if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) { | 2047 | if (sio_data->kind == nct6775) { |
1599 | fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20; | 2048 | /* On NCT6775, fan4 shares pins with the fdc interface */ |
2049 | fan3pin = 1; | ||
2050 | fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80); | ||
2051 | fan4min = 0; | ||
2052 | fan5pin = 0; | ||
2053 | } else if (sio_data->kind == nct6776) { | ||
2054 | fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40); | ||
2055 | fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01); | ||
2056 | fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02); | ||
2057 | fan4min = fan4pin; | ||
2058 | } else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) { | ||
2059 | fan3pin = 1; | ||
1600 | fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40; | 2060 | fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40; |
2061 | fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20; | ||
2062 | fan4min = fan4pin; | ||
1601 | } else { | 2063 | } else { |
1602 | fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02); | 2064 | fan3pin = 1; |
1603 | fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06); | 2065 | fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06); |
2066 | fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02); | ||
2067 | fan4min = fan4pin; | ||
1604 | } | 2068 | } |
1605 | superio_exit(sio_data->sioreg); | 2069 | superio_exit(sio_data->sioreg); |
1606 | 2070 | ||
@@ -1610,15 +2074,36 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1610 | connected fan5 as input unless they are emitting log 1, which | 2074 | connected fan5 as input unless they are emitting log 1, which |
1611 | is not the default. */ | 2075 | is not the default. */ |
1612 | 2076 | ||
1613 | data->has_fan = 0x07; /* fan1, fan2 and fan3 */ | 2077 | data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */ |
1614 | i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1); | 2078 | |
1615 | if ((i & (1 << 2)) && fan4pin) | 2079 | data->has_fan |= (fan3pin << 2); |
1616 | data->has_fan |= (1 << 3); | 2080 | data->has_fan_min |= (fan3pin << 2); |
1617 | if (!(i & (1 << 1)) && fan5pin) | 2081 | |
1618 | data->has_fan |= (1 << 4); | 2082 | /* |
2083 | * NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1 register | ||
2084 | */ | ||
2085 | if (sio_data->kind == nct6775 || sio_data->kind == nct6776) { | ||
2086 | data->has_fan |= (fan4pin << 3) | (fan5pin << 4); | ||
2087 | data->has_fan_min |= (fan4min << 3) | (fan5pin << 4); | ||
2088 | } else { | ||
2089 | i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1); | ||
2090 | if ((i & (1 << 2)) && fan4pin) { | ||
2091 | data->has_fan |= (1 << 3); | ||
2092 | data->has_fan_min |= (1 << 3); | ||
2093 | } | ||
2094 | if (!(i & (1 << 1)) && fan5pin) { | ||
2095 | data->has_fan |= (1 << 4); | ||
2096 | data->has_fan_min |= (1 << 4); | ||
2097 | } | ||
2098 | } | ||
1619 | 2099 | ||
1620 | /* Read fan clock dividers immediately */ | 2100 | /* Read fan clock dividers immediately */ |
1621 | w83627ehf_update_fan_div(data); | 2101 | w83627ehf_update_fan_div_common(dev, data); |
2102 | |||
2103 | /* Read pwm data to save original values */ | ||
2104 | w83627ehf_update_pwm_common(dev, data); | ||
2105 | for (i = 0; i < data->pwm_num; i++) | ||
2106 | data->pwm_enable_orig[i] = data->pwm_enable[i]; | ||
1622 | 2107 | ||
1623 | /* Read pwm data to save original values */ | 2108 | /* Read pwm data to save original values */ |
1624 | w83627ehf_update_pwm_common(dev, data); | 2109 | w83627ehf_update_pwm_common(dev, data); |
@@ -1635,7 +2120,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1635 | for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) { | 2120 | for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) { |
1636 | struct sensor_device_attribute *attr = | 2121 | struct sensor_device_attribute *attr = |
1637 | &sda_sf3_max_step_arrays[i]; | 2122 | &sda_sf3_max_step_arrays[i]; |
1638 | if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) { | 2123 | if (data->REG_FAN_STEP_OUTPUT && |
2124 | data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) { | ||
1639 | err = device_create_file(dev, &attr->dev_attr); | 2125 | err = device_create_file(dev, &attr->dev_attr); |
1640 | if (err) | 2126 | if (err) |
1641 | goto exit_remove; | 2127 | goto exit_remove; |
@@ -1668,12 +2154,20 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1668 | if ((err = device_create_file(dev, | 2154 | if ((err = device_create_file(dev, |
1669 | &sda_fan_input[i].dev_attr)) | 2155 | &sda_fan_input[i].dev_attr)) |
1670 | || (err = device_create_file(dev, | 2156 | || (err = device_create_file(dev, |
1671 | &sda_fan_alarm[i].dev_attr)) | 2157 | &sda_fan_alarm[i].dev_attr))) |
1672 | || (err = device_create_file(dev, | ||
1673 | &sda_fan_div[i].dev_attr)) | ||
1674 | || (err = device_create_file(dev, | ||
1675 | &sda_fan_min[i].dev_attr))) | ||
1676 | goto exit_remove; | 2158 | goto exit_remove; |
2159 | if (sio_data->kind != nct6776) { | ||
2160 | err = device_create_file(dev, | ||
2161 | &sda_fan_div[i].dev_attr); | ||
2162 | if (err) | ||
2163 | goto exit_remove; | ||
2164 | } | ||
2165 | if (data->has_fan_min & (1 << i)) { | ||
2166 | err = device_create_file(dev, | ||
2167 | &sda_fan_min[i].dev_attr); | ||
2168 | if (err) | ||
2169 | goto exit_remove; | ||
2170 | } | ||
1677 | if (i < data->pwm_num && | 2171 | if (i < data->pwm_num && |
1678 | ((err = device_create_file(dev, | 2172 | ((err = device_create_file(dev, |
1679 | &sda_pwm[i].dev_attr)) | 2173 | &sda_pwm[i].dev_attr)) |
@@ -1701,12 +2195,21 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1701 | if (err) | 2195 | if (err) |
1702 | goto exit_remove; | 2196 | goto exit_remove; |
1703 | } | 2197 | } |
2198 | if (data->reg_temp_over[i]) { | ||
2199 | err = device_create_file(dev, | ||
2200 | &sda_temp_max[i].dev_attr); | ||
2201 | if (err) | ||
2202 | goto exit_remove; | ||
2203 | } | ||
2204 | if (data->reg_temp_hyst[i]) { | ||
2205 | err = device_create_file(dev, | ||
2206 | &sda_temp_max_hyst[i].dev_attr); | ||
2207 | if (err) | ||
2208 | goto exit_remove; | ||
2209 | } | ||
1704 | if (i > 2) | 2210 | if (i > 2) |
1705 | break; | 2211 | continue; |
1706 | if ((err = device_create_file(dev, &sda_temp_max[i].dev_attr)) | 2212 | if ((err = device_create_file(dev, |
1707 | || (err = device_create_file(dev, | ||
1708 | &sda_temp_max_hyst[i].dev_attr)) | ||
1709 | || (err = device_create_file(dev, | ||
1710 | &sda_temp_alarm[i].dev_attr)) | 2213 | &sda_temp_alarm[i].dev_attr)) |
1711 | || (err = device_create_file(dev, | 2214 | || (err = device_create_file(dev, |
1712 | &sda_temp_type[i].dev_attr))) | 2215 | &sda_temp_type[i].dev_attr))) |
@@ -1767,6 +2270,8 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, | |||
1767 | static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P"; | 2270 | static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P"; |
1768 | static const char __initdata sio_name_W83667HG[] = "W83667HG"; | 2271 | static const char __initdata sio_name_W83667HG[] = "W83667HG"; |
1769 | static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B"; | 2272 | static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B"; |
2273 | static const char __initdata sio_name_NCT6775[] = "NCT6775F"; | ||
2274 | static const char __initdata sio_name_NCT6776[] = "NCT6776F"; | ||
1770 | 2275 | ||
1771 | u16 val; | 2276 | u16 val; |
1772 | const char *sio_name; | 2277 | const char *sio_name; |
@@ -1803,6 +2308,14 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, | |||
1803 | sio_data->kind = w83667hg_b; | 2308 | sio_data->kind = w83667hg_b; |
1804 | sio_name = sio_name_W83667HG_B; | 2309 | sio_name = sio_name_W83667HG_B; |
1805 | break; | 2310 | break; |
2311 | case SIO_NCT6775_ID: | ||
2312 | sio_data->kind = nct6775; | ||
2313 | sio_name = sio_name_NCT6775; | ||
2314 | break; | ||
2315 | case SIO_NCT6776_ID: | ||
2316 | sio_data->kind = nct6776; | ||
2317 | sio_name = sio_name_NCT6776; | ||
2318 | break; | ||
1806 | default: | 2319 | default: |
1807 | if (val != 0xffff) | 2320 | if (val != 0xffff) |
1808 | pr_debug("unsupported chip ID: 0x%04x\n", val); | 2321 | pr_debug("unsupported chip ID: 0x%04x\n", val); |