bk://kernel.bkbits.net/gregkh/linux/i2c-2.6 khali@linux-fr.org|ChangeSet|20040330222721|39071 khali # This is a BitKeeper generated diff -Nru style patch. # # 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 Thu Apr 1 00:55:50 2004 +++ b/Documentation/i2c/porting-clients Thu Apr 1 00:55:50 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 Thu Apr 1 00:55:50 2004 +++ b/Documentation/i2c/sysfs-interface Thu Apr 1 00:55:50 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/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig --- a/drivers/i2c/chips/Kconfig Thu Apr 1 00:55:50 2004 +++ b/drivers/i2c/chips/Kconfig Thu Apr 1 00:55:50 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 Thu Apr 1 00:55:50 2004 +++ b/drivers/i2c/chips/Makefile Thu Apr 1 00:55:50 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 Thu Apr 1 00:55:50 2004 +++ b/drivers/i2c/chips/adm1021.c Thu Apr 1 00:55:50 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 Thu Apr 1 00:55:50 2004 +++ b/drivers/i2c/chips/asb100.c Thu Apr 1 00:55:50 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 Thu Apr 1 00:55:50 2004 +++ b/drivers/i2c/chips/eeprom.c Thu Apr 1 00:55:50 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 Thu Apr 1 00:55:50 2004 +++ b/drivers/i2c/chips/lm78.c Thu Apr 1 00:55:50 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 Thu Apr 1 00:55:50 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 Thu Apr 1 00:55:50 2004 +++ b/drivers/i2c/chips/via686a.c Thu Apr 1 00:55:50 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 Thu Apr 1 00:55:50 2004 +++ b/drivers/i2c/chips/w83627hf.c Thu Apr 1 00:55:50 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 Thu Apr 1 00:55:50 2004 +++ b/drivers/i2c/chips/w83781d.c Thu Apr 1 00:55:50 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);