Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee13...
[pandora-kernel.git] / drivers / hwmon / smsc47m1.c
index 5905c1a..47132fd 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/hwmon.h>
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
 #include <asm/io.h>
 
 /* Address is autodetected, there is no default value */
@@ -102,9 +104,9 @@ superio_exit(void)
 struct smsc47m1_data {
        struct i2c_client client;
        struct class_device *class_dev;
-       struct semaphore lock;
+       struct mutex lock;
 
-       struct semaphore update_lock;
+       struct mutex update_lock;
        unsigned long last_updated;     /* In jiffies */
 
        u8 fan[2];              /* Register value */
@@ -126,8 +128,10 @@ static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
 
 
 static struct i2c_driver smsc47m1_driver = {
-       .owner          = THIS_MODULE,
-       .name           = "smsc47m1",
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "smsc47m1",
+       },
        .attach_adapter = smsc47m1_detect,
        .detach_client  = smsc47m1_detach_client,
 };
@@ -187,25 +191,25 @@ static ssize_t set_fan_min(struct device *dev, const char *buf,
        struct smsc47m1_data *data = i2c_get_clientdata(client);
        long rpmdiv, val = simple_strtol(buf, NULL, 10);
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
        rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]);
 
        if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) {
-               up(&data->update_lock);
+               mutex_unlock(&data->update_lock);
                return -EINVAL;
        }
 
        data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv);
        smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr),
                             data->fan_preload[nr]);
-       up(&data->update_lock);
+       mutex_unlock(&data->update_lock);
 
        return count;
 }
 
 /* Note: we save and restore the fan minimum here, because its value is
    determined in part by the fan clock divider.  This follows the principle
-   of least suprise; the user doesn't expect the fan minimum to change just
+   of least surprise; the user doesn't expect the fan minimum to change just
    because the divider changed. */
 static ssize_t set_fan_div(struct device *dev, const char *buf,
                size_t count, int nr)
@@ -219,14 +223,14 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
        if (new_div == old_div) /* No change */
                return count;
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
        switch (new_div) {
        case 1: data->fan_div[nr] = 0; break;
        case 2: data->fan_div[nr] = 1; break;
        case 4: data->fan_div[nr] = 2; break;
        case 8: data->fan_div[nr] = 3; break;
        default:
-               up(&data->update_lock);
+               mutex_unlock(&data->update_lock);
                return -EINVAL;
        }
 
@@ -240,7 +244,7 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
        data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191);
        smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr),
                             data->fan_preload[nr]);
-       up(&data->update_lock);
+       mutex_unlock(&data->update_lock);
 
        return count;
 }
@@ -256,12 +260,12 @@ static ssize_t set_pwm(struct device *dev, const char *buf,
        if (val < 0 || val > 255)
                return -EINVAL;
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
        data->pwm[nr] &= 0x81; /* Preserve additional bits */
        data->pwm[nr] |= PWM_TO_REG(val);
        smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
                             data->pwm[nr]);
-       up(&data->update_lock);
+       mutex_unlock(&data->update_lock);
 
        return count;
 }
@@ -277,12 +281,12 @@ static ssize_t set_pwm_en(struct device *dev, const char *buf,
        if (val != 0 && val != 1)
                return -EINVAL;
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
        data->pwm[nr] &= 0xFE; /* preserve the other bits */
        data->pwm[nr] |= !val;
        smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
                             data->pwm[nr]);
-       up(&data->update_lock);
+       mutex_unlock(&data->update_lock);
 
        return count;
 }
@@ -344,6 +348,30 @@ fan_present(2);
 
 static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
 
+/* Almost all sysfs files may or may not be created depending on the chip
+   setup so we create them individually. It is still convenient to define a
+   group to remove them all at once. */
+static struct attribute *smsc47m1_attributes[] = {
+       &dev_attr_fan1_input.attr,
+       &dev_attr_fan1_min.attr,
+       &dev_attr_fan1_div.attr,
+       &dev_attr_fan2_input.attr,
+       &dev_attr_fan2_min.attr,
+       &dev_attr_fan2_div.attr,
+
+       &dev_attr_pwm1.attr,
+       &dev_attr_pwm1_enable.attr,
+       &dev_attr_pwm2.attr,
+       &dev_attr_pwm2_enable.attr,
+
+       &dev_attr_alarms.attr,
+       NULL
+};
+
+static const struct attribute_group smsc47m1_group = {
+       .attrs = smsc47m1_attributes,
+};
+
 static int __init smsc47m1_find(unsigned short *addr)
 {
        u8 val;
@@ -394,7 +422,7 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
        int err = 0;
        int fan1, fan2, pwm1, pwm2;
 
-       if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.name)) {
+       if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.driver.name)) {
                dev_err(&adapter->dev, "Region 0x%x already in use!\n", address);
                return -EBUSY;
        }
@@ -407,13 +435,13 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
        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 = &smsc47m1_driver;
        new_client->flags = 0;
 
        strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE);
-       init_MUTEX(&data->update_lock);
+       mutex_init(&data->update_lock);
 
        /* If no function is properly configured, there's no point in
           actually registering the chip. */
@@ -426,7 +454,8 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
        pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05)
               == 0x04;
        if (!(fan1 || fan2 || pwm1 || pwm2)) {
-               dev_warn(&new_client->dev, "Device is not configured, will not use\n");
+               dev_warn(&adapter->dev, "Device at 0x%x is not configured, "
+                        "will not use\n", new_client->addr);
                err = -ENODEV;
                goto error_free;
        }
@@ -443,46 +472,62 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
        smsc47m1_update_device(&new_client->dev, 1);
 
        /* Register sysfs hooks */
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
-               goto error_detach;
-       }
-
        if (fan1) {
-               device_create_file(&new_client->dev, &dev_attr_fan1_input);
-               device_create_file(&new_client->dev, &dev_attr_fan1_min);
-               device_create_file(&new_client->dev, &dev_attr_fan1_div);
+               if ((err = device_create_file(&new_client->dev,
+                                             &dev_attr_fan1_input))
+                || (err = device_create_file(&new_client->dev,
+                                             &dev_attr_fan1_min))
+                || (err = device_create_file(&new_client->dev,
+                                             &dev_attr_fan1_div)))
+                       goto error_remove_files;
        } else
                dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, "
                        "skipping\n");
 
        if (fan2) {
-               device_create_file(&new_client->dev, &dev_attr_fan2_input);
-               device_create_file(&new_client->dev, &dev_attr_fan2_min);
-               device_create_file(&new_client->dev, &dev_attr_fan2_div);
+               if ((err = device_create_file(&new_client->dev,
+                                             &dev_attr_fan2_input))
+                || (err = device_create_file(&new_client->dev,
+                                             &dev_attr_fan2_min))
+                || (err = device_create_file(&new_client->dev,
+                                             &dev_attr_fan2_div)))
+                       goto error_remove_files;
        } else
                dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, "
                        "skipping\n");
 
        if (pwm1) {
-               device_create_file(&new_client->dev, &dev_attr_pwm1);
-               device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
+               if ((err = device_create_file(&new_client->dev,
+                                             &dev_attr_pwm1))
+                || (err = device_create_file(&new_client->dev,
+                                             &dev_attr_pwm1_enable)))
+                       goto error_remove_files;
        } else
                dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, "
                        "skipping\n");
        if (pwm2) {
-               device_create_file(&new_client->dev, &dev_attr_pwm2);
-               device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
+               if ((err = device_create_file(&new_client->dev,
+                                             &dev_attr_pwm2))
+                || (err = device_create_file(&new_client->dev,
+                                             &dev_attr_pwm2_enable)))
+                       goto error_remove_files;
        } else
                dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, "
                        "skipping\n");
 
-       device_create_file(&new_client->dev, &dev_attr_alarms);
+       if ((err = device_create_file(&new_client->dev, &dev_attr_alarms)))
+               goto error_remove_files;
+
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto error_remove_files;
+       }
 
        return 0;
 
-error_detach:
+error_remove_files:
+       sysfs_remove_group(&new_client->dev.kobj, &smsc47m1_group);
        i2c_detach_client(new_client);
 error_free:
        kfree(data);
@@ -497,6 +542,7 @@ static int smsc47m1_detach_client(struct i2c_client *client)
        int err;
 
        hwmon_device_unregister(data->class_dev);
+       sysfs_remove_group(&client->dev.kobj, &smsc47m1_group);
 
        if ((err = i2c_detach_client(client)))
                return err;
@@ -511,17 +557,17 @@ static int smsc47m1_read_value(struct i2c_client *client, u8 reg)
 {
        int res;
 
-       down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
+       mutex_lock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
        res = inb_p(client->addr + reg);
-       up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
+       mutex_unlock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
        return res;
 }
 
 static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value)
 {
-       down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
+       mutex_lock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
        outb_p(value, client->addr + reg);
-       up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
+       mutex_unlock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
 }
 
 static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
@@ -530,7 +576,7 @@ static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
        struct i2c_client *client = to_i2c_client(dev);
        struct smsc47m1_data *data = i2c_get_clientdata(client);
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
 
        if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) {
                int i;
@@ -557,7 +603,7 @@ static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
                data->last_updated = jiffies;
        }
 
-       up(&data->update_lock);
+       mutex_unlock(&data->update_lock);
        return data;
 }