From 097c23db161c6456c4af075a8a1881e3baf7e814 Mon Sep 17 00:00:00 2001 From: Bob Dougherty Date: Wed, 8 Mar 2000 04:59:33 +0000 Subject: [PATCH] fixed fan RPM reading & improved accuracy of temp LUT. git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@762 7894878c-1315-0410-8ee3-d5d059ff63e0 --- kernel/chips/via686a.c | 110 ++++++++++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 34 deletions(-) diff --git a/kernel/chips/via686a.c b/kernel/chips/via686a.c index 0d0c224b..db500b0a 100644 --- a/kernel/chips/via686a.c +++ b/kernel/chips/via686a.c @@ -85,7 +85,7 @@ SENSORS_INSMOD_1(via686a); #define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) #define VIA686A_REG_FAN(nr) (0x28 + (nr)) -//static const u8 regtemp[] = {0x20, 0x21, 0x19}; +// the following values are as speced by VIA: static const u8 regtemp[] = {0x20, 0x21, 0x1f}; static const u8 regover[] = {0x39, 0x3d, 0x1d}; static const u8 reghyst[] = {0x3a, 0x3e, 0x1e}; @@ -115,6 +115,8 @@ static const u8 reghyst[] = {0x3a, 0x3e, 0x1e}; // That is: // volts = (25*regVal+133)*factor // regVal = (volts/factor-133)/25 +// +// in0: maybe factor should be 1? // // These get us close, but they don't completely agree with what my BIOS says- // they are all a bit low. @@ -125,7 +127,7 @@ extern inline u8 IN_TO_REG(long val, int inNum) // by adding 0.5. Or, to avoid fp math, we do (...*10+5)/10. // (note that the *10 is hidden in the /250 rather than /2500 // At the end, we need to /100 because we *100 everything and we need - // to /10 because of the rounding thing, so we /1000 + // to /10 because of the rounding thing, so we /1000. if (inNum<=1) return (u8)SENSORS_LIMIT(((val*210240-13300)/250+5)/1000,0,255); else if (inNum==2) @@ -151,15 +153,18 @@ extern inline long IN_FROM_REG(u8 val, int inNum) return (long)(((250000*val+13300)/41714*10+5)/10); } +/********* FAN RPM CONVERSIONS ********/ +// Higher register values = slower fans (the fan's strobe gates a counter). +// But this chip saturates back at 0, not at 255 like all the other chips. +// So, 0 means 0 RPM extern inline u8 FAN_TO_REG(long rpm, int div) { - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); + if (rpm == 0) + return 0; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255); } - -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) +#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div))) /******** TEMP CONVERSIONS (Bob Dougherty) *********/ // linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew) @@ -170,17 +175,40 @@ extern inline u8 FAN_TO_REG(long rpm, int div) // else // return double(temp)*0.924-127.33; // -// A fifth-order polynomial fits the unofficial data (provided by Alex van Kaam ) -// a bit better. It also give more reasonable numbers on my machine (ie. they agree with what my -// BIOS tells me). Here's the fifth-order fit to the 10-bit data: -// temp = 6.500371171990e-09*val^5 +-4.006529810457e-06*val^4 +9.830610857874e-04*val^3 + -// -1.187047495730e-01*val^2 +8.700574403605e+00*val +-2.836026823804e+02 +// A fifth-order polynomial fits the unofficial data (provided by Alex van Kaam +// ) a bit better. It also give more reasonable numbers on +// my machine (ie. they agree with what my BIOS tells me). Here's the +// fifth-order fit to the 8-bit data: +// temp = 1.625093e-09*val^5 - 1.001632e-06*val^4 + 2.457653e-04*val^3 - +// 2.967619e-02*val^2 + 2.175144e+00*val - 7.090067e+0. // -// None of the elegant function-fit solutions will work because we aren't allowed -// to use floating point in the kernel, so we'll do boring-old look-up table stuff. -// Here are the unofficial data (provided by Alex van Kaam ). -// Note that t is the temp at via register values 12-240 (8-bit), 48-960 (10-bit). -static const u8 tempLUT[] = {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31,\ +// Alas, none of the elegant function-fit solutions will work because we aren't allowed +// to use floating point in the kernel, so we'll do boring old look-up table stuff. +// The unofficial data (see below) have effectively 7-bit resolution (they are +// rounded to the nearest degree). I'm assuming that the transfer function of the +// device is monotonic and smooth, so a smooth function fit to the data will allow us +// to get better precision. I used the 5th-order poly fit described above and solved for +// VIA register values 0-255. I *10 before rounding, so we get tenth-degree precision. +// (I could have done all 1024 values for our 10-bit readings, but the function is very +// linear in the useful range (0-80 deg C), so we'll just use linear interpolation for +// 10-bit readings.) So, tempLUT is the temp at via register values 0-255: +static const long tempLUT[] = {-709,-688,-667,-646,-627,-607,-589,-570,-553,-536,-519,\ +-503,-487,-471,-456,-442,-428,-414,-400,-387,-375,-362,-350,-339,-327,-316,-305,-295,\ +-285,-275,-265,-255,-246,-237,-229,-220,-212,-204,-196,-188,-180,-173,-166,-159,-152,\ +-145,-139,-132,-126,-120,-114,-108,-102,-96,-91,-85,-80,-74,-69,-64,-59,-54,-49,-44,\ +-39,-34,-29,-25,-20,-15,-11,-6,-2,3,7,12,16,20,25,29,33,37,42,46,50,54,59,63,67,71,\ +75,79,84,88,92,96,100,104,109,113,117,121,125,130,134,138,142,146,151,155,159,163,168,\ +172,176,181,185,189,193,198,202,206,211,215,219,224,228,232,237,241,245,250,254,259,\ +263,267,272,276,281,285,290,294,299,303,307,312,316,321,325,330,334,339,344,348,353,\ +357,362,366,371,376,380,385,390,395,399,404,409,414,419,423,428,433,438,443,449,454,\ +459,464,469,475,480,486,491,497,502,508,514,520,526,532,538,544,551,557,564,571,578,\ +584,592,599,606,614,621,629,637,645,654,662,671,680,689,698,708,718,728,738,749,759,\ +770,782,793,805,818,830,843,856,870,883,898,912,927,943,958,975,991,1008,1026,1044,1062,\ +1081,1101,1121,1141,1162,1184,1206,1229,1252,1276,1301,1326,1352,1378,1406,1434,1462}; + +/* the original LUT values from Alex van Kaam (for via register + values 12-240): +{-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31,\ -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15,-15,-14,\ -14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3,-3,-2,-2,-1,-1,0,0,\ 1,1,1,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,9,10,10,11,11,12,12,12,13,13,13,14,14,15,15,16,\ @@ -189,15 +217,20 @@ static const u8 tempLUT[] = {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32 42,42,43,43,44,44,45,45,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,\ 59,59,60,61,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84,85,\ 86,88,89,91,92,94,96,97,99,101,103,105,107,109,110}; +*/ -// Here's the reverse LUT. I got it by doing a 6-th order poly fit to the data and then -// solving for each temp value from -50 to 110. (n=161) -static const u16 viaLUT[] = {12,12,13,14,14,15,16,16,17,18,18,19,20,20,21,22,23,23,24,\ +// Here's the reverse LUT. I got it by doing a 6-th order poly fit (that worked better +// than the 5th-order fit for the inverse data) and then solving for each temp value +// from -50 to 110 (the useable range for this chip). +// Here's the fit: viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 +// - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) +// note that n=161: +static const u8 viaLUT[] = {12,12,13,14,14,15,16,16,17,18,18,19,20,20,21,22,23,23,24,\ 25,26,27,28,29,30,31,32,33,35,36,37,39,40,41,43,45,46,48,49,51,53,55,57,59,60,62,64,66,\ 69,71,73,75,77,79,82,84,86,88,91,93,95,98,100,103,105,107,110,112,115,117,119,122,124,\ 126,129,131,134,136,138,140,143,145,147,150,152,154,156,158,160,162,164,166,168,170,\ -172,174,176,178,180,182,183,185,187,188,190,192,193,195,196,198,199,200,202,203,204,\ -205,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,222,223,224,225,\ +172,174,176,178,180,182,183,185,187,188,190,192,193,195,196,198,199,200,202,203,205,\ +206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,222,223,224,225,\ 226,226,227,228,228,229,230,230,231,232,232,233,233,234,235,235,236,236,237,237,238,\ 238,239,239,240}; @@ -207,33 +240,42 @@ extern inline u8 TEMP_TO_REG(long val) // No interpolation here. if (val<=-500) return (u8)SENSORS_LIMIT(viaLUT[0],0,255); if (val>=1100) return (u8)SENSORS_LIMIT(viaLUT[160],0,255); - // the +5 effective rounds it off properly + // the +5 effectively rounds it off properly, the +50 is because the temps start at -50 return (u8)SENSORS_LIMIT(viaLUT[(val+5)/10+50],0,255); } /* for 8-bit temperature hyst and over registers */ extern inline long TEMP_FROM_REG(u8 val) { - // the LUT starts at 12 (not 0) and ends at 240 (not 255), so that's why we do what we do here. - return (long)(tempLUT[(val<11)?(0):((val>240)?(228):(val-12))]*10); + // the temp values are already *10, so we don't need to do that. + // However, we will round these off to the nearest degree with (...*10+5)/10 + return (long)((tempLUT[val]*10+5)/10); } /* for 10-bit temperature readings */ extern inline long TEMP_FROM_REG10(u16 val) { + // the temp values are already *10, so we don't need to do that. + long temp; u16 eightBits = val>>2; u16 twoBits = val&3; - if (val<=48) return (long)tempLUT[0]*10; // via8bit<=12 - if (val>=960) return (long)tempLUT[228]*10; // via8bit>=240 - + // handle the extremes first (they won't interpolate well! ;) + if (val==0) + return (long)tempLUT[0]; + if (val==1023) + return (long)tempLUT[255]; + if (twoBits==0) - return (long)tempLUT[eightBits-12]*10; + return (long)tempLUT[eightBits]; else { // do some interpolation by multipying the lower and uppers bounds by 25, 50 or 75 - // (depending on which it's closer to), then /100. But since we need to *10 anyway, we only /10 - // ***FIX THIS*** we should properly round this off - return (long)(((25*(4-twoBits))*tempLUT[eightBits-12] + (25*twoBits)*tempLUT[eightBits-11])/10); + // (depending on which it's closer to), then /100. + temp = ((25*(4-twoBits))*tempLUT[eightBits] + (25*twoBits)*tempLUT[eightBits+1]); + // before /100, increase the magnitude by 50 to achieve rounding. + if (temp>0) temp += 50; + else temp -= 50; + return(temp/100); } } @@ -833,7 +875,7 @@ EXPORT_NO_SYMBOLS; #ifdef MODULE -MODULE_AUTHOR("Kyösti Mälkki , Mark Studebaker "); +MODULE_AUTHOR("Kyösti Mälkki , Mark Studebaker , Bob Dougherty "); MODULE_DESCRIPTION("VIA 686A Sensor device"); int init_module(void)