hwmon: (applesmc) Add iMac9,1 and MacBookPro2,2 support
[safe/jmp/linux-2.6] / drivers / hwmon / w83627hf.c
index 9564fb0..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,19 +59,16 @@ 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");
@@ -80,9 +78,7 @@ 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
@@ -112,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
@@ -209,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 */
@@ -366,6 +369,9 @@ struct w83627hf_data {
        u32 alarms;             /* Register encoding, combined */
        u32 beep_mask;          /* Register encoding, combined */
        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 */
@@ -373,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);
@@ -957,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;
@@ -1097,11 +1135,9 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
                "W83687THF",
        };
 
-       REG = sioaddr;
-       VAL = sioaddr + 1;
-
-       superio_enter();
-       val = force_id ? force_id : 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;
@@ -1125,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, "
@@ -1142,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;
@@ -1153,7 +1182,7 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
                names[sio_data->type], *addr);
 
  exit:
-       superio_exit();
+       superio_exit(sio_data);
        return err;
 }
 
@@ -1223,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
 };
 
@@ -1366,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);
@@ -1450,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");
@@ -1471,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;
 }
 
@@ -1536,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 */
@@ -1655,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);
 
@@ -1707,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]);
@@ -1746,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;