]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/hwmon/w83791d.c
udf: add llseek method
[linux-2.6-omap-h63xx.git] / drivers / hwmon / w83791d.c
index eec43abd57fb1e59801d311c95357efac86b2265..daa7d121483bdd042c4396ec62e903e6a9b46cb8 100644 (file)
@@ -2,7 +2,7 @@
     w83791d.c - Part of lm_sensors, Linux kernel modules for hardware
                 monitoring
 
-    Copyright (C) 2006 Charles Spirakis <bezaur@gmail.com>
+    Copyright (C) 2006-2007 Charles Spirakis <bezaur@gmail.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 
     The w83791d chip appears to be part way between the 83781d and the
     83792d. Thus, this file is derived from both the w83792d.c and
-    w83781d.c files, but its output is more along the lines of the
-    83781d (which means there are no changes to the user-mode sensors
-    program which treats the 83791d as an 83781d).
+    w83781d.c files.
+
+    The w83791g chip is the same as the w83791d but lead-free.
 */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -48,7 +47,8 @@
 #define NUMBER_OF_TEMPIN       3
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
+                                               I2C_CLIENT_END };
 
 /* Insmod parameters */
 I2C_CLIENT_INSMOD_1(w83791d);
@@ -233,11 +233,9 @@ static u8 fan_to_reg(long rpm, int div)
 static u8 div_to_reg(int nr, long val)
 {
        int i;
-       int max;
 
-       /* first three fan's divisor max out at 8, rest max out at 128 */
-       max = (nr < 3) ? 8 : 128;
-       val = SENSORS_LIMIT(val, 1, max) >> 1;
+       /* fan divisors max out at 128 */
+       val = SENSORS_LIMIT(val, 1, 128) >> 1;
        for (i = 0; i < 7; i++) {
                if (val == 0)
                        break;
@@ -247,8 +245,7 @@ static u8 div_to_reg(int nr, long val)
 }
 
 struct w83791d_data {
-       struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
 
        char valid;                     /* !=0 if following fields are valid */
@@ -286,9 +283,11 @@ struct w83791d_data {
        u8 vrm;                 /* hwmon-vid */
 };
 
-static int w83791d_attach_adapter(struct i2c_adapter *adapter);
-static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind);
-static int w83791d_detach_client(struct i2c_client *client);
+static int w83791d_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id);
+static int w83791d_detect(struct i2c_client *client, int kind,
+                         struct i2c_board_info *info);
+static int w83791d_remove(struct i2c_client *client);
 
 static int w83791d_read(struct i2c_client *client, u8 register);
 static int w83791d_write(struct i2c_client *client, u8 register, u8 value);
@@ -300,12 +299,22 @@ static void w83791d_print_debug(struct w83791d_data *data, struct device *dev);
 
 static void w83791d_init_client(struct i2c_client *client);
 
+static const struct i2c_device_id w83791d_id[] = {
+       { "w83791d", w83791d },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, w83791d_id);
+
 static struct i2c_driver w83791d_driver = {
+       .class          = I2C_CLASS_HWMON,
        .driver = {
                .name = "w83791d",
        },
-       .attach_adapter = w83791d_attach_adapter,
-       .detach_client = w83791d_detach_client,
+       .probe          = w83791d_probe,
+       .remove         = w83791d_remove,
+       .id_table       = w83791d_id,
+       .detect         = w83791d_detect,
+       .address_data   = &addr_data,
 };
 
 /* following are the sysfs callback functions */
@@ -385,6 +394,85 @@ static struct sensor_device_attribute sda_in_max[] = {
        SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
 };
 
+
+static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct sensor_device_attribute *sensor_attr =
+                                               to_sensor_dev_attr(attr);
+       struct w83791d_data *data = w83791d_update_device(dev);
+       int bitnr = sensor_attr->index;
+
+       return sprintf(buf, "%d\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 sensor_device_attribute *sensor_attr =
+                                               to_sensor_dev_attr(attr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83791d_data *data = i2c_get_clientdata(client);
+       int bitnr = sensor_attr->index;
+       int bytenr = bitnr / 8;
+       long val = simple_strtol(buf, NULL, 10) ? 1 : 0;
+
+       mutex_lock(&data->update_lock);
+
+       data->beep_mask &= ~(0xff << (bytenr * 8));
+       data->beep_mask |= w83791d_read(client, W83791D_REG_BEEP_CTRL[bytenr])
+               << (bytenr * 8);
+
+       data->beep_mask &= ~(1 << bitnr);
+       data->beep_mask |= val << bitnr;
+
+       w83791d_write(client, W83791D_REG_BEEP_CTRL[bytenr],
+               (data->beep_mask >> (bytenr * 8)) & 0xff);
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct sensor_device_attribute *sensor_attr =
+                                               to_sensor_dev_attr(attr);
+       struct w83791d_data *data = w83791d_update_device(dev);
+       int bitnr = sensor_attr->index;
+
+       return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
+/* Note: The bitmask for the beep enable/disable is different than
+   the bitmask for the alarm. */
+static struct sensor_device_attribute sda_in_beep[] = {
+       SENSOR_ATTR(in0_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 0),
+       SENSOR_ATTR(in1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 13),
+       SENSOR_ATTR(in2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 2),
+       SENSOR_ATTR(in3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 3),
+       SENSOR_ATTR(in4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 8),
+       SENSOR_ATTR(in5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 9),
+       SENSOR_ATTR(in6_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 10),
+       SENSOR_ATTR(in7_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 16),
+       SENSOR_ATTR(in8_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 17),
+       SENSOR_ATTR(in9_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 14),
+};
+
+static struct sensor_device_attribute sda_in_alarm[] = {
+       SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
+       SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
+       SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
+       SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
+       SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
+       SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9),
+       SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10),
+       SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19),
+       SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20),
+       SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 14),
+};
+
 #define show_fan_reg(reg) \
 static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
                                char *buf) \
@@ -440,6 +528,7 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr,
        unsigned long min;
        u8 tmp_fan_div;
        u8 fan_div_reg;
+       u8 vbat_reg;
        int indx = 0;
        u8 keep_mask = 0;
        u8 new_shift = 0;
@@ -491,6 +580,16 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr,
        w83791d_write(client, W83791D_REG_FAN_DIV[indx],
                                fan_div_reg | tmp_fan_div);
 
+       /* Bit 2 of fans 0-2 is stored in the vbat register (bits 5-7) */
+       if (nr < 3) {
+               keep_mask = ~(1 << (nr + 5));
+               vbat_reg = w83791d_read(client, W83791D_REG_VBAT)
+                               & keep_mask;
+               tmp_fan_div = (data->fan_div[nr] << (3 + nr)) & ~keep_mask;
+               w83791d_write(client, W83791D_REG_VBAT,
+                               vbat_reg | tmp_fan_div);
+       }
+
        /* Restore fan_min */
        data->fan_min[nr] = fan_to_reg(min, DIV_FROM_REG(data->fan_div[nr]));
        w83791d_write(client, W83791D_REG_FAN_MIN[nr], data->fan_min[nr]);
@@ -537,6 +636,22 @@ static struct sensor_device_attribute sda_fan_div[] = {
                        show_fan_div, store_fan_div, 4),
 };
 
+static struct sensor_device_attribute sda_fan_beep[] = {
+       SENSOR_ATTR(fan1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 6),
+       SENSOR_ATTR(fan2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 7),
+       SENSOR_ATTR(fan3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 11),
+       SENSOR_ATTR(fan4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 21),
+       SENSOR_ATTR(fan5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 22),
+};
+
+static struct sensor_device_attribute sda_fan_alarm[] = {
+       SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
+       SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
+       SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
+       SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21),
+       SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22),
+};
+
 /* read/write the temperature1, includes measured value and limits */
 static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr,
                                char *buf)
@@ -619,6 +734,19 @@ static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
                        show_temp23, store_temp23, 1, 2),
 };
 
+/* Note: The bitmask for the beep enable/disable is different than
+   the bitmask for the alarm. */
+static struct sensor_device_attribute sda_temp_beep[] = {
+       SENSOR_ATTR(temp1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 4),
+       SENSOR_ATTR(temp2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 5),
+       SENSOR_ATTR(temp3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 1),
+};
+
+static struct sensor_device_attribute sda_temp_alarm[] = {
+       SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
+       SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
+       SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
+};
 
 /* get reatime status of all sensors items: voltage, temp, fan */
 static ssize_t show_alarms_reg(struct device *dev,
@@ -725,7 +853,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
 static ssize_t show_vrm_reg(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct w83791d_data *data = w83791d_update_device(dev);
+       struct w83791d_data *data = dev_get_drvdata(dev);
        return sprintf(buf, "%d\n", data->vrm);
 }
 
@@ -733,63 +861,76 @@ static ssize_t store_vrm_reg(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct w83791d_data *data = i2c_get_clientdata(client);
-       unsigned long val = simple_strtoul(buf, NULL, 10);
+       struct w83791d_data *data = dev_get_drvdata(dev);
 
        /* No lock needed as vrm is internal to the driver
           (not read from a chip register) and so is not
           updated in w83791d_update_device() */
-       data->vrm = val;
+       data->vrm = simple_strtoul(buf, NULL, 10);
 
        return count;
 }
 
 static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
 
-/* This function is called when:
-     * w83791d_driver is inserted (when this module is loaded), for each
-       available adapter
-     * when a new adapter is inserted (and w83791d_driver is still present) */
-static int w83791d_attach_adapter(struct i2c_adapter *adapter)
-{
-       if (!(adapter->class & I2C_CLASS_HWMON))
-               return 0;
-       return i2c_probe(adapter, &addr_data, w83791d_detect);
-}
-
-
-static int w83791d_create_subclient(struct i2c_adapter *adapter,
-                               struct i2c_client *client, int addr,
-                               struct i2c_client **sub_cli)
-{
-       int err;
-       struct i2c_client *sub_client;
+#define IN_UNIT_ATTRS(X) \
+       &sda_in_input[X].dev_attr.attr, \
+       &sda_in_min[X].dev_attr.attr,   \
+       &sda_in_max[X].dev_attr.attr,   \
+       &sda_in_beep[X].dev_attr.attr,  \
+       &sda_in_alarm[X].dev_attr.attr
+
+#define FAN_UNIT_ATTRS(X) \
+       &sda_fan_input[X].dev_attr.attr,        \
+       &sda_fan_min[X].dev_attr.attr,          \
+       &sda_fan_div[X].dev_attr.attr,          \
+       &sda_fan_beep[X].dev_attr.attr,         \
+       &sda_fan_alarm[X].dev_attr.attr
+
+#define TEMP_UNIT_ATTRS(X) \
+       &sda_temp_input[X].dev_attr.attr,       \
+       &sda_temp_max[X].dev_attr.attr,         \
+       &sda_temp_max_hyst[X].dev_attr.attr,    \
+       &sda_temp_beep[X].dev_attr.attr,        \
+       &sda_temp_alarm[X].dev_attr.attr
+
+static struct attribute *w83791d_attributes[] = {
+       IN_UNIT_ATTRS(0),
+       IN_UNIT_ATTRS(1),
+       IN_UNIT_ATTRS(2),
+       IN_UNIT_ATTRS(3),
+       IN_UNIT_ATTRS(4),
+       IN_UNIT_ATTRS(5),
+       IN_UNIT_ATTRS(6),
+       IN_UNIT_ATTRS(7),
+       IN_UNIT_ATTRS(8),
+       IN_UNIT_ATTRS(9),
+       FAN_UNIT_ATTRS(0),
+       FAN_UNIT_ATTRS(1),
+       FAN_UNIT_ATTRS(2),
+       FAN_UNIT_ATTRS(3),
+       FAN_UNIT_ATTRS(4),
+       TEMP_UNIT_ATTRS(0),
+       TEMP_UNIT_ATTRS(1),
+       TEMP_UNIT_ATTRS(2),
+       &dev_attr_alarms.attr,
+       &sda_beep_ctrl[0].dev_attr.attr,
+       &sda_beep_ctrl[1].dev_attr.attr,
+       &dev_attr_cpu0_vid.attr,
+       &dev_attr_vrm.attr,
+       NULL
+};
 
-       (*sub_cli) = sub_client =
-                       kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (!(sub_client)) {
-               return -ENOMEM;
-       }
-       sub_client->addr = 0x48 + addr;
-       i2c_set_clientdata(sub_client, NULL);
-       sub_client->adapter = adapter;
-       sub_client->driver = &w83791d_driver;
-       strlcpy(sub_client->name, "w83791d subclient", I2C_NAME_SIZE);
-       if ((err = i2c_attach_client(sub_client))) {
-               dev_err(&client->dev, "subclient registration "
-                       "at address 0x%x failed\n", sub_client->addr);
-               kfree(sub_client);
-               return err;
-       }
-       return 0;
-}
+static const struct attribute_group w83791d_group = {
+       .attrs = w83791d_attributes,
+};
 
 
-static int w83791d_detect_subclients(struct i2c_adapter *adapter, int address,
-                               int kind, struct i2c_client *client)
+static int w83791d_detect_subclients(struct i2c_client *client)
 {
+       struct i2c_adapter *adapter = client->adapter;
        struct w83791d_data *data = i2c_get_clientdata(client);
+       int address = client->addr;
        int i, id, err;
        u8 val;
 
@@ -813,10 +954,7 @@ static int w83791d_detect_subclients(struct i2c_adapter *adapter, int address,
 
        val = w83791d_read(client, W83791D_REG_I2C_SUBADDR);
        if (!(val & 0x08)) {
-               err = w83791d_create_subclient(adapter, client,
-                                               val & 0x7, &data->lm75[0]);
-               if (err < 0)
-                       goto error_sc_0;
+               data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7));
        }
        if (!(val & 0x80)) {
                if ((data->lm75[0] != NULL) &&
@@ -828,10 +966,8 @@ static int w83791d_detect_subclients(struct i2c_adapter *adapter, int address,
                        err = -ENODEV;
                        goto error_sc_1;
                }
-               err = w83791d_create_subclient(adapter, client,
-                                       (val >> 4) & 0x7, &data->lm75[1]);
-               if (err < 0)
-                       goto error_sc_1;
+               data->lm75[1] = i2c_new_dummy(adapter,
+                                             0x48 + ((val >> 4) & 0x7));
        }
 
        return 0;
@@ -839,53 +975,31 @@ static int w83791d_detect_subclients(struct i2c_adapter *adapter, int address,
 /* Undo inits in case of errors */
 
 error_sc_1:
-       if (data->lm75[0] != NULL) {
-               i2c_detach_client(data->lm75[0]);
-               kfree(data->lm75[0]);
-       }
+       if (data->lm75[0] != NULL)
+               i2c_unregister_device(data->lm75[0]);
 error_sc_0:
        return err;
 }
 
 
-static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int w83791d_detect(struct i2c_client *client, int kind,
+                         struct i2c_board_info *info)
 {
-       struct i2c_client *client;
-       struct device *dev;
-       struct w83791d_data *data;
-       int i, val1, val2;
-       int err = 0;
-       const char *client_name = "";
+       struct i2c_adapter *adapter = client->adapter;
+       int val1, val2;
+       unsigned short address = client->addr;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-               goto error0;
+               return -ENODEV;
        }
 
-       /* OK. For now, we presume we have a valid client. We now create the
-          client structure, even though we cannot fill it completely yet.
-          But it allows us to access w83791d_{read,write}_value. */
-       if (!(data = kzalloc(sizeof(struct w83791d_data), GFP_KERNEL))) {
-               err = -ENOMEM;
-               goto error0;
-       }
-
-       client = &data->client;
-       dev = &client->dev;
-       i2c_set_clientdata(client, data);
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &w83791d_driver;
-       mutex_init(&data->update_lock);
-
-       /* Now, we do the remaining detection. */
-
        /* The w83791d may be stuck in some other bank than bank 0. This may
           make reading other information impossible. Specify a force=...
           parameter, and the Winbond will be reset to the right bank. */
        if (kind < 0) {
                if (w83791d_read(client, W83791D_REG_CONFIG) & 0x80) {
-                       dev_dbg(dev, "Detection failed at step 1\n");
-                       goto error1;
+                       return -ENODEV;
                }
                val1 = w83791d_read(client, W83791D_REG_BANK);
                val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
@@ -894,15 +1008,13 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
                        /* yes it is Bank0 */
                        if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
                            ((val1 & 0x80) && (val2 != 0x5c))) {
-                               dev_dbg(dev, "Detection failed at step 2\n");
-                               goto error1;
+                               return -ENODEV;
                        }
                }
                /* If Winbond chip, address of chip and W83791D_REG_I2C_ADDR
                   should match */
                if (w83791d_read(client, W83791D_REG_I2C_ADDR) != address) {
-                       dev_dbg(dev, "Detection failed at step 3\n");
-                       goto error1;
+                       return -ENODEV;
                }
        }
 
@@ -917,30 +1029,33 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
                /* get vendor ID */
                val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
                if (val2 != 0x5c) {     /* the vendor is NOT Winbond */
-                       dev_dbg(dev, "Detection failed at step 4\n");
-                       goto error1;
+                       return -ENODEV;
                }
                val1 = w83791d_read(client, W83791D_REG_WCHIPID);
                if (val1 == 0x71) {
                        kind = w83791d;
                } else {
                        if (kind == 0)
-                               dev_warn(dev,
+                               dev_warn(&adapter->dev,
                                        "w83791d: Ignoring 'force' parameter "
                                        "for unknown chip at adapter %d, "
                                        "address 0x%02x\n",
                                        i2c_adapter_id(adapter), address);
-                       goto error1;
+                       return -ENODEV;
                }
        }
 
-       if (kind == w83791d) {
-               client_name = "w83791d";
-       } else {
-               dev_err(dev, "w83791d: Internal error: unknown kind (%d)?!?",
-                       kind);
-               goto error1;
-       }
+       strlcpy(info->type, "w83791d", I2C_NAME_SIZE);
+
+       return 0;
+}
+
+static int w83791d_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct w83791d_data *data;
+       struct device *dev = &client->dev;
+       int i, val1, err;
 
 #ifdef DEBUG
        val1 = w83791d_read(client, W83791D_REG_DID_VID4);
@@ -948,15 +1063,18 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
                        (val1 >> 5) & 0x07, (val1 >> 1) & 0x0f, val1);
 #endif
 
-       /* Fill in the remaining client fields and put into the global list */
-       strlcpy(client->name, client_name, I2C_NAME_SIZE);
+       data = kzalloc(sizeof(struct w83791d_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto error0;
+       }
 
-       /* Tell the I2C layer a new client has arrived */
-       if ((err = i2c_attach_client(client)))
-               goto error1;
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
 
-       if ((err = w83791d_detect_subclients(adapter, address, kind, client)))
-               goto error2;
+       err = w83791d_detect_subclients(client);
+       if (err)
+               goto error1;
 
        /* Initialize the chip */
        w83791d_init_client(client);
@@ -968,77 +1086,44 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
        }
 
        /* Register sysfs hooks */
-       data->class_dev = hwmon_device_register(dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       if ((err = sysfs_create_group(&client->dev.kobj, &w83791d_group)))
                goto error3;
-       }
-
-       for (i = 0; i < NUMBER_OF_VIN; i++) {
-               device_create_file(dev, &sda_in_input[i].dev_attr);
-               device_create_file(dev, &sda_in_min[i].dev_attr);
-               device_create_file(dev, &sda_in_max[i].dev_attr);
-       }
 
-       for (i = 0; i < NUMBER_OF_FANIN; i++) {
-               device_create_file(dev, &sda_fan_input[i].dev_attr);
-               device_create_file(dev, &sda_fan_div[i].dev_attr);
-               device_create_file(dev, &sda_fan_min[i].dev_attr);
-       }
-
-       for (i = 0; i < NUMBER_OF_TEMPIN; i++) {
-               device_create_file(dev, &sda_temp_input[i].dev_attr);
-               device_create_file(dev, &sda_temp_max[i].dev_attr);
-               device_create_file(dev, &sda_temp_max_hyst[i].dev_attr);
-       }
-
-       device_create_file(dev, &dev_attr_alarms);
-
-       for (i = 0; i < ARRAY_SIZE(sda_beep_ctrl); i++) {
-               device_create_file(dev, &sda_beep_ctrl[i].dev_attr);
+       /* Everything is ready, now register the working device */
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto error4;
        }
 
-       device_create_file(dev, &dev_attr_cpu0_vid);
-       device_create_file(dev, &dev_attr_vrm);
-
        return 0;
 
+error4:
+       sysfs_remove_group(&client->dev.kobj, &w83791d_group);
 error3:
-       if (data->lm75[0] != NULL) {
-               i2c_detach_client(data->lm75[0]);
-               kfree(data->lm75[0]);
-       }
-       if (data->lm75[1] != NULL) {
-               i2c_detach_client(data->lm75[1]);
-               kfree(data->lm75[1]);
-       }
-error2:
-       i2c_detach_client(client);
+       if (data->lm75[0] != NULL)
+               i2c_unregister_device(data->lm75[0]);
+       if (data->lm75[1] != NULL)
+               i2c_unregister_device(data->lm75[1]);
 error1:
        kfree(data);
 error0:
        return err;
 }
 
-static int w83791d_detach_client(struct i2c_client *client)
+static int w83791d_remove(struct i2c_client *client)
 {
        struct w83791d_data *data = i2c_get_clientdata(client);
-       int err;
 
-       /* main client */
-       if (data)
-               hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &w83791d_group);
 
-       if ((err = i2c_detach_client(client)))
-               return err;
-
-       /* main client */
-       if (data)
-               kfree(data);
-       /* subclient */
-       else
-               kfree(client);
+       if (data->lm75[0] != NULL)
+               i2c_unregister_device(data->lm75[0]);
+       if (data->lm75[1] != NULL)
+               i2c_unregister_device(data->lm75[1]);
 
+       kfree(data);
        return 0;
 }
 
@@ -1106,6 +1191,7 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
        struct w83791d_data *data = i2c_get_clientdata(client);
        int i, j;
        u8 reg_array_tmp[3];
+       u8 vbat_reg;
 
        mutex_lock(&data->update_lock);
 
@@ -1143,6 +1229,12 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
                data->fan_div[3] = reg_array_tmp[2] & 0x07;
                data->fan_div[4] = (reg_array_tmp[2] >> 4) & 0x07;
 
+               /* The fan divisor for fans 0-2 get bit 2 from
+                  bits 5-7 respectively of vbat register */
+               vbat_reg = w83791d_read(client, W83791D_REG_VBAT);
+               for (i = 0; i < 3; i++)
+                       data->fan_div[i] |= (vbat_reg >> (3 + i)) & 0x04;
+
                /* Update the first temperature sensor */
                for (i = 0; i < 3; i++) {
                        data->temp1[i] = w83791d_read(client,
@@ -1172,6 +1264,7 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
                        (w83791d_read(client, W83791D_REG_BEEP_CTRL[1]) << 8) +
                        (w83791d_read(client, W83791D_REG_BEEP_CTRL[2]) << 16);
 
+               /* Extract global beep enable flag */
                data->beep_enable =
                        (data->beep_mask >> GLOBAL_BEEP_ENABLE_SHIFT) & 0x01;