aboutsummaryrefslogtreecommitdiffstats
path: root/i2c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-04-03 15:02:22 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2006-04-03 15:02:22 -0700
commitf9b3d7ae998e086d7247a662e656c40f4de0a18b (patch)
tree45e723c9aa041ae729b47c429ec3d6bfa54c6660 /i2c
parent158d7a505ae2253c37c0ffd4a9460cbcf7ef612f (diff)
downloadpatches-f9b3d7ae998e086d7247a662e656c40f4de0a18b.tar.gz
new i2c patches
Diffstat (limited to 'i2c')
-rw-r--r--i2c/hwmon-f71805f-no-global-resource.patch56
-rw-r--r--i2c/hwmon-lm83-add-lm82-support.patch180
-rw-r--r--i2c/hwmon-smsc47m192-new-driver.patch843
-rw-r--r--i2c/hwmon-sysfs-interface-individual-alarm-files.patch145
-rw-r--r--i2c/hwmon-w83627ehf-add-alarms.patch132
-rw-r--r--i2c/hwmon-w83627ehf-add-voltages.patch198
-rw-r--r--i2c/hwmon-w83792d-quiet-on-misdetection.patch48
-rw-r--r--i2c/i2c-parport-require-type-parameter.patch127
-rw-r--r--i2c/i2c-piix4-add-ati-smbus-support.patch86
-rw-r--r--i2c/i2c-sis96x-remove-init-log-message.patch46
-rw-r--r--i2c/rtc-ds1374-convert-tasklet-to-workqueue.patch83
-rw-r--r--i2c/rtc-m41t00-driver-cleanup.patch145
-rw-r--r--i2c/rtc-m41t00-driver-should-use-workqueue-instead-of-tasklet.patch84
13 files changed, 2173 insertions, 0 deletions
diff --git a/i2c/hwmon-f71805f-no-global-resource.patch b/i2c/hwmon-f71805f-no-global-resource.patch
new file mode 100644
index 0000000000000..0a17ed3c95240
--- /dev/null
+++ b/i2c/hwmon-f71805f-no-global-resource.patch
@@ -0,0 +1,56 @@
+From khali@linux-fr.org Thu Mar 23 07:39:52 2006
+Date: Thu, 23 Mar 2006 16:40:23 +0100
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Subject: [PATCH 06/10] f71805f: Resource needs not be global
+Message-Id: <20060323164023.f5380bf9.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-f71805f-no-global-resource.patch
+
+The F71805F I/O resource structure needs not be a global variable,
+as the platform core allocs its own copy of it anyway.
+
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/hwmon/f71805f.c | 15 +++++++--------
+ 1 file changed, 7 insertions(+), 8 deletions(-)
+
+--- gregkh-2.6.orig/drivers/hwmon/f71805f.c
++++ gregkh-2.6/drivers/hwmon/f71805f.c
+@@ -99,10 +99,6 @@ superio_exit(int base)
+ #define ADDR_REG_OFFSET 0
+ #define DATA_REG_OFFSET 1
+
+-static struct resource f71805f_resource __initdata = {
+- .flags = IORESOURCE_IO,
+-};
+-
+ /*
+ * Registers
+ */
+@@ -782,6 +778,11 @@ static struct platform_driver f71805f_dr
+
+ static int __init f71805f_device_add(unsigned short address)
+ {
++ struct resource res = {
++ .start = address,
++ .end = address + REGION_LENGTH - 1,
++ .flags = IORESOURCE_IO,
++ };
+ int err;
+
+ pdev = platform_device_alloc(DRVNAME, address);
+@@ -791,10 +792,8 @@ static int __init f71805f_device_add(uns
+ goto exit;
+ }
+
+- f71805f_resource.start = address;
+- f71805f_resource.end = address + REGION_LENGTH - 1;
+- f71805f_resource.name = pdev->name;
+- err = platform_device_add_resources(pdev, &f71805f_resource, 1);
++ res.name = pdev->name;
++ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device resource addition failed "
+ "(%d)\n", err);
diff --git a/i2c/hwmon-lm83-add-lm82-support.patch b/i2c/hwmon-lm83-add-lm82-support.patch
new file mode 100644
index 0000000000000..765d97137985b
--- /dev/null
+++ b/i2c/hwmon-lm83-add-lm82-support.patch
@@ -0,0 +1,180 @@
+From khali@linux-fr.org Thu Mar 23 07:19:16 2006
+Date: Thu, 23 Mar 2006 16:19:49 +0100
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: Jordan Crouse <jordan.crouse@amd.com>
+Subject: [PATCH 01/10] lm83: Add LM82 support
+Message-Id: <20060323161949.e6dd074b.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-lm83-add-lm82-support.patch
+
+From: Jordan Crouse <jordan.crouse@amd.com>
+
+Add LM82 temperature sensor support (similar to the LM83,
+but less featureful).
+
+Signed-off-by: Jordan Crouse <jordan.crouse@amd.com>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/hwmon/lm83 | 16 +++++++++++----
+ drivers/hwmon/Kconfig | 4 +--
+ drivers/hwmon/lm83.c | 50 ++++++++++++++++++++++++++++++++++-------------
+ 3 files changed, 51 insertions(+), 19 deletions(-)
+
+--- gregkh-2.6.orig/Documentation/hwmon/lm83
++++ gregkh-2.6/Documentation/hwmon/lm83
+@@ -7,6 +7,10 @@ Supported chips:
+ Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+ Datasheet: Publicly available at the National Semiconductor website
+ http://www.national.com/pf/LM/LM83.html
++ * National Semiconductor LM82
++ Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
++ Datasheet: Publicly available at the National Semiconductor website
++ http://www.national.com/pf/LM/LM82.html
+
+
+ Author: Jean Delvare <khali@linux-fr.org>
+@@ -15,10 +19,11 @@ Description
+ -----------
+
+ The LM83 is a digital temperature sensor. It senses its own temperature as
+-well as the temperature of up to three external diodes. It is compatible
+-with many other devices such as the LM84 and all other ADM1021 clones.
+-The main difference between the LM83 and the LM84 in that the later can
+-only sense the temperature of one external diode.
++well as the temperature of up to three external diodes. The LM82 is
++a stripped down version of the LM83 that only supports one external diode.
++Both are compatible with many other devices such as the LM84 and all
++other ADM1021 clones. The main difference between the LM83 and the LM84
++in that the later can only sense the temperature of one external diode.
+
+ Using the adm1021 driver for a LM83 should work, but only two temperatures
+ will be reported instead of four.
+@@ -36,6 +41,9 @@ Unconfirmed motherboards:
+ Iwill MPX2
+ Soltek SL-75DRV5
+
++The LM82 is confirmed to have been found on most AMD Geode reference
++designs and test platforms.
++
+ The driver has been successfully tested by Magnus Forsström, who I'd
+ like to thank here. More testers will be of course welcome.
+
+--- gregkh-2.6.orig/drivers/hwmon/Kconfig
++++ gregkh-2.6/drivers/hwmon/Kconfig
+@@ -236,11 +236,11 @@ config SENSORS_LM80
+ will be called lm80.
+
+ config SENSORS_LM83
+- tristate "National Semiconductor LM83"
++ tristate "National Semiconductor LM83 and compatibles"
+ depends on HWMON && I2C
+ help
+ If you say yes here you get support for National Semiconductor
+- LM83 sensor chips.
++ LM82 and LM83 sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called lm83.
+--- gregkh-2.6.orig/drivers/hwmon/lm83.c
++++ gregkh-2.6/drivers/hwmon/lm83.c
+@@ -12,6 +12,10 @@
+ * Since the datasheet omits to give the chip stepping code, I give it
+ * here: 0x03 (at register 0xff).
+ *
++ * Also supports the LM82 temp sensor, which is basically a stripped down
++ * model of the LM83. Datasheet is here:
++ * http://www.national.com/pf/LM/LM82.html
++ *
+ * 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
+@@ -52,7 +56,7 @@ static unsigned short normal_i2c[] = { 0
+ * Insmod parameters
+ */
+
+-I2C_CLIENT_INSMOD_1(lm83);
++I2C_CLIENT_INSMOD_2(lm83, lm82);
+
+ /*
+ * The LM83 registers
+@@ -283,6 +287,9 @@ static int lm83_detect(struct i2c_adapte
+ if (man_id == 0x01) { /* National Semiconductor */
+ if (chip_id == 0x03) {
+ kind = lm83;
++ } else
++ if (chip_id == 0x01) {
++ kind = lm82;
+ }
+ }
+
+@@ -296,6 +303,9 @@ static int lm83_detect(struct i2c_adapte
+
+ if (kind == lm83) {
+ name = "lm83";
++ } else
++ if (kind == lm82) {
++ name = "lm82";
+ }
+
+ /* We can fill in the remaining client fields */
+@@ -319,32 +329,46 @@ static int lm83_detect(struct i2c_adapte
+ goto exit_detach;
+ }
+
++ /*
++ * The LM82 can only monitor one external diode which is
++ * at the same register as the LM83 temp3 entry - so we
++ * declare 1 and 3 common, and then 2 and 4 only for the LM83.
++ */
++
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_input.dev_attr);
+- device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp3_input.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp4_input.dev_attr);
++
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_max.dev_attr);
+ device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_max.dev_attr);
+- device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp3_max.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp4_max.dev_attr);
++
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_crit.dev_attr);
+ device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp2_crit.dev_attr);
+- device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp3_crit.dev_attr);
+- device_create_file(&new_client->dev,
+- &sensor_dev_attr_temp4_crit.dev_attr);
++
+ device_create_file(&new_client->dev, &dev_attr_alarms);
+
++ if (kind == lm83) {
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_temp2_input.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_temp4_input.dev_attr);
++
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_temp2_max.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_temp4_max.dev_attr);
++
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_temp2_crit.dev_attr);
++ device_create_file(&new_client->dev,
++ &sensor_dev_attr_temp4_crit.dev_attr);
++ }
++
+ return 0;
+
+ exit_detach:
diff --git a/i2c/hwmon-smsc47m192-new-driver.patch b/i2c/hwmon-smsc47m192-new-driver.patch
new file mode 100644
index 0000000000000..9f5b8811ea3a5
--- /dev/null
+++ b/i2c/hwmon-smsc47m192-new-driver.patch
@@ -0,0 +1,843 @@
+From khali@linux-fr.org Thu Mar 23 07:36:55 2006
+Date: Thu, 23 Mar 2006 16:37:23 +0100
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: Hartmut Rick <linux@rick.claranet.de>
+Subject: [PATCH 04/10] smsc47m192: New hwmon driver for SMSC LPC47M192/997
+Message-Id: <20060323163723.46c3c92b.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-smsc47m192-new-driver.patch
+
+From: Hartmut Rick <linux@rick.claranet.de>
+
+New driver (smsc47m192) which supports voltage and temperature
+measurement features of SMSC LPC47M192 and LPC47M997 chips.
+
+Signed-off-by: Hartmut Rick <linux@rick.claranet.de>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/hwmon/smsc47m192 | 102 +++++
+ Documentation/hwmon/sysfs-interface | 6
+ drivers/hwmon/Kconfig | 23 +
+ drivers/hwmon/Makefile | 1
+ drivers/hwmon/smsc47m192.c | 648 ++++++++++++++++++++++++++++++++++++
+ 5 files changed, 779 insertions(+), 1 deletion(-)
+
+--- /dev/null
++++ gregkh-2.6/Documentation/hwmon/smsc47m192
+@@ -0,0 +1,102 @@
++Kernel driver smsc47m192
++========================
++
++Supported chips:
++ * SMSC LPC47M192 and LPC47M997
++ Prefix: 'smsc47m192'
++ Addresses scanned: I2C 0x2c - 0x2d
++ Datasheet: The datasheet for LPC47M192 is publicly available from
++ http://www.smsc.com/
++ The LPC47M997 is compatible for hardware monitoring.
++
++Author: Hartmut Rick <linux@rick.claranet.de>
++ Special thanks to Jean Delvare for careful checking
++ of the code and many helpful comments and suggestions.
++
++
++Description
++-----------
++
++This driver implements support for the hardware sensor capabilities
++of the SMSC LPC47M192 and LPC47M997 Super-I/O chips.
++
++These chips support 3 temperature channels and 8 voltage inputs
++as well as CPU voltage VID input.
++
++They do also have fan monitoring and control capabilities, but the
++these features are accessed via ISA bus and are not supported by this
++driver. Use the 'smsc47m1' driver for fan monitoring and control.
++
++Voltages and temperatures are measured by an 8-bit ADC, the resolution
++of the temperatures is 1 bit per degree C.
++Voltages are scaled such that the nominal voltage corresponds to
++192 counts, i.e. 3/4 of the full range. Thus the available range for
++each voltage channel is 0V ... 255/192*(nominal voltage), the resolution
++is 1 bit per (nominal voltage)/192.
++Both voltage and temperature values are scaled by 1000, the sys files
++show voltages in mV and temperatures in units of 0.001 degC.
++
++The +12V analog voltage input channel (in4_input) is multiplexed with
++bit 4 of the encoded CPU voltage. This means that you either get
++a +12V voltage measurement or a 5 bit CPU VID, but not both.
++The default setting is to use the pin as 12V input, and use only 4 bit VID.
++This driver assumes that the information in the configuration register
++is correct, i.e. that the BIOS has updated the configuration if
++the motherboard has this input wired to VID4.
++
++The temperature and voltage readings are updated once every 1.5 seconds.
++Reading them more often repeats the same values.
++
++
++sysfs interface
++---------------
++
++in0_input - +2.5V voltage input
++in1_input - CPU voltage input (nominal 2.25V)
++in2_input - +3.3V voltage input
++in3_input - +5V voltage input
++in4_input - +12V voltage input (may be missing if used as VID4)
++in5_input - Vcc voltage input (nominal 3.3V)
++ This is the supply voltage of the sensor chip itself.
++in6_input - +1.5V voltage input
++in7_input - +1.8V voltage input
++
++in[0-7]_min,
++in[0-7]_max - lower and upper alarm thresholds for in[0-7]_input reading
++
++ All voltages are read and written in mV.
++
++in[0-7]_alarm - alarm flags for voltage inputs
++ These files read '1' in case of alarm, '0' otherwise.
++
++temp1_input - chip temperature measured by on-chip diode
++temp[2-3]_input - temperature measured by external diodes (one of these would
++ typically be wired to the diode inside the CPU)
++
++temp[1-3]_min,
++temp[1-3]_max - lower and upper alarm thresholds for temperatures
++
++temp[1-3]_offset - temperature offset registers
++ The chip adds the offsets stored in these registers to
++ the corresponding temperature readings.
++ Note that temp1 and temp2 offsets share the same register,
++ they cannot both be different from zero at the same time.
++ Writing a non-zero number to one of them will reset the other
++ offset to zero.
++
++ All temperatures and offsets are read and written in
++ units of 0.001 degC.
++
++temp[1-3]_alarm - alarm flags for temperature inputs, '1' in case of alarm,
++ '0' otherwise.
++temp[2-3]_input_fault - diode fault flags for temperature inputs 2 and 3.
++ A fault is detected if the two pins for the corresponding
++ sensor are open or shorted, or any of the two is shorted
++ to ground or Vcc. '1' indicates a diode fault.
++
++cpu0_vid - CPU voltage as received from the CPU
++
++vrm - CPU VID standard used for decoding CPU voltage
++
++ The *_min, *_max, *_offset and vrm files can be read and
++ written, all others are read-only.
+--- gregkh-2.6.orig/Documentation/hwmon/sysfs-interface
++++ gregkh-2.6/Documentation/hwmon/sysfs-interface
+@@ -218,6 +218,12 @@ temp[1-2]_crit_hyst
+ from the critical value.
+ Read/Write value.
+
++temp[1-4]_offset
++ Temperature offset which is added to the temperature reading
++ by the chip.
++ Unit: millidegree Celsius
++ Read/Write value.
++
+ If there are multiple temperature sensors, temp1_* is
+ generally the sensor inside the chip itself,
+ reported as "motherboard temperature". temp2_* to
+--- gregkh-2.6.orig/drivers/hwmon/Kconfig
++++ gregkh-2.6/drivers/hwmon/Kconfig
+@@ -333,11 +333,32 @@ config SENSORS_SMSC47M1
+ help
+ If you say yes here you get support for the integrated fan
+ monitoring and control capabilities of the SMSC LPC47B27x,
+- LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 chips.
++ LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x, LPC47M192 and
++ LPC47M997 chips.
++
++ The temperature and voltage sensor features of the LPC47M192
++ and LPC47M997 are supported by another driver, select also
++ "SMSC LPC47M192 and compatibles" below for those.
+
+ This driver can also be built as a module. If so, the module
+ will be called smsc47m1.
+
++config SENSORS_SMSC47M192
++ tristate "SMSC LPC47M192 and compatibles"
++ depends on HWMON && I2C && EXPERIMENTAL
++ select HWMON_VID
++ help
++ If you say yes here you get support for the temperature and
++ voltage sensors of the SMSC LPC47M192 and LPC47M997 chips.
++
++ The fan monitoring and control capabilities of these chips
++ are supported by another driver, select
++ "SMSC LPC47M10x and compatibles" above. You need both drivers
++ if you want fan control and voltage/temperature sensor support.
++
++ This driver can also be built as a module. If so, the module
++ will be called smsc47m192.
++
+ config SENSORS_SMSC47B397
+ tristate "SMSC LPC47B397-NC"
+ depends on HWMON && I2C && EXPERIMENTAL
+--- gregkh-2.6.orig/drivers/hwmon/Makefile
++++ gregkh-2.6/drivers/hwmon/Makefile
+@@ -40,6 +40,7 @@ obj-$(CONFIG_SENSORS_PC87360) += pc87360
+ obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
+ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
+ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
++obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
+ obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
+ obj-$(CONFIG_SENSORS_VT8231) += vt8231.o
+ obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
+--- /dev/null
++++ gregkh-2.6/drivers/hwmon/smsc47m192.c
+@@ -0,0 +1,648 @@
++/*
++ smsc47m192.c - Support for hardware monitoring block of
++ SMSC LPC47M192 and LPC47M997 Super I/O chips
++
++ Copyright (C) 2006 Hartmut Rick <linux@rick.claranet.de>
++
++ Derived from lm78.c and other chip drivers.
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++*/
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/jiffies.h>
++#include <linux/i2c.h>
++#include <linux/hwmon.h>
++#include <linux/hwmon-sysfs.h>
++#include <linux/hwmon-vid.h>
++#include <linux/err.h>
++
++/* Addresses to scan */
++static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
++
++/* Insmod parameters */
++I2C_CLIENT_INSMOD_1(smsc47m192);
++
++/* SMSC47M192 registers */
++#define SMSC47M192_REG_IN(nr) ((nr)<6 ? (0x20 + (nr)) : \
++ (0x50 + (nr) - 6))
++#define SMSC47M192_REG_IN_MAX(nr) ((nr)<6 ? (0x2b + (nr) * 2) : \
++ (0x54 + (((nr) - 6) * 2)))
++#define SMSC47M192_REG_IN_MIN(nr) ((nr)<6 ? (0x2c + (nr) * 2) : \
++ (0x55 + (((nr) - 6) * 2)))
++static u8 SMSC47M192_REG_TEMP[3] = { 0x27, 0x26, 0x52 };
++static u8 SMSC47M192_REG_TEMP_MAX[3] = { 0x39, 0x37, 0x58 };
++static u8 SMSC47M192_REG_TEMP_MIN[3] = { 0x3A, 0x38, 0x59 };
++#define SMSC47M192_REG_TEMP_OFFSET(nr) ((nr)==2 ? 0x1e : 0x1f)
++#define SMSC47M192_REG_ALARM1 0x41
++#define SMSC47M192_REG_ALARM2 0x42
++#define SMSC47M192_REG_VID 0x47
++#define SMSC47M192_REG_VID4 0x49
++#define SMSC47M192_REG_CONFIG 0x40
++#define SMSC47M192_REG_SFR 0x4f
++#define SMSC47M192_REG_COMPANY_ID 0x3e
++#define SMSC47M192_REG_VERSION 0x3f
++
++/* generalised scaling with integer rounding */
++static inline int SCALE(long val, int mul, int div)
++{
++ if (val < 0)
++ return (val * mul - div / 2) / div;
++ else
++ return (val * mul + div / 2) / div;
++}
++
++/* Conversions */
++
++/* smsc47m192 internally scales voltage measurements */
++static const u16 nom_mv[] = { 2500, 2250, 3300, 5000, 12000, 3300, 1500, 1800 };
++
++static inline unsigned int IN_FROM_REG(u8 reg, int n)
++{
++ return SCALE(reg, nom_mv[n], 192);
++}
++
++static inline u8 IN_TO_REG(unsigned long val, int n)
++{
++ return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255);
++}
++
++/* TEMP: 0.001 degC units (-128C to +127C)
++ REG: 1C/bit, two's complement */
++static inline s8 TEMP_TO_REG(int val)
++{
++ return SENSORS_LIMIT(SCALE(val, 1, 1000), -128000, 127000);
++}
++
++static inline int TEMP_FROM_REG(s8 val)
++{
++ return val * 1000;
++}
++
++struct smsc47m192_data {
++ struct i2c_client client;
++ struct class_device *class_dev;
++ struct semaphore update_lock;
++ char valid; /* !=0 if following fields are valid */
++ unsigned long last_updated; /* In jiffies */
++
++ u8 in[8]; /* Register value */
++ u8 in_max[8]; /* Register value */
++ u8 in_min[8]; /* Register value */
++ s8 temp[3]; /* Register value */
++ s8 temp_max[3]; /* Register value */
++ s8 temp_min[3]; /* Register value */
++ s8 temp_offset[3]; /* Register value */
++ u16 alarms; /* Register encoding, combined */
++ u8 vid; /* Register encoding, combined */
++ u8 vrm;
++};
++
++static int smsc47m192_attach_adapter(struct i2c_adapter *adapter);
++static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
++ int kind);
++static int smsc47m192_detach_client(struct i2c_client *client);
++static struct smsc47m192_data *smsc47m192_update_device(struct device *dev);
++
++static struct i2c_driver smsc47m192_driver = {
++ .driver = {
++ .name = "smsc47m192",
++ },
++ .attach_adapter = smsc47m192_attach_adapter,
++ .detach_client = smsc47m192_detach_client,
++};
++
++/* Voltages */
++static ssize_t show_in(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct smsc47m192_data *data = smsc47m192_update_device(dev);
++ return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr));
++}
++
++static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct smsc47m192_data *data = smsc47m192_update_device(dev);
++ return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr));
++}
++
++static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct smsc47m192_data *data = smsc47m192_update_device(dev);
++ return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr));
++}
++
++static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct i2c_client *client = to_i2c_client(dev);
++ struct smsc47m192_data *data = i2c_get_clientdata(client);
++ unsigned long val = simple_strtoul(buf, NULL, 10);
++
++ down(&data->update_lock);
++ data->in_min[nr] = IN_TO_REG(val, nr);
++ i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MIN(nr),
++ data->in_min[nr]);
++ up(&data->update_lock);
++ return count;
++}
++
++static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct i2c_client *client = to_i2c_client(dev);
++ struct smsc47m192_data *data = i2c_get_clientdata(client);
++ unsigned long val = simple_strtoul(buf, NULL, 10);
++
++ down(&data->update_lock);
++ data->in_max[nr] = IN_TO_REG(val, nr);
++ i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MAX(nr),
++ data->in_max[nr]);
++ up(&data->update_lock);
++ return count;
++}
++
++#define show_in_offset(offset) \
++static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
++ show_in, NULL, offset); \
++static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
++ show_in_min, set_in_min, offset); \
++static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
++ show_in_max, set_in_max, offset);
++
++show_in_offset(0)
++show_in_offset(1)
++show_in_offset(2)
++show_in_offset(3)
++show_in_offset(4)
++show_in_offset(5)
++show_in_offset(6)
++show_in_offset(7)
++
++/* Temperatures */
++static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct smsc47m192_data *data = smsc47m192_update_device(dev);
++ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
++}
++
++static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct smsc47m192_data *data = smsc47m192_update_device(dev);
++ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr]));
++}
++
++static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct smsc47m192_data *data = smsc47m192_update_device(dev);
++ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr]));
++}
++
++static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct i2c_client *client = to_i2c_client(dev);
++ struct smsc47m192_data *data = i2c_get_clientdata(client);
++ long val = simple_strtol(buf, NULL, 10);
++
++ down(&data->update_lock);
++ data->temp_min[nr] = TEMP_TO_REG(val);
++ i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MIN[nr],
++ data->temp_min[nr]);
++ up(&data->update_lock);
++ return count;
++}
++
++static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct i2c_client *client = to_i2c_client(dev);
++ struct smsc47m192_data *data = i2c_get_clientdata(client);
++ long val = simple_strtol(buf, NULL, 10);
++
++ down(&data->update_lock);
++ data->temp_max[nr] = TEMP_TO_REG(val);
++ i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MAX[nr],
++ data->temp_max[nr]);
++ up(&data->update_lock);
++ return count;
++}
++
++static ssize_t show_temp_offset(struct device *dev, struct device_attribute
++ *attr, char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct smsc47m192_data *data = smsc47m192_update_device(dev);
++ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_offset[nr]));
++}
++
++static ssize_t set_temp_offset(struct device *dev, struct device_attribute
++ *attr, const char *buf, size_t count)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct i2c_client *client = to_i2c_client(dev);
++ struct smsc47m192_data *data = i2c_get_clientdata(client);
++ u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
++ long val = simple_strtol(buf, NULL, 10);
++
++ down(&data->update_lock);
++ data->temp_offset[nr] = TEMP_TO_REG(val);
++ if (nr>1)
++ i2c_smbus_write_byte_data(client,
++ SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]);
++ else if (data->temp_offset[nr] != 0) {
++ /* offset[0] and offset[1] share the same register,
++ SFR bit 4 activates offset[0] */
++ i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR,
++ (sfr & 0xef) | (nr==0 ? 0x10 : 0));
++ data->temp_offset[1-nr] = 0;
++ i2c_smbus_write_byte_data(client,
++ SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]);
++ } else if ((sfr & 0x10) == (nr==0 ? 0x10 : 0))
++ i2c_smbus_write_byte_data(client,
++ SMSC47M192_REG_TEMP_OFFSET(nr), 0);
++ up(&data->update_lock);
++ return count;
++}
++
++#define show_temp_index(index) \
++static SENSOR_DEVICE_ATTR(temp##index##_input, S_IRUGO, \
++ show_temp, NULL, index-1); \
++static SENSOR_DEVICE_ATTR(temp##index##_min, S_IRUGO | S_IWUSR, \
++ show_temp_min, set_temp_min, index-1); \
++static SENSOR_DEVICE_ATTR(temp##index##_max, S_IRUGO | S_IWUSR, \
++ show_temp_max, set_temp_max, index-1); \
++static SENSOR_DEVICE_ATTR(temp##index##_offset, S_IRUGO | S_IWUSR, \
++ show_temp_offset, set_temp_offset, index-1);
++
++show_temp_index(1)
++show_temp_index(2)
++show_temp_index(3)
++
++/* VID */
++static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct smsc47m192_data *data = smsc47m192_update_device(dev);
++ return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
++}
++static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
++
++static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct smsc47m192_data *data = smsc47m192_update_device(dev);
++ return sprintf(buf, "%d\n", data->vrm);
++}
++
++static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct smsc47m192_data *data = i2c_get_clientdata(client);
++ data->vrm = simple_strtoul(buf, NULL, 10);
++ return count;
++}
++static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
++
++/* Alarms */
++static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ struct smsc47m192_data *data = smsc47m192_update_device(dev);
++ return sprintf(buf, "%u\n", (data->alarms & nr) ? 1 : 0);
++}
++
++static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0x0010);
++static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 0x0020);
++static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 0x0040);
++static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 0x4000);
++static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 0x8000);
++static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0x0001);
++static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 0x0002);
++static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 0x0004);
++static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 0x0008);
++static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 0x0100);
++static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 0x0200);
++static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 0x0400);
++static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 0x0800);
++
++/* This function is called when:
++ * smsc47m192_driver is inserted (when this module is loaded), for each
++ available adapter
++ * when a new adapter is inserted (and smsc47m192_driver is still present) */
++static int smsc47m192_attach_adapter(struct i2c_adapter *adapter)
++{
++ if (!(adapter->class & I2C_CLASS_HWMON))
++ return 0;
++ return i2c_probe(adapter, &addr_data, smsc47m192_detect);
++}
++
++static void smsc47m192_init_client(struct i2c_client *client)
++{
++ int i;
++ u8 config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
++ u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
++
++ /* select cycle mode (pause 1 sec between updates) */
++ i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR,
++ (sfr & 0xfd) | 0x02);
++ if (!(config & 0x01)) {
++ /* initialize alarm limits */
++ for (i=0; i<8; i++) {
++ i2c_smbus_write_byte_data(client,
++ SMSC47M192_REG_IN_MIN(i), 0);
++ i2c_smbus_write_byte_data(client,
++ SMSC47M192_REG_IN_MAX(i), 0xff);
++ }
++ for (i=0; i<3; i++) {
++ i2c_smbus_write_byte_data(client,
++ SMSC47M192_REG_TEMP_MIN[i], 0x80);
++ i2c_smbus_write_byte_data(client,
++ SMSC47M192_REG_TEMP_MAX[i], 0x7f);
++ }
++
++ /* start monitoring */
++ i2c_smbus_write_byte_data(client, SMSC47M192_REG_CONFIG,
++ (config & 0xf7) | 0x01);
++ }
++}
++
++/* This function is called by i2c_probe */
++static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
++ int kind)
++{
++ struct i2c_client *client;
++ struct smsc47m192_data *data;
++ int err = 0;
++ int version, config;
++
++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
++ goto exit;
++
++ if (!(data = kzalloc(sizeof(struct smsc47m192_data), GFP_KERNEL))) {
++ err = -ENOMEM;
++ goto exit;
++ }
++
++ client = &data->client;
++ i2c_set_clientdata(client, data);
++ client->addr = address;
++ client->adapter = adapter;
++ client->driver = &smsc47m192_driver;
++
++ if (kind == 0)
++ kind = smsc47m192;
++
++ /* Detection criteria from sensors_detect script */
++ if (kind < 0) {
++ if (i2c_smbus_read_byte_data(client,
++ SMSC47M192_REG_COMPANY_ID) == 0x55
++ && ((version = i2c_smbus_read_byte_data(client,
++ SMSC47M192_REG_VERSION)) & 0xf0) == 0x20
++ && (i2c_smbus_read_byte_data(client,
++ SMSC47M192_REG_VID) & 0x70) == 0x00
++ && (i2c_smbus_read_byte_data(client,
++ SMSC47M192_REG_VID4) & 0xfe) == 0x80) {
++ dev_info(&adapter->dev,
++ "found SMSC47M192 or SMSC47M997, "
++ "version 2, stepping A%d\n", version & 0x0f);
++ } else {
++ dev_dbg(&adapter->dev,
++ "SMSC47M192 detection failed at 0x%02x\n",
++ address);
++ goto exit_free;
++ }
++ }
++
++ /* Fill in the remaining client fields and put into the global list */
++ strlcpy(client->name, "smsc47m192", I2C_NAME_SIZE);
++ data->vrm = vid_which_vrm();
++ init_MUTEX(&data->update_lock);
++
++ /* Tell the I2C layer a new client has arrived */
++ if ((err = i2c_attach_client(client)))
++ goto exit_free;
++
++ /* Initialize the SMSC47M192 chip */
++ smsc47m192_init_client(client);
++
++ /* Register sysfs hooks */
++ data->class_dev = hwmon_device_register(&client->dev);
++ if (IS_ERR(data->class_dev)) {
++ err = PTR_ERR(data->class_dev);
++ goto exit_detach;
++ }
++
++ device_create_file(&client->dev, &sensor_dev_attr_in0_input.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in0_min.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in0_max.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in0_alarm.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in1_input.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in1_min.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in1_max.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in1_alarm.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in2_input.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in2_min.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in2_max.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in2_alarm.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in3_input.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in3_min.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in3_max.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in3_alarm.dev_attr);
++
++ /* Pin 110 is either in4 (+12V) or VID4 */
++ config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
++ if (!(config & 0x20)) {
++ device_create_file(&client->dev,
++ &sensor_dev_attr_in4_input.dev_attr);
++ device_create_file(&client->dev,
++ &sensor_dev_attr_in4_min.dev_attr);
++ device_create_file(&client->dev,
++ &sensor_dev_attr_in4_max.dev_attr);
++ device_create_file(&client->dev,
++ &sensor_dev_attr_in4_alarm.dev_attr);
++ }
++ device_create_file(&client->dev, &sensor_dev_attr_in5_input.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in5_min.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in5_max.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in5_alarm.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in6_input.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in6_min.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in6_max.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in6_alarm.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in7_input.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in7_min.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in7_max.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_in7_alarm.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_temp1_min.dev_attr);
++ device_create_file(&client->dev,
++ &sensor_dev_attr_temp1_offset.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_temp1_alarm.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_temp2_input.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_temp2_max.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_temp2_min.dev_attr);
++ device_create_file(&client->dev,
++ &sensor_dev_attr_temp2_offset.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_temp2_alarm.dev_attr);
++ device_create_file(&client->dev,
++ &sensor_dev_attr_temp2_input_fault.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_temp3_input.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_temp3_max.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_temp3_min.dev_attr);
++ device_create_file(&client->dev,
++ &sensor_dev_attr_temp3_offset.dev_attr);
++ device_create_file(&client->dev, &sensor_dev_attr_temp3_alarm.dev_attr);
++ device_create_file(&client->dev,
++ &sensor_dev_attr_temp3_input_fault.dev_attr);
++ device_create_file(&client->dev, &dev_attr_cpu0_vid);
++ device_create_file(&client->dev, &dev_attr_vrm);
++
++ return 0;
++
++exit_detach:
++ i2c_detach_client(client);
++exit_free:
++ kfree(data);
++exit:
++ return err;
++}
++
++static int smsc47m192_detach_client(struct i2c_client *client)
++{
++ struct smsc47m192_data *data = i2c_get_clientdata(client);
++ int err;
++
++ hwmon_device_unregister(data->class_dev);
++
++ if ((err = i2c_detach_client(client)))
++ return err;
++
++ kfree(data);
++
++ return 0;
++}
++
++static struct smsc47m192_data *smsc47m192_update_device(struct device *dev)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct smsc47m192_data *data = i2c_get_clientdata(client);
++ int i, config;
++
++ down(&data->update_lock);
++
++ if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
++ || !data->valid) {
++ u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
++
++ dev_dbg(&client->dev, "Starting smsc47m192 update\n");
++
++ for (i = 0; i <= 7; i++) {
++ data->in[i] = i2c_smbus_read_byte_data(client,
++ SMSC47M192_REG_IN(i));
++ data->in_min[i] = i2c_smbus_read_byte_data(client,
++ SMSC47M192_REG_IN_MIN(i));
++ data->in_max[i] = i2c_smbus_read_byte_data(client,
++ SMSC47M192_REG_IN_MAX(i));
++ }
++ for (i = 0; i < 3; i++) {
++ data->temp[i] = i2c_smbus_read_byte_data(client,
++ SMSC47M192_REG_TEMP[i]);
++ data->temp_max[i] = i2c_smbus_read_byte_data(client,
++ SMSC47M192_REG_TEMP_MAX[i]);
++ data->temp_min[i] = i2c_smbus_read_byte_data(client,
++ SMSC47M192_REG_TEMP_MIN[i]);
++ }
++ for (i = 1; i < 3; i++)
++ data->temp_offset[i] = i2c_smbus_read_byte_data(client,
++ SMSC47M192_REG_TEMP_OFFSET(i));
++ /* first offset is temp_offset[0] if SFR bit 4 is set,
++ temp_offset[1] otherwise */
++ if (sfr & 0x10) {
++ data->temp_offset[0] = data->temp_offset[1];
++ data->temp_offset[1] = 0;
++ } else
++ data->temp_offset[0] = 0;
++
++ data->vid = i2c_smbus_read_byte_data(client, SMSC47M192_REG_VID)
++ & 0x0f;
++ config = i2c_smbus_read_byte_data(client,
++ SMSC47M192_REG_CONFIG);
++ if (config & 0x20)
++ data->vid |= (i2c_smbus_read_byte_data(client,
++ SMSC47M192_REG_VID4) & 0x01) << 4;
++ data->alarms = i2c_smbus_read_byte_data(client,
++ SMSC47M192_REG_ALARM1) |
++ (i2c_smbus_read_byte_data(client,
++ SMSC47M192_REG_ALARM2) << 8);
++
++ data->last_updated = jiffies;
++ data->valid = 1;
++ }
++
++ up(&data->update_lock);
++
++ return data;
++}
++
++static int __init smsc47m192_init(void)
++{
++ return i2c_add_driver(&smsc47m192_driver);
++}
++
++static void __exit smsc47m192_exit(void)
++{
++ i2c_del_driver(&smsc47m192_driver);
++}
++
++MODULE_AUTHOR("Hartmut Rick <linux@rick.claranet.de>");
++MODULE_DESCRIPTION("SMSC47M192 driver");
++MODULE_LICENSE("GPL");
++
++module_init(smsc47m192_init);
++module_exit(smsc47m192_exit);
diff --git a/i2c/hwmon-sysfs-interface-individual-alarm-files.patch b/i2c/hwmon-sysfs-interface-individual-alarm-files.patch
new file mode 100644
index 0000000000000..c54aabc2aa1f4
--- /dev/null
+++ b/i2c/hwmon-sysfs-interface-individual-alarm-files.patch
@@ -0,0 +1,145 @@
+From khali@linux-fr.org Thu Mar 23 07:46:13 2006
+Date: Thu, 23 Mar 2006 16:46:47 +0100
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Subject: [PATCH 07/10] hwmon: Add sysfs interface for individual alarm files
+Message-Id: <20060323164647.0e89adcb.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-sysfs-interface-individual-alarm-files.patch
+
+Extend the sysfs interface of hardware monitoring chips, by adding
+individual alarm and beep files. Contrary to the old aggregated "alarms"
+and "beeps" files, individual files constitute a standard way to access
+the status information, making it finally possible to implement a
+chip-independant hardware monitoring chip access library (once all
+drivers have been added this new interface, that is.)
+
+If future drivers need more individual files, the interface will be
+extended as needed at the same time these drivers are merged into the
+kernel tree.
+
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/hwmon/sysfs-interface | 98 ++++++++++++++++++++++++++----------
+ 1 file changed, 73 insertions(+), 25 deletions(-)
+
+--- gregkh-2.6.orig/Documentation/hwmon/sysfs-interface
++++ gregkh-2.6/Documentation/hwmon/sysfs-interface
+@@ -252,9 +252,68 @@ curr[1-n]_input Current input value
+ Read only.
+
+
+-*********
+-* Other *
+-*********
++**********
++* Alarms *
++**********
++
++Each channel or limit may have an associated alarm file, containing a
++boolean value. 1 means than an alarm condition exists, 0 means no alarm.
++
++Usually a given chip will either use channel-related alarms, or
++limit-related alarms, not both. The driver should just reflect the hardware
++implementation.
++
++in[0-n]_alarm
++fan[1-n]_alarm
++temp[1-n]_alarm
++ Channel alarm
++ Boolean
++ Read-only
++
++OR
++
++in[0-n]_min_alarm
++in[0-n]_max_alarm
++fan[1-n]_min_alarm
++temp[1-n]_min_alarm
++temp[1-n]_max_alarm
++temp[1-n]_crit_alarm
++ Limit alarm
++ Boolean
++ Read-only
++
++Each input channel may have an associated fault file. This can be used
++to notify open diodes, unconnected fans etc. where the hardware
++supports it. When this boolean has value 1, the measurement for that
++channel should not be trusted.
++
++in[0-n]_input_fault
++fan[1-n]_input_fault
++temp[1-n]_input_fault
++ Input fault condition
++ Boolean
++ Read-only
++
++Some chips also offer the possibility to get beeped when an alarm occurs:
++
++beep_enable Master beep enable
++ Boolean
++ Read/Write
++
++in[0-n]_beep
++fan[1-n]_beep
++temp[1-n]_beep
++ Channel beep
++ 0 to disable.
++ 1 to enable.
++ Read/write
++
++In theory, a chip could provide per-limit beep masking, but no such chip
++was seen so far.
++
++Old drivers provided a different, non-standard interface to alarms and
++beeps. These interface files are deprecated, but will be kept around
++for compatibility reasons:
+
+ alarms Alarm bitmask.
+ Read only.
+@@ -265,33 +324,22 @@ alarms Alarm bitmask.
+ if it is still valid.
+ Generally a direct representation of a chip's internal
+ alarm registers; there is no standard for the position
+- of individual bits.
++ of individual bits. For this reason, the use of this
++ interface file for new drivers is discouraged. Use
++ individual *_alarm and *_fault files instead.
+ Bits are defined in kernel/include/sensors.h.
+
+-alarms_in Alarm bitmask relative to in (voltage) channels
+- Read only
+- A '1' bit means an alarm, LSB corresponds to in0 and so on
+- Prefered to 'alarms' for newer chips
+-
+-alarms_fan Alarm bitmask relative to fan channels
+- Read only
+- A '1' bit means an alarm, LSB corresponds to fan1 and so on
+- Prefered to 'alarms' for newer chips
+-
+-alarms_temp Alarm bitmask relative to temp (temperature) channels
+- Read only
+- A '1' bit means an alarm, LSB corresponds to temp1 and so on
+- Prefered to 'alarms' for newer chips
+-
+-beep_enable Beep/interrupt enable
+- 0 to disable.
+- 1 to enable.
+- Read/Write
+-
+ beep_mask Bitmask for beep.
+- Same format as 'alarms' with the same bit locations.
++ Same format as 'alarms' with the same bit locations,
++ use discouraged for the same reason. Use individual
++ *_beep files instead.
+ Read/Write
+
++
++*********
++* Other *
++*********
++
+ eeprom Raw EEPROM data in binary form.
+ Read only.
+
diff --git a/i2c/hwmon-w83627ehf-add-alarms.patch b/i2c/hwmon-w83627ehf-add-alarms.patch
new file mode 100644
index 0000000000000..fc3def3473e02
--- /dev/null
+++ b/i2c/hwmon-w83627ehf-add-alarms.patch
@@ -0,0 +1,132 @@
+From khali@linux-fr.org Thu Mar 23 07:29:53 2006
+Date: Thu, 23 Mar 2006 16:30:29 +0100
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: Yuan Mu <Ymu@winbond.com.tw>, Rudolf Marek <r.marek@sh.cvut.cz>
+Subject: [PATCH 03/10] w83627ehf: Add alarms support
+Message-Id: <20060323163029.5d56d96d.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-w83627ehf-add-alarms.patch
+
+Add alarms support for the W83627EHF/EHG hardware monitoring chip.
+
+This is based on an earlier patch from Rudolf Marek.
+
+Signed-off-by: Rudolf Marek <r.marek@sh.cvut.cz>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/hwmon/w83627ehf.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 46 insertions(+)
+
+--- gregkh-2.6.orig/drivers/hwmon/w83627ehf.c
++++ gregkh-2.6/drivers/hwmon/w83627ehf.c
+@@ -141,6 +141,10 @@ static const u16 W83627EHF_REG_TEMP_CONF
+ #define W83627EHF_REG_DIODE 0x59
+ #define W83627EHF_REG_SMI_OVT 0x4C
+
++#define W83627EHF_REG_ALARM1 0x459
++#define W83627EHF_REG_ALARM2 0x45A
++#define W83627EHF_REG_ALARM3 0x45B
++
+ /*
+ * Conversions
+ */
+@@ -218,6 +222,7 @@ struct w83627ehf_data {
+ s16 temp[2];
+ s16 temp_max[2];
+ s16 temp_max_hyst[2];
++ u32 alarms;
+ };
+
+ static inline int is_word_sized(u16 reg)
+@@ -427,6 +432,13 @@ static struct w83627ehf_data *w83627ehf_
+ W83627EHF_REG_TEMP_HYST[i]);
+ }
+
++ data->alarms = w83627ehf_read_value(client,
++ W83627EHF_REG_ALARM1) |
++ (w83627ehf_read_value(client,
++ W83627EHF_REG_ALARM2) << 8) |
++ (w83627ehf_read_value(client,
++ W83627EHF_REG_ALARM3) << 16);
++
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+@@ -474,6 +486,14 @@ store_in_##reg (struct device *dev, stru
+ store_in_reg(MIN, min)
+ store_in_reg(MAX, max)
+
++static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct w83627ehf_data *data = w83627ehf_update_device(dev);
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int nr = sensor_attr->index;
++ return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
++}
++
+ static struct sensor_device_attribute sda_in_input[] = {
+ SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
+ SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+@@ -487,6 +507,19 @@ static struct sensor_device_attribute sd
+ SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
+ };
+
++static struct sensor_device_attribute sda_in_alarm[] = {
++ SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
++ SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
++ SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
++ SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
++ SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
++ SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
++ SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
++ SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
++ SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
++ SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
++};
++
+ static struct sensor_device_attribute sda_in_min[] = {
+ SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
+ SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
+@@ -516,6 +549,7 @@ static struct sensor_device_attribute sd
+ static void device_create_file_in(struct device *dev, int i)
+ {
+ device_create_file(dev, &sda_in_input[i].dev_attr);
++ device_create_file(dev, &sda_in_alarm[i].dev_attr);
+ device_create_file(dev, &sda_in_min[i].dev_attr);
+ device_create_file(dev, &sda_in_max[i].dev_attr);
+ }
+@@ -618,6 +652,14 @@ static struct sensor_device_attribute sd
+ SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
+ };
+
++static struct sensor_device_attribute sda_fan_alarm[] = {
++ SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
++ SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
++ SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
++ SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
++ SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
++};
++
+ static struct sensor_device_attribute sda_fan_min[] = {
+ SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
+ store_fan_min, 0),
+@@ -642,6 +684,7 @@ static struct sensor_device_attribute sd
+ static void device_create_file_fan(struct device *dev, int i)
+ {
+ device_create_file(dev, &sda_fan_input[i].dev_attr);
++ device_create_file(dev, &sda_fan_alarm[i].dev_attr);
+ device_create_file(dev, &sda_fan_div[i].dev_attr);
+ device_create_file(dev, &sda_fan_min[i].dev_attr);
+ }
+@@ -729,6 +772,9 @@ static struct sensor_device_attribute sd
+ store_temp_max_hyst, 0),
+ SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 1),
++ SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
++ SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
++ SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
+ };
+
+ /*
diff --git a/i2c/hwmon-w83627ehf-add-voltages.patch b/i2c/hwmon-w83627ehf-add-voltages.patch
new file mode 100644
index 0000000000000..adce43ee714fb
--- /dev/null
+++ b/i2c/hwmon-w83627ehf-add-voltages.patch
@@ -0,0 +1,198 @@
+From khali@linux-fr.org Thu Mar 23 07:24:51 2006
+Date: Thu, 23 Mar 2006 16:25:22 +0100
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: Yuan Mu <Ymu@winbond.com.tw>, Rudolf Marek <r.marek@sh.cvut.cz>
+Subject: [PATCH 02/10] w83627ehf: Add voltage inputs support
+Message-Id: <20060323162522.f46f7072.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-w83627ehf-add-voltages.patch
+
+From: Rudolf Marek <r.marek@sh.cvut.cz>
+
+Add the voltage measuring support to W83627EHF. The code is based
+on the patch provided by Yuan Mu from Winbond.
+
+Signed-off-by: Yuan Mu <Ymu@winbond.com.tw>
+Signed-off-by: Rudolf Marek <r.marek@sh.cvut.cz>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/hwmon/w83627ehf.c | 124 ++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 120 insertions(+), 4 deletions(-)
+
+--- gregkh-2.6.orig/drivers/hwmon/w83627ehf.c
++++ gregkh-2.6/drivers/hwmon/w83627ehf.c
+@@ -30,10 +30,7 @@
+ Supports the following chips:
+
+ Chip #vin #fan #pwm #temp chip_id man_id
+- w83627ehf - 5 - 3 0x88 0x5ca3
+-
+- This is a preliminary version of the driver, only supporting the
+- fan and temperature inputs. The chip does much more than that.
++ w83627ehf 10 5 - 3 0x88 0x5ca3
+ */
+
+ #include <linux/module.h>
+@@ -121,6 +118,14 @@ superio_exit(void)
+ static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
+ static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
+
++/* The W83627EHF registers for nr=7,8,9 are in bank 5 */
++#define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
++ (0x554 + (((nr) - 7) * 2)))
++#define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
++ (0x555 + (((nr) - 7) * 2)))
++#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
++ (0x550 + (nr) - 7))
++
+ #define W83627EHF_REG_TEMP1 0x27
+ #define W83627EHF_REG_TEMP1_HYST 0x3a
+ #define W83627EHF_REG_TEMP1_OVER 0x39
+@@ -172,6 +177,20 @@ temp1_to_reg(int temp)
+ return (temp + 500) / 1000;
+ }
+
++/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
++
++static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
++
++static inline long in_from_reg(u8 reg, u8 nr)
++{
++ return reg * scale_in[nr];
++}
++
++static inline u8 in_to_reg(u32 val, u8 nr)
++{
++ return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255);
++}
++
+ /*
+ * Data structures and manipulation thereof
+ */
+@@ -186,6 +205,9 @@ struct w83627ehf_data {
+ unsigned long last_updated; /* In jiffies */
+
+ /* Register values */
++ u8 in[10]; /* Register value */
++ u8 in_max[10]; /* Register value */
++ u8 in_min[10]; /* Register value */
+ u8 fan[5];
+ u8 fan_min[5];
+ u8 fan_div[5];
+@@ -349,6 +371,16 @@ static struct w83627ehf_data *w83627ehf_
+ data->fan_div[3] |= (i >> 5) & 0x04;
+ }
+
++ /* Measured voltages and limits */
++ for (i = 0; i < 10; i++) {
++ data->in[i] = w83627ehf_read_value(client,
++ W83627EHF_REG_IN(i));
++ data->in_min[i] = w83627ehf_read_value(client,
++ W83627EHF_REG_IN_MIN(i));
++ data->in_max[i] = w83627ehf_read_value(client,
++ W83627EHF_REG_IN_MAX(i));
++ }
++
+ /* Measured fan speeds and limits */
+ for (i = 0; i < 5; i++) {
+ if (!(data->has_fan & (1 << i)))
+@@ -406,6 +438,87 @@ static struct w83627ehf_data *w83627ehf_
+ /*
+ * Sysfs callback functions
+ */
++#define show_in_reg(reg) \
++static ssize_t \
++show_##reg(struct device *dev, struct device_attribute *attr, \
++ char *buf) \
++{ \
++ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
++ int nr = sensor_attr->index; \
++ return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
++}
++show_in_reg(in)
++show_in_reg(in_min)
++show_in_reg(in_max)
++
++#define store_in_reg(REG, reg) \
++static ssize_t \
++store_in_##reg (struct device *dev, struct device_attribute *attr, \
++ const char *buf, size_t count) \
++{ \
++ struct i2c_client *client = to_i2c_client(dev); \
++ struct w83627ehf_data *data = i2c_get_clientdata(client); \
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
++ int nr = sensor_attr->index; \
++ u32 val = simple_strtoul(buf, NULL, 10); \
++ \
++ mutex_lock(&data->update_lock); \
++ data->in_##reg[nr] = in_to_reg(val, nr); \
++ w83627ehf_write_value(client, W83627EHF_REG_IN_##REG(nr), \
++ data->in_##reg[nr]); \
++ mutex_unlock(&data->update_lock); \
++ return count; \
++}
++
++store_in_reg(MIN, min)
++store_in_reg(MAX, max)
++
++static struct sensor_device_attribute sda_in_input[] = {
++ SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
++ SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
++ SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
++ SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
++ SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
++ SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
++ SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
++ SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
++ SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
++ SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
++};
++
++static struct sensor_device_attribute sda_in_min[] = {
++ SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
++ SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
++ SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
++ SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
++ SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
++ SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
++ SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
++ SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
++ SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
++ SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
++};
++
++static struct sensor_device_attribute sda_in_max[] = {
++ SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
++ SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
++ SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
++ SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
++ SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
++ SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
++ SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
++ SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
++ SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
++ SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
++};
++
++static void device_create_file_in(struct device *dev, int i)
++{
++ device_create_file(dev, &sda_in_input[i].dev_attr);
++ device_create_file(dev, &sda_in_min[i].dev_attr);
++ device_create_file(dev, &sda_in_max[i].dev_attr);
++}
+
+ #define show_fan_reg(reg) \
+ static ssize_t \
+@@ -705,6 +818,9 @@ static int w83627ehf_detect(struct i2c_a
+ goto exit_detach;
+ }
+
++ for (i = 0; i < 10; i++)
++ device_create_file_in(dev, i);
++
+ for (i = 0; i < 5; i++) {
+ if (data->has_fan & (1 << i))
+ device_create_file_fan(dev, i);
diff --git a/i2c/hwmon-w83792d-quiet-on-misdetection.patch b/i2c/hwmon-w83792d-quiet-on-misdetection.patch
new file mode 100644
index 0000000000000..2fd1a9551ad72
--- /dev/null
+++ b/i2c/hwmon-w83792d-quiet-on-misdetection.patch
@@ -0,0 +1,48 @@
+From khali@linux-fr.org Thu Mar 23 07:37:51 2006
+Date: Thu, 23 Mar 2006 16:38:21 +0100
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Subject: [PATCH 05/10] w83792d: Be quiet on misdetection
+Message-Id: <20060323163821.074148b4.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-w83792d-quiet-on-misdetection.patch
+
+Make the w83792d driver keep quiet when misdetecting a chip. This can
+happen, and the user doesn't need to know.
+
+Also renumber the messages, and add one, for consistency.
+
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/hwmon/w83792d.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/hwmon/w83792d.c
++++ gregkh-2.6/drivers/hwmon/w83792d.c
+@@ -1161,7 +1161,7 @@ w83792d_detect(struct i2c_adapter *adapt
+ bank. */
+ if (kind < 0) {
+ if (w83792d_read_value(client, W83792D_REG_CONFIG) & 0x80) {
+- dev_warn(dev, "Detection failed at step 3\n");
++ dev_dbg(dev, "Detection failed at step 1\n");
+ goto ERROR1;
+ }
+ val1 = w83792d_read_value(client, W83792D_REG_BANK);
+@@ -1170,6 +1170,7 @@ w83792d_detect(struct i2c_adapter *adapt
+ if (!(val1 & 0x07)) { /* is Bank0 */
+ if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
+ ((val1 & 0x80) && (val2 != 0x5c))) {
++ dev_dbg(dev, "Detection failed at step 2\n");
+ goto ERROR1;
+ }
+ }
+@@ -1177,7 +1178,7 @@ w83792d_detect(struct i2c_adapter *adapt
+ should match */
+ if (w83792d_read_value(client,
+ W83792D_REG_I2C_ADDR) != address) {
+- dev_warn(dev, "Detection failed at step 5\n");
++ dev_dbg(dev, "Detection failed at step 3\n");
+ goto ERROR1;
+ }
+ }
diff --git a/i2c/i2c-parport-require-type-parameter.patch b/i2c/i2c-parport-require-type-parameter.patch
new file mode 100644
index 0000000000000..374ae32d23981
--- /dev/null
+++ b/i2c/i2c-parport-require-type-parameter.patch
@@ -0,0 +1,127 @@
+From khali@linux-fr.org Thu Mar 23 07:49:59 2006
+Date: Thu, 23 Mar 2006 16:50:25 +0100
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: "Mark M. Hoffman" <mhoffman@lightlink.com>
+Subject: [PATCH 10/10] i2c-parport: Make type parameter mandatory
+Message-Id: <20060323165025.ddb0f7c7.khali@linux-fr.org>
+Content-Disposition: inline; filename=i2c-parport-require-type-parameter.patch
+
+From: "Mark M. Hoffman" <mhoffman@lightlink.com>
+
+This patch forces the user to specify what type of adapter is present when
+loading i2c-parport or i2c-parport-light. If none is specified, the driver
+init simply fails - instead of assuming adapter type 0.
+
+This alleviates the sometimes lengthy boot time delays which can be caused
+by accidentally building one of these into a kernel along with several i2c
+slave drivers that have lengthy probe routines (e.g. hwmon drivers).
+
+Kconfig and documentation updated accordingly.
+
+Signed-off-by: Mark M. Hoffman <mhoffman@lightlink.com>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/i2c/busses/i2c-parport | 16 ++++++++++------
+ drivers/i2c/busses/Kconfig | 5 ++++-
+ drivers/i2c/busses/i2c-parport-light.c | 9 +++++++--
+ drivers/i2c/busses/i2c-parport.c | 9 +++++++--
+ drivers/i2c/busses/i2c-parport.h | 2 +-
+ 5 files changed, 29 insertions(+), 12 deletions(-)
+
+--- gregkh-2.6.orig/Documentation/i2c/busses/i2c-parport
++++ gregkh-2.6/Documentation/i2c/busses/i2c-parport
+@@ -12,18 +12,22 @@ meant as a replacement for the older, in
+ teletext adapters)
+
+ It currently supports the following devices:
+- * Philips adapter
+- * home brew teletext adapter
+- * Velleman K8000 adapter
+- * ELV adapter
+- * Analog Devices evaluation boards (ADM1025, ADM1030, ADM1031, ADM1032)
+- * Barco LPT->DVI (K5800236) adapter
++ * (type=0) Philips adapter
++ * (type=1) home brew teletext adapter
++ * (type=2) Velleman K8000 adapter
++ * (type=3) ELV adapter
++ * (type=4) Analog Devices ADM1032 evaluation board
++ * (type=5) Analog Devices evaluation boards: ADM1025, ADM1030, ADM1031
++ * (type=6) Barco LPT->DVI (K5800236) adapter
+
+ These devices use different pinout configurations, so you have to tell
+ the driver what you have, using the type module parameter. There is no
+ way to autodetect the devices. Support for different pinout configurations
+ can be easily added when needed.
+
++Earlier kernels defaulted to type=0 (Philips). But now, if the type
++parameter is missing, the driver will simply fail to initialize.
++
+
+ Building your own adapter
+ -------------------------
+--- gregkh-2.6.orig/drivers/i2c/busses/Kconfig
++++ gregkh-2.6/drivers/i2c/busses/Kconfig
+@@ -286,7 +286,10 @@ config I2C_PARPORT
+ This driver is a replacement for (and was inspired by) an older
+ driver named i2c-philips-par. The new driver supports more devices,
+ and makes it easier to add support for new devices.
+-
++
++ An adapter type parameter is now mandatory. Please read the file
++ Documentation/i2c/busses/i2c-parport for details.
++
+ Another driver exists, named i2c-parport-light, which doesn't depend
+ on the parport driver. This is meant for embedded systems. Don't say
+ Y here if you intend to say Y or M there.
+--- gregkh-2.6.orig/drivers/i2c/busses/i2c-parport-light.c
++++ gregkh-2.6/drivers/i2c/busses/i2c-parport-light.c
+@@ -121,9 +121,14 @@ static struct i2c_adapter parport_adapte
+
+ static int __init i2c_parport_init(void)
+ {
+- if (type < 0 || type >= ARRAY_SIZE(adapter_parm)) {
++ if (type < 0) {
++ printk(KERN_WARNING "i2c-parport: adapter type unspecified\n");
++ return -ENODEV;
++ }
++
++ if (type >= ARRAY_SIZE(adapter_parm)) {
+ printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type);
+- type = 0;
++ return -ENODEV;
+ }
+
+ if (base == 0) {
+--- gregkh-2.6.orig/drivers/i2c/busses/i2c-parport.c
++++ gregkh-2.6/drivers/i2c/busses/i2c-parport.c
+@@ -241,9 +241,14 @@ static struct parport_driver i2c_parport
+
+ static int __init i2c_parport_init(void)
+ {
+- if (type < 0 || type >= ARRAY_SIZE(adapter_parm)) {
++ if (type < 0) {
++ printk(KERN_WARNING "i2c-parport: adapter type unspecified\n");
++ return -ENODEV;
++ }
++
++ if (type >= ARRAY_SIZE(adapter_parm)) {
+ printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type);
+- type = 0;
++ return -ENODEV;
+ }
+
+ return parport_register_driver(&i2c_parport_driver);
+--- gregkh-2.6.orig/drivers/i2c/busses/i2c-parport.h
++++ gregkh-2.6/drivers/i2c/busses/i2c-parport.h
+@@ -90,7 +90,7 @@ static struct adapter_parm adapter_parm[
+ },
+ };
+
+-static int type;
++static int type = -1;
+ module_param(type, int, 0);
+ MODULE_PARM_DESC(type,
+ "Type of adapter:\n"
diff --git a/i2c/i2c-piix4-add-ati-smbus-support.patch b/i2c/i2c-piix4-add-ati-smbus-support.patch
new file mode 100644
index 0000000000000..2014fcebf494d
--- /dev/null
+++ b/i2c/i2c-piix4-add-ati-smbus-support.patch
@@ -0,0 +1,86 @@
+From khali@linux-fr.org Thu Mar 23 07:47:43 2006
+Date: Thu, 23 Mar 2006 16:48:09 +0100
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: Rudolf Marek <r.marek@sh.cvut.cz>
+Subject: [PATCH 08/10] i2c-piix4: Add ATI IXP200/300/400 support
+Message-Id: <20060323164809.cdcef765.khali@linux-fr.org>
+Content-Disposition: inline; filename=i2c-piix4-add-ati-smbus-support.patch
+
+From: Rudolf Marek <r.marek@sh.cvut.cz>
+
+This patch adds the ATI IXP southbridges support to i2c-piix4,
+as it turned out those chips are compatible with it.
+
+Signed-off-by: Rudolf Marek <r.marek@sh.cvut.cz>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/i2c/busses/i2c-piix4 | 2 ++
+ drivers/i2c/busses/Kconfig | 5 ++++-
+ drivers/i2c/busses/i2c-piix4.c | 6 ++++++
+ include/linux/pci_ids.h | 3 +++
+ 4 files changed, 15 insertions(+), 1 deletion(-)
+
+--- gregkh-2.6.orig/Documentation/i2c/busses/i2c-piix4
++++ gregkh-2.6/Documentation/i2c/busses/i2c-piix4
+@@ -6,6 +6,8 @@ Supported adapters:
+ Datasheet: Publicly available at the Intel website
+ * ServerWorks OSB4, CSB5, CSB6 and HT-1000 southbridges
+ Datasheet: Only available via NDA from ServerWorks
++ * ATI IXP southbridges IXP200, IXP300, IXP400
++ Datasheet: Not publicly available
+ * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
+ Datasheet: Publicly available at the SMSC website http://www.smsc.com
+
+--- gregkh-2.6.orig/drivers/i2c/busses/Kconfig
++++ gregkh-2.6/drivers/i2c/busses/Kconfig
+@@ -163,7 +163,7 @@ config I2C_PXA_SLAVE
+ I2C bus.
+
+ config I2C_PIIX4
+- tristate "Intel PIIX4"
++ tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)"
+ depends on I2C && PCI
+ help
+ If you say yes to this option, support will be included for the Intel
+@@ -172,6 +172,9 @@ config I2C_PIIX4
+ of Broadcom):
+ Intel PIIX4
+ Intel 440MX
++ ATI IXP200
++ ATI IXP300
++ ATI IXP400
+ Serverworks OSB4
+ Serverworks CSB5
+ Serverworks CSB6
+--- gregkh-2.6.orig/drivers/i2c/busses/i2c-piix4.c
++++ gregkh-2.6/drivers/i2c/busses/i2c-piix4.c
+@@ -413,6 +413,12 @@ static struct i2c_adapter piix4_adapter
+ static struct pci_device_id piix4_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3),
+ .driver_data = 3 },
++ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS),
++ .driver_data = 0 },
++ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS),
++ .driver_data = 0 },
++ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS),
++ .driver_data = 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4),
+ .driver_data = 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5),
+--- gregkh-2.6.orig/include/linux/pci_ids.h
++++ gregkh-2.6/include/linux/pci_ids.h
+@@ -352,8 +352,11 @@
+ #define PCI_DEVICE_ID_ATI_RS480 0x5950
+ /* ATI IXP Chipset */
+ #define PCI_DEVICE_ID_ATI_IXP200_IDE 0x4349
++#define PCI_DEVICE_ID_ATI_IXP200_SMBUS 0x4353
++#define PCI_DEVICE_ID_ATI_IXP300_SMBUS 0x4363
+ #define PCI_DEVICE_ID_ATI_IXP300_IDE 0x4369
+ #define PCI_DEVICE_ID_ATI_IXP300_SATA 0x436e
++#define PCI_DEVICE_ID_ATI_IXP400_SMBUS 0x4372
+ #define PCI_DEVICE_ID_ATI_IXP400_IDE 0x4376
+ #define PCI_DEVICE_ID_ATI_IXP400_SATA 0x4379
+
diff --git a/i2c/i2c-sis96x-remove-init-log-message.patch b/i2c/i2c-sis96x-remove-init-log-message.patch
new file mode 100644
index 0000000000000..bab2d8e937871
--- /dev/null
+++ b/i2c/i2c-sis96x-remove-init-log-message.patch
@@ -0,0 +1,46 @@
+From khali@linux-fr.org Thu Mar 23 07:49:02 2006
+Date: Thu, 23 Mar 2006 16:49:34 +0100
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: "Mark M. Hoffman" <mhoffman@lightlink.com>
+Subject: [PATCH 09/10] i2c-sis96x: Remove an init-time log message
+Message-Id: <20060323164934.5bc2122f.khali@linux-fr.org>
+Content-Disposition: inline; filename=i2c-sis96x-remove-init-log-message.patch
+
+From: "Mark M. Hoffman" <mhoffman@lightlink.com>
+
+This patch removes an init-time kernel log message.
+http://marc.theaimsgroup.com/?l=linux-kernel&m=114232987208628&w=3
+
+Signed-off-by: Mark M. Hoffman <mhoffman@lightlink.com>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/i2c/busses/i2c-sis96x.c | 8 --------
+ 1 file changed, 8 deletions(-)
+
+--- gregkh-2.6.orig/drivers/i2c/busses/i2c-sis96x.c
++++ gregkh-2.6/drivers/i2c/busses/i2c-sis96x.c
+@@ -43,13 +43,6 @@
+ #include <linux/init.h>
+ #include <asm/io.h>
+
+-/*
+- HISTORY:
+- 2003-05-11 1.0.0 Updated from lm_sensors project for kernel 2.5
+- (was i2c-sis645.c from lm_sensors 2.7.0)
+-*/
+-#define SIS96x_VERSION "1.0.0"
+-
+ /* base address register in PCI config space */
+ #define SIS96x_BAR 0x04
+
+@@ -337,7 +330,6 @@ static struct pci_driver sis96x_driver =
+
+ static int __init i2c_sis96x_init(void)
+ {
+- printk(KERN_INFO "i2c-sis96x version %s\n", SIS96x_VERSION);
+ return pci_register_driver(&sis96x_driver);
+ }
+
diff --git a/i2c/rtc-ds1374-convert-tasklet-to-workqueue.patch b/i2c/rtc-ds1374-convert-tasklet-to-workqueue.patch
new file mode 100644
index 0000000000000..7af32236b427d
--- /dev/null
+++ b/i2c/rtc-ds1374-convert-tasklet-to-workqueue.patch
@@ -0,0 +1,83 @@
+From khali@linux-fr.org Fri Mar 31 13:04:57 2006
+Date: Fri, 31 Mar 2006 23:05:01 +0200
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Subject: [PATCH 1/3] i2c: convert ds1374 to use a workqueue
+Message-Id: <20060331230501.c9858518.khali@linux-fr.org>
+Content-Disposition: inline; filename=rtc-ds1374-convert-tasklet-to-workqueue.patch
+
+A tasklet is not suitable for what the ds1374 driver does: neither sleeping
+nor mutex operations are allowed in tasklets, and ds1374_set_tlet may do
+both.
+
+We can use a workqueue instead, where both sleeping and mutex operations
+are allowed.
+
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Acked-by: Randy Vinson <rvinson@mvista.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/i2c/chips/ds1374.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+--- gregkh-2.6.orig/drivers/i2c/chips/ds1374.c
++++ gregkh-2.6/drivers/i2c/chips/ds1374.c
+@@ -27,6 +27,7 @@
+ #include <linux/rtc.h>
+ #include <linux/bcd.h>
+ #include <linux/mutex.h>
++#include <linux/workqueue.h>
+
+ #define DS1374_REG_TOD0 0x00
+ #define DS1374_REG_TOD1 0x01
+@@ -139,7 +140,7 @@ ulong ds1374_get_rtc_time(void)
+ return t1;
+ }
+
+-static void ds1374_set_tlet(ulong arg)
++static void ds1374_set_work(void *arg)
+ {
+ ulong t1, t2;
+ int limit = 10; /* arbitrary retry limit */
+@@ -168,17 +169,18 @@ static void ds1374_set_tlet(ulong arg)
+
+ static ulong new_time;
+
+-static DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet,
+- (ulong) & new_time);
++static struct workqueue_struct *ds1374_workqueue;
++
++static DECLARE_WORK(ds1374_work, ds1374_set_work, &new_time);
+
+ int ds1374_set_rtc_time(ulong nowtime)
+ {
+ new_time = nowtime;
+
+ if (in_interrupt())
+- tasklet_schedule(&ds1374_tasklet);
++ queue_work(ds1374_workqueue, &ds1374_work);
+ else
+- ds1374_set_tlet((ulong) & new_time);
++ ds1374_set_work(&new_time);
+
+ return 0;
+ }
+@@ -204,6 +206,8 @@ static int ds1374_probe(struct i2c_adapt
+ client->adapter = adap;
+ client->driver = &ds1374_driver;
+
++ ds1374_workqueue = create_singlethread_workqueue("ds1374");
++
+ if ((rc = i2c_attach_client(client)) != 0) {
+ kfree(client);
+ return rc;
+@@ -227,7 +231,7 @@ static int ds1374_detach(struct i2c_clie
+
+ if ((rc = i2c_detach_client(client)) == 0) {
+ kfree(i2c_get_clientdata(client));
+- tasklet_kill(&ds1374_tasklet);
++ destroy_workqueue(ds1374_workqueue);
+ }
+ return rc;
+ }
diff --git a/i2c/rtc-m41t00-driver-cleanup.patch b/i2c/rtc-m41t00-driver-cleanup.patch
new file mode 100644
index 0000000000000..33b19dc070377
--- /dev/null
+++ b/i2c/rtc-m41t00-driver-cleanup.patch
@@ -0,0 +1,145 @@
+From khali@linux-fr.org Fri Mar 31 13:06:41 2006
+Date: Fri, 31 Mar 2006 23:06:46 +0200
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: "Mark A. Greer" <mgreer@mvista.com>
+Subject: [PATCH 3/3] i2c: cleanup m41t00
+Message-Id: <20060331230646.e06f73a1.khali@linux-fr.org>
+Content-Disposition: inline; filename=rtc-m41t00-driver-cleanup.patch
+
+From: "Mark A. Greer" <mgreer@mvista.com>
+
+This patch does some cleanup to the m41t00 i2c/rtc driver including:
+- use BCD2BIN/BIN2BCD instead of BCD_TO_BIN/BIN_TO_BCD
+- use strlcpy instead of strncpy
+- some whitespace cleanup
+
+Signed-off-by: Mark A. Greer <mgreer@mvista.com>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/i2c/chips/m41t00.c | 49 +++++++++++++++++++--------------------------
+ 1 file changed, 21 insertions(+), 28 deletions(-)
+
+--- gregkh-2.6.orig/drivers/i2c/chips/m41t00.c
++++ gregkh-2.6/drivers/i2c/chips/m41t00.c
+@@ -1,6 +1,4 @@
+ /*
+- * drivers/i2c/chips/m41t00.c
+- *
+ * I2C client/driver for the ST M41T00 Real-Time Clock chip.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+@@ -13,9 +11,6 @@
+ /*
+ * This i2c client/driver wedges between the drivers/char/genrtc.c RTC
+ * interface and the SMBus interface of the i2c subsystem.
+- * It would be more efficient to use i2c msgs/i2c_transfer directly but, as
+- * recommened in .../Documentation/i2c/writing-clients section
+- * "Sending and receiving", using SMBus level communication is preferred.
+ */
+
+ #include <linux/kernel.h>
+@@ -41,17 +36,17 @@ static unsigned short ignore[] = { I2C_C
+ static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END };
+
+ static struct i2c_client_address_data addr_data = {
+- .normal_i2c = normal_addr,
+- .probe = ignore,
+- .ignore = ignore,
++ .normal_i2c = normal_addr,
++ .probe = ignore,
++ .ignore = ignore,
+ };
+
+ ulong
+ m41t00_get_rtc_time(void)
+ {
+- s32 sec, min, hour, day, mon, year;
+- s32 sec1, min1, hour1, day1, mon1, year1;
+- ulong limit = 10;
++ s32 sec, min, hour, day, mon, year;
++ s32 sec1, min1, hour1, day1, mon1, year1;
++ ulong limit = 10;
+
+ sec = min = hour = day = mon = year = 0;
+ sec1 = min1 = hour1 = day1 = mon1 = year1 = 0;
+@@ -97,12 +92,12 @@ m41t00_get_rtc_time(void)
+ mon &= 0x1f;
+ year &= 0xff;
+
+- BCD_TO_BIN(sec);
+- BCD_TO_BIN(min);
+- BCD_TO_BIN(hour);
+- BCD_TO_BIN(day);
+- BCD_TO_BIN(mon);
+- BCD_TO_BIN(year);
++ sec = BCD2BIN(sec);
++ min = BCD2BIN(min);
++ hour = BCD2BIN(hour);
++ day = BCD2BIN(day);
++ mon = BCD2BIN(mon);
++ year = BCD2BIN(year);
+
+ year += 1900;
+ if (year < 1970)
+@@ -115,17 +110,17 @@ static void
+ m41t00_set(void *arg)
+ {
+ struct rtc_time tm;
+- ulong nowtime = *(ulong *)arg;
++ ulong nowtime = *(ulong *)arg;
+
+ to_tm(nowtime, &tm);
+ tm.tm_year = (tm.tm_year - 1900) % 100;
+
+- BIN_TO_BCD(tm.tm_sec);
+- BIN_TO_BCD(tm.tm_min);
+- BIN_TO_BCD(tm.tm_hour);
+- BIN_TO_BCD(tm.tm_mon);
+- BIN_TO_BCD(tm.tm_mday);
+- BIN_TO_BCD(tm.tm_year);
++ tm.tm_sec = BIN2BCD(tm.tm_sec);
++ tm.tm_min = BIN2BCD(tm.tm_min);
++ tm.tm_hour = BIN2BCD(tm.tm_hour);
++ tm.tm_mon = BIN2BCD(tm.tm_mon);
++ tm.tm_mday = BIN2BCD(tm.tm_mday);
++ tm.tm_year = BIN2BCD(tm.tm_year);
+
+ mutex_lock(&m41t00_mutex);
+ if ((i2c_smbus_write_byte_data(save_client, 0, tm.tm_sec & 0x7f) < 0)
+@@ -143,7 +138,6 @@ m41t00_set(void *arg)
+ dev_warn(&save_client->dev,"m41t00: can't write to rtc chip\n");
+
+ mutex_unlock(&m41t00_mutex);
+- return;
+ }
+
+ static ulong new_time;
+@@ -180,7 +174,7 @@ m41t00_probe(struct i2c_adapter *adap, i
+ if (!client)
+ return -ENOMEM;
+
+- strncpy(client->name, M41T00_DRV_NAME, I2C_NAME_SIZE);
++ strlcpy(client->name, M41T00_DRV_NAME, I2C_NAME_SIZE);
+ client->addr = addr;
+ client->adapter = adap;
+ client->driver = &m41t00_driver;
+@@ -204,7 +198,7 @@ m41t00_attach(struct i2c_adapter *adap)
+ static int
+ m41t00_detach(struct i2c_client *client)
+ {
+- int rc;
++ int rc;
+
+ if ((rc = i2c_detach_client(client)) == 0) {
+ kfree(client);
+@@ -232,7 +226,6 @@ static void __exit
+ m41t00_exit(void)
+ {
+ i2c_del_driver(&m41t00_driver);
+- return;
+ }
+
+ module_init(m41t00_init);
diff --git a/i2c/rtc-m41t00-driver-should-use-workqueue-instead-of-tasklet.patch b/i2c/rtc-m41t00-driver-should-use-workqueue-instead-of-tasklet.patch
new file mode 100644
index 0000000000000..1ff11eedc31de
--- /dev/null
+++ b/i2c/rtc-m41t00-driver-should-use-workqueue-instead-of-tasklet.patch
@@ -0,0 +1,84 @@
+From khali@linux-fr.org Fri Mar 31 13:05:53 2006
+Date: Fri, 31 Mar 2006 23:06:03 +0200
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: "Mark A. Greer" <mgreer@mvista.com>
+Subject: [PATCH 2/3] i2c: convert m41t00 to use a workqueue
+Message-Id: <20060331230603.4a8bc540.khali@linux-fr.org>
+Content-Disposition: inline; filename=rtc-m41t00-driver-should-use-workqueue-instead-of-tasklet.patch
+
+From: "Mark A. Greer" <mgreer@mvista.com>
+
+The m41t00 i2c/rtc driver currently uses a tasklet to schedule
+interrupt-level writes to the rtc. This patch causes the driver
+to use a workqueue instead.
+
+Signed-off-by: Mark A. Greer <mgreer@mvista.com>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/i2c/chips/m41t00.c | 16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+--- gregkh-2.6.orig/drivers/i2c/chips/m41t00.c
++++ gregkh-2.6/drivers/i2c/chips/m41t00.c
+@@ -25,6 +25,7 @@
+ #include <linux/rtc.h>
+ #include <linux/bcd.h>
+ #include <linux/mutex.h>
++#include <linux/workqueue.h>
+
+ #include <asm/time.h>
+ #include <asm/rtc.h>
+@@ -111,7 +112,7 @@ m41t00_get_rtc_time(void)
+ }
+
+ static void
+-m41t00_set_tlet(ulong arg)
++m41t00_set(void *arg)
+ {
+ struct rtc_time tm;
+ ulong nowtime = *(ulong *)arg;
+@@ -145,9 +146,9 @@ m41t00_set_tlet(ulong arg)
+ return;
+ }
+
+-static ulong new_time;
+-
+-DECLARE_TASKLET_DISABLED(m41t00_tasklet, m41t00_set_tlet, (ulong)&new_time);
++static ulong new_time;
++static struct workqueue_struct *m41t00_wq;
++static DECLARE_WORK(m41t00_work, m41t00_set, &new_time);
+
+ int
+ m41t00_set_rtc_time(ulong nowtime)
+@@ -155,9 +156,9 @@ m41t00_set_rtc_time(ulong nowtime)
+ new_time = nowtime;
+
+ if (in_interrupt())
+- tasklet_schedule(&m41t00_tasklet);
++ queue_work(m41t00_wq, &m41t00_work);
+ else
+- m41t00_set_tlet((ulong)&new_time);
++ m41t00_set(&new_time);
+
+ return 0;
+ }
+@@ -189,6 +190,7 @@ m41t00_probe(struct i2c_adapter *adap, i
+ return rc;
+ }
+
++ m41t00_wq = create_singlethread_workqueue("m41t00");
+ save_client = client;
+ return 0;
+ }
+@@ -206,7 +208,7 @@ m41t00_detach(struct i2c_client *client)
+
+ if ((rc = i2c_detach_client(client)) == 0) {
+ kfree(client);
+- tasklet_kill(&m41t00_tasklet);
++ destroy_workqueue(m41t00_wq);
+ }
+ return rc;
+ }