kernel 2.6.X lm85 fan control patch

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

Here is a patch to add back in automated fan control access for the lm85
and clones in the kernel 2.6.X driver.

I have stuck with the 

Off -> Min -> Max -> Crit

model discussed on the list archive.

Most control bits are exposed.  (And yes, this generates a LOT of 
/sys/bus/i2c/device/../ files!)

I have changed a few names around in an attempt to straighten out the naming
conventions.

The accompanying lib/chips.c, lib/chips.h, and prog/sensors.h patches follow
in separate emails.

There are undoubtedly a few bugs lurking, so I'd appreciate feedback.

Thanks,

Justin Thiessen
---------------
Linux Engineer
jthiessen at penguincomputing.com
http://www.penguincomputing.com

from:
$diff -Naur


-------------------------------------

--- lm85.c	2004-08-09 12:36:03.822501296 -0700
+++ lm85.c.updated	2004-08-09 12:35:58.627291088 -0700
@@ -4,6 +4,7 @@
     Copyright (c) 1998, 1999  Frodo Looijaard <frodol at dds.nl> 
     Copyright (c) 2002, 2003  Philip Pokorny <ppokorny at penguincomputing.com>
     Copyright (c) 2003        Margit Schubert-While <margitsw at t-online.de>
+    Copyright (c) 2004        Justin Thiessen <jthiessen at penguincomputing.com>
 
     Chip details at	      <http://www.national.com/ds/LM/LM85.pdf>
 
@@ -33,8 +34,6 @@
 #include <asm/io.h>
 */
 
-#undef	LM85EXTENDEDFUNC	/* Extended functionality */
-
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
 static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
@@ -158,19 +157,57 @@
 #define TEMP_FROM_REG(val)		(TEMPEXT_FROM_REG(val,0))
 #define EXTTEMP_TO_REG(val)		(SENSORS_LIMIT((val)/250,-127,127))
 
-#define PWM_TO_REG(val)			(SENSORS_LIMIT(val,0,255))
-#define PWM_FROM_REG(val)		(val)
+#define PWM_TO_REG(val)			(SENSORS_LIMIT(((val)+500)/1000,0,255))
+#define PWM_FROM_REG(val)		((val)*1000)
 
 #define EXT_FROM_REG(val,sensor)	(((val)>>(sensor * 2))&0x03)
 
-#ifdef	LM85EXTENDEDFUNC	/* Extended functionality */
-
-/* ZONEs have the following parameters:
+/*
+ * ZONEs have the following parameters:
  *    Limit (low) temp,           1. degC
  *    Hysteresis (below limit),   1. degC (0-15)
  *    Range of speed control,     .1 degC (2-80)
  *    Critical (high) temp,       1. degC
  *
+ *
+ * The current model for fan control in lm_sensors is:
+ *
+ * 
+ *   Off  Min                 Max   Critical
+ *  --+----+-------------------+-------+------------>
+ *
+ *                Temperature -->
+ *
+ * Where:
+ *
+ * Off -> temperature at which fan(s) controlled by a particular sensor
+ *        turn off
+ * Min -> minimum temperature that is require to spin up fan(s) controlled
+ *        by a particular sensor
+ * Max -> temperature at which fan(s) controlled by a particular sensor
+ *        are at 100%
+ * Critical -> temperature at which all fans are raised to 100%.
+ *
+ * So the conversion is obviously:
+ * 
+ * Off = Limit - Hysteresis
+ * Min = Limit
+ * Max = Limit + Range
+ * Critical = Critical
+ *
+ * within the limits imposed by the resolution and range of the Hysteresis and 
+ * Range registers.  Because of these limitations, the casual user may 
+ * occasionally be surprised as actual values for Off and Max vary from
+ * those requested, even though the code does its best to find the closest 
+ * possible match to the desired parameters.
+ *
+ * Is is really best to standardize the interface at the cost of obfuscating
+ * the way the chip's internals work?  Surely this will just lead to a new
+ * set of FAQs dealing with the subject...
+ * 
+ */
+ 
+/*
  * FAN PWMs have the following parameters:
  *    Reference Zone,                 1, 2, 3, etc.
  *    Spinup time,                    .05 sec
@@ -183,11 +220,12 @@
  *    Filter constant (or disabled)   .1 seconds
  */
 
-/* These are the zone temperature range encodings */
-static int lm85_range_map[] = {   /* .1 degC */
-		 20,  25,  33,  40,  50,  66,
-		 80, 100, 133, 160, 200, 266,
-		320, 400, 533, 800
+/* These are the zone temperature range encodings in .001 degree C */
+
+static int lm85_range_map[] = {   
+		2000,  2500,  3300,  4000,  5000,  6600,
+		8000, 10000, 13300, 16000, 20000, 26600,
+		32000, 40000, 53300, 80000
 	};
 static int RANGE_TO_REG( int range )
 {
@@ -195,8 +233,16 @@
 
 	if( range >= lm85_range_map[15] ) { return 15 ; }
 	for( i = 0 ; i < 15 ; ++i )
-		if( range <= lm85_range_map[i] )
-			break ;
+		if( range <= lm85_range_map[i] ) {
+			if (i == 0) {
+				break;
+			} else if ((lm85_range_map[i] - range) > 
+				(range - lm85_range_map[i-1])) {
+				i--;
+				break;
+			}
+			break;
+		}
 	return( i & 0x0f );
 }
 #define RANGE_FROM_REG(val) (lm85_range_map[(val)&0x0f])
@@ -223,6 +269,12 @@
 #define SMOOTH_FROM_REG(val) ((val)&0x08?lm85_smooth_map[(val)&0x07]:0)
 
 /* These are the fan spinup delay time encodings */
+
+/*
+ * What about the fact that the adm1027 datasheet does not list the .7
+ * second setting?
+ */
+
 static int lm85_spinup_map[] = {  /* .1 sec */
 		0, 1, 2, 4, 7, 10, 20, 40
 	};
@@ -240,7 +292,7 @@
 
 /* These are the PWM frequency encodings */
 static int lm85_freq_map[] = { /* .1 Hz */
-		100, 150, 230, 300, 380, 470, 620, 980
+		100, 150, 230, 300, 380, 470, 620, 940
 	};
 static int FREQ_TO_REG( int freq )
 {
@@ -265,14 +317,8 @@
  *     -1 -- PWM is always at 100%
  *     -2 -- PWM responds to manual control
  */
-
-#endif		/* Extended functionality */
-
 static int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 };
 #define ZONE_FROM_REG(val) (lm85_zone_map[((val)>>5)&0x07])
-
-#ifdef	LM85EXTENDEDFUNC	/* Extended functionality */
-
 static int ZONE_TO_REG( int zone )
 {
 	int i;
@@ -285,13 +331,15 @@
 	return( (i & 0x07)<<5 );
 }
 
-#endif		/* Extended functionality */
+/* Define Hysteresis  */
+#define HYST_TO_REG(val) (SENSORS_LIMIT(((val)+500)/1000,0,15)) 
+#define HYST_FROM_REG(val) (val * 1000)  
 
-#define HYST_TO_REG(val) (SENSORS_LIMIT((-(val)+5)/10,0,15))
-#define HYST_FROM_REG(val) (-(val)*10)
+#define ADM1027_OFFSET_TO_REG(val) (SENSORS_LIMIT((val)/1000,-127,127))
+#define ADM1027_OFFSET_FROM_REG(val) ((val)*1000)
 
-#define OFFSET_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127))
-#define OFFSET_FROM_REG(val) ((val)*25)
+#define ADT7463_OFFSET_TO_REG(val) (SENSORS_LIMIT((val)/250,-127,127))
+#define ADT7463_OFFSET_FROM_REG(val) ((val)*250)
 
 #define PPR_MASK(fan) (0x03<<(fan *2))
 #define PPR_TO_REG(val,fan) (SENSORS_LIMIT((val)-1,0,3)<<(fan *2))
@@ -332,25 +380,41 @@
    dynamically allocated, at the same time when a new lm85 client is
    allocated. */
 
+#define LM85_SPINUP_CTL_FROM_REG(val,offset) ((val & (0x01 << (offset))) \
+        >> (offset))
+#define LM85_SPINUP_CTL_TO_REG(val,offset) (val << (offset))
+
+#define ADM1027_SPINUP_CTL_FROM_REG(val) ((val >> 5) & 0x01)
+#define ADM1027_SPINUP_CTL_TO_REG(val) ((val & 0x01) << 5)
+
+#define INVERT_FROM_REG(val) (((val) & 0x10) >> 4)
+#define INVERT_TO_REG(val) (val == 1 ? val << 4 : 0)
+
+#define LM85_TACH_MODE_FROM_REG(val, tach) ( (val >> (2*tach)) & 0x03 )
+#define LM85_TACH_MODE_TO_REG(val, tach) ((val & 0x03) << (2*tach))
+
+#define ADM1027_TACH_MODE_FROM_REG(val, tach) ( (val >> (tach + 4)) & 0x01 )
+#define ADM1027_TACH_MODE_TO_REG(val, tach) (val << (tach + 4))
+
+#define DYNAMIC_TMIN_ENABLE_FROM_REG(val,nr) ((val >> (nr + 13)) & 0x01)
+#define DYNAMIC_TMIN_ENABLE_TO_REG(val,nr) ((val & 0x01) << (nr +13))
+
+#define ADT7463_THERM_LIMIT_TO_REG(val) (SENSORS_LIMIT(((val - \
+	45520)/22760),0,255))
+#define ADT7463_THERM_LIMIT_FROM_REG(val) ((val) * 22760) /* In milliseconds */
+
+#define ADT7463_THERM_TOTAL_IN_MSEC(val) ((val) * 22760) /* In milliseconds */
+
+#define ALARM_MASK_TO_REG(val,offset) ((val & 0x01) << offset)
+#define ALARM_MASK_FROM_REG(val,offset) ((val >> offset) & 0x01)
+
 /* LM85 can automatically adjust fan speeds based on temperature
  * This structure encapsulates an entire Zone config.  There are
  * three zones (one for each temperature input) on the lm85
  */
-struct lm85_zone {
-	s8 limit;	/* Low temp limit */
-	u8 hyst;	/* Low limit hysteresis. (0-15) */
-	u8 range;	/* Temp range, encoded */
-	s8 critical;	/* "All fans ON" temp limit */
-};
-
-struct lm85_autofan {
-	u8 config;	/* Register value */
-	u8 freq;	/* PWM frequency, encoded */
-	u8 min_pwm;	/* Minimum PWM value, encoded */
-	u8 min_off;	/* Min PWM or OFF below "limit", flag */
-};
 
 struct lm85_data {
+	struct i2c_client client;
 	struct semaphore lock;
 	enum chips type;
 
@@ -359,6 +423,9 @@
 	unsigned long last_reading;	/* In jiffies */
 	unsigned long last_config;	/* In jiffies */
 
+	u8 config1;		/* Register value */
+	u8 intmask1;            /* Register Value */
+	u8 intmask2;            /* Register Value */
 	u8 in[5];		/* Register value */
 	u8 in_max[5];		/* Register value */
 	u8 in_min[5];		/* Register value */
@@ -369,21 +436,88 @@
 	u16 fan[4];		/* Register value */
 	u16 fan_min[4];		/* Register value */
 	u8 pwm[3];		/* Register value */
-	u8 spinup_ctl;		/* Register encoding, combined */
+	u8 fan_auto_spinup_ctl;	/* Register encoding, combined */
 	u8 tach_mode;		/* Register encoding, combined */
 	u16 extend_adc;		/* Register value */
-	u8 fan_ppr;		/* Register value */
+	u8 adm1027_fan_ppr;	/* Register value */
 	u8 smooth[3];		/* Register encoding */
 	u8 vid;			/* Register value */
 	u8 vrm;			/* VRM version */
 	u8 syncpwm3;		/* Saved PWM3 for TACH 2,3,4 config */
-	u8 oppoint[3];		/* Register value */
+	u8 temp_auto_oppoint[3];	/* Register value */
 	u16 tmin_ctl;		/* Register value */
-	unsigned long therm_total; /* Cummulative therm count */
-	u8 therm_limit;		/* Register value */
 	u16 alarms;		/* Register encoding, combined */
-	struct lm85_autofan autofan[3];
-	struct lm85_zone zone[3];
+
+        u8 temp_auto_hyst[3];	/* Register value */
+        u8 temp_auto_range[3];	/* temp above min at which fan reaches 100% 
+				(encoded) */
+        s8 temp_auto_min[3];	/* minimum activation temp for fan_auto */
+        s8 temp_auto_critical[3];	/* "All fans ON" temp limit */
+/*
+ * Because we are shoving a square peg (the lm85 Hysteresis-temp_auto_min-range
+ * model) into a round hole (the proposed standard (temp_auto_off-
+ * temp_auto_min-temp_auto_max model), and because the lm85's allowed 
+ * Hysteresis and Range values are only a small handful of non-continuous 
+ * temperatures with varying separation between neighboring elemments,
+ * we MUST keep track of the actual values specified by the sensors.conf
+ * file or by the user via the sysfs interface.  If we were to discard the
+ * values requested and only preserve the "best-fit" numbers picked by the
+ * code, then it is entirely possible for the temp_auto_off and temp_auto_max
+ * settings to drift as new values are set for the temp_auto_min register.  
+ * This will occur even if we make sure to adjust temp_auto_off and 
+ * temp_auto_max every time temp_auto_min changes.  To observe, use the 
+ * following set of numbers:
+ *
+ * ----------------------------------
+ * temp_auto_min:		:  40
+ * Desired temp_auto_max	:  58
+ * ----------------------------------
+ *
+ * Resultant temp_auto_range	:  16
+ * Resultant temp_auto_max	:  56
+ *
+ * Now let
+ *
+ * temp_auto_min => 42
+ *
+ * If we now use 56  as the desired temp_auto_max, then we have
+ *
+ * temp_auto_max - temp_auto_min = 14
+ *
+ * The 2 bracketing elements in the allowable range table are 13.3 and 16
+ *
+ * 13.3 < 14 <= 16  --> temp_auto_range => 13.3.
+ *
+ * And so temp_auto_max => 55.3.
+ *
+ * But if we had kept track of desired temp_auto_max and used that value:
+ *
+ * temp_auto_desired_max - temp_auto_min = 16 
+ *
+ * Again using the 2 bracketing elements from the allowable range table.
+ * 
+ * 13.3 < 16 <= 16  --> temp_auto_range => 16
+ *
+ * and so temp_auto_max => 58
+ *
+ * an entirely different number.
+ * 
+ */
+        s8 temp_auto_desired_max[3];	/* temperature for pwm-controlled fan
+					to go go 100% */
+        s8 temp_auto_desired_off[3];	/* temperature for pwm-controlled fan
+					to turn off */
+        u8 fan_auto_config[3];	/* Register value */
+        u8 fan_auto_freq[3];	/* PWM frequency, encoded */
+        u8 fan_auto_min_pwm[3];	/* Minimum PWM value, encoded */
+        u8 fan_auto_min_ctl[3];	/* Min PWM or OFF below "limit", flag */
+
+	u8 adt7463_therm_limit; /* How long therm can be asserted before an
+				 * interrupt is generated.  (ADT7463-specific 
+				 * register)
+				 */
+	unsigned long adt7463_therm_total; /* Cummulative therm count in
+					    * units of 22760 ms */
 };
 
 static int lm85_attach_adapter(struct i2c_adapter *adapter);
@@ -409,7 +543,6 @@
 /* Unique ID assigned to each LM85 detected */
 static int lm85_id = 0;
 
-
 /* 4 Fans */
 static ssize_t show_fan(struct device *dev, char *buf, int nr)
 {
@@ -450,7 +583,8 @@
 {									\
 	return set_fan_min(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL) \
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset,	\
+		NULL) 							\
 static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, 		\
 		show_fan_##offset##_min, set_fan_##offset##_min)
 
@@ -517,14 +651,6 @@
 	up(&data->update_lock);
 	return count;
 }
-static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr)
-{
-	struct lm85_data *data = lm85_update_device(dev);
-	int	pwm_zone;
-
-	pwm_zone = ZONE_FROM_REG(data->autofan[nr].config);
-	return sprintf(buf,"%d\n", (pwm_zone != 0 && pwm_zone != -1) );
-}
 
 #define show_pwm_reg(offset)						\
 static ssize_t show_pwm_##offset (struct device *dev, char *buf)	\
@@ -536,13 +662,8 @@
 {									\
 	return set_pwm(dev, buf, count, 0x##offset - 1);		\
 }									\
-static ssize_t show_pwm_enable##offset (struct device *dev, char *buf)	\
-{									\
-	return show_pwm_enable(dev, buf, 0x##offset - 1);			\
-}									\
-static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, 			\
-		show_pwm_##offset, set_pwm_##offset)			\
-static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO, show_pwm_enable##offset, NULL)
+static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, 		\
+		show_pwm_##offset, set_pwm_##offset)			
 
 show_pwm_reg(1);
 show_pwm_reg(2);
@@ -696,7 +817,8 @@
 {									\
 	return set_temp_max(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL)	\
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset,	\
+		NULL)							\
 static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, 		\
 		show_temp_##offset##_min, set_temp_##offset##_min)	\
 static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, 		\
@@ -706,128 +828,1353 @@
 show_temp_reg(2);
 show_temp_reg(3);
 
+/* Automatic Fan Control bits follow */
 
-int lm85_attach_adapter(struct i2c_adapter *adapter)
+static ssize_t show_fan_auto_invert(struct device *dev, char *buf, int nr)
 {
-	return i2c_detect(adapter, &addr_data, lm85_detect);
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", INVERT_FROM_REG(data->fan_auto_config[nr]));
 }
-
-int lm85_detect(struct i2c_adapter *adapter, int address,
-		int kind)
+static ssize_t set_fan_auto_invert(struct device *dev, const char *buf,
+	size_t count, int nr)
 {
-	int company, verstep ;
-	struct i2c_client *new_client = NULL;
-	struct lm85_data *data;
-	int err = 0;
-	const char *type_name = "";
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
 
-	if (i2c_is_isa_adapter(adapter)) {
-		/* This chip has no ISA interface */
-		goto ERROR0 ;
-	};
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->fan_auto_config[nr] = (data->fan_auto_config[nr] & ~(0x10))
+		| INVERT_TO_REG(val);
+	lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr),
+		data->fan_auto_config[nr]);
+	up(&data->update_lock);
+	return count;
+}
 
-	if (!i2c_check_functionality(adapter,
-					I2C_FUNC_SMBUS_BYTE_DATA)) {
-		/* We need to be able to do byte I/O */
-		goto ERROR0 ;
-	};
+static ssize_t show_fan_auto_spinup(struct device *dev, char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", SPINUP_FROM_REG(data->fan_auto_config[nr]));
+}
+static ssize_t set_fan_auto_spinup(struct device *dev, const char *buf,
+	size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
 
-	/* OK. For now, we presume we have a valid client. We now create the
-	   client structure, even though we cannot fill it completely yet.
-	   But it allows us to access lm85_{read,write}_value. */
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->fan_auto_config[nr] = (data->fan_auto_config[nr] & (~0x07))
+		| SPINUP_TO_REG(val);
+	lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr),
+		data->fan_auto_config[nr]);
+	up(&data->update_lock);
+	return count;
+}
+static ssize_t show_fan_auto_zone(struct device *dev, char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", ZONE_FROM_REG(data->fan_auto_config[nr]));
+}
+static ssize_t set_fan_auto_zone(struct device *dev, const char *buf,
+	size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
 
-	if (!(new_client = kmalloc((sizeof(struct i2c_client)) +
-				    sizeof(struct lm85_data),
-				    GFP_KERNEL))) {
-		err = -ENOMEM;
-		goto ERROR0;
-	}
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->fan_auto_config[nr] = (data->fan_auto_config[nr] & (~0xe0))
+		| ZONE_TO_REG(val) ;
+	lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr),
+		data->fan_auto_config[nr]);
+	up(&data->update_lock);
+	return count;
+}
+static ssize_t show_fan_auto_freq(struct device *dev, char *buf, int nr)
+{
+        struct lm85_data *data = lm85_update_device(dev);
+        return sprintf(buf,"%d\n", FREQ_FROM_REG(data->fan_auto_freq[nr]));
+}
+static ssize_t set_fan_auto_freq(struct device *dev, const char *buf,
+                size_t count, int nr)
+{
+        struct i2c_client *client = to_i2c_client(dev);
+        struct lm85_data *data = i2c_get_clientdata(client);
+        int     val;
+
+        down(&data->update_lock);
+        val = simple_strtol(buf, NULL, 10);
+        data->fan_auto_freq[nr] = FREQ_TO_REG(val);
+        lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
+                (data->temp_auto_range[nr] << 4)
+                | data->fan_auto_freq[nr]
+        );
+        up(&data->update_lock);
+        return count;
+}
+static ssize_t show_fan_auto_min_pwm(struct device *dev, char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", PWM_FROM_REG(data->fan_auto_min_pwm[nr]));
+}
+static ssize_t set_fan_auto_min_pwm(struct device *dev, const char *buf,
+	size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
 
-	memset(new_client, 0, sizeof(struct i2c_client) +
-			      sizeof(struct lm85_data));
-	data = (struct lm85_data *) (new_client + 1);
-	i2c_set_clientdata(new_client, data);
-	new_client->addr = address;
-	new_client->adapter = adapter;
-	new_client->driver = &lm85_driver;
-	new_client->flags = 0;
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->fan_auto_min_pwm[nr] = PWM_TO_REG(val);
+	lm85_write_value(client, LM85_REG_AFAN_MINPWM(nr), 
+		data->fan_auto_min_pwm[nr]);
+	up(&data->update_lock);
+	return count;
+}
+static ssize_t show_fan_auto_min_ctl(struct device *dev, char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", data->fan_auto_min_ctl[nr]);
+}
+static ssize_t set_fan_auto_min_ctl(struct device *dev, const char *buf,
+	size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
 
-	/* Now, we do the remaining detection. */
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->fan_auto_min_ctl[nr] = val;
+	lm85_write_value(client, LM85_REG_AFAN_SPIKE1, data->smooth[0]
+		| data->syncpwm3
+		| (data->fan_auto_min_ctl[0] ? 0x20 : 0)
+		| (data->fan_auto_min_ctl[1] ? 0x40 : 0)
+		| (data->fan_auto_min_ctl[2] ? 0x80 : 0)
+	);
+	up(&data->update_lock);
+	return count;
+}
 
-	company = lm85_read_value(new_client, LM85_REG_COMPANY);
-	verstep = lm85_read_value(new_client, LM85_REG_VERSTEP);
+#define fan_auto_reg(offset)						\
+static ssize_t show_fan##offset##_auto (struct device *dev, char *buf)	\
+{									\
+	return show_fan_auto_freq(dev, buf, 0x##offset - 1);		\
+}									\
+static ssize_t show_fan##offset##_auto_invert (struct device *dev,	\
+	char *buf)							\
+{									\
+	return show_fan_auto_invert(dev, buf, 0x##offset - 1);		\
+}									\
+static ssize_t show_fan##offset##_auto_spinup (struct device *dev,	\
+	char *buf)							\
+{									\
+	return show_fan_auto_spinup(dev, buf, 0x##offset - 1);		\
+}									\
+static ssize_t show_fan##offset##_auto_zone (struct device *dev,	\
+	char *buf)							\
+{									\
+	return show_fan_auto_zone(dev, buf, 0x##offset - 1);		\
+}									\
+static ssize_t show_fan##offset##_auto_freq (struct device *dev,	\
+	char *buf)							\
+{									\
+	return show_fan_auto_freq(dev, buf, 0x##offset - 1);		\
+}									\
+static ssize_t show_fan##offset##_auto_min_pwm (struct device *dev,	\
+	char *buf)							\
+{									\
+	return show_fan_auto_min_pwm(dev, buf, 0x##offset - 1);		\
+}									\
+static ssize_t show_fan##offset##_auto_min_ctl (struct device *dev,	\
+	char *buf)							\
+{									\
+	return show_fan_auto_min_ctl(dev, buf, 0x##offset - 1);		\
+}									\
+static ssize_t set_fan##offset##_auto_invert (struct device *dev,	\
+	const char *buf, size_t count)					\
+{									\
+	return set_fan_auto_invert(dev, buf, count, 0x##offset - 1);	\
+}									\
+static ssize_t set_fan##offset##_auto_spinup (struct device *dev,	\
+	const char *buf, size_t count)					\
+{									\
+	return set_fan_auto_spinup(dev, buf, count, 0x##offset - 1);	\
+}									\
+static ssize_t set_fan##offset##_auto_zone (struct device *dev,		\
+	const char *buf, size_t count)					\
+{									\
+	return set_fan_auto_zone(dev, buf, count, 0x##offset - 1);	\
+}									\
+static ssize_t set_fan##offset##_auto_freq (struct device *dev,		\
+	const char *buf, size_t count)					\
+{									\
+	return set_fan_auto_freq(dev, buf, count, 0x##offset - 1);	\
+}									\
+static ssize_t set_fan##offset##_auto_min_pwm (struct device *dev,	\
+	const char *buf, size_t count)					\
+{									\
+	return set_fan_auto_min_pwm(dev, buf, count, 0x##offset - 1);	\
+}									\
+static ssize_t set_fan##offset##_auto_min_ctl (struct device *dev,	\
+	const char *buf, size_t count)					\
+{									\
+	return set_fan_auto_min_ctl(dev, buf, count, 0x##offset - 1);	\
+}									\
+static DEVICE_ATTR(fan##offset##_auto, S_IRUGO,				\
+		show_fan##offset##_auto, NULL)				\
+static DEVICE_ATTR(fan##offset##_auto_invert, S_IRUGO | S_IWUSR,	\
+		show_fan##offset##_auto_invert,				\
+		set_fan##offset##_auto_invert)				\
+static DEVICE_ATTR(fan##offset##_auto_spinup, S_IRUGO | S_IWUSR,	\
+		show_fan##offset##_auto_spinup,				\
+		set_fan##offset##_auto_spinup)				\
+static DEVICE_ATTR(fan##offset##_auto_zone, S_IRUGO | S_IWUSR,		\
+		show_fan##offset##_auto_zone,				\
+		set_fan##offset##_auto_zone)				\
+static DEVICE_ATTR(fan##offset##_auto_freq, S_IRUGO | S_IWUSR,		\
+		show_fan##offset##_auto_freq,				\
+		set_fan##offset##_auto_freq)				\
+static DEVICE_ATTR(fan##offset##_auto_min_pwm, S_IRUGO | S_IWUSR,	\
+		show_fan##offset##_auto_min_pwm,			\
+		set_fan##offset##_auto_min_pwm)				\
+static DEVICE_ATTR(fan##offset##_auto_min_ctl, S_IRUGO | S_IWUSR,	\
+		show_fan##offset##_auto_min_ctl,			\
+		set_fan##offset##_auto_min_ctl)				\
+
+fan_auto_reg(1);
+fan_auto_reg(2);
+fan_auto_reg(3);
 
-	dev_dbg(&adapter->dev, "Detecting device at %d,0x%02x with"
-		" COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
-		i2c_adapter_id(new_client->adapter), new_client->addr,
-		company, verstep);
+/* zone/temp_auto stuff */
 
-	/* If auto-detecting, Determine the chip type. */
-	if (kind <= 0) {
-		dev_dbg(&adapter->dev, "Autodetecting device at %d,0x%02x ...\n",
-			i2c_adapter_id(adapter), address );
-		if( company == LM85_COMPANY_NATIONAL
-		    && verstep == LM85_VERSTEP_LM85C ) {
-			kind = lm85c ;
-		} else if( company == LM85_COMPANY_NATIONAL
-		    && verstep == LM85_VERSTEP_LM85B ) {
-			kind = lm85b ;
-		} else if( company == LM85_COMPANY_NATIONAL
-		    && (verstep & 0xf0) == LM85_VERSTEP_GENERIC ) {
-			dev_err(&adapter->dev, "Unrecognized version/stepping 0x%02x"
-				" Defaulting to LM85.\n", verstep);
-			kind = any_chip ;
-		} else if( company == LM85_COMPANY_ANALOG_DEV
-		    && verstep == LM85_VERSTEP_ADM1027 ) {
-			kind = adm1027 ;
-		} else if( company == LM85_COMPANY_ANALOG_DEV
-		    && verstep == LM85_VERSTEP_ADT7463 ) {
-			kind = adt7463 ;
-		} else if( company == LM85_COMPANY_ANALOG_DEV
-		    && (verstep & 0xf0) == LM85_VERSTEP_GENERIC ) {
-			dev_err(&adapter->dev, "Unrecognized version/stepping 0x%02x"
-				" Defaulting to ADM1027.\n", verstep);
-			kind = adm1027 ;
-		} else if( kind == 0 && (verstep & 0xf0) == 0x60) {
-			dev_err(&adapter->dev, "Generic LM85 Version 6 detected\n");
-			/* Leave kind as "any_chip" */
-		} else {
-			dev_dbg(&adapter->dev, "Autodetection failed\n");
-			/* Not an LM85 ... */
-			if( kind == 0 ) {  /* User used force=x,y */
-				dev_err(&adapter->dev, "Generic LM85 Version 6 not"
-					" found at %d,0x%02x. Try force_lm85c.\n",
-					i2c_adapter_id(adapter), address );
-			}
-			err = 0 ;
-			goto ERROR1;
-		}
-	}
+static ssize_t show_temp_auto_off(struct device *dev, char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_auto_min[nr]) -
+		HYST_FROM_REG(data->temp_auto_hyst[nr]));
+}
+static ssize_t set_temp_auto_off(struct device *dev, const char *buf,
+	size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int    min, val;
 
-	/* Fill in the chip specific driver values */
-	if ( kind == any_chip ) {
-		type_name = "lm85";
-	} else if ( kind == lm85b ) {
-		type_name = "lm85b";
-	} else if ( kind == lm85c ) {
-		type_name = "lm85c";
-	} else if ( kind == adm1027 ) {
-		type_name = "adm1027";
-	} else if ( kind == adt7463 ) {
-		type_name = "adt7463";
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	min = TEMP_FROM_REG(data->temp_auto_min[nr]);
+	data->temp_auto_desired_off[nr] = TEMP_TO_REG(val);
+	data->temp_auto_hyst[nr] = HYST_TO_REG(min - val);
+	if( nr == 0 || nr == 1 ) {
+		lm85_write_value(client, LM85_REG_AFAN_HYST1,
+			(data->temp_auto_hyst[0] << 4)
+			| data->temp_auto_hyst[1]
+			);
+	} else {
+		lm85_write_value(client, LM85_REG_AFAN_HYST2,
+			(data->temp_auto_hyst[2] << 4)
+		);
 	}
-	strlcpy(new_client->name, type_name, I2C_NAME_SIZE);
-
-	/* Fill in the remaining client fields */
-	new_client->id = lm85_id++;
-	data->type = kind;
-	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	up(&data->update_lock);
+	return count;
+}
 
-	dev_dbg(&adapter->dev, "Assigning ID %d to %s at %d,0x%02x\n",
-		new_client->id, new_client->name,
-		i2c_adapter_id(new_client->adapter),
-		new_client->addr);
+static ssize_t show_temp_auto_critical(struct device *dev, char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_auto_critical[nr]));
+}
+
+static ssize_t set_temp_auto_critical(struct device *dev, const char *buf,
+                size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->temp_auto_critical[nr] = TEMP_TO_REG(val);
+	lm85_write_value(client, LM85_REG_AFAN_CRITICAL(nr),
+		data->temp_auto_critical[nr]);
+	up(&data->update_lock);
+	return count;
+}
+static ssize_t show_temp_auto_max(struct device *dev, char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_auto_min[nr]) +
+		RANGE_FROM_REG(data->temp_auto_range[nr]));
+}
+static ssize_t set_temp_auto_max(struct device *dev, const char *buf,
+	size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int    min, val;
+
+	down(&data->update_lock);
+	min = TEMP_FROM_REG(data->temp_auto_min[nr]);
+	val = simple_strtol(buf, NULL, 10);
+	data->temp_auto_desired_max[nr] = TEMP_TO_REG(val);
+	data->temp_auto_range[nr] = RANGE_TO_REG(
+		val - min);
+	lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
+		((data->temp_auto_range[nr] & 0x0f) << 4)
+		| (data->fan_auto_freq[nr] & 0x07));
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp_auto_min(struct device *dev, char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_auto_min[nr]) );
+}
+static ssize_t set_temp_auto_min(struct device *dev, const char *buf,
+	size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int    val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->temp_auto_min[nr] = TEMP_TO_REG(val);
+	lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr), 
+		data->temp_auto_min[nr]);
+
+/* Update temp_auto_max and temp_auto_range */
+
+	data->temp_auto_range[nr] = RANGE_TO_REG(
+		TEMP_FROM_REG(data->temp_auto_desired_max[nr]) -
+		TEMP_FROM_REG(data->temp_auto_min[nr]));
+	lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
+		((data->temp_auto_range[nr] & 0x0f) << 4)
+		| (data->fan_auto_freq[nr] & 0x07));
+
+/* Update temp_auto_hyst and temp_auto_off */
+
+	data->temp_auto_hyst[nr] = HYST_TO_REG(TEMP_FROM_REG(
+		data->temp_auto_min[nr]) - TEMP_FROM_REG(
+		data->temp_auto_desired_off[nr]));
+	if( nr == 0 || nr == 1 ) {
+		lm85_write_value(client, LM85_REG_AFAN_HYST1,
+			(data->temp_auto_hyst[0] << 4)
+			| data->temp_auto_hyst[1]
+			);
+	} else {
+		lm85_write_value(client, LM85_REG_AFAN_HYST2,
+			(data->temp_auto_hyst[2] << 4)
+		);
+	}
+	up(&data->update_lock);
+	return count;
+}
+
+
+#define temp_auto(offset)						\
+static ssize_t show_temp##offset##_auto_max (struct device *dev,	\
+	char *buf)							\
+{									\
+	return show_temp_auto_max(dev, buf, 0x##offset - 1);		\
+}									\
+static ssize_t set_temp##offset##_auto_max (struct device *dev,		\
+	const char *buf, size_t count)					\
+{									\
+	return set_temp_auto_max(dev, buf, count, 0x##offset - 1);	\
+}									\
+static ssize_t show_temp##offset##_auto_off (struct device *dev,	\
+	char *buf)							\
+{									\
+	return show_temp_auto_off(dev, buf, 0x##offset - 1);		\
+}									\
+static ssize_t set_temp##offset##_auto_off (struct device *dev,		\
+	const char *buf, size_t count)					\
+{									\
+	return set_temp_auto_off(dev, buf, count, 0x##offset - 1);	\
+}									\
+static ssize_t show_temp##offset##_auto_critical (struct device *dev,	\
+	char *buf)							\
+{									\
+	return show_temp_auto_critical(dev, buf, 0x##offset - 1);	\
+}									\
+static ssize_t set_temp##offset##_auto_critical (struct device *dev,	\
+	const char *buf, size_t count)					\
+{									\
+	return set_temp_auto_critical(dev, buf, count, 0x##offset - 1);	\
+}									\
+static ssize_t show_temp##offset##_auto_min (struct device *dev,	\
+	char *buf)							\
+{									\
+	return show_temp_auto_min(dev, buf, 0x##offset - 1);		\
+}									\
+static ssize_t set_temp##offset##_auto_min (struct device *dev,		\
+	const char *buf, size_t count)					\
+{									\
+	return set_temp_auto_min(dev, buf, count, 0x##offset - 1);	\
+}									\
+static DEVICE_ATTR(temp##offset##_auto_max, S_IRUGO | S_IWUSR,		\
+		show_temp##offset##_auto_max,				\
+		set_temp##offset##_auto_max)				\
+static DEVICE_ATTR(temp##offset##_auto_off, S_IRUGO | S_IWUSR,		\
+		show_temp##offset##_auto_off,				\
+		set_temp##offset##_auto_off)				\
+static DEVICE_ATTR(temp##offset##_auto_critical, S_IRUGO | S_IWUSR,	\
+		show_temp##offset##_auto_critical,			\
+		set_temp##offset##_auto_critical)			\
+static DEVICE_ATTR(temp##offset##_auto_min, S_IRUGO | S_IWUSR,		\
+		show_temp##offset##_auto_min,				\
+		set_temp##offset##_auto_min)
+
+temp_auto(1);
+temp_auto(2);
+temp_auto(3);
+
+
+/*
+ * ADT7463-specific operating point dynamic Tmin control -JRT 
+ */
+
+static ssize_t show_temp_auto_oppoint(struct device *dev, char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_auto_oppoint[nr]));
+}
+
+static ssize_t set_temp_auto_oppoint(struct device *dev, const char *buf,
+	size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->temp_auto_oppoint[nr] = TEMP_TO_REG(val);
+	lm85_write_value(client, ADT7463_REG_OPPOINT(nr),
+		data->temp_auto_oppoint[nr]);
+	up(&data->update_lock);
+	return count;
+}
+
+
+#define temp_auto_oppoint(offset)					\
+static ssize_t show_temp##offset##_auto_oppoint(struct device *dev, 	\
+	char *buf)							\
+{									\
+	return show_temp_auto_oppoint(dev, buf, 0x##offset - 1);	\
+}									\
+static ssize_t set_temp##offset##_auto_oppoint(struct device *dev, 	\
+	const char *buf, size_t count)					\
+{									\
+	return set_temp_auto_oppoint(dev, buf, count, 0x##offset - 1);	\
+}									\
+static DEVICE_ATTR(temp##offset##_auto_oppoint, S_IRUGO | S_IWUSR,	\
+		show_temp##offset##_auto_oppoint,			\
+		set_temp##offset##_auto_oppoint)				
+
+temp_auto_oppoint(1);
+temp_auto_oppoint(2);
+temp_auto_oppoint(3);
+
+static ssize_t show_temp_auto_dynamic_tmin_ctl(struct device *dev, 
+	char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", DYNAMIC_TMIN_ENABLE_FROM_REG(
+		data->tmin_ctl, nr));
+}
+static ssize_t set_temp_auto_dynamic_tmin_ctl(struct device *dev, 
+	const char *buf, size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->tmin_ctl = (data->tmin_ctl & ~(0x01 << (13 + nr)))
+		| DYNAMIC_TMIN_ENABLE_TO_REG(val, nr);
+	lm85_write_value(client, ADT7463_REG_TMIN_CTL1, data->tmin_ctl);
+	up(&data->update_lock);
+	return count;
+}
+
+/*
+ * Enable/Disable ADT7463 automatic Tmin control.
+ */
+
+#define temp_auto_dynamic_tmin_ctl(offset)				\
+static ssize_t show_temp##offset##_auto_dynamic_tmin_ctl (struct 	\
+	device *dev, char *buf)						\
+{									\
+	return show_temp_auto_dynamic_tmin_ctl(dev, buf, 		\
+		0x##offset - 1);					\
+}									\
+static ssize_t set_temp##offset##_auto_dynamic_tmin_ctl (struct		\
+	device *dev, const char *buf, size_t count)			\
+{									\
+	return set_temp_auto_dynamic_tmin_ctl(dev, buf, count, 		\
+		0x##offset - 1);					\
+}									\
+static DEVICE_ATTR(temp##offset##_auto_dynamic_tmin_ctl, S_IRUGO 	\
+		| S_IWUSR, 						\
+		show_temp##offset##_auto_dynamic_tmin_ctl,		\
+		set_temp##offset##_auto_dynamic_tmin_ctl)				
+
+temp_auto_dynamic_tmin_ctl(1);
+temp_auto_dynamic_tmin_ctl(2);
+temp_auto_dynamic_tmin_ctl(3);
+
+
+/* SET ADT7463 THERM LIMIT */
+
+static ssize_t adt7463_show_therm_limit(struct device *dev, 
+	char *buf)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", ADT7463_THERM_LIMIT_FROM_REG(
+		data->adt7463_therm_limit));
+}
+static ssize_t adt7463_set_therm_limit(struct device *dev, 
+	const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->adt7463_therm_limit= ADT7463_THERM_LIMIT_TO_REG(val);
+	lm85_write_value(client, ADT7463_REG_THERM_LIMIT,
+		data->adt7463_therm_limit);
+	up(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(therm_limit, S_IRUGO | S_IWUSR,
+		adt7463_show_therm_limit, adt7463_set_therm_limit)
+
+/* SHOW ADT7463 THERM TOTAL */
+
+static ssize_t adt7463_show_therm_total(struct device *dev, 
+	char *buf)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%ld\n", ADT7463_THERM_TOTAL_IN_MSEC(
+		data->adt7463_therm_total));
+}
+
+static DEVICE_ATTR(therm_total, S_IRUGO | S_IWUSR,
+		adt7463_show_therm_total, NULL)
+
+/* SPINUP_CTL STUFF */
+
+static ssize_t lm85_show_fan_auto_spinup_ctl(struct device *dev, 
+	char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", LM85_SPINUP_CTL_FROM_REG(
+		data->fan_auto_spinup_ctl, nr));
+}
+static ssize_t lm85_set_fan_auto_spinup_ctl(struct device *dev, 
+	const char *buf, size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	switch (nr) {
+	case 1 :
+	data->fan_auto_spinup_ctl = (data->fan_auto_spinup_ctl &
+		0x06) | LM85_SPINUP_CTL_TO_REG(val, nr);
+		break;
+	case 2 :
+	data->fan_auto_spinup_ctl = (data->fan_auto_spinup_ctl &
+		0x05) | LM85_SPINUP_CTL_TO_REG(val, nr);
+		break;
+	case 3 :
+	data->fan_auto_spinup_ctl = (data->fan_auto_spinup_ctl &
+		0x03) | LM85_SPINUP_CTL_TO_REG(val, nr);
+		break;
+	}
+	lm85_write_value(client, LM85_REG_SPINUP_CTL,
+		data->fan_auto_spinup_ctl);
+	up(&data->update_lock);
+	return count;
+}
+
+#define lm85_fan_auto_spinup_ctl(offset)				\
+static ssize_t show_fan##offset##_auto_spinup_ctl (struct device *dev,	\
+	char *buf)							\
+{									\
+	return lm85_show_fan_auto_spinup_ctl(dev, buf, 0x##offset - 1);	\
+}									\
+static ssize_t set_fan##offset##_auto_spinup_ctl (struct device *dev,	\
+	const char *buf, size_t count)					\
+{									\
+	return lm85_set_fan_auto_spinup_ctl(dev, buf, count,		\
+	0x##offset - 1);						\
+}									\
+static DEVICE_ATTR(fan##offset##_auto_spinup_ctl, S_IRUGO | S_IWUSR,	\
+		show_fan##offset##_auto_spinup_ctl,			\
+		set_fan##offset##_auto_spinup_ctl) 
+
+lm85_fan_auto_spinup_ctl(1);
+lm85_fan_auto_spinup_ctl(2);
+lm85_fan_auto_spinup_ctl(3);
+
+static ssize_t adm1027_show_fan_auto_spinup_ctl(struct device *dev, 
+	char *buf)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", ADM1027_SPINUP_CTL_FROM_REG(
+		data->fan_auto_spinup_ctl));
+}
+static ssize_t adm1027_set_fan_auto_spinup_ctl(struct device *dev, 
+	const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->fan_auto_spinup_ctl = ADM1027_SPINUP_CTL_TO_REG(val);
+
+/*
+ *  Because data->config1 is read from LM85_REG_CONFIG, and because
+ *  the start bit 0x01 is flipped _after_ the value in data->config1 is 
+ *  set, we must make sure the start bit is set properly when we write
+ *  the new configuration to the register.
+ */
+
+	data->config1 = (data->config1 & 0xdf) | data->fan_auto_spinup_ctl
+		| 0x01;
+	lm85_write_value(client, LM85_REG_CONFIG, data->config1); 
+	up(&data->update_lock); 
+	return count;
+}
+
+static DEVICE_ATTR(fan_auto_spinup_ctl, S_IRUGO | S_IWUSR,		
+		adm1027_show_fan_auto_spinup_ctl, 
+		adm1027_set_fan_auto_spinup_ctl) 			
+
+
+/* END SPINUP_CTL STUFF */
+
+/* SMOOTHING STUFF */
+
+static ssize_t show_smoothing(struct device *dev, char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", SMOOTH_FROM_REG(data->smooth[nr]) );
+}
+static ssize_t set_smoothing(struct device *dev, const char *buf,
+	size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->smooth[nr] = SMOOTH_TO_REG(val);
+	switch( nr ) {
+	case 1 :
+		lm85_write_value(client, LM85_REG_AFAN_SPIKE1,
+			data->smooth[0]
+			| data->syncpwm3
+			| (data->fan_auto_min_ctl[0] ? 0x20 : 0)
+			| (data->fan_auto_min_ctl[1] ? 0x40 : 0)
+			| (data->fan_auto_min_ctl[2] ? 0x80 : 0));
+		break ;
+	case 2 :
+	case 3 :
+		lm85_write_value(client, LM85_REG_AFAN_SPIKE2,
+			data->smooth[1] << 4
+			| data->smooth[2]);
+		break ;
+	}
+	up(&data->update_lock);
+	return count;
+}
+
+#define smoothing(offset)						\
+static ssize_t show_smoothing_##offset (struct device *dev, char *buf)	\
+{									\
+	return show_smoothing(dev, buf, 0x##offset - 1);		\
+}									\
+static ssize_t set_smoothing_##offset (struct device *dev,		\
+	const char *buf, size_t count)					\
+{									\
+	return set_smoothing(dev, buf, count, 0x##offset - 1);		\
+}									\
+static DEVICE_ATTR(temp##offset##_auto_smooth, S_IRUGO | S_IWUSR,		\
+		show_smoothing_##offset, set_smoothing_##offset)         
+
+smoothing(1);
+smoothing(2);
+smoothing(3);
+
+/* tach */
+
+static ssize_t lm85_show_fan_tach_mode(struct device *dev, char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", LM85_TACH_MODE_FROM_REG(data->tach_mode, nr));
+}
+static ssize_t lm85_set_fan_tach_mode(struct device *dev, const char *buf,
+	size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->tach_mode = (data->tach_mode & ~(0x03 << (2*nr)))
+		| LM85_TACH_MODE_TO_REG(val,nr);
+	lm85_write_value(client, LM85_REG_TACH_MODE, data->tach_mode);
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t adm1027_show_fan_tach_mode(struct device *dev, char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", ADM1027_TACH_MODE_FROM_REG(data->tach_mode,
+		nr));
+}
+static ssize_t adm1027_set_fan_tach_mode(struct device *dev, const char *buf,
+	size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->tach_mode = (data->tach_mode & ~(0x01 << (nr + 4)))
+		| ADM1027_TACH_MODE_TO_REG(val,nr);
+	lm85_write_value(client, ADM1027_REG_CONFIG3, data->tach_mode);
+	up(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_fan_tach_mode(struct device *dev, char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	switch (data->type) {
+	case adm1027  :
+	case adt7463  :
+		return adm1027_show_fan_tach_mode(dev, buf, nr);
+		break;
+	case any_chip :
+	case lm85b    :
+	case lm85c    :
+	default       :
+		return lm85_show_fan_tach_mode(dev, buf, nr);
+	}
+}
+static ssize_t set_fan_tach_mode(struct device *dev, const char *buf,
+	size_t count, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	switch (data->type) {
+	case adm1027  :
+	case adt7463  :
+		return adm1027_set_fan_tach_mode(dev, buf, count, nr);
+		break;
+	case any_chip :
+	case lm85b    :
+	case lm85c    :
+	default       :
+		return lm85_set_fan_tach_mode(dev, buf, count, nr);
+	}
+}
+
+#define fan_tach_mode(offset)						\
+static ssize_t show_fan##offset##_tach_mode (struct device *dev,	\
+	char *buf)							\
+{									\
+	return show_fan_tach_mode(dev, buf, 0x##offset - 1);		\
+}									\
+static ssize_t set_fan##offset##_tach_mode (struct device *dev,		\
+	const char *buf, size_t count)					\
+{									\
+	return set_fan_tach_mode(dev, buf, count, 0x##offset - 1);	\
+}									\
+static DEVICE_ATTR(fan##offset##_tach_mode, S_IRUGO | S_IWUSR,		\
+		show_fan##offset##_tach_mode, 				\
+		set_fan##offset##_tach_mode)         
+
+fan_tach_mode(1);
+fan_tach_mode(2);
+fan_tach_mode(3);
+fan_tach_mode(4);
+
+/* ADM1027 PPR control */
+
+static ssize_t adm1027_show_fan_ppr(struct device *dev, char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", PPR_FROM_REG(
+		data->adm1027_fan_ppr, nr));
+}
+
+static ssize_t adm1027_set_fan_ppr(struct device *dev, const char *buf,
+	size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->adm1027_fan_ppr = ((data->adm1027_fan_ppr & 
+		~PPR_MASK(nr)) | PPR_TO_REG(val,nr));
+	lm85_write_value(client, ADM1027_REG_FAN_PPR,
+		data->adm1027_fan_ppr);
+	up(&data->update_lock);
+	return count;
+}
+
+#define adm1027_fan_ppr(offset)						\
+static ssize_t adm1027_show_fan##offset##_ppr (struct device *dev,	\
+	char *buf)							\
+{									\
+	return adm1027_show_fan_ppr(dev, buf, 0x##offset - 1);		\
+}									\
+static ssize_t adm1027_set_fan##offset##_ppr (struct device *dev,	\
+	const char *buf, size_t count)					\
+{									\
+	return adm1027_set_fan_ppr(dev, buf, count,			\
+	0x##offset - 1);						\
+}									\
+static DEVICE_ATTR(fan##offset##_ppr, S_IRUGO | S_IWUSR,		\
+		adm1027_show_fan##offset##_ppr, 			\
+		adm1027_set_fan##offset##_ppr)         
+
+adm1027_fan_ppr(1);
+adm1027_fan_ppr(2);
+adm1027_fan_ppr(3);
+adm1027_fan_ppr(4);
+
+/* ADM1027 and ADT7463 temperature offset control */
+
+static ssize_t adm1027_show_temp_offset(struct device *dev, char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	if (data->type == adm1027) {
+		return sprintf(buf,"%d\n", ADM1027_OFFSET_FROM_REG(
+			data->temp_offset[nr]));
+	}else {
+		return sprintf(buf,"%d\n", ADT7463_OFFSET_FROM_REG(
+			data->temp_offset[nr]));
+	}
+}
+
+static ssize_t adm1027_set_temp_offset(struct device *dev, const char *buf,
+	size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	if (data->type == adm1027) {
+		data->temp_offset[nr] = ADM1027_OFFSET_TO_REG(val);
+	} else {
+		data->temp_offset[nr] = ADT7463_OFFSET_TO_REG(val);
+	}
+	lm85_write_value(client, ADM1027_REG_TEMP_OFFSET(nr),
+		data->temp_offset[nr]);
+	up(&data->update_lock);
+	return count;
+}
+
+#define adm1027_temp_offset(offset)					\
+static ssize_t adm1027_show_temp##offset##_offset (struct device *dev,	\
+	char *buf)							\
+{									\
+	return adm1027_show_temp_offset(dev, buf, 0x##offset - 1);	\
+}									\
+static ssize_t adm1027_set_temp##offset##_offset (struct device *dev,	\
+	const char *buf, size_t count)					\
+{									\
+	return adm1027_set_temp_offset(dev, buf, count,			\
+	0x##offset - 1);						\
+}									\
+static DEVICE_ATTR(temp##offset##_offset, S_IRUGO | S_IWUSR,		\
+		adm1027_show_temp##offset##_offset, 			\
+		adm1027_set_temp##offset##_offset)         
+
+adm1027_temp_offset(1);
+adm1027_temp_offset(2);
+adm1027_temp_offset(3);
+
+
+/* Here come the (many) ADM1027/ADT7463 alarm mask SET and SHOW functions */
+
+static ssize_t adm1027_show_alarm_mask_2500mv(struct device *dev, 
+	char *buf)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", ALARM_MASK_FROM_REG(
+		data->intmask1, 0));
+}
+static ssize_t adm1027_set_alarm_mask_2500mv(struct device *dev, 
+	const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->intmask1 = (data->intmask1 & ~(0x01)) 
+		| ALARM_MASK_TO_REG(val,0);
+	lm85_write_value(client, ADM1027_REG_INTMASK1, data->intmask1);
+	up(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(alarm_mask_2500mv, S_IRUGO | S_IWUSR,
+		adm1027_show_alarm_mask_2500mv, adm1027_set_alarm_mask_2500mv)
+
+static ssize_t adm1027_show_alarm_mask_vccp(struct device *dev, 
+	char *buf)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", ALARM_MASK_FROM_REG(
+		data->intmask1,1));
+}
+static ssize_t adm1027_set_alarm_mask_vccp(struct device *dev, 
+	const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->intmask1 = (data->intmask1 & ~(0x02)) 
+		| ALARM_MASK_TO_REG(val,1);
+	lm85_write_value(client, ADM1027_REG_INTMASK1, data->intmask1);
+	up(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(alarm_mask_vccp, S_IRUGO | S_IWUSR,
+		adm1027_show_alarm_mask_vccp, adm1027_set_alarm_mask_vccp)         
+
+static ssize_t adm1027_show_alarm_mask_vcc(struct device *dev, 
+	char *buf)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", ALARM_MASK_FROM_REG(
+		data->intmask1,2));
+}
+static ssize_t adm1027_set_alarm_mask_vcc(struct device *dev, 
+	const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->intmask1 = (data->intmask1 & ~(0x04)) 
+		| ALARM_MASK_TO_REG(val,2);
+	lm85_write_value(client, ADM1027_REG_INTMASK1, data->intmask1);
+	up(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(alarm_mask_vcc, S_IRUGO | S_IWUSR,
+		adm1027_show_alarm_mask_vcc, adm1027_set_alarm_mask_vcc)         
+
+static ssize_t adm1027_show_alarm_mask_5000mv(struct device *dev, 
+	char *buf)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", ALARM_MASK_FROM_REG(
+		data->intmask1,3));
+}
+static ssize_t adm1027_set_alarm_mask_5000mv(struct device *dev, 
+	const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->intmask1 = (data->intmask1 & ~(0x08)) 
+		| ALARM_MASK_TO_REG(val,3);
+	lm85_write_value(client, ADM1027_REG_INTMASK1, data->intmask1);
+	up(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(alarm_mask_5000mv, S_IRUGO | S_IWUSR,
+		adm1027_show_alarm_mask_5000mv, adm1027_set_alarm_mask_5000mv)         
+
+static ssize_t adm1027_show_alarm_mask_temp(struct device *dev, 
+	char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", ALARM_MASK_FROM_REG(
+		data->intmask1,(4+nr)));
+}
+static ssize_t adm1027_set_alarm_mask_temp(struct device *dev, 
+	const char *buf, size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int    val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	switch (nr) {
+	case 1 :
+		data->intmask1 = (data->intmask1 & ~0x10) 
+			| ALARM_MASK_TO_REG(val,(4 + nr));
+		break;
+	case 2 :
+		data->intmask1 = (data->intmask1 & ~0x20) 
+			| ALARM_MASK_TO_REG(val,(4 + nr));
+		break;
+	case 3 :
+		data->intmask1 = (data->intmask1 & ~0x40) 
+			| ALARM_MASK_TO_REG(val,(4 + nr));
+	}
+	lm85_write_value(client, ADM1027_REG_INTMASK1, data->intmask1);
+	up(&data->update_lock);
+	return count;
+}
+
+#define adm1027_alarm_mask_temp(offset)					\
+static ssize_t adm1027_show_alarm_mask_temp##offset (			\
+	struct device *dev, char *buf)					\
+{									\
+	return adm1027_show_alarm_mask_temp(dev, buf, 0x##offset - 1);	\
+}									\
+static ssize_t adm1027_set_alarm_mask_temp##offset (struct device *dev,	\
+	const char *buf, size_t count)					\
+{									\
+	return adm1027_set_alarm_mask_temp(dev, buf, count,		\
+	0x##offset - 1);						\
+}									\
+static DEVICE_ATTR(alarm_mask_temp##offset, S_IRUGO | S_IWUSR,		\
+		adm1027_show_alarm_mask_temp##offset, 			\
+		adm1027_set_alarm_mask_temp##offset)         
+
+adm1027_alarm_mask_temp(1);
+adm1027_alarm_mask_temp(2);
+adm1027_alarm_mask_temp(3);
+
+static ssize_t adm1027_show_alarm_mask_12000mv(struct device *dev, 
+	char *buf)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", ALARM_MASK_FROM_REG(
+		data->intmask2,0));
+}
+
+static ssize_t adm1027_set_alarm_mask_12000mv(struct device *dev, 
+	const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->intmask1 = data->intmask1 | 0x80;
+	data->intmask2 = (data->intmask2 & ~(0x01)) 
+		| ALARM_MASK_TO_REG(val,0);
+	lm85_write_value(client, ADM1027_REG_INTMASK1, data->intmask1);
+	lm85_write_value(client, ADM1027_REG_INTMASK2, data->intmask2);
+	up(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(alarm_mask_12000mv, S_IRUGO | S_IWUSR,
+		adm1027_show_alarm_mask_12000mv, adm1027_set_alarm_mask_12000mv)         
+
+static ssize_t adm1027_show_alarm_mask_therm(struct device *dev, 
+	char *buf)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", ALARM_MASK_FROM_REG(
+		data->intmask2,1));
+}
+static ssize_t adm1027_set_alarm_mask_therm(struct device *dev, 
+	const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int     val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	data->intmask1 = data->intmask1 | 0x80;
+	data->intmask2 = (data->intmask2 & ~(0x02)) 
+		| ALARM_MASK_TO_REG(val,1);
+	lm85_write_value(client, ADM1027_REG_INTMASK1, data->intmask1);
+	lm85_write_value(client, ADM1027_REG_INTMASK2, data->intmask2);
+	up(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(alarm_mask_therm, S_IRUGO | S_IWUSR,
+		adm1027_show_alarm_mask_therm, adm1027_set_alarm_mask_therm)         
+static ssize_t adm1027_show_alarm_mask_fan(struct device *dev, 
+	char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", ALARM_MASK_FROM_REG(
+		data->intmask2,(2+nr)));
+}
+static ssize_t adm1027_set_alarm_mask_fan(struct device *dev, 
+	const char *buf, size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int    val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	switch (nr) {
+	case 1 :
+	data->intmask2 = (data->intmask2 & ~0x04) 
+		| ALARM_MASK_TO_REG(val,(2+nr));
+		break;
+	case 2 :
+	data->intmask2 = (data->intmask2 & ~0x08) 
+		| ALARM_MASK_TO_REG(val,(2+nr));
+		break;
+	case 3 :
+	data->intmask2 = (data->intmask2 & ~0x10) 
+		| ALARM_MASK_TO_REG(val,(2+nr));
+		break;
+	case 4 :
+	data->intmask2 = (data->intmask2 & ~0x20) 
+		| ALARM_MASK_TO_REG(val,(2+nr));
+	}
+	data->intmask1 = data->intmask1 | 0x80;
+	lm85_write_value(client, ADM1027_REG_INTMASK1, data->intmask1);
+	lm85_write_value(client, ADM1027_REG_INTMASK2, data->intmask2);
+	up(&data->update_lock);
+	return count;
+}
+
+#define adm1027_alarm_mask_fan(offset)					\
+static ssize_t adm1027_show_alarm_mask_fan##offset (struct device *dev,	\
+	char *buf)							\
+{									\
+	return adm1027_show_alarm_mask_fan(dev, buf, 0x##offset - 1);	\
+}									\
+static ssize_t adm1027_set_alarm_mask_fan##offset (struct device *dev,	\
+	const char *buf, size_t count)					\
+{									\
+	return adm1027_set_alarm_mask_fan(dev, buf, count,		\
+	0x##offset - 1);						\
+}									\
+static DEVICE_ATTR(alarm_mask_fan##offset, S_IRUGO | S_IWUSR,		\
+		adm1027_show_alarm_mask_fan##offset, 			\
+		adm1027_set_alarm_mask_fan##offset)         
+
+adm1027_alarm_mask_fan(1);
+adm1027_alarm_mask_fan(2);
+adm1027_alarm_mask_fan(3);
+adm1027_alarm_mask_fan(4);
+
+
+static ssize_t adm1027_show_alarm_mask_remote_elec(struct device *dev, 
+	char *buf, int nr)
+{
+	struct lm85_data *data = lm85_update_device(dev);
+	return sprintf(buf,"%d\n", ALARM_MASK_FROM_REG(
+		data->intmask2,(6+nr)));
+}
+
+static ssize_t adm1027_set_alarm_mask_remote_elec(struct device *dev, 
+	const char *buf, size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm85_data *data = i2c_get_clientdata(client);
+	int    val;
+
+	down(&data->update_lock);
+	val = simple_strtol(buf, NULL, 10);
+	switch (nr) {
+	case 1 :
+		data->intmask2 = (data->intmask2 & ~0x40) 
+			| ALARM_MASK_TO_REG(val,(6+nr));
+		break;
+	case 2 :
+		data->intmask2 = (data->intmask2 & ~0x80) 
+			| ALARM_MASK_TO_REG(val,(6+nr));
+		break;
+	}
+	data->intmask1 = data->intmask1 | 0x80; 
+	lm85_write_value(client, ADM1027_REG_INTMASK1, data->intmask1);
+	lm85_write_value(client, ADM1027_REG_INTMASK2, data->intmask2);
+	up(&data->update_lock);
+	return count;
+}
+
+#define adm1027_alarm_mask_remote_elec(offset)				\
+static ssize_t adm1027_show_alarm_mask_remote##offset##_elec (		\
+	struct device *dev, char *buf)					\
+{									\
+	return adm1027_show_alarm_mask_remote_elec(dev, buf,		\
+		0x##offset - 1);					\
+}									\
+static ssize_t adm1027_set_alarm_mask_remote##offset##_elec (		\
+	struct device *dev, const char *buf, size_t count)		\
+{									\
+	return adm1027_set_alarm_mask_remote_elec(dev, buf, count,	\
+	0x##offset - 1);						\
+}									\
+static DEVICE_ATTR(alarm_mask_remote##offset##_elec, S_IRUGO | S_IWUSR,	\
+		adm1027_show_alarm_mask_remote##offset##_elec, 		\
+		adm1027_set_alarm_mask_remote##offset##_elec)         
+
+adm1027_alarm_mask_remote_elec(1);
+adm1027_alarm_mask_remote_elec(2);
+
+
+int lm85_attach_adapter(struct i2c_adapter *adapter)
+{
+	return i2c_detect(adapter, &addr_data, lm85_detect);
+}
+
+int lm85_detect(struct i2c_adapter *adapter, int address,
+		int kind)
+{
+	int company, verstep ;
+	struct i2c_client *new_client = NULL;
+	struct lm85_data *data;
+	int err = 0;
+	const char *type_name = "";
+
+	if (i2c_is_isa_adapter(adapter)) {
+		/* This chip has no ISA interface */
+		goto ERROR0 ;
+	};
+
+	if (!i2c_check_functionality(adapter,
+					I2C_FUNC_SMBUS_BYTE_DATA)) {
+		/* We need to be able to do byte I/O */
+		goto ERROR0 ;
+	};
+
+	/* OK. For now, we presume we have a valid client. We now create the
+	   client structure, even though we cannot fill it completely yet.
+	   But it allows us to access lm85_{read,write}_value. */
+
+	if (!(data = kmalloc(sizeof(struct lm85_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto ERROR0;
+	}
+	memset(data, 0, sizeof(struct lm85_data));
+
+	new_client = &data->client;
+	i2c_set_clientdata(new_client, data);
+	new_client->addr = address;
+	new_client->adapter = adapter;
+	new_client->driver = &lm85_driver;
+	new_client->flags = 0;
+
+	/* Now, we do the remaining detection. */
+
+	company = lm85_read_value(new_client, LM85_REG_COMPANY);
+	verstep = lm85_read_value(new_client, LM85_REG_VERSTEP);
+
+	dev_dbg(&adapter->dev, "Detecting device at %d,0x%02x with"
+		" COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
+		i2c_adapter_id(new_client->adapter), new_client->addr,
+		company, verstep);
+
+	/* If auto-detecting, Determine the chip type. */
+	if (kind <= 0) {
+		dev_dbg(&adapter->dev, "Autodetecting device at %d,0x%02x ...\n",
+			i2c_adapter_id(adapter), address );
+		if( company == LM85_COMPANY_NATIONAL
+		    && verstep == LM85_VERSTEP_LM85C ) {
+			kind = lm85c ;
+		} else if( company == LM85_COMPANY_NATIONAL
+		    && verstep == LM85_VERSTEP_LM85B ) {
+			kind = lm85b ;
+		} else if( company == LM85_COMPANY_NATIONAL
+		    && (verstep & 0xf0) == LM85_VERSTEP_GENERIC ) {
+			dev_err(&adapter->dev, "Unrecognized version/stepping 0x%02x"
+				" Defaulting to LM85.\n", verstep);
+			kind = any_chip ;
+		} else if( company == LM85_COMPANY_ANALOG_DEV
+		    && verstep == LM85_VERSTEP_ADM1027 ) {
+			kind = adm1027 ;
+		} else if( company == LM85_COMPANY_ANALOG_DEV
+		    && verstep == LM85_VERSTEP_ADT7463 ) {
+			kind = adt7463 ;
+		} else if( company == LM85_COMPANY_ANALOG_DEV
+		    && (verstep & 0xf0) == LM85_VERSTEP_GENERIC ) {
+			dev_err(&adapter->dev, "Unrecognized version/stepping 0x%02x"
+				" Defaulting to ADM1027.\n", verstep);
+			kind = adm1027 ;
+		} else if( kind == 0 && (verstep & 0xf0) == 0x60) {
+			dev_err(&adapter->dev, "Generic LM85 Version 6 detected\n");
+			/* Leave kind as "any_chip" */
+		} else {
+			dev_dbg(&adapter->dev, "Autodetection failed\n");
+			/* Not an LM85 ... */
+			if( kind == 0 ) {  /* User used force=x,y */
+				dev_err(&adapter->dev, "Generic LM85 Version 6 not"
+					" found at %d,0x%02x. Try force_lm85c.\n",
+					i2c_adapter_id(adapter), address );
+			}
+			err = 0 ;
+			goto ERROR1;
+		}
+	}
+
+	/* Fill in the chip specific driver values */
+	if ( kind == any_chip ) {
+		type_name = "lm85";
+	} else if ( kind == lm85b ) {
+	} else if ( kind == lm85c ) {
+		type_name = "lm85c";
+	} else if ( kind == adm1027 ) {
+		type_name = "adm1027";
+	} else if ( kind == adt7463 ) {
+		type_name = "adt7463";
+	}
+	strlcpy(new_client->name, type_name, I2C_NAME_SIZE);
+
+	/* Fill in the remaining client fields */
+	new_client->id = lm85_id++;
+	data->type = kind;
+	data->valid = 0;
+	init_MUTEX(&data->update_lock);
+
+	dev_dbg(&adapter->dev, "Assigning ID %d to %s at %d,0x%02x\n",
+		new_client->id, new_client->name,
+		i2c_adapter_id(new_client->adapter),
+		new_client->addr);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -851,9 +2198,6 @@
 	device_create_file(&new_client->dev, &dev_attr_fan1_pwm);
 	device_create_file(&new_client->dev, &dev_attr_fan2_pwm);
 	device_create_file(&new_client->dev, &dev_attr_fan3_pwm);
-	device_create_file(&new_client->dev, &dev_attr_fan1_pwm_enable);
-	device_create_file(&new_client->dev, &dev_attr_fan2_pwm_enable);
-	device_create_file(&new_client->dev, &dev_attr_fan3_pwm_enable);
 	device_create_file(&new_client->dev, &dev_attr_in0_input);
 	device_create_file(&new_client->dev, &dev_attr_in1_input);
 	device_create_file(&new_client->dev, &dev_attr_in2_input);
@@ -882,11 +2226,144 @@
 	device_create_file(&new_client->dev, &dev_attr_in0_ref);
 	device_create_file(&new_client->dev, &dev_attr_alarms);
 
+/* Autofan, Zone/temp_auto, spinup, and smoothing entries */
+
+	device_create_file(&new_client->dev, &dev_attr_fan1_auto);
+	device_create_file(&new_client->dev, &dev_attr_fan2_auto);
+	device_create_file(&new_client->dev, &dev_attr_fan3_auto);
+	device_create_file(&new_client->dev, &dev_attr_fan1_auto_spinup);
+	device_create_file(&new_client->dev, &dev_attr_fan2_auto_spinup);
+	device_create_file(&new_client->dev, &dev_attr_fan3_auto_spinup);
+	device_create_file(&new_client->dev, &dev_attr_fan1_auto_zone);
+	device_create_file(&new_client->dev, &dev_attr_fan2_auto_zone);
+	device_create_file(&new_client->dev, &dev_attr_fan3_auto_zone);
+	device_create_file(&new_client->dev, &dev_attr_fan1_auto_invert);
+	device_create_file(&new_client->dev, &dev_attr_fan2_auto_invert);
+	device_create_file(&new_client->dev, &dev_attr_fan3_auto_invert); 
+	device_create_file(&new_client->dev, &dev_attr_fan1_auto_freq);
+	device_create_file(&new_client->dev, &dev_attr_fan2_auto_freq);
+	device_create_file(&new_client->dev, &dev_attr_fan3_auto_freq);
+	device_create_file(&new_client->dev, &dev_attr_fan1_auto_min_pwm);
+	device_create_file(&new_client->dev, &dev_attr_fan2_auto_min_pwm);
+	device_create_file(&new_client->dev, &dev_attr_fan3_auto_min_pwm);
+	device_create_file(&new_client->dev, &dev_attr_fan1_auto_min_ctl);
+	device_create_file(&new_client->dev, &dev_attr_fan2_auto_min_ctl);
+	device_create_file(&new_client->dev, &dev_attr_fan3_auto_min_ctl);
+	device_create_file(&new_client->dev, &dev_attr_temp1_auto_min);
+	device_create_file(&new_client->dev, &dev_attr_temp2_auto_min);
+	device_create_file(&new_client->dev, &dev_attr_temp3_auto_min);
+	device_create_file(&new_client->dev, &dev_attr_temp1_auto_max);
+	device_create_file(&new_client->dev, &dev_attr_temp2_auto_max);
+	device_create_file(&new_client->dev, &dev_attr_temp3_auto_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_auto_off);
+	device_create_file(&new_client->dev, &dev_attr_temp2_auto_off);
+	device_create_file(&new_client->dev, &dev_attr_temp3_auto_off);  
+	device_create_file(&new_client->dev, &dev_attr_temp1_auto_critical);
+	device_create_file(&new_client->dev, &dev_attr_temp2_auto_critical);
+	device_create_file(&new_client->dev, &dev_attr_temp3_auto_critical);
+	device_create_file(&new_client->dev, &dev_attr_temp1_auto_smooth);
+	device_create_file(&new_client->dev, &dev_attr_temp2_auto_smooth);
+	device_create_file(&new_client->dev, &dev_attr_temp3_auto_smooth);
+	device_create_file(&new_client->dev, &dev_attr_fan1_tach_mode);
+	device_create_file(&new_client->dev, &dev_attr_fan2_tach_mode);
+	device_create_file(&new_client->dev, &dev_attr_fan3_tach_mode);
+
+/* chip variant-specific entries */
+
+	switch (data->type) {
+	case adt7463 :
+		device_create_file(&new_client->dev,
+			&dev_attr_temp1_auto_oppoint);
+		device_create_file(&new_client->dev,
+			&dev_attr_temp2_auto_oppoint);
+		device_create_file(&new_client->dev,
+			&dev_attr_temp3_auto_oppoint);
+		device_create_file(&new_client->dev,
+			&dev_attr_temp1_auto_dynamic_tmin_ctl);
+		device_create_file(&new_client->dev,
+			&dev_attr_temp2_auto_dynamic_tmin_ctl);
+		device_create_file(&new_client->dev,
+			&dev_attr_temp3_auto_dynamic_tmin_ctl);
+		device_create_file(&new_client->dev, &dev_attr_fan4_tach_mode);
+		device_create_file(&new_client->dev, 
+			&dev_attr_fan_auto_spinup_ctl); 
+		device_create_file(&new_client->dev, &dev_attr_therm_limit);
+		device_create_file(&new_client->dev, &dev_attr_therm_total);
+		device_create_file(&new_client->dev, &dev_attr_fan1_ppr);
+		device_create_file(&new_client->dev, &dev_attr_fan2_ppr);
+		device_create_file(&new_client->dev, &dev_attr_fan3_ppr);
+		device_create_file(&new_client->dev, &dev_attr_fan4_ppr);
+		device_create_file(&new_client->dev, &dev_attr_temp1_offset);
+		device_create_file(&new_client->dev, &dev_attr_temp2_offset);
+		device_create_file(&new_client->dev, &dev_attr_temp3_offset);
+		device_create_file(&new_client->dev,
+			&dev_attr_alarm_mask_2500mv);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_vccp);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_vcc);
+		device_create_file(&new_client->dev,
+			&dev_attr_alarm_mask_5000mv);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_temp1);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_temp2);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_temp3);
+		device_create_file(&new_client->dev,
+			&dev_attr_alarm_mask_12000mv);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_therm);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_fan1);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_fan2);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_fan3);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_fan4);
+		device_create_file(&new_client->dev,
+			&dev_attr_alarm_mask_remote1_elec);
+		device_create_file(&new_client->dev,
+			&dev_attr_alarm_mask_remote2_elec);
+		break;
+	case adm1027 :
+		device_create_file(&new_client->dev, &dev_attr_fan4_tach_mode);
+		device_create_file(&new_client->dev, 
+			&dev_attr_fan_auto_spinup_ctl);
+		device_create_file(&new_client->dev, &dev_attr_fan1_ppr);
+		device_create_file(&new_client->dev, &dev_attr_fan2_ppr);
+		device_create_file(&new_client->dev, &dev_attr_fan3_ppr);
+		device_create_file(&new_client->dev, &dev_attr_fan4_ppr);
+		device_create_file(&new_client->dev, &dev_attr_temp1_offset);
+		device_create_file(&new_client->dev, &dev_attr_temp2_offset);
+		device_create_file(&new_client->dev, &dev_attr_temp3_offset);
+		device_create_file(&new_client->dev,
+			&dev_attr_alarm_mask_2500mv);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_vccp);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_vcc);
+		device_create_file(&new_client->dev,
+			&dev_attr_alarm_mask_5000mv);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_temp1);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_temp2);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_temp3);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_12000mv);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_therm);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_fan1);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_fan2);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_fan3);
+		device_create_file(&new_client->dev, &dev_attr_alarm_mask_fan4);
+		device_create_file(&new_client->dev,
+			&dev_attr_alarm_mask_remote1_elec);
+		device_create_file(&new_client->dev,
+			&dev_attr_alarm_mask_remote2_elec);
+		break;
+	case lm85c :
+	case lm85b :
+	case any_chip :
+	default :
+		device_create_file(&new_client->dev, 
+			&dev_attr_fan1_auto_spinup_ctl);
+		device_create_file(&new_client->dev, 
+			&dev_attr_fan2_auto_spinup_ctl);
+		device_create_file(&new_client->dev, 
+			&dev_attr_fan3_auto_spinup_ctl);
+	}
 	return 0;
 
 	/* Error out and cleanup code */
     ERROR1:
-	kfree(new_client);
+	kfree(data);
     ERROR0:
 	return err;
 }
@@ -894,7 +2371,7 @@
 int lm85_detach_client(struct i2c_client *client)
 {
 	i2c_detach_client(client);
-	kfree(client);
+	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
@@ -915,19 +2392,19 @@
 	case LM85_REG_FAN_MIN(3) :
 	case LM85_REG_ALARM1 :	/* Read both bytes at once */
 	case ADM1027_REG_EXTEND_ADC1 :  /* Read two bytes at once */
-		res = i2c_smbus_read_byte_data(client, reg) & 0xff ;
-		res |= i2c_smbus_read_byte_data(client, reg+1) << 8 ;
-		break ;
+		res = i2c_smbus_read_byte_data(client, reg) & 0xff;
+		res |= i2c_smbus_read_byte_data(client, reg+1) << 8;
+		break;
 	case ADT7463_REG_TMIN_CTL1 :  /* Read WORD MSB, LSB */
-		res = i2c_smbus_read_byte_data(client, reg) << 8 ;
-		res |= i2c_smbus_read_byte_data(client, reg+1) & 0xff ;
-		break ;
+		res = i2c_smbus_read_byte_data(client, reg) << 8;
+		res |= i2c_smbus_read_byte_data(client, reg+1) & 0xff;
+		break;
 	default:	/* Read BYTE data */
 		res = i2c_smbus_read_byte_data(client, reg);
-		break ;
+		break;
 	}
 
-	return res ;
+	return res;
 }
 
 int lm85_write_value(struct i2c_client *client, u8 reg, int value)
@@ -944,19 +2421,21 @@
 	case LM85_REG_FAN_MIN(2) :
 	case LM85_REG_FAN_MIN(3) :
 	/* NOTE: ALARM is read only, so not included here */
-		res = i2c_smbus_write_byte_data(client, reg, value & 0xff) ;
-		res |= i2c_smbus_write_byte_data(client, reg+1, (value>>8) & 0xff) ;
-		break ;
+		res = i2c_smbus_write_byte_data(client, reg, value & 0xff);
+		res |= i2c_smbus_write_byte_data(client, reg+1, 
+			(value>>8) & 0xff);
+		break;
 	case ADT7463_REG_TMIN_CTL1 :  /* Write WORD MSB, LSB */
-		res = i2c_smbus_write_byte_data(client, reg, (value>>8) & 0xff);
-		res |= i2c_smbus_write_byte_data(client, reg+1, value & 0xff) ;
+		res = i2c_smbus_write_byte_data(client, reg,
+			(value>>8) & 0xff);
+		res |= i2c_smbus_write_byte_data(client, reg+1, value & 0xff);
 		break ;
 	default:	/* Write BYTE data */
 		res = i2c_smbus_write_byte_data(client, reg, value);
-		break ;
+		break;
 	}
 
-	return res ;
+	return res;
 }
 
 void lm85_init_client(struct i2c_client *client)
@@ -971,18 +2450,18 @@
 	dev_dbg(&client->dev, "LM85_REG_CONFIG is: 0x%02x\n", value);
 	if( value & 0x02 ) {
 		dev_err(&client->dev, "Client (%d,0x%02x) config is locked.\n",
-			    i2c_adapter_id(client->adapter), client->addr );
+			i2c_adapter_id(client->adapter), client->addr );
 	};
-	if( ! (value & 0x04) ) {
+	if ( ! (value & 0x04) ) {
 		dev_err(&client->dev, "Client (%d,0x%02x) is not ready.\n",
-			    i2c_adapter_id(client->adapter), client->addr );
+			i2c_adapter_id(client->adapter), client->addr );
 	};
-	if( value & 0x10
-	    && ( data->type == adm1027
+	if ( value & 0x10 && ( data->type == adm1027 
 		|| data->type == adt7463 ) ) {
-		dev_err(&client->dev, "Client (%d,0x%02x) VxI mode is set.  "
+			dev_err(&client->dev, 
+			"Client (%d,0x%02x) VxI mode is set.  "
 			"Please report this to the lm85 maintainer.\n",
-			    i2c_adapter_id(client->adapter), client->addr );
+			i2c_adapter_id(client->adapter), client->addr );
 	};
 
 	/* WE INTENTIONALLY make no changes to the limits,
@@ -1018,8 +2497,8 @@
 		 * more significant bits that are read later.
 		 */
 		if ( (data->type == adm1027) || (data->type == adt7463) ) {
-			data->extend_adc =
-			    lm85_read_value(client, ADM1027_REG_EXTEND_ADC1);
+			data->extend_adc = lm85_read_value(client, 
+				ADM1027_REG_EXTEND_ADC1);
 		}
 
 		for (i = 0; i <= 4; ++i) {
@@ -1043,9 +2522,10 @@
 		}
 
 		if ( data->type == adt7463 ) {
-			if( data->therm_total < ULONG_MAX - 256 ) {
-			    data->therm_total +=
-				lm85_read_value(client, ADT7463_REG_THERM );
+			if ( data->adt7463_therm_total < ULONG_MAX - 256 ) {
+				data->adt7463_therm_total += 
+					lm85_read_value(client, 
+					ADT7463_REG_THERM);
 			}
 		}
 
@@ -1061,71 +2541,77 @@
 
 		for (i = 0; i <= 4; ++i) {
 			data->in_min[i] =
-			    lm85_read_value(client, LM85_REG_IN_MIN(i));
+				lm85_read_value(client, LM85_REG_IN_MIN(i));
 			data->in_max[i] =
-			    lm85_read_value(client, LM85_REG_IN_MAX(i));
+				lm85_read_value(client, LM85_REG_IN_MAX(i));
 		}
 
 		for (i = 0; i <= 3; ++i) {
 			data->fan_min[i] =
-			    lm85_read_value(client, LM85_REG_FAN_MIN(i));
+				lm85_read_value(client, LM85_REG_FAN_MIN(i));
 		}
 
 		for (i = 0; i <= 2; ++i) {
 			data->temp_min[i] =
-			    lm85_read_value(client, LM85_REG_TEMP_MIN(i));
+				lm85_read_value(client, LM85_REG_TEMP_MIN(i));
 			data->temp_max[i] =
-			    lm85_read_value(client, LM85_REG_TEMP_MAX(i));
+				lm85_read_value(client, LM85_REG_TEMP_MAX(i));
 		}
 
 		data->vid = lm85_read_value(client, LM85_REG_VID);
 
 		for (i = 0; i <= 2; ++i) {
 			int val ;
-			data->autofan[i].config =
-			    lm85_read_value(client, LM85_REG_AFAN_CONFIG(i));
+			data->fan_auto_config[i] = lm85_read_value(client,
+				LM85_REG_AFAN_CONFIG(i));
 			val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i));
-			data->autofan[i].freq = val & 0x07 ;
-			data->zone[i].range = (val >> 4) & 0x0f ;
-			data->autofan[i].min_pwm =
-			    lm85_read_value(client, LM85_REG_AFAN_MINPWM(i));
-			data->zone[i].limit =
-			    lm85_read_value(client, LM85_REG_AFAN_LIMIT(i));
-			data->zone[i].critical =
-			    lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i));
+			data->fan_auto_freq[i] = val & 0x07 ;
+                        data->temp_auto_range[i] = (val >> 4) & 0x0f;
+                        data->temp_auto_min[i] = lm85_read_value(client, 
+				LM85_REG_AFAN_LIMIT(i)); 
+			data->temp_auto_critical[i] = lm85_read_value(client, 
+				LM85_REG_AFAN_CRITICAL(i));
+                        data->fan_auto_min_pwm[i] = lm85_read_value(client, 
+				LM85_REG_AFAN_MINPWM(i));
 		}
 
 		i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1);
 		data->smooth[0] = i & 0x0f ;
 		data->syncpwm3 = i & 0x10 ;  /* Save PWM3 config */
-		data->autofan[0].min_off = (i & 0x20) != 0 ;
-		data->autofan[1].min_off = (i & 0x40) != 0 ;
-		data->autofan[2].min_off = (i & 0x80) != 0 ;
+		data->fan_auto_min_ctl[0] = (i & 0x20) != 0 ;
+		data->fan_auto_min_ctl[1] = (i & 0x40) != 0 ;
+		data->fan_auto_min_ctl[2] = (i & 0x80) != 0 ;
 		i = lm85_read_value(client, LM85_REG_AFAN_SPIKE2);
 		data->smooth[1] = (i>>4) & 0x0f ;
 		data->smooth[2] = i & 0x0f ;
 
-		i = lm85_read_value(client, LM85_REG_AFAN_HYST1);
-		data->zone[0].hyst = (i>>4) & 0x0f ;
-		data->zone[1].hyst = i & 0x0f ;
-
+		i = lm85_read_value(client, LM85_REG_AFAN_HYST1) ;
+		data->temp_auto_hyst[0] = (i>>4)  & 0x0f ;
+		data->temp_auto_hyst[1] = i & 0x0f ;
 		i = lm85_read_value(client, LM85_REG_AFAN_HYST2);
-		data->zone[2].hyst = (i>>4) & 0x0f ;
-
+		data->temp_auto_hyst[2] = (i>>4)  & 0x0f ;
+		data->config1 = lm85_read_value(client, LM85_REG_CONFIG);
 		if ( (data->type == lm85b) || (data->type == lm85c) ) {
 			data->tach_mode = lm85_read_value(client,
 				LM85_REG_TACH_MODE );
-			data->spinup_ctl = lm85_read_value(client,
+			data->fan_auto_spinup_ctl = lm85_read_value(client,
 				LM85_REG_SPINUP_CTL );
 		} else if ( (data->type == adt7463) || (data->type == adm1027) ) {
+			data->intmask1 = lm85_read_value(client, 
+				ADM1027_REG_INTMASK1);
+			data->intmask2 = lm85_read_value(client, 
+				ADM1027_REG_INTMASK2);
+			data->fan_auto_spinup_ctl = data->config1 & 0x20;
 			if ( data->type == adt7463 ) {
 				for (i = 0; i <= 2; ++i) {
-				    data->oppoint[i] = lm85_read_value(client,
+				    data->temp_auto_oppoint[i] = 
+					lm85_read_value(client,
 					ADT7463_REG_OPPOINT(i) );
 				}
 				data->tmin_ctl = lm85_read_value(client,
 					ADT7463_REG_TMIN_CTL1 );
-				data->therm_limit = lm85_read_value(client,
+				data->adt7463_therm_limit = 
+					lm85_read_value(client,
 					ADT7463_REG_THERM_LIMIT );
 			}
 			for (i = 0; i <= 2; ++i) {
@@ -1134,7 +2620,7 @@
 			}
 			data->tach_mode = lm85_read_value(client,
 				ADM1027_REG_CONFIG3 );
-			data->fan_ppr = lm85_read_value(client,
+			data->adm1027_fan_ppr = lm85_read_value(client,
 				ADM1027_REG_FAN_PPR );
 		}
 	
@@ -1164,7 +2650,7 @@
  *     post 2.7.0 CVS changes.
  */
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Philip Pokorny <ppokorny at penguincomputing.com>, Margit Schubert-While <margitsw at t-online.de>");
+MODULE_AUTHOR("Philip Pokorny <ppokorny at penguincomputing.com>, Margit Schubert-While <margitsw at t-online.de>, Justin Thiessen <jthiessen at penguincomputing.com>");
 MODULE_DESCRIPTION("LM85-B, LM85-C driver");
 
 module_init(sm_lm85_init);




[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux