1 /*
2 * Winbond and Asus hardware monitor chip
3 *
4 ***************************************************************
5 * Before calling these routines, one must call method->Open() *
6 * After calling these routines, one must call method->Close() *
7 ***************************************************************
8 *
9 * Winbond chip: W83781D, W83782D, W83783S, W83627HF, W83697HF
10 * Asus chip : AS99127F, ASB100
11 * National Semiconductor: LM78, LM78-j, LM79 [+ [2*]LM75]
12 *
13 * Note: LM75 is temperature only sensor chip sometimes used
14 * with LM78/79.
15 * Winbond W83781D is LM78/79 + 2 * LM75 more or less.
16 *
17
18 Winbond
19 Chip Temp Volt Fan SMBus IOport
20 W83781D 3 7 3 yes yes
21 W83782D 3 9 3 yes yes
22 W83783S 1-2 5-6 3 yes no
23 W83791D 3 10 5 yes no
24 W83627HF 3 9 3 yes yes (LPC)
25 W83627THF 3 7 3 yes yes (LPC)
26 W83697HF 2 6 2 no yes (LPC)
27
28 Asus
29 Chip Temp Volt Fan SMBus IOport
30 AS99127F 3 7 3 yes no
31 ASB100(Bach) 3 7 3 yes no
32 ASM58(Mozart-2) 2 4 2 yes no
33 (Mozart-2 needs a specific treatment)
34
35 National Semiconductor
36 Chip Temp Volt Fan SMBus IOport
37 lm78/lm78-j 1 7 3 yes yes
38 lm79 1 7 3 yes yes
39
40 Analog Devices
41 Chip Temp Volt Fan SMBus IOport
42 adm9240 1 6 2 yes yes
43
44 *
45 * by YRS
46 */
47
48 /* To allow "unknown" (fuzzy probing), define this */
49 /* #define ALLOW_UNKNOWN */
50
51 #include <stdio.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include "pci_pm.h"
55 #include "sensors.h"
56 #include "sens_winbond.h"
57
58 /* external (global) data */
59 extern int pm_smb_detected;
60 extern int smb_slave;
61 extern int smb_wbtemp1, smb_wbtemp2;
62 extern int smb_wbtemp1_flag, smb_wbtemp2_flag;
63 extern LM_METHODS method_isa, method_smb;
64 extern int numSMBSlave, canSMBSlave[128];
65 extern int TyanTigerMP_flag;
66
67 #define LM75_ADDR_START 0x90 /* 0x90-0x9E (0x48-0x4F) */
68 #define LM75_ADDR_END 0x9E
69 #define WINBD_ADDR_START 0x50 /* 0x50-0x5E (0x28-0x2F) */
70 #define WINBD_ADDR_END 0x5E
71 #define ASUSM_ADDR_FIX 0xEE /* ASUS Mozart-2, 0xEE (0x77) only */
72
73 #define WINBD_CONFIG 0x40
74 #define WINBD_SMBADDR 0x48
75 #define WINBD_DEVCID 0x49
76 #define WINBD_CHIPID 0x58
77 #define WINBD_VENDEX 0x4E
78 #define WINBD_VENDID 0x4F
79 #define ANADM_VENDID 0x3E
80
81 /* temp nr=0,1,2; volt nr=0,...6; fan nr=0,1,2 */
82 #define WINBD_TEMP0 0x27
83 #define ASUSB_TEMP4 0x17
84 #define ASUSM_TEMP2 0x13
85 #define WINBD_TEMPADDR 0x4A
86 #define WINBD_VOLT(nr) (0x20 + (nr))
87 #define WINBD_FAN(nr) (0x28 + (nr))
88 #define WINBD_FANDIV 0x47
89 #define WINBD_REGPIN 0x4B
90 #define ASUSM_FANDIV 0xA1
91 #define ANADM_TEMPCFG 0x4B
92
93 #define WINBD_DIOSEL 0x59
94 #define WINBD_VMCTRL 0x5D
95
96 static int winbond_probe(LM_METHODS *);
97 static int winbond_probe_act(LM_METHODS *, int);
98 static float winbond_temp(LM_METHODS *, int);
99 static int winbond_fanrpm(LM_METHODS *, int);
100 static float winbond_volt(LM_METHODS *, int);
101
102 #define BUFF_LEN 128
103 static char buff[BUFF_LEN];
104
105 SENSOR winbond = {
106 buff,
107 winbond_probe,
108 winbond_temp,
109 winbond_volt,
110 winbond_fanrpm
111 };
112
113 /* chip idenfication */
114 static int wbdchipid = 0;
115 static int wbdlmid = 0;
116
117 /* temp1/2 flags address */
118 static int temp1_flag = 0; /* = 0 if enabled ! */
119 static int temp2_flag = 0; /* = 0 if enabled ! */
120 static int temp1_addr = 0;
121 static int temp2_addr = 0;
122
123 /* fan divisor register */
124 static int fan12div_reg = WINBD_FANDIV;
125
126 #define WINBD_chkRegNum 8
127
128 /* Register checked for probing */
129 static int chkReg[] = {
130 0x40, 0x41, 0x42, 0x43,
131 0x44, 0x45, 0x46, 0x47,
132 0x48, 0x49, 0x4A, 0x4B,
133 0x4C, 0x4D, 0x4E, 0x4F,
134 0x56, 0x58, 0x59, 0x5D,
135 0x3E, 0x13, 0x17, 0xA1,
136 0x20, 0x22, 0x23, 0x24,
137 0x27, 0x29, 0x2A, 0x2B,
138 -1 };
139
140
Temp_Bipolar(LM_METHODS * method)141 static void Temp_Bipolar(LM_METHODS *method)
142 {
143 int n;
144
145 n = method->Read(WINBD_DIOSEL) & 0x8F;
146 method->Write(WINBD_DIOSEL, n);
147 n = method->Read(WINBD_VMCTRL) | 0x0E;
148 method->Write(WINBD_VMCTRL, n);
149 }
150
Init_FanDiv(LM_METHODS * method)151 static void Init_FanDiv(LM_METHODS *method)
152 {
153 int n;
154
155 n = (method->Read(WINBD_FANDIV) & 0x0F) | 0xA0;
156 method->Write(WINBD_FANDIV, n);
157 n = (method->Read(WINBD_REGPIN) & 0x3F) | 0x80;
158 method->Write(WINBD_REGPIN, n);
159 }
160
161 /*
162 * return 0 if not probed
163 */
winbond_probe(LM_METHODS * method)164 static int winbond_probe(LM_METHODS *method)
165 {
166 int n, save, slave = 0;
167
168 if (method != &method_isa && method != &method_smb)
169 return 0;
170
171 save = smb_slave;
172
173 if (method == &method_smb) {
174 /* check ASUS Mozart Chip, first */
175 if ((slave = get_smb_slave(ASUSM_ADDR_FIX, ASUSM_ADDR_FIX))) {
176 if (winbond_probe_act(method, slave))
177 goto ret1;
178 }
179 for (n = WINBD_ADDR_START; n <= WINBD_ADDR_END;) {
180 if (!(slave = get_smb_slave(n, WINBD_ADDR_END)))
181 goto ret0;
182 else {
183 if (winbond_probe_act(method, slave))
184 goto ret1;
185 else
186 n = slave + 2;
187 }
188 }
189 goto ret0;
190 } else {
191 if (winbond_probe_act(method, slave))
192 goto ret1;
193 }
194
195 ret0:
196 smb_slave = save;
197 return 0;
198 ret1:
199 /* this is TyanTigerMP specific treatment */
200 if (TyanTigerMP_flag) {
201 Temp_Bipolar(method);
202 usleep(30000);
203 Init_FanDiv(method);
204 }
205 if (method == &method_smb) {
206 kill_smb_slave(slave);
207 if(!smb_wbtemp1_flag)
208 kill_smb_slave(smb_wbtemp1);
209 if(!smb_wbtemp2_flag)
210 kill_smb_slave(smb_wbtemp2);
211 }
212 return wbdchipid;
213 }
214
winbond_probe_act(LM_METHODS * method,int slave)215 static int winbond_probe_act(LM_METHODS *method, int slave)
216 {
217 int i, n, nd, nc, nvl, nvu, nvx, nva;
218
219 if (method == &method_smb)
220 smb_slave = slave;
221 else
222 slave = 0;
223
224 if (chkReg_Probe(slave, "Probing Winbond/Asus/LM78/79 chip:\n",
225 chkReg, method) < WINBD_chkRegNum)
226 goto ret0;
227
228 nd = method->Read(WINBD_DEVCID) & 0xFE;
229 nc = method->Read(WINBD_CHIPID);
230 nvx = method->Read(WINBD_VENDEX);
231 method->Write(WINBD_VENDEX, 0x00);
232 nvl = method->Read(WINBD_VENDID);
233 method->Write(WINBD_VENDEX, 0x80);
234 nvu = method->Read(WINBD_VENDID);
235 nva = method->Read(ANADM_VENDID);
236 #ifdef DEBUG
237 printf("DEBUG 49:0x%02X 58:0x%02X 4Fl:0x%02X 4Fu:0x%02X\n",nd,nc,nvl,nvu);
238 #endif
239
240 if (nvl == 0xA3 && nvu == 0x5C) { /* Winbond Chip */
241 switch (nc & 0xFE) {
242 case 0x10: /* 0x10 (or 0x11) */
243 wbdchipid = W83781D;
244 break;
245 case 0x20: /* 0x20 (or 0x21) 627HF */
246 case 0x90: /* 0x90 (or 0x91?) 627THF */
247 case 0x1A: /* 0x1A (??) 627THF-A */
248 case 0xA0: /* 0xA0 (or 0xA1) */
249 case 0xC0: /* 0xC0 (or 0xC1) 627DHG */
250 wbdchipid = W83627HF;
251 break;
252 case 0x30: /* 0x30 (or 0x31) */
253 wbdchipid = W83782D;
254 if (nc == 0x31)
255 wbdchipid = AS99127F; /* very special, but ... */
256 break;
257 case 0x40: /* 0x40 (or 0x41) */
258 wbdchipid = W83783S;
259 break;
260 case 0x60: /* 0x60 (or 0x61) */
261 wbdchipid = W83697HF;
262 break;
263 case 0x70: /* 0x70 (or 0x71) */
264 wbdchipid = W83791D;
265 break;
266 default:
267 #ifdef ALLOW_UNKNOWN
268 wbdchipid = WBUNKNOWN;
269 #else
270 goto ret0;
271 #endif
272 }
273 } else if ((nvl == 0xC3 && nvu == 0x12) && nc == 0x31) { /* Asus Chip */
274 wbdchipid = AS99127F;
275 } else if ((nvl == 0x94 && nvu == 0x06) && nc == 0x31) { /* Asus Chip */
276 wbdchipid = ASB100;
277 } else if ( smb_slave == ASUSM_ADDR_FIX && /* Mozart-2, special */
278 ((nvx == 0x94 && nvl == 0x36 && nc == 0x56) ||
279 (nvx == 0x94 && nvl == 0x06 && nc == 0x56) ||
280 (nvx == 0x5C && nvl == 0xA3 && nc == 0x10))) {
281 wbdchipid = ASM58;
282 } else if (nd == 0x20 || nd == 0x40) { /* 0x20, 0x40 */
283 wbdchipid = LM78;
284 } else if (nd == 0xC0) { /* 0xC0 */
285 wbdchipid = LM79;
286 } else if (nva == 0x23) { /* ADM9240 */
287 wbdchipid = ADM9240;
288 } else
289 #ifdef ALLOW_UNKNOWN
290 wbdchipid = UNKNOWN;
291 #else
292 goto ret0;
293 #endif
294
295 strcpy(buff, winbchip[wbdchipid]);
296
297 wbdlmid = wbdchipid;
298 if (wbdchipid == WBUNKNOWN || wbdchipid >= LM78)
299 wbdlmid = W83781D;
300
301 if (wbdchipid == ASB100) /* Asus Bach */
302 wbdlmid = W83781D;
303
304 if (wbdchipid == ASM58) { /* Asus Mozart-2 */
305 wbdlmid = W83781D;
306 temp1_flag = temp2_flag = 1; /* disable! */
307 fan12div_reg = ASUSM_FANDIV;
308 method->Write(WINBD_CONFIG, 0x01); /* init. chip */
309 goto ret1;
310 }
311
312 if (wbdchipid == ADM9240) {
313 temp1_flag = temp2_flag = 1; /* disable! */
314 method->Write(WINBD_CONFIG, 0x01); /* init. chip */
315 goto ret1;
316 }
317
318 if (method == &method_isa && wbdchipid >= LM78) {
319 temp1_flag = temp2_flag = 1; /* disable! */
320 goto ret1;
321 }
322
323 /* Checking Extra temperatures Temp1, Temp2 */
324
325 if (wbdchipid >= LM78) { /* possibility of LM75 sensor */
326 i = set_smb_Extemp(LM75_ADDR_START, LM75_ADDR_END,
327 &smb_wbtemp2, &smb_wbtemp1);
328 temp2_flag = i >> 1;
329 temp1_flag = i & 0x01;
330 info_Extemp(method, temp1_flag, temp2_flag);
331 if (!temp1_flag || !temp2_flag)
332 strcat(winbond.Name, "+LM75");
333 goto ret1;
334 }
335
336 n = method->Read(WINBD_TEMPADDR);
337 if (!(temp1_flag = (n & 0x08) >> 3)) {
338 temp1_addr = smb_wbtemp1;
339 smb_wbtemp1 = 2 * ( 0x48 + (n & 0x07) );
340 if (method->ReadTemp1() == 0xFFFF) {
341 temp1_flag = 1; /* disable! */
342 smb_wbtemp1 = temp1_addr;
343 }
344 }
345
346 if (!(temp2_flag = (n & 0x80) >> 7)) {
347 temp2_addr = smb_wbtemp2;
348 smb_wbtemp2 = 2 * ( 0x48 + ((n & 0x70) >> 4) );
349 if (method->ReadTemp2() == 0xFFFF) {
350 temp2_flag = 1; /* disable! */
351 smb_wbtemp2 = temp2_addr;
352 }
353 }
354 info_Extemp(method, temp1_flag, temp2_flag);
355
356 ret1:
357 if (method == &method_smb) {
358 smb_wbtemp1_flag = temp1_flag;
359 smb_wbtemp2_flag = temp2_flag;
360 }
361 return wbdchipid;
362 ret0:
363 return 0;
364 }
365
366
367 /*
368 * \retval 0xFFFF no sensor
369 * \retval other temperature
370 * no = 0,1,2
371 */
winbond_temp(LM_METHODS * method,int no)372 static float winbond_temp(LM_METHODS *method, int no)
373 {
374 int n = 0;
375 float f;
376
377 if (no < 0 || 2 < no)
378 return 0xFFFF;
379 if (no == 2 &&
380 (wbdchipid == W83783S || wbdchipid == W83697HF || wbdchipid == ASM58))
381 return 0xFFFF;
382
383 if (no == 0) {
384 f = (float) method->Read(WINBD_TEMP0);
385 if (wbdchipid == ADM9240) {
386 n = method->Read(ANADM_TEMPCFG);
387 if (n & 0x80)
388 f += 0.5;
389 }
390 return f;
391 } else if (no == 1) {
392 if (wbdchipid == ASB100)
393 return (float) method->Read(ASUSB_TEMP4);
394 if (wbdchipid == ASM58)
395 return (float) method->Read(ASUSM_TEMP2);
396 else if (!temp1_flag)
397 n = method->ReadTemp1();
398 #ifdef SYRS
399 } else if (no == 2 && !temp2_flag) {
400 #else
401 } else if (no == 2) {
402 if (wbdchipid == ASB100) {
403 if (!temp1_flag)
404 n = method->ReadTemp1();
405 } else if (!temp2_flag)
406 #endif
407 n = method->ReadTemp2();
408 }
409
410 if ((n & 0xFF) >= 0x80)
411 n = 0;
412
413 f = (float) (n & 0xFF) + 0.5 * ((n & 0xFF00) >> 15);
414
415 if (wbdchipid == AS99127F && pm_smb_detected == ICH801SMB) {
416 /* very special treatment for AS99127F with ICH chipsets */
417 if (no == 1 && (-32.0 < f && f <= 105.0)) {
418 f *= 0.697;
419 f += 25.0;
420 }
421 }
422 return f;
423 }
424
425
426 /*
427 * \retval 0x0000FFFF no sensor
428 * no = 0,1,2,...,6
429 */
winbond_volt(LM_METHODS * method,int no)430 static float winbond_volt(LM_METHODS *method, int no)
431 {
432 int n;
433 float f = 0.0;
434
435 if (no < 0 || 6 < no)
436 return 0xFFFF;
437 if (wbdchipid == ASM58 && (no == 1 || no > 4))
438 return 0xFFFF;
439 if (wbdchipid == ADM9240 && (no > 5))
440 return 0xFFFF;
441
442 n = method->Read(WINBD_VOLT(no));
443 switch (no) {
444 case 0:
445 case 1:
446 case 2:
447 f = n * 0.016;
448 break;
449 case 3:
450 f = n * 0.016 * 1.68;
451 break;
452 case 4:
453 f = n * 0.016 * 3.800;
454 break;
455 case 5:
456 if (wbdlmid == AS99127F)
457 f = - n * 0.016 * 3.968;
458 else if (wbdlmid == W83781D)
459 f = - n * 0.016 * 3.477;
460 else
461 f = ( n * 0.016 - 3.6 * 0.8056) / 0.1944;
462 break;
463 case 6:
464 if (wbdlmid == W83781D || wbdlmid == AS99127F)
465 f = - n * 0.016 * 1.500;
466 else
467 f = ( n * 0.016 - 3.6 * 0.6818) / 0.3182;
468 }
469
470 return f;
471 }
472
473
474 /*
475 Controlling Fan Divisor for 1st/2nd fans: CR = 0x47.
476 1st two bits for fan1, 2nd two bits for fan2
477
478 7 4 3 0
479 +-+-+-+-+-+-+-+-+ xx = 00,01,10,11 div1fac = 1,2,4,8
480 |y y|x x| VolID | yy = 00,01,10,11 div2fac = 1,2,4,8
481 +-+-+-+-+-+-+-+-+ initial values: xx=01, yy=01
482
483 Controlling Fan Divisor for 3rd fan: CR = 0x4B.
484 1st two bits for fan3
485
486 7 6 5 0
487 +-+-+-+-+-+-+-+-+
488 |z z| | zz = 00,01,10,11 div3fac = 1,2,4,8
489 +-+-+-+-+-+-+-+-+ initial values: zz=01
490
491 3rd fan divisor available for Winbond (not for LM78/79).
492
493 Bit 2 of Fan Divisor: CR = 0x5D (Winbond chips except 781D).
494
495 7 6 5 0
496 +-+-+-+-+-+-+-+-+
497 |z|y|x| | x, y, z for bit 2 of fan 1, 2, 3
498 +-+-+-+-+-+-+-+-+
499 */
500
501 /*
502 * \retval 0xFFFF no sensor
503 * no = 0,1,2
504 *
505 * Clock is 22.5kHz (22,500 x 60 = 1350000 counts/minute)
506 */
winbond_fanrpm(LM_METHODS * method,int no)507 static int winbond_fanrpm(LM_METHODS *method, int no)
508 {
509 int r, n1 = 0x50, n2 = 0x40, n3 = 0x00;
510 static int div[3] = {1,1,1};
511
512 if (no < 0 || 2 < no)
513 return 0xFFFF;
514 if (no == 2
515 && (wbdchipid == W83697HF || wbdchipid == ASM58
516 || wbdchipid == ADM9240))
517 return 0xFFFF;
518
519 if (W83782D <= wbdchipid && wbdchipid <= W83697HF)
520 n3 = method->Read(WINBD_VMCTRL); /* bit 2 */
521 if (no != 2) {
522 n1 = method->Read(fan12div_reg); /* bit 0,1 */
523 div[0] = ((n1 >> 4) & 0x03) | ((n3 & 0x20) >> 3);
524 div[1] = (n1 >> 6) | ((n3 & 0x40) >> 4);
525 } else if (wbdchipid < LM78) {
526 n2 = method->Read(WINBD_REGPIN); /* bit 0,1 */
527 div[2] = (n2 >> 6) | ((n3 & 0x80) >> 5);
528 }
529
530 r = method->Read(WINBD_FAN(no));
531 if (r == 0xFF) {
532 /* change divisor for the sake of next call ! */
533 if (no != 2) {
534 if (div[no] < 3)
535 ++(div[no]);
536 else
537 div[no] = 0;
538 r = (n1 & 0x0F) | ((div[0] & 0x03) << 4) | ((div[1] & 0x03) << 6);
539 method->Write(fan12div_reg, r);
540 } else if (wbdchipid < LM78) {
541 if (div[no] < 3)
542 ++(div[no]);
543 else
544 div[no] = 0;
545 r = (n2 & 0x3F) | ((div[2] & 0x03) << 6);
546 method->Write(WINBD_REGPIN, r);
547 }
548 if (W83782D <= wbdchipid && wbdchipid <= W83697HF) {
549 r = (n3 & 0x1F) | ((div[0] & 0x04) << 3) |
550 ((div[1] & 0x04) << 4) | ((div[2] & 0x04) << 5);
551 method->Write(WINBD_VMCTRL, r);
552 }
553 return 0xFFFF;
554 } else if (r == 0) {
555 return 0xFFFF;
556 }
557
558 return 1350000 / (r * (1 << div[no]));
559 }
560