From 004215f8ce0e321e9082cdb09d2266fbdcc34361 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 18 Mar 2004 21:24:14 -0800 Subject: [PATCH] I2C: w83781d fan_div code refactoring Quoting myself: > This tends to increase the size of the three set_store_regs_fan_div > functions, and I am considering refactoring them at some point. Later > though. Here is the promised refactoring. Tested on my AS99127F rev.1, seems to work. As for the previous patch, there is a part that I cannot test with the AS99127F, so additional testing is welcome. I agree this makes the code slightly less readable, but this saves 60 lines of code (1754 bytes, around 3% of the driver total), and is actually far less complex that I first feared. --- drivers/i2c/chips/w83781d.c | 94 ++++++++------------------------------------- 1 file changed, 17 insertions(+), 77 deletions(-) diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index 16b6ff518ba7..df887e2c49bd 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c @@ -620,7 +620,7 @@ show_fan_div_reg(struct device *dev, char *buf, int nr) least suprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ static ssize_t -store_regs_fan_div_1(struct device *dev, const char *buf, size_t count) +store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct w83781d_data *data = i2c_get_clientdata(client); @@ -628,92 +628,28 @@ store_regs_fan_div_1(struct device *dev, const char *buf, size_t count) u8 reg; /* Save fan_min */ - min = FAN_FROM_REG(data->fan_min[0], - DIV_FROM_REG(data->fan_div[0])); + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); - data->fan_div[0] = DIV_TO_REG(simple_strtoul(buf, NULL, 10), + data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10), data->type); - reg = w83781d_read_value(client, W83781D_REG_VID_FANDIV) & 0xcf; - reg |= (data->fan_div[0] & 0x03) << 4; - w83781d_write_value(client, W83781D_REG_VID_FANDIV, reg); + reg = (w83781d_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) + & (nr==0 ? 0xcf : 0x3f)) + | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); + w83781d_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); /* w83781d and as99127f don't have extended divisor bits */ if (data->type != w83781d && data->type != as99127f) { - reg = w83781d_read_value(client, W83781D_REG_VBAT) & 0xdf; - reg |= (data->fan_div[0] & 0x04) << 3; + reg = (w83781d_read_value(client, W83781D_REG_VBAT) + & ~(1 << (5 + nr))) + | ((data->fan_div[nr] & 0x04) << (3 + nr)); w83781d_write_value(client, W83781D_REG_VBAT, reg); } /* Restore fan_min */ - data->fan_min[0] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[0])); - w83781d_write_value(client, W83781D_REG_FAN_MIN(1), data->fan_min[0]); - - return count; -} - -static ssize_t -store_regs_fan_div_2(struct device *dev, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - unsigned long min; - u8 reg; - - /* Save fan_min */ - min = FAN_FROM_REG(data->fan_min[1], - DIV_FROM_REG(data->fan_div[1])); - - data->fan_div[1] = DIV_TO_REG(simple_strtoul(buf, NULL, 10), - data->type); - - reg = w83781d_read_value(client, W83781D_REG_VID_FANDIV) & 0x3f; - reg |= (data->fan_div[1] & 0x03) << 6; - w83781d_write_value(client, W83781D_REG_VID_FANDIV, reg); - - /* w83781d and as99127f don't have extended divisor bits */ - if (data->type != w83781d && data->type != as99127f) { - reg = w83781d_read_value(client, W83781D_REG_VBAT) & 0xbf; - reg |= (data->fan_div[1] & 0x04) << 4; - w83781d_write_value(client, W83781D_REG_VBAT, reg); - } - - /* Restore fan_min */ - data->fan_min[1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[1])); - w83781d_write_value(client, W83781D_REG_FAN_MIN(2), data->fan_min[1]); - - return count; -} - -static ssize_t -store_regs_fan_div_3(struct device *dev, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - unsigned long min; - u8 reg; - - /* Save fan_min */ - min = FAN_FROM_REG(data->fan_min[2], - DIV_FROM_REG(data->fan_div[2])); - - data->fan_div[2] = DIV_TO_REG(simple_strtoul(buf, NULL, 10), - data->type); - - reg = w83781d_read_value(client, W83781D_REG_PIN) & 0x3f; - reg |= (data->fan_div[2] & 0x03) << 6; - w83781d_write_value(client, W83781D_REG_PIN, reg); - - /* w83781d and as99127f don't have extended divisor bits */ - if (data->type != w83781d && data->type != as99127f) { - reg = w83781d_read_value(client, W83781D_REG_VBAT) & 0x7f; - reg |= (data->fan_div[2] & 0x04) << 5; - w83781d_write_value(client, W83781D_REG_VBAT, reg); - } - - /* Restore fan_min */ - data->fan_min[2] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[2])); - w83781d_write_value(client, W83781D_REG_FAN_MIN(3), data->fan_min[2]); + data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + w83781d_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); return count; } @@ -723,6 +659,10 @@ static ssize_t show_regs_fan_div_##offset (struct device *dev, char *buf) \ { \ return show_fan_div_reg(dev, buf, offset); \ } \ +static ssize_t store_regs_fan_div_##offset (struct device *dev, const char *buf, size_t count) \ +{ \ + return store_fan_div_reg(dev, buf, count, offset - 1); \ +} \ static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset) sysfs_fan_div(1); -- cgit v1.2.3 From c395ba5176fa5979ba1a07b321ab96c5918412c4 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 18 Mar 2004 21:24:39 -0800 Subject: [PATCH] I2C: add new chip driver: pcf8574 Please find below a patch against kernel 2.6.5-rc1 to add the pcf8574 driver (an I/O expander for the I2C bus). I have ported it from the 2.4 version, and it includes some fixes and simplifications. It has been reviewed by Jean Delvare on IRC. --- drivers/i2c/chips/Kconfig | 11 ++ drivers/i2c/chips/Makefile | 1 + drivers/i2c/chips/pcf8574.c | 245 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 drivers/i2c/chips/pcf8574.c diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index a25be2fb0e05..a6907a795673 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -209,4 +209,15 @@ config SENSORS_EEPROM This driver can also be built as a module. If so, the module will be called eeprom. +config SENSORS_PCF8574 + tristate "Philips PCF8574 and PCF8574A" + depends on I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Philips PCF8574 and + PCF8574A chips. + + This driver can also be built as a module. If so, the module + will be called pcf8574. + endmenu diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 0e4941850d49..05ccac8572f0 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_SENSORS_LM80) += lm80.o obj-$(CONFIG_SENSORS_LM83) += lm83.o obj-$(CONFIG_SENSORS_LM85) += lm85.o obj-$(CONFIG_SENSORS_LM90) += lm90.o +obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c new file mode 100644 index 000000000000..3a0edc7d496d --- /dev/null +++ b/drivers/i2c/chips/pcf8574.c @@ -0,0 +1,245 @@ +/* + pcf8574.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 2000 Frodo Looijaard , + Philip Edelbrock , + Dan Eaton + Ported to Linux 2.6 by Aurelien Jarno with + the help of Jean Delvare + + 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 + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* A few notes about the PCF8574: + +* The PCF8574 is an 8-bit I/O expander for the I2C bus produced by + Philips Semiconductors. It is designed to provide a byte I2C + interface to up to 8 separate devices. + +* The PCF8574 appears as a very simple SMBus device which can be + read from or written to with SMBUS byte read/write accesses. + + --Dan + +*/ + +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { 0x20, 0x27, 0x38, 0x3f, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; +static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_2(pcf8574, pcf8574a); + +/* Initial values */ +#define PCF8574_INIT 255 /* All outputs on (input mode) */ + +/* Each client has this additional data */ +struct pcf8574_data { + struct semaphore update_lock; + + u8 read, write; /* Register values */ +}; + +static int pcf8574_attach_adapter(struct i2c_adapter *adapter); +static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind); +static int pcf8574_detach_client(struct i2c_client *client); +static void pcf8574_init_client(struct i2c_client *client); +static struct pcf8574_data *pcf8574_update_client(struct device *dev); + +/* This is the driver that will be inserted */ +static struct i2c_driver pcf8574_driver = { + .owner = THIS_MODULE, + .name = "pcf8574", + .id = I2C_DRIVERID_PCF8574, + .flags = I2C_DF_NOTIFY, + .attach_adapter = pcf8574_attach_adapter, + .detach_client = pcf8574_detach_client, +}; + +static int pcf8574_id = 0; + +/* following are the sysfs callback functions */ +static ssize_t show_read(struct device *dev, char *buf) +{ + struct pcf8574_data *data = pcf8574_update_client(dev); + return sprintf(buf, "%u\n", data->read); +} + +static DEVICE_ATTR(read, S_IRUGO, show_read, NULL); + +static ssize_t show_write(struct device *dev, char *buf) +{ + struct pcf8574_data *data = i2c_get_clientdata(to_i2c_client(dev)); + return sprintf(buf, "%u\n", data->write); +} + +static ssize_t set_write(struct device *dev, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pcf8574_data *data = i2c_get_clientdata(client); + data->write = simple_strtoul(buf, NULL, 10); + i2c_smbus_write_byte(client, data->write); + return count; +} + +static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write); + +/* + * Real code + */ + +static int pcf8574_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, pcf8574_detect); +} + +/* This function is called by i2c_detect */ +int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct pcf8574_data *data; + int err = 0; + const char *client_name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) + 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. */ + if (!(new_client = kmalloc(sizeof(struct i2c_client) + + sizeof(struct pcf8574_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + memset(new_client, 0, sizeof(struct i2c_client) + + sizeof(struct pcf8574_data)); + + data = (struct pcf8574_data *) (new_client + 1); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &pcf8574_driver; + new_client->flags = 0; + + /* Now, we would do the remaining detection. But the PCF8574 is plainly + impossible to detect! Stupid chip. */ + + /* Determine the chip type */ + if (kind <= 0) { + if (address >= 0x38 && address <= 0x3f) + kind = pcf8574a; + else + kind = pcf8574; + } + + if (kind == pcf8574a) + client_name = "pcf8574a"; + else + client_name = "pcf8574"; + + /* Fill in the remaining client fields and put it into the global list */ + strlcpy(new_client->name, client_name, I2C_NAME_SIZE); + + new_client->id = pcf8574_id++; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the PCF8574 chip */ + pcf8574_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_read); + device_create_file(&new_client->dev, &dev_attr_write); + return 0; + +/* OK, this is not exactly good programming practice, usually. But it is + very code-efficient in this case. */ + + exit_free: + kfree(new_client); + exit: + return err; +} + +static int pcf8574_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(client); + return 0; +} + +/* Called when we have found a new PCF8574. */ +static void pcf8574_init_client(struct i2c_client *client) +{ + struct pcf8574_data *data = i2c_get_clientdata(client); + data->write = PCF8574_INIT; + i2c_smbus_write_byte(client, data->write); +} + +static struct pcf8574_data *pcf8574_update_client(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pcf8574_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + dev_dbg(&client->dev, "Starting pcf8574 update\n"); + data->read = i2c_smbus_read_byte(client); + up(&data->update_lock); + + return data; +} + +static int __init pcf8574_init(void) +{ + return i2c_add_driver(&pcf8574_driver); +} + +static void __exit pcf8574_exit(void) +{ + i2c_del_driver(&pcf8574_driver); +} + + +MODULE_AUTHOR + ("Frodo Looijaard , " + "Philip Edelbrock , " + "Dan Eaton " + "and Aurelien Jarno "); +MODULE_DESCRIPTION("PCF8574 driver"); +MODULE_LICENSE("GPL"); + +module_init(pcf8574_init); +module_exit(pcf8574_exit); -- cgit v1.2.3 From b3da4be8eba471eb4666f7b27930fad4d43b1112 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 24 Mar 2004 18:50:47 -0800 Subject: [PATCH] I2C: Discard out-of-date comment in adm1021 driver This simple patch discards an out-of-date comment in the adm1021 driver. I've done the same in our CVS repository where many more drivers were affected. I agree it's not very important, but I prefer it to be done before any driver with the error is used as a base to port a new driver, and the misinformation spreads. --- drivers/i2c/chips/adm1021.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c index 4993add5adeb..38d2f668c2e3 100644 --- a/drivers/i2c/chips/adm1021.c +++ b/drivers/i2c/chips/adm1021.c @@ -151,9 +151,6 @@ static struct i2c_driver adm1021_driver = { .detach_client = adm1021_detach_client, }; -/* I choose here for semi-static allocation. Complete dynamic - allocation could also be used; the code needed for this would probably - take more memory than the datastructure takes now. */ static int adm1021_id = 0; #define show(value) \ -- cgit v1.2.3 From 7b218f51797e7dc1462bf2130d7135cfccf8cc3b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 24 Mar 2004 18:51:45 -0800 Subject: [PATCH] I2C: initialize fan_mins in w83781d, asb100 and lm78 Quoting myself: > While testing, I found a corner case that isn't handled properly. It > doesn't seem to be handled by the lm78 and the asb100 either. Setting > fanN_div before ever reading from the chip or setting fanN_min will > make use of fanN_min while it was never initialized. The following patch addesses the issue. Tested to work on my AS99127F rev.1 (which means that only the changes to the w83781d driver were actually tested). Testers welcome. --- drivers/i2c/chips/asb100.c | 5 +++++ drivers/i2c/chips/lm78.c | 6 ++++++ drivers/i2c/chips/w83781d.c | 6 ++++++ 3 files changed, 17 insertions(+) diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c index 3fbdee66fb66..873666c8d057 100644 --- a/drivers/i2c/chips/asb100.c +++ b/drivers/i2c/chips/asb100.c @@ -807,6 +807,11 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) /* Initialize the chip */ asb100_init_client(new_client); + /* A few vars need to be filled upon startup */ + data->fan_min[0] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(0)); + data->fan_min[1] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(1)); + data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2)); + /* Register sysfs hooks */ device_create_file_in(new_client, 0); device_create_file_in(new_client, 1); diff --git a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c index 43ceb35583f9..f2266b0fb273 100644 --- a/drivers/i2c/chips/lm78.c +++ b/drivers/i2c/chips/lm78.c @@ -625,6 +625,12 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind) /* Initialize the LM78 chip */ lm78_init_client(new_client); + /* A few vars need to be filled upon startup */ + for (i = 0; i < 3; i++) { + data->fan_min[i] = lm78_read_value(new_client, + LM78_REG_FAN_MIN(i)); + } + /* Register sysfs hooks */ device_create_file(&new_client->dev, &dev_attr_in0_input); device_create_file(&new_client->dev, &dev_attr_in0_min); diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index df887e2c49bd..57f96b671196 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c @@ -1252,6 +1252,12 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) /* Initialize the chip */ w83781d_init_client(new_client); + /* A few vars need to be filled upon startup */ + for (i = 1; i <= 3; i++) { + data->fan_min[i - 1] = w83781d_read_value(new_client, + W83781D_REG_FAN_MIN(i)); + } + /* Register sysfs hooks */ device_create_file_in(new_client, 0); if (kind != w83783s && kind != w83697hf) -- cgit v1.2.3 From 4b65ed3affb0e422ead205b7aa27f5988b655a41 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 25 Mar 2004 21:52:39 -0800 Subject: [PATCH] I2C: adm1021 (probably) does something VERY,VERY BAD Quoting myself: > 3* Drop adm1021's limit init. This was already done in the 2.4 driver > and should have been done in 2.6 as well. Here is a patch that does that. It also prevents bit 7 (and unused bits) of configuration register from being reset, as was discussed before: http://archives.andrew.net.au/lm-sensors/msg04593.html That second part needs to be backported to the 2.4 driver, and I will do so. Additionally, we get rid of a useless label. The patch is untested (I don't own any supported chip) but quite straightforward IMHO. --- drivers/i2c/chips/adm1021.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c index 38d2f668c2e3..da8acbd6bf94 100644 --- a/drivers/i2c/chips/adm1021.c +++ b/drivers/i2c/chips/adm1021.c @@ -98,10 +98,6 @@ SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1 they don't quite work like a thermostat the way the LM75 does. I.e., a lower temp than THYST actually triggers an alarm instead of clearing it. Weird, ey? --Phil */ -#define adm1021_INIT_TOS 60 -#define adm1021_INIT_THYST 20 -#define adm1021_INIT_REMOTE_TOS 60 -#define adm1021_INIT_REMOTE_THYST 20 /* Each client has this additional data */ struct adm1021_data { @@ -306,7 +302,7 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) - goto error3; + goto error1; /* Initialize the ADM1021 chip */ adm1021_init_client(new_client); @@ -324,7 +320,6 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) return 0; -error3: error1: kfree(new_client); error0: @@ -333,17 +328,9 @@ error0: static void adm1021_init_client(struct i2c_client *client) { - /* Initialize the adm1021 chip */ - adm1021_write_value(client, ADM1021_REG_TOS_W, - adm1021_INIT_TOS); - adm1021_write_value(client, ADM1021_REG_THYST_W, - adm1021_INIT_THYST); - adm1021_write_value(client, ADM1021_REG_REMOTE_TOS_W, - adm1021_INIT_REMOTE_TOS); - adm1021_write_value(client, ADM1021_REG_REMOTE_THYST_W, - adm1021_INIT_REMOTE_THYST); /* Enable ADC and disable suspend mode */ - adm1021_write_value(client, ADM1021_REG_CONFIG_W, 0); + adm1021_write_value(client, ADM1021_REG_CONFIG_W, + adm1021_read_value(client, ADM1021_REG_CONFIG_R) & 0xBF); /* Set Conversion rate to 1/sec (this can be tinkered with) */ adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04); } -- cgit v1.2.3 From 742647e98fcaed231d4fd6f525960251fbf09140 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 25 Mar 2004 21:53:01 -0800 Subject: [PATCH] I2C: Setting w83627hf fan_div preserves fan_min Here is a patch that updates the w83627hf driver in the exact same way I did recently for the w83781d driver. There were two problems: 1* Fan divisor storing code was ugly, badly ripped from the 2.4 w83627hf driver and/or the 2.6 w83781d driver. 2* Setting fan divisors wouldn't preserve fan mins. Exactly the same as w83781d: http://archives.andrew.net.au/lm-sensors/msg06952.html http://archives.andrew.net.au/lm-sensors/msg07008.html No surprise since the w83627hf driver is a fork of the w83781d driver. Since the two drivers are strongly similar, I took the code directly from the updated w83781d driver. I cannot test the w83627hf driver (testers welcome BTW) but this makes me feel confident that the code is correct. To make it clear, this single patch is the w83627f equivalent of the three patches I submitted for the w83781d: * Cleanup * Refactoring * Setting fan_div preserves fan_min All in one (much better looking BTW). --- drivers/i2c/chips/w83627hf.c | 54 +++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c index 94365849e3bb..030b08248cc0 100644 --- a/drivers/i2c/chips/w83627hf.c +++ b/drivers/i2c/chips/w83627hf.c @@ -659,34 +659,37 @@ show_fan_div_reg(struct device *dev, char *buf, int nr) (long) DIV_FROM_REG(data->fan_div[nr - 1])); } +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ static ssize_t store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val, old, old2, old3 = 0; + unsigned long min; + u8 reg; - val = simple_strtoul(buf, NULL, 10); - old = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); - old3 = w83627hf_read_value(client, W83781D_REG_VBAT); - data->fan_div[nr - 1] = DIV_TO_REG(val); - - if (nr >= 3 && data->type != w83697hf) { - old2 = w83627hf_read_value(client, W83781D_REG_PIN); - old2 = (old2 & 0x3f) | ((data->fan_div[2] & 0x03) << 6); - w83627hf_write_value(client, W83781D_REG_PIN, old2); - old3 = (old3 & 0x7f) | ((data->fan_div[2] & 0x04) << 5); - } - if (nr >= 2) { - old = (old & 0x3f) | ((data->fan_div[1] & 0x03) << 6); - old3 = (old3 & 0xbf) | ((data->fan_div[1] & 0x04) << 4); - } - if (nr >= 1) { - old = (old & 0xcf) | ((data->fan_div[0] & 0x03) << 4); - w83627hf_write_value(client, W83781D_REG_VID_FANDIV, old); - old3 = (old3 & 0xdf) | ((data->fan_div[0] & 0x04) << 3); - w83627hf_write_value(client, W83781D_REG_VBAT, old3); - } + /* Save fan_min */ + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + + data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10)); + + reg = (w83627hf_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) + & (nr==0 ? 0xcf : 0x3f)) + | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); + w83627hf_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); + + reg = (w83627hf_read_value(client, W83781D_REG_VBAT) + & ~(1 << (5 + nr))) + | ((data->fan_div[nr] & 0x04) << (3 + nr)); + w83627hf_write_value(client, W83781D_REG_VBAT, reg); + + /* Restore fan_min */ + data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); return count; } @@ -700,7 +703,7 @@ static ssize_t \ store_regs_fan_div_##offset (struct device *dev, \ const char *buf, size_t count) \ { \ - return store_fan_div_reg(dev, buf, count, offset); \ + return store_fan_div_reg(dev, buf, count, offset - 1); \ } \ static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ show_regs_fan_div_##offset, store_regs_fan_div_##offset) @@ -982,6 +985,11 @@ int w83627hf_detect(struct i2c_adapter *adapter, int address, /* Initialize the chip */ w83627hf_init_client(new_client); + /* A few vars need to be filled upon startup */ + data->fan_min[0] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(1)); + data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2)); + data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3)); + /* Register sysfs hooks */ device_create_file_in(new_client, 0); if (kind != w83697hf) -- cgit v1.2.3 From 9f3e7af6aa633b7c58c3939d9d81a748dfb67bc6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 29 Mar 2004 22:26:19 -0800 Subject: [PATCH] I2C: Prevent misdetections in adm1021 driver Yet another patch for the adm1021 chip driver. I refined the detection code a bit in order to prevent chip misdetection. Some chips handled by the adm1021 driver are hard to detect and identify (LM84 and MAX1617) so we tend to accept any chip it the valid I2C address range as one of these. It has caused much, much trouble already. See these threads for example: http://archives.andrew.net.au/lm-sensors/msg04448.html http://archives.andrew.net.au/lm-sensors/msg04624.html http://archives.andrew.net.au/lm-sensors/msg05560.html http://archives.andrew.net.au/lm-sensors/msg05871.html http://archives.andrew.net.au/lm-sensors/msg06754.html http://archives.andrew.net.au/lm-sensors/msg07181.html And this ticket: http://www2.lm-sensors.nu/~lm78/readticket.cgi?ticket=1434 So I thought it would be good to prevent this kind of problems if possible, and read the 8 datasheets again in search for ways to refine the detection method. I changed it in sensors-detect already, and had positive feedback from one user. I will also backport the changes to the driver to the 2.4 version we have in CVS. What the patch does: * Use unused bits of two more registers (configuration and conversion rate) to reduce misdetections. * Return with -ENODEV if the detection fails. * Change the order in which we try to identify the chips. We better finish with the LM84 and the MAX1617, in this order, because they are harder to identify and are more likely to result in false positives. * Refine LM84 detection. The LM84 has less features than the other chips(chip cannot be stopped, conversion rate cannot be set, no low limits) so it has extra unused bits. * Do not intialize the chip if it was detected as an LM84. This one cannot be stopped so why would we try to start it again? And as said right before, conversion rate isn't changeable either. Note that I couldn't test the changes on any supported chip since I don't own any. Still I believe that they should be applied, since the current code already broke one system and seriously harmed several others. I believe it's not critical if it turns out that we reject valid chips (which shouldn't happen if the datasheets are correct, anyway). People will simply let us know and we'll be less restrictive. In the meantime they can force the driver. That said, testers are welcome, as usual. --- drivers/i2c/chips/adm1021.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c index da8acbd6bf94..d38319b582ae 100644 --- a/drivers/i2c/chips/adm1021.c +++ b/drivers/i2c/chips/adm1021.c @@ -246,8 +246,12 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) /* Now, we do the remaining detection. */ if (kind < 0) { - if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00) + if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00 + || (adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x3F) != 0x00 + || (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) & 0xF8) != 0x00) { + err = -ENODEV; goto error1; + } } /* Determine the chip type. */ @@ -265,11 +269,14 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) else if ((i == 0x4d) && (adm1021_read_value(new_client, ADM1021_REG_DEV_ID) == 0x01)) kind = max1617a; - /* LM84 Mfr ID in a different place */ - else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00) - kind = lm84; else if (i == 0x54) kind = mc1066; + /* LM84 Mfr ID in a different place, and it has more unused bits */ + else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00 + && (kind == 0 /* skip extra detection */ + || ((adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x7F) == 0x00 + && (adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0xAB) == 0x00))) + kind = lm84; else kind = max1617; } @@ -305,7 +312,8 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) goto error1; /* Initialize the ADM1021 chip */ - adm1021_init_client(new_client); + if (kind != lm84) + adm1021_init_client(new_client); /* Register sysfs hooks */ device_create_file(&new_client->dev, &dev_attr_temp1_max); -- cgit v1.2.3 From 92e54f42420adf75b7e66103342ed5aa2237e257 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 29 Mar 2004 22:26:38 -0800 Subject: [PATCH] I2C: i2c documentation update (1/2) Here is an update to my 2.4 to 2.6 i2c client porting guide. The changes were inspired by the feedback I got with the drivers that have been ported so far. --- Documentation/i2c/porting-clients | 46 ++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients index fab37c46bbca..886d605ce33d 100644 --- a/Documentation/i2c/porting-clients +++ b/Documentation/i2c/porting-clients @@ -1,4 +1,4 @@ -Revision 3, 2003-10-04 +Revision 4, 2004-03-30 Jean Delvare Greg KH @@ -24,9 +24,10 @@ Technical changes: #include #include #include - #include /* if you need VRM support */ - #include /* if you have I/O operations */ - Some extra headers may be required for a given driver. + #include /* if you need VRM support */ + #include /* if you have I/O operations */ + Please respect this inclusion order. Some extra headers may be + required for a given driver (e.g. "lm75.h"). * [Addresses] SENSORS_I2C_END becomes I2C_CLIENT_END, SENSORS_ISA_END becomes I2C_CLIENT_ISA_END. @@ -37,9 +38,9 @@ Technical changes: names for sysfs files (see the Sysctl section below). * [Function prototypes] The detect functions loses its flags - parameter. Sysctl (e.g. lm75_temp) and miscellaneous (e.g. - swap_bytes) functions are off the list of prototypes. This - usually leaves five prototypes: + parameter. Sysctl (e.g. lm75_temp) and miscellaneous functions + are off the list of prototypes. This usually leaves five + prototypes: static int lm75_attach_adapter(struct i2c_adapter *adapter); static int lm75_detect(struct i2c_adapter *adapter, int address, int kind); @@ -70,13 +71,14 @@ Technical changes: * [Detect] As mentioned earlier, the flags parameter is gone. The type_name and client_name strings are replaced by a single name string, which will be filled with a lowercase, short string - (typically the driver name, e.g. "lm75"). The errorN labels are - reduced to the number needed. If that number is 2 (i2c-only - drivers), it is advised that the labels are named exit and - exit_free. For i2c+isa drivers, labels should be named ERROR0, - ERROR1 and ERROR2. Don't forget to properly set err before - jumping to error labels. By the way, labels should be - left-aligned. + (typically the driver name, e.g. "lm75"). + In i2c-only drivers, drop the i2c_is_isa_adapter check, it's + useless. + The errorN labels are reduced to the number needed. If that number + is 2 (i2c-only drivers), it is advised that the labels are named + exit and exit_free. For i2c+isa drivers, labels should be named + ERROR0, ERROR1 and ERROR2. Don't forget to properly set err before + jumping to error labels. By the way, labels should be left-aligned. Use memset to fill the client and data area with 0x00. Use i2c_set_clientdata to set the client data (as opposed to a direct access to client->data). @@ -85,6 +87,11 @@ Technical changes: device_create_file. Move the driver initialization before any sysfs file creation. +* [Init] Limits must not be set by the driver (can be done later in + user-space). Chip should not be reset default (although a module + parameter may be used to force is), and initialization should be + limited to the strictly necessary steps. + * [Detach] Get rid of data, remove the call to i2c_deregister_entry. @@ -92,7 +99,8 @@ Technical changes: i2c_get_clientdata(client) instead. * [Interface] Init function should not print anything. Make sure - there is a MODULE_LICENSE() line. + there is a MODULE_LICENSE() line, at the bottom of the file + (after MODULE_AUTHOR() and MODULE_DESCRIPTION(), in this order). Coding policy: @@ -102,8 +110,7 @@ Coding policy: can. Calls to printk/pr_debug for debugging purposes are replaced by calls to dev_dbg. Here is an example on how to call it (taken from lm75_detect): - dev_dbg(&adapter->dev, - "lm75_detect called for an ISA bus adapter?!?\n"); + dev_dbg(&client->dev, "Starting lm75 update\n"); Replace other printk calls with the dev_info, dev_err or dev_warn function, as appropriate. @@ -119,3 +126,8 @@ Coding policy: * [Layout] Avoid extra empty lines between comments and what they comment. Respect the coding style (see Documentation/CodingStyle), in particular when it comes to placing curly braces. + +* [Comments] Make sure that no comment refers to a file that isn't + part of the Linux source tree (typically doc/chips/), + and that remaining comments still match the code. Merging comment + lines when possible is encouraged. -- cgit v1.2.3 From a4a5e7cfe379fac657befc526ea1b6add11c0913 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 29 Mar 2004 22:26:52 -0800 Subject: [PATCH] I2C: i2c documentation update (2/2) Here is a patch to Documentation/i2c/sysfs-interface. This is mostly my intent to make the document more readable. There are also a few incorrectnesses fixed, and some comments added. --- Documentation/i2c/sysfs-interface | 78 +++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/Documentation/i2c/sysfs-interface b/Documentation/i2c/sysfs-interface index 97aa9b920023..f651de4873f8 100644 --- a/Documentation/i2c/sysfs-interface +++ b/Documentation/i2c/sysfs-interface @@ -74,18 +74,15 @@ to cause an alarm) is chip-dependent. ************ in[0-8]_min Voltage min value. - Fixed point value in form XXXX. Divide by 1000 to get - Volts. + Unit: millivolt Read/Write in[0-8]_max Voltage max value. - Fixed point value in form XXXX. Divide by 1000 to get - Volts. + Unit: millivolt Read/Write in[0-8]_input Voltage input value. - Fixed point value in form XXXX. Divide by 1000 to get - Volts. + Unit: millivolt Read only Actual voltage depends on the scaling resistors on the motherboard, as recommended in the chip datasheet. @@ -95,10 +92,10 @@ in[0-8]_input Voltage input value. However, some drivers (notably lm87 and via686a) do scale, with various degrees of success. These drivers will output the actual voltage. - First two values are read/write and third is read only. + Typical usage: in0_* CPU #1 voltage (not scaled) - in1_* CPU #1 voltage (not scaled) + in1_* CPU #2 voltage (not scaled) in2_* 3.3V nominal (not scaled) in3_* 5.0V nominal (scaled) in4_* 12.0V nominal (scaled) @@ -108,17 +105,16 @@ in[0-8]_input Voltage input value. in8_* varies in0_ref CPU core reference voltage. + Unit: millivolt Read only. - Fixed point value in form XXXX corresponding to CPU core - voltage as told to the sensor chip. Divide by 1000 to - get Volts. Not always correct. + Not always correct. vrm Voltage Regulator Module version number. Read only. - Two digit number (XX), first is major version, second is + Two digit number, first is major version, second is minor version. - Affects the way the driver calculates the core voltage from - the vid pins. See doc/vid for details. + Affects the way the driver calculates the CPU core reference + voltage from the vid pins. ******** @@ -126,23 +122,23 @@ vrm Voltage Regulator Module version number. ******** fan[1-3]_min Fan minimum value - Integer value indicating RPM + Unit: revolution/min (RPM) Read/Write. fan[1-3]_input Fan input value. - Integer value indicating RPM + Unit: revolution/min (RPM) Read only. fan[1-3]_div Fan divisor. - Integers in powers of two (1,2,4,8,16,32,64,128). - Some chips only support values 1,2,4,8. - See doc/fan-divisors for details. + Integer value in powers of two (1, 2, 4, 8, 16, 32, 64, 128). + Some chips only support values 1, 2, 4 and 8. + Note that this is actually an internal clock divisor, which + affects the measurable speed range, not the read value. fan[1-3]_pwm Pulse width modulation fan control. - Integer 0 - 255 + Integer value in the range 0 to 255 Read/Write 255 is max or 100%. - Corresponds to the fans 1-3. fan[1-3]_pwm_enable Switch PWM on and off. @@ -157,46 +153,46 @@ fan[1-3]_pwm_enable **************** temp[1-3]_type Sensor type selection. - Integers 1,2,3, or thermistor Beta value (3435) + Integers 1, 2, 3 or thermistor Beta value (3435) Read/Write. + 1: PII/Celeron Diode + 2: 3904 transistor + 3: thermal diode + Not all types are supported by all chips temp[1-4]_max Temperature max value. - Fixed point value in form XXXXX and should be divided by - 1000 to get degrees Celsius. + Unit: millidegree Celcius Read/Write value. temp[1-3]_min Temperature min value. - Fixed point value in form XXXXX and should be divided by - 1000 to get degrees Celsius. + Unit: millidegree Celcius Read/Write value. temp[1-3]_max_hyst Temperature hysteresis value for max limit. - Fixed point value in form XXXXX and should be divided by - 1000 to get degrees Celsius. Must be reported as an - absolute temperature, NOT a delta from the max value. + Unit: millidegree Celcius + Must be reported as an absolute temperature, NOT a delta + from the max value. Read/Write value. temp[1-4]_input Temperature input value. - Fixed point value in form XXXXX and should be divided by - 1000 to get degrees Celsius. + Unit: millidegree Celcius Read only value. temp[1-4]_crit Temperature critical value, typically greater than corresponding temp_max values. - Fixed point value in form XXXXX and should be divided by - 1000 to get degrees Celsius. + Unit: millidegree Celcius Read/Write value. temp[1-2]_crit_hyst Temperature hysteresis value for critical limit. - Fixed point value in form XXXXX and should be divided by - 1000 to get degrees Celsius. Must be reported as an - absolute temperature, NOT a delta from the critical value. + Unit: millidegree Celcius + Must be reported as an absolute temperature, NOT a delta + from the critical value. Read/Write value. If there are multiple temperature sensors, temp1_* is - generally the sensor inside the chip itself, generally + generally the sensor inside the chip itself, reported as "motherboard temperature". temp2_* to temp4_* are generally sensors external to the chip itself, for example the thermal diode inside the CPU or @@ -211,15 +207,15 @@ Note that no known chip provides current measurements as of writing, so this part is theoretical, so to say. curr[1-n]_max Current max value - Fixed point XXXXX, divide by 1000 to get Amps. + Unit: milliampere Read/Write. curr[1-n]_min Current min value. - Fixed point XXXXX, divide by 1000 to get Amps. + Unit: milliampere Read/Write. curr[1-n]_input Current input value - Fixed point XXXXX, divide by 1000 to get Amps. + Unit: milliampere Read only. @@ -246,7 +242,7 @@ beep_enable Beep/interrupt enable beep_mask Bitmask for beep. Same format as 'alarms' with the same bit locations. - Read only. + Read/Write eeprom Raw EEPROM data in binary form. Read only. -- cgit v1.2.3 From af109398ca4f3b235aaebb5037cd1edf232ccfb6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 29 Mar 2004 22:27:06 -0800 Subject: [PATCH] I2C: Incorrect memset in eeprom.c Quoting Ralf Roesch: > currently I'm only working with Linux MIPS 2.4 kernel, > so it would be nice if you could forward the patch for 2.6. OK, so here we are. Greg, this is the port to 2.6 of Ralf patch that fixes an incorrect memset while initializing the eeprom driver. Please apply. --- drivers/i2c/chips/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index bed325cd8c99..ee1f60d6a4d1 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -197,7 +197,7 @@ int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) sizeof(struct eeprom_data)); data = (struct eeprom_data *) (new_client + 1); - memset(data, 0xff, EEPROM_SIZE); + memset(data->data, 0xff, EEPROM_SIZE); i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; -- cgit v1.2.3 From ff74142ef27bb5886b093fa0de39470473a316e6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 29 Mar 2004 22:27:21 -0800 Subject: [PATCH] I2C: Discard pointless comment in via686a The simple patch below discards a comment in via686a referencing a file that doesn't belong to the Linux tree. Now that I tell people not to do that in my porting guide, we better follow our own advice. --- drivers/i2c/chips/via686a.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index ca1ee66668a2..3cff23b7f3c0 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c @@ -27,7 +27,6 @@ /* Supports the Via VT82C686A, VT82C686B south bridges. Reports all as a 686A. - See doc/chips/via686a for details. Warning - only supports a single device. */ -- cgit v1.2.3 From bb883e7c039fa5acc903c925de878b76c960eca6 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Thu, 1 Apr 2004 19:02:14 -0800 Subject: [PATCH] I2C: Add ALi 1563 Device ID to pci_ids.h --- include/linux/pci_ids.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 4582d414df81..554eda2eac27 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -994,6 +994,7 @@ #define PCI_DEVICE_ID_AL_M1531 0x1531 #define PCI_DEVICE_ID_AL_M1533 0x1533 #define PCI_DEVICE_ID_AL_M1541 0x1541 +#define PCI_DEVICE_ID_AL_M1563 0x1563 #define PCI_DEVICE_ID_AL_M1621 0x1621 #define PCI_DEVICE_ID_AL_M1631 0x1631 #define PCI_DEVICE_ID_AL_M1632 0x1632 -- cgit v1.2.3 From d8ff2b7fe9e1818c2d3ee4855cdfbf2bd1a1d3f3 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Thu, 1 Apr 2004 19:02:40 -0800 Subject: [PATCH] I2C: Add support for the ALi 1563 in the PCI IRQ routing code. --- arch/i386/pci/irq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 55c8ee19df4f..4f08e3adf5c6 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -590,12 +590,13 @@ static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router, { switch(device) { - case PCI_DEVICE_ID_AL_M1533: + case PCI_DEVICE_ID_AL_M1533: + case PCI_DEVICE_ID_AL_M1563: + printk("PCI: Using ALI IRQ Router\n"); r->name = "ALI"; r->get = pirq_ali_get; r->set = pirq_ali_set; return 1; - /* Should add 156x some day */ } return 0; } -- cgit v1.2.3 From 7c45e25cf8527bf4bb34bb22f1e2df7fd8c4d011 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Thu, 1 Apr 2004 19:03:04 -0800 Subject: [PATCH] I2C: Add ALi 1563 i2c driver The i2c interface on the 1563 is totally different than on both the 1533 and the 1535. It supports i2c 2.0, and happens to be nearly identical to the interface on the i810 chipsets. --- drivers/i2c/busses/Kconfig | 12 ++ drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-ali1563.c | 421 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 434 insertions(+) create mode 100644 drivers/i2c/busses/i2c-ali1563.c diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 002862328a03..f0175793a7af 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -5,6 +5,18 @@ menu "I2C Hardware Bus support" depends on I2C +config I2C_ALI1563 + tristate "ALI 1563" + depends on I2C && PCI && EXPERIMENTAL + help + If you say yes to this option, support will be included for the SMB + Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB + controller is part of the 7101 device, which is an ACPI-compliant + Power Management Unit (PMU). + + This driver can also be built as a module. If so, the module + will be called i2c-ali1563. + config I2C_ALI1535 tristate "ALI 1535" depends on I2C && PCI && EXPERIMENTAL diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 1253bca5cbb9..952a580ae879 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o +obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c new file mode 100644 index 000000000000..b66f26bd7e92 --- /dev/null +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -0,0 +1,421 @@ +/** + * i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge + * + * Copyright (C) 2004 Patrick Mochel + * + * The 1563 southbridge is deceptively similar to the 1533, with a + * few notable exceptions. One of those happens to be the fact they + * upgraded the i2c core to be 2.0 compliant, and happens to be almost + * identical to the i2c controller found in the Intel 801 south + * bridges. + * + * This driver is based on a mix of the 15x3, 1535, and i801 drivers, + * with a little help from the ALi 1563 spec. + * + * This file is released under the GPLv2 + */ + +#include +#ifdef CONFIG_I2C_DEBUG_BUS +#define DEBUG 0 +#endif + +#include +#include +#include +#include + +#define ALI1563_MAX_TIMEOUT 500 +#define ALI1563_SMBBA 0x80 +#define ALI1563_SMB_IOEN 1 +#define ALI1563_SMB_HOSTEN 2 +#define ALI1563_SMB_IOSIZE 16 + +#define SMB_HST_STS (ali1563_smba + 0) +#define SMB_HST_CNTL1 (ali1563_smba + 1) +#define SMB_HST_CNTL2 (ali1563_smba + 2) +#define SMB_HST_CMD (ali1563_smba + 3) +#define SMB_HST_ADD (ali1563_smba + 4) +#define SMB_HST_DAT0 (ali1563_smba + 5) +#define SMB_HST_DAT1 (ali1563_smba + 6) +#define SMB_BLK_DAT (ali1563_smba + 7) + +#define HST_STS_BUSY 0x01 +#define HST_STS_INTR 0x02 +#define HST_STS_DEVERR 0x04 +#define HST_STS_BUSERR 0x08 +#define HST_STS_FAIL 0x10 +#define HST_STS_DONE 0x80 +#define HST_STS_BAD 0x1c + + +#define HST_CNTL1_TIMEOUT 0x80 +#define HST_CNTL1_LAST 0x40 + +#define HST_CNTL2_KILL 0x04 +#define HST_CNTL2_START 0x40 +#define HST_CNTL2_QUICK 0x00 +#define HST_CNTL2_BYTE 0x01 +#define HST_CNTL2_BYTE_DATA 0x02 +#define HST_CNTL2_WORD_DATA 0x03 +#define HST_CNTL2_BLOCK 0x05 + + + +static unsigned short ali1563_smba; + +static int ali1563_transaction(struct i2c_adapter * a) +{ + u32 data; + int timeout; + + dev_dbg(&a->dev, "Transaction (pre): STS=%02x, CNTL1=%02x, " + "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", + inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), + inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), + inb_p(SMB_HST_DAT1)); + + data = inb_p(SMB_HST_STS); + if (data & HST_STS_BAD) { + dev_warn(&a->dev,"ali1563: Trying to reset busy device\n"); + outb_p(data | HST_STS_BAD,SMB_HST_STS); + data = inb_p(SMB_HST_STS); + if (data & HST_STS_BAD) + return -EBUSY; + } + outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2); + + timeout = ALI1563_MAX_TIMEOUT; + do + i2c_delay(1); + while (((data = inb_p(SMB_HST_STS)) & HST_STS_BUSY) && --timeout); + + dev_dbg(&a->dev, "Transaction (post): STS=%02x, CNTL1=%02x, " + "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", + inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), + inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), + inb_p(SMB_HST_DAT1)); + + if (timeout && !(data & HST_STS_BAD)) + return 0; + dev_warn(&a->dev, "SMBus Error: %s%s%s%s%s\n", + timeout ? "Timeout " : "", + data & HST_STS_FAIL ? "Transaction Failed " : "", + data & HST_STS_BUSERR ? "No response or Bus Collision " : "", + data & HST_STS_DEVERR ? "Device Error " : "", + !(data & HST_STS_DONE) ? "Transaction Never Finished " : ""); + + if (!(data & HST_STS_DONE)) + /* Issue 'kill' to host controller */ + outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2); + else + /* Issue timeout to reset all devices on bus */ + outb_p(HST_CNTL1_TIMEOUT,SMB_HST_CNTL1); + return -1; +} + +static int ali1563_block_start(struct i2c_adapter * a) +{ + u32 data; + int timeout; + + dev_dbg(&a->dev, "Block (pre): STS=%02x, CNTL1=%02x, " + "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", + inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), + inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), + inb_p(SMB_HST_DAT1)); + + data = inb_p(SMB_HST_STS); + if (data & HST_STS_BAD) { + dev_warn(&a->dev,"ali1563: Trying to reset busy device\n"); + outb_p(data | HST_STS_BAD,SMB_HST_STS); + data = inb_p(SMB_HST_STS); + if (data & HST_STS_BAD) + return -EBUSY; + } + + /* Clear byte-ready bit */ + outb_p(data | HST_STS_DONE, SMB_HST_STS); + + /* Start transaction and wait for byte-ready bit to be set */ + outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2); + + timeout = ALI1563_MAX_TIMEOUT; + do + i2c_delay(1); + while (!((data = inb_p(SMB_HST_STS)) & HST_STS_DONE) && --timeout); + + dev_dbg(&a->dev, "Block (post): STS=%02x, CNTL1=%02x, " + "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", + inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), + inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), + inb_p(SMB_HST_DAT1)); + + if (timeout && !(data & HST_STS_BAD)) + return 0; + dev_warn(&a->dev, "SMBus Error: %s%s%s%s%s\n", + timeout ? "Timeout " : "", + data & HST_STS_FAIL ? "Transaction Failed " : "", + data & HST_STS_BUSERR ? "No response or Bus Collision " : "", + data & HST_STS_DEVERR ? "Device Error " : "", + !(data & HST_STS_DONE) ? "Transaction Never Finished " : ""); + return -1; +} + +static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8 rw) +{ + int i, len; + int error = 0; + + /* Do we need this? */ + outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1); + + if (rw == I2C_SMBUS_WRITE) { + len = data->block[0]; + if (len < 1) + len = 1; + else if (len > 32) + len = 32; + outb_p(len,SMB_HST_DAT0); + outb_p(data->block[1],SMB_BLK_DAT); + } else + len = 32; + + outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_BLOCK, SMB_HST_CNTL2); + + for (i = 0; i < len; i++) { + if (rw == I2C_SMBUS_WRITE) { + outb_p(data->block[i + 1], SMB_BLK_DAT); + if ((error = ali1563_block_start(a))) + break; + } else { + if ((error = ali1563_block_start(a))) + break; + if (i == 0) { + len = inb_p(SMB_HST_DAT0); + if (len < 1) + len = 1; + else if (len > 32) + len = 32; + } + data->block[i+1] = inb_p(SMB_BLK_DAT); + } + } + /* Do we need this? */ + outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1); + return error; +} + +static s32 ali1563_access(struct i2c_adapter * a, u16 addr, + unsigned short flags, char rw, u8 cmd, + int size, union i2c_smbus_data * data) +{ + int error = 0; + int timeout; + u32 reg; + + for (timeout = ALI1563_MAX_TIMEOUT; timeout; timeout--) { + if (!(reg = inb_p(SMB_HST_STS) & HST_STS_BUSY)) + break; + } + if (!timeout) + dev_warn(&a->dev,"SMBus not idle. HST_STS = %02x\n",reg); + outb_p(0xff,SMB_HST_STS); + + /* Map the size to what the chip understands */ + switch (size) { + case I2C_SMBUS_PROC_CALL: + dev_err(&a->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); + error = -EINVAL; + break; + case I2C_SMBUS_QUICK: + size = HST_CNTL2_QUICK; + break; + case I2C_SMBUS_BYTE: + size = HST_CNTL2_BYTE; + break; + case I2C_SMBUS_BYTE_DATA: + size = HST_CNTL2_BYTE_DATA; + break; + case I2C_SMBUS_WORD_DATA: + size = HST_CNTL2_WORD_DATA; + break; + case I2C_SMBUS_BLOCK_DATA: + size = HST_CNTL2_BLOCK; + break; + } + + outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD); + outb_p(inb_p(SMB_HST_CNTL2) | (size << 3), SMB_HST_CNTL2); + + /* Write the command register */ + switch(size) { + case HST_CNTL2_BYTE: + if (rw== I2C_SMBUS_WRITE) + outb_p(cmd, SMB_HST_CMD); + break; + case HST_CNTL2_BYTE_DATA: + outb_p(cmd, SMB_HST_CMD); + if (rw == I2C_SMBUS_WRITE) + outb_p(data->byte, SMB_HST_DAT0); + break; + case HST_CNTL2_WORD_DATA: + outb_p(cmd, SMB_HST_CMD); + if (rw == I2C_SMBUS_WRITE) { + outb_p(data->word & 0xff, SMB_HST_DAT0); + outb_p((data->word & 0xff00) >> 8, SMB_HST_DAT1); + } + break; + case HST_CNTL2_BLOCK: + outb_p(cmd, SMB_HST_CMD); + error = ali1563_block(a,data,rw); + goto Done; + } + + if ((error = ali1563_transaction(a))) + goto Done; + + if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK)) + goto Done; + + switch (size) { + case HST_CNTL2_BYTE: /* Result put in SMBHSTDAT0 */ + data->byte = inb_p(SMB_HST_DAT0); + break; + case HST_CNTL2_BYTE_DATA: + data->byte = inb_p(SMB_HST_DAT0); + break; + case HST_CNTL2_WORD_DATA: + data->word = inb_p(SMB_HST_DAT0) + (inb_p(SMB_HST_DAT1) << 8); + break; + } +Done: + return error; +} + +static u32 ali1563_func(struct i2c_adapter * a) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA; +} + + +static void ali1563_enable(struct pci_dev * dev) +{ + u16 ctrl; + + pci_read_config_word(dev,ALI1563_SMBBA,&ctrl); + ctrl |= 0x7; + pci_write_config_word(dev,ALI1563_SMBBA,ctrl); +} + +static int __init ali1563_setup(struct pci_dev * dev) +{ + u16 ctrl; + + pci_read_config_word(dev,ALI1563_SMBBA,&ctrl); + printk("ali1563: SMBus control = %04x\n",ctrl); + + /* Check if device is even enabled first */ + if (!(ctrl & ALI1563_SMB_IOEN)) { + dev_warn(&dev->dev,"I/O space not enabled, trying manually\n"); + ali1563_enable(dev); + } + if (!(ctrl & ALI1563_SMB_IOEN)) { + dev_warn(&dev->dev,"I/O space still not enabled, giving up\n"); + goto Err; + } + if (!(ctrl & ALI1563_SMB_HOSTEN)) { + dev_warn(&dev->dev,"Host Controller not enabled\n"); + goto Err; + } + + /* SMB I/O Base in high 12 bits and must be aligned with the + * size of the I/O space. */ + ali1563_smba = ctrl & ~(ALI1563_SMB_IOSIZE - 1); + if (!ali1563_smba) { + dev_warn(&dev->dev,"ali1563_smba Uninitialized\n"); + goto Err; + } + if (!request_region(ali1563_smba,ALI1563_SMB_IOSIZE,"i2c-ali1563")) { + dev_warn(&dev->dev,"Could not allocate I/O space"); + goto Err; + } + + return 0; +Err: + return -ENODEV; +} + +static void __exit ali1563_shutdown(struct pci_dev * dev) +{ + release_region(ali1563_smba,ALI1563_SMB_IOSIZE); +} + +static struct i2c_algorithm ali1563_algorithm = { + .name = "Non-i2c SMBus adapter", + .id = I2C_ALGO_SMBUS, + .smbus_xfer = ali1563_access, + .functionality = ali1563_func, +}; + +static struct i2c_adapter ali1563_adapter = { + .owner = THIS_MODULE, + .algo = &ali1563_algorithm, +}; + +static int __init ali1563_probe(struct pci_dev * dev, + const struct pci_device_id * id_table) +{ + int error; + + if ((error = ali1563_setup(dev))) + return error; + ali1563_adapter.dev.parent = &dev->dev; + sprintf(ali1563_adapter.name,"SMBus ALi 1563 Adapter @ %04x", + ali1563_smba); + if ((error = i2c_add_adapter(&ali1563_adapter))) + ali1563_shutdown(dev); + printk("%s: Returning %d\n",__FUNCTION__,error); + return error; +} + +static void __exit ali1563_remove(struct pci_dev * dev) +{ + i2c_del_adapter(&ali1563_adapter); + ali1563_shutdown(dev); +} + +static struct pci_device_id __devinitdata ali1563_id_table[] = { + { + .vendor = PCI_VENDOR_ID_AL, + .device = PCI_DEVICE_ID_AL_M1563, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + {}, +}; + +static struct pci_driver ali1563_pci_driver = { + .name = "i2c-ali1563", + .id_table = ali1563_id_table, + .probe = ali1563_probe, + .remove = ali1563_remove, +}; + +static int __init ali1563_init(void) +{ + return pci_module_init(&ali1563_pci_driver); +} + +module_init(ali1563_init); + +static void __exit ali1563_exit(void) +{ + pci_unregister_driver(&ali1563_pci_driver); +} + +module_exit(ali1563_exit); + +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 11eff1d6fc1da5c7d66938f3184bd7ae910a7cc0 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Thu, 1 Apr 2004 19:05:14 -0800 Subject: [PATCH] I2C: Fix check for DEBUG in i2c-ali1563 --- drivers/i2c/busses/i2c-ali1563.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index b66f26bd7e92..27a6fc4eb923 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -15,11 +15,6 @@ * This file is released under the GPLv2 */ -#include -#ifdef CONFIG_I2C_DEBUG_BUS -#define DEBUG 0 -#endif - #include #include #include -- cgit v1.2.3 From e6a188235cd61c064fd76a465c20d52bd84c97ec Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 7 Apr 2004 20:23:27 -0700 Subject: [PATCH] I2C: Refactor swap_bytes in i2c chip drivers > Ick, no, we should be using the proper kernel call for this, swab16(), > right? Care to redo this patch to just fix the drivers and get rid of > our duplicating of this function. Oh, I didn't know such a function existed, sorry. Here's a new patch, hope you like it. Tested to work on my as99127f, btw (w83781d driver). Documentation update follows (well, tomorrow it does). --- drivers/i2c/chips/asb100.c | 15 +++++---------- drivers/i2c/chips/ds1621.c | 10 ++-------- drivers/i2c/chips/gl518sm.c | 10 ++-------- drivers/i2c/chips/lm75.c | 10 ++-------- drivers/i2c/chips/w83781d.c | 20 +++++--------------- 5 files changed, 16 insertions(+), 49 deletions(-) diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c index 873666c8d057..0acd9202b018 100644 --- a/drivers/i2c/chips/asb100.c +++ b/drivers/i2c/chips/asb100.c @@ -862,11 +862,6 @@ static int asb100_detach_client(struct i2c_client *client) return 0; } -static u16 swap_bytes(u16 val) -{ - return (val >> 8) | (val << 8); -} - /* The SMBus locks itself, usually, but nothing may access the chip between bank switches. */ static int asb100_read_value(struct i2c_client *client, u16 reg) @@ -891,17 +886,17 @@ static int asb100_read_value(struct i2c_client *client, u16 reg) /* convert from ISA to LM75 I2C addresses */ switch (reg & 0xff) { case 0x50: /* TEMP */ - res = swap_bytes(i2c_smbus_read_word_data (cl, 0)); + res = swab16(i2c_smbus_read_word_data (cl, 0)); break; case 0x52: /* CONFIG */ res = i2c_smbus_read_byte_data(cl, 1); break; case 0x53: /* HYST */ - res = swap_bytes(i2c_smbus_read_word_data (cl, 2)); + res = swab16(i2c_smbus_read_word_data (cl, 2)); break; case 0x55: /* MAX */ default: - res = swap_bytes(i2c_smbus_read_word_data (cl, 3)); + res = swab16(i2c_smbus_read_word_data (cl, 3)); break; } } @@ -939,10 +934,10 @@ static void asb100_write_value(struct i2c_client *client, u16 reg, u16 value) i2c_smbus_write_byte_data(cl, 1, value & 0xff); break; case 0x53: /* HYST */ - i2c_smbus_write_word_data(cl, 2, swap_bytes(value)); + i2c_smbus_write_word_data(cl, 2, swab16(value)); break; case 0x55: /* MAX */ - i2c_smbus_write_word_data(cl, 3, swap_bytes(value)); + i2c_smbus_write_word_data(cl, 3, swab16(value)); break; } } diff --git a/drivers/i2c/chips/ds1621.c b/drivers/i2c/chips/ds1621.c index 694de51952f5..b057ea96d985 100644 --- a/drivers/i2c/chips/ds1621.c +++ b/drivers/i2c/chips/ds1621.c @@ -97,11 +97,6 @@ static struct i2c_driver ds1621_driver = { static int ds1621_id = 0; -static u16 swap_bytes(u16 val) -{ - return (val >> 8) | (val << 8); -} - /* All registers are word-sized, except for the configuration register. DS1621 uses a high-byte first convention, which is exactly opposite to the usual practice. */ @@ -110,7 +105,7 @@ static int ds1621_read_value(struct i2c_client *client, u8 reg) if (reg == DS1621_REG_CONF) return i2c_smbus_read_byte_data(client, reg); else - return swap_bytes(i2c_smbus_read_word_data(client, reg)); + return swab16(i2c_smbus_read_word_data(client, reg)); } /* All registers are word-sized, except for the configuration register. @@ -121,8 +116,7 @@ static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) if (reg == DS1621_REG_CONF) return i2c_smbus_write_byte_data(client, reg, value); else - return i2c_smbus_write_word_data(client, reg, - swap_bytes(value)); + return i2c_smbus_write_word_data(client, reg, swab16(value)); } static void ds1621_init_client(struct i2c_client *client) diff --git a/drivers/i2c/chips/gl518sm.c b/drivers/i2c/chips/gl518sm.c index 224a497f04f4..d12c204e0125 100644 --- a/drivers/i2c/chips/gl518sm.c +++ b/drivers/i2c/chips/gl518sm.c @@ -484,18 +484,13 @@ static int gl518_detach_client(struct i2c_client *client) return 0; } -static inline u16 swap_bytes(u16 val) -{ - return (val >> 8) | (val << 8); -} - /* Registers 0x07 to 0x0c are word-sized, others are byte-sized GL518 uses a high-byte first convention, which is exactly opposite to the usual practice. */ static int gl518_read_value(struct i2c_client *client, u8 reg) { if ((reg >= 0x07) && (reg <= 0x0c)) - return swap_bytes(i2c_smbus_read_word_data(client, reg)); + return swab16(i2c_smbus_read_word_data(client, reg)); else return i2c_smbus_read_byte_data(client, reg); } @@ -506,8 +501,7 @@ static int gl518_read_value(struct i2c_client *client, u8 reg) static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value) { if ((reg >= 0x07) && (reg <= 0x0c)) - return i2c_smbus_write_word_data(client, reg, - swap_bytes(value)); + return i2c_smbus_write_word_data(client, reg, swab16(value)); else return i2c_smbus_write_byte_data(client, reg, value); } diff --git a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c index c5496dd21260..a1616fd6319b 100644 --- a/drivers/i2c/chips/lm75.c +++ b/drivers/i2c/chips/lm75.c @@ -206,11 +206,6 @@ static int lm75_detach_client(struct i2c_client *client) return 0; } -static u16 swap_bytes(u16 val) -{ - return (val >> 8) | (val << 8); -} - /* All registers are word-sized, except for the configuration register. LM75 uses a high-byte first convention, which is exactly opposite to the usual practice. */ @@ -219,7 +214,7 @@ static int lm75_read_value(struct i2c_client *client, u8 reg) if (reg == LM75_REG_CONF) return i2c_smbus_read_byte_data(client, reg); else - return swap_bytes(i2c_smbus_read_word_data(client, reg)); + return swab16(i2c_smbus_read_word_data(client, reg)); } /* All registers are word-sized, except for the configuration register. @@ -230,8 +225,7 @@ static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) if (reg == LM75_REG_CONF) return i2c_smbus_write_byte_data(client, reg, value); else - return i2c_smbus_write_word_data(client, reg, - swap_bytes(value)); + return i2c_smbus_write_word_data(client, reg, swab16(value)); } static void lm75_init_client(struct i2c_client *client) diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index 57f96b671196..af96cab0a828 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c @@ -275,11 +275,6 @@ static int w83781d_write_value(struct i2c_client *client, u16 register, static struct w83781d_data *w83781d_update_device(struct device *dev); static void w83781d_init_client(struct i2c_client *client); -static inline u16 swap_bytes(u16 val) -{ - return (val >> 8) | (val << 8); -} - static struct i2c_driver w83781d_driver = { .owner = THIS_MODULE, .name = "w83781d", @@ -1407,20 +1402,17 @@ w83781d_read_value(struct i2c_client *client, u16 reg) /* convert from ISA to LM75 I2C addresses */ switch (reg & 0xff) { case 0x50: /* TEMP */ - res = - swap_bytes(i2c_smbus_read_word_data(cl, 0)); + res = swab16(i2c_smbus_read_word_data(cl, 0)); break; case 0x52: /* CONFIG */ res = i2c_smbus_read_byte_data(cl, 1); break; case 0x53: /* HYST */ - res = - swap_bytes(i2c_smbus_read_word_data(cl, 2)); + res = swab16(i2c_smbus_read_word_data(cl, 2)); break; case 0x55: /* OVER */ default: - res = - swap_bytes(i2c_smbus_read_word_data(cl, 3)); + res = swab16(i2c_smbus_read_word_data(cl, 3)); break; } } @@ -1481,12 +1473,10 @@ w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) i2c_smbus_write_byte_data(cl, 1, value & 0xff); break; case 0x53: /* HYST */ - i2c_smbus_write_word_data(cl, 2, - swap_bytes(value)); + i2c_smbus_write_word_data(cl, 2, swab16(value)); break; case 0x55: /* OVER */ - i2c_smbus_write_word_data(cl, 3, - swap_bytes(value)); + i2c_smbus_write_word_data(cl, 3, swab16(value)); break; } } -- cgit v1.2.3 From a0f8eb34fb8daabc343e8f9f7aaeecdbf7a9ea99 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Thu, 8 Apr 2004 00:12:22 -0700 Subject: [PATCH] I2C: class fixup for the ali1563 driver --- drivers/i2c/busses/i2c-ali1563.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 27a6fc4eb923..1343de7c73b1 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -357,6 +357,7 @@ static struct i2c_algorithm ali1563_algorithm = { static struct i2c_adapter ali1563_adapter = { .owner = THIS_MODULE, + .class = I2C_ADAP_CLASS_SMBUS, .algo = &ali1563_algorithm, }; -- cgit v1.2.3 From 94da7b6b251edbc1f93acdbfb009ec75df55d8bf Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 8 Apr 2004 00:12:39 -0700 Subject: [PATCH] I2C: i2c-ali1563.c section fix ali1563_shutdown() is called from __init ali1563_probe() and hence cannot be marked __init. --- drivers/i2c/busses/i2c-ali1563.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 1343de7c73b1..3807c96821f1 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -343,7 +343,7 @@ Err: return -ENODEV; } -static void __exit ali1563_shutdown(struct pci_dev * dev) +static void ali1563_shutdown(struct pci_dev *dev) { release_region(ali1563_smba,ALI1563_SMB_IOSIZE); } -- cgit v1.2.3 From 640bbbb57bf71cfd0cff8b48624c4b5d3ed9a226 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 8 Apr 2004 21:58:21 -0700 Subject: [PATCH] I2C: Enable changing fan_divs in lm80 driver For some reason the original lm80 driver in 2.6 cannot set fan_divs (while the 2.4 driver could). This patch brings support back. It was lightly tested by one user. This patch also suggests some code cleanups (fan code refactoring). I'll send a different patch later for these. --- drivers/i2c/chips/lm80.c | 57 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/chips/lm80.c b/drivers/i2c/chips/lm80.c index 480927677cb3..2fe0188b2172 100644 --- a/drivers/i2c/chips/lm80.c +++ b/drivers/i2c/chips/lm80.c @@ -44,10 +44,9 @@ SENSORS_INSMOD_1(lm80); #define LM80_REG_IN_MIN(nr) (0x2b + (nr) * 2) #define LM80_REG_IN(nr) (0x20 + (nr)) -#define LM80_REG_FAN1_MIN 0x3c -#define LM80_REG_FAN2_MIN 0x3d #define LM80_REG_FAN1 0x28 #define LM80_REG_FAN2 0x29 +#define LM80_REG_FAN_MIN(nr) (0x3b + (nr)) #define LM80_REG_TEMP 0x27 #define LM80_REG_TEMP_HOT_MAX 0x38 @@ -250,8 +249,46 @@ static ssize_t set_fan_##suffix(struct device *dev, const char *buf, \ lm80_write_value(client, reg, data->value); \ return count; \ } -set_fan(min1, fan_min[0], LM80_REG_FAN1_MIN, fan_div[0]); -set_fan(min2, fan_min[1], LM80_REG_FAN2_MIN, fan_div[1]); +set_fan(min1, fan_min[0], LM80_REG_FAN_MIN(1), fan_div[0]); +set_fan(min2, fan_min[1], LM80_REG_FAN_MIN(2), fan_div[1]); + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm80_data *data = i2c_get_clientdata(client); + unsigned long min; + u8 reg; + + /* Save fan_min */ + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + + data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10)); + + reg = (lm80_read_value(client, LM80_REG_FANDIV) & ~(3 << (2 * (nr + 1)))) + | (data->fan_div[nr] << (2 * (nr + 1))); + lm80_write_value(client, LM80_REG_FANDIV, reg); + + /* Restore fan_min */ + data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]); + + return count; +} + +#define set_fan_div(number) \ +static ssize_t set_fan_div##number(struct device *dev, const char *buf, \ + size_t count) \ +{ \ + return set_fan_div(dev, buf, count, number - 1); \ +} +set_fan_div(1); +set_fan_div(2); static ssize_t show_temp_input1(struct device *dev, char *buf) { @@ -319,8 +356,8 @@ static DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min2, set_fan_min2); static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL); static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL); -static DEVICE_ATTR(fan1_div, S_IRUGO, show_fan_div1, NULL); -static DEVICE_ATTR(fan2_div, S_IRUGO, show_fan_div2, NULL); +static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div1, set_fan_div1); +static DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div2, set_fan_div2); static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_hot_max, set_temp_hot_max); @@ -401,6 +438,10 @@ int lm80_detect(struct i2c_adapter *adapter, int address, int kind) /* Initialize the LM80 chip */ lm80_init_client(new_client); + /* A few vars need to be filled upon startup */ + data->fan_min[0] = lm80_read_value(new_client, LM80_REG_FAN_MIN(1)); + data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2)); + /* Register sysfs hooks */ device_create_file(&new_client->dev, &dev_attr_in0_min); device_create_file(&new_client->dev, &dev_attr_in1_min); @@ -504,10 +545,10 @@ static struct lm80_data *lm80_update_device(struct device *dev) } data->fan[0] = lm80_read_value(client, LM80_REG_FAN1); data->fan_min[0] = - lm80_read_value(client, LM80_REG_FAN1_MIN); + lm80_read_value(client, LM80_REG_FAN_MIN(1)); data->fan[1] = lm80_read_value(client, LM80_REG_FAN2); data->fan_min[1] = - lm80_read_value(client, LM80_REG_FAN2_MIN); + lm80_read_value(client, LM80_REG_FAN_MIN(2)); data->temp = (lm80_read_value(client, LM80_REG_TEMP) << 8) | -- cgit v1.2.3 From fffab9e05930a8dea5867f51ba3b7e94f26f03fe Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 8 Apr 2004 22:05:44 -0700 Subject: [PATCH] I2C: New chip driver: pcf8591 Please find below a patch against kernel 2.6.5-rc2-mm4 to add the pcf8591 driver (a 8-bit A/D and D/A converter). I have ported it from the 2.4 version, and it includes some fixes, improvements and simplifications. It has been reviewed by Jean Delvare on IRC. Please also note that the patch also fixes a missing space in drivers/i2c/chips/Kconfig, introduced by the previous patch I sent you concerning the pcf8574. --- drivers/i2c/chips/Kconfig | 12 +- drivers/i2c/chips/Makefile | 1 + drivers/i2c/chips/pcf8591.c | 321 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 drivers/i2c/chips/pcf8591.c diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index a6907a795673..e005b02484b8 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -217,7 +217,17 @@ config SENSORS_PCF8574 If you say yes here you get support for Philips PCF8574 and PCF8574A chips. - This driver can also be built as a module. If so, the module + This driver can also be built as a module. If so, the module will be called pcf8574. +config SENSORS_PCF8591 + tristate "Philips PCF8591" + depends on I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Philips PCF8591 chips. + + This driver can also be built as a module. If so, the module + will be called pcf8591. + endmenu diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 05ccac8572f0..6de7d4711612 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_SENSORS_LM83) += lm83.o obj-$(CONFIG_SENSORS_LM85) += lm85.o obj-$(CONFIG_SENSORS_LM90) += lm90.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o +obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c new file mode 100644 index 000000000000..bdad91a3b044 --- /dev/null +++ b/drivers/i2c/chips/pcf8591.c @@ -0,0 +1,321 @@ +/* + pcf8591.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (C) 2001-2004 Aurelien Jarno + Ported to Linux 2.6 by Aurelien Jarno with + the help of Jean Delvare + + 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 + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { 0x48, 0x4f, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; +static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(pcf8591); + +static int input_mode; +MODULE_PARM(input_mode, "i"); +MODULE_PARM_DESC(input_mode, + "Analog input mode:\n" + " 0 = four single ended inputs\n" + " 1 = three differential inputs\n" + " 2 = single ended and differential mixed\n" + " 3 = two differential inputs\n"); + +/* The PCF8591 control byte + 7 6 5 4 3 2 1 0 + | 0 |AOEF| AIP | 0 |AINC| AICH | */ + +/* Analog Output Enable Flag (analog output active if 1) */ +#define PCF8591_CONTROL_AOEF 0x40 + +/* Analog Input Programming + 0x00 = four single ended inputs + 0x10 = three differential inputs + 0x20 = single ended and differential mixed + 0x30 = two differential inputs */ +#define PCF8591_CONTROL_AIP_MASK 0x30 + +/* Autoincrement Flag (switch on if 1) */ +#define PCF8591_CONTROL_AINC 0x04 + +/* Channel selection + 0x00 = channel 0 + 0x01 = channel 1 + 0x02 = channel 2 + 0x03 = channel 3 */ +#define PCF8591_CONTROL_AICH_MASK 0x03 + +/* Initial values */ +#define PCF8591_INIT_CONTROL ((input_mode << 4) | PCF8591_CONTROL_AOEF) +#define PCF8591_INIT_AOUT 0 /* DAC out = 0 */ + +/* Conversions */ +#define REG_TO_SIGNED(reg) (((reg) & 0x80)?((reg) - 256):(reg)) + +struct pcf8591_data { + struct semaphore update_lock; + + u8 control; + u8 aout; +}; + +static int pcf8591_attach_adapter(struct i2c_adapter *adapter); +static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind); +static int pcf8591_detach_client(struct i2c_client *client); +static void pcf8591_init_client(struct i2c_client *client); +static int pcf8591_read_channel(struct device *dev, int channel); + +/* This is the driver that will be inserted */ +static struct i2c_driver pcf8591_driver = { + .owner = THIS_MODULE, + .name = "pcf8591", + .id = I2C_DRIVERID_PCF8591, + .flags = I2C_DF_NOTIFY, + .attach_adapter = pcf8591_attach_adapter, + .detach_client = pcf8591_detach_client, +}; + +static int pcf8591_id = 0; + +/* following are the sysfs callback functions */ +#define show_in_channel(channel) \ +static ssize_t show_in##channel##_input(struct device *dev, char *buf) \ +{ \ + return sprintf(buf, "%d\n", pcf8591_read_channel(dev, channel));\ +} \ +static DEVICE_ATTR(in##channel##_input, S_IRUGO, \ + show_in##channel##_input, NULL); + +show_in_channel(0); +show_in_channel(1); +show_in_channel(2); +show_in_channel(3); + +static ssize_t show_out0_ouput(struct device *dev, char *buf) +{ + struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); + return sprintf(buf, "%d\n", data->aout * 10); +} + +static ssize_t set_out0_output(struct device *dev, const char *buf, size_t count) +{ + unsigned int value; + struct i2c_client *client = to_i2c_client(dev); + struct pcf8591_data *data = i2c_get_clientdata(client); + if ((value = (simple_strtoul(buf, NULL, 10) + 5) / 10) <= 255); + { + data->aout = value; + i2c_smbus_write_byte_data(client, data->control, data->aout); + } + return count; +} + +static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO, + show_out0_ouput, set_out0_output); + +static ssize_t show_out0_enable(struct device *dev, char *buf) +{ + struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); + return sprintf(buf, "%u\n", !(!(data->control & PCF8591_CONTROL_AOEF))); +} + +static ssize_t set_out0_enable(struct device *dev, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pcf8591_data *data = i2c_get_clientdata(client); + if (simple_strtoul(buf, NULL, 10)) + data->control |= PCF8591_CONTROL_AOEF; + else + data->control &= ~PCF8591_CONTROL_AOEF; + i2c_smbus_write_byte(client, data->control); + return count; +} + +static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO, + show_out0_enable, set_out0_enable); + +/* + * Real code + */ +static int pcf8591_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, pcf8591_detect); +} + +/* This function is called by i2c_detect */ +int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct pcf8591_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, 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. */ + if (!(new_client = kmalloc(sizeof(struct i2c_client) + + sizeof(struct pcf8591_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + memset(new_client, 0, sizeof(struct i2c_client) + + sizeof(struct pcf8591_data)); + + data = (struct pcf8591_data *) (new_client + 1); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &pcf8591_driver; + new_client->flags = 0; + + /* Now, we would do the remaining detection. But the PCF8591 is plainly + impossible to detect! Stupid chip. */ + + /* Determine the chip type - only one kind supported! */ + if (kind <= 0) + kind = pcf8591; + + /* Fill in the remaining client fields and put it into the global + list */ + strlcpy(new_client->name, "pcf8591", I2C_NAME_SIZE); + + new_client->id = pcf8591_id++; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_kfree; + + /* Initialize the PCF8591 chip */ + pcf8591_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_out0_enable); + device_create_file(&new_client->dev, &dev_attr_out0_output); + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in1_input); + + /* Register input2 if not in "two differential inputs" mode */ + if (input_mode != 3 ) + device_create_file(&new_client->dev, &dev_attr_in2_input); + + /* Register input3 only in "four single ended inputs" mode */ + if (input_mode == 0) + device_create_file(&new_client->dev, &dev_attr_in3_input); + + return 0; + + /* OK, this is not exactly good programming practice, usually. But it is + very code-efficient in this case. */ + + exit_kfree: + kfree(new_client); + exit: + return err; +} + +static int pcf8591_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(client); + return 0; +} + +/* Called when we have found a new PCF8591. */ +static void pcf8591_init_client(struct i2c_client *client) +{ + struct pcf8591_data *data = i2c_get_clientdata(client); + data->control = PCF8591_INIT_CONTROL; + data->aout = PCF8591_INIT_AOUT; + + i2c_smbus_write_byte_data(client, data->control, data->aout); + + /* The first byte transmitted contains the conversion code of the + previous read cycle. FLUSH IT! */ + i2c_smbus_read_byte(client); +} + +static int pcf8591_read_channel(struct device *dev, int channel) +{ + u8 value; + struct i2c_client *client = to_i2c_client(dev); + struct pcf8591_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if ((data->control & PCF8591_CONTROL_AICH_MASK) != channel) + { + data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK) + | channel; + i2c_smbus_write_byte(client, data->control); + + /* The first byte transmitted contains the conversion code of + the previous read cycle. FLUSH IT! */ + i2c_smbus_read_byte(client); + } + value = i2c_smbus_read_byte(client); + + up(&data->update_lock); + + if ((channel == 2 && input_mode == 2) || + (channel != 3 && (input_mode == 1 || input_mode == 3))) + return (10 * REG_TO_SIGNED(value)); + else + return (10 * value); +} + +static int __init pcf8591_init(void) +{ + if (input_mode < 0 || input_mode > 3) { + printk(KERN_WARNING "pcf8591: invalid input_mode (%d)\n", + input_mode); + input_mode = 0; + } + return i2c_add_driver(&pcf8591_driver); +} + +static void __exit pcf8591_exit(void) +{ + i2c_del_driver(&pcf8591_driver); +} + +MODULE_AUTHOR("Aurelien Jarno "); +MODULE_DESCRIPTION("PCF8591 driver"); +MODULE_LICENSE("GPL"); + +module_init(pcf8591_init); +module_exit(pcf8591_exit); -- cgit v1.2.3 From 14dc9e49a14bd7707064dc2f82328ad69977ef92 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 8 Apr 2004 22:06:02 -0700 Subject: [PATCH] I2C: minor bugfixes for the pcf8591.c driver and formatting cleanups. --- drivers/i2c/chips/pcf8591.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c index bdad91a3b044..7243487afb5f 100644 --- a/drivers/i2c/chips/pcf8591.c +++ b/drivers/i2c/chips/pcf8591.c @@ -125,8 +125,7 @@ static ssize_t set_out0_output(struct device *dev, const char *buf, size_t count unsigned int value; struct i2c_client *client = to_i2c_client(dev); struct pcf8591_data *data = i2c_get_clientdata(client); - if ((value = (simple_strtoul(buf, NULL, 10) + 5) / 10) <= 255); - { + if ((value = (simple_strtoul(buf, NULL, 10) + 5) / 10) <= 255) { data->aout = value; i2c_smbus_write_byte_data(client, data->control, data->aout); } @@ -235,9 +234,9 @@ int pcf8591_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_kfree: +exit_kfree: kfree(new_client); - exit: +exit: return err; } @@ -277,8 +276,7 @@ static int pcf8591_read_channel(struct device *dev, int channel) down(&data->update_lock); - if ((data->control & PCF8591_CONTROL_AICH_MASK) != channel) - { + if ((data->control & PCF8591_CONTROL_AICH_MASK) != channel) { data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK) | channel; i2c_smbus_write_byte(client, data->control); -- cgit v1.2.3 From c3f20125b421e0ce8bfe82342c5bd973d5d94219 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 8 Apr 2004 22:06:16 -0700 Subject: [PATCH] I2C: clean up out of order bus Makefile and Kconfig entries. --- drivers/i2c/busses/Kconfig | 16 ++++++++-------- drivers/i2c/busses/Makefile | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index f0175793a7af..65a118038c92 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -5,29 +5,29 @@ menu "I2C Hardware Bus support" depends on I2C -config I2C_ALI1563 - tristate "ALI 1563" +config I2C_ALI1535 + tristate "ALI 1535" depends on I2C && PCI && EXPERIMENTAL help If you say yes to this option, support will be included for the SMB - Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB + Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB controller is part of the 7101 device, which is an ACPI-compliant Power Management Unit (PMU). This driver can also be built as a module. If so, the module - will be called i2c-ali1563. + will be called i2c-ali1535. -config I2C_ALI1535 - tristate "ALI 1535" +config I2C_ALI1563 + tristate "ALI 1563" depends on I2C && PCI && EXPERIMENTAL help If you say yes to this option, support will be included for the SMB - Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB + Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB controller is part of the 7101 device, which is an ACPI-compliant Power Management Unit (PMU). This driver can also be built as a module. If so, the module - will be called i2c-ali1535. + will be called i2c-ali1563. config I2C_ALI15X3 tristate "ALI 15x3" diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 952a580ae879..13d07d54a48b 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -3,8 +3,8 @@ # obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o -obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o +obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o -- cgit v1.2.3 From 2dbac5971bcb467b73346b04281da95d96b74f17 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 12 Apr 2004 01:15:13 -0700 Subject: [PATCH] I2C: Rework memory allocation in i2c chip drivers Additional remarks: 1* This patch also removes an unused struct member in via686a and fixes an error message in ds1621. 2* I discovered error path problems in it87 and via686a detection functions. For the it87, I think that this patch makes it even more broken. I will fix both drivers in a later patch (really soon). --- drivers/i2c/chips/adm1021.c | 14 ++++++-------- drivers/i2c/chips/asb100.c | 14 ++++++-------- drivers/i2c/chips/ds1621.c | 18 ++++++++---------- drivers/i2c/chips/eeprom.c | 14 ++++++-------- drivers/i2c/chips/fscher.c | 17 ++++++++--------- drivers/i2c/chips/gl518sm.c | 14 ++++++-------- drivers/i2c/chips/it87.c | 16 +++++++--------- drivers/i2c/chips/lm75.c | 14 ++++++-------- drivers/i2c/chips/lm78.c | 14 ++++++-------- drivers/i2c/chips/lm80.c | 13 ++++++------- drivers/i2c/chips/lm83.c | 17 ++++++++--------- drivers/i2c/chips/lm85.c | 14 ++++++-------- drivers/i2c/chips/lm90.c | 17 ++++++++--------- drivers/i2c/chips/pcf8574.c | 15 ++++++--------- drivers/i2c/chips/pcf8591.c | 15 ++++++--------- drivers/i2c/chips/via686a.c | 16 ++++++---------- drivers/i2c/chips/w83627hf.c | 15 ++++++--------- drivers/i2c/chips/w83781d.c | 14 ++++++-------- drivers/i2c/chips/w83l785ts.c | 18 ++++++++---------- 19 files changed, 125 insertions(+), 164 deletions(-) diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c index d38319b582ae..5010461ccf29 100644 --- a/drivers/i2c/chips/adm1021.c +++ b/drivers/i2c/chips/adm1021.c @@ -101,6 +101,7 @@ clearing it. Weird, ey? --Phil */ /* Each client has this additional data */ struct adm1021_data { + struct i2c_client client; enum chips type; struct semaphore update_lock; @@ -228,16 +229,13 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access adm1021_{read,write}_value. */ - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct adm1021_data), - GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct adm1021_data), GFP_KERNEL))) { err = -ENOMEM; goto error0; } - memset(new_client, 0x00, sizeof(struct i2c_client) + - sizeof(struct adm1021_data)); + memset(data, 0, sizeof(struct adm1021_data)); - data = (struct adm1021_data *) (new_client + 1); + new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; @@ -329,7 +327,7 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) return 0; error1: - kfree(new_client); + kfree(data); error0: return err; } @@ -352,7 +350,7 @@ static int adm1021_detach_client(struct i2c_client *client) return err; } - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c index 0acd9202b018..20ac530e9090 100644 --- a/drivers/i2c/chips/asb100.c +++ b/drivers/i2c/chips/asb100.c @@ -193,6 +193,7 @@ static u8 DIV_TO_REG(long val) data is pointed to by client->data. The structure itself is dynamically allocated, at the same time the client itself is allocated. */ struct asb100_data { + struct i2c_client client; struct semaphore lock; enum chips type; @@ -722,17 +723,14 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access asb100_{read,write}_value. */ - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct asb100_data), GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct asb100_data), GFP_KERNEL))) { pr_debug("asb100.o: detect failed, kmalloc failed!\n"); err = -ENOMEM; goto ERROR0; } + memset(data, 0, sizeof(struct asb100_data)); - memset(new_client, 0, - sizeof(struct i2c_client) + sizeof(struct asb100_data)); - - data = (struct asb100_data *) (new_client + 1); + new_client = &data->client; init_MUTEX(&data->lock); i2c_set_clientdata(new_client, data); new_client->addr = address; @@ -842,7 +840,7 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) ERROR2: i2c_detach_client(new_client); ERROR1: - kfree(new_client); + kfree(data); ERROR0: return err; } @@ -857,7 +855,7 @@ static int asb100_detach_client(struct i2c_client *client) return err; } - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/ds1621.c b/drivers/i2c/chips/ds1621.c index b057ea96d985..bf3e2149599e 100644 --- a/drivers/i2c/chips/ds1621.c +++ b/drivers/i2c/chips/ds1621.c @@ -70,6 +70,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 semaphore update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -196,16 +197,13 @@ int ds1621_detect(struct i2c_adapter *adapter, int address, /* 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 ds1621_{read,write}_value. */ - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct ds1621_data), - GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct ds1621_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(new_client, 0, sizeof(struct i2c_client) + - sizeof(struct ds1621_data)); + memset(data, 0, sizeof(struct ds1621_data)); - data = (struct ds1621_data *) (new_client + 1); + new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; @@ -258,7 +256,7 @@ 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_free: - kfree(new_client); + kfree(data); exit: return err; } @@ -268,12 +266,12 @@ static int ds1621_detach_client(struct i2c_client *client) int err; if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "ds1621.o: Client deregistration failed, client not detached.\n"); + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); return err; } - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index ee1f60d6a4d1..21fa361344cf 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -63,6 +63,7 @@ enum eeprom_nature { /* Each client has this additional data */ struct eeprom_data { + struct i2c_client client; struct semaphore update_lock; u8 valid; /* bitfield, bit!=0 if slice is valid */ unsigned long last_updated[8]; /* In jiffies, 8 slices */ @@ -187,16 +188,13 @@ int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) /* 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 (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct eeprom_data), - GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(new_client, 0x00, sizeof(struct i2c_client) + - sizeof(struct eeprom_data)); + memset(data, 0, sizeof(struct eeprom_data)); - data = (struct eeprom_data *) (new_client + 1); + new_client = &data->client; memset(data->data, 0xff, EEPROM_SIZE); i2c_set_clientdata(new_client, data); new_client->addr = address; @@ -244,7 +242,7 @@ int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_kfree: - kfree(new_client); + kfree(data); exit: return err; } @@ -259,7 +257,7 @@ static int eeprom_detach_client(struct i2c_client *client) return err; } - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/fscher.c b/drivers/i2c/chips/fscher.c index d1ad718910be..a02072c76e5b 100644 --- a/drivers/i2c/chips/fscher.c +++ b/drivers/i2c/chips/fscher.c @@ -133,6 +133,7 @@ static struct i2c_driver fscher_driver = { */ struct fscher_data { + struct i2c_client client; struct semaphore update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -309,17 +310,15 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind) /* 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 i2c_smbus_read_byte_data. */ - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct fscher_data), GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct fscher_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(new_client, 0x00, sizeof(struct i2c_client) + - sizeof(struct fscher_data)); + memset(data, 0, sizeof(struct fscher_data)); - /* The Hermes-specific data is placed right after the common I2C - * client data. */ - data = (struct fscher_data *) (new_client + 1); + /* The common I2C client data is placed right before the + * Hermes-specific data. */ + new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; @@ -371,7 +370,7 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_free: - kfree(new_client); + kfree(data); exit: return err; } @@ -386,7 +385,7 @@ static int fscher_detach_client(struct i2c_client *client) return err; } - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/gl518sm.c b/drivers/i2c/chips/gl518sm.c index d12c204e0125..3258a2892836 100644 --- a/drivers/i2c/chips/gl518sm.c +++ b/drivers/i2c/chips/gl518sm.c @@ -118,6 +118,7 @@ static inline u8 FAN_TO_REG(long rpm, int div) /* Each client has this additional data */ struct gl518_data { + struct i2c_client client; enum chips type; struct semaphore update_lock; @@ -354,16 +355,13 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access gl518_{read,write}_value. */ - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct gl518_data), - GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct gl518_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(new_client, 0x00, sizeof(struct i2c_client) + - sizeof(struct gl518_data)); + memset(data, 0, sizeof(struct gl518_data)); - data = (struct gl518_data *) (new_client + 1); + new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; @@ -445,7 +443,7 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) very code-efficient in this case. */ exit_free: - kfree(new_client); + kfree(data); exit: return err; } @@ -479,7 +477,7 @@ static int gl518_detach_client(struct i2c_client *client) return err; } - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index 51d6499e4e06..eb6215c45215 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c @@ -134,6 +134,7 @@ static int DIV_TO_REG(int val) dynamically allocated, at the same time when a new it87 client is allocated. */ struct it87_data { + struct i2c_client client; struct semaphore lock; enum chips type; @@ -508,7 +509,7 @@ static int it87_attach_adapter(struct i2c_adapter *adapter) int it87_detect(struct i2c_adapter *adapter, int address, int kind) { int i; - struct i2c_client *new_client = NULL; + struct i2c_client *new_client; struct it87_data *data; int err = 0; const char *name = ""; @@ -554,16 +555,13 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access it87_{read,write}_value. */ - if (!(new_client = kmalloc((sizeof(struct i2c_client)) + - sizeof(struct it87_data), - GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct it87_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR1; } - memset(new_client, 0x00, sizeof(struct i2c_client) + - sizeof(struct it87_data)); + memset(data, 0, sizeof(struct it87_data)); - data = (struct it87_data *) (new_client + 1); + new_client = &data->client; if (is_isa) init_MUTEX(&data->lock); i2c_set_clientdata(new_client, data); @@ -670,7 +668,7 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) return 0; ERROR1: - kfree(new_client); + kfree(data); if (is_isa) release_region(address, IT87_EXTENT); @@ -690,7 +688,7 @@ static int it87_detach_client(struct i2c_client *client) if(i2c_is_isa_client(client)) release_region(client->addr, IT87_EXTENT); - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c index a1616fd6319b..5c6ebdc096ea 100644 --- a/drivers/i2c/chips/lm75.c +++ b/drivers/i2c/chips/lm75.c @@ -46,6 +46,7 @@ SENSORS_INSMOD_1(lm75); /* Each client has this additional data */ struct lm75_data { + struct i2c_client client; struct semaphore update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -135,16 +136,13 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) /* 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 lm75_{read,write}_value. */ - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct lm75_data), - GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct lm75_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(new_client, 0x00, sizeof(struct i2c_client) + - sizeof(struct lm75_data)); + memset(data, 0, sizeof(struct lm75_data)); - data = (struct lm75_data *) (new_client + 1); + new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; @@ -194,7 +192,7 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_free: - kfree(new_client); + kfree(data); exit: return err; } @@ -202,7 +200,7 @@ exit: static int lm75_detach_client(struct i2c_client *client) { i2c_detach_client(client); - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c index f2266b0fb273..2d697f4282f6 100644 --- a/drivers/i2c/chips/lm78.c +++ b/drivers/i2c/chips/lm78.c @@ -192,6 +192,7 @@ static inline u8 DIV_TO_REG(int val) dynamically allocated, at the same time when a new lm78 client is allocated. */ struct lm78_data { + struct i2c_client client; struct semaphore lock; enum chips type; @@ -552,16 +553,13 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access lm78_{read,write}_value. */ - if (!(new_client = kmalloc((sizeof(struct i2c_client)) + - sizeof(struct lm78_data), - GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct lm78_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR1; } - memset(new_client, 0, sizeof(struct i2c_client) + - sizeof(struct lm78_data)); + memset(data, 0, sizeof(struct lm78_data)); - data = (struct lm78_data *) (new_client + 1); + new_client = &data->client; if (is_isa) init_MUTEX(&data->lock); i2c_set_clientdata(new_client, data); @@ -671,7 +669,7 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind) return 0; ERROR2: - kfree(new_client); + kfree(data); ERROR1: if (is_isa) release_region(address, LM78_EXTENT); @@ -694,7 +692,7 @@ static int lm78_detach_client(struct i2c_client *client) return err; } - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/lm80.c b/drivers/i2c/chips/lm80.c index 2fe0188b2172..913f40d8c951 100644 --- a/drivers/i2c/chips/lm80.c +++ b/drivers/i2c/chips/lm80.c @@ -110,6 +110,7 @@ static inline long TEMP_FROM_REG(u16 temp) */ struct lm80_data { + struct i2c_client client; struct semaphore update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -394,15 +395,13 @@ int lm80_detect(struct i2c_adapter *adapter, int address, int kind) /* 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 lm80_{read,write}_value. */ - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct lm80_data), GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct lm80_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(new_client, 0x00, sizeof(struct i2c_client) + - sizeof(struct lm80_data)); + memset(data, 0, sizeof(struct lm80_data)); - data = (struct lm80_data *) (new_client + 1); + new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; @@ -480,7 +479,7 @@ int lm80_detect(struct i2c_adapter *adapter, int address, int kind) return 0; error_free: - kfree(new_client); + kfree(data); exit: return err; } @@ -495,7 +494,7 @@ static int lm80_detach_client(struct i2c_client *client) return err; } - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/lm83.c b/drivers/i2c/chips/lm83.c index f4e7d2723b73..f50e9344662d 100644 --- a/drivers/i2c/chips/lm83.c +++ b/drivers/i2c/chips/lm83.c @@ -134,6 +134,7 @@ static struct i2c_driver lm83_driver = { */ struct lm83_data { + struct i2c_client client; struct semaphore update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -234,17 +235,15 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct lm83_data), GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct lm83_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(new_client, 0x00, sizeof(struct i2c_client) + - sizeof(struct lm83_data)); + memset(data, 0, sizeof(struct lm83_data)); - /* The LM83-specific data is placed right after the common I2C - * client data. */ - data = (struct lm83_data *) (new_client + 1); + /* The common I2C client data is placed right after the + * LM83-specific data. */ + new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; @@ -329,7 +328,7 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_free: - kfree(new_client); + kfree(data); exit: return err; } @@ -344,7 +343,7 @@ static int lm83_detach_client(struct i2c_client *client) return err; } - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c index 4515a74bace0..795852aa6719 100644 --- a/drivers/i2c/chips/lm85.c +++ b/drivers/i2c/chips/lm85.c @@ -351,6 +351,7 @@ struct lm85_autofan { }; struct lm85_data { + struct i2c_client client; struct semaphore lock; enum chips type; @@ -736,16 +737,13 @@ int lm85_detect(struct i2c_adapter *adapter, int address, client structure, even though we cannot fill it completely yet. But it allows us to access lm85_{read,write}_value. */ - if (!(new_client = kmalloc((sizeof(struct i2c_client)) + - sizeof(struct lm85_data), - GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct lm85_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR0; } + memset(data, 0, sizeof(struct lm85_data)); - memset(new_client, 0, sizeof(struct i2c_client) + - sizeof(struct lm85_data)); - data = (struct lm85_data *) (new_client + 1); + new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; @@ -886,7 +884,7 @@ int lm85_detect(struct i2c_adapter *adapter, int address, /* Error out and cleanup code */ ERROR1: - kfree(new_client); + kfree(data); ERROR0: return err; } @@ -894,7 +892,7 @@ int lm85_detect(struct i2c_adapter *adapter, int address, int lm85_detach_client(struct i2c_client *client) { i2c_detach_client(client); - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c index dd8e98b03413..111781a5069d 100644 --- a/drivers/i2c/chips/lm90.c +++ b/drivers/i2c/chips/lm90.c @@ -142,6 +142,7 @@ static struct i2c_driver lm90_driver = { */ struct lm90_data { + struct i2c_client client; struct semaphore update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -280,17 +281,15 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct lm90_data), GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct lm90_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(new_client, 0x00, sizeof(struct i2c_client) + - sizeof(struct lm90_data)); + memset(data, 0, sizeof(struct lm90_data)); - /* The LM90-specific data is placed right after the common I2C - * client data. */ - data = (struct lm90_data *) (new_client + 1); + /* The common I2C client data is placed right before the + LM90-specific data. */ + new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; @@ -390,7 +389,7 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_free: - kfree(new_client); + kfree(data); exit: return err; } @@ -420,7 +419,7 @@ static int lm90_detach_client(struct i2c_client *client) return err; } - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index 3a0edc7d496d..78c6693f327c 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c @@ -55,6 +55,7 @@ SENSORS_INSMOD_2(pcf8574, pcf8574a); /* Each client has this additional data */ struct pcf8574_data { + struct i2c_client client; struct semaphore update_lock; u8 read, write; /* Register values */ @@ -127,17 +128,13 @@ int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. */ - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct pcf8574_data), - GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } + memset(data, 0, sizeof(struct pcf8574_data)); - memset(new_client, 0, sizeof(struct i2c_client) + - sizeof(struct pcf8574_data)); - - data = (struct pcf8574_data *) (new_client + 1); + new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; @@ -182,7 +179,7 @@ int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) very code-efficient in this case. */ exit_free: - kfree(new_client); + kfree(data); exit: return err; } @@ -197,7 +194,7 @@ static int pcf8574_detach_client(struct i2c_client *client) return err; } - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c index 7243487afb5f..d8fbd1169a6a 100644 --- a/drivers/i2c/chips/pcf8591.c +++ b/drivers/i2c/chips/pcf8591.c @@ -76,6 +76,7 @@ MODULE_PARM_DESC(input_mode, #define REG_TO_SIGNED(reg) (((reg) & 0x80)?((reg) - 256):(reg)) struct pcf8591_data { + struct i2c_client client; struct semaphore update_lock; u8 control; @@ -177,17 +178,13 @@ int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. */ - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct pcf8591_data), - GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - - memset(new_client, 0, sizeof(struct i2c_client) + - sizeof(struct pcf8591_data)); + memset(data, 0, sizeof(struct pcf8591_data)); - data = (struct pcf8591_data *) (new_client + 1); + new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; @@ -235,7 +232,7 @@ int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind) very code-efficient in this case. */ exit_kfree: - kfree(new_client); + kfree(data); exit: return err; } @@ -250,7 +247,7 @@ static int pcf8591_detach_client(struct i2c_client *client) return err; } - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index 3cff23b7f3c0..f51b48965174 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c @@ -369,8 +369,7 @@ static inline long TEMP_FROM_REG10(u16 val) dynamically allocated, at the same time when a new via686a client is allocated. */ struct via686a_data { - int sysctl_id; - + struct i2c_client client; struct semaphore update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -687,16 +686,13 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) return -ENODEV; } - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct via686a_data), - GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct via686a_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR0; } + memset(data, 0, sizeof(struct via686a_data)); - memset(new_client,0x00, sizeof(struct i2c_client) + - sizeof(struct via686a_data)); - data = (struct via686a_data *) (new_client + 1); + new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; @@ -753,7 +749,7 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) ERROR3: release_region(address, VIA686A_EXTENT); - kfree(new_client); + kfree(data); ERROR0: return err; } @@ -769,7 +765,7 @@ static int via686a_detach_client(struct i2c_client *client) } release_region(client->addr, VIA686A_EXTENT); - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c index 030b08248cc0..c38a7f9712b6 100644 --- a/drivers/i2c/chips/w83627hf.c +++ b/drivers/i2c/chips/w83627hf.c @@ -277,6 +277,7 @@ static inline u8 DIV_TO_REG(long val) data is pointed to by w83627hf_list[NR]->data. The structure itself is dynamically allocated, at the same time when a new client is allocated. */ struct w83627hf_data { + struct i2c_client client; struct semaphore lock; enum chips type; @@ -941,17 +942,13 @@ int w83627hf_detect(struct i2c_adapter *adapter, int address, client structure, even though we cannot fill it completely yet. But it allows us to access w83627hf_{read,write}_value. */ - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct w83627hf_data), - GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR1; } + memset(data, 0, sizeof(struct w83627hf_data)); - memset(new_client, 0x00, sizeof (struct i2c_client) + - sizeof (struct w83627hf_data)); - - data = (struct w83627hf_data *) (new_client + 1); + new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; init_MUTEX(&data->lock); @@ -1042,7 +1039,7 @@ int w83627hf_detect(struct i2c_adapter *adapter, int address, return 0; ERROR2: - kfree(new_client); + kfree(data); ERROR1: release_region(address, WINB_EXTENT); ERROR0: @@ -1060,7 +1057,7 @@ static int w83627hf_detach_client(struct i2c_client *client) } release_region(client->addr, WINB_EXTENT); - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index af96cab0a828..ff425337ebd7 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c @@ -226,6 +226,7 @@ DIV_TO_REG(long val, enum chips type) dynamically allocated, at the same time when a new w83781d client is allocated. */ struct w83781d_data { + struct i2c_client client; struct semaphore lock; enum chips type; @@ -1112,16 +1113,13 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access w83781d_{read,write}_value. */ - if (!(new_client = kmalloc(sizeof (struct i2c_client) + - sizeof (struct w83781d_data), GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct w83781d_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR1; } + memset(data, 0, sizeof(struct w83781d_data)); - memset(new_client, 0x00, sizeof (struct i2c_client) + - sizeof (struct w83781d_data)); - - data = (struct w83781d_data *) (new_client + 1); + new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; init_MUTEX(&data->lock); @@ -1321,7 +1319,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) ERROR3: i2c_detach_client(new_client); ERROR2: - kfree(new_client); + kfree(data); ERROR1: if (is_isa) release_region(address, W83781D_EXTENT); @@ -1343,7 +1341,7 @@ w83781d_detach_client(struct i2c_client *client) return err; } - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/i2c/chips/w83l785ts.c b/drivers/i2c/chips/w83l785ts.c index ad5bb437f139..0062d86f1f6e 100644 --- a/drivers/i2c/chips/w83l785ts.c +++ b/drivers/i2c/chips/w83l785ts.c @@ -105,7 +105,7 @@ static struct i2c_driver w83l785ts_driver = { */ struct w83l785ts_data { - + struct i2c_client client; struct semaphore update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -164,18 +164,16 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct w83l785ts_data), GFP_KERNEL))) { + if (!(data = kmalloc(sizeof(struct w83l785ts_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(new_client, 0x00, sizeof(struct i2c_client) + - sizeof(struct w83l785ts_data)); + memset(data, 0, sizeof(struct w83l785ts_data)); - /* The W83L785TS-specific data is placed right after the common I2C - * client data. */ - data = (struct w83l785ts_data *) (new_client + 1); + /* The common I2C client data is placed right before the + * W83L785TS-specific data. */ + new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; @@ -255,7 +253,7 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_free: - kfree(new_client); + kfree(data); exit: return err; } @@ -270,7 +268,7 @@ static int w83l785ts_detach_client(struct i2c_client *client) return err; } - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } -- cgit v1.2.3 From ee23f4b726fef7381d9fe851efa35dcfc482a54c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 12 Apr 2004 01:15:36 -0700 Subject: [PATCH] I2C: Error paths in it87 and via686a drivers Here comes the patch that fixes error paths in the it87 and via686a detection functions. The it87 part also adds missing error values. --- drivers/i2c/chips/it87.c | 33 ++++++++++++++++++--------------- drivers/i2c/chips/via686a.c | 2 +- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index eb6215c45215..80e4f256b209 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c @@ -533,12 +533,12 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) /* We need the timeouts for at least some IT87-like chips. But only if we read 'undefined' registers. */ i = inb_p(address + 1); - if (inb_p(address + 2) != i) - goto ERROR1; - if (inb_p(address + 3) != i) - goto ERROR1; - if (inb_p(address + 7) != i) + if (inb_p(address + 2) != i + || inb_p(address + 3) != i + || inb_p(address + 7) != i) { + err = -ENODEV; goto ERROR1; + } #undef REALLY_SLOW_IO /* Let's just hope nothing breaks here */ @@ -546,7 +546,8 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) outb_p(~i & 0x7f, address + 5); if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { outb_p(i, address + 5); - return 0; + err = -ENODEV; + goto ERROR1; } } } @@ -573,11 +574,12 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) /* Now, we do the remaining detection. */ if (kind < 0) { - if (it87_read_value(new_client, IT87_REG_CONFIG) & 0x80) - goto ERROR1; - if (!is_isa - && (it87_read_value(new_client, IT87_REG_I2C_ADDR) != - address)) goto ERROR1; + if ((it87_read_value(new_client, IT87_REG_CONFIG) & 0x80) + || (!is_isa + && it87_read_value(new_client, IT87_REG_I2C_ADDR) != address)) { + err = -ENODEV; + goto ERROR2; + } } /* Determine the chip type. */ @@ -592,7 +594,8 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) "Ignoring 'force' parameter for unknown chip at " "adapter %d, address 0x%02x\n", i2c_adapter_id(adapter), address); - goto ERROR1; + err = -ENODEV; + goto ERROR2; } } @@ -611,7 +614,7 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) - goto ERROR1; + goto ERROR2; /* Initialize the IT87 chip */ it87_init_client(new_client, data); @@ -667,9 +670,9 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) return 0; -ERROR1: +ERROR2: kfree(data); - +ERROR1: if (is_isa) release_region(address, IT87_EXTENT); ERROR0: diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index f51b48965174..1e13bc16494c 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c @@ -748,9 +748,9 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) return 0; ERROR3: - release_region(address, VIA686A_EXTENT); kfree(data); ERROR0: + release_region(address, VIA686A_EXTENT); return err; } -- cgit v1.2.3 From a30b044ac7194c0a7ce973a8f592b0008c6ec731 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 12 Apr 2004 01:16:08 -0700 Subject: [PATCH] I2C: pwm support in w83781d.c Here is a general pwm support cleanup patch for the w83781d chip driver. Featuring: * Don't pretend that we handle PWM on AS99127F chips. We don't know how it works, and one of the register we are accessing for now is clearly not a PWM register, and changing its value usually breaks temperature readings. * Discard irrelevant comments. * Rewrite show_pwmenable_reg. It was obviously taken from the 2.4 driver, with unneeded tests and the code was much too complicated anyway. And now we handle errors correctly. * Initialize pwm_enable at load time. So far it was done conditionally (if init=1) while it should always be done. And pwm2_enable wasn't read from the chip, while it should. I could test that my AS99127F doesn't expose pwm files through ssysfs anymore. Which means that I couldn't test the rest of the pwm changes, unfortunately. I've applied similar changes to our 2.4/CVS repository. --- drivers/i2c/chips/w83781d.c | 65 +++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index ff425337ebd7..b2274c5b7848 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c @@ -24,7 +24,7 @@ Supports following chips: Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - as99127f 7 3 1? 3 0x31 0x12c3 yes no + as99127f 7 3 0 3 0x31 0x12c3 yes no as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) @@ -670,7 +670,6 @@ do { \ device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ } while (0) -/* w83697hf only has two fans */ static ssize_t show_pwm_reg(struct device *dev, char *buf, int nr) { @@ -678,7 +677,6 @@ show_pwm_reg(struct device *dev, char *buf, int nr) return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr - 1])); } -/* w83697hf only has two fans */ static ssize_t show_pwmenable_reg(struct device *dev, char *buf, int nr) { @@ -706,38 +704,26 @@ store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct w83781d_data *data = i2c_get_clientdata(client); - u32 val, j, k; + u32 val, reg; val = simple_strtoul(buf, NULL, 10); - /* only PWM2 can be enabled/disabled */ - if (nr == 2) { - j = w83781d_read_value(client, W83781D_REG_PWMCLK12); - k = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); + switch (val) { + case 0: + case 1: + reg = w83781d_read_value(client, W83781D_REG_PWMCLK12); + w83781d_write_value(client, W83781D_REG_PWMCLK12, + (reg & 0xf7) | (val << 3)); - if (val > 0) { - if (!(j & 0x08)) - w83781d_write_value(client, - W83781D_REG_PWMCLK12, - j | 0x08); - if (k & 0x10) - w83781d_write_value(client, - W83781D_REG_BEEP_CONFIG, - k & 0xef); + reg = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); + w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, + (reg & 0xef) | (!val << 4)); - data->pwmenable[1] = 1; - } else { - if (j & 0x08) - w83781d_write_value(client, - W83781D_REG_PWMCLK12, - j & 0xf7); - if (!(k & 0x10)) - w83781d_write_value(client, - W83781D_REG_BEEP_CONFIG, - j | 0x10); + data->pwmenable[nr - 1] = val; + break; - data->pwmenable[1] = 0; - } + default: + return -EINVAL; } return count; @@ -1250,6 +1236,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) data->fan_min[i - 1] = w83781d_read_value(new_client, W83781D_REG_FAN_MIN(i)); } + if (kind != w83781d && kind != as99127f) + for (i = 0; i < 4; i++) + data->pwmenable[i] = 1; /* Register sysfs hooks */ device_create_file_in(new_client, 0); @@ -1290,7 +1279,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file_beep(new_client); - if (kind != w83781d) { + if (kind != w83781d && kind != as99127f) { device_create_file_pwm(new_client, 1); device_create_file_pwm(new_client, 2); device_create_file_pwmenable(new_client, 2); @@ -1578,9 +1567,6 @@ w83781d_init_client(struct i2c_client *client) if (!(i & 0x40)) w83781d_write_value(client, W83781D_REG_IRQ, i | 0x40); - - for (i = 0; i < 3; i++) - data->pwmenable[i] = 1; } } @@ -1624,20 +1610,19 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) data->fan_min[i - 1] = w83781d_read_value(client, W83781D_REG_FAN_MIN(i)); } - if (data->type != w83781d) { + if (data->type != w83781d && data->type != as99127f) { for (i = 1; i <= 4; i++) { data->pwm[i - 1] = w83781d_read_value(client, W83781D_REG_PWM(i)); - if (((data->type == w83783s) - || (data->type == w83627hf) - || (data->type == as99127f) - || (data->type == w83697hf) - || ((data->type == w83782d) - && i2c_is_isa_client(client))) + if ((data->type != w83782d + || i2c_is_isa_client(client)) && i == 2) break; } + /* Only PWM2 can be disabled */ + data->pwmenable[1] = (w83781d_read_value(client, + W83781D_REG_PWMCLK12) & 0x08) >> 3; } data->temp = w83781d_read_value(client, W83781D_REG_TEMP(1)); -- cgit v1.2.3 From 07b21537c76e6734d678099bea4a497d10693d04 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 12 Apr 2004 01:16:36 -0700 Subject: [PATCH] I2C: make I2C chip drivers return -EINVAL on error --- drivers/i2c/chips/fscher.c | 2 +- drivers/i2c/chips/it87.c | 2 +- drivers/i2c/chips/pcf8591.c | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/chips/fscher.c b/drivers/i2c/chips/fscher.c index a02072c76e5b..1901a524a845 100644 --- a/drivers/i2c/chips/fscher.c +++ b/drivers/i2c/chips/fscher.c @@ -512,7 +512,7 @@ static ssize_t set_fan_div(struct i2c_client *client, struct fscher_data *data, default: dev_err(&client->dev, "fan_div value %ld not " "supported. Choose one of 2, 4 or 8!\n", v); - return -1; + return -EINVAL; } /* bits 2..7 reserved => mask with 0x03 */ diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index 80e4f256b209..856d5f57291b 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c @@ -367,7 +367,7 @@ static ssize_t set_sensor(struct device *dev, const char *buf, else if (val == 2) data->sensor |= 8 << nr; else if (val != 0) - return -1; + return -EINVAL; it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor); return count; } diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c index d8fbd1169a6a..87ad9b9734eb 100644 --- a/drivers/i2c/chips/pcf8591.c +++ b/drivers/i2c/chips/pcf8591.c @@ -129,8 +129,9 @@ static ssize_t set_out0_output(struct device *dev, const char *buf, size_t count if ((value = (simple_strtoul(buf, NULL, 10) + 5) / 10) <= 255) { data->aout = value; i2c_smbus_write_byte_data(client, data->control, data->aout); + return count; } - return count; + return -EINVAL; } static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO, -- cgit v1.2.3 From 998f14c4b726ca273f59b787aa22705030a102ba Mon Sep 17 00:00:00 2001 From: "Mark M. Hoffman" Date: Mon, 12 Apr 2004 01:17:01 -0700 Subject: [PATCH] I2C: fix asb100 bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hi nymisi, Greg: * Nyeste Mihály [2004-01-27 16:02:04 +0100]: > Hi! > > I reported a bug of asb100 chip at: > http://www2.lm-sensors.nu/~lm78/readticket.cgi?ticket=1539 > > The reply was the follow: > > "Is there a BIOS option you can disable, e.g. Asus "COP", > "QFAN", or some such? My guess is that the BIOS is > somehow interfering with the asb100 driver. Otherwise > I don´t know how this could happen. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Yeah, I wrote that. "You do that, you go to the box, you know. Two minutes by yourself, and you feel shame, you know." - Denis the goalie Greg, please apply this fix (vs. 2.6.5): --- drivers/i2c/chips/asb100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c index 20ac530e9090..288fb9ea7374 100644 --- a/drivers/i2c/chips/asb100.c +++ b/drivers/i2c/chips/asb100.c @@ -468,7 +468,7 @@ static ssize_t set_##reg(struct device *dev, const char *buf, \ data->reg[nr] = TEMP_TO_REG(val); \ break; \ } \ - asb100_write_value(client, ASB100_REG_TEMP_##REG(nr), \ + asb100_write_value(client, ASB100_REG_TEMP_##REG(nr+1), \ data->reg[nr]); \ return count; \ } -- cgit v1.2.3 From 02dd2c14cfe4daefde15497c96cc15eef4724e8f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 12 Apr 2004 01:17:24 -0700 Subject: [PATCH] I2C: Fix voltage rounding in lm80 This one line patch fixes voltage rounding in the lm80 chip driver. --- drivers/i2c/chips/lm80.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/chips/lm80.c b/drivers/i2c/chips/lm80.c index 913f40d8c951..ec8cbe68d755 100644 --- a/drivers/i2c/chips/lm80.c +++ b/drivers/i2c/chips/lm80.c @@ -68,7 +68,7 @@ SENSORS_INSMOD_1(lm80); these macros are called: arguments may be evaluated more than once. Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((val)/10,0,255)) +#define IN_TO_REG(val) (SENSORS_LIMIT(((val)+5)/10,0,255)) #define IN_FROM_REG(val) ((val)*10) static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div) -- cgit v1.2.3 From 6088582c2bc76462716daa9fe84dbd82259ff8bf Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 12 Apr 2004 01:17:46 -0700 Subject: [PATCH] I2C: No reset not limit init in via686a The following patch removes limits initialization in the via686a driver. It was decided some times ago that this belongs to user-space, not kernel. See the thread here: http://archives.andrew.net.au/lm-sensors/msg06134.html It also prevents the sensor chip from being savagely reset at load time. This too follows a decision taken long ago that drivers should do as little as possible in their init procedure. See the thread here: http://archives.andrew.net.au/lm-sensors/msg04593.html This should make the driver smaller, safer and faster to load. The same was done to our 2.4/CVS version of the driver 5 months ago and it seems to work just fine. --- drivers/i2c/chips/via686a.c | 90 ++++----------------------------------------- 1 file changed, 7 insertions(+), 83 deletions(-) diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index 1e13bc16494c..d3f14e965fed 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c @@ -329,45 +329,9 @@ static inline long TEMP_FROM_REG10(u16 val) #define DIV_FROM_REG(val) (1 << (val)) #define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) -/* Initial limits */ -#define VIA686A_INIT_IN_0 200 -#define VIA686A_INIT_IN_1 250 -#define VIA686A_INIT_IN_2 330 -#define VIA686A_INIT_IN_3 500 -#define VIA686A_INIT_IN_4 1200 - -#define VIA686A_INIT_IN_PERCENTAGE 10 - -#define VIA686A_INIT_IN_MIN_0 (VIA686A_INIT_IN_0 - VIA686A_INIT_IN_0 \ - * VIA686A_INIT_IN_PERCENTAGE / 100) -#define VIA686A_INIT_IN_MAX_0 (VIA686A_INIT_IN_0 + VIA686A_INIT_IN_0 \ - * VIA686A_INIT_IN_PERCENTAGE / 100) -#define VIA686A_INIT_IN_MIN_1 (VIA686A_INIT_IN_1 - VIA686A_INIT_IN_1 \ - * VIA686A_INIT_IN_PERCENTAGE / 100) -#define VIA686A_INIT_IN_MAX_1 (VIA686A_INIT_IN_1 + VIA686A_INIT_IN_1 \ - * VIA686A_INIT_IN_PERCENTAGE / 100) -#define VIA686A_INIT_IN_MIN_2 (VIA686A_INIT_IN_2 - VIA686A_INIT_IN_2 \ - * VIA686A_INIT_IN_PERCENTAGE / 100) -#define VIA686A_INIT_IN_MAX_2 (VIA686A_INIT_IN_2 + VIA686A_INIT_IN_2 \ - * VIA686A_INIT_IN_PERCENTAGE / 100) -#define VIA686A_INIT_IN_MIN_3 (VIA686A_INIT_IN_3 - VIA686A_INIT_IN_3 \ - * VIA686A_INIT_IN_PERCENTAGE / 100) -#define VIA686A_INIT_IN_MAX_3 (VIA686A_INIT_IN_3 + VIA686A_INIT_IN_3 \ - * VIA686A_INIT_IN_PERCENTAGE / 100) -#define VIA686A_INIT_IN_MIN_4 (VIA686A_INIT_IN_4 - VIA686A_INIT_IN_4 \ - * VIA686A_INIT_IN_PERCENTAGE / 100) -#define VIA686A_INIT_IN_MAX_4 (VIA686A_INIT_IN_4 + VIA686A_INIT_IN_4 \ - * VIA686A_INIT_IN_PERCENTAGE / 100) - -#define VIA686A_INIT_FAN_MIN 3000 - -#define VIA686A_INIT_TEMP_OVER 600 -#define VIA686A_INIT_TEMP_HYST 500 - -/* For the VIA686A, we need to keep some data in memory. That - data is pointed to by via686a_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new via686a client is - allocated. */ +/* For the VIA686A, we need to keep some data in memory. + The structure is dynamically allocated, at the same time when a new + via686a client is allocated. */ struct via686a_data { struct i2c_client client; struct semaphore update_lock; @@ -773,53 +737,13 @@ static int via686a_detach_client(struct i2c_client *client) /* Called when we have found a new VIA686A. Set limits, etc. */ static void via686a_init_client(struct i2c_client *client) { - int i; - - /* Reset the device */ - via686a_write_value(client, VIA686A_REG_CONFIG, 0x80); - - /* Have to wait for reset to complete or else the following - initializations won't work reliably. The delay was arrived at - empirically, the datasheet doesn't tell you. - Waiting for the reset bit to clear doesn't work, it - clears in about 2-4 udelays and that isn't nearly enough. */ - udelay(50); - - via686a_write_value(client, VIA686A_REG_IN_MIN(0), - IN_TO_REG(VIA686A_INIT_IN_MIN_0, 0)); - via686a_write_value(client, VIA686A_REG_IN_MAX(0), - IN_TO_REG(VIA686A_INIT_IN_MAX_0, 0)); - via686a_write_value(client, VIA686A_REG_IN_MIN(1), - IN_TO_REG(VIA686A_INIT_IN_MIN_1, 1)); - via686a_write_value(client, VIA686A_REG_IN_MAX(1), - IN_TO_REG(VIA686A_INIT_IN_MAX_1, 1)); - via686a_write_value(client, VIA686A_REG_IN_MIN(2), - IN_TO_REG(VIA686A_INIT_IN_MIN_2, 2)); - via686a_write_value(client, VIA686A_REG_IN_MAX(2), - IN_TO_REG(VIA686A_INIT_IN_MAX_2, 2)); - via686a_write_value(client, VIA686A_REG_IN_MIN(3), - IN_TO_REG(VIA686A_INIT_IN_MIN_3, 3)); - via686a_write_value(client, VIA686A_REG_IN_MAX(3), - IN_TO_REG(VIA686A_INIT_IN_MAX_3, 3)); - via686a_write_value(client, VIA686A_REG_IN_MIN(4), - IN_TO_REG(VIA686A_INIT_IN_MIN_4, 4)); - via686a_write_value(client, VIA686A_REG_IN_MAX(4), - IN_TO_REG(VIA686A_INIT_IN_MAX_4, 4)); - via686a_write_value(client, VIA686A_REG_FAN_MIN(1), - FAN_TO_REG(VIA686A_INIT_FAN_MIN, 2)); - via686a_write_value(client, VIA686A_REG_FAN_MIN(2), - FAN_TO_REG(VIA686A_INIT_FAN_MIN, 2)); - for (i = 0; i <= 2; i++) { - via686a_write_value(client, VIA686A_REG_TEMP_OVER(i), - TEMP_TO_REG(VIA686A_INIT_TEMP_OVER)); - via686a_write_value(client, VIA686A_REG_TEMP_HYST(i), - TEMP_TO_REG(VIA686A_INIT_TEMP_HYST)); - } + u8 reg; /* Start monitoring */ - via686a_write_value(client, VIA686A_REG_CONFIG, 0x01); + reg = via686a_read_value(client, VIA686A_REG_CONFIG); + via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F); - /* Cofigure temp interrupt mode for continuous-interrupt operation */ + /* Configure temp interrupt mode for continuous-interrupt operation */ via686a_write_value(client, VIA686A_REG_TEMP_MODE, via686a_read_value(client, VIA686A_REG_TEMP_MODE) & !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS)); -- cgit v1.2.3 From a27bfa92df32ff05f9222dde4805dc28814e8aa7 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 13 Apr 2004 23:10:38 -0700 Subject: [PATCH] I2C: Fix voltage rounding in asb100 This one line patch fixes voltage rounding in the asb100 chip driver. It's very similar to a patch I submitted for the lm80 a few days ago. --- drivers/i2c/chips/asb100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c index 288fb9ea7374..355972cff6d9 100644 --- a/drivers/i2c/chips/asb100.c +++ b/drivers/i2c/chips/asb100.c @@ -124,7 +124,7 @@ static const u16 asb100_reg_temp_hyst[] = {0, 0x3a, 0x153, 0x253, 0x19}; static u8 IN_TO_REG(unsigned val) { unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX); - return nval / 16; + return (nval + 8) / 16; } static unsigned IN_FROM_REG(u8 reg) -- cgit v1.2.3