hwmon: (smsc47m1) Differentiate between LPC47M233 and LPC47M292
[safe/jmp/linux-2.6] / drivers / hwmon / lm85.c
index 4ee9388..b251d86 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,17 +60,26 @@ 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
 #define        LM85_COMPANY_SMSC               0x5c
 #define        LM85_VERSTEP_VMASK              0xf0
 #define        LM85_VERSTEP_GENERIC            0x60
+#define        LM85_VERSTEP_GENERIC2           0x70
 #define        LM85_VERSTEP_LM85C              0x60
 #define        LM85_VERSTEP_LM85B              0x62
 #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
@@ -174,20 +184,13 @@ static int RANGE_TO_REG(int range)
 {
        int i;
 
-       if (range >= lm85_range_map[15])
-               return 15;
-
        /* Find the closest match */
-       for (i = 14; i >= 0; --i) {
-               if (range >= lm85_range_map[i]) {
-                       if ((lm85_range_map[i + 1] - range) <
-                                       (range - lm85_range_map[i]))
-                               return i + 1;
-                       return i;
-               }
+       for (i = 0; i < 15; ++i) {
+               if (range <= (lm85_range_map[i] + lm85_range_map[i + 1]) / 2)
+                       break;
        }
 
-       return 0;
+       return i;
 }
 #define RANGE_FROM_REG(val)    lm85_range_map[(val) & 0x0f]
 
@@ -313,6 +316,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];
 };
@@ -331,6 +335,7 @@ static struct lm85_data *lm85_update_device(struct device *dev);
 static const struct i2c_device_id lm85_id[] = {
        { "adm1027", adm1027 },
        { "adt7463", adt7463 },
+       { "adt7468", adt7468 },
        { "lm85", any_chip },
        { "lm85b", lm85b },
        { "lm85c", lm85c },
@@ -405,7 +410,8 @@ static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr,
        struct lm85_data *data = lm85_update_device(dev);
        int vid;
 
-       if (data->type == adt7463 && (data->vid & 0x80)) {
+       if ((data->type == adt7463 || data->type == adt7468) &&
+           (data->vid & 0x80)) {
                /* 6-pin VID (VRM 10) */
                vid = vid_from_reg(data->vid & 0x3f, data->vrm);
        } else {
@@ -692,6 +698,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]);
@@ -715,6 +724,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]);
@@ -1144,7 +1156,8 @@ static int lm85_detect(struct i2c_client *client, int kind,
                        address, company, verstep);
 
                /* All supported chips have the version in common */
-               if ((verstep & LM85_VERSTEP_VMASK) != LM85_VERSTEP_GENERIC) {
+               if ((verstep & LM85_VERSTEP_VMASK) != LM85_VERSTEP_GENERIC &&
+                   (verstep & LM85_VERSTEP_VMASK) != LM85_VERSTEP_GENERIC2) {
                        dev_dbg(&adapter->dev, "Autodetection failed: "
                                "unsupported version\n");
                        return -ENODEV;
@@ -1170,6 +1183,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) {
@@ -1202,6 +1219,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;
@@ -1251,37 +1271,38 @@ static int lm85_probe(struct i2c_client *client,
        /* Register sysfs hooks */
        err = sysfs_create_group(&client->dev.kobj, &lm85_group);
        if (err)
-               goto ERROR1;
+               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 ERROR3;
+                       goto err_remove_files;
 
        /* The EMC6D100 has 3 additional voltage inputs */
        if (data->type == emc6d100)
                if ((err = sysfs_create_group(&client->dev.kobj,
                                        &lm85_group_in567)))
-                       goto ERROR3;
+                       goto err_remove_files;
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
                err = PTR_ERR(data->hwmon_dev);
-               goto ERROR3;
+               goto err_remove_files;
        }
 
        return 0;
 
        /* Error out and cleanup code */
ERROR3:
err_remove_files:
        sysfs_remove_group(&client->dev.kobj, &lm85_group);
        sysfs_remove_group(&client->dev.kobj, &lm85_group_in4);
        if (data->type == emc6d100)
                sysfs_remove_group(&client->dev.kobj, &lm85_group_in567);
ERROR1:
err_kfree:
        kfree(data);
        return err;
 }
@@ -1364,7 +1385,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,
@@ -1389,16 +1411,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);
@@ -1453,7 +1482,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,
@@ -1488,6 +1518,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);