summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <greg@kroah.com>2004-04-13 23:33:29 -0700
committerGreg Kroah-Hartman <greg@kroah.com>2004-04-13 23:33:29 -0700
commitde2bd6e93a2bbd83cacd7925f94ce05957bc68b5 (patch)
tree9c181f5dd1ffaac8e5439ec8e4e8fb12098b60f2
parent69202577667bf8b90bbae934880302d055cf3e15 (diff)
parenta27bfa92df32ff05f9222dde4805dc28814e8aa7 (diff)
Merge kroah.com:/home/greg/linux/BK/bleed-2.6
into kroah.com:/home/greg/linux/BK/i2c-2.6
-rw-r--r--Documentation/i2c/porting-clients46
-rw-r--r--Documentation/i2c/sysfs-interface78
-rw-r--r--arch/i386/pci/irq.c5
-rw-r--r--drivers/i2c/busses/Kconfig12
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-ali1563.c417
-rw-r--r--drivers/i2c/chips/Kconfig21
-rw-r--r--drivers/i2c/chips/Makefile2
-rw-r--r--drivers/i2c/chips/adm1021.c54
-rw-r--r--drivers/i2c/chips/asb100.c38
-rw-r--r--drivers/i2c/chips/ds1621.c28
-rw-r--r--drivers/i2c/chips/eeprom.c16
-rw-r--r--drivers/i2c/chips/fscher.c19
-rw-r--r--drivers/i2c/chips/gl518sm.c24
-rw-r--r--drivers/i2c/chips/it87.c49
-rw-r--r--drivers/i2c/chips/lm75.c24
-rw-r--r--drivers/i2c/chips/lm78.c20
-rw-r--r--drivers/i2c/chips/lm80.c72
-rw-r--r--drivers/i2c/chips/lm83.c17
-rw-r--r--drivers/i2c/chips/lm85.c14
-rw-r--r--drivers/i2c/chips/lm90.c17
-rw-r--r--drivers/i2c/chips/pcf8574.c242
-rw-r--r--drivers/i2c/chips/pcf8591.c317
-rw-r--r--drivers/i2c/chips/via686a.c109
-rw-r--r--drivers/i2c/chips/w83627hf.c69
-rw-r--r--drivers/i2c/chips/w83781d.c199
-rw-r--r--drivers/i2c/chips/w83l785ts.c18
-rw-r--r--include/linux/pci_ids.h1
28 files changed, 1397 insertions, 532 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 <khali@linux-fr.org>
Greg KH <greg@kroah.com>
@@ -24,9 +24,10 @@ Technical changes:
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/i2c-sensor.h>
- #include <linux/i2c-vid.h> /* if you need VRM support */
- #include <asm/io.h> /* if you have I/O operations */
- Some extra headers may be required for a given driver.
+ #include <linux/i2c-vid.h> /* if you need VRM support */
+ #include <asm/io.h> /* 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/<chip name>),
+ and that remaining comments still match the code. Merging comment
+ lines when possible is encouraged.
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.
diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c
index 752e1b3fe175..cfd60cd58b75 100644
--- a/arch/i386/pci/irq.c
+++ b/arch/i386/pci/irq.c
@@ -591,12 +591,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;
}
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 002862328a03..65a118038c92 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -17,6 +17,18 @@ config I2C_ALI1535
This driver can also be built as a module. If so, the module
will be called i2c-ali1535.
+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_ALI15X3
tristate "ALI 15x3"
depends on I2C && PCI && EXPERIMENTAL
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 1253bca5cbb9..13d07d54a48b 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.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
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
new file mode 100644
index 000000000000..3807c96821f1
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -0,0 +1,417 @@
+/**
+ * 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 <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#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 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,
+ .class = I2C_ADAP_CLASS_SMBUS,
+ .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");
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index a25be2fb0e05..e005b02484b8 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -209,4 +209,25 @@ 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.
+
+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 0e4941850d49..6de7d4711612 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -19,6 +19,8 @@ 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_PCF8591) += pcf8591.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c
index 4993add5adeb..5010461ccf29 100644
--- a/drivers/i2c/chips/adm1021.c
+++ b/drivers/i2c/chips/adm1021.c
@@ -98,13 +98,10 @@ 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 {
+ struct i2c_client client;
enum chips type;
struct semaphore update_lock;
@@ -151,9 +148,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) \
@@ -235,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;
@@ -253,8 +244,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. */
@@ -272,11 +267,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;
}
@@ -309,10 +307,11 @@ 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);
+ if (kind != lm84)
+ adm1021_init_client(new_client);
/* Register sysfs hooks */
device_create_file(&new_client->dev, &dev_attr_temp1_max);
@@ -327,26 +326,17 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
-error3:
error1:
- kfree(new_client);
+ kfree(data);
error0:
return err;
}
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);
}
@@ -360,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 3fbdee66fb66..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)
@@ -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;
@@ -467,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; \
}
@@ -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;
@@ -807,6 +805,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);
@@ -837,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;
}
@@ -852,16 +855,11 @@ static int asb100_detach_client(struct i2c_client *client)
return err;
}
- kfree(client);
+ kfree(i2c_get_clientdata(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)
@@ -886,17 +884,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;
}
}
@@ -934,10 +932,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..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 */
@@ -97,11 +98,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 +106,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 +117,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)
@@ -202,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;
@@ -264,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;
}
@@ -274,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 bed325cd8c99..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,17 +188,14 @@ 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);
- memset(data, 0xff, EEPROM_SIZE);
+ new_client = &data->client;
+ memset(data->data, 0xff, EEPROM_SIZE);
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
@@ -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..1901a524a845 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;
}
@@ -513,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/gl518sm.c b/drivers/i2c/chips/gl518sm.c
index 224a497f04f4..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,23 +477,18 @@ static int gl518_detach_client(struct i2c_client *client)
return err;
}
- kfree(client);
+ kfree(i2c_get_clientdata(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 +499,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/it87.c b/drivers/i2c/chips/it87.c
index 51d6499e4e06..856d5f57291b 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;
@@ -366,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;
}
@@ -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 = "";
@@ -532,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 */
@@ -545,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;
}
}
}
@@ -554,16 +556,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);
@@ -575,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. */
@@ -594,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;
}
}
@@ -613,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);
@@ -669,9 +670,9 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+ERROR2:
+ kfree(data);
ERROR1:
- kfree(new_client);
-
if (is_isa)
release_region(address, IT87_EXTENT);
ERROR0:
@@ -690,7 +691,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 c5496dd21260..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,15 +200,10 @@ exit:
static int lm75_detach_client(struct i2c_client *client)
{
i2c_detach_client(client);
- kfree(client);
+ kfree(i2c_get_clientdata(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 +212,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 +223,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/lm78.c b/drivers/i2c/chips/lm78.c
index 43ceb35583f9..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);
@@ -625,6 +623,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);
@@ -665,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);
@@ -688,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 480927677cb3..ec8cbe68d755 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
@@ -69,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)
@@ -111,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 */
@@ -250,8 +250,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 +357,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);
@@ -357,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;
@@ -401,6 +437,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);
@@ -439,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;
}
@@ -454,7 +494,7 @@ static int lm80_detach_client(struct i2c_client *client)
return err;
}
- kfree(client);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -504,10 +544,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) |
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
new file mode 100644
index 000000000000..78c6693f327c
--- /dev/null
+++ b/drivers/i2c/chips/pcf8574.c
@@ -0,0 +1,242 @@
+/*
+ pcf8574.c - Part of lm_sensors, Linux kernel modules for hardware
+ monitoring
+ Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>,
+ Dan Eaton <dan.eaton@rocketlogix.com>
+ Ported to Linux 2.6 by Aurelien Jarno <aurel32@debian.org> with
+ the help of Jean Delvare <khali@linux-fr.org>
+
+ 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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+
+/* 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 i2c_client client;
+ 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 (!(data = kmalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ memset(data, 0, sizeof(struct pcf8574_data));
+
+ new_client = &data->client;
+ 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(data);
+ 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(i2c_get_clientdata(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 <frodol@dds.nl>, "
+ "Philip Edelbrock <phil@netroedge.com>, "
+ "Dan Eaton <dan.eaton@rocketlogix.com> "
+ "and Aurelien Jarno <aurelien@aurel32.net>");
+MODULE_DESCRIPTION("PCF8574 driver");
+MODULE_LICENSE("GPL");
+
+module_init(pcf8574_init);
+module_exit(pcf8574_exit);
diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c
new file mode 100644
index 000000000000..87ad9b9734eb
--- /dev/null
+++ b/drivers/i2c/chips/pcf8591.c
@@ -0,0 +1,317 @@
+/*
+ pcf8591.c - Part of lm_sensors, Linux kernel modules for hardware
+ monitoring
+ Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net>
+ Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
+ the help of Jean Delvare <khali@linux-fr.org>
+
+ 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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+
+/* 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 i2c_client client;
+ 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;
+ }
+ return -EINVAL;
+}
+
+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 (!(data = kmalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ memset(data, 0, sizeof(struct pcf8591_data));
+
+ new_client = &data->client;
+ 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(data);
+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(i2c_get_clientdata(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 <aurelien@aurel32.net>");
+MODULE_DESCRIPTION("PCF8591 driver");
+MODULE_LICENSE("GPL");
+
+module_init(pcf8591_init);
+module_exit(pcf8591_exit);
diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c
index ca1ee66668a2..d3f14e965fed 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.
*/
@@ -330,48 +329,11 @@ 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 {
- 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 */
@@ -688,16 +650,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,9 +712,9 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
ERROR3:
- release_region(address, VIA686A_EXTENT);
- kfree(new_client);
+ kfree(data);
ERROR0:
+ release_region(address, VIA686A_EXTENT);
return err;
}
@@ -770,7 +729,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;
}
@@ -778,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));
diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c
index 94365849e3bb..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;
@@ -659,34 +660,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 +704,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)
@@ -938,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);
@@ -982,6 +982,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)
@@ -1034,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:
@@ -1052,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 16b6ff518ba7..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)
@@ -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;
@@ -275,11 +276,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",
@@ -620,73 +616,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)
-{
- 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[0],
- DIV_FROM_REG(data->fan_div[0]));
-
- data->fan_div[0] = 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);
-
- /* 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;
- 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)
+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);
@@ -694,26 +624,28 @@ store_regs_fan_div_3(struct device *dev, const char *buf, size_t count)
u8 reg;
/* Save fan_min */
- min = FAN_FROM_REG(data->fan_min[2],
- DIV_FROM_REG(data->fan_div[2]));
+ min = FAN_FROM_REG(data->fan_min[nr],
+ DIV_FROM_REG(data->fan_div[nr]));
- data->fan_div[2] = 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_PIN) & 0x3f;
- reg |= (data->fan_div[2] & 0x03) << 6;
- w83781d_write_value(client, W83781D_REG_PIN, 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) & 0x7f;
- reg |= (data->fan_div[2] & 0x04) << 5;
+ 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[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 +655,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);
@@ -734,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)
{
@@ -742,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)
{
@@ -770,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;
@@ -1177,16 +1099,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);
@@ -1312,6 +1231,15 @@ 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));
+ }
+ 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);
if (kind != w83783s && kind != w83697hf)
@@ -1351,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);
@@ -1380,7 +1308,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);
@@ -1402,7 +1330,7 @@ w83781d_detach_client(struct i2c_client *client)
return err;
}
- kfree(client);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1461,20 +1389,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;
}
}
@@ -1535,12 +1460,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;
}
}
@@ -1644,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;
}
}
@@ -1690,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));
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;
}
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index c48f2b65d081..8cc50cef040c 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -995,6 +995,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