|
@@ -37,11 +37,10 @@
|
|
|
* 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
|
|
@@ -137,6 +136,11 @@ I2C_CLIENT_INSMOD_7(lm90, adm1032, lm99, lm86, max6657, adt7461, max6680);
|
|
|
|
|
|
#define MAX6657_REG_R_LOCAL_TEMPL 0x11
|
|
|
|
|
|
+/*
|
|
|
+ * Device flags
|
|
|
+ */
|
|
|
+#define LM90_FLAG_ADT7461_EXT 0x01 /* ADT7461 extended mode */
|
|
|
+
|
|
|
/*
|
|
|
* Functions declaration
|
|
|
*/
|
|
@@ -191,6 +195,7 @@ struct lm90_data {
|
|
|
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
|
|
@@ -256,26 +261,61 @@ static u8 hyst_to_reg(long val)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * 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;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -287,7 +327,14 @@ static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
|
|
|
{
|
|
|
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,
|
|
@@ -308,7 +355,7 @@ 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]);
|
|
@@ -321,7 +368,14 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
|
|
|
{
|
|
|
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,
|
|
@@ -344,7 +398,7 @@ 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
|
|
@@ -364,8 +418,14 @@ static ssize_t show_temphyst(struct device *dev, struct device_attribute *devatt
|
|
|
{
|
|
|
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,
|
|
@@ -598,7 +658,7 @@ static int lm90_detect(struct i2c_client *new_client, int kind,
|
|
|
kind = adm1032;
|
|
|
} else
|
|
|
if (chip_id == 0x51 /* ADT7461 */
|
|
|
- && (reg_config1 & 0x1F) == 0x00 /* check compat mode */
|
|
|
+ && (reg_config1 & 0x1B) == 0x00
|
|
|
&& reg_convrate <= 0x0A) {
|
|
|
kind = adt7461;
|
|
|
}
|
|
@@ -737,6 +797,12 @@ static void lm90_init_client(struct i2c_client *client)
|
|
|
}
|
|
|
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
|