summaryrefslogtreecommitdiff
path: root/drivers/hwmon
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/Kconfig9
-rw-r--r--drivers/hwmon/lm90.c264
2 files changed, 234 insertions, 39 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 39ce1b2ccbb3..1dd812cf15bb 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1358,11 +1358,12 @@ config SENSORS_LM90
tristate "National Semiconductor LM90 and compatibles"
depends on I2C
help
- If you say yes here you get support for National Semiconductor LM90,
- LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, ADT7461A,
+ If you say yes here you get support for National Semiconductor LM84,
+ LM90, LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, ADT7461A,
ADT7481, ADT7482, and ADT7483A,
- Maxim MAX6642, MAX6646, MAX6647, MAX6648, MAX6649, MAX6654, MAX6657,
- MAX6658, MAX6659, MAX6680, MAX6681, MAX6692, MAX6695, MAX6696,
+ Maxim MAX1617, MAX6642, MAX6646, MAX6647, MAX6648, MAX6649, MAX6654,
+ MAX6657, MAX6658, MAX6659, MAX6680, MAX6681, MAX6692, MAX6695,
+ MAX6696,
ON Semiconductor NCT1008, Winbond/Nuvoton W83L771W/G/AWG/ASG,
Philips SA56004, GMT G781, Texas Instruments TMP451 and TMP461
sensor chips.
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 75ea3a993920..2e85dbc4def7 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -80,6 +80,9 @@
* They are mostly compatible with ADT7461 except for local temperature
* low byte register and max conversion rate.
*
+ * This driver also supports MAX1617 and various clones such as G767
+ * and NE1617. Such clones will be detected as MAX1617.
+ *
* Since the LM90 was the first chipset supported by this driver, most
* comments will refer to this chipset, but are actually general and
* concern all supported chipsets, unless mentioned otherwise.
@@ -119,8 +122,8 @@ static const unsigned short normal_i2c[] = {
0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
-enum chips { adm1032, adt7461, adt7461a, adt7481, g781, lm86, lm90, lm99,
- max6642, max6646, max6648, max6654, max6657, max6659, max6680, max6696,
+enum chips { adm1032, adt7461, adt7461a, adt7481, g781, lm84, lm86, lm90, lm99,
+ max1617, max6642, max6646, max6648, max6654, max6657, max6659, max6680, max6696,
sa56004, tmp451, tmp461, w83l771,
};
@@ -194,6 +197,7 @@ enum chips { adm1032, adt7461, adt7461a, adt7481, g781, lm86, lm90, lm99,
#define LM90_HAVE_EXT_UNSIGNED BIT(14) /* extended unsigned temperature*/
#define LM90_HAVE_LOW BIT(15) /* low limits */
#define LM90_HAVE_CONVRATE BIT(16) /* conversion rate */
+#define LM90_HAVE_REMOTE_EXT BIT(17) /* extended remote temperature */
/* LM90 status */
#define LM90_STATUS_LTHRM BIT(0) /* local THERM limit tripped */
@@ -226,10 +230,12 @@ static const struct i2c_device_id lm90_id[] = {
{ "adt7482", adt7481 },
{ "adt7483a", adt7481 },
{ "g781", g781 },
- { "lm90", lm90 },
+ { "lm84", lm84 },
{ "lm86", lm86 },
{ "lm89", lm86 },
+ { "lm90", lm90 },
{ "lm99", lm99 },
+ { "max1617", max1617 },
{ "max6642", max6642 },
{ "max6646", max6646 },
{ "max6647", max6646 },
@@ -373,7 +379,7 @@ static const struct lm90_params lm90_params[] = {
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
| LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT
| LM90_HAVE_PARTIAL_PEC | LM90_HAVE_ALARMS
- | LM90_HAVE_LOW | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_LOW | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7c,
.max_convrate = 10,
},
@@ -386,7 +392,8 @@ static const struct lm90_params lm90_params[] = {
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
| LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP
| LM90_HAVE_CRIT | LM90_HAVE_PARTIAL_PEC
- | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+ | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7c,
.max_convrate = 10,
.resolution = 10,
@@ -395,7 +402,7 @@ static const struct lm90_params lm90_params[] = {
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
| LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP
| LM90_HAVE_CRIT | LM90_HAVE_PEC | LM90_HAVE_ALARMS
- | LM90_HAVE_LOW | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_LOW | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7c,
.max_convrate = 10,
},
@@ -404,7 +411,7 @@ static const struct lm90_params lm90_params[] = {
| LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP
| LM90_HAVE_UNSIGNED_TEMP | LM90_HAVE_PEC
| LM90_HAVE_TEMP3 | LM90_HAVE_CRIT | LM90_HAVE_LOW
- | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x1c7c,
.max_convrate = 11,
.resolution = 10,
@@ -413,38 +420,54 @@ static const struct lm90_params lm90_params[] = {
[g781] = {
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
| LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT
- | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+ | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7c,
.max_convrate = 7,
},
+ [lm84] = {
+ .flags = LM90_HAVE_ALARMS,
+ .resolution = 8,
+ },
[lm86] = {
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
- | LM90_HAVE_CRIT | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_CRIT | LM90_HAVE_ALARMS | LM90_HAVE_LOW
+ | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7b,
.max_convrate = 9,
},
[lm90] = {
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
- | LM90_HAVE_CRIT | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_CRIT | LM90_HAVE_ALARMS | LM90_HAVE_LOW
+ | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7b,
.max_convrate = 9,
},
[lm99] = {
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
- | LM90_HAVE_CRIT | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_CRIT | LM90_HAVE_ALARMS | LM90_HAVE_LOW
+ | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7b,
.max_convrate = 9,
},
+ [max1617] = {
+ .flags = LM90_HAVE_CONVRATE | LM90_HAVE_BROKEN_ALERT |
+ LM90_HAVE_LOW | LM90_HAVE_ALARMS,
+ .alert_alarms = 0x78,
+ .resolution = 8,
+ .max_convrate = 7,
+ },
[max6642] = {
- .flags = LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXT_UNSIGNED,
+ .flags = LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXT_UNSIGNED
+ | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x50,
- .reg_local_ext = MAX6657_REG_LOCAL_TEMPL,
.resolution = 10,
+ .reg_local_ext = MAX6657_REG_LOCAL_TEMPL,
},
[max6646] = {
.flags = LM90_HAVE_CRIT | LM90_HAVE_BROKEN_ALERT
| LM90_HAVE_EXT_UNSIGNED | LM90_HAVE_ALARMS | LM90_HAVE_LOW
- | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7c,
.max_convrate = 6,
.reg_local_ext = MAX6657_REG_LOCAL_TEMPL,
@@ -452,28 +475,30 @@ static const struct lm90_params lm90_params[] = {
[max6648] = {
.flags = LM90_HAVE_UNSIGNED_TEMP | LM90_HAVE_CRIT
| LM90_HAVE_BROKEN_ALERT | LM90_HAVE_LOW
- | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7c,
.max_convrate = 6,
.reg_local_ext = MAX6657_REG_LOCAL_TEMPL,
},
[max6654] = {
.flags = LM90_HAVE_BROKEN_ALERT | LM90_HAVE_ALARMS | LM90_HAVE_LOW
- | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7c,
.max_convrate = 7,
.reg_local_ext = MAX6657_REG_LOCAL_TEMPL,
},
[max6657] = {
.flags = LM90_PAUSE_FOR_CONFIG | LM90_HAVE_CRIT
- | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+ | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7c,
.max_convrate = 8,
.reg_local_ext = MAX6657_REG_LOCAL_TEMPL,
},
[max6659] = {
.flags = LM90_HAVE_EMERGENCY | LM90_HAVE_CRIT
- | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+ | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7c,
.max_convrate = 8,
.reg_local_ext = MAX6657_REG_LOCAL_TEMPL,
@@ -486,14 +511,16 @@ static const struct lm90_params lm90_params[] = {
*/
.flags = LM90_HAVE_OFFSET | LM90_HAVE_CRIT
| LM90_HAVE_CRIT_ALRM_SWP | LM90_HAVE_BROKEN_ALERT
- | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+ | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7c,
.max_convrate = 7,
},
[max6696] = {
.flags = LM90_HAVE_EMERGENCY
| LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3 | LM90_HAVE_CRIT
- | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+ | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x1c7c,
.max_convrate = 6,
.reg_status2 = MAX6696_REG_STATUS2,
@@ -501,7 +528,8 @@ static const struct lm90_params lm90_params[] = {
},
[w83l771] = {
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT
- | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+ | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7c,
.max_convrate = 8,
},
@@ -512,7 +540,8 @@ static const struct lm90_params lm90_params[] = {
* be set).
*/
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT
- | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+ | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7b,
.max_convrate = 9,
.reg_local_ext = SA56004_REG_LOCAL_TEMPL,
@@ -521,7 +550,7 @@ static const struct lm90_params lm90_params[] = {
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
| LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT
| LM90_HAVE_UNSIGNED_TEMP | LM90_HAVE_ALARMS | LM90_HAVE_LOW
- | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7c,
.max_convrate = 9,
.resolution = 12,
@@ -530,7 +559,8 @@ static const struct lm90_params lm90_params[] = {
[tmp461] = {
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
| LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT
- | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE,
+ | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+ | LM90_HAVE_REMOTE_EXT,
.alert_alarms = 0x7c,
.max_convrate = 9,
.resolution = 12,
@@ -596,6 +626,7 @@ struct lm90_data {
u8 max_convrate; /* Maximum conversion rate */
u8 reg_status2; /* 2nd status register (optional) */
u8 reg_local_ext; /* local extension register offset */
+ u8 reg_remote_ext; /* remote temperature low byte */
/* registers values */
u16 temp[TEMP_REG_NUM];
@@ -1078,7 +1109,7 @@ static int lm90_update_device(struct device *dev)
return val;
data->temp[LOCAL_TEMP] = val;
val = lm90_read16(client, LM90_REG_REMOTE_TEMPH,
- LM90_REG_REMOTE_TEMPL, true);
+ data->reg_remote_ext, true);
if (val < 0)
return val;
data->temp[REMOTE_TEMP] = val;
@@ -1089,7 +1120,7 @@ static int lm90_update_device(struct device *dev)
return val;
val = lm90_read16(client, LM90_REG_REMOTE_TEMPH,
- LM90_REG_REMOTE_TEMPL, true);
+ data->reg_remote_ext, true);
if (val < 0) {
lm90_select_remote_channel(data, false);
return val;
@@ -1150,6 +1181,9 @@ static int lm90_temp_get_resolution(struct lm90_data *data, int index)
{
switch (index) {
case REMOTE_TEMP:
+ if (data->reg_remote_ext)
+ return data->resolution;
+ return 8;
case REMOTE_OFFSET:
case REMOTE2_TEMP:
return data->resolution;
@@ -1560,11 +1594,118 @@ static umode_t lm90_is_visible(const void *data, enum hwmon_sensor_types type,
}
}
-/*
- * Per-manufacturer chip detect functions.
- * Functions are expected to return a pointer to the chip name or NULL
- * if detection was not successful.
- */
+static const char *lm90_detect_lm84(struct i2c_client *client)
+{
+ static const u8 regs[] = {
+ LM90_REG_STATUS, LM90_REG_LOCAL_TEMP, LM90_REG_LOCAL_HIGH,
+ LM90_REG_REMOTE_TEMPH, LM90_REG_REMOTE_HIGHH
+ };
+ int status = i2c_smbus_read_byte_data(client, LM90_REG_STATUS);
+ int reg1, reg2, reg3, reg4;
+ bool nonzero = false;
+ u8 ff = 0xff;
+ int i;
+
+ if (status < 0 || (status & 0xab))
+ return NULL;
+
+ /*
+ * For LM84, undefined registers return the most recent value.
+ * Repeat several times, each time checking against a different
+ * (presumably) existing register.
+ */
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ reg1 = i2c_smbus_read_byte_data(client, regs[i]);
+ reg2 = i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_TEMPL);
+ reg3 = i2c_smbus_read_byte_data(client, LM90_REG_LOCAL_LOW);
+ reg4 = i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_LOWH);
+
+ if (reg1 < 0)
+ return NULL;
+
+ /* If any register has a different value, this is not an LM84 */
+ if (reg2 != reg1 || reg3 != reg1 || reg4 != reg1)
+ return NULL;
+
+ nonzero |= reg1 || reg2 || reg3 || reg4;
+ ff &= reg1;
+ }
+ /*
+ * If all registers always returned 0 or 0xff, all bets are off,
+ * and we can not make any predictions about the chip type.
+ */
+ return nonzero && ff != 0xff ? "lm84" : NULL;
+}
+
+static const char *lm90_detect_max1617(struct i2c_client *client, int config1)
+{
+ int status = i2c_smbus_read_byte_data(client, LM90_REG_STATUS);
+ int llo, rlo, lhi, rhi;
+
+ if (status < 0 || (status & 0x03))
+ return NULL;
+
+ if (config1 & 0x3f)
+ return NULL;
+
+ /*
+ * Fail if unsupported registers return anything but 0xff.
+ * The calling code already checked man_id and chip_id.
+ * A byte read operation repeats the most recent read operation
+ * and should also return 0xff.
+ */
+ if (i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_TEMPL) != 0xff ||
+ i2c_smbus_read_byte_data(client, MAX6657_REG_LOCAL_TEMPL) != 0xff ||
+ i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_LOWL) != 0xff ||
+ i2c_smbus_read_byte(client) != 0xff)
+ return NULL;
+
+ llo = i2c_smbus_read_byte_data(client, LM90_REG_LOCAL_LOW);
+ rlo = i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_LOWH);
+
+ lhi = i2c_smbus_read_byte_data(client, LM90_REG_LOCAL_HIGH);
+ rhi = i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_HIGHH);
+
+ if (llo < 0 || rlo < 0)
+ return NULL;
+
+ /*
+ * A byte read operation repeats the most recent read and should
+ * return the same value.
+ */
+ if (i2c_smbus_read_byte(client) != rhi)
+ return NULL;
+
+ /*
+ * The following two checks are marginal since the checked values
+ * are strictly speaking valid.
+ */
+
+ /* fail for negative high limits; this also catches read errors */
+ if ((s8)lhi < 0 || (s8)rhi < 0)
+ return NULL;
+
+ /* fail if low limits are larger than or equal to high limits */
+ if ((s8)llo >= lhi || (s8)rlo >= rhi)
+ return NULL;
+
+ if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+ /*
+ * Word read operations return 0xff in second byte
+ */
+ if (i2c_smbus_read_word_data(client, LM90_REG_REMOTE_TEMPL) !=
+ 0xffff)
+ return NULL;
+ if (i2c_smbus_read_word_data(client, LM90_REG_CONFIG1) !=
+ (config1 | 0xff00))
+ return NULL;
+ if (i2c_smbus_read_word_data(client, LM90_REG_LOCAL_HIGH) !=
+ (lhi | 0xff00))
+ return NULL;
+ }
+
+ return "max1617";
+}
static const char *lm90_detect_national(struct i2c_client *client, int chip_id,
int config1, int convrate)
@@ -1714,10 +1855,29 @@ static const char *lm90_detect_maxim(struct i2c_client *client, bool common_addr
* The chip_id register of the MAX6680 and MAX6681 holds the
* revision of the chip. The lowest bit of the config1 register
* is unused and should return zero when read, so should the
- * second to last bit of config1 (software reset).
+ * second to last bit of config1 (software reset). Register
+ * address 0x12 (LM90_REG_REMOTE_OFFSL) exists for this chip and
+ * should differ from emerg2, and emerg2 should match man_id
+ * since it does not exist.
*/
- else if (!(config1 & 0x03) && convrate <= 0x07)
+ else if (!(config1 & 0x03) && convrate <= 0x07 &&
+ emerg2 == man_id && emerg2 != status2)
name = "max6680";
+ /*
+ * MAX1617A does not have any extended registers (register
+ * address 0x10 or higher) except for manufacturer and
+ * device ID registers. Unlike other chips of this series,
+ * unsupported registers were observed to return a fixed value
+ * of 0x01.
+ * Note: Multiple chips with different markings labeled as
+ * "MAX1617" (no "A") were observed to report manufacturer ID
+ * 0x4d and device ID 0x01. It is unknown if other variants of
+ * MAX1617/MAX617A with different behavior exist. The detection
+ * code below works for those chips.
+ */
+ else if (!(config1 & 0x03f) && convrate <= 0x07 &&
+ emerg == 0x01 && emerg2 == 0x01 && status2 == 0x01)
+ name = "max1617";
break;
case 0x08:
/*
@@ -1963,7 +2123,7 @@ static const char *lm90_detect_ti(struct i2c_client *client, int chip_id,
static int lm90_detect(struct i2c_client *client, struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
- int man_id, chip_id, config1, convrate;
+ int man_id, chip_id, config1, convrate, lhigh;
const char *name = NULL;
int address = client->addr;
bool common_address =
@@ -1974,15 +2134,43 @@ static int lm90_detect(struct i2c_client *client, struct i2c_board_info *info)
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
+ /*
+ * Get well defined register value for chips with neither man_id nor
+ * chip_id registers.
+ */
+ lhigh = i2c_smbus_read_byte_data(client, LM90_REG_LOCAL_HIGH);
+
/* detection and identification */
man_id = i2c_smbus_read_byte_data(client, LM90_REG_MAN_ID);
chip_id = i2c_smbus_read_byte_data(client, LM90_REG_CHIP_ID);
config1 = i2c_smbus_read_byte_data(client, LM90_REG_CONFIG1);
convrate = i2c_smbus_read_byte_data(client, LM90_REG_CONVRATE);
- if (man_id < 0 || chip_id < 0 || config1 < 0 || convrate < 0)
+ if (man_id < 0 || chip_id < 0 || config1 < 0 || convrate < 0 || lhigh < 0)
return -ENODEV;
+ /* Bail out immediately if all register report the same value */
+ if (lhigh == man_id && lhigh == chip_id && lhigh == config1 && lhigh == convrate)
+ return -ENODEV;
+
+ /*
+ * If reading man_id and chip_id both return the same value as lhigh,
+ * the chip may not support those registers and return the most recent read
+ * value. Check again with a different register and handle accordingly.
+ */
+ if (man_id == lhigh && chip_id == lhigh) {
+ convrate = i2c_smbus_read_byte_data(client, LM90_REG_CONVRATE);
+ man_id = i2c_smbus_read_byte_data(client, LM90_REG_MAN_ID);
+ chip_id = i2c_smbus_read_byte_data(client, LM90_REG_CHIP_ID);
+ if (convrate < 0 || man_id < 0 || chip_id < 0)
+ return -ENODEV;
+ if (man_id == convrate && chip_id == convrate)
+ man_id = -1;
+ }
switch (man_id) {
+ case -1: /* Chip does not support man_id / chip_id */
+ if (common_address && !convrate && !(config1 & 0x7f))
+ name = lm90_detect_lm84(client);
+ break;
case 0x01: /* National Semiconductor */
name = lm90_detect_national(client, chip_id, config1, convrate);
break;
@@ -2005,6 +2193,10 @@ static int lm90_detect(struct i2c_client *client, struct i2c_board_info *info)
case 0xa1: /* NXP Semiconductor/Philips */
name = lm90_detect_nxp(client, chip_id, config1, convrate);
break;
+ case 0xff: /* MAX1617, G767, NE1617 */
+ if (common_address && chip_id == 0xff && convrate < 8)
+ name = lm90_detect_max1617(client, config1);
+ break;
default:
break;
}
@@ -2265,6 +2457,8 @@ static int lm90_probe(struct i2c_client *client)
}
data->reg_local_ext = lm90_params[data->kind].reg_local_ext;
+ if (data->flags & LM90_HAVE_REMOTE_EXT)
+ data->reg_remote_ext = LM90_REG_REMOTE_TEMPL;
data->reg_status2 = lm90_params[data->kind].reg_status2;
/* Set maximum conversion rate */