hwmon: (applesmc) Add iMac9,1 and MacBookPro2,2 support
[safe/jmp/linux-2.6] / drivers / hwmon / w83627hf.c
index 879d0a6..38e2805 100644 (file)
@@ -50,7 +50,8 @@
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/ioport.h>
-#include <asm/io.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
 #include "lm75.h"
 
 static struct platform_device *pdev;
@@ -58,27 +59,26 @@ static struct platform_device *pdev;
 #define DRVNAME "w83627hf"
 enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
 
-static u16 force_addr;
-module_param(force_addr, ushort, 0);
-MODULE_PARM_DESC(force_addr,
-                "Initialize the base address of the sensors");
+struct w83627hf_sio_data {
+       enum chips type;
+       int sioaddr;
+};
+
 static u8 force_i2c = 0x1f;
 module_param(force_i2c, byte, 0);
 MODULE_PARM_DESC(force_i2c,
                 "Initialize the i2c address of the sensors");
 
-static int reset;
-module_param(reset, bool, 0);
-MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
-
 static int init = 1;
 module_param(init, bool, 0);
 MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
 
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
 /* modified from kernel/include/traps.c */
-static int REG;                /* The register to read/write */
 #define        DEV     0x07    /* Register: Logical device select */
-static int VAL;                /* The value to read/write */
 
 /* logical device numbers for superio_select (below) */
 #define W83627HF_LD_FDC                0x00
@@ -108,37 +108,37 @@ static int VAL;           /* The value to read/write */
 #define W83687THF_VID_DATA     0xF1 /* w83687thf only */
 
 static inline void
-superio_outb(int reg, int val)
+superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
 {
-       outb(reg, REG);
-       outb(val, VAL);
+       outb(reg, sio->sioaddr);
+       outb(val, sio->sioaddr + 1);
 }
 
 static inline int
-superio_inb(int reg)
+superio_inb(struct w83627hf_sio_data *sio, int reg)
 {
-       outb(reg, REG);
-       return inb(VAL);
+       outb(reg, sio->sioaddr);
+       return inb(sio->sioaddr + 1);
 }
 
 static inline void
-superio_select(int ld)
+superio_select(struct w83627hf_sio_data *sio, int ld)
 {
-       outb(DEV, REG);
-       outb(ld, VAL);
+       outb(DEV, sio->sioaddr);
+       outb(ld,  sio->sioaddr + 1);
 }
 
 static inline void
-superio_enter(void)
+superio_enter(struct w83627hf_sio_data *sio)
 {
-       outb(0x87, REG);
-       outb(0x87, REG);
+       outb(0x87, sio->sioaddr);
+       outb(0x87, sio->sioaddr);
 }
 
 static inline void
-superio_exit(void)
+superio_exit(struct w83627hf_sio_data *sio)
 {
-       outb(0xAA, REG);
+       outb(0xAA, sio->sioaddr);
 }
 
 #define W627_DEVID 0x52
@@ -205,6 +205,13 @@ static const u16 w83627hf_reg_temp_over[]  = { 0x39, 0x155, 0x255 };
 #define W83627HF_REG_PWM1 0x5A
 #define W83627HF_REG_PWM2 0x5B
 
+static const u8 W83627THF_REG_PWM_ENABLE[] = {
+       0x04,           /* FAN 1 mode */
+       0x04,           /* FAN 2 mode */
+       0x12,           /* FAN AUX mode */
+};
+static const u8 W83627THF_PWM_ENABLE_SHIFT[] = { 2, 4, 1 };
+
 #define W83627THF_REG_PWM1             0x01    /* 697HF/637HF/687THF too */
 #define W83627THF_REG_PWM2             0x03    /* 697HF/637HF/687THF too */
 #define W83627THF_REG_PWM3             0x11    /* 637HF/687THF too */
@@ -319,10 +326,8 @@ static inline u8 pwm_freq_to_reg(unsigned long val)
                return (0x80 | (180000UL / (val << 8)));
 }
 
-#define BEEP_MASK_FROM_REG(val)                 (val)
-#define BEEP_MASK_TO_REG(val)          ((val) & 0xffffff)
-#define BEEP_ENABLE_TO_REG(val)                ((val)?1:0)
-#define BEEP_ENABLE_FROM_REG(val)      ((val)?1:0)
+#define BEEP_MASK_FROM_REG(val)                ((val) & 0xff7fff)
+#define BEEP_MASK_TO_REG(val)          ((val) & 0xff7fff)
 
 #define DIV_FROM_REG(val) (1 << (val))
 
@@ -363,8 +368,10 @@ struct w83627hf_data {
        u8 vid;                 /* Register encoding, combined */
        u32 alarms;             /* Register encoding, combined */
        u32 beep_mask;          /* Register encoding, combined */
-       u8 beep_enable;         /* Boolean */
        u8 pwm[3];              /* Register value */
+       u8 pwm_enable[3];       /* 1 = manual
+                                  2 = thermal cruise (also called SmartFan I)
+                                  3 = fan speed cruise */
        u8 pwm_freq[3];         /* Register value */
        u16 sens[3];            /* 1 = pentium diode; 2 = 3904 diode;
                                   4 = thermistor */
@@ -372,10 +379,6 @@ struct w83627hf_data {
        u8 vrm_ovt;             /* Register value, 627THF/637HF/687THF only */
 };
 
-struct w83627hf_sio_data {
-       enum chips type;
-};
-
 
 static int w83627hf_probe(struct platform_device *pdev);
 static int __devexit w83627hf_remove(struct platform_device *pdev);
@@ -713,65 +716,151 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
 
-#define show_beep_reg(REG, reg) \
-static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       struct w83627hf_data *data = w83627hf_update_device(dev); \
-       return sprintf(buf,"%ld\n", \
-                     (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \
+static ssize_t
+show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct w83627hf_data *data = w83627hf_update_device(dev);
+       int bitnr = to_sensor_dev_attr(attr)->index;
+       return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
 }
-show_beep_reg(ENABLE, enable)
-show_beep_reg(MASK, mask)
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13);
 
-#define BEEP_ENABLE                    0       /* Store beep_enable */
-#define BEEP_MASK                      1       /* Store beep_mask */
+static ssize_t
+show_beep_mask(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct w83627hf_data *data = w83627hf_update_device(dev);
+       return sprintf(buf, "%ld\n",
+                     (long)BEEP_MASK_FROM_REG(data->beep_mask));
+}
 
 static ssize_t
-store_beep_reg(struct device *dev, const char *buf, size_t count,
-              int update_mask)
+store_beep_mask(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
 {
        struct w83627hf_data *data = dev_get_drvdata(dev);
-       u32 val, val2;
+       unsigned long val;
 
        val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
 
-       if (update_mask == BEEP_MASK) { /* We are storing beep_mask */
-               data->beep_mask = BEEP_MASK_TO_REG(val);
-               w83627hf_write_value(data, W83781D_REG_BEEP_INTS1,
-                                   data->beep_mask & 0xff);
-               w83627hf_write_value(data, W83781D_REG_BEEP_INTS3,
-                                   ((data->beep_mask) >> 16) & 0xff);
-               val2 = (data->beep_mask >> 8) & 0x7f;
-       } else {                /* We are storing beep_enable */
-               val2 =
-                   w83627hf_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f;
-               data->beep_enable = BEEP_ENABLE_TO_REG(val);
-       }
-
+       /* preserve beep enable */
+       data->beep_mask = (data->beep_mask & 0x8000)
+                       | BEEP_MASK_TO_REG(val);
+       w83627hf_write_value(data, W83781D_REG_BEEP_INTS1,
+                           data->beep_mask & 0xff);
+       w83627hf_write_value(data, W83781D_REG_BEEP_INTS3,
+                           ((data->beep_mask) >> 16) & 0xff);
        w83627hf_write_value(data, W83781D_REG_BEEP_INTS2,
-                           val2 | data->beep_enable << 7);
+                           (data->beep_mask >> 8) & 0xff);
 
        mutex_unlock(&data->update_lock);
        return count;
 }
 
-#define sysfs_beep(REG, reg) \
-static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       return show_beep_##reg(dev, attr, buf); \
-} \
-static ssize_t \
-store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
-       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_mask, S_IRUGO | S_IWUSR,
+                  show_beep_mask, store_beep_mask);
+
+static ssize_t
+show_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct w83627hf_data *data = w83627hf_update_device(dev);
+       int bitnr = to_sensor_dev_attr(attr)->index;
+       return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct w83627hf_data *data = dev_get_drvdata(dev);
+       int bitnr = to_sensor_dev_attr(attr)->index;
+       unsigned long bit;
+       u8 reg;
+
+       bit = simple_strtoul(buf, NULL, 10);
+       if (bit & ~1)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       if (bit)
+               data->beep_mask |= (1 << bitnr);
+       else
+               data->beep_mask &= ~(1 << bitnr);
+
+       if (bitnr < 8) {
+               reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS1);
+               if (bit)
+                       reg |= (1 << bitnr);
+               else
+                       reg &= ~(1 << bitnr);
+               w83627hf_write_value(data, W83781D_REG_BEEP_INTS1, reg);
+       } else if (bitnr < 16) {
+               reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
+               if (bit)
+                       reg |= (1 << (bitnr - 8));
+               else
+                       reg &= ~(1 << (bitnr - 8));
+               w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, reg);
+       } else {
+               reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS3);
+               if (bit)
+                       reg |= (1 << (bitnr - 16));
+               else
+                       reg &= ~(1 << (bitnr - 16));
+               w83627hf_write_value(data, W83781D_REG_BEEP_INTS3, reg);
+       }
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
 
-sysfs_beep(ENABLE, enable);
-sysfs_beep(MASK, mask);
+static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 0);
+static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 1);
+static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 2);
+static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 3);
+static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 8);
+static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 9);
+static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 10);
+static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 16);
+static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 17);
+static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 6);
+static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 7);
+static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 11);
+static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 4);
+static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 5);
+static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 13);
+static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 15);
 
 static ssize_t
 show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
@@ -870,6 +959,42 @@ static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1);
 static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2);
 
 static ssize_t
+show_pwm_enable(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       int nr = to_sensor_dev_attr(devattr)->index;
+       struct w83627hf_data *data = w83627hf_update_device(dev);
+       return sprintf(buf, "%d\n", data->pwm_enable[nr]);
+}
+
+static ssize_t
+store_pwm_enable(struct device *dev, struct device_attribute *devattr,
+         const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(devattr)->index;
+       struct w83627hf_data *data = dev_get_drvdata(dev);
+       unsigned long val = simple_strtoul(buf, NULL, 10);
+       u8 reg;
+
+       if (!val || (val > 3))  /* modes 1, 2 and 3 are supported */
+               return -EINVAL;
+       mutex_lock(&data->update_lock);
+       data->pwm_enable[nr] = val;
+       reg = w83627hf_read_value(data, W83627THF_REG_PWM_ENABLE[nr]);
+       reg &= ~(0x03 << W83627THF_PWM_ENABLE_SHIFT[nr]);
+       reg |= (val - 1) << W83627THF_PWM_ENABLE_SHIFT[nr];
+       w83627hf_write_value(data, W83627THF_REG_PWM_ENABLE[nr], reg);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+                                                 store_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+                                                 store_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+                                                 store_pwm_enable, 2);
+
+static ssize_t
 show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf)
 {
        int nr = to_sensor_dev_attr(devattr)->index;
@@ -1010,11 +1135,9 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
                "W83687THF",
        };
 
-       REG = sioaddr;
-       VAL = sioaddr + 1;
-
-       superio_enter();
-       val= superio_inb(DEVID);
+       sio_data->sioaddr = sioaddr;
+       superio_enter(sio_data);
+       val = force_id ? force_id : superio_inb(sio_data, DEVID);
        switch (val) {
        case W627_DEVID:
                sio_data->type = w83627hf;
@@ -1038,16 +1161,9 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
                goto exit;
        }
 
-       superio_select(W83627HF_LD_HWM);
-       force_addr &= WINB_ALIGNMENT;
-       if (force_addr) {
-               printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
-                      force_addr);
-               superio_outb(WINB_BASE_REG, force_addr >> 8);
-               superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
-       }
-       val = (superio_inb(WINB_BASE_REG) << 8) |
-              superio_inb(WINB_BASE_REG + 1);
+       superio_select(sio_data, W83627HF_LD_HWM);
+       val = (superio_inb(sio_data, WINB_BASE_REG) << 8) |
+              superio_inb(sio_data, WINB_BASE_REG + 1);
        *addr = val & WINB_ALIGNMENT;
        if (*addr == 0) {
                printk(KERN_WARNING DRVNAME ": Base address not set, "
@@ -1055,10 +1171,10 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
                goto exit;
        }
 
-       val = superio_inb(WINB_ACT_REG);
+       val = superio_inb(sio_data, WINB_ACT_REG);
        if (!(val & 0x01)) {
                printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
-               superio_outb(WINB_ACT_REG, val | 0x01);
+               superio_outb(sio_data, WINB_ACT_REG, val | 0x01);
        }
 
        err = 0;
@@ -1066,30 +1182,38 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
                names[sio_data->type], *addr);
 
  exit:
-       superio_exit();
+       superio_exit(sio_data);
        return err;
 }
 
 #define VIN_UNIT_ATTRS(_X_)    \
        &sensor_dev_attr_in##_X_##_input.dev_attr.attr,         \
        &sensor_dev_attr_in##_X_##_min.dev_attr.attr,           \
-       &sensor_dev_attr_in##_X_##_max.dev_attr.attr
+       &sensor_dev_attr_in##_X_##_max.dev_attr.attr,           \
+       &sensor_dev_attr_in##_X_##_alarm.dev_attr.attr,         \
+       &sensor_dev_attr_in##_X_##_beep.dev_attr.attr
 
 #define FAN_UNIT_ATTRS(_X_)    \
        &sensor_dev_attr_fan##_X_##_input.dev_attr.attr,        \
        &sensor_dev_attr_fan##_X_##_min.dev_attr.attr,          \
-       &sensor_dev_attr_fan##_X_##_div.dev_attr.attr
+       &sensor_dev_attr_fan##_X_##_div.dev_attr.attr,          \
+       &sensor_dev_attr_fan##_X_##_alarm.dev_attr.attr,        \
+       &sensor_dev_attr_fan##_X_##_beep.dev_attr.attr
 
 #define TEMP_UNIT_ATTRS(_X_)   \
        &sensor_dev_attr_temp##_X_##_input.dev_attr.attr,       \
        &sensor_dev_attr_temp##_X_##_max.dev_attr.attr,         \
        &sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr,    \
-       &sensor_dev_attr_temp##_X_##_type.dev_attr.attr
+       &sensor_dev_attr_temp##_X_##_type.dev_attr.attr,        \
+       &sensor_dev_attr_temp##_X_##_alarm.dev_attr.attr,       \
+       &sensor_dev_attr_temp##_X_##_beep.dev_attr.attr
 
 static struct attribute *w83627hf_attributes[] = {
        &dev_attr_in0_input.attr,
        &dev_attr_in0_min.attr,
        &dev_attr_in0_max.attr,
+       &sensor_dev_attr_in0_alarm.dev_attr.attr,
+       &sensor_dev_attr_in0_beep.dev_attr.attr,
        VIN_UNIT_ATTRS(2),
        VIN_UNIT_ATTRS(3),
        VIN_UNIT_ATTRS(4),
@@ -1103,7 +1227,7 @@ static struct attribute *w83627hf_attributes[] = {
        TEMP_UNIT_ATTRS(2),
 
        &dev_attr_alarms.attr,
-       &dev_attr_beep_enable.attr,
+       &sensor_dev_attr_beep_enable.dev_attr.attr,
        &dev_attr_beep_mask.attr,
 
        &sensor_dev_attr_pwm1.dev_attr.attr,
@@ -1128,6 +1252,11 @@ static struct attribute *w83627hf_attributes_opt[] = {
        &sensor_dev_attr_pwm1_freq.dev_attr.attr,
        &sensor_dev_attr_pwm2_freq.dev_attr.attr,
        &sensor_dev_attr_pwm3_freq.dev_attr.attr,
+
+       &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+
        NULL
 };
 
@@ -1193,12 +1322,20 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
                 || (err = device_create_file(dev,
                                &sensor_dev_attr_in5_max.dev_attr))
                 || (err = device_create_file(dev,
+                               &sensor_dev_attr_in5_alarm.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_in5_beep.dev_attr))
+                || (err = device_create_file(dev,
                                &sensor_dev_attr_in6_input.dev_attr))
                 || (err = device_create_file(dev,
                                &sensor_dev_attr_in6_min.dev_attr))
                 || (err = device_create_file(dev,
                                &sensor_dev_attr_in6_max.dev_attr))
                 || (err = device_create_file(dev,
+                               &sensor_dev_attr_in6_alarm.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_in6_beep.dev_attr))
+                || (err = device_create_file(dev,
                                &sensor_dev_attr_pwm1_freq.dev_attr))
                 || (err = device_create_file(dev,
                                &sensor_dev_attr_pwm2_freq.dev_attr)))
@@ -1212,18 +1349,30 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
                 || (err = device_create_file(dev,
                                &sensor_dev_attr_in1_max.dev_attr))
                 || (err = device_create_file(dev,
+                               &sensor_dev_attr_in1_alarm.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_in1_beep.dev_attr))
+                || (err = device_create_file(dev,
                                &sensor_dev_attr_fan3_input.dev_attr))
                 || (err = device_create_file(dev,
                                &sensor_dev_attr_fan3_min.dev_attr))
                 || (err = device_create_file(dev,
                                &sensor_dev_attr_fan3_div.dev_attr))
                 || (err = device_create_file(dev,
+                               &sensor_dev_attr_fan3_alarm.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_fan3_beep.dev_attr))
+                || (err = device_create_file(dev,
                                &sensor_dev_attr_temp3_input.dev_attr))
                 || (err = device_create_file(dev,
                                &sensor_dev_attr_temp3_max.dev_attr))
                 || (err = device_create_file(dev,
                                &sensor_dev_attr_temp3_max_hyst.dev_attr))
                 || (err = device_create_file(dev,
+                               &sensor_dev_attr_temp3_alarm.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_temp3_beep.dev_attr))
+                || (err = device_create_file(dev,
                                &sensor_dev_attr_temp3_type.dev_attr)))
                        goto ERROR4;
 
@@ -1251,6 +1400,19 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
                                &sensor_dev_attr_pwm3_freq.dev_attr)))
                        goto ERROR4;
 
+       if (data->type != w83627hf)
+               if ((err = device_create_file(dev,
+                               &sensor_dev_attr_pwm1_enable.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_pwm2_enable.dev_attr)))
+                       goto ERROR4;
+
+       if (data->type == w83627thf || data->type == w83637hf
+        || data->type == w83687thf)
+               if ((err = device_create_file(dev,
+                               &sensor_dev_attr_pwm3_enable.dev_attr)))
+                       goto ERROR4;
+
        data->hwmon_dev = hwmon_device_register(dev);
        if (IS_ERR(data->hwmon_dev)) {
                err = PTR_ERR(data->hwmon_dev);
@@ -1335,20 +1497,21 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
 
 static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
 {
+       struct w83627hf_sio_data *sio_data = pdev->dev.platform_data;
        int res = 0xff, sel;
 
-       superio_enter();
-       superio_select(W83627HF_LD_GPIO5);
+       superio_enter(sio_data);
+       superio_select(sio_data, W83627HF_LD_GPIO5);
 
        /* Make sure these GPIO pins are enabled */
-       if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
+       if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) {
                dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
                goto exit;
        }
 
        /* Make sure the pins are configured for input
           There must be at least five (VRM 9), and possibly 6 (VRM 10) */
-       sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
+       sel = superio_inb(sio_data, W83627THF_GPIO5_IOSR) & 0x3f;
        if ((sel & 0x1f) != 0x1f) {
                dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
                        "function\n");
@@ -1356,37 +1519,38 @@ static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
        }
 
        dev_info(&pdev->dev, "Reading VID from GPIO5\n");
-       res = superio_inb(W83627THF_GPIO5_DR) & sel;
+       res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel;
 
 exit:
-       superio_exit();
+       superio_exit(sio_data);
        return res;
 }
 
 static int __devinit w83687thf_read_vid(struct platform_device *pdev)
 {
+       struct w83627hf_sio_data *sio_data = pdev->dev.platform_data;
        int res = 0xff;
 
-       superio_enter();
-       superio_select(W83627HF_LD_HWM);
+       superio_enter(sio_data);
+       superio_select(sio_data, W83627HF_LD_HWM);
 
        /* Make sure these GPIO pins are enabled */
-       if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
+       if (!(superio_inb(sio_data, W83687THF_VID_EN) & (1 << 2))) {
                dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
                goto exit;
        }
 
        /* Make sure the pins are configured for input */
-       if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
+       if (!(superio_inb(sio_data, W83687THF_VID_CFG) & (1 << 4))) {
                dev_dbg(&pdev->dev, "VID configured as output, "
                        "no VID function\n");
                goto exit;
        }
 
-       res = superio_inb(W83687THF_VID_DATA) & 0x3f;
+       res = superio_inb(sio_data, W83687THF_VID_DATA) & 0x3f;
 
 exit:
-       superio_exit();
+       superio_exit(sio_data);
        return res;
 }
 
@@ -1421,29 +1585,6 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
        enum chips type = data->type;
        u8 tmp;
 
-       if (reset) {
-               /* Resetting the chip has been the default for a long time,
-                  but repeatedly caused problems (fans going to full
-                  speed...) so it is now optional. It might even go away if
-                  nobody reports it as being useful, as I see very little
-                  reason why this would be needed at all. */
-               dev_info(&pdev->dev, "If reset=1 solved a problem you were "
-                        "having, please report!\n");
-
-               /* save this register */
-               i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG);
-               /* Reset all except Watchdog values and last conversion values
-                  This sets fan-divs to 2, among others */
-               w83627hf_write_value(data, W83781D_REG_CONFIG, 0x80);
-               /* Restore the register and disable power-on abnormal beep.
-                  This saves FAN 1/2/3 input/output values set by BIOS. */
-               w83627hf_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
-               /* Disable master beep-enable (reset turns it on).
-                  Individual beeps should be reset to off but for some reason
-                  disabling this bit helps some people not get beeped */
-               w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, 0);
-       }
-
        /* Minimize conflicts with other winbond i2c-only clients...  */
        /* disable i2c subclients... how to disable main i2c client?? */
        /* force i2c address to relatively uncommon address */
@@ -1511,6 +1652,11 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
                            (w83627hf_read_value(data,
                                                W83781D_REG_CONFIG) & 0xf7)
                            | 0x01);
+
+       /* Enable VBAT monitoring if needed */
+       tmp = w83627hf_read_value(data, W83781D_REG_VBAT);
+       if (!(tmp & 0x01))
+               w83627hf_write_value(data, W83781D_REG_VBAT, tmp | 0x01);
 }
 
 static void w83627hf_update_fan_div(struct w83627hf_data *data)
@@ -1535,6 +1681,7 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 {
        struct w83627hf_data *data = dev_get_drvdata(dev);
        int i, num_temps = (data->type == w83697hf) ? 2 : 3;
+       int num_pwms = (data->type == w83697hf) ? 2 : 3;
 
        mutex_lock(&data->update_lock);
 
@@ -1587,6 +1734,15 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
                                        break;
                        }
                }
+               if (data->type != w83627hf) {
+                       for (i = 0; i < num_pwms; i++) {
+                               u8 tmp = w83627hf_read_value(data,
+                                       W83627THF_REG_PWM_ENABLE[i]);
+                               data->pwm_enable[i] =
+                                       ((tmp >> W83627THF_PWM_ENABLE_SHIFT[i])
+                                       & 0x03) + 1;
+                       }
+               }
                for (i = 0; i < num_temps; i++) {
                        data->temp[i] = w83627hf_read_value(
                                                data, w83627hf_reg_temp[i]);
@@ -1603,8 +1759,7 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
                    (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |
                    (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16);
                i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
-               data->beep_enable = i >> 7;
-               data->beep_mask = ((i & 0x7f) << 8) |
+               data->beep_mask = (i << 8) |
                    w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) |
                    w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16;
                data->last_updated = jiffies;
@@ -1627,6 +1782,10 @@ static int __init w83627hf_device_add(unsigned short address,
        };
        int err;
 
+       err = acpi_check_resource_conflict(&res);
+       if (err)
+               goto exit;
+
        pdev = platform_device_alloc(DRVNAME, address);
        if (!pdev) {
                err = -ENOMEM;