lm85: support adt7468 chips
authorDarrick J. Wong <djwong@us.ibm.com>
Wed, 12 Nov 2008 21:26:59 +0000 (13:26 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Nov 2008 01:17:17 +0000 (17:17 -0800)
The adt7468 is a follow-on to the adt7463, so plumb in adt7468 support
along the same code paths.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
Cc: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/hwmon/lm85.c

index 3ff0285..cfc1ee9 100644 (file)
@@ -39,7 +39,8 @@
 static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
 
 /* Insmod parameters */
-I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
+I2C_CLIENT_INSMOD_7(lm85b, lm85c, adm1027, adt7463, adt7468, emc6d100,
+                   emc6d102);
 
 /* The LM85 registers */
 
@@ -59,6 +60,12 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
 
 #define        LM85_REG_COMPANY                0x3e
 #define        LM85_REG_VERSTEP                0x3f
+
+#define        ADT7468_REG_CFG5                0x7c
+#define                ADT7468_OFF64           0x01
+#define        IS_ADT7468_OFF64(data)          \
+       ((data)->type == adt7468 && !((data)->cfg5 & ADT7468_OFF64))
+
 /* These are the recognized values for the above regs */
 #define        LM85_COMPANY_NATIONAL           0x01
 #define        LM85_COMPANY_ANALOG_DEV         0x41
@@ -70,6 +77,8 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
 #define        LM85_VERSTEP_ADM1027            0x60
 #define        LM85_VERSTEP_ADT7463            0x62
 #define        LM85_VERSTEP_ADT7463C           0x6A
+#define        LM85_VERSTEP_ADT7468_1          0x71
+#define        LM85_VERSTEP_ADT7468_2          0x72
 #define        LM85_VERSTEP_EMC6D100_A0        0x60
 #define        LM85_VERSTEP_EMC6D100_A1        0x61
 #define        LM85_VERSTEP_EMC6D102           0x65
@@ -306,6 +315,7 @@ struct lm85_data {
        u8 vid;                 /* Register value */
        u8 vrm;                 /* VRM version */
        u32 alarms;             /* Register encoding, combined */
+       u8 cfg5;                /* Config Register 5 on ADT7468 */
        struct lm85_autofan autofan[3];
        struct lm85_zone zone[3];
 };
@@ -685,6 +695,9 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
        struct lm85_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);
 
+       if (IS_ADT7468_OFF64(data))
+               val += 64;
+
        mutex_lock(&data->update_lock);
        data->temp_min[nr] = TEMP_TO_REG(val);
        lm85_write_value(client, LM85_REG_TEMP_MIN(nr), data->temp_min[nr]);
@@ -708,6 +721,9 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
        struct lm85_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);
 
+       if (IS_ADT7468_OFF64(data))
+               val += 64;
+
        mutex_lock(&data->update_lock);
        data->temp_max[nr] = TEMP_TO_REG(val);
        lm85_write_value(client, LM85_REG_TEMP_MAX(nr), data->temp_max[nr]);
@@ -1163,6 +1179,10 @@ static int lm85_detect(struct i2c_client *client, int kind,
                        case LM85_VERSTEP_ADT7463C:
                                kind = adt7463;
                                break;
+                       case LM85_VERSTEP_ADT7468_1:
+                       case LM85_VERSTEP_ADT7468_2:
+                               kind = adt7468;
+                               break;
                        }
                } else if (company == LM85_COMPANY_SMSC) {
                        switch (verstep) {
@@ -1195,6 +1215,9 @@ static int lm85_detect(struct i2c_client *client, int kind,
        case adt7463:
                type_name = "adt7463";
                break;
+       case adt7468:
+               type_name = "adt7468";
+               break;
        case emc6d100:
                type_name = "emc6d100";
                break;
@@ -1246,10 +1269,11 @@ static int lm85_probe(struct i2c_client *client,
        if (err)
                goto err_kfree;
 
-       /* The ADT7463 has an optional VRM 10 mode where pin 21 is used
+       /* The ADT7463/68 have an optional VRM 10 mode where pin 21 is used
           as a sixth digital VID input rather than an analog input. */
        data->vid = lm85_read_value(client, LM85_REG_VID);
-       if (!(data->type == adt7463 && (data->vid & 0x80)))
+       if (!((data->type == adt7463 || data->type == adt7468) &&
+           (data->vid & 0x80)))
                if ((err = sysfs_create_group(&client->dev.kobj,
                                        &lm85_group_in4)))
                        goto err_remove_files;
@@ -1357,7 +1381,8 @@ static struct lm85_data *lm85_update_device(struct device *dev)
                 * There are 2 additional resolution bits per channel and we
                 * have room for 4, so we shift them to the left.
                 */
-               if (data->type == adm1027 || data->type == adt7463) {
+               if (data->type == adm1027 || data->type == adt7463 ||
+                   data->type == adt7468) {
                        int ext1 = lm85_read_value(client,
                                                   ADM1027_REG_EXTEND_ADC1);
                        int ext2 =  lm85_read_value(client,
@@ -1382,16 +1407,23 @@ static struct lm85_data *lm85_update_device(struct device *dev)
                            lm85_read_value(client, LM85_REG_FAN(i));
                }
 
-               if (!(data->type == adt7463 && (data->vid & 0x80))) {
+               if (!((data->type == adt7463 || data->type == adt7468) &&
+                   (data->vid & 0x80))) {
                        data->in[4] = lm85_read_value(client,
                                      LM85_REG_IN(4));
                }
 
+               if (data->type == adt7468)
+                       data->cfg5 = lm85_read_value(client, ADT7468_REG_CFG5);
+
                for (i = 0; i <= 2; ++i) {
                        data->temp[i] =
                            lm85_read_value(client, LM85_REG_TEMP(i));
                        data->pwm[i] =
                            lm85_read_value(client, LM85_REG_PWM(i));
+
+                       if (IS_ADT7468_OFF64(data))
+                               data->temp[i] -= 64;
                }
 
                data->alarms = lm85_read_value(client, LM85_REG_ALARM1);
@@ -1446,7 +1478,8 @@ static struct lm85_data *lm85_update_device(struct device *dev)
                            lm85_read_value(client, LM85_REG_FAN_MIN(i));
                }
 
-               if (!(data->type == adt7463 && (data->vid & 0x80))) {
+               if (!((data->type == adt7463 || data->type == adt7468) &&
+                   (data->vid & 0x80))) {
                        data->in_min[4] = lm85_read_value(client,
                                          LM85_REG_IN_MIN(4));
                        data->in_max[4] = lm85_read_value(client,
@@ -1481,6 +1514,13 @@ static struct lm85_data *lm85_update_device(struct device *dev)
                            lm85_read_value(client, LM85_REG_AFAN_LIMIT(i));
                        data->zone[i].critical =
                            lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i));
+
+                       if (IS_ADT7468_OFF64(data)) {
+                               data->temp_min[i] -= 64;
+                               data->temp_max[i] -= 64;
+                               data->zone[i].limit -= 64;
+                               data->zone[i].critical -= 64;
+                       }
                }
 
                i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1);