xref: /openbmc/linux/drivers/hwmon/via686a.c (revision b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812)
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>,
696de0e25SJan Engelhardt 			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>
372ec342e6SJean Delvare #include <linux/platform_device.h>
38943b0830SMark M. Hoffman #include <linux/hwmon.h>
391e71a5a2SJean Delvare #include <linux/hwmon-sysfs.h>
40943b0830SMark M. Hoffman #include <linux/err.h>
418d5d45fbSJean Delvare #include <linux/init.h>
429a61bf63SIngo Molnar #include <linux/mutex.h>
43a5ebe668SJean Delvare #include <linux/sysfs.h>
44*b9acb64aSJean Delvare #include <linux/acpi.h>
458d5d45fbSJean Delvare #include <asm/io.h>
468d5d45fbSJean Delvare 
478d5d45fbSJean Delvare 
488d5d45fbSJean Delvare /* If force_addr is set to anything different from 0, we forcibly enable
498d5d45fbSJean Delvare    the device at the given address. */
5002002963SJean Delvare static unsigned short force_addr;
518d5d45fbSJean Delvare module_param(force_addr, ushort, 0);
528d5d45fbSJean Delvare MODULE_PARM_DESC(force_addr,
538d5d45fbSJean Delvare 		 "Initialize the base address of the sensors");
548d5d45fbSJean Delvare 
552ec342e6SJean Delvare static struct platform_device *pdev;
568d5d45fbSJean Delvare 
578d5d45fbSJean Delvare /*
588d5d45fbSJean Delvare    The Via 686a southbridge has a LM78-like chip integrated on the same IC.
598d5d45fbSJean Delvare    This driver is a customized copy of lm78.c
608d5d45fbSJean Delvare */
618d5d45fbSJean Delvare 
628d5d45fbSJean Delvare /* Many VIA686A constants specified below */
638d5d45fbSJean Delvare 
648d5d45fbSJean Delvare /* Length of ISA address segment */
658d5d45fbSJean Delvare #define VIA686A_EXTENT		0x80
668d5d45fbSJean Delvare #define VIA686A_BASE_REG	0x70
678d5d45fbSJean Delvare #define VIA686A_ENABLE_REG	0x74
688d5d45fbSJean Delvare 
698d5d45fbSJean Delvare /* The VIA686A registers */
708d5d45fbSJean Delvare /* ins numbered 0-4 */
718d5d45fbSJean Delvare #define VIA686A_REG_IN_MAX(nr)	(0x2b + ((nr) * 2))
728d5d45fbSJean Delvare #define VIA686A_REG_IN_MIN(nr)	(0x2c + ((nr) * 2))
738d5d45fbSJean Delvare #define VIA686A_REG_IN(nr)	(0x22 + (nr))
748d5d45fbSJean Delvare 
758d5d45fbSJean Delvare /* fans numbered 1-2 */
768d5d45fbSJean Delvare #define VIA686A_REG_FAN_MIN(nr)	(0x3a + (nr))
778d5d45fbSJean Delvare #define VIA686A_REG_FAN(nr)	(0x28 + (nr))
788d5d45fbSJean Delvare 
798d5d45fbSJean Delvare /* temps numbered 1-3 */
808d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP[]	= { 0x20, 0x21, 0x1f };
818d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_OVER[]	= { 0x39, 0x3d, 0x1d };
828d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_HYST[]	= { 0x3a, 0x3e, 0x1e };
838d5d45fbSJean Delvare /* bits 7-6 */
848d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW1	0x4b
858d5d45fbSJean Delvare /* 2 = bits 5-4, 3 = bits 7-6 */
868d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW23	0x49
878d5d45fbSJean Delvare 
888d5d45fbSJean Delvare #define VIA686A_REG_ALARM1	0x41
898d5d45fbSJean Delvare #define VIA686A_REG_ALARM2	0x42
908d5d45fbSJean Delvare #define VIA686A_REG_FANDIV	0x47
918d5d45fbSJean Delvare #define VIA686A_REG_CONFIG	0x40
928d5d45fbSJean Delvare /* The following register sets temp interrupt mode (bits 1-0 for temp1,
938d5d45fbSJean Delvare  3-2 for temp2, 5-4 for temp3).  Modes are:
948d5d45fbSJean Delvare     00 interrupt stays as long as value is out-of-range
958d5d45fbSJean Delvare     01 interrupt is cleared once register is read (default)
968d5d45fbSJean Delvare     10 comparator mode- like 00, but ignores hysteresis
978d5d45fbSJean Delvare     11 same as 00 */
988d5d45fbSJean Delvare #define VIA686A_REG_TEMP_MODE		0x4b
998d5d45fbSJean Delvare /* We'll just assume that you want to set all 3 simultaneously: */
1008d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_MASK		0x3F
1018d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_CONTINUOUS	0x00
1028d5d45fbSJean Delvare 
1038d5d45fbSJean Delvare /* Conversions. Limit checking is only done on the TO_REG
1048d5d45fbSJean Delvare    variants.
1058d5d45fbSJean Delvare 
1068d5d45fbSJean Delvare ********* VOLTAGE CONVERSIONS (Bob Dougherty) ********
1078d5d45fbSJean Delvare  From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew):
1088d5d45fbSJean Delvare  voltagefactor[0]=1.25/2628; (2628/1.25=2102.4)   // Vccp
1098d5d45fbSJean Delvare  voltagefactor[1]=1.25/2628; (2628/1.25=2102.4)   // +2.5V
1108d5d45fbSJean Delvare  voltagefactor[2]=1.67/2628; (2628/1.67=1573.7)   // +3.3V
1118d5d45fbSJean Delvare  voltagefactor[3]=2.6/2628;  (2628/2.60=1010.8)   // +5V
1128d5d45fbSJean Delvare  voltagefactor[4]=6.3/2628;  (2628/6.30=417.14)   // +12V
1138d5d45fbSJean Delvare  in[i]=(data[i+2]*25.0+133)*voltagefactor[i];
1148d5d45fbSJean Delvare  That is:
1158d5d45fbSJean Delvare  volts = (25*regVal+133)*factor
1168d5d45fbSJean Delvare  regVal = (volts/factor-133)/25
1178d5d45fbSJean Delvare  (These conversions were contributed by Jonathan Teh Soon Yew
1188d5d45fbSJean Delvare  <j.teh@iname.com>) */
1198d5d45fbSJean Delvare static inline u8 IN_TO_REG(long val, int inNum)
1208d5d45fbSJean Delvare {
1218d5d45fbSJean Delvare 	/* To avoid floating point, we multiply constants by 10 (100 for +12V).
1228d5d45fbSJean Delvare 	   Rounding is done (120500 is actually 133000 - 12500).
1238d5d45fbSJean Delvare 	   Remember that val is expressed in 0.001V/bit, which is why we divide
1248d5d45fbSJean Delvare 	   by an additional 10000 (100000 for +12V): 1000 for val and 10 (100)
1258d5d45fbSJean Delvare 	   for the constants. */
1268d5d45fbSJean Delvare 	if (inNum <= 1)
1278d5d45fbSJean Delvare 		return (u8)
1288d5d45fbSJean Delvare 		    SENSORS_LIMIT((val * 21024 - 1205000) / 250000, 0, 255);
1298d5d45fbSJean Delvare 	else if (inNum == 2)
1308d5d45fbSJean Delvare 		return (u8)
1318d5d45fbSJean Delvare 		    SENSORS_LIMIT((val * 15737 - 1205000) / 250000, 0, 255);
1328d5d45fbSJean Delvare 	else if (inNum == 3)
1338d5d45fbSJean Delvare 		return (u8)
1348d5d45fbSJean Delvare 		    SENSORS_LIMIT((val * 10108 - 1205000) / 250000, 0, 255);
1358d5d45fbSJean Delvare 	else
1368d5d45fbSJean Delvare 		return (u8)
1378d5d45fbSJean Delvare 		    SENSORS_LIMIT((val * 41714 - 12050000) / 2500000, 0, 255);
1388d5d45fbSJean Delvare }
1398d5d45fbSJean Delvare 
1408d5d45fbSJean Delvare static inline long IN_FROM_REG(u8 val, int inNum)
1418d5d45fbSJean Delvare {
1428d5d45fbSJean Delvare 	/* To avoid floating point, we multiply constants by 10 (100 for +12V).
1438d5d45fbSJean Delvare 	   We also multiply them by 1000 because we want 0.001V/bit for the
1448d5d45fbSJean Delvare 	   output value. Rounding is done. */
1458d5d45fbSJean Delvare 	if (inNum <= 1)
1468d5d45fbSJean Delvare 		return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024);
1478d5d45fbSJean Delvare 	else if (inNum == 2)
1488d5d45fbSJean Delvare 		return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737);
1498d5d45fbSJean Delvare 	else if (inNum == 3)
1508d5d45fbSJean Delvare 		return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108);
1518d5d45fbSJean Delvare 	else
1528d5d45fbSJean Delvare 		return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714);
1538d5d45fbSJean Delvare }
1548d5d45fbSJean Delvare 
1558d5d45fbSJean Delvare /********* FAN RPM CONVERSIONS ********/
1568d5d45fbSJean Delvare /* Higher register values = slower fans (the fan's strobe gates a counter).
1578d5d45fbSJean Delvare  But this chip saturates back at 0, not at 255 like all the other chips.
1588d5d45fbSJean Delvare  So, 0 means 0 RPM */
1598d5d45fbSJean Delvare static inline u8 FAN_TO_REG(long rpm, int div)
1608d5d45fbSJean Delvare {
1618d5d45fbSJean Delvare 	if (rpm == 0)
1628d5d45fbSJean Delvare 		return 0;
1638d5d45fbSJean Delvare 	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
1648d5d45fbSJean Delvare 	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255);
1658d5d45fbSJean Delvare }
1668d5d45fbSJean Delvare 
1678d5d45fbSJean Delvare #define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div)))
1688d5d45fbSJean Delvare 
1698d5d45fbSJean Delvare /******** TEMP CONVERSIONS (Bob Dougherty) *********/
1708d5d45fbSJean Delvare /* linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew)
1718d5d45fbSJean Delvare       if(temp<169)
1728d5d45fbSJean Delvare 	      return double(temp)*0.427-32.08;
1738d5d45fbSJean Delvare       else if(temp>=169 && temp<=202)
1748d5d45fbSJean Delvare 	      return double(temp)*0.582-58.16;
1758d5d45fbSJean Delvare       else
1768d5d45fbSJean Delvare 	      return double(temp)*0.924-127.33;
1778d5d45fbSJean Delvare 
1788d5d45fbSJean Delvare  A fifth-order polynomial fits the unofficial data (provided by Alex van
1798d5d45fbSJean Delvare  Kaam <darkside@chello.nl>) a bit better.  It also give more reasonable
1808d5d45fbSJean Delvare  numbers on my machine (ie. they agree with what my BIOS tells me).
1818d5d45fbSJean Delvare  Here's the fifth-order fit to the 8-bit data:
1828d5d45fbSJean Delvare  temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 -
1838d5d45fbSJean Delvare 	2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0.
1848d5d45fbSJean Delvare 
1858d5d45fbSJean Delvare  (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for
1868d5d45fbSJean Delvare  finding my typos in this formula!)
1878d5d45fbSJean Delvare 
1888d5d45fbSJean Delvare  Alas, none of the elegant function-fit solutions will work because we
1898d5d45fbSJean Delvare  aren't allowed to use floating point in the kernel and doing it with
1908d5d45fbSJean Delvare  integers doesn't provide enough precision.  So we'll do boring old
1918d5d45fbSJean Delvare  look-up table stuff.  The unofficial data (see below) have effectively
1928d5d45fbSJean Delvare  7-bit resolution (they are rounded to the nearest degree).  I'm assuming
1938d5d45fbSJean Delvare  that the transfer function of the device is monotonic and smooth, so a
1948d5d45fbSJean Delvare  smooth function fit to the data will allow us to get better precision.
1958d5d45fbSJean Delvare  I used the 5th-order poly fit described above and solved for
1968d5d45fbSJean Delvare  VIA register values 0-255.  I *10 before rounding, so we get tenth-degree
1978d5d45fbSJean Delvare  precision.  (I could have done all 1024 values for our 10-bit readings,
1988d5d45fbSJean Delvare  but the function is very linear in the useful range (0-80 deg C), so
1998d5d45fbSJean Delvare  we'll just use linear interpolation for 10-bit readings.)  So, tempLUT
2008d5d45fbSJean Delvare  is the temp at via register values 0-255: */
201088341bdSJean Delvare static const s16 tempLUT[] =
2028d5d45fbSJean Delvare { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
2038d5d45fbSJean Delvare 	-503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
2048d5d45fbSJean Delvare 	-362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
2058d5d45fbSJean Delvare 	-255, -246, -237, -229, -220, -212, -204, -196, -188, -180,
2068d5d45fbSJean Delvare 	-173, -166, -159, -152, -145, -139, -132, -126, -120, -114,
2078d5d45fbSJean Delvare 	-108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49,
2088d5d45fbSJean Delvare 	-44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16,
2098d5d45fbSJean Delvare 	20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84,
2108d5d45fbSJean Delvare 	88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138,
2118d5d45fbSJean Delvare 	142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189,
2128d5d45fbSJean Delvare 	193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241,
2138d5d45fbSJean Delvare 	245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294,
2148d5d45fbSJean Delvare 	299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348,
2158d5d45fbSJean Delvare 	353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404,
2168d5d45fbSJean Delvare 	409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464,
2178d5d45fbSJean Delvare 	469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532,
2188d5d45fbSJean Delvare 	538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614,
2198d5d45fbSJean Delvare 	621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718,
2208d5d45fbSJean Delvare 	728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856,
2218d5d45fbSJean Delvare 	870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044,
2228d5d45fbSJean Delvare 	1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252,
2238d5d45fbSJean Delvare 	1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462
2248d5d45fbSJean Delvare };
2258d5d45fbSJean Delvare 
2268d5d45fbSJean Delvare /* the original LUT values from Alex van Kaam <darkside@chello.nl>
2278d5d45fbSJean Delvare    (for via register values 12-240):
2288d5d45fbSJean Delvare {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31,
2298d5d45fbSJean Delvare -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15,
2308d5d45fbSJean Delvare -15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3,
2318d5d45fbSJean 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,
2328d5d45fbSJean 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,
2338d5d45fbSJean 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,
2348d5d45fbSJean 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,
2358d5d45fbSJean 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,
2368d5d45fbSJean 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,
2378d5d45fbSJean Delvare 85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110};
2388d5d45fbSJean Delvare 
2398d5d45fbSJean Delvare 
2408d5d45fbSJean Delvare  Here's the reverse LUT.  I got it by doing a 6-th order poly fit (needed
2418d5d45fbSJean Delvare  an extra term for a good fit to these inverse data!) and then
2428d5d45fbSJean Delvare  solving for each temp value from -50 to 110 (the useable range for
2438d5d45fbSJean Delvare  this chip).  Here's the fit:
2448d5d45fbSJean Delvare  viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4
2458d5d45fbSJean Delvare  - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
2468d5d45fbSJean Delvare  Note that n=161: */
2478d5d45fbSJean Delvare static const u8 viaLUT[] =
2488d5d45fbSJean Delvare { 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
2498d5d45fbSJean Delvare 	23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
2508d5d45fbSJean Delvare 	41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
2518d5d45fbSJean Delvare 	69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100,
2528d5d45fbSJean Delvare 	103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129,
2538d5d45fbSJean Delvare 	131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156,
2548d5d45fbSJean Delvare 	158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
2558d5d45fbSJean Delvare 	182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199,
2568d5d45fbSJean Delvare 	200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213,
2578d5d45fbSJean Delvare 	214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224,
2588d5d45fbSJean Delvare 	225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232,
2598d5d45fbSJean Delvare 	233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
2608d5d45fbSJean Delvare 	239, 240
2618d5d45fbSJean Delvare };
2628d5d45fbSJean Delvare 
2638d5d45fbSJean Delvare /* Converting temps to (8-bit) hyst and over registers
2648d5d45fbSJean Delvare    No interpolation here.
2658d5d45fbSJean Delvare    The +50 is because the temps start at -50 */
2668d5d45fbSJean Delvare static inline u8 TEMP_TO_REG(long val)
2678d5d45fbSJean Delvare {
2688d5d45fbSJean Delvare 	return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 :
2698d5d45fbSJean Delvare 		      (val < 0 ? val - 500 : val + 500) / 1000 + 50];
2708d5d45fbSJean Delvare }
2718d5d45fbSJean Delvare 
2728d5d45fbSJean Delvare /* for 8-bit temperature hyst and over registers */
273088341bdSJean Delvare #define TEMP_FROM_REG(val)	((long)tempLUT[val] * 100)
2748d5d45fbSJean Delvare 
2758d5d45fbSJean Delvare /* for 10-bit temperature readings */
2768d5d45fbSJean Delvare static inline long TEMP_FROM_REG10(u16 val)
2778d5d45fbSJean Delvare {
2788d5d45fbSJean Delvare 	u16 eightBits = val >> 2;
2798d5d45fbSJean Delvare 	u16 twoBits = val & 3;
2808d5d45fbSJean Delvare 
2818d5d45fbSJean Delvare 	/* no interpolation for these */
2828d5d45fbSJean Delvare 	if (twoBits == 0 || eightBits == 255)
2838d5d45fbSJean Delvare 		return TEMP_FROM_REG(eightBits);
2848d5d45fbSJean Delvare 
2858d5d45fbSJean Delvare 	/* do some linear interpolation */
2868d5d45fbSJean Delvare 	return (tempLUT[eightBits] * (4 - twoBits) +
2878d5d45fbSJean Delvare 		tempLUT[eightBits + 1] * twoBits) * 25;
2888d5d45fbSJean Delvare }
2898d5d45fbSJean Delvare 
2908d5d45fbSJean Delvare #define DIV_FROM_REG(val) (1 << (val))
2918d5d45fbSJean Delvare #define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
2928d5d45fbSJean Delvare 
293ed6bafbfSJean Delvare /* For each registered chip, we need to keep some data in memory.
294ed6bafbfSJean Delvare    The structure is dynamically allocated. */
2958d5d45fbSJean Delvare struct via686a_data {
2962ec342e6SJean Delvare 	unsigned short addr;
2972ec342e6SJean Delvare 	const char *name;
2981beeffe4STony Jones 	struct device *hwmon_dev;
2999a61bf63SIngo Molnar 	struct mutex update_lock;
3008d5d45fbSJean Delvare 	char valid;		/* !=0 if following fields are valid */
3018d5d45fbSJean Delvare 	unsigned long last_updated;	/* In jiffies */
3028d5d45fbSJean Delvare 
3038d5d45fbSJean Delvare 	u8 in[5];		/* Register value */
3048d5d45fbSJean Delvare 	u8 in_max[5];		/* Register value */
3058d5d45fbSJean Delvare 	u8 in_min[5];		/* Register value */
3068d5d45fbSJean Delvare 	u8 fan[2];		/* Register value */
3078d5d45fbSJean Delvare 	u8 fan_min[2];		/* Register value */
3088d5d45fbSJean Delvare 	u16 temp[3];		/* Register value 10 bit */
3098d5d45fbSJean Delvare 	u8 temp_over[3];	/* Register value */
3108d5d45fbSJean Delvare 	u8 temp_hyst[3];	/* Register value */
3118d5d45fbSJean Delvare 	u8 fan_div[2];		/* Register encoding, shifted right */
3128d5d45fbSJean Delvare 	u16 alarms;		/* Register encoding, combined */
3138d5d45fbSJean Delvare };
3148d5d45fbSJean Delvare 
3158d5d45fbSJean Delvare static struct pci_dev *s_bridge;	/* pointer to the (only) via686a */
3168d5d45fbSJean Delvare 
3172ec342e6SJean Delvare static int via686a_probe(struct platform_device *pdev);
318d0546128SJean Delvare static int __devexit via686a_remove(struct platform_device *pdev);
3198d5d45fbSJean Delvare 
3202ec342e6SJean Delvare static inline int via686a_read_value(struct via686a_data *data, u8 reg)
3218d5d45fbSJean Delvare {
3222ec342e6SJean Delvare 	return inb_p(data->addr + reg);
3238d5d45fbSJean Delvare }
3248d5d45fbSJean Delvare 
3252ec342e6SJean Delvare static inline void via686a_write_value(struct via686a_data *data, u8 reg,
3268d5d45fbSJean Delvare 				       u8 value)
3278d5d45fbSJean Delvare {
3282ec342e6SJean Delvare 	outb_p(value, data->addr + reg);
3298d5d45fbSJean Delvare }
3308d5d45fbSJean Delvare 
3318d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev);
3322ec342e6SJean Delvare static void via686a_init_device(struct via686a_data *data);
3338d5d45fbSJean Delvare 
3348d5d45fbSJean Delvare /* following are the sysfs callback functions */
3358d5d45fbSJean Delvare 
3368d5d45fbSJean Delvare /* 7 voltage sensors */
3371e71a5a2SJean Delvare static ssize_t show_in(struct device *dev, struct device_attribute *da,
3381e71a5a2SJean Delvare 		char *buf) {
3398d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
3401e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3411e71a5a2SJean Delvare 	int nr = attr->index;
3428d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr));
3438d5d45fbSJean Delvare }
3448d5d45fbSJean Delvare 
3451e71a5a2SJean Delvare static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
3461e71a5a2SJean Delvare 		char *buf) {
3478d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
3481e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3491e71a5a2SJean Delvare 	int nr = attr->index;
3508d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr));
3518d5d45fbSJean Delvare }
3528d5d45fbSJean Delvare 
3531e71a5a2SJean Delvare static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
3541e71a5a2SJean Delvare 		char *buf) {
3558d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
3561e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3571e71a5a2SJean Delvare 	int nr = attr->index;
3588d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
3598d5d45fbSJean Delvare }
3608d5d45fbSJean Delvare 
3611e71a5a2SJean Delvare static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
3621e71a5a2SJean Delvare 		const char *buf, size_t count) {
3632ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
3641e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3651e71a5a2SJean Delvare 	int nr = attr->index;
3668d5d45fbSJean Delvare 	unsigned long val = simple_strtoul(buf, NULL, 10);
3678d5d45fbSJean Delvare 
3689a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
3698d5d45fbSJean Delvare 	data->in_min[nr] = IN_TO_REG(val, nr);
3702ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_IN_MIN(nr),
3718d5d45fbSJean Delvare 			data->in_min[nr]);
3729a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
3738d5d45fbSJean Delvare 	return count;
3748d5d45fbSJean Delvare }
3751e71a5a2SJean Delvare static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
3761e71a5a2SJean Delvare 		const char *buf, size_t count) {
3772ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
3781e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3791e71a5a2SJean Delvare 	int nr = attr->index;
3808d5d45fbSJean Delvare 	unsigned long val = simple_strtoul(buf, NULL, 10);
3818d5d45fbSJean Delvare 
3829a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
3838d5d45fbSJean Delvare 	data->in_max[nr] = IN_TO_REG(val, nr);
3842ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_IN_MAX(nr),
3858d5d45fbSJean Delvare 			data->in_max[nr]);
3869a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
3878d5d45fbSJean Delvare 	return count;
3888d5d45fbSJean Delvare }
3898d5d45fbSJean Delvare #define show_in_offset(offset)					\
3901e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
3911e71a5a2SJean Delvare 		show_in, NULL, offset);				\
3921e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
3931e71a5a2SJean Delvare 		show_in_min, set_in_min, offset);		\
3941e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
3951e71a5a2SJean Delvare 		show_in_max, set_in_max, offset);
3968d5d45fbSJean Delvare 
3978d5d45fbSJean Delvare show_in_offset(0);
3988d5d45fbSJean Delvare show_in_offset(1);
3998d5d45fbSJean Delvare show_in_offset(2);
4008d5d45fbSJean Delvare show_in_offset(3);
4018d5d45fbSJean Delvare show_in_offset(4);
4028d5d45fbSJean Delvare 
4038d5d45fbSJean Delvare /* 3 temperatures */
4041e71a5a2SJean Delvare static ssize_t show_temp(struct device *dev, struct device_attribute *da,
4051e71a5a2SJean Delvare 		char *buf) {
4068d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4071e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4081e71a5a2SJean Delvare 	int nr = attr->index;
4098d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
4108d5d45fbSJean Delvare }
4111e71a5a2SJean Delvare static ssize_t show_temp_over(struct device *dev, struct device_attribute *da,
4121e71a5a2SJean Delvare 		char *buf) {
4138d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4141e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4151e71a5a2SJean Delvare 	int nr = attr->index;
4168d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
4178d5d45fbSJean Delvare }
4181e71a5a2SJean Delvare static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da,
4191e71a5a2SJean Delvare 		char *buf) {
4208d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4211e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4221e71a5a2SJean Delvare 	int nr = attr->index;
4238d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
4248d5d45fbSJean Delvare }
4251e71a5a2SJean Delvare static ssize_t set_temp_over(struct device *dev, struct device_attribute *da,
4261e71a5a2SJean Delvare 		const char *buf, size_t count) {
4272ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
4281e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4291e71a5a2SJean Delvare 	int nr = attr->index;
4308d5d45fbSJean Delvare 	int val = simple_strtol(buf, NULL, 10);
4318d5d45fbSJean Delvare 
4329a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4338d5d45fbSJean Delvare 	data->temp_over[nr] = TEMP_TO_REG(val);
4342ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr],
4358d5d45fbSJean Delvare 			    data->temp_over[nr]);
4369a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4378d5d45fbSJean Delvare 	return count;
4388d5d45fbSJean Delvare }
4391e71a5a2SJean Delvare static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da,
4401e71a5a2SJean Delvare 		const char *buf, size_t count) {
4412ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
4421e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4431e71a5a2SJean Delvare 	int nr = attr->index;
4448d5d45fbSJean Delvare 	int val = simple_strtol(buf, NULL, 10);
4458d5d45fbSJean Delvare 
4469a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4478d5d45fbSJean Delvare 	data->temp_hyst[nr] = TEMP_TO_REG(val);
4482ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr],
4498d5d45fbSJean Delvare 			    data->temp_hyst[nr]);
4509a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4518d5d45fbSJean Delvare 	return count;
4528d5d45fbSJean Delvare }
4538d5d45fbSJean Delvare #define show_temp_offset(offset)					\
4541e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,		\
4551e71a5a2SJean Delvare 		show_temp, NULL, offset - 1);				\
4561e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,	\
4571e71a5a2SJean Delvare 		show_temp_over, set_temp_over, offset - 1);		\
4581e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR,	\
4591e71a5a2SJean Delvare 		show_temp_hyst, set_temp_hyst, offset - 1);
4608d5d45fbSJean Delvare 
4618d5d45fbSJean Delvare show_temp_offset(1);
4628d5d45fbSJean Delvare show_temp_offset(2);
4638d5d45fbSJean Delvare show_temp_offset(3);
4648d5d45fbSJean Delvare 
4658d5d45fbSJean Delvare /* 2 Fans */
4661e71a5a2SJean Delvare static ssize_t show_fan(struct device *dev, struct device_attribute *da,
4671e71a5a2SJean Delvare 		char *buf) {
4688d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4691e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4701e71a5a2SJean Delvare 	int nr = attr->index;
4718d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
4728d5d45fbSJean Delvare 				DIV_FROM_REG(data->fan_div[nr])) );
4738d5d45fbSJean Delvare }
4741e71a5a2SJean Delvare static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
4751e71a5a2SJean Delvare 		char *buf) {
4768d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4771e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4781e71a5a2SJean Delvare 	int nr = attr->index;
4798d5d45fbSJean Delvare 	return sprintf(buf, "%d\n",
4808d5d45fbSJean Delvare 		FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) );
4818d5d45fbSJean Delvare }
4821e71a5a2SJean Delvare static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
4831e71a5a2SJean Delvare 		char *buf) {
4848d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4851e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4861e71a5a2SJean Delvare 	int nr = attr->index;
4878d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
4888d5d45fbSJean Delvare }
4891e71a5a2SJean Delvare static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
4901e71a5a2SJean Delvare 		const char *buf, size_t count) {
4912ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
4921e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4931e71a5a2SJean Delvare 	int nr = attr->index;
4948d5d45fbSJean Delvare 	int val = simple_strtol(buf, NULL, 10);
4958d5d45fbSJean Delvare 
4969a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4978d5d45fbSJean Delvare 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
4982ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
4999a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
5008d5d45fbSJean Delvare 	return count;
5018d5d45fbSJean Delvare }
5021e71a5a2SJean Delvare static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
5031e71a5a2SJean Delvare 		const char *buf, size_t count) {
5042ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
5051e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5061e71a5a2SJean Delvare 	int nr = attr->index;
5078d5d45fbSJean Delvare 	int val = simple_strtol(buf, NULL, 10);
5088d5d45fbSJean Delvare 	int old;
5098d5d45fbSJean Delvare 
5109a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
5112ec342e6SJean Delvare 	old = via686a_read_value(data, VIA686A_REG_FANDIV);
5128d5d45fbSJean Delvare 	data->fan_div[nr] = DIV_TO_REG(val);
5138d5d45fbSJean Delvare 	old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
5142ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_FANDIV, old);
5159a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
5168d5d45fbSJean Delvare 	return count;
5178d5d45fbSJean Delvare }
5188d5d45fbSJean Delvare 
5198d5d45fbSJean Delvare #define show_fan_offset(offset)						\
5201e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,			\
5211e71a5a2SJean Delvare 		show_fan, NULL, offset - 1);				\
5221e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
5231e71a5a2SJean Delvare 		show_fan_min, set_fan_min, offset - 1);			\
5241e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
5251e71a5a2SJean Delvare 		show_fan_div, set_fan_div, offset - 1);
5268d5d45fbSJean Delvare 
5278d5d45fbSJean Delvare show_fan_offset(1);
5288d5d45fbSJean Delvare show_fan_offset(2);
5298d5d45fbSJean Delvare 
5308d5d45fbSJean Delvare /* Alarms */
5318d5d45fbSJean Delvare static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) {
5328d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5338d5d45fbSJean Delvare 	return sprintf(buf, "%u\n", data->alarms);
5348d5d45fbSJean Delvare }
5358d5d45fbSJean Delvare static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
5368d5d45fbSJean Delvare 
53713ff05e9SJean Delvare static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
53813ff05e9SJean Delvare 			  char *buf)
53913ff05e9SJean Delvare {
54013ff05e9SJean Delvare 	int bitnr = to_sensor_dev_attr(attr)->index;
54113ff05e9SJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
54213ff05e9SJean Delvare 	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
54313ff05e9SJean Delvare }
54413ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
54513ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
54613ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
54713ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
54813ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
54913ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
55013ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 11);
55113ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 15);
55213ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
55313ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
55413ff05e9SJean Delvare 
5552ec342e6SJean Delvare static ssize_t show_name(struct device *dev, struct device_attribute
5562ec342e6SJean Delvare 			 *devattr, char *buf)
5572ec342e6SJean Delvare {
5582ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
5592ec342e6SJean Delvare 	return sprintf(buf, "%s\n", data->name);
5602ec342e6SJean Delvare }
5612ec342e6SJean Delvare static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
5622ec342e6SJean Delvare 
563a5ebe668SJean Delvare static struct attribute *via686a_attributes[] = {
5641e71a5a2SJean Delvare 	&sensor_dev_attr_in0_input.dev_attr.attr,
5651e71a5a2SJean Delvare 	&sensor_dev_attr_in1_input.dev_attr.attr,
5661e71a5a2SJean Delvare 	&sensor_dev_attr_in2_input.dev_attr.attr,
5671e71a5a2SJean Delvare 	&sensor_dev_attr_in3_input.dev_attr.attr,
5681e71a5a2SJean Delvare 	&sensor_dev_attr_in4_input.dev_attr.attr,
5691e71a5a2SJean Delvare 	&sensor_dev_attr_in0_min.dev_attr.attr,
5701e71a5a2SJean Delvare 	&sensor_dev_attr_in1_min.dev_attr.attr,
5711e71a5a2SJean Delvare 	&sensor_dev_attr_in2_min.dev_attr.attr,
5721e71a5a2SJean Delvare 	&sensor_dev_attr_in3_min.dev_attr.attr,
5731e71a5a2SJean Delvare 	&sensor_dev_attr_in4_min.dev_attr.attr,
5741e71a5a2SJean Delvare 	&sensor_dev_attr_in0_max.dev_attr.attr,
5751e71a5a2SJean Delvare 	&sensor_dev_attr_in1_max.dev_attr.attr,
5761e71a5a2SJean Delvare 	&sensor_dev_attr_in2_max.dev_attr.attr,
5771e71a5a2SJean Delvare 	&sensor_dev_attr_in3_max.dev_attr.attr,
5781e71a5a2SJean Delvare 	&sensor_dev_attr_in4_max.dev_attr.attr,
57913ff05e9SJean Delvare 	&sensor_dev_attr_in0_alarm.dev_attr.attr,
58013ff05e9SJean Delvare 	&sensor_dev_attr_in1_alarm.dev_attr.attr,
58113ff05e9SJean Delvare 	&sensor_dev_attr_in2_alarm.dev_attr.attr,
58213ff05e9SJean Delvare 	&sensor_dev_attr_in3_alarm.dev_attr.attr,
58313ff05e9SJean Delvare 	&sensor_dev_attr_in4_alarm.dev_attr.attr,
584a5ebe668SJean Delvare 
5851e71a5a2SJean Delvare 	&sensor_dev_attr_temp1_input.dev_attr.attr,
5861e71a5a2SJean Delvare 	&sensor_dev_attr_temp2_input.dev_attr.attr,
5871e71a5a2SJean Delvare 	&sensor_dev_attr_temp3_input.dev_attr.attr,
5881e71a5a2SJean Delvare 	&sensor_dev_attr_temp1_max.dev_attr.attr,
5891e71a5a2SJean Delvare 	&sensor_dev_attr_temp2_max.dev_attr.attr,
5901e71a5a2SJean Delvare 	&sensor_dev_attr_temp3_max.dev_attr.attr,
5911e71a5a2SJean Delvare 	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
5921e71a5a2SJean Delvare 	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
5931e71a5a2SJean Delvare 	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
59413ff05e9SJean Delvare 	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
59513ff05e9SJean Delvare 	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
59613ff05e9SJean Delvare 	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
597a5ebe668SJean Delvare 
5981e71a5a2SJean Delvare 	&sensor_dev_attr_fan1_input.dev_attr.attr,
5991e71a5a2SJean Delvare 	&sensor_dev_attr_fan2_input.dev_attr.attr,
6001e71a5a2SJean Delvare 	&sensor_dev_attr_fan1_min.dev_attr.attr,
6011e71a5a2SJean Delvare 	&sensor_dev_attr_fan2_min.dev_attr.attr,
6021e71a5a2SJean Delvare 	&sensor_dev_attr_fan1_div.dev_attr.attr,
6031e71a5a2SJean Delvare 	&sensor_dev_attr_fan2_div.dev_attr.attr,
60413ff05e9SJean Delvare 	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
60513ff05e9SJean Delvare 	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
606a5ebe668SJean Delvare 
607a5ebe668SJean Delvare 	&dev_attr_alarms.attr,
6082ec342e6SJean Delvare 	&dev_attr_name.attr,
609a5ebe668SJean Delvare 	NULL
610a5ebe668SJean Delvare };
611a5ebe668SJean Delvare 
612a5ebe668SJean Delvare static const struct attribute_group via686a_group = {
613a5ebe668SJean Delvare 	.attrs = via686a_attributes,
614a5ebe668SJean Delvare };
615a5ebe668SJean Delvare 
6162ec342e6SJean Delvare static struct platform_driver via686a_driver = {
617cdaf7934SLaurent Riffard 	.driver = {
61887218842SJean Delvare 		.owner	= THIS_MODULE,
6198d5d45fbSJean Delvare 		.name	= "via686a",
620cdaf7934SLaurent Riffard 	},
6212ec342e6SJean Delvare 	.probe		= via686a_probe,
6222ec342e6SJean Delvare 	.remove		= __devexit_p(via686a_remove),
6238d5d45fbSJean Delvare };
6248d5d45fbSJean Delvare 
6258d5d45fbSJean Delvare 
6268d5d45fbSJean Delvare /* This is called when the module is loaded */
6272ec342e6SJean Delvare static int __devinit via686a_probe(struct platform_device *pdev)
6288d5d45fbSJean Delvare {
6298d5d45fbSJean Delvare 	struct via686a_data *data;
6302ec342e6SJean Delvare 	struct resource *res;
6312ec342e6SJean Delvare 	int err;
6328d5d45fbSJean Delvare 
6338d5d45fbSJean Delvare 	/* Reserve the ISA region */
6342ec342e6SJean Delvare 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
6352ec342e6SJean Delvare 	if (!request_region(res->start, VIA686A_EXTENT,
636cdaf7934SLaurent Riffard 			    via686a_driver.driver.name)) {
6372ec342e6SJean Delvare 		dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
6382ec342e6SJean Delvare 			(unsigned long)res->start, (unsigned long)res->end);
6398d5d45fbSJean Delvare 		return -ENODEV;
6408d5d45fbSJean Delvare 	}
6418d5d45fbSJean Delvare 
642ba9c2e8dSDeepak Saxena 	if (!(data = kzalloc(sizeof(struct via686a_data), GFP_KERNEL))) {
6438d5d45fbSJean Delvare 		err = -ENOMEM;
644943b0830SMark M. Hoffman 		goto exit_release;
6458d5d45fbSJean Delvare 	}
6468d5d45fbSJean Delvare 
6472ec342e6SJean Delvare 	platform_set_drvdata(pdev, data);
6482ec342e6SJean Delvare 	data->addr = res->start;
6492ec342e6SJean Delvare 	data->name = "via686a";
6509a61bf63SIngo Molnar 	mutex_init(&data->update_lock);
6518d5d45fbSJean Delvare 
6528d5d45fbSJean Delvare 	/* Initialize the VIA686A chip */
6532ec342e6SJean Delvare 	via686a_init_device(data);
6548d5d45fbSJean Delvare 
6558d5d45fbSJean Delvare 	/* Register sysfs hooks */
6562ec342e6SJean Delvare 	if ((err = sysfs_create_group(&pdev->dev.kobj, &via686a_group)))
6572ec342e6SJean Delvare 		goto exit_free;
658a5ebe668SJean Delvare 
6591beeffe4STony Jones 	data->hwmon_dev = hwmon_device_register(&pdev->dev);
6601beeffe4STony Jones 	if (IS_ERR(data->hwmon_dev)) {
6611beeffe4STony Jones 		err = PTR_ERR(data->hwmon_dev);
662a5ebe668SJean Delvare 		goto exit_remove_files;
663943b0830SMark M. Hoffman 	}
664943b0830SMark M. Hoffman 
6658d5d45fbSJean Delvare 	return 0;
6668d5d45fbSJean Delvare 
667a5ebe668SJean Delvare exit_remove_files:
6682ec342e6SJean Delvare 	sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
669943b0830SMark M. Hoffman exit_free:
6708d5d45fbSJean Delvare 	kfree(data);
671943b0830SMark M. Hoffman exit_release:
6722ec342e6SJean Delvare 	release_region(res->start, VIA686A_EXTENT);
6738d5d45fbSJean Delvare 	return err;
6748d5d45fbSJean Delvare }
6758d5d45fbSJean Delvare 
6762ec342e6SJean Delvare static int __devexit via686a_remove(struct platform_device *pdev)
6778d5d45fbSJean Delvare {
6782ec342e6SJean Delvare 	struct via686a_data *data = platform_get_drvdata(pdev);
6798d5d45fbSJean Delvare 
6801beeffe4STony Jones 	hwmon_device_unregister(data->hwmon_dev);
6812ec342e6SJean Delvare 	sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
682943b0830SMark M. Hoffman 
6832ec342e6SJean Delvare 	release_region(data->addr, VIA686A_EXTENT);
6842ec342e6SJean Delvare 	platform_set_drvdata(pdev, NULL);
685943b0830SMark M. Hoffman 	kfree(data);
6868d5d45fbSJean Delvare 
6878d5d45fbSJean Delvare 	return 0;
6888d5d45fbSJean Delvare }
6898d5d45fbSJean Delvare 
6902ec342e6SJean Delvare static void __devinit via686a_init_device(struct via686a_data *data)
6918d5d45fbSJean Delvare {
6928d5d45fbSJean Delvare 	u8 reg;
6938d5d45fbSJean Delvare 
6948d5d45fbSJean Delvare 	/* Start monitoring */
6952ec342e6SJean Delvare 	reg = via686a_read_value(data, VIA686A_REG_CONFIG);
6962ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
6978d5d45fbSJean Delvare 
6988d5d45fbSJean Delvare 	/* Configure temp interrupt mode for continuous-interrupt operation */
6992ec342e6SJean Delvare 	reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
7002ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_TEMP_MODE,
70158fe0809SJean Delvare 			    (reg & ~VIA686A_TEMP_MODE_MASK)
70258fe0809SJean Delvare 			    | VIA686A_TEMP_MODE_CONTINUOUS);
7038d5d45fbSJean Delvare }
7048d5d45fbSJean Delvare 
7058d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev)
7068d5d45fbSJean Delvare {
7072ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
7088d5d45fbSJean Delvare 	int i;
7098d5d45fbSJean Delvare 
7109a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
7118d5d45fbSJean Delvare 
7128d5d45fbSJean Delvare 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
7138d5d45fbSJean Delvare 	    || !data->valid) {
7148d5d45fbSJean Delvare 		for (i = 0; i <= 4; i++) {
7158d5d45fbSJean Delvare 			data->in[i] =
7162ec342e6SJean Delvare 			    via686a_read_value(data, VIA686A_REG_IN(i));
7172ec342e6SJean Delvare 			data->in_min[i] = via686a_read_value(data,
7188d5d45fbSJean Delvare 							     VIA686A_REG_IN_MIN
7198d5d45fbSJean Delvare 							     (i));
7208d5d45fbSJean Delvare 			data->in_max[i] =
7212ec342e6SJean Delvare 			    via686a_read_value(data, VIA686A_REG_IN_MAX(i));
7228d5d45fbSJean Delvare 		}
7238d5d45fbSJean Delvare 		for (i = 1; i <= 2; i++) {
7248d5d45fbSJean Delvare 			data->fan[i - 1] =
7252ec342e6SJean Delvare 			    via686a_read_value(data, VIA686A_REG_FAN(i));
7262ec342e6SJean Delvare 			data->fan_min[i - 1] = via686a_read_value(data,
7278d5d45fbSJean Delvare 						     VIA686A_REG_FAN_MIN(i));
7288d5d45fbSJean Delvare 		}
7298d5d45fbSJean Delvare 		for (i = 0; i <= 2; i++) {
7302ec342e6SJean Delvare 			data->temp[i] = via686a_read_value(data,
7318d5d45fbSJean Delvare 						 VIA686A_REG_TEMP[i]) << 2;
7328d5d45fbSJean Delvare 			data->temp_over[i] =
7332ec342e6SJean Delvare 			    via686a_read_value(data,
7348d5d45fbSJean Delvare 					       VIA686A_REG_TEMP_OVER[i]);
7358d5d45fbSJean Delvare 			data->temp_hyst[i] =
7362ec342e6SJean Delvare 			    via686a_read_value(data,
7378d5d45fbSJean Delvare 					       VIA686A_REG_TEMP_HYST[i]);
7388d5d45fbSJean Delvare 		}
7398d5d45fbSJean Delvare 		/* add in lower 2 bits
7408d5d45fbSJean Delvare 		   temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1
7418d5d45fbSJean Delvare 		   temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
7428d5d45fbSJean Delvare 		   temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
7438d5d45fbSJean Delvare 		 */
7442ec342e6SJean Delvare 		data->temp[0] |= (via686a_read_value(data,
7458d5d45fbSJean Delvare 						     VIA686A_REG_TEMP_LOW1)
7468d5d45fbSJean Delvare 				  & 0xc0) >> 6;
7478d5d45fbSJean Delvare 		data->temp[1] |=
7482ec342e6SJean Delvare 		    (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
7498d5d45fbSJean Delvare 		     0x30) >> 4;
7508d5d45fbSJean Delvare 		data->temp[2] |=
7512ec342e6SJean Delvare 		    (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
7528d5d45fbSJean Delvare 		     0xc0) >> 6;
7538d5d45fbSJean Delvare 
7542ec342e6SJean Delvare 		i = via686a_read_value(data, VIA686A_REG_FANDIV);
7558d5d45fbSJean Delvare 		data->fan_div[0] = (i >> 4) & 0x03;
7568d5d45fbSJean Delvare 		data->fan_div[1] = i >> 6;
7578d5d45fbSJean Delvare 		data->alarms =
7582ec342e6SJean Delvare 		    via686a_read_value(data,
7598d5d45fbSJean Delvare 				       VIA686A_REG_ALARM1) |
7602ec342e6SJean Delvare 		    (via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
7618d5d45fbSJean Delvare 		data->last_updated = jiffies;
7628d5d45fbSJean Delvare 		data->valid = 1;
7638d5d45fbSJean Delvare 	}
7648d5d45fbSJean Delvare 
7659a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
7668d5d45fbSJean Delvare 
7678d5d45fbSJean Delvare 	return data;
7688d5d45fbSJean Delvare }
7698d5d45fbSJean Delvare 
7708d5d45fbSJean Delvare static struct pci_device_id via686a_pci_ids[] = {
7718d5d45fbSJean Delvare 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
7728d5d45fbSJean Delvare 	{ 0, }
7738d5d45fbSJean Delvare };
7748d5d45fbSJean Delvare 
7758d5d45fbSJean Delvare MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
7768d5d45fbSJean Delvare 
7772ec342e6SJean Delvare static int __devinit via686a_device_add(unsigned short address)
7782ec342e6SJean Delvare {
7792ec342e6SJean Delvare 	struct resource res = {
7802ec342e6SJean Delvare 		.start	= address,
7812ec342e6SJean Delvare 		.end	= address + VIA686A_EXTENT - 1,
7822ec342e6SJean Delvare 		.name	= "via686a",
7832ec342e6SJean Delvare 		.flags	= IORESOURCE_IO,
7842ec342e6SJean Delvare 	};
7852ec342e6SJean Delvare 	int err;
7862ec342e6SJean Delvare 
787*b9acb64aSJean Delvare 	err = acpi_check_resource_conflict(&res);
788*b9acb64aSJean Delvare 	if (err)
789*b9acb64aSJean Delvare 		goto exit;
790*b9acb64aSJean Delvare 
7912ec342e6SJean Delvare 	pdev = platform_device_alloc("via686a", address);
7922ec342e6SJean Delvare 	if (!pdev) {
7932ec342e6SJean Delvare 		err = -ENOMEM;
7942ec342e6SJean Delvare 		printk(KERN_ERR "via686a: Device allocation failed\n");
7952ec342e6SJean Delvare 		goto exit;
7962ec342e6SJean Delvare 	}
7972ec342e6SJean Delvare 
7982ec342e6SJean Delvare 	err = platform_device_add_resources(pdev, &res, 1);
7992ec342e6SJean Delvare 	if (err) {
8002ec342e6SJean Delvare 		printk(KERN_ERR "via686a: Device resource addition failed "
8012ec342e6SJean Delvare 		       "(%d)\n", err);
8022ec342e6SJean Delvare 		goto exit_device_put;
8032ec342e6SJean Delvare 	}
8042ec342e6SJean Delvare 
8052ec342e6SJean Delvare 	err = platform_device_add(pdev);
8062ec342e6SJean Delvare 	if (err) {
8072ec342e6SJean Delvare 		printk(KERN_ERR "via686a: Device addition failed (%d)\n",
8082ec342e6SJean Delvare 		       err);
8092ec342e6SJean Delvare 		goto exit_device_put;
8102ec342e6SJean Delvare 	}
8112ec342e6SJean Delvare 
8122ec342e6SJean Delvare 	return 0;
8132ec342e6SJean Delvare 
8142ec342e6SJean Delvare exit_device_put:
8152ec342e6SJean Delvare 	platform_device_put(pdev);
8162ec342e6SJean Delvare exit:
8172ec342e6SJean Delvare 	return err;
8182ec342e6SJean Delvare }
8192ec342e6SJean Delvare 
8208d5d45fbSJean Delvare static int __devinit via686a_pci_probe(struct pci_dev *dev,
8218d5d45fbSJean Delvare 				       const struct pci_device_id *id)
8228d5d45fbSJean Delvare {
8232ec342e6SJean Delvare 	u16 address, val;
8248d5d45fbSJean Delvare 
8252ec342e6SJean Delvare 	if (force_addr) {
8262ec342e6SJean Delvare 		address = force_addr & ~(VIA686A_EXTENT - 1);
8272ec342e6SJean Delvare 		dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
8282ec342e6SJean Delvare 		if (PCIBIOS_SUCCESSFUL !=
8292ec342e6SJean Delvare 		    pci_write_config_word(dev, VIA686A_BASE_REG, address | 1))
8302ec342e6SJean Delvare 			return -ENODEV;
8312ec342e6SJean Delvare 	}
8328d5d45fbSJean Delvare 	if (PCIBIOS_SUCCESSFUL !=
8338d5d45fbSJean Delvare 	    pci_read_config_word(dev, VIA686A_BASE_REG, &val))
8348d5d45fbSJean Delvare 		return -ENODEV;
8358d5d45fbSJean Delvare 
8362d8672c5SJean Delvare 	address = val & ~(VIA686A_EXTENT - 1);
8372ec342e6SJean Delvare 	if (address == 0) {
8388d5d45fbSJean Delvare 		dev_err(&dev->dev, "base address not set - upgrade BIOS "
8398d5d45fbSJean Delvare 			"or use force_addr=0xaddr\n");
8408d5d45fbSJean Delvare 		return -ENODEV;
8418d5d45fbSJean Delvare 	}
8428d5d45fbSJean Delvare 
8432ec342e6SJean Delvare 	if (PCIBIOS_SUCCESSFUL !=
8442ec342e6SJean Delvare 	    pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
8452ec342e6SJean Delvare 		return -ENODEV;
8462ec342e6SJean Delvare 	if (!(val & 0x0001)) {
8472ec342e6SJean Delvare 		if (!force_addr) {
8482ec342e6SJean Delvare 			dev_warn(&dev->dev, "Sensors disabled, enable "
8492ec342e6SJean Delvare 				 "with force_addr=0x%x\n", address);
8502ec342e6SJean Delvare 			return -ENODEV;
8518d5d45fbSJean Delvare 		}
8528d5d45fbSJean Delvare 
8532ec342e6SJean Delvare 		dev_warn(&dev->dev, "Enabling sensors\n");
8542ec342e6SJean Delvare 		if (PCIBIOS_SUCCESSFUL !=
8552ec342e6SJean Delvare 		    pci_write_config_word(dev, VIA686A_ENABLE_REG,
8562ec342e6SJean Delvare 					  val | 0x0001))
8572ec342e6SJean Delvare 			return -ENODEV;
8582ec342e6SJean Delvare 	}
8592ec342e6SJean Delvare 
8602ec342e6SJean Delvare 	if (platform_driver_register(&via686a_driver))
8612ec342e6SJean Delvare 		goto exit;
8622ec342e6SJean Delvare 
8632ec342e6SJean Delvare 	/* Sets global pdev as a side effect */
8642ec342e6SJean Delvare 	if (via686a_device_add(address))
8652ec342e6SJean Delvare 		goto exit_unregister;
8662ec342e6SJean Delvare 
8678d5d45fbSJean Delvare 	/* Always return failure here.  This is to allow other drivers to bind
8688d5d45fbSJean Delvare 	 * to this pci device.  We don't really want to have control over the
8698d5d45fbSJean Delvare 	 * pci device, we only wanted to read as few register values from it.
8708d5d45fbSJean Delvare 	 */
8712ec342e6SJean Delvare 	s_bridge = pci_dev_get(dev);
8722ec342e6SJean Delvare 	return -ENODEV;
8732ec342e6SJean Delvare 
8742ec342e6SJean Delvare exit_unregister:
8752ec342e6SJean Delvare 	platform_driver_unregister(&via686a_driver);
8762ec342e6SJean Delvare exit:
8778d5d45fbSJean Delvare 	return -ENODEV;
8788d5d45fbSJean Delvare }
8798d5d45fbSJean Delvare 
8808d5d45fbSJean Delvare static struct pci_driver via686a_pci_driver = {
8818d5d45fbSJean Delvare 	.name		= "via686a",
8828d5d45fbSJean Delvare 	.id_table	= via686a_pci_ids,
8838d5d45fbSJean Delvare 	.probe		= via686a_pci_probe,
8848d5d45fbSJean Delvare };
8858d5d45fbSJean Delvare 
8868d5d45fbSJean Delvare static int __init sm_via686a_init(void)
8878d5d45fbSJean Delvare {
8888d5d45fbSJean Delvare 	return pci_register_driver(&via686a_pci_driver);
8898d5d45fbSJean Delvare }
8908d5d45fbSJean Delvare 
8918d5d45fbSJean Delvare static void __exit sm_via686a_exit(void)
8928d5d45fbSJean Delvare {
8938d5d45fbSJean Delvare 	pci_unregister_driver(&via686a_pci_driver);
8948d5d45fbSJean Delvare 	if (s_bridge != NULL) {
8952ec342e6SJean Delvare 		platform_device_unregister(pdev);
8962ec342e6SJean Delvare 		platform_driver_unregister(&via686a_driver);
8978d5d45fbSJean Delvare 		pci_dev_put(s_bridge);
8988d5d45fbSJean Delvare 		s_bridge = NULL;
8998d5d45fbSJean Delvare 	}
9008d5d45fbSJean Delvare }
9018d5d45fbSJean Delvare 
90296de0e25SJan Engelhardt MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, "
9038d5d45fbSJean Delvare 	      "Mark Studebaker <mdsxyz123@yahoo.com> "
9048d5d45fbSJean Delvare 	      "and Bob Dougherty <bobd@stanford.edu>");
9058d5d45fbSJean Delvare MODULE_DESCRIPTION("VIA 686A Sensor device");
9068d5d45fbSJean Delvare MODULE_LICENSE("GPL");
9078d5d45fbSJean Delvare 
9088d5d45fbSJean Delvare module_init(sm_via686a_init);
9098d5d45fbSJean Delvare module_exit(sm_via686a_exit);
910