xref: /openbmc/linux/drivers/hwmon/via686a.c (revision 943b0830cebe4711354945ed3cb44e84152aaca0)
18d5d45fbSJean Delvare /*
28d5d45fbSJean Delvare     via686a.c - Part of lm_sensors, Linux kernel modules
38d5d45fbSJean Delvare 		for hardware monitoring
48d5d45fbSJean Delvare 
58d5d45fbSJean Delvare     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
68d5d45fbSJean Delvare 			Ky�sti M�lkki <kmalkki@cc.hut.fi>,
78d5d45fbSJean Delvare 			Mark Studebaker <mdsxyz123@yahoo.com>,
88d5d45fbSJean Delvare 			and Bob Dougherty <bobd@stanford.edu>
98d5d45fbSJean Delvare     (Some conversion-factor data were contributed by Jonathan Teh Soon Yew
108d5d45fbSJean Delvare     <j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.)
118d5d45fbSJean Delvare 
128d5d45fbSJean Delvare     This program is free software; you can redistribute it and/or modify
138d5d45fbSJean Delvare     it under the terms of the GNU General Public License as published by
148d5d45fbSJean Delvare     the Free Software Foundation; either version 2 of the License, or
158d5d45fbSJean Delvare     (at your option) any later version.
168d5d45fbSJean Delvare 
178d5d45fbSJean Delvare     This program is distributed in the hope that it will be useful,
188d5d45fbSJean Delvare     but WITHOUT ANY WARRANTY; without even the implied warranty of
198d5d45fbSJean Delvare     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
208d5d45fbSJean Delvare     GNU General Public License for more details.
218d5d45fbSJean Delvare 
228d5d45fbSJean Delvare     You should have received a copy of the GNU General Public License
238d5d45fbSJean Delvare     along with this program; if not, write to the Free Software
248d5d45fbSJean Delvare     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
258d5d45fbSJean Delvare */
268d5d45fbSJean Delvare 
278d5d45fbSJean Delvare /*
288d5d45fbSJean Delvare     Supports the Via VT82C686A, VT82C686B south bridges.
298d5d45fbSJean Delvare     Reports all as a 686A.
308d5d45fbSJean Delvare     Warning - only supports a single device.
318d5d45fbSJean Delvare */
328d5d45fbSJean Delvare 
338d5d45fbSJean Delvare #include <linux/module.h>
348d5d45fbSJean Delvare #include <linux/slab.h>
358d5d45fbSJean Delvare #include <linux/pci.h>
368d5d45fbSJean Delvare #include <linux/jiffies.h>
378d5d45fbSJean Delvare #include <linux/i2c.h>
388d5d45fbSJean Delvare #include <linux/i2c-sensor.h>
39*943b0830SMark M. Hoffman #include <linux/hwmon.h>
40*943b0830SMark M. Hoffman #include <linux/err.h>
418d5d45fbSJean Delvare #include <linux/init.h>
428d5d45fbSJean Delvare #include <asm/io.h>
438d5d45fbSJean Delvare 
448d5d45fbSJean Delvare 
458d5d45fbSJean Delvare /* If force_addr is set to anything different from 0, we forcibly enable
468d5d45fbSJean Delvare    the device at the given address. */
478d5d45fbSJean Delvare static unsigned short force_addr = 0;
488d5d45fbSJean Delvare module_param(force_addr, ushort, 0);
498d5d45fbSJean Delvare MODULE_PARM_DESC(force_addr,
508d5d45fbSJean Delvare 		 "Initialize the base address of the sensors");
518d5d45fbSJean Delvare 
528d5d45fbSJean Delvare /* Addresses to scan.
538d5d45fbSJean Delvare    Note that we can't determine the ISA address until we have initialized
548d5d45fbSJean Delvare    our module */
558d5d45fbSJean Delvare static unsigned short normal_i2c[] = { I2C_CLIENT_END };
568d5d45fbSJean Delvare static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
578d5d45fbSJean Delvare 
588d5d45fbSJean Delvare /* Insmod parameters */
598d5d45fbSJean Delvare SENSORS_INSMOD_1(via686a);
608d5d45fbSJean Delvare 
618d5d45fbSJean Delvare /*
628d5d45fbSJean Delvare    The Via 686a southbridge has a LM78-like chip integrated on the same IC.
638d5d45fbSJean Delvare    This driver is a customized copy of lm78.c
648d5d45fbSJean Delvare */
658d5d45fbSJean Delvare 
668d5d45fbSJean Delvare /* Many VIA686A constants specified below */
678d5d45fbSJean Delvare 
688d5d45fbSJean Delvare /* Length of ISA address segment */
698d5d45fbSJean Delvare #define VIA686A_EXTENT		0x80
708d5d45fbSJean Delvare #define VIA686A_BASE_REG	0x70
718d5d45fbSJean Delvare #define VIA686A_ENABLE_REG	0x74
728d5d45fbSJean Delvare 
738d5d45fbSJean Delvare /* The VIA686A registers */
748d5d45fbSJean Delvare /* ins numbered 0-4 */
758d5d45fbSJean Delvare #define VIA686A_REG_IN_MAX(nr)	(0x2b + ((nr) * 2))
768d5d45fbSJean Delvare #define VIA686A_REG_IN_MIN(nr)	(0x2c + ((nr) * 2))
778d5d45fbSJean Delvare #define VIA686A_REG_IN(nr)	(0x22 + (nr))
788d5d45fbSJean Delvare 
798d5d45fbSJean Delvare /* fans numbered 1-2 */
808d5d45fbSJean Delvare #define VIA686A_REG_FAN_MIN(nr)	(0x3a + (nr))
818d5d45fbSJean Delvare #define VIA686A_REG_FAN(nr)	(0x28 + (nr))
828d5d45fbSJean Delvare 
838d5d45fbSJean Delvare /* temps numbered 1-3 */
848d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP[]	= { 0x20, 0x21, 0x1f };
858d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_OVER[]	= { 0x39, 0x3d, 0x1d };
868d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_HYST[]	= { 0x3a, 0x3e, 0x1e };
878d5d45fbSJean Delvare /* bits 7-6 */
888d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW1	0x4b
898d5d45fbSJean Delvare /* 2 = bits 5-4, 3 = bits 7-6 */
908d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW23	0x49
918d5d45fbSJean Delvare 
928d5d45fbSJean Delvare #define VIA686A_REG_ALARM1	0x41
938d5d45fbSJean Delvare #define VIA686A_REG_ALARM2	0x42
948d5d45fbSJean Delvare #define VIA686A_REG_FANDIV	0x47
958d5d45fbSJean Delvare #define VIA686A_REG_CONFIG	0x40
968d5d45fbSJean Delvare /* The following register sets temp interrupt mode (bits 1-0 for temp1,
978d5d45fbSJean Delvare  3-2 for temp2, 5-4 for temp3).  Modes are:
988d5d45fbSJean Delvare     00 interrupt stays as long as value is out-of-range
998d5d45fbSJean Delvare     01 interrupt is cleared once register is read (default)
1008d5d45fbSJean Delvare     10 comparator mode- like 00, but ignores hysteresis
1018d5d45fbSJean Delvare     11 same as 00 */
1028d5d45fbSJean Delvare #define VIA686A_REG_TEMP_MODE		0x4b
1038d5d45fbSJean Delvare /* We'll just assume that you want to set all 3 simultaneously: */
1048d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_MASK		0x3F
1058d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_CONTINUOUS	0x00
1068d5d45fbSJean Delvare 
1078d5d45fbSJean Delvare /* Conversions. Limit checking is only done on the TO_REG
1088d5d45fbSJean Delvare    variants.
1098d5d45fbSJean Delvare 
1108d5d45fbSJean Delvare ********* VOLTAGE CONVERSIONS (Bob Dougherty) ********
1118d5d45fbSJean Delvare  From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew):
1128d5d45fbSJean Delvare  voltagefactor[0]=1.25/2628; (2628/1.25=2102.4)   // Vccp
1138d5d45fbSJean Delvare  voltagefactor[1]=1.25/2628; (2628/1.25=2102.4)   // +2.5V
1148d5d45fbSJean Delvare  voltagefactor[2]=1.67/2628; (2628/1.67=1573.7)   // +3.3V
1158d5d45fbSJean Delvare  voltagefactor[3]=2.6/2628;  (2628/2.60=1010.8)   // +5V
1168d5d45fbSJean Delvare  voltagefactor[4]=6.3/2628;  (2628/6.30=417.14)   // +12V
1178d5d45fbSJean Delvare  in[i]=(data[i+2]*25.0+133)*voltagefactor[i];
1188d5d45fbSJean Delvare  That is:
1198d5d45fbSJean Delvare  volts = (25*regVal+133)*factor
1208d5d45fbSJean Delvare  regVal = (volts/factor-133)/25
1218d5d45fbSJean Delvare  (These conversions were contributed by Jonathan Teh Soon Yew
1228d5d45fbSJean Delvare  <j.teh@iname.com>) */
1238d5d45fbSJean Delvare static inline u8 IN_TO_REG(long val, int inNum)
1248d5d45fbSJean Delvare {
1258d5d45fbSJean Delvare 	/* To avoid floating point, we multiply constants by 10 (100 for +12V).
1268d5d45fbSJean Delvare 	   Rounding is done (120500 is actually 133000 - 12500).
1278d5d45fbSJean Delvare 	   Remember that val is expressed in 0.001V/bit, which is why we divide
1288d5d45fbSJean Delvare 	   by an additional 10000 (100000 for +12V): 1000 for val and 10 (100)
1298d5d45fbSJean Delvare 	   for the constants. */
1308d5d45fbSJean Delvare 	if (inNum <= 1)
1318d5d45fbSJean Delvare 		return (u8)
1328d5d45fbSJean Delvare 		    SENSORS_LIMIT((val * 21024 - 1205000) / 250000, 0, 255);
1338d5d45fbSJean Delvare 	else if (inNum == 2)
1348d5d45fbSJean Delvare 		return (u8)
1358d5d45fbSJean Delvare 		    SENSORS_LIMIT((val * 15737 - 1205000) / 250000, 0, 255);
1368d5d45fbSJean Delvare 	else if (inNum == 3)
1378d5d45fbSJean Delvare 		return (u8)
1388d5d45fbSJean Delvare 		    SENSORS_LIMIT((val * 10108 - 1205000) / 250000, 0, 255);
1398d5d45fbSJean Delvare 	else
1408d5d45fbSJean Delvare 		return (u8)
1418d5d45fbSJean Delvare 		    SENSORS_LIMIT((val * 41714 - 12050000) / 2500000, 0, 255);
1428d5d45fbSJean Delvare }
1438d5d45fbSJean Delvare 
1448d5d45fbSJean Delvare static inline long IN_FROM_REG(u8 val, int inNum)
1458d5d45fbSJean Delvare {
1468d5d45fbSJean Delvare 	/* To avoid floating point, we multiply constants by 10 (100 for +12V).
1478d5d45fbSJean Delvare 	   We also multiply them by 1000 because we want 0.001V/bit for the
1488d5d45fbSJean Delvare 	   output value. Rounding is done. */
1498d5d45fbSJean Delvare 	if (inNum <= 1)
1508d5d45fbSJean Delvare 		return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024);
1518d5d45fbSJean Delvare 	else if (inNum == 2)
1528d5d45fbSJean Delvare 		return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737);
1538d5d45fbSJean Delvare 	else if (inNum == 3)
1548d5d45fbSJean Delvare 		return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108);
1558d5d45fbSJean Delvare 	else
1568d5d45fbSJean Delvare 		return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714);
1578d5d45fbSJean Delvare }
1588d5d45fbSJean Delvare 
1598d5d45fbSJean Delvare /********* FAN RPM CONVERSIONS ********/
1608d5d45fbSJean Delvare /* Higher register values = slower fans (the fan's strobe gates a counter).
1618d5d45fbSJean Delvare  But this chip saturates back at 0, not at 255 like all the other chips.
1628d5d45fbSJean Delvare  So, 0 means 0 RPM */
1638d5d45fbSJean Delvare static inline u8 FAN_TO_REG(long rpm, int div)
1648d5d45fbSJean Delvare {
1658d5d45fbSJean Delvare 	if (rpm == 0)
1668d5d45fbSJean Delvare 		return 0;
1678d5d45fbSJean Delvare 	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
1688d5d45fbSJean Delvare 	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255);
1698d5d45fbSJean Delvare }
1708d5d45fbSJean Delvare 
1718d5d45fbSJean Delvare #define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div)))
1728d5d45fbSJean Delvare 
1738d5d45fbSJean Delvare /******** TEMP CONVERSIONS (Bob Dougherty) *********/
1748d5d45fbSJean Delvare /* linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew)
1758d5d45fbSJean Delvare       if(temp<169)
1768d5d45fbSJean Delvare 	      return double(temp)*0.427-32.08;
1778d5d45fbSJean Delvare       else if(temp>=169 && temp<=202)
1788d5d45fbSJean Delvare 	      return double(temp)*0.582-58.16;
1798d5d45fbSJean Delvare       else
1808d5d45fbSJean Delvare 	      return double(temp)*0.924-127.33;
1818d5d45fbSJean Delvare 
1828d5d45fbSJean Delvare  A fifth-order polynomial fits the unofficial data (provided by Alex van
1838d5d45fbSJean Delvare  Kaam <darkside@chello.nl>) a bit better.  It also give more reasonable
1848d5d45fbSJean Delvare  numbers on my machine (ie. they agree with what my BIOS tells me).
1858d5d45fbSJean Delvare  Here's the fifth-order fit to the 8-bit data:
1868d5d45fbSJean Delvare  temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 -
1878d5d45fbSJean Delvare 	2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0.
1888d5d45fbSJean Delvare 
1898d5d45fbSJean Delvare  (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for
1908d5d45fbSJean Delvare  finding my typos in this formula!)
1918d5d45fbSJean Delvare 
1928d5d45fbSJean Delvare  Alas, none of the elegant function-fit solutions will work because we
1938d5d45fbSJean Delvare  aren't allowed to use floating point in the kernel and doing it with
1948d5d45fbSJean Delvare  integers doesn't provide enough precision.  So we'll do boring old
1958d5d45fbSJean Delvare  look-up table stuff.  The unofficial data (see below) have effectively
1968d5d45fbSJean Delvare  7-bit resolution (they are rounded to the nearest degree).  I'm assuming
1978d5d45fbSJean Delvare  that the transfer function of the device is monotonic and smooth, so a
1988d5d45fbSJean Delvare  smooth function fit to the data will allow us to get better precision.
1998d5d45fbSJean Delvare  I used the 5th-order poly fit described above and solved for
2008d5d45fbSJean Delvare  VIA register values 0-255.  I *10 before rounding, so we get tenth-degree
2018d5d45fbSJean Delvare  precision.  (I could have done all 1024 values for our 10-bit readings,
2028d5d45fbSJean Delvare  but the function is very linear in the useful range (0-80 deg C), so
2038d5d45fbSJean Delvare  we'll just use linear interpolation for 10-bit readings.)  So, tempLUT
2048d5d45fbSJean Delvare  is the temp at via register values 0-255: */
2058d5d45fbSJean Delvare static const long tempLUT[] =
2068d5d45fbSJean Delvare { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
2078d5d45fbSJean Delvare 	-503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
2088d5d45fbSJean Delvare 	-362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
2098d5d45fbSJean Delvare 	-255, -246, -237, -229, -220, -212, -204, -196, -188, -180,
2108d5d45fbSJean Delvare 	-173, -166, -159, -152, -145, -139, -132, -126, -120, -114,
2118d5d45fbSJean Delvare 	-108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49,
2128d5d45fbSJean Delvare 	-44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16,
2138d5d45fbSJean Delvare 	20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84,
2148d5d45fbSJean Delvare 	88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138,
2158d5d45fbSJean Delvare 	142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189,
2168d5d45fbSJean Delvare 	193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241,
2178d5d45fbSJean Delvare 	245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294,
2188d5d45fbSJean Delvare 	299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348,
2198d5d45fbSJean Delvare 	353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404,
2208d5d45fbSJean Delvare 	409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464,
2218d5d45fbSJean Delvare 	469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532,
2228d5d45fbSJean Delvare 	538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614,
2238d5d45fbSJean Delvare 	621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718,
2248d5d45fbSJean Delvare 	728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856,
2258d5d45fbSJean Delvare 	870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044,
2268d5d45fbSJean Delvare 	1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252,
2278d5d45fbSJean Delvare 	1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462
2288d5d45fbSJean Delvare };
2298d5d45fbSJean Delvare 
2308d5d45fbSJean Delvare /* the original LUT values from Alex van Kaam <darkside@chello.nl>
2318d5d45fbSJean Delvare    (for via register values 12-240):
2328d5d45fbSJean Delvare {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31,
2338d5d45fbSJean Delvare -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15,
2348d5d45fbSJean Delvare -15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3,
2358d5d45fbSJean Delvare -3,-2,-2,-1,-1,0,0,1,1,1,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,9,10,10,11,11,12,
2368d5d45fbSJean Delvare 12,12,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,20,20,21,21,21,22,22,
2378d5d45fbSJean Delvare 22,23,23,24,24,25,25,26,26,26,27,27,27,28,28,29,29,30,30,30,31,31,32,32,33,
2388d5d45fbSJean Delvare 33,34,34,35,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,
2398d5d45fbSJean Delvare 45,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,59,59,60,
2408d5d45fbSJean Delvare 61,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84,
2418d5d45fbSJean Delvare 85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110};
2428d5d45fbSJean Delvare 
2438d5d45fbSJean Delvare 
2448d5d45fbSJean Delvare  Here's the reverse LUT.  I got it by doing a 6-th order poly fit (needed
2458d5d45fbSJean Delvare  an extra term for a good fit to these inverse data!) and then
2468d5d45fbSJean Delvare  solving for each temp value from -50 to 110 (the useable range for
2478d5d45fbSJean Delvare  this chip).  Here's the fit:
2488d5d45fbSJean Delvare  viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4
2498d5d45fbSJean Delvare  - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
2508d5d45fbSJean Delvare  Note that n=161: */
2518d5d45fbSJean Delvare static const u8 viaLUT[] =
2528d5d45fbSJean Delvare { 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
2538d5d45fbSJean Delvare 	23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
2548d5d45fbSJean Delvare 	41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
2558d5d45fbSJean Delvare 	69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100,
2568d5d45fbSJean Delvare 	103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129,
2578d5d45fbSJean Delvare 	131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156,
2588d5d45fbSJean Delvare 	158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
2598d5d45fbSJean Delvare 	182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199,
2608d5d45fbSJean Delvare 	200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213,
2618d5d45fbSJean Delvare 	214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224,
2628d5d45fbSJean Delvare 	225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232,
2638d5d45fbSJean Delvare 	233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
2648d5d45fbSJean Delvare 	239, 240
2658d5d45fbSJean Delvare };
2668d5d45fbSJean Delvare 
2678d5d45fbSJean Delvare /* Converting temps to (8-bit) hyst and over registers
2688d5d45fbSJean Delvare    No interpolation here.
2698d5d45fbSJean Delvare    The +50 is because the temps start at -50 */
2708d5d45fbSJean Delvare static inline u8 TEMP_TO_REG(long val)
2718d5d45fbSJean Delvare {
2728d5d45fbSJean Delvare 	return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 :
2738d5d45fbSJean Delvare 		      (val < 0 ? val - 500 : val + 500) / 1000 + 50];
2748d5d45fbSJean Delvare }
2758d5d45fbSJean Delvare 
2768d5d45fbSJean Delvare /* for 8-bit temperature hyst and over registers */
2778d5d45fbSJean Delvare #define TEMP_FROM_REG(val) (tempLUT[(val)] * 100)
2788d5d45fbSJean Delvare 
2798d5d45fbSJean Delvare /* for 10-bit temperature readings */
2808d5d45fbSJean Delvare static inline long TEMP_FROM_REG10(u16 val)
2818d5d45fbSJean Delvare {
2828d5d45fbSJean Delvare 	u16 eightBits = val >> 2;
2838d5d45fbSJean Delvare 	u16 twoBits = val & 3;
2848d5d45fbSJean Delvare 
2858d5d45fbSJean Delvare 	/* no interpolation for these */
2868d5d45fbSJean Delvare 	if (twoBits == 0 || eightBits == 255)
2878d5d45fbSJean Delvare 		return TEMP_FROM_REG(eightBits);
2888d5d45fbSJean Delvare 
2898d5d45fbSJean Delvare 	/* do some linear interpolation */
2908d5d45fbSJean Delvare 	return (tempLUT[eightBits] * (4 - twoBits) +
2918d5d45fbSJean Delvare 		tempLUT[eightBits + 1] * twoBits) * 25;
2928d5d45fbSJean Delvare }
2938d5d45fbSJean Delvare 
2948d5d45fbSJean Delvare #define DIV_FROM_REG(val) (1 << (val))
2958d5d45fbSJean Delvare #define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
2968d5d45fbSJean Delvare 
2978d5d45fbSJean Delvare /* For the VIA686A, we need to keep some data in memory.
2988d5d45fbSJean Delvare    The structure is dynamically allocated, at the same time when a new
2998d5d45fbSJean Delvare    via686a client is allocated. */
3008d5d45fbSJean Delvare struct via686a_data {
3018d5d45fbSJean Delvare 	struct i2c_client client;
302*943b0830SMark M. Hoffman 	struct class_device *class_dev;
3038d5d45fbSJean Delvare 	struct semaphore update_lock;
3048d5d45fbSJean Delvare 	char valid;		/* !=0 if following fields are valid */
3058d5d45fbSJean Delvare 	unsigned long last_updated;	/* In jiffies */
3068d5d45fbSJean Delvare 
3078d5d45fbSJean Delvare 	u8 in[5];		/* Register value */
3088d5d45fbSJean Delvare 	u8 in_max[5];		/* Register value */
3098d5d45fbSJean Delvare 	u8 in_min[5];		/* Register value */
3108d5d45fbSJean Delvare 	u8 fan[2];		/* Register value */
3118d5d45fbSJean Delvare 	u8 fan_min[2];		/* Register value */
3128d5d45fbSJean Delvare 	u16 temp[3];		/* Register value 10 bit */
3138d5d45fbSJean Delvare 	u8 temp_over[3];	/* Register value */
3148d5d45fbSJean Delvare 	u8 temp_hyst[3];	/* Register value */
3158d5d45fbSJean Delvare 	u8 fan_div[2];		/* Register encoding, shifted right */
3168d5d45fbSJean Delvare 	u16 alarms;		/* Register encoding, combined */
3178d5d45fbSJean Delvare };
3188d5d45fbSJean Delvare 
3198d5d45fbSJean Delvare static struct pci_dev *s_bridge;	/* pointer to the (only) via686a */
3208d5d45fbSJean Delvare 
3218d5d45fbSJean Delvare static int via686a_attach_adapter(struct i2c_adapter *adapter);
3228d5d45fbSJean Delvare static int via686a_detect(struct i2c_adapter *adapter, int address, int kind);
3238d5d45fbSJean Delvare static int via686a_detach_client(struct i2c_client *client);
3248d5d45fbSJean Delvare 
3258d5d45fbSJean Delvare static inline int via686a_read_value(struct i2c_client *client, u8 reg)
3268d5d45fbSJean Delvare {
3278d5d45fbSJean Delvare 	return (inb_p(client->addr + reg));
3288d5d45fbSJean Delvare }
3298d5d45fbSJean Delvare 
3308d5d45fbSJean Delvare static inline void via686a_write_value(struct i2c_client *client, u8 reg,
3318d5d45fbSJean Delvare 				       u8 value)
3328d5d45fbSJean Delvare {
3338d5d45fbSJean Delvare 	outb_p(value, client->addr + reg);
3348d5d45fbSJean Delvare }
3358d5d45fbSJean Delvare 
3368d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev);
3378d5d45fbSJean Delvare static void via686a_init_client(struct i2c_client *client);
3388d5d45fbSJean Delvare 
3398d5d45fbSJean Delvare /* following are the sysfs callback functions */
3408d5d45fbSJean Delvare 
3418d5d45fbSJean Delvare /* 7 voltage sensors */
3428d5d45fbSJean Delvare static ssize_t show_in(struct device *dev, char *buf, int nr) {
3438d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
3448d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr));
3458d5d45fbSJean Delvare }
3468d5d45fbSJean Delvare 
3478d5d45fbSJean Delvare static ssize_t show_in_min(struct device *dev, char *buf, int nr) {
3488d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
3498d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr));
3508d5d45fbSJean Delvare }
3518d5d45fbSJean Delvare 
3528d5d45fbSJean Delvare static ssize_t show_in_max(struct device *dev, char *buf, int nr) {
3538d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
3548d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
3558d5d45fbSJean Delvare }
3568d5d45fbSJean Delvare 
3578d5d45fbSJean Delvare static ssize_t set_in_min(struct device *dev, const char *buf,
3588d5d45fbSJean Delvare 		size_t count, int nr) {
3598d5d45fbSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
3608d5d45fbSJean Delvare 	struct via686a_data *data = i2c_get_clientdata(client);
3618d5d45fbSJean Delvare 	unsigned long val = simple_strtoul(buf, NULL, 10);
3628d5d45fbSJean Delvare 
3638d5d45fbSJean Delvare 	down(&data->update_lock);
3648d5d45fbSJean Delvare 	data->in_min[nr] = IN_TO_REG(val, nr);
3658d5d45fbSJean Delvare 	via686a_write_value(client, VIA686A_REG_IN_MIN(nr),
3668d5d45fbSJean Delvare 			data->in_min[nr]);
3678d5d45fbSJean Delvare 	up(&data->update_lock);
3688d5d45fbSJean Delvare 	return count;
3698d5d45fbSJean Delvare }
3708d5d45fbSJean Delvare static ssize_t set_in_max(struct device *dev, const char *buf,
3718d5d45fbSJean Delvare 		size_t count, int nr) {
3728d5d45fbSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
3738d5d45fbSJean Delvare 	struct via686a_data *data = i2c_get_clientdata(client);
3748d5d45fbSJean Delvare 	unsigned long val = simple_strtoul(buf, NULL, 10);
3758d5d45fbSJean Delvare 
3768d5d45fbSJean Delvare 	down(&data->update_lock);
3778d5d45fbSJean Delvare 	data->in_max[nr] = IN_TO_REG(val, nr);
3788d5d45fbSJean Delvare 	via686a_write_value(client, VIA686A_REG_IN_MAX(nr),
3798d5d45fbSJean Delvare 			data->in_max[nr]);
3808d5d45fbSJean Delvare 	up(&data->update_lock);
3818d5d45fbSJean Delvare 	return count;
3828d5d45fbSJean Delvare }
3838d5d45fbSJean Delvare #define show_in_offset(offset)					\
3848d5d45fbSJean Delvare static ssize_t 							\
3858d5d45fbSJean Delvare 	show_in##offset (struct device *dev, struct device_attribute *attr, char *buf)		\
3868d5d45fbSJean Delvare {								\
3878d5d45fbSJean Delvare 	return show_in(dev, buf, offset);			\
3888d5d45fbSJean Delvare }								\
3898d5d45fbSJean Delvare static ssize_t 							\
3908d5d45fbSJean Delvare 	show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)	\
3918d5d45fbSJean Delvare {								\
3928d5d45fbSJean Delvare 	return show_in_min(dev, buf, offset);		\
3938d5d45fbSJean Delvare }								\
3948d5d45fbSJean Delvare static ssize_t 							\
3958d5d45fbSJean Delvare 	show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf)	\
3968d5d45fbSJean Delvare {								\
3978d5d45fbSJean Delvare 	return show_in_max(dev, buf, offset);		\
3988d5d45fbSJean Delvare }								\
3998d5d45fbSJean Delvare static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, 	\
4008d5d45fbSJean Delvare 		const char *buf, size_t count) 			\
4018d5d45fbSJean Delvare {								\
4028d5d45fbSJean Delvare 	return set_in_min(dev, buf, count, offset);		\
4038d5d45fbSJean Delvare }								\
4048d5d45fbSJean Delvare static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr,	\
4058d5d45fbSJean Delvare 			const char *buf, size_t count)		\
4068d5d45fbSJean Delvare {								\
4078d5d45fbSJean Delvare 	return set_in_max(dev, buf, count, offset);		\
4088d5d45fbSJean Delvare }								\
4098d5d45fbSJean Delvare static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);\
4108d5d45fbSJean Delvare static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, 	\
4118d5d45fbSJean Delvare 		show_in##offset##_min, set_in##offset##_min);	\
4128d5d45fbSJean Delvare static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, 	\
4138d5d45fbSJean Delvare 		show_in##offset##_max, set_in##offset##_max);
4148d5d45fbSJean Delvare 
4158d5d45fbSJean Delvare show_in_offset(0);
4168d5d45fbSJean Delvare show_in_offset(1);
4178d5d45fbSJean Delvare show_in_offset(2);
4188d5d45fbSJean Delvare show_in_offset(3);
4198d5d45fbSJean Delvare show_in_offset(4);
4208d5d45fbSJean Delvare 
4218d5d45fbSJean Delvare /* 3 temperatures */
4228d5d45fbSJean Delvare static ssize_t show_temp(struct device *dev, char *buf, int nr) {
4238d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4248d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
4258d5d45fbSJean Delvare }
4268d5d45fbSJean Delvare static ssize_t show_temp_over(struct device *dev, char *buf, int nr) {
4278d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4288d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
4298d5d45fbSJean Delvare }
4308d5d45fbSJean Delvare static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) {
4318d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4328d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
4338d5d45fbSJean Delvare }
4348d5d45fbSJean Delvare static ssize_t set_temp_over(struct device *dev, const char *buf,
4358d5d45fbSJean Delvare 		size_t count, int nr) {
4368d5d45fbSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
4378d5d45fbSJean Delvare 	struct via686a_data *data = i2c_get_clientdata(client);
4388d5d45fbSJean Delvare 	int val = simple_strtol(buf, NULL, 10);
4398d5d45fbSJean Delvare 
4408d5d45fbSJean Delvare 	down(&data->update_lock);
4418d5d45fbSJean Delvare 	data->temp_over[nr] = TEMP_TO_REG(val);
4428d5d45fbSJean Delvare 	via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr],
4438d5d45fbSJean Delvare 			    data->temp_over[nr]);
4448d5d45fbSJean Delvare 	up(&data->update_lock);
4458d5d45fbSJean Delvare 	return count;
4468d5d45fbSJean Delvare }
4478d5d45fbSJean Delvare static ssize_t set_temp_hyst(struct device *dev, const char *buf,
4488d5d45fbSJean Delvare 		size_t count, int nr) {
4498d5d45fbSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
4508d5d45fbSJean Delvare 	struct via686a_data *data = i2c_get_clientdata(client);
4518d5d45fbSJean Delvare 	int val = simple_strtol(buf, NULL, 10);
4528d5d45fbSJean Delvare 
4538d5d45fbSJean Delvare 	down(&data->update_lock);
4548d5d45fbSJean Delvare 	data->temp_hyst[nr] = TEMP_TO_REG(val);
4558d5d45fbSJean Delvare 	via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr],
4568d5d45fbSJean Delvare 			    data->temp_hyst[nr]);
4578d5d45fbSJean Delvare 	up(&data->update_lock);
4588d5d45fbSJean Delvare 	return count;
4598d5d45fbSJean Delvare }
4608d5d45fbSJean Delvare #define show_temp_offset(offset)					\
4618d5d45fbSJean Delvare static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf)	\
4628d5d45fbSJean Delvare {									\
4638d5d45fbSJean Delvare 	return show_temp(dev, buf, offset - 1);				\
4648d5d45fbSJean Delvare }									\
4658d5d45fbSJean Delvare static ssize_t								\
4668d5d45fbSJean Delvare show_temp_##offset##_over (struct device *dev, struct device_attribute *attr, char *buf)		\
4678d5d45fbSJean Delvare {									\
4688d5d45fbSJean Delvare 	return show_temp_over(dev, buf, offset - 1);			\
4698d5d45fbSJean Delvare }									\
4708d5d45fbSJean Delvare static ssize_t								\
4718d5d45fbSJean Delvare show_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, char *buf)		\
4728d5d45fbSJean Delvare {									\
4738d5d45fbSJean Delvare 	return show_temp_hyst(dev, buf, offset - 1);			\
4748d5d45fbSJean Delvare }									\
4758d5d45fbSJean Delvare static ssize_t set_temp_##offset##_over (struct device *dev, struct device_attribute *attr, 		\
4768d5d45fbSJean Delvare 		const char *buf, size_t count) 				\
4778d5d45fbSJean Delvare {									\
4788d5d45fbSJean Delvare 	return set_temp_over(dev, buf, count, offset - 1);		\
4798d5d45fbSJean Delvare }									\
4808d5d45fbSJean Delvare static ssize_t set_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, 		\
4818d5d45fbSJean Delvare 		const char *buf, size_t count) 				\
4828d5d45fbSJean Delvare {									\
4838d5d45fbSJean Delvare 	return set_temp_hyst(dev, buf, count, offset - 1);		\
4848d5d45fbSJean Delvare }									\
4858d5d45fbSJean Delvare static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\
4868d5d45fbSJean Delvare static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, 		\
4878d5d45fbSJean Delvare 		show_temp_##offset##_over, set_temp_##offset##_over);	\
4888d5d45fbSJean Delvare static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, 		\
4898d5d45fbSJean Delvare 		show_temp_##offset##_hyst, set_temp_##offset##_hyst);
4908d5d45fbSJean Delvare 
4918d5d45fbSJean Delvare show_temp_offset(1);
4928d5d45fbSJean Delvare show_temp_offset(2);
4938d5d45fbSJean Delvare show_temp_offset(3);
4948d5d45fbSJean Delvare 
4958d5d45fbSJean Delvare /* 2 Fans */
4968d5d45fbSJean Delvare static ssize_t show_fan(struct device *dev, char *buf, int nr) {
4978d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4988d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
4998d5d45fbSJean Delvare 				DIV_FROM_REG(data->fan_div[nr])) );
5008d5d45fbSJean Delvare }
5018d5d45fbSJean Delvare static ssize_t show_fan_min(struct device *dev, char *buf, int nr) {
5028d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5038d5d45fbSJean Delvare 	return sprintf(buf, "%d\n",
5048d5d45fbSJean Delvare 		FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) );
5058d5d45fbSJean Delvare }
5068d5d45fbSJean Delvare static ssize_t show_fan_div(struct device *dev, char *buf, int nr) {
5078d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5088d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
5098d5d45fbSJean Delvare }
5108d5d45fbSJean Delvare static ssize_t set_fan_min(struct device *dev, const char *buf,
5118d5d45fbSJean Delvare 		size_t count, int nr) {
5128d5d45fbSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
5138d5d45fbSJean Delvare 	struct via686a_data *data = i2c_get_clientdata(client);
5148d5d45fbSJean Delvare 	int val = simple_strtol(buf, NULL, 10);
5158d5d45fbSJean Delvare 
5168d5d45fbSJean Delvare 	down(&data->update_lock);
5178d5d45fbSJean Delvare 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
5188d5d45fbSJean Delvare 	via686a_write_value(client, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
5198d5d45fbSJean Delvare 	up(&data->update_lock);
5208d5d45fbSJean Delvare 	return count;
5218d5d45fbSJean Delvare }
5228d5d45fbSJean Delvare static ssize_t set_fan_div(struct device *dev, const char *buf,
5238d5d45fbSJean Delvare 		size_t count, int nr) {
5248d5d45fbSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
5258d5d45fbSJean Delvare 	struct via686a_data *data = i2c_get_clientdata(client);
5268d5d45fbSJean Delvare 	int val = simple_strtol(buf, NULL, 10);
5278d5d45fbSJean Delvare 	int old;
5288d5d45fbSJean Delvare 
5298d5d45fbSJean Delvare 	down(&data->update_lock);
5308d5d45fbSJean Delvare 	old = via686a_read_value(client, VIA686A_REG_FANDIV);
5318d5d45fbSJean Delvare 	data->fan_div[nr] = DIV_TO_REG(val);
5328d5d45fbSJean Delvare 	old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
5338d5d45fbSJean Delvare 	via686a_write_value(client, VIA686A_REG_FANDIV, old);
5348d5d45fbSJean Delvare 	up(&data->update_lock);
5358d5d45fbSJean Delvare 	return count;
5368d5d45fbSJean Delvare }
5378d5d45fbSJean Delvare 
5388d5d45fbSJean Delvare #define show_fan_offset(offset)						\
5398d5d45fbSJean Delvare static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf)	\
5408d5d45fbSJean Delvare {									\
5418d5d45fbSJean Delvare 	return show_fan(dev, buf, offset - 1);				\
5428d5d45fbSJean Delvare }									\
5438d5d45fbSJean Delvare static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)	\
5448d5d45fbSJean Delvare {									\
5458d5d45fbSJean Delvare 	return show_fan_min(dev, buf, offset - 1);			\
5468d5d45fbSJean Delvare }									\
5478d5d45fbSJean Delvare static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf)	\
5488d5d45fbSJean Delvare {									\
5498d5d45fbSJean Delvare 	return show_fan_div(dev, buf, offset - 1);			\
5508d5d45fbSJean Delvare }									\
5518d5d45fbSJean Delvare static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, 		\
5528d5d45fbSJean Delvare 	const char *buf, size_t count) 					\
5538d5d45fbSJean Delvare {									\
5548d5d45fbSJean Delvare 	return set_fan_min(dev, buf, count, offset - 1);		\
5558d5d45fbSJean Delvare }									\
5568d5d45fbSJean Delvare static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, 		\
5578d5d45fbSJean Delvare 		const char *buf, size_t count) 				\
5588d5d45fbSJean Delvare {									\
5598d5d45fbSJean Delvare 	return set_fan_div(dev, buf, count, offset - 1);		\
5608d5d45fbSJean Delvare }									\
5618d5d45fbSJean Delvare static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
5628d5d45fbSJean Delvare static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, 		\
5638d5d45fbSJean Delvare 		show_fan_##offset##_min, set_fan_##offset##_min);	\
5648d5d45fbSJean Delvare static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, 		\
5658d5d45fbSJean Delvare 		show_fan_##offset##_div, set_fan_##offset##_div);
5668d5d45fbSJean Delvare 
5678d5d45fbSJean Delvare show_fan_offset(1);
5688d5d45fbSJean Delvare show_fan_offset(2);
5698d5d45fbSJean Delvare 
5708d5d45fbSJean Delvare /* Alarms */
5718d5d45fbSJean Delvare static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) {
5728d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5738d5d45fbSJean Delvare 	return sprintf(buf, "%u\n", data->alarms);
5748d5d45fbSJean Delvare }
5758d5d45fbSJean Delvare static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
5768d5d45fbSJean Delvare 
5778d5d45fbSJean Delvare /* The driver. I choose to use type i2c_driver, as at is identical to both
5788d5d45fbSJean Delvare    smbus_driver and isa_driver, and clients could be of either kind */
5798d5d45fbSJean Delvare static struct i2c_driver via686a_driver = {
5808d5d45fbSJean Delvare 	.owner		= THIS_MODULE,
5818d5d45fbSJean Delvare 	.name		= "via686a",
5828d5d45fbSJean Delvare 	.id		= I2C_DRIVERID_VIA686A,
5838d5d45fbSJean Delvare 	.flags		= I2C_DF_NOTIFY,
5848d5d45fbSJean Delvare 	.attach_adapter	= via686a_attach_adapter,
5858d5d45fbSJean Delvare 	.detach_client	= via686a_detach_client,
5868d5d45fbSJean Delvare };
5878d5d45fbSJean Delvare 
5888d5d45fbSJean Delvare 
5898d5d45fbSJean Delvare /* This is called when the module is loaded */
5908d5d45fbSJean Delvare static int via686a_attach_adapter(struct i2c_adapter *adapter)
5918d5d45fbSJean Delvare {
5928d5d45fbSJean Delvare 	if (!(adapter->class & I2C_CLASS_HWMON))
5938d5d45fbSJean Delvare 		return 0;
5948d5d45fbSJean Delvare 	return i2c_detect(adapter, &addr_data, via686a_detect);
5958d5d45fbSJean Delvare }
5968d5d45fbSJean Delvare 
5978d5d45fbSJean Delvare static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
5988d5d45fbSJean Delvare {
5998d5d45fbSJean Delvare 	struct i2c_client *new_client;
6008d5d45fbSJean Delvare 	struct via686a_data *data;
6018d5d45fbSJean Delvare 	int err = 0;
6028d5d45fbSJean Delvare 	const char client_name[] = "via686a";
6038d5d45fbSJean Delvare 	u16 val;
6048d5d45fbSJean Delvare 
6058d5d45fbSJean Delvare 	/* Make sure we are probing the ISA bus!!  */
6068d5d45fbSJean Delvare 	if (!i2c_is_isa_adapter(adapter)) {
6078d5d45fbSJean Delvare 		dev_err(&adapter->dev,
6088d5d45fbSJean Delvare 		"via686a_detect called for an I2C bus adapter?!?\n");
6098d5d45fbSJean Delvare 		return 0;
6108d5d45fbSJean Delvare 	}
6118d5d45fbSJean Delvare 
6128d5d45fbSJean Delvare 	/* 8231 requires multiple of 256, we enforce that on 686 as well */
6138d5d45fbSJean Delvare 	if (force_addr)
6148d5d45fbSJean Delvare 		address = force_addr & 0xFF00;
6158d5d45fbSJean Delvare 
6168d5d45fbSJean Delvare 	if (force_addr) {
6178d5d45fbSJean Delvare 		dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n",
6188d5d45fbSJean Delvare 			 address);
6198d5d45fbSJean Delvare 		if (PCIBIOS_SUCCESSFUL !=
6208d5d45fbSJean Delvare 		    pci_write_config_word(s_bridge, VIA686A_BASE_REG, address))
6218d5d45fbSJean Delvare 			return -ENODEV;
6228d5d45fbSJean Delvare 	}
6238d5d45fbSJean Delvare 	if (PCIBIOS_SUCCESSFUL !=
6248d5d45fbSJean Delvare 	    pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val))
6258d5d45fbSJean Delvare 		return -ENODEV;
6268d5d45fbSJean Delvare 	if (!(val & 0x0001)) {
6278d5d45fbSJean Delvare 		dev_warn(&adapter->dev, "enabling sensors\n");
6288d5d45fbSJean Delvare 		if (PCIBIOS_SUCCESSFUL !=
6298d5d45fbSJean Delvare 		    pci_write_config_word(s_bridge, VIA686A_ENABLE_REG,
6308d5d45fbSJean Delvare 					  val | 0x0001))
6318d5d45fbSJean Delvare 			return -ENODEV;
6328d5d45fbSJean Delvare 	}
6338d5d45fbSJean Delvare 
6348d5d45fbSJean Delvare 	/* Reserve the ISA region */
6358d5d45fbSJean Delvare 	if (!request_region(address, VIA686A_EXTENT, via686a_driver.name)) {
6368d5d45fbSJean Delvare 		dev_err(&adapter->dev, "region 0x%x already in use!\n",
6378d5d45fbSJean Delvare 			address);
6388d5d45fbSJean Delvare 		return -ENODEV;
6398d5d45fbSJean Delvare 	}
6408d5d45fbSJean Delvare 
6418d5d45fbSJean Delvare 	if (!(data = kmalloc(sizeof(struct via686a_data), GFP_KERNEL))) {
6428d5d45fbSJean Delvare 		err = -ENOMEM;
643*943b0830SMark M. Hoffman 		goto exit_release;
6448d5d45fbSJean Delvare 	}
6458d5d45fbSJean Delvare 	memset(data, 0, sizeof(struct via686a_data));
6468d5d45fbSJean Delvare 
6478d5d45fbSJean Delvare 	new_client = &data->client;
6488d5d45fbSJean Delvare 	i2c_set_clientdata(new_client, data);
6498d5d45fbSJean Delvare 	new_client->addr = address;
6508d5d45fbSJean Delvare 	new_client->adapter = adapter;
6518d5d45fbSJean Delvare 	new_client->driver = &via686a_driver;
6528d5d45fbSJean Delvare 	new_client->flags = 0;
6538d5d45fbSJean Delvare 
6548d5d45fbSJean Delvare 	/* Fill in the remaining client fields and put into the global list */
6558d5d45fbSJean Delvare 	strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
6568d5d45fbSJean Delvare 
6578d5d45fbSJean Delvare 	data->valid = 0;
6588d5d45fbSJean Delvare 	init_MUTEX(&data->update_lock);
6598d5d45fbSJean Delvare 	/* Tell the I2C layer a new client has arrived */
6608d5d45fbSJean Delvare 	if ((err = i2c_attach_client(new_client)))
661*943b0830SMark M. Hoffman 		goto exit_free;
6628d5d45fbSJean Delvare 
6638d5d45fbSJean Delvare 	/* Initialize the VIA686A chip */
6648d5d45fbSJean Delvare 	via686a_init_client(new_client);
6658d5d45fbSJean Delvare 
6668d5d45fbSJean Delvare 	/* Register sysfs hooks */
667*943b0830SMark M. Hoffman 	data->class_dev = hwmon_device_register(&new_client->dev);
668*943b0830SMark M. Hoffman 	if (IS_ERR(data->class_dev)) {
669*943b0830SMark M. Hoffman 		err = PTR_ERR(data->class_dev);
670*943b0830SMark M. Hoffman 		goto exit_detach;
671*943b0830SMark M. Hoffman 	}
672*943b0830SMark M. Hoffman 
6738d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in0_input);
6748d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in1_input);
6758d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in2_input);
6768d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in3_input);
6778d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in4_input);
6788d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in0_min);
6798d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in1_min);
6808d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in2_min);
6818d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in3_min);
6828d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in4_min);
6838d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in0_max);
6848d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in1_max);
6858d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in2_max);
6868d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in3_max);
6878d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in4_max);
6888d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_temp1_input);
6898d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_temp2_input);
6908d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_temp3_input);
6918d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_temp1_max);
6928d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_temp2_max);
6938d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_temp3_max);
6948d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
6958d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_temp2_max_hyst);
6968d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_temp3_max_hyst);
6978d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_fan1_input);
6988d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_fan2_input);
6998d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_fan1_min);
7008d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_fan2_min);
7018d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_fan1_div);
7028d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_fan2_div);
7038d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_alarms);
7048d5d45fbSJean Delvare 
7058d5d45fbSJean Delvare 	return 0;
7068d5d45fbSJean Delvare 
707*943b0830SMark M. Hoffman exit_detach:
708*943b0830SMark M. Hoffman 	i2c_detach_client(new_client);
709*943b0830SMark M. Hoffman exit_free:
7108d5d45fbSJean Delvare 	kfree(data);
711*943b0830SMark M. Hoffman exit_release:
7128d5d45fbSJean Delvare 	release_region(address, VIA686A_EXTENT);
7138d5d45fbSJean Delvare 	return err;
7148d5d45fbSJean Delvare }
7158d5d45fbSJean Delvare 
7168d5d45fbSJean Delvare static int via686a_detach_client(struct i2c_client *client)
7178d5d45fbSJean Delvare {
718*943b0830SMark M. Hoffman 	struct via686a_data *data = i2c_get_clientdata(client);
7198d5d45fbSJean Delvare 	int err;
7208d5d45fbSJean Delvare 
721*943b0830SMark M. Hoffman 	hwmon_device_unregister(data->class_dev);
722*943b0830SMark M. Hoffman 
7238d5d45fbSJean Delvare 	if ((err = i2c_detach_client(client))) {
7248d5d45fbSJean Delvare 		dev_err(&client->dev,
7258d5d45fbSJean Delvare 		"Client deregistration failed, client not detached.\n");
7268d5d45fbSJean Delvare 		return err;
7278d5d45fbSJean Delvare 	}
7288d5d45fbSJean Delvare 
7298d5d45fbSJean Delvare 	release_region(client->addr, VIA686A_EXTENT);
730*943b0830SMark M. Hoffman 	kfree(data);
7318d5d45fbSJean Delvare 
7328d5d45fbSJean Delvare 	return 0;
7338d5d45fbSJean Delvare }
7348d5d45fbSJean Delvare 
7358d5d45fbSJean Delvare /* Called when we have found a new VIA686A. Set limits, etc. */
7368d5d45fbSJean Delvare static void via686a_init_client(struct i2c_client *client)
7378d5d45fbSJean Delvare {
7388d5d45fbSJean Delvare 	u8 reg;
7398d5d45fbSJean Delvare 
7408d5d45fbSJean Delvare 	/* Start monitoring */
7418d5d45fbSJean Delvare 	reg = via686a_read_value(client, VIA686A_REG_CONFIG);
7428d5d45fbSJean Delvare 	via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F);
7438d5d45fbSJean Delvare 
7448d5d45fbSJean Delvare 	/* Configure temp interrupt mode for continuous-interrupt operation */
7458d5d45fbSJean Delvare 	via686a_write_value(client, VIA686A_REG_TEMP_MODE,
7468d5d45fbSJean Delvare 			    via686a_read_value(client, VIA686A_REG_TEMP_MODE) &
7478d5d45fbSJean Delvare 			    !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS));
7488d5d45fbSJean Delvare }
7498d5d45fbSJean Delvare 
7508d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev)
7518d5d45fbSJean Delvare {
7528d5d45fbSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
7538d5d45fbSJean Delvare 	struct via686a_data *data = i2c_get_clientdata(client);
7548d5d45fbSJean Delvare 	int i;
7558d5d45fbSJean Delvare 
7568d5d45fbSJean Delvare 	down(&data->update_lock);
7578d5d45fbSJean Delvare 
7588d5d45fbSJean Delvare 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
7598d5d45fbSJean Delvare 	    || !data->valid) {
7608d5d45fbSJean Delvare 		for (i = 0; i <= 4; i++) {
7618d5d45fbSJean Delvare 			data->in[i] =
7628d5d45fbSJean Delvare 			    via686a_read_value(client, VIA686A_REG_IN(i));
7638d5d45fbSJean Delvare 			data->in_min[i] = via686a_read_value(client,
7648d5d45fbSJean Delvare 							     VIA686A_REG_IN_MIN
7658d5d45fbSJean Delvare 							     (i));
7668d5d45fbSJean Delvare 			data->in_max[i] =
7678d5d45fbSJean Delvare 			    via686a_read_value(client, VIA686A_REG_IN_MAX(i));
7688d5d45fbSJean Delvare 		}
7698d5d45fbSJean Delvare 		for (i = 1; i <= 2; i++) {
7708d5d45fbSJean Delvare 			data->fan[i - 1] =
7718d5d45fbSJean Delvare 			    via686a_read_value(client, VIA686A_REG_FAN(i));
7728d5d45fbSJean Delvare 			data->fan_min[i - 1] = via686a_read_value(client,
7738d5d45fbSJean Delvare 						     VIA686A_REG_FAN_MIN(i));
7748d5d45fbSJean Delvare 		}
7758d5d45fbSJean Delvare 		for (i = 0; i <= 2; i++) {
7768d5d45fbSJean Delvare 			data->temp[i] = via686a_read_value(client,
7778d5d45fbSJean Delvare 						 VIA686A_REG_TEMP[i]) << 2;
7788d5d45fbSJean Delvare 			data->temp_over[i] =
7798d5d45fbSJean Delvare 			    via686a_read_value(client,
7808d5d45fbSJean Delvare 					       VIA686A_REG_TEMP_OVER[i]);
7818d5d45fbSJean Delvare 			data->temp_hyst[i] =
7828d5d45fbSJean Delvare 			    via686a_read_value(client,
7838d5d45fbSJean Delvare 					       VIA686A_REG_TEMP_HYST[i]);
7848d5d45fbSJean Delvare 		}
7858d5d45fbSJean Delvare 		/* add in lower 2 bits
7868d5d45fbSJean Delvare 		   temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1
7878d5d45fbSJean Delvare 		   temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
7888d5d45fbSJean Delvare 		   temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
7898d5d45fbSJean Delvare 		 */
7908d5d45fbSJean Delvare 		data->temp[0] |= (via686a_read_value(client,
7918d5d45fbSJean Delvare 						     VIA686A_REG_TEMP_LOW1)
7928d5d45fbSJean Delvare 				  & 0xc0) >> 6;
7938d5d45fbSJean Delvare 		data->temp[1] |=
7948d5d45fbSJean Delvare 		    (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
7958d5d45fbSJean Delvare 		     0x30) >> 4;
7968d5d45fbSJean Delvare 		data->temp[2] |=
7978d5d45fbSJean Delvare 		    (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
7988d5d45fbSJean Delvare 		     0xc0) >> 6;
7998d5d45fbSJean Delvare 
8008d5d45fbSJean Delvare 		i = via686a_read_value(client, VIA686A_REG_FANDIV);
8018d5d45fbSJean Delvare 		data->fan_div[0] = (i >> 4) & 0x03;
8028d5d45fbSJean Delvare 		data->fan_div[1] = i >> 6;
8038d5d45fbSJean Delvare 		data->alarms =
8048d5d45fbSJean Delvare 		    via686a_read_value(client,
8058d5d45fbSJean Delvare 				       VIA686A_REG_ALARM1) |
8068d5d45fbSJean Delvare 		    (via686a_read_value(client, VIA686A_REG_ALARM2) << 8);
8078d5d45fbSJean Delvare 		data->last_updated = jiffies;
8088d5d45fbSJean Delvare 		data->valid = 1;
8098d5d45fbSJean Delvare 	}
8108d5d45fbSJean Delvare 
8118d5d45fbSJean Delvare 	up(&data->update_lock);
8128d5d45fbSJean Delvare 
8138d5d45fbSJean Delvare 	return data;
8148d5d45fbSJean Delvare }
8158d5d45fbSJean Delvare 
8168d5d45fbSJean Delvare static struct pci_device_id via686a_pci_ids[] = {
8178d5d45fbSJean Delvare 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
8188d5d45fbSJean Delvare 	{ 0, }
8198d5d45fbSJean Delvare };
8208d5d45fbSJean Delvare 
8218d5d45fbSJean Delvare MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
8228d5d45fbSJean Delvare 
8238d5d45fbSJean Delvare static int __devinit via686a_pci_probe(struct pci_dev *dev,
8248d5d45fbSJean Delvare 				       const struct pci_device_id *id)
8258d5d45fbSJean Delvare {
8268d5d45fbSJean Delvare 	u16 val;
8278d5d45fbSJean Delvare 	int addr = 0;
8288d5d45fbSJean Delvare 
8298d5d45fbSJean Delvare 	if (PCIBIOS_SUCCESSFUL !=
8308d5d45fbSJean Delvare 	    pci_read_config_word(dev, VIA686A_BASE_REG, &val))
8318d5d45fbSJean Delvare 		return -ENODEV;
8328d5d45fbSJean Delvare 
8338d5d45fbSJean Delvare 	addr = val & ~(VIA686A_EXTENT - 1);
8348d5d45fbSJean Delvare 	if (addr == 0 && force_addr == 0) {
8358d5d45fbSJean Delvare 		dev_err(&dev->dev, "base address not set - upgrade BIOS "
8368d5d45fbSJean Delvare 			"or use force_addr=0xaddr\n");
8378d5d45fbSJean Delvare 		return -ENODEV;
8388d5d45fbSJean Delvare 	}
8398d5d45fbSJean Delvare 	if (force_addr)
8408d5d45fbSJean Delvare 		addr = force_addr;	/* so detect will get called */
8418d5d45fbSJean Delvare 
8428d5d45fbSJean Delvare 	if (!addr) {
8438d5d45fbSJean Delvare 		dev_err(&dev->dev, "No Via 686A sensors found.\n");
8448d5d45fbSJean Delvare 		return -ENODEV;
8458d5d45fbSJean Delvare 	}
8468d5d45fbSJean Delvare 	normal_isa[0] = addr;
8478d5d45fbSJean Delvare 
8488d5d45fbSJean Delvare 	s_bridge = pci_dev_get(dev);
8498d5d45fbSJean Delvare 	if (i2c_add_driver(&via686a_driver)) {
8508d5d45fbSJean Delvare 		pci_dev_put(s_bridge);
8518d5d45fbSJean Delvare 		s_bridge = NULL;
8528d5d45fbSJean Delvare 	}
8538d5d45fbSJean Delvare 
8548d5d45fbSJean Delvare 	/* Always return failure here.  This is to allow other drivers to bind
8558d5d45fbSJean Delvare 	 * to this pci device.  We don't really want to have control over the
8568d5d45fbSJean Delvare 	 * pci device, we only wanted to read as few register values from it.
8578d5d45fbSJean Delvare 	 */
8588d5d45fbSJean Delvare 	return -ENODEV;
8598d5d45fbSJean Delvare }
8608d5d45fbSJean Delvare 
8618d5d45fbSJean Delvare static struct pci_driver via686a_pci_driver = {
8628d5d45fbSJean Delvare 	.name		= "via686a",
8638d5d45fbSJean Delvare 	.id_table	= via686a_pci_ids,
8648d5d45fbSJean Delvare 	.probe		= via686a_pci_probe,
8658d5d45fbSJean Delvare };
8668d5d45fbSJean Delvare 
8678d5d45fbSJean Delvare static int __init sm_via686a_init(void)
8688d5d45fbSJean Delvare {
8698d5d45fbSJean Delvare 	return pci_register_driver(&via686a_pci_driver);
8708d5d45fbSJean Delvare }
8718d5d45fbSJean Delvare 
8728d5d45fbSJean Delvare static void __exit sm_via686a_exit(void)
8738d5d45fbSJean Delvare {
8748d5d45fbSJean Delvare 	pci_unregister_driver(&via686a_pci_driver);
8758d5d45fbSJean Delvare 	if (s_bridge != NULL) {
8768d5d45fbSJean Delvare 		i2c_del_driver(&via686a_driver);
8778d5d45fbSJean Delvare 		pci_dev_put(s_bridge);
8788d5d45fbSJean Delvare 		s_bridge = NULL;
8798d5d45fbSJean Delvare 	}
8808d5d45fbSJean Delvare }
8818d5d45fbSJean Delvare 
8828d5d45fbSJean Delvare MODULE_AUTHOR("Ky�sti M�lkki <kmalkki@cc.hut.fi>, "
8838d5d45fbSJean Delvare 	      "Mark Studebaker <mdsxyz123@yahoo.com> "
8848d5d45fbSJean Delvare 	      "and Bob Dougherty <bobd@stanford.edu>");
8858d5d45fbSJean Delvare MODULE_DESCRIPTION("VIA 686A Sensor device");
8868d5d45fbSJean Delvare MODULE_LICENSE("GPL");
8878d5d45fbSJean Delvare 
8888d5d45fbSJean Delvare module_init(sm_via686a_init);
8898d5d45fbSJean Delvare module_exit(sm_via686a_exit);
890