Addresses scanned: I2C 0x4c and 0x4d
Datasheet: Publicly available at the ON Semiconductor website
http://www.onsemi.com/PowerSolutions/product.do?id=ADT7461
- Note: Only if in ADM1032 compatibility mode
* Maxim MAX6657
Prefix: 'max6657'
Addresses scanned: I2C 0x4c
The LM90 is a digital temperature sensor. It senses its own temperature as
well as the temperature of up to one external diode. It is compatible
-with many other devices such as the LM86, the LM89, the LM99, the ADM1032,
-the MAX6657, MAX6658, MAX6659, MAX6680 and the MAX6681 all of which are
-supported by this driver.
+with many other devices, many of which are supported by this driver.
Note that there is no easy way to differentiate between the MAX6657,
MAX6658 and MAX6659 variants. The extra address and features of the
MAX6659 are not supported by this driver. The MAX6680 and MAX6681 only
differ in their pinout, therefore they obviously can't (and don't need to)
-be distinguished. Additionally, the ADT7461 is supported if found in
-ADM1032 compatibility mode.
+be distinguished.
The specificity of this family of chipsets over the ADM1021/LM84
family is that it features critical limits with hysteresis, and an
* chips. The MAX6680 and MAX6681 only differ in the pinout so they can
* be treated identically.
*
- * This driver also supports the ADT7461 chip from Analog Devices but
- * only in its "compatability mode". If an ADT7461 chip is found but
- * is configured in non-compatible mode (where its temperature
- * register values are decoded differently) it is ignored by this
- * driver.
+ * This driver also supports the ADT7461 chip from Analog Devices.
+ * It's supported in both compatibility and extended mode. It is mostly
+ * compatible with LM90 except for a data format difference for the
+ * temperature value registers.
*
* Since the LM90 was the first chipset supported by this driver, most
* comments will refer to this chipset, but are actually general and
#define MAX6657_REG_R_LOCAL_TEMPL 0x11
/*
+ * Device flags
+ */
+#define LM90_FLAG_ADT7461_EXT 0x01 /* ADT7461 extended mode */
+
+/*
* Functions declaration
*/
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
int kind;
+ int flags;
/* registers values */
s8 temp8[4]; /* 0: local low limit
}
/*
- * ADT7461 is almost identical to LM90 except that attempts to write
- * values that are outside the range 0 < temp < 127 are treated as
- * the boundary value.
+ * ADT7461 in compatibility mode is almost identical to LM90 except that
+ * attempts to write values that are outside the range 0 < temp < 127 are
+ * treated as the boundary value.
+ *
+ * ADT7461 in "extended mode" operation uses unsigned integers offset by
+ * 64 (e.g., 0 -> -64 degC). The range is restricted to -64..191 degC.
*/
-static u8 temp1_to_reg_adt7461(long val)
+static inline int temp1_from_reg_adt7461(struct lm90_data *data, u8 val)
{
- if (val <= 0)
- return 0;
- if (val >= 127000)
- return 127;
- return (val + 500) / 1000;
+ if (data->flags & LM90_FLAG_ADT7461_EXT)
+ return (val - 64) * 1000;
+ else
+ return temp1_from_reg(val);
}
-static u16 temp2_to_reg_adt7461(long val)
+static inline int temp2_from_reg_adt7461(struct lm90_data *data, u16 val)
{
- if (val <= 0)
- return 0;
- if (val >= 127750)
- return 0x7FC0;
- return (val + 125) / 250 * 64;
+ if (data->flags & LM90_FLAG_ADT7461_EXT)
+ return (val - 0x4000) / 64 * 250;
+ else
+ return temp2_from_reg(val);
+}
+
+static u8 temp1_to_reg_adt7461(struct lm90_data *data, long val)
+{
+ if (data->flags & LM90_FLAG_ADT7461_EXT) {
+ if (val <= -64000)
+ return 0;
+ if (val >= 191000)
+ return 0xFF;
+ return (val + 500 + 64000) / 1000;
+ } else {
+ if (val <= 0)
+ return 0;
+ if (val >= 127000)
+ return 127;
+ return (val + 500) / 1000;
+ }
+}
+
+static u16 temp2_to_reg_adt7461(struct lm90_data *data, long val)
+{
+ if (data->flags & LM90_FLAG_ADT7461_EXT) {
+ if (val <= -64000)
+ return 0;
+ if (val >= 191750)
+ return 0xFFC0;
+ return (val + 64000 + 125) / 250 * 64;
+ } else {
+ if (val <= 0)
+ return 0;
+ if (val >= 127750)
+ return 0x7FC0;
+ return (val + 125) / 250 * 64;
+ }
}
/*
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm90_data *data = lm90_update_device(dev);
- return sprintf(buf, "%d\n", temp1_from_reg(data->temp8[attr->index]));
+ int temp;
+
+ if (data->kind == adt7461)
+ temp = temp1_from_reg_adt7461(data, data->temp8[attr->index]);
+ else
+ temp = temp1_from_reg(data->temp8[attr->index]);
+
+ return sprintf(buf, "%d\n", temp);
}
static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
mutex_lock(&data->update_lock);
if (data->kind == adt7461)
- data->temp8[nr] = temp1_to_reg_adt7461(val);
+ data->temp8[nr] = temp1_to_reg_adt7461(data, val);
else
data->temp8[nr] = temp1_to_reg(val);
i2c_smbus_write_byte_data(client, reg[nr], data->temp8[nr]);
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm90_data *data = lm90_update_device(dev);
- return sprintf(buf, "%d\n", temp2_from_reg(data->temp11[attr->index]));
+ int temp;
+
+ if (data->kind == adt7461)
+ temp = temp2_from_reg_adt7461(data, data->temp11[attr->index]);
+ else
+ temp = temp2_from_reg(data->temp11[attr->index]);
+
+ return sprintf(buf, "%d\n", temp);
}
static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
mutex_lock(&data->update_lock);
if (data->kind == adt7461)
- data->temp11[nr] = temp2_to_reg_adt7461(val);
+ data->temp11[nr] = temp2_to_reg_adt7461(data, val);
else if (data->kind == max6657 || data->kind == max6680)
data->temp11[nr] = temp1_to_reg(val) << 8;
else
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm90_data *data = lm90_update_device(dev);
- return sprintf(buf, "%d\n", temp1_from_reg(data->temp8[attr->index])
- - temp1_from_reg(data->temp_hyst));
+ int temp;
+
+ if (data->kind == adt7461)
+ temp = temp1_from_reg_adt7461(data, data->temp8[attr->index]);
+ else
+ temp = temp1_from_reg(data->temp8[attr->index]);
+
+ return sprintf(buf, "%d\n", temp - temp1_from_reg(data->temp_hyst));
}
static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy,
kind = adm1032;
} else
if (chip_id == 0x51 /* ADT7461 */
- && (reg_config1 & 0x1F) == 0x00 /* check compat mode */
+ && (reg_config1 & 0x1B) == 0x00
&& reg_convrate <= 0x0A) {
kind = adt7461;
}
}
config_orig = config;
+ /* Check Temperature Range Select */
+ if (data->kind == adt7461) {
+ if (config & 0x04)
+ data->flags |= LM90_FLAG_ADT7461_EXT;
+ }
+
/*
* Put MAX6680/MAX8881 into extended resolution (bit 0x10,
* 0.125 degree resolution) and range (0x08, extend range