/* * VIA VT82C686A/B hardware monitor chip * *************************************************************** * Before calling these routines, one must call method->Open() * * After calling these routines, one must call method->Close() * *************************************************************** * VIA Chip Temp Volt Fan SMBus IOport via686a 3 5 2 yes yes * * by YRS */ #include "pci_pm.h" #include "sensors.h" /* external (global) data */ extern int smb_slave; extern int pm_smb_detected; extern LM_METHODS method_via, method_smb; extern int numSMBSlave, canSMBSlave[128]; #define VIA_ADDR_START 0x50 /*0x50-0x5E*/ #define VIA_ADDR_END 0x5E /* temp nr=0,1,2; volt nr=0,...4; fan nr=0,1 */ #define VIA686_TEMP(nr) (0x1F + (nr)) #define VIA686_VOLT(nr) (0x22 + (nr)) #define VIA686_FAN(nr) (0x29 + (nr)) #define VIA686_FANDIV 0x47 static int via686_probe(LM_METHODS *methods); static float via686_temp(LM_METHODS *methods, int no); static int via686_fanrpm(LM_METHODS *methods, int no); static float via686_volt(LM_METHODS *methods, int no); SENSOR via686 = { "VIA Chip VT82C686A/B", via686_probe, via686_temp, via686_volt, via686_fanrpm }; #define VIA_chkRegNum 5 /* Register checked for probing */ static int chkReg[] = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x47, 0x49, 0x4B, 0x3F, 0x14, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x29, 0x2B, -1 }; /* * return 0 if not probed */ static int via686_probe(LM_METHODS *method) { int n, save; if (method != &method_via && method != &method_smb) return 0; if (pm_smb_detected != VIA686HWM && pm_smb_detected != VIA686SMB) return 0; save = smb_slave; if (method == &method_smb) { for (n = VIA_ADDR_START; n <= VIA_ADDR_END;) { if (!(smb_slave = get_smb_slave(n, VIA_ADDR_END))) goto ret0; else { if (chkReg_Probe(smb_slave, "Probing VIA686A/B chip:\n", chkReg, method) >= VIA_chkRegNum) goto ret1; else n = smb_slave + 2; } } } else { if (chkReg_Probe(0, "Probing VIA686A/B chip:\n", chkReg, method) >= VIA_chkRegNum) goto ret1; } ret0: smb_slave = save; return 0; ret1: if (method == &method_smb) kill_smb_slave(smb_slave); return 1; } static const float via686temp_tab[256] = {\ .00, .00, .00, .00, .00, .00, .00, .00, .00, .00, .00, .00, .00, .00, .00,-50.00, -48.00,-46.09,-44.26,-42.52,-40.86,-39.28,-37.78,-36.35, -34.99,-33.70,-32.47,-31.31,-30.20,-29.15,-28.14,-27.18, -26.27,-25.39,-24.55,-23.73,-22.95,-22.18,-21.44,-20.70, -19.98,-19.27,-18.57,-17.87,-17.19,-16.51,-15.85,-15.20, -14.56,-13.93,-13.32,-12.72,-12.14,-11.58,-11.03,-10.50, -9.99, -9.50, -9.03, -8.57, -8.11, -7.67, -7.22, -6.77, -6.31, -5.85, -5.37, -4.87, -4.36, -3.81, -3.24, -2.64, -2.00, -1.33, -.65, .00, .59, 1.12, 1.60, 2.03, 2.42, 2.79, 3.12, 3.44, 3.75, 4.05, 4.35, 4.67, 4.99, 5.34, 5.71, 6.09, 6.49, 6.91, 7.34, 7.78, 8.23, 8.69, 9.15, 9.62, 10.09, 10.57, 11.04, 11.51, 11.98, 12.44, 12.90, 13.35, 13.80, 14.24, 14.68, 15.12, 15.55, 15.99, 16.42, 16.85, 17.27, 17.70, 18.13, 18.56, 18.99, 19.42, 19.85, 20.29, 20.72, 21.15, 21.59, 22.03, 22.47, 22.90, 23.34, 23.78, 24.22, 24.66, 25.10, 25.54, 25.99, 26.43, 26.87, 27.31, 27.75, 28.19, 28.63, 29.07, 29.51, 29.95, 30.38, 30.82, 31.25, 31.68, 32.11, 32.53, 32.96, 33.38, 33.80, 34.22, 34.63, 35.05, 35.48, 35.90, 36.33, 36.76, 37.20, 37.64, 38.09, 38.55, 39.02, 39.50, 39.99, 40.49, 41.00, 41.52, 42.06, 42.60, 43.15, 43.70, 44.27, 44.84, 45.41, 45.99, 46.57, 47.16, 47.75, 48.35, 48.94, 49.54, 50.13, 50.73, 51.33, 51.94, 52.55, 53.16, 53.78, 54.41, 55.04, 55.68, 56.32, 56.98, 57.64, 58.32, 59.00, 59.69, 60.40, 61.12, 61.85, 62.60, 63.36, 64.13, 64.93, 65.73, 66.56, 67.40, 68.26, 69.14, 70.05, 70.97, 71.91, 72.88, 73.86, 74.88, 75.92, 76.98, 78.08, 79.21, 80.36, 81.55, 82.78, 84.03, 85.33, 86.66, 88.04, 89.45, 90.90, 92.40, 93.94, 95.53, 97.16, 98.85,100.58,102.36, 104.19,106.07,108.01,110.00, .00, .00, .00, .00, .00, .00, .00, .00, .00, .00, .00, .00 }; /* * \retval 0xFFFF no sensor * \retval other temperature * no = 0,1,2,... */ static float via686_temp(LM_METHODS *method, int no) { if (no < 0 || 2 < no) return 0xFFFF; return via686temp_tab[method->Read(VIA686_TEMP(no))]; } /* * \retval 0x0000FFFF no sensor * no = 0,1,2,... */ static float via686_volt(LM_METHODS *method, int no) { int n; float fac; if ( no < 0 || 4 < no ) return 0xFFFF; switch (no) { case 0: case 1: fac = 5. / 10512.; break; case 2: fac = 5. / 7884.; break; case 3: fac = 26. / 26280.; break; case 4: fac = 63. / 26280.; } if ((n = method->Read(VIA686_VOLT(no))) <= 0x40) n |= 0x100; return (float) (n * 25 + 133) * fac; } /* Controlling Fan Divisor: CR = 0x47. highest two bits for fan2, next two bits for fan1 7 3 0 +-+-+-+-+-+-+-+-+ xx = 00,01,10,11 div1fac = 1,2,4,8 |y y|x x| VolID | yy = 00,01,10,11 div2fac = 1,2,4,8 +-+-+-+-+-+-+-+-+ initial values: xx=01, yy=01 */ /* * \retval 0x0000FFFF no sensor * no = 0,1,2,... * * Clock is 22.5kHz (22,500 x 60 = 1350000 counts/minute) */ static int via686_fanrpm(LM_METHODS *method, int no) { int r, n; static int div[2] = {1,1}; if (no < 0 || 1 < no) return 0xFFFF; n = method->Read(VIA686_FANDIV); div[0] = (n >> 4) & 0x03; div[1] = n >> 6; r = method->Read(VIA686_FAN(no)); if (r == 0xFF) { /* change divisor for the sake of next call ! */ if (div[no] < 3) ++(div[no]); else div[no] = 0; r = (n & 0x0F) | (div[0] << 4) | (div[1] << 6); method->Write(VIA686_FANDIV, r); return 0xFFFF; } else if (r == 0) { return 0xFFFF; } return 1350000 / (r * (1 << div[no])); }