From bc769ff8f5f6e3d249bfde082653e5bf1c2b5698 Mon Sep 17 00:00:00 2001 From: "bgardner@wabtec.com" Date: Tue, 12 Jul 2005 13:21:11 -0500 Subject: [PATCH] I2C: simplify max6875 driver This is an update to the max6875 driver. It no longer does any detection, so the address must be forced on module load. It only makes available the user EEPROM (read-only). This patch is based off 2.6.13-rc2-mm2. Signed-off-by: Ben Gardner Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/max6875.c | 445 ++++++++++++-------------------------------- 1 file changed, 123 insertions(+), 322 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c index 0230375f72e..4d4ace4b805 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/i2c/chips/max6875.c @@ -5,97 +5,62 @@ Based on i2c/chips/eeprom.c - The MAX6875 has two EEPROM sections: config and user. - At reset, the config EEPROM is read into the registers. + The MAX6875 has a bank of registers and two banks of EEPROM. + Address ranges are defined as follows: + * 0x0000 - 0x0046 = configuration registers + * 0x8000 - 0x8046 = configuration EEPROM + * 0x8100 - 0x82FF = user EEPROM - This driver make 3 binary files available in sysfs: - reg_config - direct access to the registers - eeprom_config - acesses configuration eeprom space - eeprom_user - free for application use + This driver makes the user EEPROM available for read. - In our application, we put device serial & model numbers in user eeprom. + The registers & config EEPROM should be accessed via i2c-dev. - Notes: - 1) The datasheet says that register 0x44 / EEPROM 0x8044 should NOT - be overwritten, so the driver explicitly prevents that. - 2) It's a good idea to keep the config (0x45) locked in config EEPROM. - You can temporarily enable config writes by changing register 0x45. + The MAX6875 ignores the lowest address bit, so each chip responds to + two addresses - 0x50/0x51 and 0x52/0x53. + + Note that the MAX6875 uses i2c_smbus_write_byte_data() to set the read + address, so this driver is destructive if loaded for the wrong EEPROM chip. 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 Free Software Foundation; version 2 of the License. */ -#include #include #include #include #include -#include -#include #include #include +#include -/* Addresses to scan */ -/* No address scanned by default, as this could corrupt standard EEPROMS. */ +/* Do not scan - the MAX6875 access method will write to some EEPROM chips */ static unsigned short normal_i2c[] = {I2C_CLIENT_END}; static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END}; /* Insmod parameters */ SENSORS_INSMOD_1(max6875); -/* this param will prevent 'accidental' writes to the eeprom */ -static int allow_write = 0; -module_param(allow_write, int, 0); -MODULE_PARM_DESC(allow_write, - "Enable write access:\n" - "*0: Read only\n" - " 1: Read/Write access"); - /* The MAX6875 can only read/write 16 bytes at a time */ #define SLICE_SIZE 16 #define SLICE_BITS 4 -/* CONFIG EEPROM is at addresses 0x8000 - 0x8045, registers are at 0 - 0x45 */ -#define CONFIG_EEPROM_BASE 0x8000 -#define CONFIG_EEPROM_SIZE 0x0046 -#define CONFIG_EEPROM_SLICES 5 - /* USER EEPROM is at addresses 0x8100 - 0x82FF */ #define USER_EEPROM_BASE 0x8100 #define USER_EEPROM_SIZE 0x0200 #define USER_EEPROM_SLICES 32 /* MAX6875 commands */ -#define MAX6875_CMD_BLOCK_WRITE 0x83 -#define MAX6875_CMD_BLOCK_READ 0x84 -#define MAX6875_CMD_REBOOT 0x88 - -enum max6875_area_type { - max6875_register_config=0, - max6875_eeprom_config, - max6875_eeprom_user, - max6857_max -}; - -struct eeprom_block { - enum max6875_area_type type; - u8 slices; - u32 size; - u32 valid; - u32 base; - unsigned long *updated; - u8 *data; -}; +#define MAX6875_CMD_BLK_READ 0x84 /* Each client has this additional data */ struct max6875_data { struct i2c_client client; struct semaphore update_lock; - struct eeprom_block blocks[max6857_max]; - /* the above structs point into the arrays below */ - u8 data[USER_EEPROM_SIZE + (CONFIG_EEPROM_SIZE*2)]; - unsigned long last_updated[USER_EEPROM_SLICES + (CONFIG_EEPROM_SLICES*2)]; + + u32 valid; + u8 data[USER_EEPROM_SIZE]; + unsigned long last_updated[USER_EEPROM_SLICES]; }; static int max6875_attach_adapter(struct i2c_adapter *adapter); @@ -111,224 +76,98 @@ static struct i2c_driver max6875_driver = { .detach_client = max6875_detach_client, }; -static int max6875_update_slice(struct i2c_client *client, - struct eeprom_block *blk, - int slice) +static void max6875_update_slice(struct i2c_client *client, int slice) { struct max6875_data *data = i2c_get_clientdata(client); - int i, j, addr, count; - u8 rdbuf[SLICE_SIZE]; + int i, j, addr; + u8 *buf; int retval = 0; - if (slice >= blk->slices) - return -1; + if (slice >= USER_EEPROM_SLICES) + return; down(&data->update_lock); - if (!(blk->valid & (1 << slice)) || - (jiffies - blk->updated[slice] > 300 * HZ) || - (jiffies < blk->updated[slice])) { - dev_dbg(&client->dev, "Starting eeprom update, slice %u, base %u\n", + buf = &data->data[slice << SLICE_BITS]; + + if (!(data->valid & (1 << slice)) || + time_after(jiffies, data->last_updated[slice])) { + + dev_dbg(&client->dev, "Starting update of slice %u\n", slice, blk->base); - addr = blk->base + (slice << SLICE_BITS); - count = blk->size - (slice << SLICE_BITS); - if (count > SLICE_SIZE) { - count = SLICE_SIZE; - } + data->valid &= ~(1 << slice); - /* Preset the read address */ - if (addr < 0x100) { - /* select the register */ - if (i2c_smbus_write_byte(client, addr & 0xFF)) { - dev_dbg(&client->dev, "max6875 register select has failed!\n"); - retval = -1; - goto exit; - } - } else { - /* select the eeprom */ - if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) { - dev_dbg(&client->dev, "max6875 address set has failed!\n"); - retval = -1; - goto exit; - } + addr = USER_EEPROM_BASE + (slice << SLICE_BITS); + + /* select the eeprom address */ + if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) { + dev_err(&client->dev, "address set failed\n"); + retval = -1; + goto exit_up; } - if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - if (i2c_smbus_read_i2c_block_data(client, MAX6875_CMD_BLOCK_READ, - rdbuf) != SLICE_SIZE) - { + if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + if (i2c_smbus_read_i2c_block_data(client, + MAX6875_CMD_BLK_READ, + buf) != SLICE_SIZE) { retval = -1; - goto exit; + goto exit_up; } - - memcpy(&blk->data[slice << SLICE_BITS], rdbuf, count); } else { - for (i = 0; i < count; i++) { + for (i = 0; i < SLICE_SIZE; i++) { j = i2c_smbus_read_byte(client); - if (j < 0) - { + if (j < 0) { retval = -1; - goto exit; + goto exit_up; } - blk->data[(slice << SLICE_BITS) + i] = (u8) j; + buf[i] = j; } } - blk->updated[slice] = jiffies; - blk->valid |= (1 << slice); + data->last_updated[slice] = jiffies; + data->valid |= (1 << slice); } - exit: +exit_up: up(&data->update_lock); - return retval; -} - -static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off, size_t count, - enum max6875_area_type area_type) -{ - struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj)); - struct max6875_data *data = i2c_get_clientdata(client); - struct eeprom_block *blk; - int slice; - - blk = &data->blocks[area_type]; - - if (off > blk->size) - return 0; - if (off + count > blk->size) - count = blk->size - off; - - /* Only refresh slices which contain requested bytes */ - for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++) - max6875_update_slice(client, blk, slice); - - memcpy(buf, &blk->data[off], count); - - return count; -} - -static ssize_t max6875_user_read(struct kobject *kobj, char *buf, loff_t off, size_t count) -{ - return max6875_read(kobj, buf, off, count, max6875_eeprom_user); } -static ssize_t max6875_config_read(struct kobject *kobj, char *buf, loff_t off, size_t count) +static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj) { - return max6875_read(kobj, buf, off, count, max6875_eeprom_config); + return to_i2c_client(container_of(kobj, struct device, kobj)); } -static ssize_t max6875_cfgreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count) +static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off, + size_t count) { - return max6875_read(kobj, buf, off, count, max6875_register_config); -} - - -static ssize_t max6875_write(struct kobject *kobj, char *buf, loff_t off, size_t count, - enum max6875_area_type area_type) -{ - struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj)); + struct i2c_client *client = kobj_to_i2c_client(kobj); struct max6875_data *data = i2c_get_clientdata(client); - struct eeprom_block *blk; - int slice, addr, retval; - ssize_t sent = 0; - - blk = &data->blocks[area_type]; + int slice, max_slice; - if (off > blk->size) + if (off > USER_EEPROM_SIZE) return 0; - if ((off + count) > blk->size) - count = blk->size - off; - if (down_interruptible(&data->update_lock)) - return -EAGAIN; + if (off + count > USER_EEPROM_SIZE) + count = USER_EEPROM_SIZE - off; - /* writing to a register is done with i2c_smbus_write_byte_data() */ - if (blk->type == max6875_register_config) { - for (sent = 0; sent < count; sent++) { - addr = off + sent; - if (addr == 0x44) - continue; + /* refresh slices which contain requested bytes */ + max_slice = (off + count - 1) >> SLICE_BITS; + for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++) + max6875_update_slice(client, slice); - retval = i2c_smbus_write_byte_data(client, addr, buf[sent]); - } - } else { - int cmd, val; - - /* We are writing to EEPROM */ - for (sent = 0; sent < count; sent++) { - addr = blk->base + off + sent; - cmd = addr >> 8; - val = (addr & 0xff) | (buf[sent] << 8); // reversed - - if (addr == 0x8044) - continue; - - retval = i2c_smbus_write_word_data(client, cmd, val); - - if (retval) { - goto error_exit; - } + memcpy(buf, &data->data[off], count); - /* A write takes up to 11 ms */ - msleep(11); - } - } - - /* Invalidate the scratch buffer */ - for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++) - blk->valid &= ~(1 << slice); - - error_exit: - up(&data->update_lock); - - return sent; -} - -static ssize_t max6875_user_write(struct kobject *kobj, char *buf, loff_t off, size_t count) -{ - return max6875_write(kobj, buf, off, count, max6875_eeprom_user); -} - -static ssize_t max6875_config_write(struct kobject *kobj, char *buf, loff_t off, size_t count) -{ - return max6875_write(kobj, buf, off, count, max6875_eeprom_config); -} - -static ssize_t max6875_cfgreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count) -{ - return max6875_write(kobj, buf, off, count, max6875_register_config); + return count; } static struct bin_attribute user_eeprom_attr = { .attr = { - .name = "eeprom_user", - .mode = S_IRUGO | S_IWUSR | S_IWGRP, + .name = "eeprom", + .mode = S_IRUGO, .owner = THIS_MODULE, }, - .size = USER_EEPROM_SIZE, - .read = max6875_user_read, - .write = max6875_user_write, -}; - -static struct bin_attribute config_eeprom_attr = { - .attr = { - .name = "eeprom_config", - .mode = S_IRUGO | S_IWUSR, - .owner = THIS_MODULE, - }, - .size = CONFIG_EEPROM_SIZE, - .read = max6875_config_read, - .write = max6875_config_write, -}; - -static struct bin_attribute config_register_attr = { - .attr = { - .name = "reg_config", - .mode = S_IRUGO | S_IWUSR, - .owner = THIS_MODULE, - }, - .size = CONFIG_EEPROM_SIZE, - .read = max6875_cfgreg_read, - .write = max6875_cfgreg_write, + .size = USER_EEPROM_SIZE, + .read = max6875_read, }; static int max6875_attach_adapter(struct i2c_adapter *adapter) @@ -339,109 +178,73 @@ static int max6875_attach_adapter(struct i2c_adapter *adapter) /* This function is called by i2c_detect */ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) { - struct i2c_client *new_client; + struct i2c_client *real_client; + struct i2c_client *fake_client; struct max6875_data *data; int err = 0; - /* Prevent 24RF08 corruption (in case of user error) */ + /* Prevent 24rf08 corruption (in case of user error) */ if (kind < 0) i2c_smbus_xfer(adapter, address, 0, 0, 0, I2C_SMBUS_QUICK, NULL); - /* There are three ways we can read the EEPROM data: - (1) I2C block reads (faster, but unsupported by most adapters) - (2) Consecutive byte reads (100% overhead) - (3) Regular byte data reads (200% overhead) - The third method is not implemented by this driver because all - known adapters support at least the second. */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA | - I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) - goto exit; - - /* 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 eeprom_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA + | I2C_FUNC_SMBUS_READ_BYTE)) + return 0; + + /* Only check even addresses */ + if (address & 1) + return 0; + + if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL))) + return -ENOMEM; memset(data, 0, sizeof(struct max6875_data)); - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &max6875_driver; - new_client->flags = 0; - - /* Setup the user section */ - data->blocks[max6875_eeprom_user].type = max6875_eeprom_user; - data->blocks[max6875_eeprom_user].slices = USER_EEPROM_SLICES; - data->blocks[max6875_eeprom_user].size = USER_EEPROM_SIZE; - data->blocks[max6875_eeprom_user].base = USER_EEPROM_BASE; - data->blocks[max6875_eeprom_user].data = data->data; - data->blocks[max6875_eeprom_user].updated = data->last_updated; - - /* Setup the config section */ - data->blocks[max6875_eeprom_config].type = max6875_eeprom_config; - data->blocks[max6875_eeprom_config].slices = CONFIG_EEPROM_SLICES; - data->blocks[max6875_eeprom_config].size = CONFIG_EEPROM_SIZE; - data->blocks[max6875_eeprom_config].base = CONFIG_EEPROM_BASE; - data->blocks[max6875_eeprom_config].data = &data->data[USER_EEPROM_SIZE]; - data->blocks[max6875_eeprom_config].updated = &data->last_updated[USER_EEPROM_SLICES]; - - /* Setup the register section */ - data->blocks[max6875_register_config].type = max6875_register_config; - data->blocks[max6875_register_config].slices = CONFIG_EEPROM_SLICES; - data->blocks[max6875_register_config].size = CONFIG_EEPROM_SIZE; - data->blocks[max6875_register_config].base = 0; - data->blocks[max6875_register_config].data = &data->data[USER_EEPROM_SIZE+CONFIG_EEPROM_SIZE]; - data->blocks[max6875_register_config].updated = &data->last_updated[USER_EEPROM_SLICES+CONFIG_EEPROM_SLICES]; - - /* Init the data */ - memset(data->data, 0xff, sizeof(data->data)); - - /* Fill in the remaining client fields */ - strlcpy(new_client->name, "max6875", I2C_NAME_SIZE); + /* A fake client is created on the odd address */ + if (!(fake_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { + err = -ENOMEM; + goto exit_kfree1; + } + memset(fake_client, 0, sizeof(struct i2c_client)); + + /* Init real i2c_client */ + real_client = &data->client; + i2c_set_clientdata(real_client, data); + real_client->addr = address; + real_client->adapter = adapter; + real_client->driver = &max6875_driver; + real_client->flags = 0; + strlcpy(real_client->name, "max6875", I2C_NAME_SIZE); init_MUTEX(&data->update_lock); - /* Verify that the chip is really what we think it is */ - if ((max6875_update_slice(new_client, &data->blocks[max6875_eeprom_config], 4) < 0) || - (max6875_update_slice(new_client, &data->blocks[max6875_register_config], 4) < 0)) - goto exit_kfree; - - /* 0x41,0x42 must be zero and 0x40 must match in eeprom and registers */ - if ((data->blocks[max6875_eeprom_config].data[0x41] != 0) || - (data->blocks[max6875_eeprom_config].data[0x42] != 0) || - (data->blocks[max6875_register_config].data[0x41] != 0) || - (data->blocks[max6875_register_config].data[0x42] != 0) || - (data->blocks[max6875_eeprom_config].data[0x40] != - data->blocks[max6875_register_config].data[0x40])) - goto exit_kfree; - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_kfree; - - /* create the sysfs eeprom files with the correct permissions */ - if (allow_write == 0) { - user_eeprom_attr.attr.mode &= ~S_IWUGO; - user_eeprom_attr.write = NULL; - config_eeprom_attr.attr.mode &= ~S_IWUGO; - config_eeprom_attr.write = NULL; - config_register_attr.attr.mode &= ~S_IWUGO; - config_register_attr.write = NULL; - } - sysfs_create_bin_file(&new_client->dev.kobj, &user_eeprom_attr); - sysfs_create_bin_file(&new_client->dev.kobj, &config_eeprom_attr); - sysfs_create_bin_file(&new_client->dev.kobj, &config_register_attr); + /* Init fake client data */ + /* set the client data to the i2c_client so that it will get freed */ + i2c_set_clientdata(fake_client, fake_client); + fake_client->addr = address | 1; + fake_client->adapter = adapter; + fake_client->driver = &max6875_driver; + fake_client->flags = 0; + strlcpy(fake_client->name, "max6875-dummy", I2C_NAME_SIZE); + + /* Prevent 24RF08 corruption (in case of user error) */ + i2c_smbus_write_quick(real_client, 0); + + if ((err = i2c_attach_client(real_client)) != 0) + goto exit_kfree2; + + if ((err = i2c_attach_client(fake_client)) != 0) + goto exit_detach; + + sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr); return 0; -exit_kfree: +exit_detach: + i2c_detach_client(real_client); +exit_kfree2: + kfree(fake_client); +exit_kfree1: kfree(data); -exit: return err; } @@ -451,12 +254,10 @@ static int max6875_detach_client(struct i2c_client *client) err = i2c_detach_client(client); if (err) { - dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); + dev_err(&client->dev, "i2c_detach_client() failed\n"); return err; } - kfree(i2c_get_clientdata(client)); - return 0; } -- cgit v1.2.3-18-g5258 From a8decc658a8800e61f13b9240125f2a34d7fd3f5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 27 Jul 2005 12:43:03 -0500 Subject: [PATCH] I2C: fix max6875 build error Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/max6875.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c index 4d4ace4b805..1a7993e6354 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/i2c/chips/max6875.c @@ -93,8 +93,7 @@ static void max6875_update_slice(struct i2c_client *client, int slice) if (!(data->valid & (1 << slice)) || time_after(jiffies, data->last_updated[slice])) { - dev_dbg(&client->dev, "Starting update of slice %u\n", - slice, blk->base); + dev_dbg(&client->dev, "Starting update of slice %u\n", slice); data->valid &= ~(1 << slice); -- cgit v1.2.3-18-g5258 From 5033017c2678df9dc75be0139f19701ff224a498 Mon Sep 17 00:00:00 2001 From: Hans-Frieder Vogt Date: Sat, 23 Jul 2005 15:33:39 +0200 Subject: [PATCH] I2C: cleanup of i2c-nforce2 attached is a small patch that removes unused code from i2c-nforce2 and adds a single debug message. The patch is against 2.6.13-rc3-mm1. I have tested the patch with 2.6.13-rc3: compiles cleanly and works as without the patch (as expected). Signed-off-by: Hans-Frieder Vogt Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-nforce2.c | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 74eb89aa935..1df601bb7f4 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -131,7 +131,6 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, struct nforce2_smbus *smbus = adap->algo_data; unsigned char protocol, pec, temp; unsigned char len = 0; /* to keep the compiler quiet */ - int timeout = 0; int i; protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ : @@ -191,29 +190,10 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, case I2C_SMBUS_PROC_CALL: dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); return -1; - /* - outb_p(command, NVIDIA_SMB_CMD); - outb_p(data->word, NVIDIA_SMB_DATA); - outb_p(data->word >> 8, NVIDIA_SMB_DATA + 1); - protocol = NVIDIA_SMB_PRTCL_PROC_CALL | pec; - read_write = I2C_SMBUS_READ; - break; - */ case I2C_SMBUS_BLOCK_PROC_CALL: dev_err(&adap->dev, "I2C_SMBUS_BLOCK_PROC_CALL not supported!\n"); return -1; - /* - protocol |= pec; - len = min_t(u8, data->block[0], 31); - outb_p(command, NVIDIA_SMB_CMD); - outb_p(len, NVIDIA_SMB_BCNT); - for (i = 0; i < len; i++) - outb_p(data->block[i + 1], NVIDIA_SMB_DATA + i); - protocol = NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL | pec; - read_write = I2C_SMBUS_READ; - break; - */ case I2C_SMBUS_WORD_DATA_PEC: case I2C_SMBUS_BLOCK_DATA_PEC: @@ -232,12 +212,6 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, temp = inb_p(NVIDIA_SMB_STS); -#if 0 - do { - i2c_do_pause(1); - temp = inb_p(NVIDIA_SMB_STS); - } while (((temp & NVIDIA_SMB_STS_DONE) == 0) && (timeout++ < MAX_TIMEOUT)); -#endif if (~temp & NVIDIA_SMB_STS_DONE) { udelay(500); temp = inb_p(NVIDIA_SMB_STS); @@ -247,9 +221,10 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, temp = inb_p(NVIDIA_SMB_STS); } - if ((timeout >= MAX_TIMEOUT) || (~temp & NVIDIA_SMB_STS_DONE) - || (temp & NVIDIA_SMB_STS_STATUS)) + if ((~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) { + dev_dbg(&adap->dev, "SMBus Timeout! (0x%02x)\n", temp); return -1; + } if (read_write == I2C_SMBUS_WRITE) return 0; -- cgit v1.2.3-18-g5258 From a61fc683ae1b7871d8d81ac5025af1a923731547 Mon Sep 17 00:00:00 2001 From: "bgardner@wabtec.com" Date: Wed, 27 Jul 2005 12:43:03 -0500 Subject: [PATCH] I2C: add kobj_to_i2c_client Move the inline function kobj_to_i2c_client() from max6875.c to i2c.h. Signed-off-by: Ben Gardner Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/max6875.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c index 1a7993e6354..35a8e921529 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/i2c/chips/max6875.c @@ -131,11 +131,6 @@ exit_up: up(&data->update_lock); } -static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj) -{ - return to_i2c_client(container_of(kobj, struct device, kobj)); -} - static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off, size_t count) { -- cgit v1.2.3-18-g5258 From 17f990c87a1e5addc49b99a53b3d2a2fac9680e9 Mon Sep 17 00:00:00 2001 From: "bgardner@wabtec.com" Date: Wed, 27 Jul 2005 12:43:14 -0500 Subject: [PATCH] I2C: max6875 code cleanup Remove an unused local variable and change the subclient name. Signed-off-by: Ben Gardner Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/max6875.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c index 35a8e921529..f0e30623773 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/i2c/chips/max6875.c @@ -81,7 +81,6 @@ static void max6875_update_slice(struct i2c_client *client, int slice) struct max6875_data *data = i2c_get_clientdata(client); int i, j, addr; u8 *buf; - int retval = 0; if (slice >= USER_EEPROM_SLICES) return; @@ -102,7 +101,6 @@ static void max6875_update_slice(struct i2c_client *client, int slice) /* select the eeprom address */ if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) { dev_err(&client->dev, "address set failed\n"); - retval = -1; goto exit_up; } @@ -111,14 +109,12 @@ static void max6875_update_slice(struct i2c_client *client, int slice) if (i2c_smbus_read_i2c_block_data(client, MAX6875_CMD_BLK_READ, buf) != SLICE_SIZE) { - retval = -1; goto exit_up; } } else { for (i = 0; i < SLICE_SIZE; i++) { j = i2c_smbus_read_byte(client); if (j < 0) { - retval = -1; goto exit_up; } buf[i] = j; @@ -182,7 +178,7 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) i2c_smbus_xfer(adapter, address, 0, 0, 0, I2C_SMBUS_QUICK, NULL); - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA | I2C_FUNC_SMBUS_READ_BYTE)) return 0; @@ -218,7 +214,7 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) fake_client->adapter = adapter; fake_client->driver = &max6875_driver; fake_client->flags = 0; - strlcpy(fake_client->name, "max6875-dummy", I2C_NAME_SIZE); + strlcpy(fake_client->name, "max6875 subclient", I2C_NAME_SIZE); /* Prevent 24RF08 corruption (in case of user error) */ i2c_smbus_write_quick(real_client, 0); -- cgit v1.2.3-18-g5258 From e647ecf15e365679f0528d7815ab4db0d4802918 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 27 Jul 2005 21:28:28 +0200 Subject: [PATCH] hwmon: soften lm75 initialization The LM75 initialization is a bit agressive, it arbitrarily reconfigures the chip. Make it only change the bit it needs. This is a port from the 2.4 kernel version of the driver (lm_sensors). Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/lm75.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 5be164ed278..79d7ebc9b14 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -251,8 +251,12 @@ static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) static void lm75_init_client(struct i2c_client *client) { - /* Initialize the LM75 chip */ - lm75_write_value(client, LM75_REG_CONF, 0); + int reg; + + /* Enable if in shutdown mode */ + reg = lm75_read_value(client, LM75_REG_CONF); + if (reg >= 0 && (reg & 0x01)) + lm75_write_value(client, LM75_REG_CONF, reg & 0xfe); } static struct lm75_data *lm75_update_device(struct device *dev) -- cgit v1.2.3-18-g5258 From 27fe048eb3787d29bf9cf9d6d12077bb8af869a6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 27 Jul 2005 21:30:16 +0200 Subject: [PATCH] hwmon: kill client name lm78-j Drop the separate client name for the LM78-J chip. This is really only a later revision of the LM78, with almost no difference and no difference the driver handles in any case. This was the only client name that had a dash in it, and special care had to be taken in libsensors because of it. As we plan to write a new library soon, I'd like to get rid of this exception before we do. As a nice side effect, it saves 876 bytes in lm78.ko. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/lm78.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 29241469dcb..cf7a2a7f54b 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -34,7 +34,7 @@ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; /* Insmod parameters */ -SENSORS_INSMOD_3(lm78, lm78j, lm79); +SENSORS_INSMOD_2(lm78, lm79); /* Many LM78 constants specified below */ @@ -559,10 +559,9 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind) /* Determine the chip type. */ if (kind <= 0) { i = lm78_read_value(new_client, LM78_REG_CHIPID); - if (i == 0x00 || i == 0x20) + if (i == 0x00 || i == 0x20 /* LM78 */ + || i == 0x40) /* LM78-J */ kind = lm78; - else if (i == 0x40) - kind = lm78j; else if ((i & 0xfe) == 0xc0) kind = lm79; else { @@ -578,8 +577,6 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind) if (kind == lm78) { client_name = "lm78"; - } else if (kind == lm78j) { - client_name = "lm78-j"; } else if (kind == lm79) { client_name = "lm79"; } @@ -788,7 +785,7 @@ static void __exit sm_lm78_exit(void) MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver"); +MODULE_DESCRIPTION("LM78/LM79 driver"); MODULE_LICENSE("GPL"); module_init(sm_lm78_init); -- cgit v1.2.3-18-g5258 From 8dd2d2ca7fafdedaebd1862e954fccaef212f1e1 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 27 Jul 2005 21:33:15 +0200 Subject: [PATCH] hwmon: Document on the W83627EHG chip Document the fact that the W83627EHG is compatible with the W83627EHF. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/Kconfig | 3 +++ drivers/hwmon/w83627ehf.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 140d5f851a5..f9aa3faa6b8 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -404,6 +404,9 @@ config SENSORS_W83627EHF Only fan and temperature inputs are supported at the moment, while the chip does much more than that. + This driver also supports the W83627EHG, which is the lead-free + version of the W83627EHF. + This driver can also be built as a module. If so, the module will be called w83627ehf. diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 8a40b6976e1..250f6b059a5 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -9,6 +9,9 @@ Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help in testing and debugging this driver. + This driver also supports the W83627EHG, which is the lead-free + version of the W83627EHF. + 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 Free Software Foundation; either version 2 of the License, or -- cgit v1.2.3-18-g5258 From 1236441f38b6a98caf4c7983e7efdecc2d1527b5 Mon Sep 17 00:00:00 2001 From: "Mark M. Hoffman" Date: Fri, 15 Jul 2005 21:38:08 -0400 Subject: [PATCH] I2C hwmon: hwmon sysfs class This patch adds the sysfs class "hwmon" for use by hardware monitoring (sensors) chip drivers. It also fixes up the related Kconfig/Makefile bits. Signed-off-by: Mark M. Hoffman Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/Kconfig | 7 +++- drivers/hwmon/Makefile | 2 ++ drivers/hwmon/hwmon.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 drivers/hwmon/hwmon.c (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index f9aa3faa6b8..8c391131370 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -12,7 +12,12 @@ config HWMON of a system. Most modern motherboards include such a device. It can include temperature sensors, voltage sensors, fan speed sensors and various additional features such as the ability to - control the speed of the fans. + control the speed of the fans. If you want this support you + should say Y here and also to the specific driver(s) for your + sensors chip(s) below. + + This support can also be built as a module. If so, the module + will be called hwmon. config SENSORS_ADM1021 tristate "Analog Devices ADM1021 and compatibles" diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 2781403a023..bd1bd59eb14 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -2,6 +2,8 @@ # Makefile for sensor chip drivers. # +obj-$(CONFIG_HWMON) += hwmon.o + # asb100, then w83781d go first, as they can override other drivers' addresses. obj-$(CONFIG_SENSORS_ASB100) += asb100.o obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c new file mode 100644 index 00000000000..9b41c9bd805 --- /dev/null +++ b/drivers/hwmon/hwmon.c @@ -0,0 +1,98 @@ +/* + hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring + + This file defines the sysfs class "hwmon", for use by sensors drivers. + + Copyright (C) 2005 Mark M. Hoffman + + 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 Free Software Foundation; version 2 of the License. +*/ + +#include +#include +#include +#include +#include +#include + +#define HWMON_ID_PREFIX "hwmon" +#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" + +static struct class *hwmon_class; + +static DEFINE_IDR(hwmon_idr); + +/** + * hwmon_device_register - register w/ hwmon sysfs class + * @dev: the device to register + * + * hwmon_device_unregister() must be called when the class device is no + * longer needed. + * + * Returns the pointer to the new struct class device. + */ +struct class_device *hwmon_device_register(struct device *dev) +{ + struct class_device *cdev; + int id; + + if (idr_pre_get(&hwmon_idr, GFP_KERNEL) == 0) + return ERR_PTR(-ENOMEM); + + if (idr_get_new(&hwmon_idr, NULL, &id) < 0) + return ERR_PTR(-ENOMEM); + + id = id & MAX_ID_MASK; + cdev = class_device_create(hwmon_class, MKDEV(0,0), dev, + HWMON_ID_FORMAT, id); + + if (IS_ERR(cdev)) + idr_remove(&hwmon_idr, id); + + return cdev; +} + +/** + * hwmon_device_unregister - removes the previously registered class device + * + * @cdev: the class device to destroy + */ +void hwmon_device_unregister(struct class_device *cdev) +{ + int id; + + if (sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1) { + class_device_unregister(cdev); + idr_remove(&hwmon_idr, id); + } else + dev_dbg(cdev->dev, + "hwmon_device_unregister() failed: bad class ID!\n"); +} + +static int __init hwmon_init(void) +{ + hwmon_class = class_create(THIS_MODULE, "hwmon"); + if (IS_ERR(hwmon_class)) { + printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n"); + return PTR_ERR(hwmon_class); + } + return 0; +} + +static void __exit hwmon_exit(void) +{ + class_destroy(hwmon_class); +} + +module_init(hwmon_init); +module_exit(hwmon_exit); + +EXPORT_SYMBOL_GPL(hwmon_device_register); +EXPORT_SYMBOL_GPL(hwmon_device_unregister); + +MODULE_AUTHOR("Mark M. Hoffman "); +MODULE_DESCRIPTION("hardware monitoring sysfs/class support"); +MODULE_LICENSE("GPL"); + -- cgit v1.2.3-18-g5258 From 943b0830cebe4711354945ed3cb44e84152aaca0 Mon Sep 17 00:00:00 2001 From: "Mark M. Hoffman" Date: Fri, 15 Jul 2005 21:39:18 -0400 Subject: [PATCH] I2C hwmon: add hwmon sysfs class to drivers This patch modifies sensors chip drivers to make use of the new sysfs class "hwmon". Signed-off-by: Mark M. Hoffman Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/adm1021.c | 16 +++++++++++++++- drivers/hwmon/adm1025.c | 16 +++++++++++++++- drivers/hwmon/adm1026.c | 15 ++++++++++++++- drivers/hwmon/adm1031.c | 16 +++++++++++++++- drivers/hwmon/adm9240.c | 17 ++++++++++++++++- drivers/hwmon/asb100.c | 31 +++++++++++++++++++++++++------ drivers/hwmon/atxp1.c | 16 +++++++++++++++- drivers/hwmon/ds1621.c | 16 +++++++++++++++- drivers/hwmon/fscher.c | 16 +++++++++++++++- drivers/hwmon/fscpos.c | 16 +++++++++++++++- drivers/hwmon/gl518sm.c | 17 +++++++++++++++-- drivers/hwmon/gl520sm.c | 16 +++++++++++++++- drivers/hwmon/it87.c | 16 +++++++++++++++- drivers/hwmon/lm63.c | 16 +++++++++++++++- drivers/hwmon/lm75.c | 15 ++++++++++++++- drivers/hwmon/lm77.c | 16 ++++++++++++++-- drivers/hwmon/lm78.c | 16 +++++++++++++++- drivers/hwmon/lm80.c | 16 +++++++++++++++- drivers/hwmon/lm83.c | 16 +++++++++++++++- drivers/hwmon/lm85.c | 15 ++++++++++++++- drivers/hwmon/lm87.c | 16 +++++++++++++++- drivers/hwmon/lm90.c | 16 +++++++++++++++- drivers/hwmon/lm92.c | 17 +++++++++++++++-- drivers/hwmon/max1619.c | 17 +++++++++++++++-- drivers/hwmon/pc87360.c | 13 +++++++++++++ drivers/hwmon/sis5595.c | 18 ++++++++++++++++-- drivers/hwmon/smsc47b397.c | 16 +++++++++++++++- drivers/hwmon/smsc47m1.c | 17 ++++++++++++++++- drivers/hwmon/via686a.c | 24 +++++++++++++++++++----- drivers/hwmon/w83627ehf.c | 16 +++++++++++++++- drivers/hwmon/w83627hf.c | 16 +++++++++++++++- drivers/hwmon/w83781d.c | 39 +++++++++++++++++++++++++++++++-------- drivers/hwmon/w83l785ts.c | 16 +++++++++++++++- 33 files changed, 522 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index d2c774c32f4..a483d96e4ce 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include /* Addresses to scan */ @@ -89,6 +91,7 @@ clearing it. Weird, ey? --Phil */ /* Each client has this additional data */ struct adm1021_data { struct i2c_client client; + struct class_device *class_dev; enum chips type; struct semaphore update_lock; @@ -295,6 +298,12 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) adm1021_init_client(new_client); /* 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 error2; + } + device_create_file(&new_client->dev, &dev_attr_temp1_max); device_create_file(&new_client->dev, &dev_attr_temp1_min); device_create_file(&new_client->dev, &dev_attr_temp1_input); @@ -305,6 +314,8 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) return 0; +error2: + i2c_detach_client(new_client); error1: kfree(data); error0: @@ -322,14 +333,17 @@ static void adm1021_init_client(struct i2c_client *client) static int adm1021_detach_client(struct i2c_client *client) { + struct adm1021_data *data = i2c_get_clientdata(client); int err; + hwmon_device_unregister(data->class_dev); + if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); return err; } - kfree(i2c_get_clientdata(client)); + kfree(data); return 0; } diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index e452d0daf90..b68b292c00d 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -52,6 +52,8 @@ #include #include #include +#include +#include /* * Addresses to scan @@ -132,6 +134,7 @@ static struct i2c_driver adm1025_driver = { struct adm1025_data { struct i2c_client client; + struct class_device *class_dev; struct semaphore update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -416,6 +419,12 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) adm1025_init_client(new_client); /* 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 exit_detach; + } + device_create_file(&new_client->dev, &dev_attr_in0_input); device_create_file(&new_client->dev, &dev_attr_in1_input); device_create_file(&new_client->dev, &dev_attr_in2_input); @@ -452,6 +461,8 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) return 0; +exit_detach: + i2c_detach_client(new_client); exit_free: kfree(data); exit: @@ -502,15 +513,18 @@ static void adm1025_init_client(struct i2c_client *client) static int adm1025_detach_client(struct i2c_client *client) { + struct adm1025_data *data = i2c_get_clientdata(client); int err; + hwmon_device_unregister(data->class_dev); + if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, " "client not detached.\n"); return err; } - kfree(i2c_get_clientdata(client)); + kfree(data); return 0; } diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index c8a7f47911f..eb55133a13e 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; @@ -259,6 +261,7 @@ struct pwm_data { struct adm1026_data { struct i2c_client client; + struct class_device *class_dev; struct semaphore lock; enum chips type; @@ -324,8 +327,10 @@ int adm1026_attach_adapter(struct i2c_adapter *adapter) int adm1026_detach_client(struct i2c_client *client) { + struct adm1026_data *data = i2c_get_clientdata(client); + hwmon_device_unregister(data->class_dev); i2c_detach_client(client); - kfree(i2c_get_clientdata(client)); + kfree(data); return 0; } @@ -1555,6 +1560,12 @@ int adm1026_detect(struct i2c_adapter *adapter, int address, adm1026_init_client(new_client); /* 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 exitdetach; + } + device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr); device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr); @@ -1690,6 +1701,8 @@ int adm1026_detect(struct i2c_adapter *adapter, int address, return 0; /* Error out and cleanup code */ +exitdetach: + i2c_detach_client(new_client); exitfree: kfree(data); exit: diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index 93625095727..ac3b1542556 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include /* Following macros takes channel parameter starting from 0 to 2 */ #define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr)) @@ -69,6 +71,7 @@ typedef u8 auto_chan_table_t[8][2]; /* Each client has this additional data */ struct adm1031_data { struct i2c_client client; + struct class_device *class_dev; struct semaphore update_lock; int chip_type; char valid; /* !=0 if following fields are valid */ @@ -788,6 +791,12 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) adm1031_init_client(new_client); /* 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 exit_detach; + } + device_create_file(&new_client->dev, &dev_attr_fan1_input); device_create_file(&new_client->dev, &dev_attr_fan1_div); device_create_file(&new_client->dev, &dev_attr_fan1_min); @@ -833,6 +842,8 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) return 0; +exit_detach: + i2c_detach_client(new_client); exit_free: kfree(data); exit: @@ -841,11 +852,14 @@ exit: static int adm1031_detach_client(struct i2c_client *client) { + struct adm1031_data *data = i2c_get_clientdata(client); int ret; + + hwmon_device_unregister(data->class_dev); if ((ret = i2c_detach_client(client)) != 0) { return ret; } - kfree(i2c_get_clientdata(client)); + kfree(data); return 0; } diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index ce2a6eb93f6..7ef61206ba1 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -47,6 +47,8 @@ #include #include #include +#include +#include /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, @@ -150,6 +152,7 @@ static struct i2c_driver adm9240_driver = { struct adm9240_data { enum chips type; struct i2c_client client; + struct class_device *class_dev; struct semaphore update_lock; char valid; unsigned long last_updated_measure; @@ -582,6 +585,12 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) adm9240_init_client(new_client); /* populate sysfs filesystem */ + data->class_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_detach; + } + device_create_file(&new_client->dev, &dev_attr_in0_input); device_create_file(&new_client->dev, &dev_attr_in0_min); device_create_file(&new_client->dev, &dev_attr_in0_max); @@ -615,6 +624,9 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file(&new_client->dev, &dev_attr_cpu0_vid); return 0; + +exit_detach: + i2c_detach_client(new_client); exit_free: kfree(data); exit: @@ -630,15 +642,18 @@ static int adm9240_attach_adapter(struct i2c_adapter *adapter) static int adm9240_detach_client(struct i2c_client *client) { + struct adm9240_data *data = i2c_get_clientdata(client); int err; + hwmon_device_unregister(data->class_dev); + if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, " "client not detached.\n"); return err; } - kfree(i2c_get_clientdata(client)); + kfree(data); return 0; } diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index 70d996d6fe0..3ab7a2ddafb 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include #include "lm75.h" @@ -183,6 +185,7 @@ static u8 DIV_TO_REG(long val) dynamically allocated, at the same time the client itself is allocated. */ struct asb100_data { struct i2c_client client; + struct class_device *class_dev; struct semaphore lock; enum chips type; @@ -821,6 +824,12 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2)); /* 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 ERROR3; + } + device_create_file_in(new_client, 0); device_create_file_in(new_client, 1); device_create_file_in(new_client, 2); @@ -847,6 +856,11 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) return 0; +ERROR3: + i2c_detach_client(data->lm75[1]); + i2c_detach_client(data->lm75[0]); + kfree(data->lm75[1]); + kfree(data->lm75[0]); ERROR2: i2c_detach_client(new_client); ERROR1: @@ -857,21 +871,26 @@ ERROR0: static int asb100_detach_client(struct i2c_client *client) { + struct asb100_data *data = i2c_get_clientdata(client); int err; + /* main client */ + if (data) + hwmon_device_unregister(data->class_dev); + if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "client deregistration failed; " "client not detached.\n"); return err; } - if (i2c_get_clientdata(client)==NULL) { - /* subclients */ + /* main client */ + if (data) + kfree(data); + + /* subclient */ + else kfree(client); - } else { - /* main client */ - kfree(i2c_get_clientdata(client)); - } return 0; } diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index fca3fc1cef7..5f79f07a4ab 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("System voltages control via Attansic ATXP1"); @@ -59,6 +61,7 @@ static struct i2c_driver atxp1_driver = { struct atxp1_data { struct i2c_client client; + struct class_device *class_dev; struct semaphore update_lock; unsigned long last_updated; u8 valid; @@ -317,6 +320,12 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_free; } + data->class_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_detach; + } + device_create_file(&new_client->dev, &dev_attr_gpio1); device_create_file(&new_client->dev, &dev_attr_gpio2); device_create_file(&new_client->dev, &dev_attr_cpu0_vid); @@ -326,6 +335,8 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind) return 0; +exit_detach: + i2c_detach_client(new_client); exit_free: kfree(data); exit: @@ -334,14 +345,17 @@ exit: static int atxp1_detach_client(struct i2c_client * client) { + struct atxp1_data * data = i2c_get_clientdata(client); int err; + hwmon_device_unregister(data->class_dev); + err = i2c_detach_client(client); if (err) dev_err(&client->dev, "Failed to detach client.\n"); else - kfree(i2c_get_clientdata(client)); + kfree(data); return err; }; diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index 5360d58804f..9ed21ac46e9 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "lm75.h" /* Addresses to scan */ @@ -71,6 +73,7 @@ MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low") /* Each client has this additional data */ struct ds1621_data { struct i2c_client client; + struct class_device *class_dev; struct semaphore update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -250,6 +253,12 @@ int ds1621_detect(struct i2c_adapter *adapter, int address, ds1621_init_client(new_client); /* 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 exit_detach; + } + device_create_file(&new_client->dev, &dev_attr_alarms); device_create_file(&new_client->dev, &dev_attr_temp1_input); device_create_file(&new_client->dev, &dev_attr_temp1_min); @@ -259,6 +268,8 @@ int ds1621_detect(struct i2c_adapter *adapter, int address, /* OK, this is not exactly good programming practice, usually. But it is very code-efficient in this case. */ + exit_detach: + i2c_detach_client(new_client); exit_free: kfree(data); exit: @@ -267,15 +278,18 @@ int ds1621_detect(struct i2c_adapter *adapter, int address, static int ds1621_detach_client(struct i2c_client *client) { + struct ds1621_data *data = i2c_get_clientdata(client); int err; + hwmon_device_unregister(data->class_dev); + if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, " "client not detached.\n"); return err; } - kfree(i2c_get_clientdata(client)); + kfree(data); return 0; } diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c index da411741c2c..b794580a072 100644 --- a/drivers/hwmon/fscher.c +++ b/drivers/hwmon/fscher.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include /* * Addresses to scan @@ -132,6 +134,7 @@ static struct i2c_driver fscher_driver = { struct fscher_data { struct i2c_client client; + struct class_device *class_dev; struct semaphore update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -341,6 +344,12 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind) fscher_init_client(new_client); /* 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 exit_detach; + } + device_create_file_revision(new_client); device_create_file_alarms(new_client); device_create_file_control(new_client); @@ -360,6 +369,8 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind) return 0; +exit_detach: + i2c_detach_client(new_client); exit_free: kfree(data); exit: @@ -368,15 +379,18 @@ exit: static int fscher_detach_client(struct i2c_client *client) { + struct fscher_data *data = i2c_get_clientdata(client); int err; + hwmon_device_unregister(data->class_dev); + if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, " "client not detached.\n"); return err; } - kfree(i2c_get_clientdata(client)); + kfree(data); return 0; } diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c index 301ae98bd0a..4cb33b23112 100644 --- a/drivers/hwmon/fscpos.c +++ b/drivers/hwmon/fscpos.c @@ -36,6 +36,8 @@ #include #include #include +#include +#include /* * Addresses to scan @@ -113,6 +115,7 @@ static struct i2c_driver fscpos_driver = { */ struct fscpos_data { struct i2c_client client; + struct class_device *class_dev; struct semaphore update_lock; char valid; /* 0 until following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -496,6 +499,12 @@ int fscpos_detect(struct i2c_adapter *adapter, int address, int kind) dev_info(&new_client->dev, "Found fscpos chip, rev %u\n", data->revision); /* 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 exit_detach; + } + device_create_file(&new_client->dev, &dev_attr_event); device_create_file(&new_client->dev, &dev_attr_in0_input); device_create_file(&new_client->dev, &dev_attr_in1_input); @@ -526,6 +535,8 @@ int fscpos_detect(struct i2c_adapter *adapter, int address, int kind) return 0; +exit_detach: + i2c_detach_client(new_client); exit_free: kfree(data); exit: @@ -534,14 +545,17 @@ exit: static int fscpos_detach_client(struct i2c_client *client) { + struct fscpos_data *data = i2c_get_clientdata(client); int err; + hwmon_device_unregister(data->class_dev); + if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, client" " not detached.\n"); return err; } - kfree(i2c_get_clientdata(client)); + kfree(data); return 0; } diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index 6bedf729dcf..49972929a69 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -42,6 +42,8 @@ #include #include #include +#include +#include /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; @@ -117,6 +119,7 @@ static inline u8 FAN_TO_REG(long rpm, int div) /* Each client has this additional data */ struct gl518_data { struct i2c_client client; + struct class_device *class_dev; enum chips type; struct semaphore update_lock; @@ -419,6 +422,12 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) gl518_init_client((struct i2c_client *) new_client); /* 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 exit_detach; + } + device_create_file(&new_client->dev, &dev_attr_in0_input); device_create_file(&new_client->dev, &dev_attr_in1_input); device_create_file(&new_client->dev, &dev_attr_in2_input); @@ -450,6 +459,8 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) /* OK, this is not exactly good programming practice, usually. But it is very code-efficient in this case. */ +exit_detach: + i2c_detach_client(new_client); exit_free: kfree(data); exit: @@ -477,16 +488,18 @@ static void gl518_init_client(struct i2c_client *client) static int gl518_detach_client(struct i2c_client *client) { + struct gl518_data *data = i2c_get_clientdata(client); int err; + hwmon_device_unregister(data->class_dev); + if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, " "client not detached.\n"); return err; } - kfree(i2c_get_clientdata(client)); - + kfree(data); return 0; } diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index 80ae8d30c2a..ce482e17e03 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include /* Type of the extra sensor */ static unsigned short extra_sensor_type; @@ -120,6 +122,7 @@ static struct i2c_driver gl520_driver = { /* Client data */ struct gl520_data { struct i2c_client client; + struct class_device *class_dev; struct semaphore update_lock; char valid; /* zero until the following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -571,6 +574,12 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) gl520_init_client(new_client); /* 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 exit_detach; + } + device_create_file_vid(new_client, 0); device_create_file_in(new_client, 0); @@ -592,6 +601,8 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) return 0; +exit_detach: + i2c_detach_client(new_client); exit_free: kfree(data); exit: @@ -639,15 +650,18 @@ static void gl520_init_client(struct i2c_client *client) static int gl520_detach_client(struct i2c_client *client) { + struct gl520_data *data = i2c_get_clientdata(client); int err; + hwmon_device_unregister(data->class_dev); + if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, " "client not detached.\n"); return err; } - kfree(i2c_get_clientdata(client)); + kfree(data); return 0; } diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index db20c9e4739..92c5b2420f9 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include @@ -192,6 +194,7 @@ static int DIV_TO_REG(int val) allocated. */ struct it87_data { struct i2c_client client; + struct class_device *class_dev; struct semaphore lock; enum chips type; @@ -840,6 +843,12 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) it87_init_client(new_client, data); /* 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 ERROR3; + } + device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr); device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr); @@ -904,6 +913,8 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) return 0; +ERROR3: + i2c_detach_client(new_client); ERROR2: kfree(data); ERROR1: @@ -915,8 +926,11 @@ ERROR0: static int it87_detach_client(struct i2c_client *client) { + struct it87_data *data = i2c_get_clientdata(client); int err; + hwmon_device_unregister(data->class_dev); + if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); @@ -925,7 +939,7 @@ static int it87_detach_client(struct i2c_client *client) if(i2c_is_isa_client(client)) release_region(client->addr, IT87_EXTENT); - kfree(i2c_get_clientdata(client)); + kfree(data); return 0; } diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 7c6f9ea5a25..cba0a40ad66 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -44,6 +44,8 @@ #include #include #include +#include +#include /* * Addresses to scan @@ -152,6 +154,7 @@ static struct i2c_driver lm63_driver = { struct lm63_data { struct i2c_client client; + struct class_device *class_dev; struct semaphore update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -437,6 +440,12 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) lm63_init_client(new_client); /* 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 exit_detach; + } + if (data->config & 0x04) { /* tachometer enabled */ device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); @@ -462,6 +471,8 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) return 0; +exit_detach: + i2c_detach_client(new_client); exit_free: kfree(data); exit: @@ -505,15 +516,18 @@ static void lm63_init_client(struct i2c_client *client) static int lm63_detach_client(struct i2c_client *client) { + struct lm63_data *data = i2c_get_clientdata(client); int err; + hwmon_device_unregister(data->class_dev); + if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, " "client not detached\n"); return err; } - kfree(i2c_get_clientdata(client)); + kfree(data); return 0; } diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 79d7ebc9b14..129c8f21333 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "lm75.h" @@ -46,6 +48,7 @@ SENSORS_INSMOD_1(lm75); /* Each client has this additional data */ struct lm75_data { struct i2c_client client; + struct class_device *class_dev; struct semaphore update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -208,12 +211,20 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) lm75_init_client(new_client); /* 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 exit_detach; + } + device_create_file(&new_client->dev, &dev_attr_temp1_max); device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); device_create_file(&new_client->dev, &dev_attr_temp1_input); return 0; +exit_detach: + i2c_detach_client(new_client); exit_free: kfree(data); exit: @@ -222,8 +233,10 @@ exit: