Merge branch 'linus' into cont_syslog
[safe/jmp/linux-2.6] / drivers / hwmon / fschmd.c
index ac515bd..b7ca2a9 100644 (file)
@@ -19,7 +19,7 @@
 
 /*
  *  Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes,
- *  Scylla, Heracles, Heimdall and Syleus chips
+ *  Scylla, Heracles, Heimdall, Hades and Syleus chips
  *
  *  Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6
  *  (candidate) fschmd drivers:
@@ -38,6 +38,7 @@
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/smp_lock.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/sysfs.h>
@@ -56,7 +57,8 @@ static int nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-I2C_CLIENT_INSMOD_6(fscpos, fscher, fscscy, fschrc, fschmd, fscsyl);
+
+enum chips { fscpos, fscher, fscscy, fschrc, fschmd, fschds, fscsyl };
 
 /*
  * The FSCHMD registers and other defines
@@ -75,12 +77,12 @@ I2C_CLIENT_INSMOD_6(fscpos, fscher, fscscy, fschrc, fschmd, fscsyl);
 #define FSCHMD_CONTROL_ALERT_LED       0x01
 
 /* watchdog */
-static const u8 FSCHMD_REG_WDOG_CONTROL[6] =
-       { 0x21, 0x21, 0x21, 0x21, 0x21, 0x28 };
-static const u8 FSCHMD_REG_WDOG_STATE[6] =
-       { 0x23, 0x23, 0x23, 0x23, 0x23, 0x29 };
-static const u8 FSCHMD_REG_WDOG_PRESET[6] =
-       { 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a };
+static const u8 FSCHMD_REG_WDOG_CONTROL[7] =
+       { 0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 };
+static const u8 FSCHMD_REG_WDOG_STATE[7] =
+       { 0x23, 0x23, 0x23, 0x23, 0x23, 0x29, 0x29 };
+static const u8 FSCHMD_REG_WDOG_PRESET[7] =
+       { 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x2a };
 
 #define FSCHMD_WDOG_CONTROL_TRIGGER    0x10
 #define FSCHMD_WDOG_CONTROL_STARTED    0x10 /* the same as trigger */
@@ -90,61 +92,66 @@ static const u8 FSCHMD_REG_WDOG_PRESET[6] =
 #define FSCHMD_WDOG_STATE_CARDRESET    0x02
 
 /* voltages, weird order is to keep the same order as the old drivers */
-static const u8 FSCHMD_REG_VOLT[6][6] = {
+static const u8 FSCHMD_REG_VOLT[7][6] = {
        { 0x45, 0x42, 0x48 },                           /* pos */
        { 0x45, 0x42, 0x48 },                           /* her */
        { 0x45, 0x42, 0x48 },                           /* scy */
        { 0x45, 0x42, 0x48 },                           /* hrc */
        { 0x45, 0x42, 0x48 },                           /* hmd */
+       { 0x21, 0x20, 0x22 },                           /* hds */
        { 0x21, 0x20, 0x22, 0x23, 0x24, 0x25 },         /* syl */
 };
 
-static const int FSCHMD_NO_VOLT_SENSORS[6] = { 3, 3, 3, 3, 3, 6 };
+static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 };
 
 /* minimum pwm at which the fan is driven (pwm can by increased depending on
    the temp. Notice that for the scy some fans share there minimum speed.
    Also notice that with the scy the sensor order is different than with the
    other chips, this order was in the 2.4 driver and kept for consistency. */
-static const u8 FSCHMD_REG_FAN_MIN[6][7] = {
+static const u8 FSCHMD_REG_FAN_MIN[7][7] = {
        { 0x55, 0x65 },                                 /* pos */
        { 0x55, 0x65, 0xb5 },                           /* her */
        { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 },         /* scy */
        { 0x55, 0x65, 0xa5, 0xb5 },                     /* hrc */
        { 0x55, 0x65, 0xa5, 0xb5, 0xc5 },               /* hmd */
+       { 0x55, 0x65, 0xa5, 0xb5, 0xc5 },               /* hds */
        { 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 },   /* syl */
 };
 
 /* actual fan speed */
-static const u8 FSCHMD_REG_FAN_ACT[6][7] = {
+static const u8 FSCHMD_REG_FAN_ACT[7][7] = {
        { 0x0e, 0x6b, 0xab },                           /* pos */
        { 0x0e, 0x6b, 0xbb },                           /* her */
        { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb },         /* scy */
        { 0x0e, 0x6b, 0xab, 0xbb },                     /* hrc */
        { 0x5b, 0x6b, 0xab, 0xbb, 0xcb },               /* hmd */
+       { 0x5b, 0x6b, 0xab, 0xbb, 0xcb },               /* hds */
        { 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 },   /* syl */
 };
 
 /* fan status registers */
-static const u8 FSCHMD_REG_FAN_STATE[6][7] = {
+static const u8 FSCHMD_REG_FAN_STATE[7][7] = {
        { 0x0d, 0x62, 0xa2 },                           /* pos */
        { 0x0d, 0x62, 0xb2 },                           /* her */
        { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 },         /* scy */
        { 0x0d, 0x62, 0xa2, 0xb2 },                     /* hrc */
        { 0x52, 0x62, 0xa2, 0xb2, 0xc2 },               /* hmd */
+       { 0x52, 0x62, 0xa2, 0xb2, 0xc2 },               /* hds */
        { 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 },   /* syl */
 };
 
 /* fan ripple / divider registers */
-static const u8 FSCHMD_REG_FAN_RIPPLE[6][7] = {
+static const u8 FSCHMD_REG_FAN_RIPPLE[7][7] = {
        { 0x0f, 0x6f, 0xaf },                           /* pos */
        { 0x0f, 0x6f, 0xbf },                           /* her */
        { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf },         /* scy */
        { 0x0f, 0x6f, 0xaf, 0xbf },                     /* hrc */
        { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf },               /* hmd */
+       { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf },               /* hds */
        { 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6 },   /* syl */
 };
 
-static const int FSCHMD_NO_FAN_SENSORS[6] = { 3, 3, 6, 4, 5, 7 };
+static const int FSCHMD_NO_FAN_SENSORS[7] = { 3, 3, 6, 4, 5, 5, 7 };
 
 /* Fan status register bitmasks */
 #define FSCHMD_FAN_ALARM       0x04 /* called fault by FSC! */
@@ -153,23 +160,25 @@ static const int FSCHMD_NO_FAN_SENSORS[6] = { 3, 3, 6, 4, 5, 7 };
 
 
 /* actual temperature registers */
-static const u8 FSCHMD_REG_TEMP_ACT[6][11] = {
+static const u8 FSCHMD_REG_TEMP_ACT[7][11] = {
        { 0x64, 0x32, 0x35 },                           /* pos */
        { 0x64, 0x32, 0x35 },                           /* her */
        { 0x64, 0xD0, 0x32, 0x35 },                     /* scy */
        { 0x64, 0x32, 0x35 },                           /* hrc */
        { 0x70, 0x80, 0x90, 0xd0, 0xe0 },               /* hmd */
+       { 0x70, 0x80, 0x90, 0xd0, 0xe0 },               /* hds */
        { 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8,           /* syl */
          0xb8, 0xc8, 0xd8, 0xe8, 0xf8 },
 };
 
 /* temperature state registers */
-static const u8 FSCHMD_REG_TEMP_STATE[6][11] = {
+static const u8 FSCHMD_REG_TEMP_STATE[7][11] = {
        { 0x71, 0x81, 0x91 },                           /* pos */
        { 0x71, 0x81, 0x91 },                           /* her */
        { 0x71, 0xd1, 0x81, 0x91 },                     /* scy */
        { 0x71, 0x81, 0x91 },                           /* hrc */
        { 0x71, 0x81, 0x91, 0xd1, 0xe1 },               /* hmd */
+       { 0x71, 0x81, 0x91, 0xd1, 0xe1 },               /* hds */
        { 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9,           /* syl */
          0xb9, 0xc9, 0xd9, 0xe9, 0xf9 },
 };
@@ -179,12 +188,13 @@ static const u8 FSCHMD_REG_TEMP_STATE[6][11] = {
    in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
    at these addresses, but doesn't want to confirm they are the same as with
    the fscher?? */
-static const u8 FSCHMD_REG_TEMP_LIMIT[6][11] = {
+static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = {
        { 0, 0, 0 },                                    /* pos */
        { 0x76, 0x86, 0x96 },                           /* her */
        { 0x76, 0xd6, 0x86, 0x96 },                     /* scy */
        { 0x76, 0x86, 0x96 },                           /* hrc */
        { 0x76, 0x86, 0x96, 0xd6, 0xe6 },               /* hmd */
+       { 0x76, 0x86, 0x96, 0xd6, 0xe6 },               /* hds */
        { 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa,           /* syl */
          0xba, 0xca, 0xda, 0xea, 0xfa },
 };
@@ -197,7 +207,7 @@ static const u8 FSCHMD_REG_TEMP_LIMIT[6][11] = {
 static const u8 FSCHER_REG_TEMP_AUTOP1[] =     { 0x73, 0x83, 0x93 };
 static const u8 FSCHER_REG_TEMP_AUTOP2[] =     { 0x75, 0x85, 0x95 }; */
 
-static const int FSCHMD_NO_TEMP_SENSORS[6] = { 3, 3, 4, 3, 5, 11 };
+static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 };
 
 /* temp status register bitmasks */
 #define FSCHMD_TEMP_WORKING    0x01
@@ -213,7 +223,7 @@ static const int FSCHMD_NO_TEMP_SENSORS[6] = { 3, 3, 4, 3, 5, 11 };
 
 static int fschmd_probe(struct i2c_client *client,
                        const struct i2c_device_id *id);
-static int fschmd_detect(struct i2c_client *client, int kind,
+static int fschmd_detect(struct i2c_client *client,
                         struct i2c_board_info *info);
 static int fschmd_remove(struct i2c_client *client);
 static struct fschmd_data *fschmd_update_device(struct device *dev);
@@ -228,6 +238,7 @@ static const struct i2c_device_id fschmd_id[] = {
        { "fscscy", fscscy },
        { "fschrc", fschrc },
        { "fschmd", fschmd },
+       { "fschds", fschds },
        { "fscsyl", fscsyl },
        { }
 };
@@ -242,7 +253,7 @@ static struct i2c_driver fschmd_driver = {
        .remove         = fschmd_remove,
        .id_table       = fschmd_id,
        .detect         = fschmd_detect,
-       .address_data   = &addr_data,
+       .address_list   = normal_i2c,
 };
 
 /*
@@ -257,7 +268,7 @@ struct fschmd_data {
        struct list_head list; /* member of the watchdog_data_list */
        struct kref kref;
        struct miscdevice watchdog_miscdev;
-       int kind;
+       enum chips kind;
        unsigned long watchdog_is_open;
        char watchdog_expect_close;
        char watchdog_name[10]; /* must be unique to avoid sysfs conflict */
@@ -315,8 +326,7 @@ static ssize_t show_in_value(struct device *dev,
        int index = to_sensor_dev_attr(devattr)->index;
        struct fschmd_data *data = fschmd_update_device(dev);
 
-       /* fscher / fschrc - 1 as data->kind is an array index, not a chips */
-       if (data->kind == (fscher - 1) || data->kind >= (fschrc - 1))
+       if (data->kind == fscher || data->kind >= fschrc)
                return sprintf(buf, "%d\n", (data->volt[index] * dmi_vref *
                        dmi_mult[index]) / 255 + dmi_offset[index]);
        else
@@ -482,7 +492,7 @@ static ssize_t show_pwm_auto_point1_pwm(struct device *dev,
        int val = data->fan_min[index];
 
        /* 0 = allow turning off (except on the syl), 1-255 = 50-100% */
-       if (val || data->kind == fscsyl - 1)
+       if (val || data->kind == fscsyl)
                val = val / 2 + 128;
 
        return sprintf(buf, "%d\n", val);
@@ -496,7 +506,7 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
        unsigned long v = simple_strtoul(buf, NULL, 10);
 
        /* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
-       if (v || data->kind == fscsyl - 1) {
+       if (v || data->kind == fscsyl) {
                v = SENSORS_LIMIT(v, 128, 255);
                v = (v - 128) * 2 + 1;
        }
@@ -758,6 +768,7 @@ leave:
 static int watchdog_open(struct inode *inode, struct file *filp)
 {
        struct fschmd_data *pos, *data = NULL;
+       int watchdog_is_open;
 
        /* We get called from drivers/char/misc.c with misc_mtx hold, and we
           call misc_register() from fschmd_probe() with watchdog_data_mutex
@@ -772,10 +783,12 @@ static int watchdog_open(struct inode *inode, struct file *filp)
                }
        }
        /* Note we can never not have found data, so we don't check for this */
-       kref_get(&data->kref);
+       watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open);
+       if (!watchdog_is_open)
+               kref_get(&data->kref);
        mutex_unlock(&watchdog_data_mutex);
 
-       if (test_and_set_bit(0, &data->watchdog_is_open))
+       if (watchdog_is_open)
                return -EBUSY;
 
        /* Start the watchdog */
@@ -810,7 +823,7 @@ static int watchdog_release(struct inode *inode, struct file *filp)
 static ssize_t watchdog_write(struct file *filp, const char __user *buf,
        size_t count, loff_t *offset)
 {
-       size_t ret;
+       int ret;
        struct fschmd_data *data = filp->private_data;
 
        if (count) {
@@ -835,8 +848,7 @@ static ssize_t watchdog_write(struct file *filp, const char __user *buf,
        return count;
 }
 
-static int watchdog_ioctl(struct inode *inode, struct file *filp,
-       unsigned int cmd, unsigned long arg)
+static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        static struct watchdog_info ident = {
                .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
@@ -846,6 +858,7 @@ static int watchdog_ioctl(struct inode *inode, struct file *filp,
        int i, ret = 0;
        struct fschmd_data *data = filp->private_data;
 
+       lock_kernel();
        switch (cmd) {
        case WDIOC_GETSUPPORT:
                ident.firmware_version = data->revision;
@@ -902,17 +915,17 @@ static int watchdog_ioctl(struct inode *inode, struct file *filp,
        default:
                ret = -ENOTTY;
        }
-
+       unlock_kernel();
        return ret;
 }
 
-static struct file_operations watchdog_fops = {
+static const struct file_operations watchdog_fops = {
        .owner = THIS_MODULE,
        .llseek = no_llseek,
        .open = watchdog_open,
        .release = watchdog_release,
        .write = watchdog_write,
-       .ioctl = watchdog_ioctl,
+       .unlocked_ioctl = watchdog_ioctl,
 };
 
 
@@ -991,43 +1004,40 @@ static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy)
        }
 }
 
-static int fschmd_detect(struct i2c_client *client, int kind,
+static int fschmd_detect(struct i2c_client *client,
                         struct i2c_board_info *info)
 {
+       enum chips kind;
        struct i2c_adapter *adapter = client->adapter;
+       char id[4];
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
        /* Detect & Identify the chip */
-       if (kind <= 0) {
-               char id[4];
-
-               id[0] = i2c_smbus_read_byte_data(client,
-                               FSCHMD_REG_IDENT_0);
-               id[1] = i2c_smbus_read_byte_data(client,
-                               FSCHMD_REG_IDENT_1);
-               id[2] = i2c_smbus_read_byte_data(client,
-                               FSCHMD_REG_IDENT_2);
-               id[3] = '\0';
-
-               if (!strcmp(id, "PEG"))
-                       kind = fscpos;
-               else if (!strcmp(id, "HER"))
-                       kind = fscher;
-               else if (!strcmp(id, "SCY"))
-                       kind = fscscy;
-               else if (!strcmp(id, "HRC"))
-                       kind = fschrc;
-               else if (!strcmp(id, "HMD"))
-                       kind = fschmd;
-               else if (!strcmp(id, "SYL"))
-                       kind = fscsyl;
-               else
-                       return -ENODEV;
-       }
+       id[0] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_0);
+       id[1] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_1);
+       id[2] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_2);
+       id[3] = '\0';
+
+       if (!strcmp(id, "PEG"))
+               kind = fscpos;
+       else if (!strcmp(id, "HER"))
+               kind = fscher;
+       else if (!strcmp(id, "SCY"))
+               kind = fscscy;
+       else if (!strcmp(id, "HRC"))
+               kind = fschrc;
+       else if (!strcmp(id, "HMD"))
+               kind = fschmd;
+       else if (!strcmp(id, "HDS"))
+               kind = fschds;
+       else if (!strcmp(id, "SYL"))
+               kind = fscsyl;
+       else
+               return -ENODEV;
 
-       strlcpy(info->type, fschmd_id[kind - 1].name, I2C_NAME_SIZE);
+       strlcpy(info->type, fschmd_id[kind].name, I2C_NAME_SIZE);
 
        return 0;
 }
@@ -1036,8 +1046,8 @@ static int fschmd_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct fschmd_data *data;
-       const char * const names[6] = { "Poseidon", "Hermes", "Scylla",
-                                       "Heracles", "Heimdall", "Syleus" };
+       const char * const names[7] = { "Poseidon", "Hermes", "Scylla",
+                               "Heracles", "Heimdall", "Hades", "Syleus" };
        const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
        int i, err;
        enum chips kind = id->driver_data;
@@ -1055,6 +1065,7 @@ static int fschmd_probe(struct i2c_client *client,
           (where the client is found through a data ptr instead of the
           otherway around) */
        data->client = client;
+       data->kind = kind;
 
        if (kind == fscpos) {
                /* The Poseidon has hardwired temp limits, fill these
@@ -1075,9 +1086,6 @@ static int fschmd_probe(struct i2c_client *client,
                }
        }
 
-       /* i2c kind goes from 1-6, we want from 0-5 to address arrays */
-       data->kind = kind - 1;
-
        /* Read in some never changing registers */
        data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
        data->global_control = i2c_smbus_read_byte_data(client,
@@ -1320,8 +1328,8 @@ static void __exit fschmd_exit(void)
 }
 
 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
-MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall and "
-                       "Syleus driver");
+MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall, Hades "
+                       "and Syleus driver");
 MODULE_LICENSE("GPL");
 
 module_init(fschmd_init);