Linux 2.6.21-rc5
[powerpc.git] / drivers / hwmon / smsc47b397.c
index 251ac26..72b0e2d 100644 (file)
 #include <linux/ioport.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
 /* Address is autodetected, there is no default value */
-static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
-static struct i2c_force_data forces[] = {{NULL}};
-
-enum chips { any_chip, smsc47b397 };
-static struct i2c_address_data addr_data = {
-       .normal_i2c             = normal_i2c,
-       .normal_isa             = normal_isa,
-       .probe                  = normal_i2c,           /* cheat */
-       .ignore                 = normal_i2c,           /* cheat */
-       .forces                 = forces,
-};
+static unsigned short address;
 
 /* Super-I/0 registers and commands */
 
@@ -100,9 +92,10 @@ static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80};
 
 struct smsc47b397_data {
        struct i2c_client client;
-       struct semaphore lock;
+       struct class_device *class_dev;
+       struct mutex lock;
 
-       struct semaphore update_lock;
+       struct mutex update_lock;
        unsigned long last_updated; /* in jiffies */
        int valid;
 
@@ -116,10 +109,10 @@ static int smsc47b397_read_value(struct i2c_client *client, u8 reg)
        struct smsc47b397_data *data = i2c_get_clientdata(client);
        int res;
 
-       down(&data->lock);
+       mutex_lock(&data->lock);
        outb(reg, client->addr);
        res = inb_p(client->addr + 1);
-       up(&data->lock);
+       mutex_unlock(&data->lock);
        return res;
 }
 
@@ -129,7 +122,7 @@ static struct smsc47b397_data *smsc47b397_update_device(struct device *dev)
        struct smsc47b397_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) || !data->valid) {
                dev_dbg(&client->dev, "starting device update...\n");
@@ -152,7 +145,7 @@ static struct smsc47b397_data *smsc47b397_update_device(struct device *dev)
                dev_dbg(&client->dev, "... device update complete\n");
        }
 
-       up(&data->update_lock);
+       mutex_unlock(&data->update_lock);
 
        return data;
 }
@@ -183,9 +176,6 @@ sysfs_temp(2);
 sysfs_temp(3);
 sysfs_temp(4);
 
-#define device_create_file_temp(client, num) \
-       device_create_file(&client->dev, &dev_attr_temp##num##_input)
-
 /* FAN: 1 RPM/bit
    REG: count of 90kHz pulses / revolution */
 static int fan_from_reg(u16 reg)
@@ -212,106 +202,114 @@ sysfs_fan(2);
 sysfs_fan(3);
 sysfs_fan(4);
 
-#define device_create_file_fan(client, num) \
-       device_create_file(&client->dev, &dev_attr_fan##num##_input)
-
-static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind);
+static struct attribute *smsc47b397_attributes[] = {
+       &dev_attr_temp1_input.attr,
+       &dev_attr_temp2_input.attr,
+       &dev_attr_temp3_input.attr,
+       &dev_attr_temp4_input.attr,
+       &dev_attr_fan1_input.attr,
+       &dev_attr_fan2_input.attr,
+       &dev_attr_fan3_input.attr,
+       &dev_attr_fan4_input.attr,
+
+       NULL
+};
 
-static int smsc47b397_attach_adapter(struct i2c_adapter *adapter)
-{
-       if (!(adapter->class & I2C_CLASS_HWMON))
-               return 0;
-       return i2c_detect(adapter, &addr_data, smsc47b397_detect);
-}
+static const struct attribute_group smsc47b397_group = {
+       .attrs = smsc47b397_attributes,
+};
 
 static int smsc47b397_detach_client(struct i2c_client *client)
 {
+       struct smsc47b397_data *data = i2c_get_clientdata(client);
        int err;
 
-       if ((err = i2c_detach_client(client))) {
-               dev_err(&client->dev, "Client deregistration failed, "
-                       "client not detached.\n");
+       hwmon_device_unregister(data->class_dev);
+       sysfs_remove_group(&client->dev.kobj, &smsc47b397_group);
+
+       if ((err = i2c_detach_client(client)))
                return err;
-       }
 
        release_region(client->addr, SMSC_EXTENT);
-       kfree(i2c_get_clientdata(client));
+       kfree(data);
 
        return 0;
 }
 
+static int smsc47b397_detect(struct i2c_adapter *adapter);
+
 static struct i2c_driver smsc47b397_driver = {
-       .owner          = THIS_MODULE,
-       .name           = "smsc47b397",
-       .id             = I2C_DRIVERID_SMSC47B397,
-       .flags          = I2C_DF_NOTIFY,
-       .attach_adapter = smsc47b397_attach_adapter,
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "smsc47b397",
+       },
+       .attach_adapter = smsc47b397_detect,
        .detach_client  = smsc47b397_detach_client,
 };
 
-static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind)
+static int smsc47b397_detect(struct i2c_adapter *adapter)
 {
        struct i2c_client *new_client;
        struct smsc47b397_data *data;
        int err = 0;
 
-       if (!i2c_is_isa_adapter(adapter)) {
-               return 0;
-       }
-
-       if (!request_region(addr, SMSC_EXTENT, smsc47b397_driver.name)) {
-               dev_err(&adapter->dev, "Region 0x%x already in use!\n", addr);
+       if (!request_region(address, SMSC_EXTENT,
+                           smsc47b397_driver.driver.name)) {
+               dev_err(&adapter->dev, "Region 0x%x already in use!\n",
+                       address);
                return -EBUSY;
        }
 
-       if (!(data = kmalloc(sizeof(struct smsc47b397_data), GFP_KERNEL))) {
+       if (!(data = kzalloc(sizeof(struct smsc47b397_data), GFP_KERNEL))) {
                err = -ENOMEM;
                goto error_release;
        }
-       memset(data, 0x00, sizeof(struct smsc47b397_data));
 
        new_client = &data->client;
        i2c_set_clientdata(new_client, data);
-       new_client->addr = addr;
-       init_MUTEX(&data->lock);
+       new_client->addr = address;
+       mutex_init(&data->lock);
        new_client->adapter = adapter;
        new_client->driver = &smsc47b397_driver;
        new_client->flags = 0;
 
        strlcpy(new_client->name, "smsc47b397", I2C_NAME_SIZE);
 
-       init_MUTEX(&data->update_lock);
+       mutex_init(&data->update_lock);
 
        if ((err = i2c_attach_client(new_client)))
                goto error_free;
 
-       device_create_file_temp(new_client, 1);
-       device_create_file_temp(new_client, 2);
-       device_create_file_temp(new_client, 3);
-       device_create_file_temp(new_client, 4);
+       if ((err = sysfs_create_group(&new_client->dev.kobj, &smsc47b397_group)))
+               goto error_detach;
 
-       device_create_file_fan(new_client, 1);
-       device_create_file_fan(new_client, 2);
-       device_create_file_fan(new_client, 3);
-       device_create_file_fan(new_client, 4);
+       data->class_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto error_remove;
+       }
 
        return 0;
 
+error_remove:
+       sysfs_remove_group(&new_client->dev.kobj, &smsc47b397_group);
+error_detach:
+       i2c_detach_client(new_client);
 error_free:
-       kfree(new_client);
+       kfree(data);
 error_release:
-       release_region(addr, SMSC_EXTENT);
+       release_region(address, SMSC_EXTENT);
        return err;
 }
 
-static int __init smsc47b397_find(unsigned int *addr)
+static int __init smsc47b397_find(unsigned short *addr)
 {
        u8 id, rev;
 
        superio_enter();
        id = superio_inb(SUPERIO_REG_DEVID);
 
-       if (id != 0x6f) {
+       if ((id != 0x6f) && (id != 0x81)) {
                superio_exit();
                return -ENODEV;
        }
@@ -322,8 +320,9 @@ static int __init smsc47b397_find(unsigned int *addr)
        *addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8)
                 |  superio_inb(SUPERIO_REG_BASE_LSB);
 
-       printk(KERN_INFO "smsc47b397: found SMSC LPC47B397-NC "
-               "(base address 0x%04x, revision %u)\n", *addr, rev);
+       printk(KERN_INFO "smsc47b397: found SMSC %s "
+               "(base address 0x%04x, revision %u)\n",
+               id == 0x81 ? "SCH5307-NS" : "LPC47B397-NC", *addr, rev);
 
        superio_exit();
        return 0;
@@ -333,15 +332,15 @@ static int __init smsc47b397_init(void)
 {
        int ret;
 
-       if ((ret = smsc47b397_find(normal_isa)))
+       if ((ret = smsc47b397_find(&address)))
                return ret;
 
-       return i2c_add_driver(&smsc47b397_driver);
+       return i2c_isa_add_driver(&smsc47b397_driver);
 }
 
 static void __exit smsc47b397_exit(void)
 {
-       i2c_del_driver(&smsc47b397_driver);
+       i2c_isa_del_driver(&smsc47b397_driver);
 }
 
 MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");