diff options
author | Nate Case <ncase@xes-inc.com> | 2008-10-17 11:51:10 -0400 |
---|---|---|
committer | Jean Delvare <khali@mahadeva.delvare> | 2008-10-17 11:51:10 -0400 |
commit | 23b2d4778ad33ee6bfe60439fb73c16580f204f2 (patch) | |
tree | 9122f72ca2c06558b6e1f176e277393c85dda52d | |
parent | cea50fe2fdea36174aa24b58c69c4eb9770e7c49 (diff) |
hwmon: (lm90) Support ADT7461 in extended mode
Support ADT7461 in extended temperature range mode, which will change
the range of readings from 0..127 to -64..191 degC. Adjust the
register conversion functions accordingly.
Signed-off-by: Nate Case <ncase@xes-inc.com>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Tested-by: Martyn Welch <martyn.welch@gefanuc.com>
-rw-r--r-- | Documentation/hwmon/lm90 | 8 | ||||
-rw-r--r-- | drivers/hwmon/Kconfig | 7 | ||||
-rw-r--r-- | drivers/hwmon/lm90.c | 120 |
3 files changed, 97 insertions, 38 deletions
diff --git a/Documentation/hwmon/lm90 b/Documentation/hwmon/lm90 index 0c08c5c5637b..53cd829f3f4d 100644 --- a/Documentation/hwmon/lm90 +++ b/Documentation/hwmon/lm90 | |||
@@ -32,7 +32,6 @@ Supported chips: | |||
32 | Addresses scanned: I2C 0x4c and 0x4d | 32 | Addresses scanned: I2C 0x4c and 0x4d |
33 | Datasheet: Publicly available at the ON Semiconductor website | 33 | Datasheet: Publicly available at the ON Semiconductor website |
34 | http://www.onsemi.com/PowerSolutions/product.do?id=ADT7461 | 34 | http://www.onsemi.com/PowerSolutions/product.do?id=ADT7461 |
35 | Note: Only if in ADM1032 compatibility mode | ||
36 | * Maxim MAX6657 | 35 | * Maxim MAX6657 |
37 | Prefix: 'max6657' | 36 | Prefix: 'max6657' |
38 | Addresses scanned: I2C 0x4c | 37 | Addresses scanned: I2C 0x4c |
@@ -70,16 +69,13 @@ Description | |||
70 | 69 | ||
71 | The LM90 is a digital temperature sensor. It senses its own temperature as | 70 | The LM90 is a digital temperature sensor. It senses its own temperature as |
72 | well as the temperature of up to one external diode. It is compatible | 71 | well as the temperature of up to one external diode. It is compatible |
73 | with many other devices such as the LM86, the LM89, the LM99, the ADM1032, | 72 | with many other devices, many of which are supported by this driver. |
74 | the MAX6657, MAX6658, MAX6659, MAX6680 and the MAX6681 all of which are | ||
75 | supported by this driver. | ||
76 | 73 | ||
77 | Note that there is no easy way to differentiate between the MAX6657, | 74 | Note that there is no easy way to differentiate between the MAX6657, |
78 | MAX6658 and MAX6659 variants. The extra address and features of the | 75 | MAX6658 and MAX6659 variants. The extra address and features of the |
79 | MAX6659 are not supported by this driver. The MAX6680 and MAX6681 only | 76 | MAX6659 are not supported by this driver. The MAX6680 and MAX6681 only |
80 | differ in their pinout, therefore they obviously can't (and don't need to) | 77 | differ in their pinout, therefore they obviously can't (and don't need to) |
81 | be distinguished. Additionally, the ADT7461 is supported if found in | 78 | be distinguished. |
82 | ADM1032 compatibility mode. | ||
83 | 79 | ||
84 | The specificity of this family of chipsets over the ADM1021/LM84 | 80 | The specificity of this family of chipsets over the ADM1021/LM84 |
85 | family is that it features critical limits with hysteresis, and an | 81 | family is that it features critical limits with hysteresis, and an |
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index ebacc0af40fe..96701e099e81 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -510,11 +510,8 @@ config SENSORS_LM90 | |||
510 | depends on I2C | 510 | depends on I2C |
511 | help | 511 | help |
512 | If you say yes here you get support for National Semiconductor LM90, | 512 | If you say yes here you get support for National Semiconductor LM90, |
513 | LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657, | 513 | LM86, LM89 and LM99, Analog Devices ADM1032 and ADT7461, and Maxim |
514 | MAX6658, MAX6659, MAX6680 and MAX6681 sensor chips. | 514 | MAX6657, MAX6658, MAX6659, MAX6680 and MAX6681 sensor chips. |
515 | |||
516 | The Analog Devices ADT7461 sensor chip is also supported, but only | ||
517 | if found in ADM1032 compatibility mode. | ||
518 | 515 | ||
519 | This driver can also be built as a module. If so, the module | 516 | This driver can also be built as a module. If so, the module |
520 | will be called lm90. | 517 | will be called lm90. |
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index b2d9b3f0946d..fe5d860fc838 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c | |||
@@ -37,11 +37,10 @@ | |||
37 | * chips. The MAX6680 and MAX6681 only differ in the pinout so they can | 37 | * chips. The MAX6680 and MAX6681 only differ in the pinout so they can |
38 | * be treated identically. | 38 | * be treated identically. |
39 | * | 39 | * |
40 | * This driver also supports the ADT7461 chip from Analog Devices but | 40 | * This driver also supports the ADT7461 chip from Analog Devices. |
41 | * only in its "compatability mode". If an ADT7461 chip is found but | 41 | * It's supported in both compatibility and extended mode. It is mostly |
42 | * is configured in non-compatible mode (where its temperature | 42 | * compatible with LM90 except for a data format difference for the |
43 | * register values are decoded differently) it is ignored by this | 43 | * temperature value registers. |
44 | * driver. | ||
45 | * | 44 | * |
46 | * Since the LM90 was the first chipset supported by this driver, most | 45 | * Since the LM90 was the first chipset supported by this driver, most |
47 | * comments will refer to this chipset, but are actually general and | 46 | * comments will refer to this chipset, but are actually general and |
@@ -138,6 +137,11 @@ I2C_CLIENT_INSMOD_7(lm90, adm1032, lm99, lm86, max6657, adt7461, max6680); | |||
138 | #define MAX6657_REG_R_LOCAL_TEMPL 0x11 | 137 | #define MAX6657_REG_R_LOCAL_TEMPL 0x11 |
139 | 138 | ||
140 | /* | 139 | /* |
140 | * Device flags | ||
141 | */ | ||
142 | #define LM90_FLAG_ADT7461_EXT 0x01 /* ADT7461 extended mode */ | ||
143 | |||
144 | /* | ||
141 | * Functions declaration | 145 | * Functions declaration |
142 | */ | 146 | */ |
143 | 147 | ||
@@ -191,6 +195,7 @@ struct lm90_data { | |||
191 | char valid; /* zero until following fields are valid */ | 195 | char valid; /* zero until following fields are valid */ |
192 | unsigned long last_updated; /* in jiffies */ | 196 | unsigned long last_updated; /* in jiffies */ |
193 | int kind; | 197 | int kind; |
198 | int flags; | ||
194 | 199 | ||
195 | /* registers values */ | 200 | /* registers values */ |
196 | s8 temp8[4]; /* 0: local low limit | 201 | s8 temp8[4]; /* 0: local low limit |
@@ -256,26 +261,61 @@ static u8 hyst_to_reg(long val) | |||
256 | } | 261 | } |
257 | 262 | ||
258 | /* | 263 | /* |
259 | * ADT7461 is almost identical to LM90 except that attempts to write | 264 | * ADT7461 in compatibility mode is almost identical to LM90 except that |
260 | * values that are outside the range 0 < temp < 127 are treated as | 265 | * attempts to write values that are outside the range 0 < temp < 127 are |
261 | * the boundary value. | 266 | * treated as the boundary value. |
267 | * | ||
268 | * ADT7461 in "extended mode" operation uses unsigned integers offset by | ||
269 | * 64 (e.g., 0 -> -64 degC). The range is restricted to -64..191 degC. | ||
262 | */ | 270 | */ |
263 | static u8 temp1_to_reg_adt7461(long val) | 271 | static inline int temp1_from_reg_adt7461(struct lm90_data *data, u8 val) |
264 | { | 272 | { |
265 | if (val <= 0) | 273 | if (data->flags & LM90_FLAG_ADT7461_EXT) |
266 | return 0; | 274 | return (val - 64) * 1000; |
267 | if (val >= 127000) | 275 | else |
268 | return 127; | 276 | return temp1_from_reg(val); |
269 | return (val + 500) / 1000; | ||
270 | } | 277 | } |
271 | 278 | ||
272 | static u16 temp2_to_reg_adt7461(long val) | 279 | static inline int temp2_from_reg_adt7461(struct lm90_data *data, u16 val) |
273 | { | 280 | { |
274 | if (val <= 0) | 281 | if (data->flags & LM90_FLAG_ADT7461_EXT) |
275 | return 0; | 282 | return (val - 0x4000) / 64 * 250; |
276 | if (val >= 127750) | 283 | else |
277 | return 0x7FC0; | 284 | return temp2_from_reg(val); |
278 | return (val + 125) / 250 * 64; | 285 | } |
286 | |||
287 | static u8 temp1_to_reg_adt7461(struct lm90_data *data, long val) | ||
288 | { | ||
289 | if (data->flags & LM90_FLAG_ADT7461_EXT) { | ||
290 | if (val <= -64000) | ||
291 | return 0; | ||
292 | if (val >= 191000) | ||
293 | return 0xFF; | ||
294 | return (val + 500 + 64000) / 1000; | ||
295 | } else { | ||
296 | if (val <= 0) | ||
297 | return 0; | ||
298 | if (val >= 127000) | ||
299 | return 127; | ||
300 | return (val + 500) / 1000; | ||
301 | } | ||
302 | } | ||
303 | |||
304 | static u16 temp2_to_reg_adt7461(struct lm90_data *data, long val) | ||
305 | { | ||
306 | if (data->flags & LM90_FLAG_ADT7461_EXT) { | ||
307 | if (val <= -64000) | ||
308 | return 0; | ||
309 | if (val >= 191750) | ||
310 | return 0xFFC0; | ||
311 | return (val + 64000 + 125) / 250 * 64; | ||
312 | } else { | ||
313 | if (val <= 0) | ||
314 | return 0; | ||
315 | if (val >= 127750) | ||
316 | return 0x7FC0; | ||
317 | return (val + 125) / 250 * 64; | ||
318 | } | ||
279 | } | 319 | } |
280 | 320 | ||
281 | /* | 321 | /* |
@@ -287,7 +327,14 @@ static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, | |||
287 | { | 327 | { |
288 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 328 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
289 | struct lm90_data *data = lm90_update_device(dev); | 329 | struct lm90_data *data = lm90_update_device(dev); |
290 | return sprintf(buf, "%d\n", temp1_from_reg(data->temp8[attr->index])); | 330 | int temp; |
331 | |||
332 | if (data->kind == adt7461) | ||
333 | temp = temp1_from_reg_adt7461(data, data->temp8[attr->index]); | ||
334 | else | ||
335 | temp = temp1_from_reg(data->temp8[attr->index]); | ||
336 | |||
337 | return sprintf(buf, "%d\n", temp); | ||
291 | } | 338 | } |
292 | 339 | ||
293 | static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, | 340 | static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, |
@@ -308,7 +355,7 @@ static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, | |||
308 | 355 | ||
309 | mutex_lock(&data->update_lock); | 356 | mutex_lock(&data->update_lock); |
310 | if (data->kind == adt7461) | 357 | if (data->kind == adt7461) |
311 | data->temp8[nr] = temp1_to_reg_adt7461(val); | 358 | data->temp8[nr] = temp1_to_reg_adt7461(data, val); |
312 | else | 359 | else |
313 | data->temp8[nr] = temp1_to_reg(val); | 360 | data->temp8[nr] = temp1_to_reg(val); |
314 | i2c_smbus_write_byte_data(client, reg[nr], data->temp8[nr]); | 361 | i2c_smbus_write_byte_data(client, reg[nr], data->temp8[nr]); |
@@ -321,7 +368,14 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, | |||
321 | { | 368 | { |
322 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 369 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
323 | struct lm90_data *data = lm90_update_device(dev); | 370 | struct lm90_data *data = lm90_update_device(dev); |
324 | return sprintf(buf, "%d\n", temp2_from_reg(data->temp11[attr->index])); | 371 | int temp; |
372 | |||
373 | if (data->kind == adt7461) | ||
374 | temp = temp2_from_reg_adt7461(data, data->temp11[attr->index]); | ||
375 | else | ||
376 | temp = temp2_from_reg(data->temp11[attr->index]); | ||
377 | |||
378 | return sprintf(buf, "%d\n", temp); | ||
325 | } | 379 | } |
326 | 380 | ||
327 | static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, | 381 | static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, |
@@ -344,7 +398,7 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, | |||
344 | 398 | ||
345 | mutex_lock(&data->update_lock); | 399 | mutex_lock(&data->update_lock); |
346 | if (data->kind == adt7461) | 400 | if (data->kind == adt7461) |
347 | data->temp11[nr] = temp2_to_reg_adt7461(val); | 401 | data->temp11[nr] = temp2_to_reg_adt7461(data, val); |
348 | else if (data->kind == max6657 || data->kind == max6680) | 402 | else if (data->kind == max6657 || data->kind == max6680) |
349 | data->temp11[nr] = temp1_to_reg(val) << 8; | 403 | data->temp11[nr] = temp1_to_reg(val) << 8; |
350 | else | 404 | else |
@@ -364,8 +418,14 @@ static ssize_t show_temphyst(struct device *dev, struct device_attribute *devatt | |||
364 | { | 418 | { |
365 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 419 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
366 | struct lm90_data *data = lm90_update_device(dev); | 420 | struct lm90_data *data = lm90_update_device(dev); |
367 | return sprintf(buf, "%d\n", temp1_from_reg(data->temp8[attr->index]) | 421 | int temp; |
368 | - temp1_from_reg(data->temp_hyst)); | 422 | |
423 | if (data->kind == adt7461) | ||
424 | temp = temp1_from_reg_adt7461(data, data->temp8[attr->index]); | ||
425 | else | ||
426 | temp = temp1_from_reg(data->temp8[attr->index]); | ||
427 | |||
428 | return sprintf(buf, "%d\n", temp - temp1_from_reg(data->temp_hyst)); | ||
369 | } | 429 | } |
370 | 430 | ||
371 | static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy, | 431 | static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy, |
@@ -598,7 +658,7 @@ static int lm90_detect(struct i2c_client *new_client, int kind, | |||
598 | kind = adm1032; | 658 | kind = adm1032; |
599 | } else | 659 | } else |
600 | if (chip_id == 0x51 /* ADT7461 */ | 660 | if (chip_id == 0x51 /* ADT7461 */ |
601 | && (reg_config1 & 0x1F) == 0x00 /* check compat mode */ | 661 | && (reg_config1 & 0x1B) == 0x00 |
602 | && reg_convrate <= 0x0A) { | 662 | && reg_convrate <= 0x0A) { |
603 | kind = adt7461; | 663 | kind = adt7461; |
604 | } | 664 | } |
@@ -737,6 +797,12 @@ static void lm90_init_client(struct i2c_client *client) | |||
737 | } | 797 | } |
738 | config_orig = config; | 798 | config_orig = config; |
739 | 799 | ||
800 | /* Check Temperature Range Select */ | ||
801 | if (data->kind == adt7461) { | ||
802 | if (config & 0x04) | ||
803 | data->flags |= LM90_FLAG_ADT7461_EXT; | ||
804 | } | ||
805 | |||
740 | /* | 806 | /* |
741 | * Put MAX6680/MAX8881 into extended resolution (bit 0x10, | 807 | * Put MAX6680/MAX8881 into extended resolution (bit 0x10, |
742 | * 0.125 degree resolution) and range (0x08, extend range | 808 | * 0.125 degree resolution) and range (0x08, extend range |