Merge ../linux-2.6-watchdog-mm
[linux-drm-fsl-dcu.git] / drivers / hwmon / smsc47m1.c
index 9cd28f2709fce5ddb2f0fe3d479013d1e5690f4f..beb881c4b2e8ce1f2c191f6ce2343655a0e57200 100644 (file)
@@ -2,8 +2,8 @@
     smsc47m1.c - Part of lm_sensors, Linux kernel modules
                  for hardware monitoring
 
-    Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x,
-    LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips.
+    Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x,
+    LPC47M14x, LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips.
 
     Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
     Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
@@ -35,6 +35,7 @@
 #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 */
@@ -347,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;
@@ -355,8 +380,8 @@ static int __init smsc47m1_find(unsigned short *addr)
        val = superio_inb(SUPERIO_REG_DEVID);
 
        /*
-        * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id
-        * 0x5F) and LPC47B27x (device id 0x51) have fan control.
+        * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x
+        * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control.
         * The LPC47M15x and LPC47M192 chips "with hardware monitoring block"
         * can do much more besides (device id 0x60).
         * The LPC47M997 is undocumented, but seems to be compatible with
@@ -365,7 +390,8 @@ static int __init smsc47m1_find(unsigned short *addr)
        if (val == 0x51)
                printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n");
        else if (val == 0x59)
-               printk(KERN_INFO "smsc47m1: Found SMSC LPC47M10x/LPC47M13x\n");
+               printk(KERN_INFO "smsc47m1: Found SMSC "
+                      "LPC47M10x/LPC47M112/LPC47M13x\n");
        else if (val == 0x5F)
                printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n");
        else if (val == 0x60)
@@ -447,46 +473,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);
@@ -501,6 +543,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;