[PATCH] hwmon: Fix the Kconfig header
[safe/jmp/linux-2.6] / drivers / hwmon / w83781d.c
index 66835c1..e4c7003 100644 (file)
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-isa.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
 #include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include "lm75.h"
 
@@ -53,10 +53,14 @@ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
 static unsigned short isa_address = 0x290;
 
 /* Insmod parameters */
-SENSORS_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f);
+I2C_CLIENT_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f);
 I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
                    "{bus, clientaddr, subclientaddr1, subclientaddr2}");
 
+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");
@@ -96,11 +100,16 @@ MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
                                                     (0x39)))
 
 #define W83781D_REG_CONFIG             0x40
+
+/* Interrupt status (W83781D, AS99127F) */
 #define W83781D_REG_ALARM1             0x41
 #define W83781D_REG_ALARM2             0x42
-#define W83781D_REG_ALARM3             0x450   /* not on W83781D */
 
-#define W83781D_REG_IRQ                        0x4C
+/* Real-time status (W83782D, W83783S, W83627HF) */
+#define W83782D_REG_ALARM1             0x459
+#define W83782D_REG_ALARM2             0x45A
+#define W83782D_REG_ALARM3             0x45B
+
 #define W83781D_REG_BEEP_CONFIG                0x4D
 #define W83781D_REG_BEEP_INTS1         0x56
 #define W83781D_REG_BEEP_INTS2         0x57
@@ -222,10 +231,10 @@ DIV_TO_REG(long val, enum chips type)
 struct w83781d_data {
        struct i2c_client client;
        struct class_device *class_dev;
-       struct semaphore lock;
+       struct mutex lock;
        enum chips type;
 
-       struct semaphore update_lock;
+       struct mutex update_lock;
        char valid;             /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
 
@@ -263,24 +272,24 @@ static int w83781d_isa_attach_adapter(struct i2c_adapter *adapter);
 static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind);
 static int w83781d_detach_client(struct i2c_client *client);
 
-static int w83781d_read_value(struct i2c_client *client, u16 register);
-static int w83781d_write_value(struct i2c_client *client, u16 register,
-                              u16 value);
+static int w83781d_read_value(struct i2c_client *client, u16 reg);
+static int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value);
 static struct w83781d_data *w83781d_update_device(struct device *dev);
 static void w83781d_init_client(struct i2c_client *client);
 
 static struct i2c_driver w83781d_driver = {
-       .owner = THIS_MODULE,
-       .name = "w83781d",
+       .driver = {
+               .name = "w83781d",
+       },
        .id = I2C_DRIVERID_W83781D,
-       .flags = I2C_DF_NOTIFY,
        .attach_adapter = w83781d_attach_adapter,
        .detach_client = w83781d_detach_client,
 };
 
 static struct i2c_driver w83781d_isa_driver = {
-       .owner = THIS_MODULE,
-       .name = "w83781d-isa",
+       .driver = {
+               .name = "w83781d-isa",
+       },
        .attach_adapter = w83781d_isa_attach_adapter,
        .detach_client = w83781d_detach_client,
 };
@@ -306,11 +315,11 @@ static ssize_t store_in_##reg (struct device *dev, const char *buf, size_t count
         \
        val = simple_strtoul(buf, NULL, 10) / 10; \
         \
-       down(&data->update_lock); \
+       mutex_lock(&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); \
+       mutex_unlock(&data->update_lock); \
        return count; \
 }
 store_in_reg(MIN, min);
@@ -376,13 +385,13 @@ store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
 
        val = simple_strtoul(buf, NULL, 10);
 
-       down(&data->update_lock);
+       mutex_lock(&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);
+       mutex_unlock(&data->update_lock);
        return count;
 }
 
@@ -441,7 +450,7 @@ 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); \
+       mutex_lock(&data->update_lock); \
         \
        if (nr >= 2) {  /* TEMP2 and TEMP3 */ \
                data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
@@ -453,7 +462,7 @@ static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t cou
                        data->temp_##reg); \
        } \
         \
-       up(&data->update_lock); \
+       mutex_unlock(&data->update_lock); \
        return count; \
 }
 store_temp_reg(OVER, max);
@@ -566,7 +575,7 @@ store_beep_reg(struct device *dev, const char *buf, size_t count,
 
        val = simple_strtoul(buf, NULL, 10);
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
 
        if (update_mask == BEEP_MASK) { /* We are storing beep_mask */
                data->beep_mask = BEEP_MASK_TO_REG(val, data->type);
@@ -587,7 +596,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);
+       mutex_unlock(&data->update_lock);
        return count;
 }
 
@@ -632,7 +641,7 @@ store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
        u8 reg;
        unsigned long val = simple_strtoul(buf, NULL, 10);
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
        
        /* Save fan_min */
        min = FAN_FROM_REG(data->fan_min[nr],
@@ -657,7 +666,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);
+       mutex_unlock(&data->update_lock);
        return count;
 }
 
@@ -704,10 +713,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);
+       mutex_lock(&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);
+       mutex_unlock(&data->update_lock);
        return count;
 }
 
@@ -720,7 +729,7 @@ store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr)
 
        val = simple_strtoul(buf, NULL, 10);
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
 
        switch (val) {
        case 0:
@@ -737,11 +746,11 @@ store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr)
                break;
 
        default:
-               up(&data->update_lock);
+               mutex_unlock(&data->update_lock);
                return -EINVAL;
        }
 
-       up(&data->update_lock);
+       mutex_unlock(&data->update_lock);
        return count;
 }
 
@@ -803,7 +812,7 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
 
        val = simple_strtoul(buf, NULL, 10);
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
 
        switch (val) {
        case 1:         /* PII/Celeron diode */
@@ -836,7 +845,7 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
                break;
        }
 
-       up(&data->update_lock);
+       mutex_unlock(&data->update_lock);
        return count;
 }
 
@@ -869,7 +878,7 @@ w83781d_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON))
                return 0;
-       return i2c_detect(adapter, &addr_data, w83781d_detect);
+       return i2c_probe(adapter, &addr_data, w83781d_detect);
 }
 
 static int
@@ -890,12 +899,11 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
        const char *client_name = "";
        struct w83781d_data *data = i2c_get_clientdata(new_client);
 
-       data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       data->lm75[0] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
        if (!(data->lm75[0])) {
                err = -ENOMEM;
                goto ERROR_SC_0;
        }
-       memset(data->lm75[0], 0x00, sizeof (struct i2c_client));
 
        id = i2c_adapter_id(adapter);
 
@@ -920,13 +928,11 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
        }
 
        if (kind != w83783s) {
-
-               data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+               data->lm75[1] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
                if (!(data->lm75[1])) {
                        err = -ENOMEM;
                        goto ERROR_SC_1;
                }
-               memset(data->lm75[1], 0x0, sizeof(struct i2c_client));
 
                if (force_subclients[0] == id &&
                    force_subclients[1] == address) {
@@ -980,11 +986,9 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
 ERROR_SC_3:
        i2c_detach_client(data->lm75[0]);
 ERROR_SC_2:
-       if (data->lm75[1])
-               kfree(data->lm75[1]);
+       kfree(data->lm75[1]);
 ERROR_SC_1:
-       if (data->lm75[0])
-               kfree(data->lm75[0]);
+       kfree(data->lm75[0]);
 ERROR_SC_0:
        return err;
 }
@@ -1018,7 +1022,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
        
        if (is_isa)
                if (!request_region(address, W83781D_EXTENT,
-                                   w83781d_isa_driver.name)) {
+                                   w83781d_isa_driver.driver.name)) {
                        dev_dbg(&adapter->dev, "Request of region "
                                "0x%x-0x%x for w83781d failed\n", address,
                                address + W83781D_EXTENT - 1);
@@ -1065,16 +1069,15 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
           client structure, even though we cannot fill it completely yet.
           But it allows us to access w83781d_{read,write}_value. */
 
-       if (!(data = kmalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {
+       if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {
                err = -ENOMEM;
                goto ERROR1;
        }
-       memset(data, 0, sizeof(struct w83781d_data));
 
        new_client = &data->client;
        i2c_set_clientdata(new_client, data);
        new_client->addr = address;
-       init_MUTEX(&data->lock);
+       mutex_init(&data->lock);
        new_client->adapter = adapter;
        new_client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
        new_client->flags = 0;
@@ -1179,7 +1182,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
        data->type = kind;
 
        data->valid = 0;
-       init_MUTEX(&data->update_lock);
+       mutex_init(&data->update_lock);
 
        /* Tell the I2C layer a new client has arrived */
        if ((err = i2c_attach_client(new_client)))
@@ -1326,7 +1329,7 @@ w83781d_read_value(struct i2c_client *client, u16 reg)
        int res, word_sized, bank;
        struct i2c_client *cl;
 
-       down(&data->lock);
+       mutex_lock(&data->lock);
        if (i2c_is_isa_client(client)) {
                word_sized = (((reg & 0xff00) == 0x100)
                              || ((reg & 0xff00) == 0x200))
@@ -1384,7 +1387,7 @@ w83781d_read_value(struct i2c_client *client, u16 reg)
                if (bank > 2)
                        i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
        }
-       up(&data->lock);
+       mutex_unlock(&data->lock);
        return res;
 }
 
@@ -1395,7 +1398,7 @@ w83781d_write_value(struct i2c_client *client, u16 reg, u16 value)
        int word_sized, bank;
        struct i2c_client *cl;
 
-       down(&data->lock);
+       mutex_lock(&data->lock);
        if (i2c_is_isa_client(client)) {
                word_sized = (((reg & 0xff00) == 0x100)
                              || ((reg & 0xff00) == 0x200))
@@ -1448,11 +1451,10 @@ w83781d_write_value(struct i2c_client *client, u16 reg, u16 value)
                if (bank > 2)
                        i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
        }
-       up(&data->lock);
+       mutex_unlock(&data->lock);
        return 0;
 }
 
-/* Called when we have found a new W83781D. It should set limits, etc. */
 static void
 w83781d_init_client(struct i2c_client *client)
 {
@@ -1461,8 +1463,17 @@ w83781d_init_client(struct i2c_client *client)
        int type = data->type;
        u8 tmp;
 
-       if (init && type != as99127f) { /* this resets registers we don't have
+       if (reset && type != as99127f) { /* this resets registers we don't have
                                           documentation for on the as99127f */
+               /* Resetting the chip has been the default for a long time,
+                  but it causes the BIOS initializations (fan clock dividers,
+                  thermal sensor types...) to be lost, 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(&client->dev, "If reset=1 solved a problem you were "
+                        "having, please report!\n");
+
                /* save these registers */
                i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
                p = w83781d_read_value(client, W83781D_REG_PWMCLK12);
@@ -1479,7 +1490,14 @@ w83781d_init_client(struct i2c_client *client)
                w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0);
        }
 
-       data->vrm = i2c_which_vrm();
+       /* Disable power-on abnormal beep, as advised by the datasheet.
+          Already done if reset=1. */
+       if (init && !reset && type != as99127f) {
+               i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
+               w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);
+       }
+
+       data->vrm = vid_which_vrm();
 
        if ((type != w83781d) && (type != as99127f)) {
                tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
@@ -1520,15 +1538,6 @@ w83781d_init_client(struct i2c_client *client)
                                        W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
                        }
                }
-
-               if (type != w83781d) {
-                       /* enable comparator mode for temp2 and temp3 so
-                          alarm indication will work correctly */
-                       i = w83781d_read_value(client, W83781D_REG_IRQ);
-                       if (!(i & 0x40))
-                               w83781d_write_value(client, W83781D_REG_IRQ,
-                                                   i | 0x40);
-               }
        }
 
        /* Start monitoring */
@@ -1544,7 +1553,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev)
        struct w83781d_data *data = i2c_get_clientdata(client);
        int i;
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
 
        if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
            || !data->valid) {
@@ -1619,14 +1628,25 @@ static struct w83781d_data *w83781d_update_device(struct device *dev)
                        data->fan_div[1] |= (i >> 4) & 0x04;
                        data->fan_div[2] |= (i >> 5) & 0x04;
                }
-               data->alarms =
-                   w83781d_read_value(client,
-                                      W83781D_REG_ALARM1) +
-                   (w83781d_read_value(client, W83781D_REG_ALARM2) << 8);
                if ((data->type == w83782d) || (data->type == w83627hf)) {
-                       data->alarms |=
-                           w83781d_read_value(client,
-                                              W83781D_REG_ALARM3) << 16;
+                       data->alarms = w83781d_read_value(client,
+                                               W83782D_REG_ALARM1)
+                                    | (w83781d_read_value(client,
+                                               W83782D_REG_ALARM2) << 8)
+                                    | (w83781d_read_value(client,
+                                               W83782D_REG_ALARM3) << 16);
+               } else if (data->type == w83783s) {
+                       data->alarms = w83781d_read_value(client,
+                                               W83782D_REG_ALARM1)
+                                    | (w83781d_read_value(client,
+                                               W83782D_REG_ALARM2) << 8);
+               } else {
+                       /* No real-time status registers, fall back to
+                          interrupt status registers */
+                       data->alarms = w83781d_read_value(client,
+                                               W83781D_REG_ALARM1)
+                                    | (w83781d_read_value(client,
+                                               W83781D_REG_ALARM2) << 8);
                }
                i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2);
                data->beep_enable = i >> 7;
@@ -1641,7 +1661,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev)
                data->valid = 1;
        }
 
-       up(&data->update_lock);
+       mutex_unlock(&data->update_lock);
 
        return data;
 }