Commit 06ad1312 authored by Jean Delvare's avatar Jean Delvare Committed by Deepak Saxena

[PATCH] I2C: Rewrite temperature conversions in via686a driver

The following patch rewrites the temperature conversion macros and
functions found in the via686a chip driver. Contrary to the voltage
conversions a few weeks ago, temperature conversions were numerically
correct, but artificially complex. The new ones are cleaner. It also
fixes a highly improbable array overflow (would take one of the measured
temperatures to be over 145 degrees C).

Successfully tested by Mark D. Studebaker and I, and already applied to
our CVS repository.
parent 888c8b6b
...@@ -268,52 +268,31 @@ static const u8 viaLUT[] = ...@@ -268,52 +268,31 @@ static const u8 viaLUT[] =
239, 240 239, 240
}; };
/* Converting temps to (8-bit) hyst and over registers /* Converting temps to (8-bit) hyst and over registers
No interpolation here. Just check the limits and go. No interpolation here.
The +5 effectively rounds off properly and the +50 is because The +50 is because the temps start at -50 */
the temps start at -50 */
static inline u8 TEMP_TO_REG(long val) static inline u8 TEMP_TO_REG(long val)
{ {
return (u8) return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 :
SENSORS_LIMIT(viaLUT[((val <= -500) ? 0 : (val >= 1100) ? 160 : (val < 0 ? val - 500 : val + 500) / 1000 + 50];
((val + 5) / 10 + 50))], 0, 255);
} }
/* for 8-bit temperature hyst and over registers /* for 8-bit temperature hyst and over registers */
The temp values are already *10, so we don't need to do that. #define TEMP_FROM_REG(val) (tempLUT[(val)] * 100)
But we _will_ round these off to the nearest degree with (...*10+5)/10 */
#define TEMP_FROM_REG(val) ((tempLUT[(val)]*10+5)/10)
/* for 10-bit temperature readings /* for 10-bit temperature readings */
You might _think_ this is too long to inline, but's it's really only
called once... */
static inline long TEMP_FROM_REG10(u16 val) static 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 eightBits = val >> 2;
u16 twoBits = val & 3; u16 twoBits = val & 3;
/* handle the extremes first (they won't interpolate well! ;-) */ /* no interpolation for these */
if (val == 0) if (twoBits == 0 || eightBits == 255)
return (long) tempLUT[0]; return TEMP_FROM_REG(eightBits);
if (val == 1023)
return (long) tempLUT[255]; /* do some linear interpolation */
return (tempLUT[eightBits] * (4 - twoBits) +
if (twoBits == 0) tempLUT[eightBits + 1] * twoBits) * 25;
return (long) tempLUT[eightBits];
else {
/* do some interpolation by multipying the lower and upper
bounds by 25, 50 or 75, then /100. */
temp = ((25 * (4 - twoBits)) * tempLUT[eightBits]
+ (25 * twoBits) * tempLUT[eightBits + 1]);
/* increase the magnitude by 50 to achieve rounding. */
if (temp > 0)
temp += 50;
else
temp -= 50;
return (temp / 100);
}
} }
#define ALARMS_FROM_REG(val) (val) #define ALARMS_FROM_REG(val) (val)
...@@ -441,21 +420,21 @@ show_in_offset(4); ...@@ -441,21 +420,21 @@ show_in_offset(4);
/* 3 temperatures */ /* 3 temperatures */
static ssize_t show_temp(struct device *dev, char *buf, int nr) { static ssize_t show_temp(struct device *dev, char *buf, int nr) {
struct via686a_data *data = via686a_update_device(dev); struct via686a_data *data = via686a_update_device(dev);
return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr])*100 ); return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
} }
static ssize_t show_temp_over(struct device *dev, char *buf, int nr) { static ssize_t show_temp_over(struct device *dev, char *buf, int nr) {
struct via686a_data *data = via686a_update_device(dev); struct via686a_data *data = via686a_update_device(dev);
return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr])*100); return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
} }
static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) { static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) {
struct via686a_data *data = via686a_update_device(dev); struct via686a_data *data = via686a_update_device(dev);
return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr])*100); return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
} }
static ssize_t set_temp_over(struct device *dev, const char *buf, static ssize_t set_temp_over(struct device *dev, const char *buf,
size_t count, int nr) { size_t count, int nr) {
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client); struct via686a_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10)/100; int val = simple_strtol(buf, NULL, 10);
data->temp_over[nr] = TEMP_TO_REG(val); data->temp_over[nr] = TEMP_TO_REG(val);
via686a_write_value(client, VIA686A_REG_TEMP_OVER(nr), data->temp_over[nr]); via686a_write_value(client, VIA686A_REG_TEMP_OVER(nr), data->temp_over[nr]);
return count; return count;
...@@ -464,7 +443,7 @@ static ssize_t set_temp_hyst(struct device *dev, const char *buf, ...@@ -464,7 +443,7 @@ static ssize_t set_temp_hyst(struct device *dev, const char *buf,
size_t count, int nr) { size_t count, int nr) {
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client); struct via686a_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10)/100; int val = simple_strtol(buf, NULL, 10);
data->temp_hyst[nr] = TEMP_TO_REG(val); data->temp_hyst[nr] = TEMP_TO_REG(val);
via686a_write_value(client, VIA686A_REG_TEMP_HYST(nr), data->temp_hyst[nr]); via686a_write_value(client, VIA686A_REG_TEMP_HYST(nr), data->temp_hyst[nr]);
return count; return count;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment