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>
This commit is contained in:
parent
cea50fe2fd
commit
23b2d4778a
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user