diff options
author | Guenter Roeck <linux@roeck-us.net> | 2013-06-27 13:07:19 -0400 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2013-06-28 09:43:55 -0400 |
commit | a50d9a4d9ad3c71341788099d733e4151b8a511b (patch) | |
tree | b443b672ccc6a1bb6fc50dfdff3f5c5d3cf087ae /drivers/hwmon | |
parent | 41fa9a944fce1d7efd5ee3d50ac85b92f42dcc3d (diff) |
hwmon: (ds1621) Fix temperature rounding operations
Commit "hwmon: (ds1621) Add ds1721 chip support" broke rounding
for chips or configurations with less than 12 bit resolution.
Tested-by: Jean Delvare <khali@linux-fr.org>
Acked-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/ds1621.c | 21 |
1 files changed, 12 insertions, 9 deletions
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index 591758bb629f..a26ba7a17c2b 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c | |||
@@ -128,6 +128,8 @@ struct ds1621_data { | |||
128 | 128 | ||
129 | u16 temp[3]; /* Register values, word */ | 129 | u16 temp[3]; /* Register values, word */ |
130 | u8 conf; /* Register encoding, combined */ | 130 | u8 conf; /* Register encoding, combined */ |
131 | u8 zbits; /* Resolution encoded as number of | ||
132 | * zero bits */ | ||
131 | u16 update_interval; /* Conversion rate in milliseconds */ | 133 | u16 update_interval; /* Conversion rate in milliseconds */ |
132 | }; | 134 | }; |
133 | 135 | ||
@@ -139,16 +141,14 @@ static inline int DS1621_TEMP_FROM_REG(u16 reg) | |||
139 | /* | 141 | /* |
140 | * TEMP: 0.001C/bit (-55C to +125C) | 142 | * TEMP: 0.001C/bit (-55C to +125C) |
141 | * REG: | 143 | * REG: |
142 | * - 1621, 1625: 0.5C/bit | 144 | * - 1621, 1625: 0.5C/bit, 7 zero-bits |
143 | * - 1631, 1721, 1731: 0.0625C/bit | 145 | * - 1631, 1721, 1731: 0.0625C/bit, 4 zero-bits |
144 | * Assume highest resolution and let the bits fall where they may.. | ||
145 | */ | 146 | */ |
146 | static inline u16 DS1621_TEMP_TO_REG(long temp) | 147 | static inline u16 DS1621_TEMP_TO_REG(long temp, u8 zbits) |
147 | { | 148 | { |
148 | int ntemp = clamp_val(temp, DS1621_TEMP_MIN, DS1621_TEMP_MAX); | 149 | temp = clamp_val(temp, DS1621_TEMP_MIN, DS1621_TEMP_MAX); |
149 | ntemp += (ntemp < 0 ? -31 : 31); | 150 | temp = DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits; |
150 | ntemp = DIV_ROUND_CLOSEST(ntemp * 10, 625) << 4; | 151 | return temp; |
151 | return (u16)ntemp; | ||
152 | } | 152 | } |
153 | 153 | ||
154 | static void ds1621_init_client(struct i2c_client *client) | 154 | static void ds1621_init_client(struct i2c_client *client) |
@@ -172,6 +172,7 @@ static void ds1621_init_client(struct i2c_client *client) | |||
172 | switch (data->kind) { | 172 | switch (data->kind) { |
173 | case ds1625: | 173 | case ds1625: |
174 | data->update_interval = DS1625_CONVERSION_MAX; | 174 | data->update_interval = DS1625_CONVERSION_MAX; |
175 | data->zbits = 7; | ||
175 | sreg = DS1621_COM_START; | 176 | sreg = DS1621_COM_START; |
176 | break; | 177 | break; |
177 | case ds1631: | 178 | case ds1631: |
@@ -180,10 +181,12 @@ static void ds1621_init_client(struct i2c_client *client) | |||
180 | resol = (new_conf & DS1621_REG_CONFIG_RESOL) >> | 181 | resol = (new_conf & DS1621_REG_CONFIG_RESOL) >> |
181 | DS1621_REG_CONFIG_RESOL_SHIFT; | 182 | DS1621_REG_CONFIG_RESOL_SHIFT; |
182 | data->update_interval = ds1721_convrates[resol]; | 183 | data->update_interval = ds1721_convrates[resol]; |
184 | data->zbits = 7 - resol; | ||
183 | sreg = DS1721_COM_START; | 185 | sreg = DS1721_COM_START; |
184 | break; | 186 | break; |
185 | default: | 187 | default: |
186 | data->update_interval = DS1621_CONVERSION_MAX; | 188 | data->update_interval = DS1621_CONVERSION_MAX; |
189 | data->zbits = 7; | ||
187 | sreg = DS1621_COM_START; | 190 | sreg = DS1621_COM_START; |
188 | break; | 191 | break; |
189 | } | 192 | } |
@@ -254,7 +257,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, | |||
254 | return err; | 257 | return err; |
255 | 258 | ||
256 | mutex_lock(&data->update_lock); | 259 | mutex_lock(&data->update_lock); |
257 | data->temp[attr->index] = DS1621_TEMP_TO_REG(val); | 260 | data->temp[attr->index] = DS1621_TEMP_TO_REG(val, data->zbits); |
258 | i2c_smbus_write_word_swapped(client, DS1621_REG_TEMP[attr->index], | 261 | i2c_smbus_write_word_swapped(client, DS1621_REG_TEMP[attr->index], |
259 | data->temp[attr->index]); | 262 | data->temp[attr->index]); |
260 | mutex_unlock(&data->update_lock); | 263 | mutex_unlock(&data->update_lock); |