bk://kernel.bkbits.net/gregkh/linux/i2c-2.6 mochel@digitalimplant.org|ChangeSet|20040402190514|57654 mochel # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/04/02 11:26:04-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/i2c-2.6 # into bix.(none):/usr/src/bk-i2c # # include/linux/pci_ids.h # 2004/04/02 11:26:01-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/02 11:05:14-08:00 mochel@digitalimplant.org # [PATCH] I2C: Fix check for DEBUG in i2c-ali1563 # # drivers/i2c/busses/i2c-ali1563.c # 2004/04/02 02:51:16-08:00 mochel@digitalimplant.org +0 -5 # I2C: Fix check for DEBUG in i2c-ali1563 # # ChangeSet # 2004/04/02 11:03:04-08:00 mochel@digitalimplant.org # [PATCH] I2C: Add ALi 1563 i2c driver # # The i2c interface on the 1563 is totally different than on both the 1533 # and the 1535. It supports i2c 2.0, and happens to be nearly identical to # the interface on the i810 chipsets. # # drivers/i2c/busses/i2c-ali1563.c # 2004/03/19 13:50:06-08:00 mochel@digitalimplant.org +421 -0 # I2C: Add ALi 1563 i2c driver # # drivers/i2c/busses/i2c-ali1563.c # 2004/03/19 13:50:06-08:00 mochel@digitalimplant.org +0 -0 # BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/i2c/busses/i2c-ali1563.c # # drivers/i2c/busses/Makefile # 2004/03/19 13:50:06-08:00 mochel@digitalimplant.org +1 -0 # I2C: Add ALi 1563 i2c driver # # drivers/i2c/busses/Kconfig # 2004/03/19 13:45:26-08:00 mochel@digitalimplant.org +12 -0 # I2C: Add ALi 1563 i2c driver # # ChangeSet # 2004/04/02 11:02:40-08:00 mochel@digitalimplant.org # [PATCH] I2C: Add support for the ALi 1563 in the PCI IRQ routing code. # # arch/i386/pci/irq.c # 2004/03/19 13:49:31-08:00 mochel@digitalimplant.org +3 -2 # I2C: Add support for the ALi 1563 in the PCI IRQ routing code. # # ChangeSet # 2004/04/02 11:02:14-08:00 mochel@digitalimplant.org # [PATCH] I2C: Add ALi 1563 Device ID to pci_ids.h # # include/linux/pci_ids.h # 2004/04/01 15:38:19-08:00 mochel@digitalimplant.org +1 -0 # I2C: Add ALi 1563 Device ID to pci_ids.h # # ChangeSet # 2004/03/31 19:14:08-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-i2c # # include/linux/pci_ids.h # 2004/03/31 19:14:06-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/30 14:27:21-08:00 khali@linux-fr.org # [PATCH] I2C: Discard pointless comment in via686a # # The simple patch below discards a comment in via686a referencing a file # that doesn't belong to the Linux tree. Now that I tell people not to do # that in my porting guide, we better follow our own advice. # # drivers/i2c/chips/via686a.c # 2004/03/30 12:26:13-08:00 khali@linux-fr.org +0 -1 # I2C: Discard pointless comment in via686a # # ChangeSet # 2004/03/30 14:27:06-08:00 khali@linux-fr.org # [PATCH] I2C: Incorrect memset in eeprom.c # # Quoting Ralf Roesch: # # > currently I'm only working with Linux MIPS 2.4 kernel, # > so it would be nice if you could forward the patch for 2.6. # # OK, so here we are. Greg, this is the port to 2.6 of Ralf patch that # fixes an incorrect memset while initializing the eeprom driver. Please # apply. # # drivers/i2c/chips/eeprom.c # 2004/03/30 12:29:34-08:00 khali@linux-fr.org +1 -1 # I2C: Incorrect memset in eeprom.c # # ChangeSet # 2004/03/30 14:26:52-08:00 khali@linux-fr.org # [PATCH] I2C: i2c documentation update (2/2) # # Here is a patch to Documentation/i2c/sysfs-interface. This is mostly my # intent to make the document more readable. There are also a few # incorrectnesses fixed, and some comments added. # # Documentation/i2c/sysfs-interface # 2004/03/30 12:14:38-08:00 khali@linux-fr.org +37 -41 # I2C: i2c documentation update (2/2) # # ChangeSet # 2004/03/30 14:26:38-08:00 khali@linux-fr.org # [PATCH] I2C: i2c documentation update (1/2) # # Here is an update to my 2.4 to 2.6 i2c client porting guide. The changes # were inspired by the feedback I got with the drivers that have been # ported so far. # # Documentation/i2c/porting-clients # 2004/03/30 12:14:41-08:00 khali@linux-fr.org +29 -17 # I2C: i2c documentation update (1/2) # # ChangeSet # 2004/03/30 14:26:19-08:00 khali@linux-fr.org # [PATCH] I2C: Prevent misdetections in adm1021 driver # # Yet another patch for the adm1021 chip driver. I refined the detection # code a bit in order to prevent chip misdetection. Some chips handled # by the adm1021 driver are hard to detect and identify (LM84 and # MAX1617) so we tend to accept any chip it the valid I2C address range # as one of these. It has caused much, much trouble already. See these # threads for example: # # http://archives.andrew.net.au/lm-sensors/msg04448.html # http://archives.andrew.net.au/lm-sensors/msg04624.html # http://archives.andrew.net.au/lm-sensors/msg05560.html # http://archives.andrew.net.au/lm-sensors/msg05871.html # http://archives.andrew.net.au/lm-sensors/msg06754.html # http://archives.andrew.net.au/lm-sensors/msg07181.html # # And this ticket: # # http://www2.lm-sensors.nu/~lm78/readticket.cgi?ticket=1434 # # So I thought it would be good to prevent this kind of problems if # possible, and read the 8 datasheets again in search for ways to refine # the detection method. # # I changed it in sensors-detect already, and had positive feedback from # one user. I will also backport the changes to the driver to the 2.4 # version we have in CVS. # # What the patch does: # # * Use unused bits of two more registers (configuration and conversion # rate) to reduce misdetections. # # * Return with -ENODEV if the detection fails. # # * Change the order in which we try to identify the chips. We better # finish with the LM84 and the MAX1617, in this order, because they are # harder to identify and are more likely to result in false positives. # # * Refine LM84 detection. The LM84 has less features than the other # chips(chip cannot be stopped, conversion rate cannot be set, no low # limits) so it has extra unused bits. # # * Do not intialize the chip if it was detected as an LM84. This one # cannot be stopped so why would we try to start it again? And as said # right before, conversion rate isn't changeable either. # # Note that I couldn't test the changes on any supported chip since I # don't own any. Still I believe that they should be applied, since the # current code already broke one system and seriously harmed several # others. I believe it's not critical if it turns out that we reject # valid chips (which shouldn't happen if the datasheets are correct, # anyway). People will simply let us know and we'll be less restrictive. # In the meantime they can force the driver. That said, testers are # welcome, as usual. # # drivers/i2c/chips/adm1021.c # 2004/03/27 07:14:41-08:00 khali@linux-fr.org +13 -5 # I2C: Prevent misdetections in adm1021 driver # # ChangeSet # 2004/03/26 13:53:01-08:00 khali@linux-fr.org # [PATCH] I2C: Setting w83627hf fan_div preserves fan_min # # Here is a patch that updates the w83627hf driver in the exact same way I # did recently for the w83781d driver. There were two problems: # 1* Fan divisor storing code was ugly, badly ripped from the 2.4 w83627hf # driver and/or the 2.6 w83781d driver. # 2* Setting fan divisors wouldn't preserve fan mins. # # Exactly the same as w83781d: # http://archives.andrew.net.au/lm-sensors/msg06952.html # http://archives.andrew.net.au/lm-sensors/msg07008.html # # No surprise since the w83627hf driver is a fork of the w83781d driver. # # Since the two drivers are strongly similar, I took the code directly # from the updated w83781d driver. I cannot test the w83627hf driver # (testers welcome BTW) but this makes me feel confident that the code is # correct. # # To make it clear, this single patch is the w83627f equivalent of the # three patches I submitted for the w83781d: # * Cleanup # * Refactoring # * Setting fan_div preserves fan_min # All in one (much better looking BTW). # # drivers/i2c/chips/w83627hf.c # 2004/03/25 12:30:00-08:00 khali@linux-fr.org +31 -23 # I2C: Setting w83627hf fan_div preserves fan_min # # ChangeSet # 2004/03/26 13:52:39-08:00 khali@linux-fr.org # [PATCH] I2C: adm1021 (probably) does something VERY,VERY BAD # # Quoting myself: # # > 3* Drop adm1021's limit init. This was already done in the 2.4 driver # > and should have been done in 2.6 as well. # # Here is a patch that does that. It also prevents bit 7 (and unused bits) # of configuration register from being reset, as was discussed before: # http://archives.andrew.net.au/lm-sensors/msg04593.html # That second part needs to be backported to the 2.4 driver, and I will do # so. # # Additionally, we get rid of a useless label. # # The patch is untested (I don't own any supported chip) but quite # straightforward IMHO. # # drivers/i2c/chips/adm1021.c # 2004/03/25 11:45:18-08:00 khali@linux-fr.org +3 -16 # I2C: adm1021 (probably) does something VERY,VERY BAD # # ChangeSet # 2004/03/26 12:13:35-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-i2c # # include/linux/pci_ids.h # 2004/03/26 12:13:32-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/25 10:51:45-08:00 khali@linux-fr.org # [PATCH] I2C: initialize fan_mins in w83781d, asb100 and lm78 # # Quoting myself: # # > While testing, I found a corner case that isn't handled properly. It # > doesn't seem to be handled by the lm78 and the asb100 either. Setting # > fanN_div before ever reading from the chip or setting fanN_min will # > make use of fanN_min while it was never initialized. # # The following patch addesses the issue. Tested to work on my AS99127F # rev.1 (which means that only the changes to the w83781d driver were # actually tested). Testers welcome. # # drivers/i2c/chips/w83781d.c # 2004/03/22 15:09:59-08:00 khali@linux-fr.org +6 -0 # I2C: initialize fan_mins in w83781d, asb100 and lm78 # # drivers/i2c/chips/lm78.c # 2004/03/22 15:10:06-08:00 khali@linux-fr.org +6 -0 # I2C: initialize fan_mins in w83781d, asb100 and lm78 # # drivers/i2c/chips/asb100.c # 2004/03/22 15:05:12-08:00 khali@linux-fr.org +5 -0 # I2C: initialize fan_mins in w83781d, asb100 and lm78 # # ChangeSet # 2004/03/25 10:50:47-08:00 khali@linux-fr.org # [PATCH] I2C: Discard out-of-date comment in adm1021 driver # # This simple patch discards an out-of-date comment in the adm1021 driver. # I've done the same in our CVS repository where many more drivers were # affected. # # I agree it's not very important, but I prefer it to be done before any # driver with the error is used as a base to port a new driver, and the # misinformation spreads. # # drivers/i2c/chips/adm1021.c # 2004/03/18 05:42:50-08:00 khali@linux-fr.org +0 -3 # I2C: Discard out-of-date comment in adm1021 driver # # ChangeSet # 2004/03/19 13:24:39-08:00 aurelien@aurel32.net # [PATCH] I2C: add new chip driver: pcf8574 # # Please find below a patch against kernel 2.6.5-rc1 to add the pcf8574 # driver (an I/O expander for the I2C bus). I have ported it from the 2.4 # version, and it includes some fixes and simplifications. # # It has been reviewed by Jean Delvare on IRC. # # drivers/i2c/chips/pcf8574.c # 2004/03/18 13:23:10-08:00 aurelien@aurel32.net +245 -0 # I2C: add new chip driver: pcf8574 # # drivers/i2c/chips/Makefile # 2004/03/18 11:25:26-08:00 aurelien@aurel32.net +1 -0 # I2C: add new chip driver: pcf8574 # # drivers/i2c/chips/Kconfig # 2004/03/18 11:25:26-08:00 aurelien@aurel32.net +11 -0 # I2C: add new chip driver: pcf8574 # # drivers/i2c/chips/pcf8574.c # 2004/03/18 13:23:10-08:00 aurelien@aurel32.net +0 -0 # BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/i2c/chips/pcf8574.c # # ChangeSet # 2004/03/19 13:24:14-08:00 khali@linux-fr.org # [PATCH] I2C: w83781d fan_div code refactoring # # Quoting myself: # # > This tends to increase the size of the three set_store_regs_fan_div # > functions, and I am considering refactoring them at some point. Later # > though. # # Here is the promised refactoring. Tested on my AS99127F rev.1, seems to # work. As for the previous patch, there is a part that I cannot test with # the AS99127F, so additional testing is welcome. # # I agree this makes the code slightly less readable, but this saves 60 # lines of code (1754 bytes, around 3% of the driver total), and is # actually far less complex that I first feared. # # drivers/i2c/chips/w83781d.c # 2004/03/16 14:34:08-08:00 khali@linux-fr.org +17 -77 # I2C: w83781d fan_div code refactoring # # ChangeSet # 2004/03/16 20:13:31-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-i2c # # include/linux/pci_ids.h # 2004/03/16 20:13:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/15 22:33:45-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-i2c # # BitKeeper/deleted/.del-i2c-velleman.c~9a4fd0cf1e7a194c # 2004/03/15 22:33:31-08:00 akpm@bix.(none) +0 -0 # Auto merged # # BitKeeper/deleted/.del-i2c-elv.c~3b5450cc3140a51a # 2004/03/15 22:33:31-08:00 akpm@bix.(none) +0 -0 # Auto merged # # BitKeeper/deleted/.del-i2c-velleman.c~9a4fd0cf1e7a194c # 2004/03/15 22:33:31-08:00 akpm@bix.(none) +0 -0 # Merge rename: drivers/i2c/busses/i2c-velleman.c -> BitKeeper/deleted/.del-i2c-velleman.c~9a4fd0cf1e7a194c # # BitKeeper/deleted/.del-i2c-elv.c~3b5450cc3140a51a # 2004/03/15 22:33:31-08:00 akpm@bix.(none) +0 -0 # Merge rename: drivers/i2c/busses/i2c-elv.c -> BitKeeper/deleted/.del-i2c-elv.c~3b5450cc3140a51a # # ChangeSet # 2004/03/08 12:11:41-08:00 akpm@mnm.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/i2c-2.6 # into mnm.(none):/usr/src/bk-i2c # # include/linux/pci_ids.h # 2004/03/08 12:11:34-08:00 akpm@mnm.(none) +0 -0 # Auto merged # # drivers/pci/quirks.c # 2004/03/08 12:11:34-08:00 akpm@mnm.(none) +0 -0 # Auto merged # # drivers/i2c/busses/i2c-velleman.c # 2004/03/08 12:11:34-08:00 akpm@mnm.(none) +0 -0 # Auto merged # # drivers/i2c/busses/i2c-elv.c # 2004/03/08 12:11:34-08:00 akpm@mnm.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/07 01:29:25-08:00 akpm@mnm.(none) # Merge # # drivers/i2c/busses/i2c-velleman.c # 2004/03/07 01:29:23-08:00 akpm@mnm.(none) +0 -0 # SCCS merged # # drivers/i2c/busses/i2c-elv.c # 2004/03/07 01:29:23-08:00 akpm@mnm.(none) +0 -0 # SCCS merged # # include/linux/pci_ids.h # 2004/03/07 01:24:40-08:00 akpm@mnm.(none) +0 -0 # Auto merged # # drivers/pci/quirks.c # 2004/03/07 01:24:40-08:00 akpm@mnm.(none) +0 -0 # Auto merged # diff -Nru a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients --- a/Documentation/i2c/porting-clients Tue Apr 6 17:17:12 2004 +++ b/Documentation/i2c/porting-clients Tue Apr 6 17:17:12 2004 @@ -1,4 +1,4 @@ -Revision 3, 2003-10-04 +Revision 4, 2004-03-30 Jean Delvare Greg KH @@ -24,9 +24,10 @@ #include #include #include - #include /* if you need VRM support */ - #include /* if you have I/O operations */ - Some extra headers may be required for a given driver. + #include /* if you need VRM support */ + #include /* if you have I/O operations */ + Please respect this inclusion order. Some extra headers may be + required for a given driver (e.g. "lm75.h"). * [Addresses] SENSORS_I2C_END becomes I2C_CLIENT_END, SENSORS_ISA_END becomes I2C_CLIENT_ISA_END. @@ -37,9 +38,9 @@ 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 @@ * [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 @@ 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 @@ 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 @@ 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 @@ * [Layout] Avoid extra empty lines between comments and what they comment. Respect the coding style (see Documentation/CodingStyle), in particular when it comes to placing curly braces. + +* [Comments] Make sure that no comment refers to a file that isn't + part of the Linux source tree (typically doc/chips/), + and that remaining comments still match the code. Merging comment + lines when possible is encouraged. diff -Nru a/Documentation/i2c/sysfs-interface b/Documentation/i2c/sysfs-interface --- a/Documentation/i2c/sysfs-interface Tue Apr 6 17:17:12 2004 +++ b/Documentation/i2c/sysfs-interface Tue Apr 6 17:17:12 2004 @@ -74,18 +74,15 @@ ************ 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 @@ 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 @@ 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 @@ ******** 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 @@ **************** 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 @@ 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_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 -Nru a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c --- a/arch/i386/pci/irq.c Tue Apr 6 17:17:12 2004 +++ b/arch/i386/pci/irq.c Tue Apr 6 17:17:12 2004 @@ -590,12 +590,13 @@ { 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 -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig --- a/drivers/i2c/busses/Kconfig Tue Apr 6 17:17:12 2004 +++ b/drivers/i2c/busses/Kconfig Tue Apr 6 17:17:12 2004 @@ -5,6 +5,18 @@ menu "I2C Hardware Bus support" depends on I2C +config I2C_ALI1563 + tristate "ALI 1563" + depends on I2C && PCI && EXPERIMENTAL + help + If you say yes to this option, support will be included for the SMB + Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB + controller is part of the 7101 device, which is an ACPI-compliant + Power Management Unit (PMU). + + This driver can also be built as a module. If so, the module + will be called i2c-ali1563. + config I2C_ALI1535 tristate "ALI 1535" depends on I2C && PCI && EXPERIMENTAL diff -Nru a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile --- a/drivers/i2c/busses/Makefile Tue Apr 6 17:17:12 2004 +++ b/drivers/i2c/busses/Makefile Tue Apr 6 17:17:12 2004 @@ -4,6 +4,7 @@ obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o +obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o diff -Nru a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/i2c/busses/i2c-ali1563.c Tue Apr 6 17:17:12 2004 @@ -0,0 +1,416 @@ +/** + * 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 +#include +#include +#include + +#define ALI1563_MAX_TIMEOUT 500 +#define ALI1563_SMBBA 0x80 +#define ALI1563_SMB_IOEN 1 +#define ALI1563_SMB_HOSTEN 2 +#define ALI1563_SMB_IOSIZE 16 + +#define SMB_HST_STS (ali1563_smba + 0) +#define SMB_HST_CNTL1 (ali1563_smba + 1) +#define SMB_HST_CNTL2 (ali1563_smba + 2) +#define SMB_HST_CMD (ali1563_smba + 3) +#define SMB_HST_ADD (ali1563_smba + 4) +#define SMB_HST_DAT0 (ali1563_smba + 5) +#define SMB_HST_DAT1 (ali1563_smba + 6) +#define SMB_BLK_DAT (ali1563_smba + 7) + +#define HST_STS_BUSY 0x01 +#define HST_STS_INTR 0x02 +#define HST_STS_DEVERR 0x04 +#define HST_STS_BUSERR 0x08 +#define HST_STS_FAIL 0x10 +#define HST_STS_DONE 0x80 +#define HST_STS_BAD 0x1c + + +#define HST_CNTL1_TIMEOUT 0x80 +#define HST_CNTL1_LAST 0x40 + +#define HST_CNTL2_KILL 0x04 +#define HST_CNTL2_START 0x40 +#define HST_CNTL2_QUICK 0x00 +#define HST_CNTL2_BYTE 0x01 +#define HST_CNTL2_BYTE_DATA 0x02 +#define HST_CNTL2_WORD_DATA 0x03 +#define HST_CNTL2_BLOCK 0x05 + + + +static unsigned short ali1563_smba; + +static int ali1563_transaction(struct i2c_adapter * a) +{ + u32 data; + int timeout; + + dev_dbg(&a->dev, "Transaction (pre): STS=%02x, CNTL1=%02x, " + "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", + inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), + inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), + inb_p(SMB_HST_DAT1)); + + data = inb_p(SMB_HST_STS); + if (data & HST_STS_BAD) { + dev_warn(&a->dev,"ali1563: Trying to reset busy device\n"); + outb_p(data | HST_STS_BAD,SMB_HST_STS); + data = inb_p(SMB_HST_STS); + if (data & HST_STS_BAD) + return -EBUSY; + } + outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2); + + timeout = ALI1563_MAX_TIMEOUT; + do + i2c_delay(1); + while (((data = inb_p(SMB_HST_STS)) & HST_STS_BUSY) && --timeout); + + dev_dbg(&a->dev, "Transaction (post): STS=%02x, CNTL1=%02x, " + "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", + inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), + inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), + inb_p(SMB_HST_DAT1)); + + if (timeout && !(data & HST_STS_BAD)) + return 0; + dev_warn(&a->dev, "SMBus Error: %s%s%s%s%s\n", + timeout ? "Timeout " : "", + data & HST_STS_FAIL ? "Transaction Failed " : "", + data & HST_STS_BUSERR ? "No response or Bus Collision " : "", + data & HST_STS_DEVERR ? "Device Error " : "", + !(data & HST_STS_DONE) ? "Transaction Never Finished " : ""); + + if (!(data & HST_STS_DONE)) + /* Issue 'kill' to host controller */ + outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2); + else + /* Issue timeout to reset all devices on bus */ + outb_p(HST_CNTL1_TIMEOUT,SMB_HST_CNTL1); + return -1; +} + +static int ali1563_block_start(struct i2c_adapter * a) +{ + u32 data; + int timeout; + + dev_dbg(&a->dev, "Block (pre): STS=%02x, CNTL1=%02x, " + "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", + inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), + inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), + inb_p(SMB_HST_DAT1)); + + data = inb_p(SMB_HST_STS); + if (data & HST_STS_BAD) { + dev_warn(&a->dev,"ali1563: Trying to reset busy device\n"); + outb_p(data | HST_STS_BAD,SMB_HST_STS); + data = inb_p(SMB_HST_STS); + if (data & HST_STS_BAD) + return -EBUSY; + } + + /* Clear byte-ready bit */ + outb_p(data | HST_STS_DONE, SMB_HST_STS); + + /* Start transaction and wait for byte-ready bit to be set */ + outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2); + + timeout = ALI1563_MAX_TIMEOUT; + do + i2c_delay(1); + while (!((data = inb_p(SMB_HST_STS)) & HST_STS_DONE) && --timeout); + + dev_dbg(&a->dev, "Block (post): STS=%02x, CNTL1=%02x, " + "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", + inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), + inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), + inb_p(SMB_HST_DAT1)); + + if (timeout && !(data & HST_STS_BAD)) + return 0; + dev_warn(&a->dev, "SMBus Error: %s%s%s%s%s\n", + timeout ? "Timeout " : "", + data & HST_STS_FAIL ? "Transaction Failed " : "", + data & HST_STS_BUSERR ? "No response or Bus Collision " : "", + data & HST_STS_DEVERR ? "Device Error " : "", + !(data & HST_STS_DONE) ? "Transaction Never Finished " : ""); + return -1; +} + +static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8 rw) +{ + int i, len; + int error = 0; + + /* Do we need this? */ + outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1); + + if (rw == I2C_SMBUS_WRITE) { + len = data->block[0]; + if (len < 1) + len = 1; + else if (len > 32) + len = 32; + outb_p(len,SMB_HST_DAT0); + outb_p(data->block[1],SMB_BLK_DAT); + } else + len = 32; + + outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_BLOCK, SMB_HST_CNTL2); + + for (i = 0; i < len; i++) { + if (rw == I2C_SMBUS_WRITE) { + outb_p(data->block[i + 1], SMB_BLK_DAT); + if ((error = ali1563_block_start(a))) + break; + } else { + if ((error = ali1563_block_start(a))) + break; + if (i == 0) { + len = inb_p(SMB_HST_DAT0); + if (len < 1) + len = 1; + else if (len > 32) + len = 32; + } + data->block[i+1] = inb_p(SMB_BLK_DAT); + } + } + /* Do we need this? */ + outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1); + return error; +} + +static s32 ali1563_access(struct i2c_adapter * a, u16 addr, + unsigned short flags, char rw, u8 cmd, + int size, union i2c_smbus_data * data) +{ + int error = 0; + int timeout; + u32 reg; + + for (timeout = ALI1563_MAX_TIMEOUT; timeout; timeout--) { + if (!(reg = inb_p(SMB_HST_STS) & HST_STS_BUSY)) + break; + } + if (!timeout) + dev_warn(&a->dev,"SMBus not idle. HST_STS = %02x\n",reg); + outb_p(0xff,SMB_HST_STS); + + /* Map the size to what the chip understands */ + switch (size) { + case I2C_SMBUS_PROC_CALL: + dev_err(&a->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); + error = -EINVAL; + break; + case I2C_SMBUS_QUICK: + size = HST_CNTL2_QUICK; + break; + case I2C_SMBUS_BYTE: + size = HST_CNTL2_BYTE; + break; + case I2C_SMBUS_BYTE_DATA: + size = HST_CNTL2_BYTE_DATA; + break; + case I2C_SMBUS_WORD_DATA: + size = HST_CNTL2_WORD_DATA; + break; + case I2C_SMBUS_BLOCK_DATA: + size = HST_CNTL2_BLOCK; + break; + } + + outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD); + outb_p(inb_p(SMB_HST_CNTL2) | (size << 3), SMB_HST_CNTL2); + + /* Write the command register */ + switch(size) { + case HST_CNTL2_BYTE: + if (rw== I2C_SMBUS_WRITE) + outb_p(cmd, SMB_HST_CMD); + break; + case HST_CNTL2_BYTE_DATA: + outb_p(cmd, SMB_HST_CMD); + if (rw == I2C_SMBUS_WRITE) + outb_p(data->byte, SMB_HST_DAT0); + break; + case HST_CNTL2_WORD_DATA: + outb_p(cmd, SMB_HST_CMD); + if (rw == I2C_SMBUS_WRITE) { + outb_p(data->word & 0xff, SMB_HST_DAT0); + outb_p((data->word & 0xff00) >> 8, SMB_HST_DAT1); + } + break; + case HST_CNTL2_BLOCK: + outb_p(cmd, SMB_HST_CMD); + error = ali1563_block(a,data,rw); + goto Done; + } + + if ((error = ali1563_transaction(a))) + goto Done; + + if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK)) + goto Done; + + switch (size) { + case HST_CNTL2_BYTE: /* Result put in SMBHSTDAT0 */ + data->byte = inb_p(SMB_HST_DAT0); + break; + case HST_CNTL2_BYTE_DATA: + data->byte = inb_p(SMB_HST_DAT0); + break; + case HST_CNTL2_WORD_DATA: + data->word = inb_p(SMB_HST_DAT0) + (inb_p(SMB_HST_DAT1) << 8); + break; + } +Done: + return error; +} + +static u32 ali1563_func(struct i2c_adapter * a) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA; +} + + +static void ali1563_enable(struct pci_dev * dev) +{ + u16 ctrl; + + pci_read_config_word(dev,ALI1563_SMBBA,&ctrl); + ctrl |= 0x7; + pci_write_config_word(dev,ALI1563_SMBBA,ctrl); +} + +static int __init ali1563_setup(struct pci_dev * dev) +{ + u16 ctrl; + + pci_read_config_word(dev,ALI1563_SMBBA,&ctrl); + printk("ali1563: SMBus control = %04x\n",ctrl); + + /* Check if device is even enabled first */ + if (!(ctrl & ALI1563_SMB_IOEN)) { + dev_warn(&dev->dev,"I/O space not enabled, trying manually\n"); + ali1563_enable(dev); + } + if (!(ctrl & ALI1563_SMB_IOEN)) { + dev_warn(&dev->dev,"I/O space still not enabled, giving up\n"); + goto Err; + } + if (!(ctrl & ALI1563_SMB_HOSTEN)) { + dev_warn(&dev->dev,"Host Controller not enabled\n"); + goto Err; + } + + /* SMB I/O Base in high 12 bits and must be aligned with the + * size of the I/O space. */ + ali1563_smba = ctrl & ~(ALI1563_SMB_IOSIZE - 1); + if (!ali1563_smba) { + dev_warn(&dev->dev,"ali1563_smba Uninitialized\n"); + goto Err; + } + if (!request_region(ali1563_smba,ALI1563_SMB_IOSIZE,"i2c-ali1563")) { + dev_warn(&dev->dev,"Could not allocate I/O space"); + goto Err; + } + + return 0; +Err: + return -ENODEV; +} + +static void __exit ali1563_shutdown(struct pci_dev * dev) +{ + release_region(ali1563_smba,ALI1563_SMB_IOSIZE); +} + +static struct i2c_algorithm ali1563_algorithm = { + .name = "Non-i2c SMBus adapter", + .id = I2C_ALGO_SMBUS, + .smbus_xfer = ali1563_access, + .functionality = ali1563_func, +}; + +static struct i2c_adapter ali1563_adapter = { + .owner = THIS_MODULE, + .algo = &ali1563_algorithm, +}; + +static int __init ali1563_probe(struct pci_dev * dev, + const struct pci_device_id * id_table) +{ + int error; + + if ((error = ali1563_setup(dev))) + return error; + ali1563_adapter.dev.parent = &dev->dev; + sprintf(ali1563_adapter.name,"SMBus ALi 1563 Adapter @ %04x", + ali1563_smba); + if ((error = i2c_add_adapter(&ali1563_adapter))) + ali1563_shutdown(dev); + printk("%s: Returning %d\n",__FUNCTION__,error); + return error; +} + +static void __exit ali1563_remove(struct pci_dev * dev) +{ + i2c_del_adapter(&ali1563_adapter); + ali1563_shutdown(dev); +} + +static struct pci_device_id __devinitdata ali1563_id_table[] = { + { + .vendor = PCI_VENDOR_ID_AL, + .device = PCI_DEVICE_ID_AL_M1563, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + {}, +}; + +static struct pci_driver ali1563_pci_driver = { + .name = "i2c-ali1563", + .id_table = ali1563_id_table, + .probe = ali1563_probe, + .remove = ali1563_remove, +}; + +static int __init ali1563_init(void) +{ + return pci_module_init(&ali1563_pci_driver); +} + +module_init(ali1563_init); + +static void __exit ali1563_exit(void) +{ + pci_unregister_driver(&ali1563_pci_driver); +} + +module_exit(ali1563_exit); + +MODULE_LICENSE("GPL"); diff -Nru a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig --- a/drivers/i2c/chips/Kconfig Tue Apr 6 17:17:12 2004 +++ b/drivers/i2c/chips/Kconfig Tue Apr 6 17:17:12 2004 @@ -209,4 +209,15 @@ This driver can also be built as a module. If so, the module will be called eeprom. +config SENSORS_PCF8574 + tristate "Philips PCF8574 and PCF8574A" + depends on I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Philips PCF8574 and + PCF8574A chips. + + This driver can also be built as a module. If so, the module + will be called pcf8574. + endmenu diff -Nru a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile --- a/drivers/i2c/chips/Makefile Tue Apr 6 17:17:12 2004 +++ b/drivers/i2c/chips/Makefile Tue Apr 6 17:17:12 2004 @@ -19,6 +19,7 @@ obj-$(CONFIG_SENSORS_LM83) += lm83.o obj-$(CONFIG_SENSORS_LM85) += lm85.o obj-$(CONFIG_SENSORS_LM90) += lm90.o +obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o diff -Nru a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c --- a/drivers/i2c/chips/adm1021.c Tue Apr 6 17:17:12 2004 +++ b/drivers/i2c/chips/adm1021.c Tue Apr 6 17:17:12 2004 @@ -98,10 +98,6 @@ 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 { @@ -151,9 +147,6 @@ .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) \ @@ -253,8 +246,12 @@ /* 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 +269,14 @@ 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 +309,11 @@ /* 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,7 +328,6 @@ return 0; -error3: error1: kfree(new_client); error0: @@ -336,17 +336,9 @@ 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); } diff -Nru a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c --- a/drivers/i2c/chips/asb100.c Tue Apr 6 17:17:12 2004 +++ b/drivers/i2c/chips/asb100.c Tue Apr 6 17:17:12 2004 @@ -807,6 +807,11 @@ /* Initialize the chip */ asb100_init_client(new_client); + /* A few vars need to be filled upon startup */ + data->fan_min[0] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(0)); + data->fan_min[1] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(1)); + data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2)); + /* Register sysfs hooks */ device_create_file_in(new_client, 0); device_create_file_in(new_client, 1); diff -Nru a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c --- a/drivers/i2c/chips/eeprom.c Tue Apr 6 17:17:12 2004 +++ b/drivers/i2c/chips/eeprom.c Tue Apr 6 17:17:12 2004 @@ -197,7 +197,7 @@ sizeof(struct eeprom_data)); data = (struct eeprom_data *) (new_client + 1); - memset(data, 0xff, EEPROM_SIZE); + memset(data->data, 0xff, EEPROM_SIZE); i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; diff -Nru a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c --- a/drivers/i2c/chips/lm78.c Tue Apr 6 17:17:12 2004 +++ b/drivers/i2c/chips/lm78.c Tue Apr 6 17:17:12 2004 @@ -625,6 +625,12 @@ /* Initialize the LM78 chip */ lm78_init_client(new_client); + /* A few vars need to be filled upon startup */ + for (i = 0; i < 3; i++) { + data->fan_min[i] = lm78_read_value(new_client, + LM78_REG_FAN_MIN(i)); + } + /* Register sysfs hooks */ device_create_file(&new_client->dev, &dev_attr_in0_input); device_create_file(&new_client->dev, &dev_attr_in0_min); diff -Nru a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/i2c/chips/pcf8574.c Tue Apr 6 17:17:12 2004 @@ -0,0 +1,245 @@ +/* + pcf8574.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 2000 Frodo Looijaard , + Philip Edelbrock , + Dan Eaton + Ported to Linux 2.6 by Aurelien Jarno with + the help of Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* A few notes about the PCF8574: + +* The PCF8574 is an 8-bit I/O expander for the I2C bus produced by + Philips Semiconductors. It is designed to provide a byte I2C + interface to up to 8 separate devices. + +* The PCF8574 appears as a very simple SMBus device which can be + read from or written to with SMBUS byte read/write accesses. + + --Dan + +*/ + +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { 0x20, 0x27, 0x38, 0x3f, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; +static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_2(pcf8574, pcf8574a); + +/* Initial values */ +#define PCF8574_INIT 255 /* All outputs on (input mode) */ + +/* Each client has this additional data */ +struct pcf8574_data { + struct semaphore update_lock; + + u8 read, write; /* Register values */ +}; + +static int pcf8574_attach_adapter(struct i2c_adapter *adapter); +static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind); +static int pcf8574_detach_client(struct i2c_client *client); +static void pcf8574_init_client(struct i2c_client *client); +static struct pcf8574_data *pcf8574_update_client(struct device *dev); + +/* This is the driver that will be inserted */ +static struct i2c_driver pcf8574_driver = { + .owner = THIS_MODULE, + .name = "pcf8574", + .id = I2C_DRIVERID_PCF8574, + .flags = I2C_DF_NOTIFY, + .attach_adapter = pcf8574_attach_adapter, + .detach_client = pcf8574_detach_client, +}; + +static int pcf8574_id = 0; + +/* following are the sysfs callback functions */ +static ssize_t show_read(struct device *dev, char *buf) +{ + struct pcf8574_data *data = pcf8574_update_client(dev); + return sprintf(buf, "%u\n", data->read); +} + +static DEVICE_ATTR(read, S_IRUGO, show_read, NULL); + +static ssize_t show_write(struct device *dev, char *buf) +{ + struct pcf8574_data *data = i2c_get_clientdata(to_i2c_client(dev)); + return sprintf(buf, "%u\n", data->write); +} + +static ssize_t set_write(struct device *dev, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pcf8574_data *data = i2c_get_clientdata(client); + data->write = simple_strtoul(buf, NULL, 10); + i2c_smbus_write_byte(client, data->write); + return count; +} + +static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write); + +/* + * Real code + */ + +static int pcf8574_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, pcf8574_detect); +} + +/* This function is called by i2c_detect */ +int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct pcf8574_data *data; + int err = 0; + const char *client_name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. */ + if (!(new_client = kmalloc(sizeof(struct i2c_client) + + sizeof(struct pcf8574_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + memset(new_client, 0, sizeof(struct i2c_client) + + sizeof(struct pcf8574_data)); + + data = (struct pcf8574_data *) (new_client + 1); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &pcf8574_driver; + new_client->flags = 0; + + /* Now, we would do the remaining detection. But the PCF8574 is plainly + impossible to detect! Stupid chip. */ + + /* Determine the chip type */ + if (kind <= 0) { + if (address >= 0x38 && address <= 0x3f) + kind = pcf8574a; + else + kind = pcf8574; + } + + if (kind == pcf8574a) + client_name = "pcf8574a"; + else + client_name = "pcf8574"; + + /* Fill in the remaining client fields and put it into the global list */ + strlcpy(new_client->name, client_name, I2C_NAME_SIZE); + + new_client->id = pcf8574_id++; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the PCF8574 chip */ + pcf8574_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_read); + device_create_file(&new_client->dev, &dev_attr_write); + return 0; + +/* OK, this is not exactly good programming practice, usually. But it is + very code-efficient in this case. */ + + exit_free: + kfree(new_client); + exit: + return err; +} + +static int pcf8574_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(client); + return 0; +} + +/* Called when we have found a new PCF8574. */ +static void pcf8574_init_client(struct i2c_client *client) +{ + struct pcf8574_data *data = i2c_get_clientdata(client); + data->write = PCF8574_INIT; + i2c_smbus_write_byte(client, data->write); +} + +static struct pcf8574_data *pcf8574_update_client(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pcf8574_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + dev_dbg(&client->dev, "Starting pcf8574 update\n"); + data->read = i2c_smbus_read_byte(client); + up(&data->update_lock); + + return data; +} + +static int __init pcf8574_init(void) +{ + return i2c_add_driver(&pcf8574_driver); +} + +static void __exit pcf8574_exit(void) +{ + i2c_del_driver(&pcf8574_driver); +} + + +MODULE_AUTHOR + ("Frodo Looijaard , " + "Philip Edelbrock , " + "Dan Eaton " + "and Aurelien Jarno "); +MODULE_DESCRIPTION("PCF8574 driver"); +MODULE_LICENSE("GPL"); + +module_init(pcf8574_init); +module_exit(pcf8574_exit); diff -Nru a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c --- a/drivers/i2c/chips/via686a.c Tue Apr 6 17:17:12 2004 +++ b/drivers/i2c/chips/via686a.c Tue Apr 6 17:17:12 2004 @@ -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. */ diff -Nru a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c --- a/drivers/i2c/chips/w83627hf.c Tue Apr 6 17:17:12 2004 +++ b/drivers/i2c/chips/w83627hf.c Tue Apr 6 17:17:12 2004 @@ -659,34 +659,37 @@ (long) DIV_FROM_REG(data->fan_div[nr - 1])); } +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ static ssize_t store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val, old, old2, old3 = 0; + unsigned long min; + u8 reg; - val = simple_strtoul(buf, NULL, 10); - old = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); - old3 = w83627hf_read_value(client, W83781D_REG_VBAT); - data->fan_div[nr - 1] = DIV_TO_REG(val); - - if (nr >= 3 && data->type != w83697hf) { - old2 = w83627hf_read_value(client, W83781D_REG_PIN); - old2 = (old2 & 0x3f) | ((data->fan_div[2] & 0x03) << 6); - w83627hf_write_value(client, W83781D_REG_PIN, old2); - old3 = (old3 & 0x7f) | ((data->fan_div[2] & 0x04) << 5); - } - if (nr >= 2) { - old = (old & 0x3f) | ((data->fan_div[1] & 0x03) << 6); - old3 = (old3 & 0xbf) | ((data->fan_div[1] & 0x04) << 4); - } - if (nr >= 1) { - old = (old & 0xcf) | ((data->fan_div[0] & 0x03) << 4); - w83627hf_write_value(client, W83781D_REG_VID_FANDIV, old); - old3 = (old3 & 0xdf) | ((data->fan_div[0] & 0x04) << 3); - w83627hf_write_value(client, W83781D_REG_VBAT, old3); - } + /* Save fan_min */ + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + + data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10)); + + reg = (w83627hf_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) + & (nr==0 ? 0xcf : 0x3f)) + | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); + w83627hf_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); + + reg = (w83627hf_read_value(client, W83781D_REG_VBAT) + & ~(1 << (5 + nr))) + | ((data->fan_div[nr] & 0x04) << (3 + nr)); + w83627hf_write_value(client, W83781D_REG_VBAT, reg); + + /* Restore fan_min */ + data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); return count; } @@ -700,7 +703,7 @@ 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) @@ -981,6 +984,11 @@ /* 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); diff -Nru a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c --- a/drivers/i2c/chips/w83781d.c Tue Apr 6 17:17:12 2004 +++ b/drivers/i2c/chips/w83781d.c Tue Apr 6 17:17:12 2004 @@ -620,7 +620,7 @@ least suprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ static ssize_t -store_regs_fan_div_1(struct device *dev, const char *buf, size_t count) +store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct w83781d_data *data = i2c_get_clientdata(client); @@ -628,92 +628,28 @@ u8 reg; /* Save fan_min */ - min = FAN_FROM_REG(data->fan_min[0], - DIV_FROM_REG(data->fan_div[0])); + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); - data->fan_div[0] = DIV_TO_REG(simple_strtoul(buf, NULL, 10), + data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10), data->type); - reg = w83781d_read_value(client, W83781D_REG_VID_FANDIV) & 0xcf; - reg |= (data->fan_div[0] & 0x03) << 4; - w83781d_write_value(client, W83781D_REG_VID_FANDIV, reg); + reg = (w83781d_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) + & (nr==0 ? 0xcf : 0x3f)) + | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); + w83781d_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); /* w83781d and as99127f don't have extended divisor bits */ if (data->type != w83781d && data->type != as99127f) { - reg = w83781d_read_value(client, W83781D_REG_VBAT) & 0xdf; - reg |= (data->fan_div[0] & 0x04) << 3; + reg = (w83781d_read_value(client, W83781D_REG_VBAT) + & ~(1 << (5 + nr))) + | ((data->fan_div[nr] & 0x04) << (3 + nr)); w83781d_write_value(client, W83781D_REG_VBAT, reg); } /* Restore fan_min */ - data->fan_min[0] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[0])); - w83781d_write_value(client, W83781D_REG_FAN_MIN(1), data->fan_min[0]); - - return count; -} - -static ssize_t -store_regs_fan_div_2(struct device *dev, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - unsigned long min; - u8 reg; - - /* Save fan_min */ - min = FAN_FROM_REG(data->fan_min[1], - DIV_FROM_REG(data->fan_div[1])); - - data->fan_div[1] = DIV_TO_REG(simple_strtoul(buf, NULL, 10), - data->type); - - reg = w83781d_read_value(client, W83781D_REG_VID_FANDIV) & 0x3f; - reg |= (data->fan_div[1] & 0x03) << 6; - w83781d_write_value(client, W83781D_REG_VID_FANDIV, reg); - - /* w83781d and as99127f don't have extended divisor bits */ - if (data->type != w83781d && data->type != as99127f) { - reg = w83781d_read_value(client, W83781D_REG_VBAT) & 0xbf; - reg |= (data->fan_div[1] & 0x04) << 4; - w83781d_write_value(client, W83781D_REG_VBAT, reg); - } - - /* Restore fan_min */ - data->fan_min[1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[1])); - w83781d_write_value(client, W83781D_REG_FAN_MIN(2), data->fan_min[1]); - - return count; -} - -static ssize_t -store_regs_fan_div_3(struct device *dev, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - unsigned long min; - u8 reg; - - /* Save fan_min */ - min = FAN_FROM_REG(data->fan_min[2], - DIV_FROM_REG(data->fan_div[2])); - - data->fan_div[2] = DIV_TO_REG(simple_strtoul(buf, NULL, 10), - data->type); - - reg = w83781d_read_value(client, W83781D_REG_PIN) & 0x3f; - reg |= (data->fan_div[2] & 0x03) << 6; - w83781d_write_value(client, W83781D_REG_PIN, reg); - - /* w83781d and as99127f don't have extended divisor bits */ - if (data->type != w83781d && data->type != as99127f) { - reg = w83781d_read_value(client, W83781D_REG_VBAT) & 0x7f; - reg |= (data->fan_div[2] & 0x04) << 5; - w83781d_write_value(client, W83781D_REG_VBAT, reg); - } - - /* Restore fan_min */ - data->fan_min[2] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[2])); - w83781d_write_value(client, W83781D_REG_FAN_MIN(3), data->fan_min[2]); + data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + w83781d_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); return count; } @@ -723,6 +659,10 @@ { \ 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); @@ -1311,6 +1251,12 @@ /* Initialize the chip */ w83781d_init_client(new_client); + + /* A few vars need to be filled upon startup */ + for (i = 1; i <= 3; i++) { + data->fan_min[i - 1] = w83781d_read_value(new_client, + W83781D_REG_FAN_MIN(i)); + } /* Register sysfs hooks */ device_create_file_in(new_client, 0); diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h Tue Apr 6 17:17:12 2004 +++ b/include/linux/pci_ids.h Tue Apr 6 17:17:12 2004 @@ -994,6 +994,7 @@ #define PCI_DEVICE_ID_AL_M1531 0x1531 #define PCI_DEVICE_ID_AL_M1533 0x1533 #define PCI_DEVICE_ID_AL_M1541 0x1541 +#define PCI_DEVICE_ID_AL_M1563 0x1563 #define PCI_DEVICE_ID_AL_M1621 0x1621 #define PCI_DEVICE_ID_AL_M1631 0x1631 #define PCI_DEVICE_ID_AL_M1632 0x1632