Merge to Fedora kernel-2.6.18-1.2239_FC5 patched with stable patch-2.6.18.2-vs2.0...
[linux-2.6.git] / drivers / i2c / chips / w83781d.c
index b2274c5..4954e46 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/i2c-vid.h>
 #include <asm/io.h>
 #include "lm75.h"
 
-/* RT Table support #defined so we can take it out if it gets bothersome */
-#define W83781D_RT                     1
-
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { 0x20, 0x2f, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+                                       0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+                                       0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
 static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END };
-static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
 SENSORS_INSMOD_6(w83781d, w83782d, w83783s, w83627hf, as99127f, w83697hf);
@@ -60,7 +58,7 @@ I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
                    "{bus, clientaddr, subclientaddr1, subclientaddr2}");
 
 static int init = 1;
-MODULE_PARM(init, "i");
+module_param(init, bool, 0);
 MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
 
 /* Constants specified below */
@@ -175,16 +173,13 @@ FAN_TO_REG(long rpm, int div)
                                                : (val)) / 1000, 0, 0xff))
 #define TEMP_FROM_REG(val)             (((val) & 0x80 ? (val)-0x100 : (val)) * 1000)
 
-#define AS99127_TEMP_ADD_TO_REG(val)   (SENSORS_LIMIT((((val) < 0 ? (val)+0x10000*250 \
-                                               : (val)) / 250) << 7, 0, 0xffff))
-#define AS99127_TEMP_ADD_FROM_REG(val) ((((val) & 0x8000 ? (val)-0x10000 : (val)) \
-                                               >> 7) * 250)
-
 #define ALARMS_FROM_REG(val)           (val)
 #define PWM_FROM_REG(val)              (val)
 #define PWM_TO_REG(val)                        (SENSORS_LIMIT((val),0,255))
-#define BEEP_MASK_FROM_REG(val)                (val)
-#define BEEP_MASK_TO_REG(val)          ((val) & 0xffffff)
+#define BEEP_MASK_FROM_REG(val,type)   ((type) == as99127f ? \
+                                        (val) ^ 0x7fff : (val))
+#define BEEP_MASK_TO_REG(val,type)     ((type) == as99127f ? \
+                                        (~(val)) & 0x7fff : (val) & 0xffffff)
 
 #define BEEP_ENABLE_TO_REG(val)                ((val) ? 1 : 0)
 #define BEEP_ENABLE_FROM_REG(val)      ((val) ? 1 : 0)
@@ -260,9 +255,6 @@ struct w83781d_data {
                                   3000-5000 = thermistor beta.
                                   Default = 3435. 
                                   Other Betas unimplemented */
-#ifdef W83781D_RT
-       u8 rt[3][32];           /* Register value */
-#endif
        u8 vrm;
 };
 
@@ -304,9 +296,12 @@ static ssize_t store_in_##reg (struct device *dev, const char *buf, size_t count
        u32 val; \
         \
        val = simple_strtoul(buf, NULL, 10) / 10; \
+        \
+       down(&data->update_lock); \
        data->in_##reg[nr] = IN_TO_REG(val); \
        w83781d_write_value(client, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
         \
+       up(&data->update_lock); \
        return count; \
 }
 store_in_reg(MIN, min);
@@ -316,20 +311,20 @@ store_in_reg(MAX, max);
 static ssize_t \
 show_regs_in_##offset (struct device *dev, char *buf) \
 { \
-        return show_in(dev, buf, 0x##offset); \
+        return show_in(dev, buf, offset); \
 } \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL)
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
 
 #define sysfs_in_reg_offset(reg, offset) \
 static ssize_t show_regs_in_##reg##offset (struct device *dev, char *buf) \
 { \
-       return show_in_##reg (dev, buf, 0x##offset); \
+       return show_in_##reg (dev, buf, offset); \
 } \
 static ssize_t store_regs_in_##reg##offset (struct device *dev, const char *buf, size_t count) \
 { \
-       return store_in_##reg (dev, buf, count, 0x##offset); \
+       return store_in_##reg (dev, buf, count, offset); \
 } \
-static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset)
+static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset);
 
 #define sysfs_in_offsets(offset) \
 sysfs_in_offset(offset); \
@@ -371,31 +366,34 @@ store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
        u32 val;
 
        val = simple_strtoul(buf, NULL, 10);
+
+       down(&data->update_lock);
        data->fan_min[nr - 1] =
            FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
        w83781d_write_value(client, W83781D_REG_FAN_MIN(nr),
                            data->fan_min[nr - 1]);
 
+       up(&data->update_lock);
        return count;
 }
 
 #define sysfs_fan_offset(offset) \
 static ssize_t show_regs_fan_##offset (struct device *dev, char *buf) \
 { \
-       return show_fan(dev, buf, 0x##offset); \
+       return show_fan(dev, buf, offset); \
 } \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL)
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL);
 
 #define sysfs_fan_min_offset(offset) \
 static ssize_t show_regs_fan_min##offset (struct device *dev, char *buf) \
 { \
-       return show_fan_min(dev, buf, 0x##offset); \
+       return show_fan_min(dev, buf, offset); \
 } \
 static ssize_t store_regs_fan_min##offset (struct device *dev, const char *buf, size_t count) \
 { \
-       return store_fan_min(dev, buf, count, 0x##offset); \
+       return store_fan_min(dev, buf, count, offset); \
 } \
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset)
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset);
 
 sysfs_fan_offset(1);
 sysfs_fan_min_offset(1);
@@ -415,13 +413,8 @@ static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
 { \
        struct w83781d_data *data = w83781d_update_device(dev); \
        if (nr >= 2) {  /* TEMP2 and TEMP3 */ \
-               if (data->type == as99127f) { \
-                       return sprintf(buf,"%ld\n", \
-                               (long)AS99127_TEMP_ADD_FROM_REG(data->reg##_add[nr-2])); \
-               } else { \
-                       return sprintf(buf,"%d\n", \
-                               LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
-               } \
+               return sprintf(buf,"%d\n", \
+                       LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
        } else {        /* TEMP1 */ \
                return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
        } \
@@ -439,12 +432,10 @@ static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t cou
         \
        val = simple_strtol(buf, NULL, 10); \
         \
+       down(&data->update_lock); \
+        \
        if (nr >= 2) {  /* TEMP2 and TEMP3 */ \
-               if (data->type == as99127f) \
-                       data->temp_##reg##_add[nr-2] = AS99127_TEMP_ADD_TO_REG(val); \
-               else \
-                       data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
-                \
+               data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
                w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \
                                data->temp_##reg##_add[nr-2]); \
        } else {        /* TEMP1 */ \
@@ -453,6 +444,7 @@ static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t cou
                        data->temp_##reg); \
        } \
         \
+       up(&data->update_lock); \
        return count; \
 }
 store_temp_reg(OVER, max);
@@ -462,20 +454,20 @@ store_temp_reg(HYST, max_hyst);
 static ssize_t \
 show_regs_temp_##offset (struct device *dev, char *buf) \
 { \
-       return show_temp(dev, buf, 0x##offset); \
+       return show_temp(dev, buf, offset); \
 } \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL)
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL);
 
 #define sysfs_temp_reg_offset(reg, offset) \
 static ssize_t show_regs_temp_##reg##offset (struct device *dev, char *buf) \
 { \
-       return show_temp_##reg (dev, buf, 0x##offset); \
+       return show_temp_##reg (dev, buf, offset); \
 } \
 static ssize_t store_regs_temp_##reg##offset (struct device *dev, const char *buf, size_t count) \
 { \
-       return store_temp_##reg (dev, buf, count, 0x##offset); \
+       return store_temp_##reg (dev, buf, count, offset); \
 } \
-static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset)
+static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset);
 
 #define sysfs_temp_offsets(offset) \
 sysfs_temp_offset(offset); \
@@ -501,9 +493,9 @@ show_vid_reg(struct device *dev, char *buf)
 }
 
 static
-DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL)
+DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
 #define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_in0_ref);
+device_create_file(&client->dev, &dev_attr_cpu0_vid);
 static ssize_t
 show_vrm_reg(struct device *dev, char *buf)
 {
@@ -525,7 +517,7 @@ store_vrm_reg(struct device *dev, const char *buf, size_t count)
 }
 
 static
-DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg)
+DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
 #define device_create_file_vrm(client) \
 device_create_file(&client->dev, &dev_attr_vrm);
 static ssize_t
@@ -536,17 +528,21 @@ show_alarms_reg(struct device *dev, char *buf)
 }
 
 static
-DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL)
+DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
 #define device_create_file_alarms(client) \
 device_create_file(&client->dev, &dev_attr_alarms);
-#define show_beep_reg(REG, reg) \
-static ssize_t show_beep_##reg (struct device *dev, char *buf) \
-{ \
-       struct w83781d_data *data = w83781d_update_device(dev); \
-       return sprintf(buf,"%ld\n", (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \
+static ssize_t show_beep_mask (struct device *dev, char *buf)
+{
+       struct w83781d_data *data = w83781d_update_device(dev);
+       return sprintf(buf, "%ld\n",
+                      (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type));
+}
+static ssize_t show_beep_enable (struct device *dev, char *buf)
+{
+       struct w83781d_data *data = w83781d_update_device(dev);
+       return sprintf(buf, "%ld\n",
+                      (long)BEEP_ENABLE_FROM_REG(data->beep_enable));
 }
-show_beep_reg(ENABLE, enable);
-show_beep_reg(MASK, mask);
 
 #define BEEP_ENABLE                    0       /* Store beep_enable */
 #define BEEP_MASK                      1       /* Store beep_mask */
@@ -561,8 +557,10 @@ store_beep_reg(struct device *dev, const char *buf, size_t count,
 
        val = simple_strtoul(buf, NULL, 10);
 
+       down(&data->update_lock);
+
        if (update_mask == BEEP_MASK) { /* We are storing beep_mask */
-               data->beep_mask = BEEP_MASK_TO_REG(val);
+               data->beep_mask = BEEP_MASK_TO_REG(val, data->type);
                w83781d_write_value(client, W83781D_REG_BEEP_INTS1,
                                    data->beep_mask & 0xff);
 
@@ -580,6 +578,7 @@ store_beep_reg(struct device *dev, const char *buf, size_t count,
        w83781d_write_value(client, W83781D_REG_BEEP_INTS2,
                            val2 | data->beep_enable << 7);
 
+       up(&data->update_lock);
        return count;
 }
 
@@ -592,7 +591,7 @@ static ssize_t store_regs_beep_##reg (struct device *dev, const char *buf, size_
 { \
        return store_beep_reg(dev, buf, count, BEEP_##REG); \
 } \
-static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg)
+static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg);
 
 sysfs_beep(ENABLE, enable);
 sysfs_beep(MASK, mask);
@@ -622,13 +621,15 @@ store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
        struct w83781d_data *data = i2c_get_clientdata(client);
        unsigned long min;
        u8 reg;
+       unsigned long val = simple_strtoul(buf, NULL, 10);
 
+       down(&data->update_lock);
+       
        /* Save fan_min */
        min = FAN_FROM_REG(data->fan_min[nr],
                           DIV_FROM_REG(data->fan_div[nr]));
 
-       data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10),
-                                     data->type);
+       data->fan_div[nr] = DIV_TO_REG(val, data->type);
 
        reg = (w83781d_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
               & (nr==0 ? 0xcf : 0x3f))
@@ -647,6 +648,7 @@ store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
        data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
        w83781d_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
 
+       up(&data->update_lock);
        return count;
 }
 
@@ -659,7 +661,7 @@ static ssize_t store_regs_fan_div_##offset (struct device *dev, const char *buf,
 { \
        return store_fan_div_reg(dev, buf, count, offset - 1); \
 } \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset)
+static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset);
 
 sysfs_fan_div(1);
 sysfs_fan_div(2);
@@ -693,9 +695,10 @@ store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr)
 
        val = simple_strtoul(buf, NULL, 10);
 
+       down(&data->update_lock);
        data->pwm[nr - 1] = PWM_TO_REG(val);
        w83781d_write_value(client, W83781D_REG_PWM(nr), data->pwm[nr - 1]);
-
+       up(&data->update_lock);
        return count;
 }
 
@@ -708,6 +711,8 @@ store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr)
 
        val = simple_strtoul(buf, NULL, 10);
 
+       down(&data->update_lock);
+
        switch (val) {
        case 0:
        case 1:
@@ -723,9 +728,11 @@ store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr)
                break;
 
        default:
+               up(&data->update_lock);
                return -EINVAL;
        }
 
+       up(&data->update_lock);
        return count;
 }
 
@@ -734,22 +741,26 @@ static ssize_t show_regs_pwm_##offset (struct device *dev, char *buf) \
 { \
        return show_pwm_reg(dev, buf, offset); \
 } \
-static ssize_t store_regs_pwm_##offset (struct device *dev, const char *buf, size_t count) \
+static ssize_t store_regs_pwm_##offset (struct device *dev, \
+               const char *buf, size_t count) \
 { \
        return store_pwm_reg(dev, buf, count, offset); \
 } \
-static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, show_regs_pwm_##offset, store_regs_pwm_##offset)
+static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
+               show_regs_pwm_##offset, store_regs_pwm_##offset);
 
 #define sysfs_pwmenable(offset) \
 static ssize_t show_regs_pwmenable_##offset (struct device *dev, char *buf) \
 { \
        return show_pwmenable_reg(dev, buf, offset); \
 } \
-static ssize_t store_regs_pwmenable_##offset (struct device *dev, const char *buf, size_t count) \
+static ssize_t store_regs_pwmenable_##offset (struct device *dev, \
+               const char *buf, size_t count) \
 { \
        return store_pwmenable_reg(dev, buf, count, offset); \
 } \
-static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO | S_IWUSR, show_regs_pwmenable_##offset, store_regs_pwmenable_##offset)
+static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
+               show_regs_pwmenable_##offset, store_regs_pwmenable_##offset);
 
 sysfs_pwm(1);
 sysfs_pwm(2);
@@ -759,12 +770,12 @@ sysfs_pwm(4);
 
 #define device_create_file_pwm(client, offset) \
 do { \
-device_create_file(&client->dev, &dev_attr_fan##offset##_pwm); \
+device_create_file(&client->dev, &dev_attr_pwm##offset); \
 } while (0)
 
 #define device_create_file_pwmenable(client, offset) \
 do { \
-device_create_file(&client->dev, &dev_attr_fan##offset##_pwm_enable); \
+device_create_file(&client->dev, &dev_attr_pwm##offset##_enable); \
 } while (0)
 
 static ssize_t
@@ -783,6 +794,8 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
 
        val = simple_strtoul(buf, NULL, 10);
 
+       down(&data->update_lock);
+
        switch (val) {
        case 1:         /* PII/Celeron diode */
                tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
@@ -809,12 +822,12 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
                data->sens[nr - 1] = val;
                break;
        default:
-               dev_err(&client->dev,
-                      "Invalid sensor type %ld; must be 1, 2, or %d\n",
+               dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n",
                       (long) val, W83781D_DEFAULT_BETA);
                break;
        }
 
+       up(&data->update_lock);
        return count;
 }
 
@@ -827,7 +840,7 @@ static ssize_t store_regs_sensor_##offset (struct device *dev, const char *buf,
 { \
     return store_sensor_reg(dev, buf, count, offset); \
 } \
-static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset)
+static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset);
 
 sysfs_sensor(1);
 sysfs_sensor(2);
@@ -838,66 +851,6 @@ do { \
 device_create_file(&client->dev, &dev_attr_temp##offset##_type); \
 } while (0)
 
-#ifdef W83781D_RT
-static ssize_t
-show_rt_reg(struct device *dev, char *buf, int nr)
-{
-       struct w83781d_data *data = w83781d_update_device(dev);
-       int i, j = 0;
-
-       for (i = 0; i < 32; i++) {
-               if (i > 0)
-                       j += sprintf(buf, " %ld", (long) data->rt[nr - 1][i]);
-               else
-                       j += sprintf(buf, "%ld", (long) data->rt[nr - 1][i]);
-       }
-       j += sprintf(buf, "\n");
-
-       return j;
-}
-
-static ssize_t
-store_rt_reg(struct device *dev, const char *buf, size_t count, int nr)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct w83781d_data *data = i2c_get_clientdata(client);
-       u32 val, i;
-
-       for (i = 0; i < count; i++) {
-               val = simple_strtoul(buf + count, NULL, 10);
-
-               /* fixme: no bounds checking 0-255 */
-               data->rt[nr - 1][i] = val & 0xff;
-               w83781d_write_value(client, W83781D_REG_RT_IDX, i);
-               w83781d_write_value(client, W83781D_REG_RT_VAL,
-                                   data->rt[nr - 1][i]);
-       }
-
-       return count;
-}
-
-#define sysfs_rt(offset) \
-static ssize_t show_regs_rt_##offset (struct device *dev, char *buf) \
-{ \
-       return show_rt_reg(dev, buf, offset); \
-} \
-static ssize_t store_regs_rt_##offset (struct device *dev, const char *buf, size_t count) \
-{ \
-    return store_rt_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(rt##offset, S_IRUGO | S_IWUSR, show_regs_rt_##offset, store_regs_rt_##offset)
-
-sysfs_rt(1);
-sysfs_rt(2);
-sysfs_rt(3);
-
-#define device_create_file_rt(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_rt##offset); \
-} while (0)
-
-#endif                         /* ifdef W83781D_RT */
-
 /* This function is called when:
      * w83781d_driver is inserted (when this module is loaded), for each
        available adapter
@@ -905,7 +858,7 @@ device_create_file(&client->dev, &dev_attr_rt##offset); \
 static int
 w83781d_attach_adapter(struct i2c_adapter *adapter)
 {
-       if (!(adapter->class & I2C_ADAP_CLASS_SMBUS))
+       if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
        return i2c_detect(adapter, &addr_data, w83781d_detect);
 }
@@ -1056,7 +1009,11 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
        }
        
        if (is_isa)
-               if (!request_region(address, W83781D_EXTENT, "w83781d")) {
+               if (!request_region(address, W83781D_EXTENT,
+                                   w83781d_driver.name)) {
+                       dev_dbg(&adapter->dev, "Request of region "
+                               "0x%x-0x%x for w83781d failed\n", address,
+                               address + W83781D_EXTENT - 1);
                        err = -EBUSY;
                        goto ERROR0;
                }
@@ -1070,15 +1027,11 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
                        /* We need the timeouts for at least some LM78-like
                           chips. But only if we read 'undefined' registers. */
                        i = inb_p(address + 1);
-                       if (inb_p(address + 2) != i) {
-                               err = -ENODEV;
-                               goto ERROR1;
-                       }
-                       if (inb_p(address + 3) != i) {
-                               err = -ENODEV;
-                               goto ERROR1;
-                       }
-                       if (inb_p(address + 7) != i) {
+                       if (inb_p(address + 2) != i
+                        || inb_p(address + 3) != i
+                        || inb_p(address + 7) != i) {
+                               dev_dbg(&adapter->dev, "Detection of w83781d "
+                                       "chip failed at step 1\n");
                                err = -ENODEV;
                                goto ERROR1;
                        }
@@ -1087,8 +1040,13 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
                        /* Let's just hope nothing breaks here */
                        i = inb_p(address + 5) & 0x7f;
                        outb_p(~i & 0x7f, address + 5);
-                       if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) {
+                       val2 = inb_p(address + 5) & 0x7f;
+                       if (val2 != (~i & 0x7f)) {
                                outb_p(i, address + 5);
+                               dev_dbg(&adapter->dev, "Detection of w83781d "
+                                       "chip failed at step 2 (0x%x != "
+                                       "0x%x at 0x%x)\n", val2, ~i & 0x7f,
+                                       address + 5);
                                err = -ENODEV;
                                goto ERROR1;
                        }
@@ -1120,7 +1078,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
           force_*=... parameter, and the Winbond will be reset to the right
           bank. */
        if (kind < 0) {
-               if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80){
+               if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80) {
+                       dev_dbg(&new_client->dev, "Detection failed at step "
+                               "3\n");
                        err = -ENODEV;
                        goto ERROR2;
                }
@@ -1130,6 +1090,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
                if ((!(val1 & 0x07)) &&
                    (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
                     || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {
+                       dev_dbg(&new_client->dev, "Detection failed at step "
+                               "4\n");
                        err = -ENODEV;
                        goto ERROR2;
                }
@@ -1139,6 +1101,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
                                  ((val1 & 0x80) && (val2 == 0x5c)))) {
                        if (w83781d_read_value
                            (new_client, W83781D_REG_I2C_ADDR) != address) {
+                               dev_dbg(&new_client->dev, "Detection failed "
+                                       "at step 5\n");
                                err = -ENODEV;
                                goto ERROR2;
                        }
@@ -1161,6 +1125,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
                else if (val2 == 0x12)
                        vendid = asus;
                else {
+                       dev_dbg(&new_client->dev, "Chip was made by neither "
+                               "Winbond nor Asus?\n");
                        err = -ENODEV;
                        goto ERROR2;
                }
@@ -1181,10 +1147,10 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
                        kind = w83697hf;
                else {
                        if (kind == 0)
-                               dev_warn(&new_client->dev,
-                                      "Ignoring 'force' parameter for unknown chip at"
-                                      "adapter %d, address 0x%02x\n",
-                                      i2c_adapter_id(adapter), address);
+                               dev_warn(&new_client->dev, "Ignoring 'force' "
+                                        "parameter for unknown chip at "
+                                        "adapter %d, address 0x%02x\n",
+                                        i2c_adapter_id(adapter), address);
                        err = -EINVAL;
                        goto ERROR2;
                }
@@ -1295,13 +1261,6 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
                if (kind != w83783s && kind != w83697hf)
                        device_create_file_sensor(new_client, 3);
        }
-#ifdef W83781D_RT
-       if (kind == w83781d) {
-               device_create_file_rt(new_client, 1);
-               device_create_file_rt(new_client, 2);
-               device_create_file_rt(new_client, 3);
-       }
-#endif
 
        return 0;
 
@@ -1330,7 +1289,13 @@ w83781d_detach_client(struct i2c_client *client)
                return err;
        }
 
-       kfree(i2c_get_clientdata(client));
+       if (i2c_get_clientdata(client)==NULL) {
+               /* subclients */
+               kfree(client);
+       } else {
+               /* main client */
+               kfree(i2c_get_clientdata(client));
+       }
 
        return 0;
 }
@@ -1479,7 +1444,7 @@ static void
 w83781d_init_client(struct i2c_client *client)
 {
        struct w83781d_data *data = i2c_get_clientdata(client);
-       int vid = 0, i, p;
+       int i, p;
        int type = data->type;
        u8 tmp;
 
@@ -1501,14 +1466,7 @@ w83781d_init_client(struct i2c_client *client)
                w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0);
        }
 
-       if (type != w83697hf) {
-               vid = w83781d_read_value(client, W83781D_REG_VID_FANDIV) & 0x0f;
-               vid |=
-                   (w83781d_read_value(client, W83781D_REG_CHIPID) & 0x01) <<
-                   4;
-               data->vrm = DEFAULT_VRM;
-               vid = vid_from_reg(vid, data->vrm);
-       }
+       data->vrm = i2c_which_vrm();
 
        if ((type != w83781d) && (type != as99127f)) {
                tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
@@ -1527,39 +1485,29 @@ w83781d_init_client(struct i2c_client *client)
                                break;
                }
        }
-#ifdef W83781D_RT
-/*
-   Fill up the RT Tables.
-   We assume that they are 32 bytes long, in order for temp 1-3.
-   Data sheet documentation is sparse.
-   We also assume that it is only for the 781D although I suspect
-   that the others support it as well....
-*/
 
-       if (init && type == w83781d) {
-               u16 k = 0;
-/*
-    Auto-indexing doesn't seem to work...
-    w83781d_write_value(client,W83781D_REG_RT_IDX,0);
-*/
-               for (i = 0; i < 3; i++) {
-                       int j;
-                       for (j = 0; j < 32; j++) {
-                               w83781d_write_value(client,
-                                                   W83781D_REG_RT_IDX, k++);
-                               data->rt[i][j] =
-                                   w83781d_read_value(client,
-                                                      W83781D_REG_RT_VAL);
-                       }
+       if (init && type != as99127f) {
+               /* Enable temp2 */
+               tmp = w83781d_read_value(client, W83781D_REG_TEMP2_CONFIG);
+               if (tmp & 0x01) {
+                       dev_warn(&client->dev, "Enabling temp2, readings "
+                                "might not make sense\n");
+                       w83781d_write_value(client, W83781D_REG_TEMP2_CONFIG,
+                               tmp & 0xfe);
                }
-       }
-#endif                         /* W83781D_RT */
 
-       if (init) {
+               /* Enable temp3 */
                if (type != w83783s && type != w83697hf) {
-                       w83781d_write_value(client, W83781D_REG_TEMP3_CONFIG,
-                                           0x00);
+                       tmp = w83781d_read_value(client,
+                               W83781D_REG_TEMP3_CONFIG);
+                       if (tmp & 0x01) {
+                               dev_warn(&client->dev, "Enabling temp3, "
+                                        "readings might not make sense\n");
+                               w83781d_write_value(client,
+                                       W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
+                       }
                }
+
                if (type != w83781d) {
                        /* enable comparator mode for temp2 and temp3 so
                           alarm indication will work correctly */
@@ -1585,10 +1533,9 @@ static struct w83781d_data *w83781d_update_device(struct device *dev)
 
        down(&data->update_lock);
 
-       if (time_after
-           (jiffies - data->last_updated, (unsigned long) (HZ + HZ / 2))
-           || time_before(jiffies, data->last_updated) || !data->valid) {
-               pr_debug("Starting device update\n");
+       if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+           || !data->valid) {
+               dev_dbg(dev, "Starting device update\n");
 
                for (i = 0; i <= 8; i++) {
                        if ((data->type == w83783s || data->type == w83697hf)