summaryrefslogtreecommitdiff
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2021-11-19 13:55:47 -0800
committerGuenter Roeck <linux@roeck-us.net>2022-07-13 08:38:18 -0700
commitc09472fcf9e08b650453906ec9ab70662fe57fea (patch)
tree76eb97f89d20672ca2612fcd08682feaf033995c /drivers/hwmon
parent6be4b1a430824852f7c67f510f4ab88eada2d838 (diff)
hwmon: (lm90) Support MAX1617 and LM84
MAX1617 and LM84 are stripped-down versions of LM90, so they can easily be supported by the LM90 driver. The most difficult part is chip detection, since those old chips do not support manufacturer ID or chip ID registers. The "alarms" attribute is enabled for both chips to match the functionality of the adm1021 driver. Chip detection was improved and is less prone to misdetection than the chip detection in the adm1021 driver. Devicetree nodes are not added for the added chips since it is quite unlikely that such old chips will ever be used in a devicetree based system. They can be added later if needed. Signed-off-by: Guenter Roeck <linux@roeck-us.net>
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 */