xref: /openbmc/linux/drivers/hwmon/via686a.c (revision 9004ac8134de260b2eb9a6d8fb2dd4a37321e49b)
18d5d45fbSJean Delvare /*
2*9004ac81SGuenter Roeck  * via686a.c - Part of lm_sensors, Linux kernel modules
3*9004ac81SGuenter Roeck  *	       for hardware monitoring
4*9004ac81SGuenter Roeck  *
5*9004ac81SGuenter Roeck  * Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
6*9004ac81SGuenter Roeck  *			      Kyösti Mälkki <kmalkki@cc.hut.fi>,
7*9004ac81SGuenter Roeck  *			      Mark Studebaker <mdsxyz123@yahoo.com>,
8*9004ac81SGuenter Roeck  *			      and Bob Dougherty <bobd@stanford.edu>
9*9004ac81SGuenter Roeck  *
10*9004ac81SGuenter Roeck  * (Some conversion-factor data were contributed by Jonathan Teh Soon Yew
11*9004ac81SGuenter Roeck  * <j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.)
12*9004ac81SGuenter Roeck  *
13*9004ac81SGuenter Roeck  * This program is free software; you can redistribute it and/or modify
14*9004ac81SGuenter Roeck  * it under the terms of the GNU General Public License as published by
15*9004ac81SGuenter Roeck  * the Free Software Foundation; either version 2 of the License, or
16*9004ac81SGuenter Roeck  * (at your option) any later version.
17*9004ac81SGuenter Roeck  *
18*9004ac81SGuenter Roeck  * This program is distributed in the hope that it will be useful,
19*9004ac81SGuenter Roeck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20*9004ac81SGuenter Roeck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21*9004ac81SGuenter Roeck  * GNU General Public License for more details.
22*9004ac81SGuenter Roeck  *
23*9004ac81SGuenter Roeck  * You should have received a copy of the GNU General Public License
24*9004ac81SGuenter Roeck  * along with this program; if not, write to the Free Software
25*9004ac81SGuenter Roeck  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
268d5d45fbSJean Delvare  */
278d5d45fbSJean Delvare 
288d5d45fbSJean Delvare /*
29*9004ac81SGuenter Roeck  * Supports the Via VT82C686A, VT82C686B south bridges.
30*9004ac81SGuenter Roeck  * Reports all as a 686A.
31*9004ac81SGuenter Roeck  * Warning - only supports a single device.
328d5d45fbSJean Delvare  */
338d5d45fbSJean Delvare 
34774f7827SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
35774f7827SJoe Perches 
368d5d45fbSJean Delvare #include <linux/module.h>
378d5d45fbSJean Delvare #include <linux/slab.h>
388d5d45fbSJean Delvare #include <linux/pci.h>
398d5d45fbSJean Delvare #include <linux/jiffies.h>
402ec342e6SJean Delvare #include <linux/platform_device.h>
41943b0830SMark M. Hoffman #include <linux/hwmon.h>
421e71a5a2SJean Delvare #include <linux/hwmon-sysfs.h>
43943b0830SMark M. Hoffman #include <linux/err.h>
448d5d45fbSJean Delvare #include <linux/init.h>
459a61bf63SIngo Molnar #include <linux/mutex.h>
46a5ebe668SJean Delvare #include <linux/sysfs.h>
47b9acb64aSJean Delvare #include <linux/acpi.h>
486055fae8SH Hartley Sweeten #include <linux/io.h>
498d5d45fbSJean Delvare 
508d5d45fbSJean Delvare 
51*9004ac81SGuenter Roeck /*
52*9004ac81SGuenter Roeck  * If force_addr is set to anything different from 0, we forcibly enable
53*9004ac81SGuenter Roeck  * the device at the given address.
54*9004ac81SGuenter Roeck  */
5502002963SJean Delvare static unsigned short force_addr;
568d5d45fbSJean Delvare module_param(force_addr, ushort, 0);
578d5d45fbSJean Delvare MODULE_PARM_DESC(force_addr,
588d5d45fbSJean Delvare 		 "Initialize the base address of the sensors");
598d5d45fbSJean Delvare 
602ec342e6SJean Delvare static struct platform_device *pdev;
618d5d45fbSJean Delvare 
628d5d45fbSJean Delvare /*
63*9004ac81SGuenter Roeck  * The Via 686a southbridge has a LM78-like chip integrated on the same IC.
64*9004ac81SGuenter Roeck  * This driver is a customized copy of lm78.c
658d5d45fbSJean Delvare  */
668d5d45fbSJean Delvare 
678d5d45fbSJean Delvare /* Many VIA686A constants specified below */
688d5d45fbSJean Delvare 
698d5d45fbSJean Delvare /* Length of ISA address segment */
708d5d45fbSJean Delvare #define VIA686A_EXTENT		0x80
718d5d45fbSJean Delvare #define VIA686A_BASE_REG	0x70
728d5d45fbSJean Delvare #define VIA686A_ENABLE_REG	0x74
738d5d45fbSJean Delvare 
748d5d45fbSJean Delvare /* The VIA686A registers */
758d5d45fbSJean Delvare /* ins numbered 0-4 */
768d5d45fbSJean Delvare #define VIA686A_REG_IN_MAX(nr)	(0x2b + ((nr) * 2))
778d5d45fbSJean Delvare #define VIA686A_REG_IN_MIN(nr)	(0x2c + ((nr) * 2))
788d5d45fbSJean Delvare #define VIA686A_REG_IN(nr)	(0x22 + (nr))
798d5d45fbSJean Delvare 
808d5d45fbSJean Delvare /* fans numbered 1-2 */
818d5d45fbSJean Delvare #define VIA686A_REG_FAN_MIN(nr)	(0x3a + (nr))
828d5d45fbSJean Delvare #define VIA686A_REG_FAN(nr)	(0x28 + (nr))
838d5d45fbSJean Delvare 
848d5d45fbSJean Delvare /* temps numbered 1-3 */
858d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP[]	= { 0x20, 0x21, 0x1f };
868d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_OVER[]	= { 0x39, 0x3d, 0x1d };
878d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_HYST[]	= { 0x3a, 0x3e, 0x1e };
888d5d45fbSJean Delvare /* bits 7-6 */
898d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW1	0x4b
908d5d45fbSJean Delvare /* 2 = bits 5-4, 3 = bits 7-6 */
918d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW23	0x49
928d5d45fbSJean Delvare 
938d5d45fbSJean Delvare #define VIA686A_REG_ALARM1	0x41
948d5d45fbSJean Delvare #define VIA686A_REG_ALARM2	0x42
958d5d45fbSJean Delvare #define VIA686A_REG_FANDIV	0x47
968d5d45fbSJean Delvare #define VIA686A_REG_CONFIG	0x40
97*9004ac81SGuenter Roeck /*
98*9004ac81SGuenter Roeck  * The following register sets temp interrupt mode (bits 1-0 for temp1,
99*9004ac81SGuenter Roeck  * 3-2 for temp2, 5-4 for temp3).  Modes are:
100*9004ac81SGuenter Roeck  * 00 interrupt stays as long as value is out-of-range
101*9004ac81SGuenter Roeck  * 01 interrupt is cleared once register is read (default)
102*9004ac81SGuenter Roeck  * 10 comparator mode- like 00, but ignores hysteresis
103*9004ac81SGuenter Roeck  * 11 same as 00
104*9004ac81SGuenter Roeck  */
1058d5d45fbSJean Delvare #define VIA686A_REG_TEMP_MODE		0x4b
1068d5d45fbSJean Delvare /* We'll just assume that you want to set all 3 simultaneously: */
1078d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_MASK		0x3F
1088d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_CONTINUOUS	0x00
1098d5d45fbSJean Delvare 
110*9004ac81SGuenter Roeck /*
111*9004ac81SGuenter Roeck  * Conversions. Limit checking is only done on the TO_REG
112*9004ac81SGuenter Roeck  * variants.
113*9004ac81SGuenter Roeck  *
114*9004ac81SGuenter Roeck  ******** VOLTAGE CONVERSIONS (Bob Dougherty) ********
115*9004ac81SGuenter Roeck  * From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew):
116*9004ac81SGuenter Roeck  * voltagefactor[0]=1.25/2628; (2628/1.25=2102.4)   // Vccp
117*9004ac81SGuenter Roeck  * voltagefactor[1]=1.25/2628; (2628/1.25=2102.4)   // +2.5V
118*9004ac81SGuenter Roeck  * voltagefactor[2]=1.67/2628; (2628/1.67=1573.7)   // +3.3V
119*9004ac81SGuenter Roeck  * voltagefactor[3]=2.6/2628;  (2628/2.60=1010.8)   // +5V
120*9004ac81SGuenter Roeck  * voltagefactor[4]=6.3/2628;  (2628/6.30=417.14)   // +12V
121*9004ac81SGuenter Roeck  * in[i]=(data[i+2]*25.0+133)*voltagefactor[i];
122*9004ac81SGuenter Roeck  * That is:
123*9004ac81SGuenter Roeck  * volts = (25*regVal+133)*factor
124*9004ac81SGuenter Roeck  * regVal = (volts/factor-133)/25
125*9004ac81SGuenter Roeck  * (These conversions were contributed by Jonathan Teh Soon Yew
126*9004ac81SGuenter Roeck  * <j.teh@iname.com>)
127*9004ac81SGuenter Roeck  */
1288d5d45fbSJean Delvare static inline u8 IN_TO_REG(long val, int inNum)
1298d5d45fbSJean Delvare {
130*9004ac81SGuenter Roeck 	/*
131*9004ac81SGuenter Roeck 	 * To avoid floating point, we multiply constants by 10 (100 for +12V).
132*9004ac81SGuenter Roeck 	 * Rounding is done (120500 is actually 133000 - 12500).
133*9004ac81SGuenter Roeck 	 * Remember that val is expressed in 0.001V/bit, which is why we divide
134*9004ac81SGuenter Roeck 	 * by an additional 10000 (100000 for +12V): 1000 for val and 10 (100)
135*9004ac81SGuenter Roeck 	 * for the constants.
136*9004ac81SGuenter Roeck 	 */
1378d5d45fbSJean Delvare 	if (inNum <= 1)
1388d5d45fbSJean Delvare 		return (u8)
1398d5d45fbSJean Delvare 		    SENSORS_LIMIT((val * 21024 - 1205000) / 250000, 0, 255);
1408d5d45fbSJean Delvare 	else if (inNum == 2)
1418d5d45fbSJean Delvare 		return (u8)
1428d5d45fbSJean Delvare 		    SENSORS_LIMIT((val * 15737 - 1205000) / 250000, 0, 255);
1438d5d45fbSJean Delvare 	else if (inNum == 3)
1448d5d45fbSJean Delvare 		return (u8)
1458d5d45fbSJean Delvare 		    SENSORS_LIMIT((val * 10108 - 1205000) / 250000, 0, 255);
1468d5d45fbSJean Delvare 	else
1478d5d45fbSJean Delvare 		return (u8)
1488d5d45fbSJean Delvare 		    SENSORS_LIMIT((val * 41714 - 12050000) / 2500000, 0, 255);
1498d5d45fbSJean Delvare }
1508d5d45fbSJean Delvare 
1518d5d45fbSJean Delvare static inline long IN_FROM_REG(u8 val, int inNum)
1528d5d45fbSJean Delvare {
153*9004ac81SGuenter Roeck 	/*
154*9004ac81SGuenter Roeck 	 * To avoid floating point, we multiply constants by 10 (100 for +12V).
155*9004ac81SGuenter Roeck 	 * We also multiply them by 1000 because we want 0.001V/bit for the
156*9004ac81SGuenter Roeck 	 * output value. Rounding is done.
157*9004ac81SGuenter Roeck 	 */
1588d5d45fbSJean Delvare 	if (inNum <= 1)
1598d5d45fbSJean Delvare 		return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024);
1608d5d45fbSJean Delvare 	else if (inNum == 2)
1618d5d45fbSJean Delvare 		return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737);
1628d5d45fbSJean Delvare 	else if (inNum == 3)
1638d5d45fbSJean Delvare 		return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108);
1648d5d45fbSJean Delvare 	else
1658d5d45fbSJean Delvare 		return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714);
1668d5d45fbSJean Delvare }
1678d5d45fbSJean Delvare 
1688d5d45fbSJean Delvare /********* FAN RPM CONVERSIONS ********/
169*9004ac81SGuenter Roeck /*
170*9004ac81SGuenter Roeck  * Higher register values = slower fans (the fan's strobe gates a counter).
171*9004ac81SGuenter Roeck  * But this chip saturates back at 0, not at 255 like all the other chips.
172*9004ac81SGuenter Roeck  * So, 0 means 0 RPM
173*9004ac81SGuenter Roeck  */
1748d5d45fbSJean Delvare static inline u8 FAN_TO_REG(long rpm, int div)
1758d5d45fbSJean Delvare {
1768d5d45fbSJean Delvare 	if (rpm == 0)
1778d5d45fbSJean Delvare 		return 0;
1788d5d45fbSJean Delvare 	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
1798d5d45fbSJean Delvare 	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255);
1808d5d45fbSJean Delvare }
1818d5d45fbSJean Delvare 
182*9004ac81SGuenter Roeck #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (val) == 255 ? 0 : 1350000 / \
183*9004ac81SGuenter Roeck 				((val) * (div)))
1848d5d45fbSJean Delvare 
1858d5d45fbSJean Delvare /******** TEMP CONVERSIONS (Bob Dougherty) *********/
186*9004ac81SGuenter Roeck /*
187*9004ac81SGuenter Roeck  * linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew)
188*9004ac81SGuenter Roeck  *	if(temp<169)
189*9004ac81SGuenter Roeck  *		return double(temp)*0.427-32.08;
190*9004ac81SGuenter Roeck  *	else if(temp>=169 && temp<=202)
191*9004ac81SGuenter Roeck  *		return double(temp)*0.582-58.16;
192*9004ac81SGuenter Roeck  *	else
193*9004ac81SGuenter Roeck  *		return double(temp)*0.924-127.33;
194*9004ac81SGuenter Roeck  *
195*9004ac81SGuenter Roeck  * A fifth-order polynomial fits the unofficial data (provided by Alex van
196*9004ac81SGuenter Roeck  * Kaam <darkside@chello.nl>) a bit better.  It also give more reasonable
197*9004ac81SGuenter Roeck  * numbers on my machine (ie. they agree with what my BIOS tells me).
198*9004ac81SGuenter Roeck  * Here's the fifth-order fit to the 8-bit data:
199*9004ac81SGuenter Roeck  * temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 -
200*9004ac81SGuenter Roeck  *	2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0.
201*9004ac81SGuenter Roeck  *
202*9004ac81SGuenter Roeck  * (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for
203*9004ac81SGuenter Roeck  * finding my typos in this formula!)
204*9004ac81SGuenter Roeck  *
205*9004ac81SGuenter Roeck  * Alas, none of the elegant function-fit solutions will work because we
206*9004ac81SGuenter Roeck  * aren't allowed to use floating point in the kernel and doing it with
207*9004ac81SGuenter Roeck  * integers doesn't provide enough precision.  So we'll do boring old
208*9004ac81SGuenter Roeck  * look-up table stuff.  The unofficial data (see below) have effectively
209*9004ac81SGuenter Roeck  * 7-bit resolution (they are rounded to the nearest degree).  I'm assuming
210*9004ac81SGuenter Roeck  * that the transfer function of the device is monotonic and smooth, so a
211*9004ac81SGuenter Roeck  * smooth function fit to the data will allow us to get better precision.
212*9004ac81SGuenter Roeck  * I used the 5th-order poly fit described above and solved for
213*9004ac81SGuenter Roeck  * VIA register values 0-255.  I *10 before rounding, so we get tenth-degree
214*9004ac81SGuenter Roeck  * precision.  (I could have done all 1024 values for our 10-bit readings,
215*9004ac81SGuenter Roeck  * but the function is very linear in the useful range (0-80 deg C), so
216*9004ac81SGuenter Roeck  * we'll just use linear interpolation for 10-bit readings.)  So, tempLUT
217*9004ac81SGuenter Roeck  * is the temp at via register values 0-255:
218*9004ac81SGuenter Roeck  */
219*9004ac81SGuenter Roeck static const s16 tempLUT[] = {
220*9004ac81SGuenter Roeck 	-709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
2218d5d45fbSJean Delvare 	-503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
2228d5d45fbSJean Delvare 	-362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
2238d5d45fbSJean Delvare 	-255, -246, -237, -229, -220, -212, -204, -196, -188, -180,
2248d5d45fbSJean Delvare 	-173, -166, -159, -152, -145, -139, -132, -126, -120, -114,
2258d5d45fbSJean Delvare 	-108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49,
2268d5d45fbSJean Delvare 	-44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16,
2278d5d45fbSJean Delvare 	20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84,
2288d5d45fbSJean Delvare 	88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138,
2298d5d45fbSJean Delvare 	142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189,
2308d5d45fbSJean Delvare 	193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241,
2318d5d45fbSJean Delvare 	245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294,
2328d5d45fbSJean Delvare 	299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348,
2338d5d45fbSJean Delvare 	353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404,
2348d5d45fbSJean Delvare 	409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464,
2358d5d45fbSJean Delvare 	469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532,
2368d5d45fbSJean Delvare 	538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614,
2378d5d45fbSJean Delvare 	621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718,
2388d5d45fbSJean Delvare 	728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856,
2398d5d45fbSJean Delvare 	870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044,
2408d5d45fbSJean Delvare 	1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252,
2418d5d45fbSJean Delvare 	1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462
2428d5d45fbSJean Delvare };
2438d5d45fbSJean Delvare 
244*9004ac81SGuenter Roeck /*
245*9004ac81SGuenter Roeck  * the original LUT values from Alex van Kaam <darkside@chello.nl>
246*9004ac81SGuenter Roeck  * (for via register values 12-240):
247*9004ac81SGuenter Roeck  * {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31,
248*9004ac81SGuenter Roeck  * -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15,
249*9004ac81SGuenter Roeck  * -15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3,
250*9004ac81SGuenter Roeck  * -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,
251*9004ac81SGuenter Roeck  * 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,
252*9004ac81SGuenter Roeck  * 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,
253*9004ac81SGuenter Roeck  * 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,
254*9004ac81SGuenter Roeck  * 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,
255*9004ac81SGuenter Roeck  * 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,
256*9004ac81SGuenter Roeck  * 85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110};
257*9004ac81SGuenter Roeck  *
258*9004ac81SGuenter Roeck  *
259*9004ac81SGuenter Roeck  * Here's the reverse LUT.  I got it by doing a 6-th order poly fit (needed
260*9004ac81SGuenter Roeck  * an extra term for a good fit to these inverse data!) and then
261*9004ac81SGuenter Roeck  * solving for each temp value from -50 to 110 (the useable range for
262*9004ac81SGuenter Roeck  * this chip).  Here's the fit:
263*9004ac81SGuenter Roeck  * viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4
264*9004ac81SGuenter Roeck  * - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
265*9004ac81SGuenter Roeck  * Note that n=161:
266*9004ac81SGuenter Roeck  */
267*9004ac81SGuenter Roeck static const u8 viaLUT[] = {
268*9004ac81SGuenter Roeck 	12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
2698d5d45fbSJean Delvare 	23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
2708d5d45fbSJean Delvare 	41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
2718d5d45fbSJean Delvare 	69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100,
2728d5d45fbSJean Delvare 	103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129,
2738d5d45fbSJean Delvare 	131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156,
2748d5d45fbSJean Delvare 	158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
2758d5d45fbSJean Delvare 	182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199,
2768d5d45fbSJean Delvare 	200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213,
2778d5d45fbSJean Delvare 	214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224,
2788d5d45fbSJean Delvare 	225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232,
2798d5d45fbSJean Delvare 	233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
2808d5d45fbSJean Delvare 	239, 240
2818d5d45fbSJean Delvare };
2828d5d45fbSJean Delvare 
283*9004ac81SGuenter Roeck /*
284*9004ac81SGuenter Roeck  * Converting temps to (8-bit) hyst and over registers
285*9004ac81SGuenter Roeck  * No interpolation here.
286*9004ac81SGuenter Roeck  * The +50 is because the temps start at -50
287*9004ac81SGuenter Roeck  */
2888d5d45fbSJean Delvare static inline u8 TEMP_TO_REG(long val)
2898d5d45fbSJean Delvare {
2908d5d45fbSJean Delvare 	return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 :
2918d5d45fbSJean Delvare 		      (val < 0 ? val - 500 : val + 500) / 1000 + 50];
2928d5d45fbSJean Delvare }
2938d5d45fbSJean Delvare 
2948d5d45fbSJean Delvare /* for 8-bit temperature hyst and over registers */
295088341bdSJean Delvare #define TEMP_FROM_REG(val)	((long)tempLUT[val] * 100)
2968d5d45fbSJean Delvare 
2978d5d45fbSJean Delvare /* for 10-bit temperature readings */
2988d5d45fbSJean Delvare static inline long TEMP_FROM_REG10(u16 val)
2998d5d45fbSJean Delvare {
3008d5d45fbSJean Delvare 	u16 eightBits = val >> 2;
3018d5d45fbSJean Delvare 	u16 twoBits = val & 3;
3028d5d45fbSJean Delvare 
3038d5d45fbSJean Delvare 	/* no interpolation for these */
3048d5d45fbSJean Delvare 	if (twoBits == 0 || eightBits == 255)
3058d5d45fbSJean Delvare 		return TEMP_FROM_REG(eightBits);
3068d5d45fbSJean Delvare 
3078d5d45fbSJean Delvare 	/* do some linear interpolation */
3088d5d45fbSJean Delvare 	return (tempLUT[eightBits] * (4 - twoBits) +
3098d5d45fbSJean Delvare 		tempLUT[eightBits + 1] * twoBits) * 25;
3108d5d45fbSJean Delvare }
3118d5d45fbSJean Delvare 
3128d5d45fbSJean Delvare #define DIV_FROM_REG(val) (1 << (val))
3138d5d45fbSJean Delvare #define DIV_TO_REG(val) ((val) == 8 ? 3 : (val) == 4 ? 2 : (val) == 1 ? 0 : 1)
3148d5d45fbSJean Delvare 
315*9004ac81SGuenter Roeck /*
316*9004ac81SGuenter Roeck  * For each registered chip, we need to keep some data in memory.
317*9004ac81SGuenter Roeck  * The structure is dynamically allocated.
318*9004ac81SGuenter Roeck  */
3198d5d45fbSJean Delvare struct via686a_data {
3202ec342e6SJean Delvare 	unsigned short addr;
3212ec342e6SJean Delvare 	const char *name;
3221beeffe4STony Jones 	struct device *hwmon_dev;
3239a61bf63SIngo Molnar 	struct mutex update_lock;
3248d5d45fbSJean Delvare 	char valid;		/* !=0 if following fields are valid */
3258d5d45fbSJean Delvare 	unsigned long last_updated;	/* In jiffies */
3268d5d45fbSJean Delvare 
3278d5d45fbSJean Delvare 	u8 in[5];		/* Register value */
3288d5d45fbSJean Delvare 	u8 in_max[5];		/* Register value */
3298d5d45fbSJean Delvare 	u8 in_min[5];		/* Register value */
3308d5d45fbSJean Delvare 	u8 fan[2];		/* Register value */
3318d5d45fbSJean Delvare 	u8 fan_min[2];		/* Register value */
3328d5d45fbSJean Delvare 	u16 temp[3];		/* Register value 10 bit */
3338d5d45fbSJean Delvare 	u8 temp_over[3];	/* Register value */
3348d5d45fbSJean Delvare 	u8 temp_hyst[3];	/* Register value */
3358d5d45fbSJean Delvare 	u8 fan_div[2];		/* Register encoding, shifted right */
3368d5d45fbSJean Delvare 	u16 alarms;		/* Register encoding, combined */
3378d5d45fbSJean Delvare };
3388d5d45fbSJean Delvare 
3398d5d45fbSJean Delvare static struct pci_dev *s_bridge;	/* pointer to the (only) via686a */
3408d5d45fbSJean Delvare 
3412ec342e6SJean Delvare static int via686a_probe(struct platform_device *pdev);
342d0546128SJean Delvare static int __devexit via686a_remove(struct platform_device *pdev);
3438d5d45fbSJean Delvare 
3442ec342e6SJean Delvare static inline int via686a_read_value(struct via686a_data *data, u8 reg)
3458d5d45fbSJean Delvare {
3462ec342e6SJean Delvare 	return inb_p(data->addr + reg);
3478d5d45fbSJean Delvare }
3488d5d45fbSJean Delvare 
3492ec342e6SJean Delvare static inline void via686a_write_value(struct via686a_data *data, u8 reg,
3508d5d45fbSJean Delvare 				       u8 value)
3518d5d45fbSJean Delvare {
3522ec342e6SJean Delvare 	outb_p(value, data->addr + reg);
3538d5d45fbSJean Delvare }
3548d5d45fbSJean Delvare 
3558d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev);
3562ec342e6SJean Delvare static void via686a_init_device(struct via686a_data *data);
3578d5d45fbSJean Delvare 
3588d5d45fbSJean Delvare /* following are the sysfs callback functions */
3598d5d45fbSJean Delvare 
3608d5d45fbSJean Delvare /* 7 voltage sensors */
3611e71a5a2SJean Delvare static ssize_t show_in(struct device *dev, struct device_attribute *da,
3621e71a5a2SJean Delvare 		char *buf) {
3638d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
3641e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3651e71a5a2SJean Delvare 	int nr = attr->index;
3668d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr));
3678d5d45fbSJean Delvare }
3688d5d45fbSJean Delvare 
3691e71a5a2SJean Delvare static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
3701e71a5a2SJean Delvare 		char *buf) {
3718d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
3721e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3731e71a5a2SJean Delvare 	int nr = attr->index;
3748d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr));
3758d5d45fbSJean Delvare }
3768d5d45fbSJean Delvare 
3771e71a5a2SJean Delvare static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
3781e71a5a2SJean Delvare 		char *buf) {
3798d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
3801e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3811e71a5a2SJean Delvare 	int nr = attr->index;
3828d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
3838d5d45fbSJean Delvare }
3848d5d45fbSJean Delvare 
3851e71a5a2SJean Delvare static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
3861e71a5a2SJean Delvare 		const char *buf, size_t count) {
3872ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
3881e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3891e71a5a2SJean Delvare 	int nr = attr->index;
390*9004ac81SGuenter Roeck 	unsigned long val;
391*9004ac81SGuenter Roeck 	int err;
392*9004ac81SGuenter Roeck 
393*9004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
394*9004ac81SGuenter Roeck 	if (err)
395*9004ac81SGuenter Roeck 		return err;
3968d5d45fbSJean Delvare 
3979a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
3988d5d45fbSJean Delvare 	data->in_min[nr] = IN_TO_REG(val, nr);
3992ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_IN_MIN(nr),
4008d5d45fbSJean Delvare 			data->in_min[nr]);
4019a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4028d5d45fbSJean Delvare 	return count;
4038d5d45fbSJean Delvare }
4041e71a5a2SJean Delvare static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
4051e71a5a2SJean Delvare 		const char *buf, size_t count) {
4062ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
4071e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4081e71a5a2SJean Delvare 	int nr = attr->index;
409*9004ac81SGuenter Roeck 	unsigned long val;
410*9004ac81SGuenter Roeck 	int err;
411*9004ac81SGuenter Roeck 
412*9004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
413*9004ac81SGuenter Roeck 	if (err)
414*9004ac81SGuenter Roeck 		return err;
4158d5d45fbSJean Delvare 
4169a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4178d5d45fbSJean Delvare 	data->in_max[nr] = IN_TO_REG(val, nr);
4182ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_IN_MAX(nr),
4198d5d45fbSJean Delvare 			data->in_max[nr]);
4209a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4218d5d45fbSJean Delvare 	return count;
4228d5d45fbSJean Delvare }
4238d5d45fbSJean Delvare #define show_in_offset(offset)					\
4241e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
4251e71a5a2SJean Delvare 		show_in, NULL, offset);				\
4261e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
4271e71a5a2SJean Delvare 		show_in_min, set_in_min, offset);		\
4281e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
4291e71a5a2SJean Delvare 		show_in_max, set_in_max, offset);
4308d5d45fbSJean Delvare 
4318d5d45fbSJean Delvare show_in_offset(0);
4328d5d45fbSJean Delvare show_in_offset(1);
4338d5d45fbSJean Delvare show_in_offset(2);
4348d5d45fbSJean Delvare show_in_offset(3);
4358d5d45fbSJean Delvare show_in_offset(4);
4368d5d45fbSJean Delvare 
4378d5d45fbSJean Delvare /* 3 temperatures */
4381e71a5a2SJean Delvare static ssize_t show_temp(struct device *dev, struct device_attribute *da,
4391e71a5a2SJean Delvare 		char *buf) {
4408d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4411e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4421e71a5a2SJean Delvare 	int nr = attr->index;
4438d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
4448d5d45fbSJean Delvare }
4451e71a5a2SJean Delvare static ssize_t show_temp_over(struct device *dev, struct device_attribute *da,
4461e71a5a2SJean Delvare 		char *buf) {
4478d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4481e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4491e71a5a2SJean Delvare 	int nr = attr->index;
4508d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
4518d5d45fbSJean Delvare }
4521e71a5a2SJean Delvare static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da,
4531e71a5a2SJean Delvare 		char *buf) {
4548d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4551e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4561e71a5a2SJean Delvare 	int nr = attr->index;
4578d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
4588d5d45fbSJean Delvare }
4591e71a5a2SJean Delvare static ssize_t set_temp_over(struct device *dev, struct device_attribute *da,
4601e71a5a2SJean Delvare 		const char *buf, size_t count) {
4612ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
4621e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4631e71a5a2SJean Delvare 	int nr = attr->index;
464*9004ac81SGuenter Roeck 	long val;
465*9004ac81SGuenter Roeck 	int err;
466*9004ac81SGuenter Roeck 
467*9004ac81SGuenter Roeck 	err = kstrtol(buf, 10, &val);
468*9004ac81SGuenter Roeck 	if (err)
469*9004ac81SGuenter Roeck 		return err;
4708d5d45fbSJean Delvare 
4719a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4728d5d45fbSJean Delvare 	data->temp_over[nr] = TEMP_TO_REG(val);
4732ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr],
4748d5d45fbSJean Delvare 			    data->temp_over[nr]);
4759a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4768d5d45fbSJean Delvare 	return count;
4778d5d45fbSJean Delvare }
4781e71a5a2SJean Delvare static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da,
4791e71a5a2SJean Delvare 		const char *buf, size_t count) {
4802ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
4811e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4821e71a5a2SJean Delvare 	int nr = attr->index;
483*9004ac81SGuenter Roeck 	long val;
484*9004ac81SGuenter Roeck 	int err;
485*9004ac81SGuenter Roeck 
486*9004ac81SGuenter Roeck 	err = kstrtol(buf, 10, &val);
487*9004ac81SGuenter Roeck 	if (err)
488*9004ac81SGuenter Roeck 		return err;
4898d5d45fbSJean Delvare 
4909a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4918d5d45fbSJean Delvare 	data->temp_hyst[nr] = TEMP_TO_REG(val);
4922ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr],
4938d5d45fbSJean Delvare 			    data->temp_hyst[nr]);
4949a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4958d5d45fbSJean Delvare 	return count;
4968d5d45fbSJean Delvare }
4978d5d45fbSJean Delvare #define show_temp_offset(offset)					\
4981e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,		\
4991e71a5a2SJean Delvare 		show_temp, NULL, offset - 1);				\
5001e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,	\
5011e71a5a2SJean Delvare 		show_temp_over, set_temp_over, offset - 1);		\
5021e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR,	\
5031e71a5a2SJean Delvare 		show_temp_hyst, set_temp_hyst, offset - 1);
5048d5d45fbSJean Delvare 
5058d5d45fbSJean Delvare show_temp_offset(1);
5068d5d45fbSJean Delvare show_temp_offset(2);
5078d5d45fbSJean Delvare show_temp_offset(3);
5088d5d45fbSJean Delvare 
5098d5d45fbSJean Delvare /* 2 Fans */
5101e71a5a2SJean Delvare static ssize_t show_fan(struct device *dev, struct device_attribute *da,
5111e71a5a2SJean Delvare 		char *buf) {
5128d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5131e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5141e71a5a2SJean Delvare 	int nr = attr->index;
5158d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
5168d5d45fbSJean Delvare 				DIV_FROM_REG(data->fan_div[nr])));
5178d5d45fbSJean Delvare }
5181e71a5a2SJean Delvare static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
5191e71a5a2SJean Delvare 		char *buf) {
5208d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5211e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5221e71a5a2SJean Delvare 	int nr = attr->index;
5238d5d45fbSJean Delvare 	return sprintf(buf, "%d\n",
524*9004ac81SGuenter Roeck 		FAN_FROM_REG(data->fan_min[nr],
525*9004ac81SGuenter Roeck 			     DIV_FROM_REG(data->fan_div[nr])));
5268d5d45fbSJean Delvare }
5271e71a5a2SJean Delvare static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
5281e71a5a2SJean Delvare 		char *buf) {
5298d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5301e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5311e71a5a2SJean Delvare 	int nr = attr->index;
5328d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
5338d5d45fbSJean Delvare }
5341e71a5a2SJean Delvare static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
5351e71a5a2SJean Delvare 		const char *buf, size_t count) {
5362ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
5371e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5381e71a5a2SJean Delvare 	int nr = attr->index;
539*9004ac81SGuenter Roeck 	unsigned long val;
540*9004ac81SGuenter Roeck 	int err;
541*9004ac81SGuenter Roeck 
542*9004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
543*9004ac81SGuenter Roeck 	if (err)
544*9004ac81SGuenter Roeck 		return err;
5458d5d45fbSJean Delvare 
5469a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
5478d5d45fbSJean Delvare 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
5482ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
5499a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
5508d5d45fbSJean Delvare 	return count;
5518d5d45fbSJean Delvare }
5521e71a5a2SJean Delvare static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
5531e71a5a2SJean Delvare 		const char *buf, size_t count) {
5542ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
5551e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5561e71a5a2SJean Delvare 	int nr = attr->index;
5578d5d45fbSJean Delvare 	int old;
558*9004ac81SGuenter Roeck 	unsigned long val;
559*9004ac81SGuenter Roeck 	int err;
560*9004ac81SGuenter Roeck 
561*9004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
562*9004ac81SGuenter Roeck 	if (err)
563*9004ac81SGuenter Roeck 		return err;
5648d5d45fbSJean Delvare 
5659a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
5662ec342e6SJean Delvare 	old = via686a_read_value(data, VIA686A_REG_FANDIV);
5678d5d45fbSJean Delvare 	data->fan_div[nr] = DIV_TO_REG(val);
5688d5d45fbSJean Delvare 	old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
5692ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_FANDIV, old);
5709a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
5718d5d45fbSJean Delvare 	return count;
5728d5d45fbSJean Delvare }
5738d5d45fbSJean Delvare 
5748d5d45fbSJean Delvare #define show_fan_offset(offset)						\
5751e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,			\
5761e71a5a2SJean Delvare 		show_fan, NULL, offset - 1);				\
5771e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
5781e71a5a2SJean Delvare 		show_fan_min, set_fan_min, offset - 1);			\
5791e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
5801e71a5a2SJean Delvare 		show_fan_div, set_fan_div, offset - 1);
5818d5d45fbSJean Delvare 
5828d5d45fbSJean Delvare show_fan_offset(1);
5838d5d45fbSJean Delvare show_fan_offset(2);
5848d5d45fbSJean Delvare 
5858d5d45fbSJean Delvare /* Alarms */
586*9004ac81SGuenter Roeck static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
587*9004ac81SGuenter Roeck 			   char *buf)
588*9004ac81SGuenter Roeck {
5898d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5908d5d45fbSJean Delvare 	return sprintf(buf, "%u\n", data->alarms);
5918d5d45fbSJean Delvare }
592*9004ac81SGuenter Roeck 
5938d5d45fbSJean Delvare static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
5948d5d45fbSJean Delvare 
59513ff05e9SJean Delvare static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
59613ff05e9SJean Delvare 			  char *buf)
59713ff05e9SJean Delvare {
59813ff05e9SJean Delvare 	int bitnr = to_sensor_dev_attr(attr)->index;
59913ff05e9SJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
60013ff05e9SJean Delvare 	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
60113ff05e9SJean Delvare }
60213ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
60313ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
60413ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
60513ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
60613ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
60713ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
60813ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 11);
60913ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 15);
61013ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
61113ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
61213ff05e9SJean Delvare 
6132ec342e6SJean Delvare static ssize_t show_name(struct device *dev, struct device_attribute
6142ec342e6SJean Delvare 			 *devattr, char *buf)
6152ec342e6SJean Delvare {
6162ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
6172ec342e6SJean Delvare 	return sprintf(buf, "%s\n", data->name);
6182ec342e6SJean Delvare }
6192ec342e6SJean Delvare static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
6202ec342e6SJean Delvare 
621a5ebe668SJean Delvare static struct attribute *via686a_attributes[] = {
6221e71a5a2SJean Delvare 	&sensor_dev_attr_in0_input.dev_attr.attr,
6231e71a5a2SJean Delvare 	&sensor_dev_attr_in1_input.dev_attr.attr,
6241e71a5a2SJean Delvare 	&sensor_dev_attr_in2_input.dev_attr.attr,
6251e71a5a2SJean Delvare 	&sensor_dev_attr_in3_input.dev_attr.attr,
6261e71a5a2SJean Delvare 	&sensor_dev_attr_in4_input.dev_attr.attr,
6271e71a5a2SJean Delvare 	&sensor_dev_attr_in0_min.dev_attr.attr,
6281e71a5a2SJean Delvare 	&sensor_dev_attr_in1_min.dev_attr.attr,
6291e71a5a2SJean Delvare 	&sensor_dev_attr_in2_min.dev_attr.attr,
6301e71a5a2SJean Delvare 	&sensor_dev_attr_in3_min.dev_attr.attr,
6311e71a5a2SJean Delvare 	&sensor_dev_attr_in4_min.dev_attr.attr,
6321e71a5a2SJean Delvare 	&sensor_dev_attr_in0_max.dev_attr.attr,
6331e71a5a2SJean Delvare 	&sensor_dev_attr_in1_max.dev_attr.attr,
6341e71a5a2SJean Delvare 	&sensor_dev_attr_in2_max.dev_attr.attr,
6351e71a5a2SJean Delvare 	&sensor_dev_attr_in3_max.dev_attr.attr,
6361e71a5a2SJean Delvare 	&sensor_dev_attr_in4_max.dev_attr.attr,
63713ff05e9SJean Delvare 	&sensor_dev_attr_in0_alarm.dev_attr.attr,
63813ff05e9SJean Delvare 	&sensor_dev_attr_in1_alarm.dev_attr.attr,
63913ff05e9SJean Delvare 	&sensor_dev_attr_in2_alarm.dev_attr.attr,
64013ff05e9SJean Delvare 	&sensor_dev_attr_in3_alarm.dev_attr.attr,
64113ff05e9SJean Delvare 	&sensor_dev_attr_in4_alarm.dev_attr.attr,
642a5ebe668SJean Delvare 
6431e71a5a2SJean Delvare 	&sensor_dev_attr_temp1_input.dev_attr.attr,
6441e71a5a2SJean Delvare 	&sensor_dev_attr_temp2_input.dev_attr.attr,
6451e71a5a2SJean Delvare 	&sensor_dev_attr_temp3_input.dev_attr.attr,
6461e71a5a2SJean Delvare 	&sensor_dev_attr_temp1_max.dev_attr.attr,
6471e71a5a2SJean Delvare 	&sensor_dev_attr_temp2_max.dev_attr.attr,
6481e71a5a2SJean Delvare 	&sensor_dev_attr_temp3_max.dev_attr.attr,
6491e71a5a2SJean Delvare 	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
6501e71a5a2SJean Delvare 	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
6511e71a5a2SJean Delvare 	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
65213ff05e9SJean Delvare 	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
65313ff05e9SJean Delvare 	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
65413ff05e9SJean Delvare 	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
655a5ebe668SJean Delvare 
6561e71a5a2SJean Delvare 	&sensor_dev_attr_fan1_input.dev_attr.attr,
6571e71a5a2SJean Delvare 	&sensor_dev_attr_fan2_input.dev_attr.attr,
6581e71a5a2SJean Delvare 	&sensor_dev_attr_fan1_min.dev_attr.attr,
6591e71a5a2SJean Delvare 	&sensor_dev_attr_fan2_min.dev_attr.attr,
6601e71a5a2SJean Delvare 	&sensor_dev_attr_fan1_div.dev_attr.attr,
6611e71a5a2SJean Delvare 	&sensor_dev_attr_fan2_div.dev_attr.attr,
66213ff05e9SJean Delvare 	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
66313ff05e9SJean Delvare 	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
664a5ebe668SJean Delvare 
665a5ebe668SJean Delvare 	&dev_attr_alarms.attr,
6662ec342e6SJean Delvare 	&dev_attr_name.attr,
667a5ebe668SJean Delvare 	NULL
668a5ebe668SJean Delvare };
669a5ebe668SJean Delvare 
670a5ebe668SJean Delvare static const struct attribute_group via686a_group = {
671a5ebe668SJean Delvare 	.attrs = via686a_attributes,
672a5ebe668SJean Delvare };
673a5ebe668SJean Delvare 
6742ec342e6SJean Delvare static struct platform_driver via686a_driver = {
675cdaf7934SLaurent Riffard 	.driver = {
67687218842SJean Delvare 		.owner	= THIS_MODULE,
6778d5d45fbSJean Delvare 		.name	= "via686a",
678cdaf7934SLaurent Riffard 	},
6792ec342e6SJean Delvare 	.probe		= via686a_probe,
6802ec342e6SJean Delvare 	.remove		= __devexit_p(via686a_remove),
6818d5d45fbSJean Delvare };
6828d5d45fbSJean Delvare 
6838d5d45fbSJean Delvare 
6848d5d45fbSJean Delvare /* This is called when the module is loaded */
6852ec342e6SJean Delvare static int __devinit via686a_probe(struct platform_device *pdev)
6868d5d45fbSJean Delvare {
6878d5d45fbSJean Delvare 	struct via686a_data *data;
6882ec342e6SJean Delvare 	struct resource *res;
6892ec342e6SJean Delvare 	int err;
6908d5d45fbSJean Delvare 
6918d5d45fbSJean Delvare 	/* Reserve the ISA region */
6922ec342e6SJean Delvare 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
6932ec342e6SJean Delvare 	if (!request_region(res->start, VIA686A_EXTENT,
694cdaf7934SLaurent Riffard 			    via686a_driver.driver.name)) {
6952ec342e6SJean Delvare 		dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
6962ec342e6SJean Delvare 			(unsigned long)res->start, (unsigned long)res->end);
6978d5d45fbSJean Delvare 		return -ENODEV;
6988d5d45fbSJean Delvare 	}
6998d5d45fbSJean Delvare 
700*9004ac81SGuenter Roeck 	data = kzalloc(sizeof(struct via686a_data), GFP_KERNEL);
701*9004ac81SGuenter Roeck 	if (!data) {
7028d5d45fbSJean Delvare 		err = -ENOMEM;
703943b0830SMark M. Hoffman 		goto exit_release;
7048d5d45fbSJean Delvare 	}
7058d5d45fbSJean Delvare 
7062ec342e6SJean Delvare 	platform_set_drvdata(pdev, data);
7072ec342e6SJean Delvare 	data->addr = res->start;
7082ec342e6SJean Delvare 	data->name = "via686a";
7099a61bf63SIngo Molnar 	mutex_init(&data->update_lock);
7108d5d45fbSJean Delvare 
7118d5d45fbSJean Delvare 	/* Initialize the VIA686A chip */
7122ec342e6SJean Delvare 	via686a_init_device(data);
7138d5d45fbSJean Delvare 
7148d5d45fbSJean Delvare 	/* Register sysfs hooks */
715*9004ac81SGuenter Roeck 	err = sysfs_create_group(&pdev->dev.kobj, &via686a_group);
716*9004ac81SGuenter Roeck 	if (err)
7172ec342e6SJean Delvare 		goto exit_free;
718a5ebe668SJean Delvare 
7191beeffe4STony Jones 	data->hwmon_dev = hwmon_device_register(&pdev->dev);
7201beeffe4STony Jones 	if (IS_ERR(data->hwmon_dev)) {
7211beeffe4STony Jones 		err = PTR_ERR(data->hwmon_dev);
722a5ebe668SJean Delvare 		goto exit_remove_files;
723943b0830SMark M. Hoffman 	}
724943b0830SMark M. Hoffman 
7258d5d45fbSJean Delvare 	return 0;
7268d5d45fbSJean Delvare 
727a5ebe668SJean Delvare exit_remove_files:
7282ec342e6SJean Delvare 	sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
729943b0830SMark M. Hoffman exit_free:
7308d5d45fbSJean Delvare 	kfree(data);
731943b0830SMark M. Hoffman exit_release:
7322ec342e6SJean Delvare 	release_region(res->start, VIA686A_EXTENT);
7338d5d45fbSJean Delvare 	return err;
7348d5d45fbSJean Delvare }
7358d5d45fbSJean Delvare 
7362ec342e6SJean Delvare static int __devexit via686a_remove(struct platform_device *pdev)
7378d5d45fbSJean Delvare {
7382ec342e6SJean Delvare 	struct via686a_data *data = platform_get_drvdata(pdev);
7398d5d45fbSJean Delvare 
7401beeffe4STony Jones 	hwmon_device_unregister(data->hwmon_dev);
7412ec342e6SJean Delvare 	sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
742943b0830SMark M. Hoffman 
7432ec342e6SJean Delvare 	release_region(data->addr, VIA686A_EXTENT);
7442ec342e6SJean Delvare 	platform_set_drvdata(pdev, NULL);
745943b0830SMark M. Hoffman 	kfree(data);
7468d5d45fbSJean Delvare 
7478d5d45fbSJean Delvare 	return 0;
7488d5d45fbSJean Delvare }
7498d5d45fbSJean Delvare 
750f790674dSJean Delvare static void via686a_update_fan_div(struct via686a_data *data)
751f790674dSJean Delvare {
752f790674dSJean Delvare 	int reg = via686a_read_value(data, VIA686A_REG_FANDIV);
753f790674dSJean Delvare 	data->fan_div[0] = (reg >> 4) & 0x03;
754f790674dSJean Delvare 	data->fan_div[1] = reg >> 6;
755f790674dSJean Delvare }
756f790674dSJean Delvare 
7572ec342e6SJean Delvare static void __devinit via686a_init_device(struct via686a_data *data)
7588d5d45fbSJean Delvare {
7598d5d45fbSJean Delvare 	u8 reg;
7608d5d45fbSJean Delvare 
7618d5d45fbSJean Delvare 	/* Start monitoring */
7622ec342e6SJean Delvare 	reg = via686a_read_value(data, VIA686A_REG_CONFIG);
7632ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
7648d5d45fbSJean Delvare 
7658d5d45fbSJean Delvare 	/* Configure temp interrupt mode for continuous-interrupt operation */
7662ec342e6SJean Delvare 	reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
7672ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_TEMP_MODE,
76858fe0809SJean Delvare 			    (reg & ~VIA686A_TEMP_MODE_MASK)
76958fe0809SJean Delvare 			    | VIA686A_TEMP_MODE_CONTINUOUS);
770f790674dSJean Delvare 
771f790674dSJean Delvare 	/* Pre-read fan clock divisor values */
772f790674dSJean Delvare 	via686a_update_fan_div(data);
7738d5d45fbSJean Delvare }
7748d5d45fbSJean Delvare 
7758d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev)
7768d5d45fbSJean Delvare {
7772ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
7788d5d45fbSJean Delvare 	int i;
7798d5d45fbSJean Delvare 
7809a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
7818d5d45fbSJean Delvare 
7828d5d45fbSJean Delvare 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
7838d5d45fbSJean Delvare 	    || !data->valid) {
7848d5d45fbSJean Delvare 		for (i = 0; i <= 4; i++) {
7858d5d45fbSJean Delvare 			data->in[i] =
7862ec342e6SJean Delvare 			    via686a_read_value(data, VIA686A_REG_IN(i));
7872ec342e6SJean Delvare 			data->in_min[i] = via686a_read_value(data,
7888d5d45fbSJean Delvare 							     VIA686A_REG_IN_MIN
7898d5d45fbSJean Delvare 							     (i));
7908d5d45fbSJean Delvare 			data->in_max[i] =
7912ec342e6SJean Delvare 			    via686a_read_value(data, VIA686A_REG_IN_MAX(i));
7928d5d45fbSJean Delvare 		}
7938d5d45fbSJean Delvare 		for (i = 1; i <= 2; i++) {
7948d5d45fbSJean Delvare 			data->fan[i - 1] =
7952ec342e6SJean Delvare 			    via686a_read_value(data, VIA686A_REG_FAN(i));
7962ec342e6SJean Delvare 			data->fan_min[i - 1] = via686a_read_value(data,
7978d5d45fbSJean Delvare 						     VIA686A_REG_FAN_MIN(i));
7988d5d45fbSJean Delvare 		}
7998d5d45fbSJean Delvare 		for (i = 0; i <= 2; i++) {
8002ec342e6SJean Delvare 			data->temp[i] = via686a_read_value(data,
8018d5d45fbSJean Delvare 						 VIA686A_REG_TEMP[i]) << 2;
8028d5d45fbSJean Delvare 			data->temp_over[i] =
8032ec342e6SJean Delvare 			    via686a_read_value(data,
8048d5d45fbSJean Delvare 					       VIA686A_REG_TEMP_OVER[i]);
8058d5d45fbSJean Delvare 			data->temp_hyst[i] =
8062ec342e6SJean Delvare 			    via686a_read_value(data,
8078d5d45fbSJean Delvare 					       VIA686A_REG_TEMP_HYST[i]);
8088d5d45fbSJean Delvare 		}
809*9004ac81SGuenter Roeck 		/*
810*9004ac81SGuenter Roeck 		 * add in lower 2 bits
811*9004ac81SGuenter Roeck 		 * temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1
812*9004ac81SGuenter Roeck 		 * temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
813*9004ac81SGuenter Roeck 		 * temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
8148d5d45fbSJean Delvare 		 */
8152ec342e6SJean Delvare 		data->temp[0] |= (via686a_read_value(data,
8168d5d45fbSJean Delvare 						     VIA686A_REG_TEMP_LOW1)
8178d5d45fbSJean Delvare 				  & 0xc0) >> 6;
8188d5d45fbSJean Delvare 		data->temp[1] |=
8192ec342e6SJean Delvare 		    (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
8208d5d45fbSJean Delvare 		     0x30) >> 4;
8218d5d45fbSJean Delvare 		data->temp[2] |=
8222ec342e6SJean Delvare 		    (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
8238d5d45fbSJean Delvare 		     0xc0) >> 6;
8248d5d45fbSJean Delvare 
825f790674dSJean Delvare 		via686a_update_fan_div(data);
8268d5d45fbSJean Delvare 		data->alarms =
8272ec342e6SJean Delvare 		    via686a_read_value(data,
8288d5d45fbSJean Delvare 				       VIA686A_REG_ALARM1) |
8292ec342e6SJean Delvare 		    (via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
8308d5d45fbSJean Delvare 		data->last_updated = jiffies;
8318d5d45fbSJean Delvare 		data->valid = 1;
8328d5d45fbSJean Delvare 	}
8338d5d45fbSJean Delvare 
8349a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
8358d5d45fbSJean Delvare 
8368d5d45fbSJean Delvare 	return data;
8378d5d45fbSJean Delvare }
8388d5d45fbSJean Delvare 
839600151b9SFrans Meulenbroeks static DEFINE_PCI_DEVICE_TABLE(via686a_pci_ids) = {
8408d5d45fbSJean Delvare 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
841*9004ac81SGuenter Roeck 	{ }
8428d5d45fbSJean Delvare };
8438d5d45fbSJean Delvare MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
8448d5d45fbSJean Delvare 
8452ec342e6SJean Delvare static int __devinit via686a_device_add(unsigned short address)
8462ec342e6SJean Delvare {
8472ec342e6SJean Delvare 	struct resource res = {
8482ec342e6SJean Delvare 		.start	= address,
8492ec342e6SJean Delvare 		.end	= address + VIA686A_EXTENT - 1,
8502ec342e6SJean Delvare 		.name	= "via686a",
8512ec342e6SJean Delvare 		.flags	= IORESOURCE_IO,
8522ec342e6SJean Delvare 	};
8532ec342e6SJean Delvare 	int err;
8542ec342e6SJean Delvare 
855b9acb64aSJean Delvare 	err = acpi_check_resource_conflict(&res);
856b9acb64aSJean Delvare 	if (err)
857b9acb64aSJean Delvare 		goto exit;
858b9acb64aSJean Delvare 
8592ec342e6SJean Delvare 	pdev = platform_device_alloc("via686a", address);
8602ec342e6SJean Delvare 	if (!pdev) {
8612ec342e6SJean Delvare 		err = -ENOMEM;
862774f7827SJoe Perches 		pr_err("Device allocation failed\n");
8632ec342e6SJean Delvare 		goto exit;
8642ec342e6SJean Delvare 	}
8652ec342e6SJean Delvare 
8662ec342e6SJean Delvare 	err = platform_device_add_resources(pdev, &res, 1);
8672ec342e6SJean Delvare 	if (err) {
868774f7827SJoe Perches 		pr_err("Device resource addition failed (%d)\n", err);
8692ec342e6SJean Delvare 		goto exit_device_put;
8702ec342e6SJean Delvare 	}
8712ec342e6SJean Delvare 
8722ec342e6SJean Delvare 	err = platform_device_add(pdev);
8732ec342e6SJean Delvare 	if (err) {
874774f7827SJoe Perches 		pr_err("Device addition failed (%d)\n", err);
8752ec342e6SJean Delvare 		goto exit_device_put;
8762ec342e6SJean Delvare 	}
8772ec342e6SJean Delvare 
8782ec342e6SJean Delvare 	return 0;
8792ec342e6SJean Delvare 
8802ec342e6SJean Delvare exit_device_put:
8812ec342e6SJean Delvare 	platform_device_put(pdev);
8822ec342e6SJean Delvare exit:
8832ec342e6SJean Delvare 	return err;
8842ec342e6SJean Delvare }
8852ec342e6SJean Delvare 
8868d5d45fbSJean Delvare static int __devinit via686a_pci_probe(struct pci_dev *dev,
8878d5d45fbSJean Delvare 				       const struct pci_device_id *id)
8888d5d45fbSJean Delvare {
8892ec342e6SJean Delvare 	u16 address, val;
8908d5d45fbSJean Delvare 
8912ec342e6SJean Delvare 	if (force_addr) {
8922ec342e6SJean Delvare 		address = force_addr & ~(VIA686A_EXTENT - 1);
8932ec342e6SJean Delvare 		dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
8942ec342e6SJean Delvare 		if (PCIBIOS_SUCCESSFUL !=
8952ec342e6SJean Delvare 		    pci_write_config_word(dev, VIA686A_BASE_REG, address | 1))
8962ec342e6SJean Delvare 			return -ENODEV;
8972ec342e6SJean Delvare 	}
8988d5d45fbSJean Delvare 	if (PCIBIOS_SUCCESSFUL !=
8998d5d45fbSJean Delvare 	    pci_read_config_word(dev, VIA686A_BASE_REG, &val))
9008d5d45fbSJean Delvare 		return -ENODEV;
9018d5d45fbSJean Delvare 
9022d8672c5SJean Delvare 	address = val & ~(VIA686A_EXTENT - 1);
9032ec342e6SJean Delvare 	if (address == 0) {
9048d5d45fbSJean Delvare 		dev_err(&dev->dev, "base address not set - upgrade BIOS "
9058d5d45fbSJean Delvare 			"or use force_addr=0xaddr\n");
9068d5d45fbSJean Delvare 		return -ENODEV;
9078d5d45fbSJean Delvare 	}
9088d5d45fbSJean Delvare 
9092ec342e6SJean Delvare 	if (PCIBIOS_SUCCESSFUL !=
9102ec342e6SJean Delvare 	    pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
9112ec342e6SJean Delvare 		return -ENODEV;
9122ec342e6SJean Delvare 	if (!(val & 0x0001)) {
9132ec342e6SJean Delvare 		if (!force_addr) {
9142ec342e6SJean Delvare 			dev_warn(&dev->dev, "Sensors disabled, enable "
9152ec342e6SJean Delvare 				 "with force_addr=0x%x\n", address);
9162ec342e6SJean Delvare 			return -ENODEV;
9178d5d45fbSJean Delvare 		}
9188d5d45fbSJean Delvare 
9192ec342e6SJean Delvare 		dev_warn(&dev->dev, "Enabling sensors\n");
9202ec342e6SJean Delvare 		if (PCIBIOS_SUCCESSFUL !=
9212ec342e6SJean Delvare 		    pci_write_config_word(dev, VIA686A_ENABLE_REG,
9222ec342e6SJean Delvare 					  val | 0x0001))
9232ec342e6SJean Delvare 			return -ENODEV;
9242ec342e6SJean Delvare 	}
9252ec342e6SJean Delvare 
9262ec342e6SJean Delvare 	if (platform_driver_register(&via686a_driver))
9272ec342e6SJean Delvare 		goto exit;
9282ec342e6SJean Delvare 
9292ec342e6SJean Delvare 	/* Sets global pdev as a side effect */
9302ec342e6SJean Delvare 	if (via686a_device_add(address))
9312ec342e6SJean Delvare 		goto exit_unregister;
9322ec342e6SJean Delvare 
933*9004ac81SGuenter Roeck 	/*
934*9004ac81SGuenter Roeck 	 * Always return failure here.  This is to allow other drivers to bind
9358d5d45fbSJean Delvare 	 * to this pci device.  We don't really want to have control over the
9368d5d45fbSJean Delvare 	 * pci device, we only wanted to read as few register values from it.
9378d5d45fbSJean Delvare 	 */
9382ec342e6SJean Delvare 	s_bridge = pci_dev_get(dev);
9392ec342e6SJean Delvare 	return -ENODEV;
9402ec342e6SJean Delvare 
9412ec342e6SJean Delvare exit_unregister:
9422ec342e6SJean Delvare 	platform_driver_unregister(&via686a_driver);
9432ec342e6SJean Delvare exit:
9448d5d45fbSJean Delvare 	return -ENODEV;
9458d5d45fbSJean Delvare }
9468d5d45fbSJean Delvare 
9478d5d45fbSJean Delvare static struct pci_driver via686a_pci_driver = {
9488d5d45fbSJean Delvare 	.name		= "via686a",
9498d5d45fbSJean Delvare 	.id_table	= via686a_pci_ids,
9508d5d45fbSJean Delvare 	.probe		= via686a_pci_probe,
9518d5d45fbSJean Delvare };
9528d5d45fbSJean Delvare 
9538d5d45fbSJean Delvare static int __init sm_via686a_init(void)
9548d5d45fbSJean Delvare {
9558d5d45fbSJean Delvare 	return pci_register_driver(&via686a_pci_driver);
9568d5d45fbSJean Delvare }
9578d5d45fbSJean Delvare 
9588d5d45fbSJean Delvare static void __exit sm_via686a_exit(void)
9598d5d45fbSJean Delvare {
9608d5d45fbSJean Delvare 	pci_unregister_driver(&via686a_pci_driver);
9618d5d45fbSJean Delvare 	if (s_bridge != NULL) {
9622ec342e6SJean Delvare 		platform_device_unregister(pdev);
9632ec342e6SJean Delvare 		platform_driver_unregister(&via686a_driver);
9648d5d45fbSJean Delvare 		pci_dev_put(s_bridge);
9658d5d45fbSJean Delvare 		s_bridge = NULL;
9668d5d45fbSJean Delvare 	}
9678d5d45fbSJean Delvare }
9688d5d45fbSJean Delvare 
96996de0e25SJan Engelhardt MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, "
9708d5d45fbSJean Delvare 	      "Mark Studebaker <mdsxyz123@yahoo.com> "
9718d5d45fbSJean Delvare 	      "and Bob Dougherty <bobd@stanford.edu>");
9728d5d45fbSJean Delvare MODULE_DESCRIPTION("VIA 686A Sensor device");
9738d5d45fbSJean Delvare MODULE_LICENSE("GPL");
9748d5d45fbSJean Delvare 
9758d5d45fbSJean Delvare module_init(sm_via686a_init);
9768d5d45fbSJean Delvare module_exit(sm_via686a_exit);
977