diff options
| author | Greg Kroah-Hartman <greg@kroah.com> | 2004-04-13 23:33:29 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <greg@kroah.com> | 2004-04-13 23:33:29 -0700 |
| commit | de2bd6e93a2bbd83cacd7925f94ce05957bc68b5 (patch) | |
| tree | 9c181f5dd1ffaac8e5439ec8e4e8fb12098b60f2 | |
| parent | 69202577667bf8b90bbae934880302d055cf3e15 (diff) | |
| parent | a27bfa92df32ff05f9222dde4805dc28814e8aa7 (diff) | |
Merge kroah.com:/home/greg/linux/BK/bleed-2.6
into kroah.com:/home/greg/linux/BK/i2c-2.6
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 |
