Commit 23b2d477 authored by Nate Case's avatar Nate Case Committed by Jean Delvare

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: default avatarNate Case <ncase@xes-inc.com>
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
Tested-by: default avatarMartyn Welch <martyn.welch@gefanuc.com>
parent cea50fe2
......@@ -32,7 +32,6 @@ Supported chips:
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
......@@ -70,16 +69,13 @@ Description
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
......
......@@ -510,11 +510,8 @@ config SENSORS_LM90
depends on I2C
help
If you say yes here you get support for National Semiconductor LM90,
LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657,
MAX6658, MAX6659, MAX6680 and MAX6681 sensor chips.
The Analog Devices ADT7461 sensor chip is also supported, but only
if found in ADM1032 compatibility mode.
LM86, LM89 and LM99, Analog Devices ADM1032 and ADT7461, and Maxim
MAX6657, MAX6658, MAX6659, MAX6680 and MAX6681 sensor chips.
This driver can also be built as a module. If so, the module
will be called lm90.
......
......@@ -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
......
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