hwmon: (adm1021) Improve detection of LM84, MAX1617, and MAX1617A
authorGuenter Roeck <linux@roeck-us.net>
Mon, 15 Nov 2021 06:06:35 +0000 (22:06 -0800)
committerGuenter Roeck <linux@roeck-us.net>
Sun, 26 Dec 2021 23:02:05 +0000 (15:02 -0800)
The adm1021 driver is quite generous with its automatic chip detection
and easily misdetects several chips. Strengthen detection of MAX1617,
MAX1617A, and LM84 to make the driver less vulnerable to false matches.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
drivers/hwmon/adm1021.c

index 38b447c..91ecfee 100644 (file)
@@ -324,7 +324,7 @@ static int adm1021_detect(struct i2c_client *client,
 {
        struct i2c_adapter *adapter = client->adapter;
        const char *type_name;
-       int conv_rate, status, config, man_id, dev_id;
+       int reg, conv_rate, status, config, man_id, dev_id;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
                pr_debug("detect failed, smbus byte data not supported!\n");
@@ -349,9 +349,19 @@ static int adm1021_detect(struct i2c_client *client,
        if (man_id < 0 || dev_id < 0)
                return -ENODEV;
 
-       if (man_id == 0x4d && dev_id == 0x01)
+       if (man_id == 0x4d && dev_id == 0x01) {
+               /*
+                * dev_id 0x01 matches MAX6680, MAX6695, MAX6696, and possibly
+                * others. Read register which is unsupported on MAX1617 but
+                * exists on all those chips and compare with the dev_id
+                * register. If it matches, it may be a MAX1617A.
+                */
+               reg = i2c_smbus_read_byte_data(client,
+                                              ADM1023_REG_REM_TEMP_PREC);
+               if (reg != dev_id)
+                       return -ENODEV;
                type_name = "max1617a";
-       else if (man_id == 0x41) {
+       else if (man_id == 0x41) {
                if ((dev_id & 0xF0) == 0x30)
                        type_name = "adm1023";
                else if ((dev_id & 0xF0) == 0x00)
@@ -395,13 +405,18 @@ static int adm1021_detect(struct i2c_client *client,
 
                /*
                 * LM84 Mfr ID is in a different place,
-                * and it has more unused bits.
+                * and it has more unused bits. Registers at 0xfe and 0xff
+                * are undefined and return the most recently read value,
+                * here the value of the configuration register.
                 */
                if (conv_rate == 0x00
+                   && man_id == config && dev_id == config
                    && (config & 0x7F) == 0x00
                    && (status & 0xAB) == 0x00) {
                        type_name = "lm84";
                } else {
+                       if ((config & 0x3f) || (status & 0x03))
+                               return -ENODEV;
                        /* fail if low limits are larger than high limits */
                        if ((s8)llo > lhi || (s8)rlo > rhi)
                                return -ENODEV;