hwmon: (adm1021) Strengthen chip detection for ADM1021, LM84 and MAX1617
authorGuenter Roeck <linux@roeck-us.net>
Wed, 5 Jun 2013 21:09:30 +0000 (14:09 -0700)
committerGuenter Roeck <linux@roeck-us.net>
Fri, 7 Jun 2013 19:29:31 +0000 (12:29 -0700)
On a system with both MAX1617 and JC42 sensors, JC42 sensors can be misdetected
as LM84. Strengthen detection sufficiently enough to avoid this misdetection.
Also improve detection for ADM1021.

Modeled after chip detection code in sensors-detect command.

Cc: stable@vger.kernel.org
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Jean Delvare <khali@linux-fr.org>
Acked-by: Jean Delvare <khali@linux-fr.org>
drivers/hwmon/adm1021.c

index 7e76922a4ba9b0f9a56191b2afb1fba5814ccdf0..f920619cd6da5405ca5cd9c64e9f1ad31fb8a526 100644 (file)
@@ -331,26 +331,68 @@ static int adm1021_detect(struct i2c_client *client,
        man_id = i2c_smbus_read_byte_data(client, ADM1021_REG_MAN_ID);
        dev_id = i2c_smbus_read_byte_data(client, ADM1021_REG_DEV_ID);
 
+       if (man_id < 0 || dev_id < 0)
+               return -ENODEV;
+
        if (man_id == 0x4d && dev_id == 0x01)
                type_name = "max1617a";
        else if (man_id == 0x41) {
                if ((dev_id & 0xF0) == 0x30)
                        type_name = "adm1023";
-               else
+               else if ((dev_id & 0xF0) == 0x00)
                        type_name = "adm1021";
+               else
+                       return -ENODEV;
        } else if (man_id == 0x49)
                type_name = "thmc10";
        else if (man_id == 0x23)
                type_name = "gl523sm";
        else if (man_id == 0x54)
                type_name = "mc1066";
-       /* LM84 Mfr ID in a different place, and it has more unused bits */
-       else if (conv_rate == 0x00
-                && (config & 0x7F) == 0x00
-                && (status & 0xAB) == 0x00)
-               type_name = "lm84";
-       else
-               type_name = "max1617";
+       else {
+               int lte, rte, lhi, rhi, llo, rlo;
+
+               /* extra checks for LM84 and MAX1617 to avoid misdetections */
+
+               llo = i2c_smbus_read_byte_data(client, ADM1021_REG_THYST_R(0));
+               rlo = i2c_smbus_read_byte_data(client, ADM1021_REG_THYST_R(1));
+
+               /* fail if any of the additional register reads failed */
+               if (llo < 0 || rlo < 0)
+                       return -ENODEV;
+
+               lte = i2c_smbus_read_byte_data(client, ADM1021_REG_TEMP(0));
+               rte = i2c_smbus_read_byte_data(client, ADM1021_REG_TEMP(1));
+               lhi = i2c_smbus_read_byte_data(client, ADM1021_REG_TOS_R(0));
+               rhi = i2c_smbus_read_byte_data(client, ADM1021_REG_TOS_R(1));
+
+               /*
+                * Fail for negative temperatures and negative high limits.
+                * This check also catches read errors on the tested registers.
+                */
+               if ((s8)lte < 0 || (s8)rte < 0 || (s8)lhi < 0 || (s8)rhi < 0)
+                       return -ENODEV;
+
+               /* fail if all registers hold the same value */
+               if (lte == rte && lte == lhi && lte == rhi && lte == llo
+                   && lte == rlo)
+                       return -ENODEV;
+
+               /*
+                * LM84 Mfr ID is in a different place,
+                * and it has more unused bits.
+                */
+               if (conv_rate == 0x00
+                   && (config & 0x7F) == 0x00
+                   && (status & 0xAB) == 0x00) {
+                       type_name = "lm84";
+               } else {
+                       /* fail if low limits are larger than high limits */
+                       if ((s8)llo > lhi || (s8)rlo > rhi)
+                               return -ENODEV;
+                       type_name = "max1617";
+               }
+       }
 
        pr_debug("Detected chip %s at adapter %d, address 0x%02x.\n",
                 type_name, i2c_adapter_id(adapter), client->addr);