xref: /linux/drivers/hwmon/via686a.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28d5d45fbSJean Delvare /*
39004ac81SGuenter Roeck  * via686a.c - Part of lm_sensors, Linux kernel modules
49004ac81SGuenter Roeck  *	       for hardware monitoring
59004ac81SGuenter Roeck  *
69004ac81SGuenter Roeck  * Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
79004ac81SGuenter Roeck  *			      Kyösti Mälkki <kmalkki@cc.hut.fi>,
89004ac81SGuenter Roeck  *			      Mark Studebaker <mdsxyz123@yahoo.com>,
99004ac81SGuenter Roeck  *			      and Bob Dougherty <bobd@stanford.edu>
109004ac81SGuenter Roeck  *
119004ac81SGuenter Roeck  * (Some conversion-factor data were contributed by Jonathan Teh Soon Yew
129004ac81SGuenter Roeck  * <j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.)
138d5d45fbSJean Delvare  */
148d5d45fbSJean Delvare 
158d5d45fbSJean Delvare /*
169004ac81SGuenter Roeck  * Supports the Via VT82C686A, VT82C686B south bridges.
179004ac81SGuenter Roeck  * Reports all as a 686A.
189004ac81SGuenter Roeck  * Warning - only supports a single device.
198d5d45fbSJean Delvare  */
208d5d45fbSJean Delvare 
21774f7827SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22774f7827SJoe Perches 
238d5d45fbSJean Delvare #include <linux/module.h>
248d5d45fbSJean Delvare #include <linux/slab.h>
258d5d45fbSJean Delvare #include <linux/pci.h>
268d5d45fbSJean Delvare #include <linux/jiffies.h>
272ec342e6SJean Delvare #include <linux/platform_device.h>
28943b0830SMark M. Hoffman #include <linux/hwmon.h>
291e71a5a2SJean Delvare #include <linux/hwmon-sysfs.h>
30943b0830SMark M. Hoffman #include <linux/err.h>
318d5d45fbSJean Delvare #include <linux/init.h>
329a61bf63SIngo Molnar #include <linux/mutex.h>
33a5ebe668SJean Delvare #include <linux/sysfs.h>
34b9acb64aSJean Delvare #include <linux/acpi.h>
356055fae8SH Hartley Sweeten #include <linux/io.h>
368d5d45fbSJean Delvare 
3750e52c1fSUwe Kleine-König #define DRIVER_NAME "via686a"
3850e52c1fSUwe Kleine-König 
399004ac81SGuenter Roeck /*
409004ac81SGuenter Roeck  * If force_addr is set to anything different from 0, we forcibly enable
419004ac81SGuenter Roeck  * the device at the given address.
429004ac81SGuenter Roeck  */
4302002963SJean Delvare static unsigned short force_addr;
448d5d45fbSJean Delvare module_param(force_addr, ushort, 0);
458d5d45fbSJean Delvare MODULE_PARM_DESC(force_addr,
468d5d45fbSJean Delvare 		 "Initialize the base address of the sensors");
478d5d45fbSJean Delvare 
482ec342e6SJean Delvare static struct platform_device *pdev;
498d5d45fbSJean Delvare 
508d5d45fbSJean Delvare /*
519004ac81SGuenter Roeck  * The Via 686a southbridge has a LM78-like chip integrated on the same IC.
529004ac81SGuenter Roeck  * This driver is a customized copy of lm78.c
538d5d45fbSJean Delvare  */
548d5d45fbSJean Delvare 
558d5d45fbSJean Delvare /* Many VIA686A constants specified below */
568d5d45fbSJean Delvare 
578d5d45fbSJean Delvare /* Length of ISA address segment */
588d5d45fbSJean Delvare #define VIA686A_EXTENT		0x80
598d5d45fbSJean Delvare #define VIA686A_BASE_REG	0x70
608d5d45fbSJean Delvare #define VIA686A_ENABLE_REG	0x74
618d5d45fbSJean Delvare 
628d5d45fbSJean Delvare /* The VIA686A registers */
638d5d45fbSJean Delvare /* ins numbered 0-4 */
648d5d45fbSJean Delvare #define VIA686A_REG_IN_MAX(nr)	(0x2b + ((nr) * 2))
658d5d45fbSJean Delvare #define VIA686A_REG_IN_MIN(nr)	(0x2c + ((nr) * 2))
668d5d45fbSJean Delvare #define VIA686A_REG_IN(nr)	(0x22 + (nr))
678d5d45fbSJean Delvare 
688d5d45fbSJean Delvare /* fans numbered 1-2 */
698d5d45fbSJean Delvare #define VIA686A_REG_FAN_MIN(nr)	(0x3a + (nr))
708d5d45fbSJean Delvare #define VIA686A_REG_FAN(nr)	(0x28 + (nr))
718d5d45fbSJean Delvare 
728d5d45fbSJean Delvare /* temps numbered 1-3 */
738d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP[]	= { 0x20, 0x21, 0x1f };
748d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_OVER[]	= { 0x39, 0x3d, 0x1d };
758d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_HYST[]	= { 0x3a, 0x3e, 0x1e };
768d5d45fbSJean Delvare /* bits 7-6 */
778d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW1	0x4b
788d5d45fbSJean Delvare /* 2 = bits 5-4, 3 = bits 7-6 */
798d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW23	0x49
808d5d45fbSJean Delvare 
818d5d45fbSJean Delvare #define VIA686A_REG_ALARM1	0x41
828d5d45fbSJean Delvare #define VIA686A_REG_ALARM2	0x42
838d5d45fbSJean Delvare #define VIA686A_REG_FANDIV	0x47
848d5d45fbSJean Delvare #define VIA686A_REG_CONFIG	0x40
859004ac81SGuenter Roeck /*
869004ac81SGuenter Roeck  * The following register sets temp interrupt mode (bits 1-0 for temp1,
879004ac81SGuenter Roeck  * 3-2 for temp2, 5-4 for temp3).  Modes are:
889004ac81SGuenter Roeck  * 00 interrupt stays as long as value is out-of-range
899004ac81SGuenter Roeck  * 01 interrupt is cleared once register is read (default)
909004ac81SGuenter Roeck  * 10 comparator mode- like 00, but ignores hysteresis
919004ac81SGuenter Roeck  * 11 same as 00
929004ac81SGuenter Roeck  */
938d5d45fbSJean Delvare #define VIA686A_REG_TEMP_MODE		0x4b
948d5d45fbSJean Delvare /* We'll just assume that you want to set all 3 simultaneously: */
958d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_MASK		0x3F
968d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_CONTINUOUS	0x00
978d5d45fbSJean Delvare 
989004ac81SGuenter Roeck /*
999004ac81SGuenter Roeck  * Conversions. Limit checking is only done on the TO_REG
1009004ac81SGuenter Roeck  * variants.
1019004ac81SGuenter Roeck  *
1029004ac81SGuenter Roeck  ******** VOLTAGE CONVERSIONS (Bob Dougherty) ********
1039004ac81SGuenter Roeck  * From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew):
1049004ac81SGuenter Roeck  * voltagefactor[0]=1.25/2628; (2628/1.25=2102.4)   // Vccp
1059004ac81SGuenter Roeck  * voltagefactor[1]=1.25/2628; (2628/1.25=2102.4)   // +2.5V
1069004ac81SGuenter Roeck  * voltagefactor[2]=1.67/2628; (2628/1.67=1573.7)   // +3.3V
1079004ac81SGuenter Roeck  * voltagefactor[3]=2.6/2628;  (2628/2.60=1010.8)   // +5V
1089004ac81SGuenter Roeck  * voltagefactor[4]=6.3/2628;  (2628/6.30=417.14)   // +12V
1099004ac81SGuenter Roeck  * in[i]=(data[i+2]*25.0+133)*voltagefactor[i];
1109004ac81SGuenter Roeck  * That is:
1119004ac81SGuenter Roeck  * volts = (25*regVal+133)*factor
1129004ac81SGuenter Roeck  * regVal = (volts/factor-133)/25
1139004ac81SGuenter Roeck  * (These conversions were contributed by Jonathan Teh Soon Yew
1149004ac81SGuenter Roeck  * <j.teh@iname.com>)
1159004ac81SGuenter Roeck  */
IN_TO_REG(long val,int in_num)116088ce2acSGuenter Roeck static inline u8 IN_TO_REG(long val, int in_num)
1178d5d45fbSJean Delvare {
1189004ac81SGuenter Roeck 	/*
1199004ac81SGuenter Roeck 	 * To avoid floating point, we multiply constants by 10 (100 for +12V).
1209004ac81SGuenter Roeck 	 * Rounding is done (120500 is actually 133000 - 12500).
1219004ac81SGuenter Roeck 	 * Remember that val is expressed in 0.001V/bit, which is why we divide
1229004ac81SGuenter Roeck 	 * by an additional 10000 (100000 for +12V): 1000 for val and 10 (100)
1239004ac81SGuenter Roeck 	 * for the constants.
1249004ac81SGuenter Roeck 	 */
125088ce2acSGuenter Roeck 	if (in_num <= 1)
1262a844c14SGuenter Roeck 		return (u8) clamp_val((val * 21024 - 1205000) / 250000, 0, 255);
127088ce2acSGuenter Roeck 	else if (in_num == 2)
1282a844c14SGuenter Roeck 		return (u8) clamp_val((val * 15737 - 1205000) / 250000, 0, 255);
129088ce2acSGuenter Roeck 	else if (in_num == 3)
1302a844c14SGuenter Roeck 		return (u8) clamp_val((val * 10108 - 1205000) / 250000, 0, 255);
1318d5d45fbSJean Delvare 	else
1322a844c14SGuenter Roeck 		return (u8) clamp_val((val * 41714 - 12050000) / 2500000, 0,
1332a844c14SGuenter Roeck 				      255);
1348d5d45fbSJean Delvare }
1358d5d45fbSJean Delvare 
IN_FROM_REG(u8 val,int in_num)136088ce2acSGuenter Roeck static inline long IN_FROM_REG(u8 val, int in_num)
1378d5d45fbSJean Delvare {
1389004ac81SGuenter Roeck 	/*
1399004ac81SGuenter Roeck 	 * To avoid floating point, we multiply constants by 10 (100 for +12V).
1409004ac81SGuenter Roeck 	 * We also multiply them by 1000 because we want 0.001V/bit for the
1419004ac81SGuenter Roeck 	 * output value. Rounding is done.
1429004ac81SGuenter Roeck 	 */
143088ce2acSGuenter Roeck 	if (in_num <= 1)
1448d5d45fbSJean Delvare 		return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024);
145088ce2acSGuenter Roeck 	else if (in_num == 2)
1468d5d45fbSJean Delvare 		return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737);
147088ce2acSGuenter Roeck 	else if (in_num == 3)
1488d5d45fbSJean Delvare 		return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108);
1498d5d45fbSJean Delvare 	else
1508d5d45fbSJean Delvare 		return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714);
1518d5d45fbSJean Delvare }
1528d5d45fbSJean Delvare 
1538d5d45fbSJean Delvare /********* FAN RPM CONVERSIONS ********/
1549004ac81SGuenter Roeck /*
1559004ac81SGuenter Roeck  * Higher register values = slower fans (the fan's strobe gates a counter).
1569004ac81SGuenter Roeck  * But this chip saturates back at 0, not at 255 like all the other chips.
1579004ac81SGuenter Roeck  * So, 0 means 0 RPM
1589004ac81SGuenter Roeck  */
FAN_TO_REG(long rpm,int div)1598d5d45fbSJean Delvare static inline u8 FAN_TO_REG(long rpm, int div)
1608d5d45fbSJean Delvare {
1618d5d45fbSJean Delvare 	if (rpm == 0)
1628d5d45fbSJean Delvare 		return 0;
1632a844c14SGuenter Roeck 	rpm = clamp_val(rpm, 1, 1000000);
1642a844c14SGuenter Roeck 	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 255);
1658d5d45fbSJean Delvare }
1668d5d45fbSJean Delvare 
1679004ac81SGuenter Roeck #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (val) == 255 ? 0 : 1350000 / \
1689004ac81SGuenter Roeck 				((val) * (div)))
1698d5d45fbSJean Delvare 
1708d5d45fbSJean Delvare /******** TEMP CONVERSIONS (Bob Dougherty) *********/
1719004ac81SGuenter Roeck /*
1729004ac81SGuenter Roeck  * linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew)
1739004ac81SGuenter Roeck  *	if(temp<169)
1749004ac81SGuenter Roeck  *		return double(temp)*0.427-32.08;
1759004ac81SGuenter Roeck  *	else if(temp>=169 && temp<=202)
1769004ac81SGuenter Roeck  *		return double(temp)*0.582-58.16;
1779004ac81SGuenter Roeck  *	else
1789004ac81SGuenter Roeck  *		return double(temp)*0.924-127.33;
1799004ac81SGuenter Roeck  *
1809004ac81SGuenter Roeck  * A fifth-order polynomial fits the unofficial data (provided by Alex van
1819004ac81SGuenter Roeck  * Kaam <darkside@chello.nl>) a bit better.  It also give more reasonable
1829004ac81SGuenter Roeck  * numbers on my machine (ie. they agree with what my BIOS tells me).
1839004ac81SGuenter Roeck  * Here's the fifth-order fit to the 8-bit data:
1849004ac81SGuenter Roeck  * temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 -
1859004ac81SGuenter Roeck  *	2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0.
1869004ac81SGuenter Roeck  *
1879004ac81SGuenter Roeck  * (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for
1889004ac81SGuenter Roeck  * finding my typos in this formula!)
1899004ac81SGuenter Roeck  *
1909004ac81SGuenter Roeck  * Alas, none of the elegant function-fit solutions will work because we
1919004ac81SGuenter Roeck  * aren't allowed to use floating point in the kernel and doing it with
1929004ac81SGuenter Roeck  * integers doesn't provide enough precision.  So we'll do boring old
1939004ac81SGuenter Roeck  * look-up table stuff.  The unofficial data (see below) have effectively
1949004ac81SGuenter Roeck  * 7-bit resolution (they are rounded to the nearest degree).  I'm assuming
1959004ac81SGuenter Roeck  * that the transfer function of the device is monotonic and smooth, so a
1969004ac81SGuenter Roeck  * smooth function fit to the data will allow us to get better precision.
1979004ac81SGuenter Roeck  * I used the 5th-order poly fit described above and solved for
1989004ac81SGuenter Roeck  * VIA register values 0-255.  I *10 before rounding, so we get tenth-degree
1999004ac81SGuenter Roeck  * precision.  (I could have done all 1024 values for our 10-bit readings,
2009004ac81SGuenter Roeck  * but the function is very linear in the useful range (0-80 deg C), so
201088ce2acSGuenter Roeck  * we'll just use linear interpolation for 10-bit readings.)  So, temp_lut
2029004ac81SGuenter Roeck  * is the temp at via register values 0-255:
2039004ac81SGuenter Roeck  */
204088ce2acSGuenter Roeck static const s16 temp_lut[] = {
2059004ac81SGuenter Roeck 	-709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
2068d5d45fbSJean Delvare 	-503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
2078d5d45fbSJean Delvare 	-362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
2088d5d45fbSJean Delvare 	-255, -246, -237, -229, -220, -212, -204, -196, -188, -180,
2098d5d45fbSJean Delvare 	-173, -166, -159, -152, -145, -139, -132, -126, -120, -114,
2108d5d45fbSJean Delvare 	-108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49,
2118d5d45fbSJean Delvare 	-44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16,
2128d5d45fbSJean Delvare 	20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84,
2138d5d45fbSJean Delvare 	88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138,
2148d5d45fbSJean Delvare 	142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189,
2158d5d45fbSJean Delvare 	193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241,
2168d5d45fbSJean Delvare 	245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294,
2178d5d45fbSJean Delvare 	299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348,
2188d5d45fbSJean Delvare 	353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404,
2198d5d45fbSJean Delvare 	409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464,
2208d5d45fbSJean Delvare 	469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532,
2218d5d45fbSJean Delvare 	538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614,
2228d5d45fbSJean Delvare 	621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718,
2238d5d45fbSJean Delvare 	728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856,
2248d5d45fbSJean Delvare 	870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044,
2258d5d45fbSJean Delvare 	1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252,
2268d5d45fbSJean Delvare 	1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462
2278d5d45fbSJean Delvare };
2288d5d45fbSJean Delvare 
2299004ac81SGuenter Roeck /*
2309004ac81SGuenter Roeck  * the original LUT values from Alex van Kaam <darkside@chello.nl>
2319004ac81SGuenter Roeck  * (for via register values 12-240):
2329004ac81SGuenter Roeck  * {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31,
2339004ac81SGuenter Roeck  * -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15,
2349004ac81SGuenter Roeck  * -15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3,
2359004ac81SGuenter 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,
2369004ac81SGuenter 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,
2379004ac81SGuenter 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,
2389004ac81SGuenter 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,
2399004ac81SGuenter 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,
2409004ac81SGuenter 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,
2419004ac81SGuenter Roeck  * 85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110};
2429004ac81SGuenter Roeck  *
2439004ac81SGuenter Roeck  *
2449004ac81SGuenter Roeck  * Here's the reverse LUT.  I got it by doing a 6-th order poly fit (needed
2459004ac81SGuenter Roeck  * an extra term for a good fit to these inverse data!) and then
2469004ac81SGuenter Roeck  * solving for each temp value from -50 to 110 (the useable range for
2479004ac81SGuenter Roeck  * this chip).  Here's the fit:
2489004ac81SGuenter Roeck  * viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4
2499004ac81SGuenter Roeck  * - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
2509004ac81SGuenter Roeck  * Note that n=161:
2519004ac81SGuenter Roeck  */
252088ce2acSGuenter Roeck static const u8 via_lut[] = {
2539004ac81SGuenter Roeck 	12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
2548d5d45fbSJean Delvare 	23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
2558d5d45fbSJean Delvare 	41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
2568d5d45fbSJean Delvare 	69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100,
2578d5d45fbSJean Delvare 	103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129,
2588d5d45fbSJean Delvare 	131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156,
2598d5d45fbSJean Delvare 	158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
2608d5d45fbSJean Delvare 	182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199,
2618d5d45fbSJean Delvare 	200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213,
2628d5d45fbSJean Delvare 	214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224,
2638d5d45fbSJean Delvare 	225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232,
2648d5d45fbSJean Delvare 	233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
2658d5d45fbSJean Delvare 	239, 240
2668d5d45fbSJean Delvare };
2678d5d45fbSJean Delvare 
2689004ac81SGuenter Roeck /*
2699004ac81SGuenter Roeck  * Converting temps to (8-bit) hyst and over registers
2709004ac81SGuenter Roeck  * No interpolation here.
2719004ac81SGuenter Roeck  * The +50 is because the temps start at -50
2729004ac81SGuenter Roeck  */
TEMP_TO_REG(long val)2738d5d45fbSJean Delvare static inline u8 TEMP_TO_REG(long val)
2748d5d45fbSJean Delvare {
275088ce2acSGuenter Roeck 	return via_lut[val <= -50000 ? 0 : val >= 110000 ? 160 :
2768d5d45fbSJean Delvare 		      (val < 0 ? val - 500 : val + 500) / 1000 + 50];
2778d5d45fbSJean Delvare }
2788d5d45fbSJean Delvare 
2798d5d45fbSJean Delvare /* for 8-bit temperature hyst and over registers */
280088ce2acSGuenter Roeck #define TEMP_FROM_REG(val)	((long)temp_lut[val] * 100)
2818d5d45fbSJean Delvare 
2828d5d45fbSJean Delvare /* for 10-bit temperature readings */
TEMP_FROM_REG10(u16 val)2838d5d45fbSJean Delvare static inline long TEMP_FROM_REG10(u16 val)
2848d5d45fbSJean Delvare {
285088ce2acSGuenter Roeck 	u16 eight_bits = val >> 2;
286088ce2acSGuenter Roeck 	u16 two_bits = val & 3;
2878d5d45fbSJean Delvare 
2888d5d45fbSJean Delvare 	/* no interpolation for these */
289088ce2acSGuenter Roeck 	if (two_bits == 0 || eight_bits == 255)
290088ce2acSGuenter Roeck 		return TEMP_FROM_REG(eight_bits);
2918d5d45fbSJean Delvare 
2928d5d45fbSJean Delvare 	/* do some linear interpolation */
293088ce2acSGuenter Roeck 	return (temp_lut[eight_bits] * (4 - two_bits) +
294088ce2acSGuenter Roeck 		temp_lut[eight_bits + 1] * two_bits) * 25;
2958d5d45fbSJean Delvare }
2968d5d45fbSJean Delvare 
2978d5d45fbSJean Delvare #define DIV_FROM_REG(val) (1 << (val))
2988d5d45fbSJean Delvare #define DIV_TO_REG(val) ((val) == 8 ? 3 : (val) == 4 ? 2 : (val) == 1 ? 0 : 1)
2998d5d45fbSJean Delvare 
3009004ac81SGuenter Roeck /*
3019004ac81SGuenter Roeck  * For each registered chip, we need to keep some data in memory.
3029004ac81SGuenter Roeck  * The structure is dynamically allocated.
3039004ac81SGuenter Roeck  */
3048d5d45fbSJean Delvare struct via686a_data {
3052ec342e6SJean Delvare 	unsigned short addr;
3062ec342e6SJean Delvare 	const char *name;
3071beeffe4STony Jones 	struct device *hwmon_dev;
3089a61bf63SIngo Molnar 	struct mutex update_lock;
309952a11caSPaul Fertser 	bool valid;		/* true if following fields are valid */
3108d5d45fbSJean Delvare 	unsigned long last_updated;	/* In jiffies */
3118d5d45fbSJean Delvare 
3128d5d45fbSJean Delvare 	u8 in[5];		/* Register value */
3138d5d45fbSJean Delvare 	u8 in_max[5];		/* Register value */
3148d5d45fbSJean Delvare 	u8 in_min[5];		/* Register value */
3158d5d45fbSJean Delvare 	u8 fan[2];		/* Register value */
3168d5d45fbSJean Delvare 	u8 fan_min[2];		/* Register value */
3178d5d45fbSJean Delvare 	u16 temp[3];		/* Register value 10 bit */
3188d5d45fbSJean Delvare 	u8 temp_over[3];	/* Register value */
3198d5d45fbSJean Delvare 	u8 temp_hyst[3];	/* Register value */
3208d5d45fbSJean Delvare 	u8 fan_div[2];		/* Register encoding, shifted right */
3218d5d45fbSJean Delvare 	u16 alarms;		/* Register encoding, combined */
3228d5d45fbSJean Delvare };
3238d5d45fbSJean Delvare 
3248d5d45fbSJean Delvare static struct pci_dev *s_bridge;	/* pointer to the (only) via686a */
3258d5d45fbSJean Delvare 
via686a_read_value(struct via686a_data * data,u8 reg)3262ec342e6SJean Delvare static inline int via686a_read_value(struct via686a_data *data, u8 reg)
3278d5d45fbSJean Delvare {
3282ec342e6SJean Delvare 	return inb_p(data->addr + reg);
3298d5d45fbSJean Delvare }
3308d5d45fbSJean Delvare 
via686a_write_value(struct via686a_data * data,u8 reg,u8 value)3312ec342e6SJean Delvare static inline void via686a_write_value(struct via686a_data *data, u8 reg,
3328d5d45fbSJean Delvare 				       u8 value)
3338d5d45fbSJean Delvare {
3342ec342e6SJean Delvare 	outb_p(value, data->addr + reg);
3358d5d45fbSJean Delvare }
3368d5d45fbSJean Delvare 
via686a_update_fan_div(struct via686a_data * data)337984fed56SUwe Kleine-König static void via686a_update_fan_div(struct via686a_data *data)
338984fed56SUwe Kleine-König {
339984fed56SUwe Kleine-König 	int reg = via686a_read_value(data, VIA686A_REG_FANDIV);
340984fed56SUwe Kleine-König 	data->fan_div[0] = (reg >> 4) & 0x03;
341984fed56SUwe Kleine-König 	data->fan_div[1] = reg >> 6;
342984fed56SUwe Kleine-König }
343984fed56SUwe Kleine-König 
via686a_update_device(struct device * dev)344984fed56SUwe Kleine-König static struct via686a_data *via686a_update_device(struct device *dev)
345984fed56SUwe Kleine-König {
346984fed56SUwe Kleine-König 	struct via686a_data *data = dev_get_drvdata(dev);
347984fed56SUwe Kleine-König 	int i;
348984fed56SUwe Kleine-König 
349984fed56SUwe Kleine-König 	mutex_lock(&data->update_lock);
350984fed56SUwe Kleine-König 
351984fed56SUwe Kleine-König 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
352984fed56SUwe Kleine-König 	    || !data->valid) {
353984fed56SUwe Kleine-König 		for (i = 0; i <= 4; i++) {
354984fed56SUwe Kleine-König 			data->in[i] =
355984fed56SUwe Kleine-König 			    via686a_read_value(data, VIA686A_REG_IN(i));
356984fed56SUwe Kleine-König 			data->in_min[i] = via686a_read_value(data,
357984fed56SUwe Kleine-König 							     VIA686A_REG_IN_MIN
358984fed56SUwe Kleine-König 							     (i));
359984fed56SUwe Kleine-König 			data->in_max[i] =
360984fed56SUwe Kleine-König 			    via686a_read_value(data, VIA686A_REG_IN_MAX(i));
361984fed56SUwe Kleine-König 		}
362984fed56SUwe Kleine-König 		for (i = 1; i <= 2; i++) {
363984fed56SUwe Kleine-König 			data->fan[i - 1] =
364984fed56SUwe Kleine-König 			    via686a_read_value(data, VIA686A_REG_FAN(i));
365984fed56SUwe Kleine-König 			data->fan_min[i - 1] = via686a_read_value(data,
366984fed56SUwe Kleine-König 						     VIA686A_REG_FAN_MIN(i));
367984fed56SUwe Kleine-König 		}
368984fed56SUwe Kleine-König 		for (i = 0; i <= 2; i++) {
369984fed56SUwe Kleine-König 			data->temp[i] = via686a_read_value(data,
370984fed56SUwe Kleine-König 						 VIA686A_REG_TEMP[i]) << 2;
371984fed56SUwe Kleine-König 			data->temp_over[i] =
372984fed56SUwe Kleine-König 			    via686a_read_value(data,
373984fed56SUwe Kleine-König 					       VIA686A_REG_TEMP_OVER[i]);
374984fed56SUwe Kleine-König 			data->temp_hyst[i] =
375984fed56SUwe Kleine-König 			    via686a_read_value(data,
376984fed56SUwe Kleine-König 					       VIA686A_REG_TEMP_HYST[i]);
377984fed56SUwe Kleine-König 		}
378984fed56SUwe Kleine-König 		/*
379984fed56SUwe Kleine-König 		 * add in lower 2 bits
380984fed56SUwe Kleine-König 		 * temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1
381984fed56SUwe Kleine-König 		 * temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
382984fed56SUwe Kleine-König 		 * temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
383984fed56SUwe Kleine-König 		 */
384984fed56SUwe Kleine-König 		data->temp[0] |= (via686a_read_value(data,
385984fed56SUwe Kleine-König 						     VIA686A_REG_TEMP_LOW1)
386984fed56SUwe Kleine-König 				  & 0xc0) >> 6;
387984fed56SUwe Kleine-König 		data->temp[1] |=
388984fed56SUwe Kleine-König 		    (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
389984fed56SUwe Kleine-König 		     0x30) >> 4;
390984fed56SUwe Kleine-König 		data->temp[2] |=
391984fed56SUwe Kleine-König 		    (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
392984fed56SUwe Kleine-König 		     0xc0) >> 6;
393984fed56SUwe Kleine-König 
394984fed56SUwe Kleine-König 		via686a_update_fan_div(data);
395984fed56SUwe Kleine-König 		data->alarms =
396984fed56SUwe Kleine-König 		    via686a_read_value(data,
397984fed56SUwe Kleine-König 				       VIA686A_REG_ALARM1) |
398984fed56SUwe Kleine-König 		    (via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
399984fed56SUwe Kleine-König 		data->last_updated = jiffies;
400984fed56SUwe Kleine-König 		data->valid = true;
401984fed56SUwe Kleine-König 	}
402984fed56SUwe Kleine-König 
403984fed56SUwe Kleine-König 	mutex_unlock(&data->update_lock);
404984fed56SUwe Kleine-König 
405984fed56SUwe Kleine-König 	return data;
406984fed56SUwe Kleine-König }
4078d5d45fbSJean Delvare 
4088d5d45fbSJean Delvare /* following are the sysfs callback functions */
4098d5d45fbSJean Delvare 
4108d5d45fbSJean Delvare /* 7 voltage sensors */
in_show(struct device * dev,struct device_attribute * da,char * buf)4119d5bc090SGuenter Roeck static ssize_t in_show(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", IN_FROM_REG(data->in[nr], nr));
4178d5d45fbSJean Delvare }
4188d5d45fbSJean Delvare 
in_min_show(struct device * dev,struct device_attribute * da,char * buf)4199d5bc090SGuenter Roeck static ssize_t in_min_show(struct device *dev, struct device_attribute *da,
4201e71a5a2SJean Delvare 			   char *buf) {
4218d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4221e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4231e71a5a2SJean Delvare 	int nr = attr->index;
4248d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr));
4258d5d45fbSJean Delvare }
4268d5d45fbSJean Delvare 
in_max_show(struct device * dev,struct device_attribute * da,char * buf)4279d5bc090SGuenter Roeck static ssize_t in_max_show(struct device *dev, struct device_attribute *da,
4281e71a5a2SJean Delvare 			   char *buf) {
4298d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4301e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4311e71a5a2SJean Delvare 	int nr = attr->index;
4328d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
4338d5d45fbSJean Delvare }
4348d5d45fbSJean Delvare 
in_min_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)4359d5bc090SGuenter Roeck static ssize_t in_min_store(struct device *dev, struct device_attribute *da,
4361e71a5a2SJean Delvare 			    const char *buf, size_t count) {
4372ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
4381e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4391e71a5a2SJean Delvare 	int nr = attr->index;
4409004ac81SGuenter Roeck 	unsigned long val;
4419004ac81SGuenter Roeck 	int err;
4429004ac81SGuenter Roeck 
4439004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
4449004ac81SGuenter Roeck 	if (err)
4459004ac81SGuenter Roeck 		return err;
4468d5d45fbSJean Delvare 
4479a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4488d5d45fbSJean Delvare 	data->in_min[nr] = IN_TO_REG(val, nr);
4492ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_IN_MIN(nr),
4508d5d45fbSJean Delvare 			data->in_min[nr]);
4519a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4528d5d45fbSJean Delvare 	return count;
4538d5d45fbSJean Delvare }
in_max_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)4549d5bc090SGuenter Roeck static ssize_t in_max_store(struct device *dev, struct device_attribute *da,
4551e71a5a2SJean Delvare 			    const char *buf, size_t count) {
4562ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
4571e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4581e71a5a2SJean Delvare 	int nr = attr->index;
4599004ac81SGuenter Roeck 	unsigned long val;
4609004ac81SGuenter Roeck 	int err;
4619004ac81SGuenter Roeck 
4629004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
4639004ac81SGuenter Roeck 	if (err)
4649004ac81SGuenter Roeck 		return err;
4658d5d45fbSJean Delvare 
4669a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4678d5d45fbSJean Delvare 	data->in_max[nr] = IN_TO_REG(val, nr);
4682ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_IN_MAX(nr),
4698d5d45fbSJean Delvare 			data->in_max[nr]);
4709a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4718d5d45fbSJean Delvare 	return count;
4728d5d45fbSJean Delvare }
4738d5d45fbSJean Delvare 
4749d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in0_input, in, 0);
4759d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in0_min, in_min, 0);
4769d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in0_max, in_max, 0);
4779d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in1_input, in, 1);
4789d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 1);
4799d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 1);
4809d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in2_input, in, 2);
4819d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 2);
4829d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 2);
4839d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in3_input, in, 3);
4849d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 3);
4859d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 3);
4869d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in4_input, in, 4);
4879d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 4);
4889d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 4);
4898d5d45fbSJean Delvare 
4908d5d45fbSJean Delvare /* 3 temperatures */
temp_show(struct device * dev,struct device_attribute * da,char * buf)4919d5bc090SGuenter Roeck static ssize_t temp_show(struct device *dev, struct device_attribute *da,
4921e71a5a2SJean Delvare 			 char *buf) {
4938d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4941e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4951e71a5a2SJean Delvare 	int nr = attr->index;
4968d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
4978d5d45fbSJean Delvare }
temp_over_show(struct device * dev,struct device_attribute * da,char * buf)4989d5bc090SGuenter Roeck static ssize_t temp_over_show(struct device *dev, struct device_attribute *da,
4991e71a5a2SJean Delvare 			      char *buf) {
5008d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5011e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5021e71a5a2SJean Delvare 	int nr = attr->index;
5038d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
5048d5d45fbSJean Delvare }
temp_hyst_show(struct device * dev,struct device_attribute * da,char * buf)5059d5bc090SGuenter Roeck static ssize_t temp_hyst_show(struct device *dev, struct device_attribute *da,
5061e71a5a2SJean Delvare 			      char *buf) {
5078d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5081e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5091e71a5a2SJean Delvare 	int nr = attr->index;
5108d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
5118d5d45fbSJean Delvare }
temp_over_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)5129d5bc090SGuenter Roeck static ssize_t temp_over_store(struct device *dev,
5139d5bc090SGuenter Roeck 			       struct device_attribute *da, const char *buf,
5149d5bc090SGuenter Roeck 			       size_t count) {
5152ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
5161e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5171e71a5a2SJean Delvare 	int nr = attr->index;
5189004ac81SGuenter Roeck 	long val;
5199004ac81SGuenter Roeck 	int err;
5209004ac81SGuenter Roeck 
5219004ac81SGuenter Roeck 	err = kstrtol(buf, 10, &val);
5229004ac81SGuenter Roeck 	if (err)
5239004ac81SGuenter Roeck 		return err;
5248d5d45fbSJean Delvare 
5259a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
5268d5d45fbSJean Delvare 	data->temp_over[nr] = TEMP_TO_REG(val);
5272ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr],
5288d5d45fbSJean Delvare 			    data->temp_over[nr]);
5299a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
5308d5d45fbSJean Delvare 	return count;
5318d5d45fbSJean Delvare }
temp_hyst_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)5329d5bc090SGuenter Roeck static ssize_t temp_hyst_store(struct device *dev,
5339d5bc090SGuenter Roeck 			       struct device_attribute *da, const char *buf,
5349d5bc090SGuenter Roeck 			       size_t count) {
5352ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
5361e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5371e71a5a2SJean Delvare 	int nr = attr->index;
5389004ac81SGuenter Roeck 	long val;
5399004ac81SGuenter Roeck 	int err;
5409004ac81SGuenter Roeck 
5419004ac81SGuenter Roeck 	err = kstrtol(buf, 10, &val);
5429004ac81SGuenter Roeck 	if (err)
5439004ac81SGuenter Roeck 		return err;
5448d5d45fbSJean Delvare 
5459a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
5468d5d45fbSJean Delvare 	data->temp_hyst[nr] = TEMP_TO_REG(val);
5472ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr],
5488d5d45fbSJean Delvare 			    data->temp_hyst[nr]);
5499a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
5508d5d45fbSJean Delvare 	return count;
5518d5d45fbSJean Delvare }
5528d5d45fbSJean Delvare 
5539d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
5549d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_over, 0);
5559d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, temp_hyst, 0);
5569d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1);
5579d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_over, 1);
5589d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_max_hyst, temp_hyst, 1);
5599d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2);
5609d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_max, temp_over, 2);
5619d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_max_hyst, temp_hyst, 2);
5628d5d45fbSJean Delvare 
5638d5d45fbSJean Delvare /* 2 Fans */
fan_show(struct device * dev,struct device_attribute * da,char * buf)5649d5bc090SGuenter Roeck static ssize_t fan_show(struct device *dev, struct device_attribute *da,
5651e71a5a2SJean Delvare 			char *buf) {
5668d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5671e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5681e71a5a2SJean Delvare 	int nr = attr->index;
5698d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
5708d5d45fbSJean Delvare 				DIV_FROM_REG(data->fan_div[nr])));
5718d5d45fbSJean Delvare }
fan_min_show(struct device * dev,struct device_attribute * da,char * buf)5729d5bc090SGuenter Roeck static ssize_t fan_min_show(struct device *dev, struct device_attribute *da,
5731e71a5a2SJean Delvare 			    char *buf) {
5748d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5751e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5761e71a5a2SJean Delvare 	int nr = attr->index;
5778d5d45fbSJean Delvare 	return sprintf(buf, "%d\n",
5789004ac81SGuenter Roeck 		FAN_FROM_REG(data->fan_min[nr],
5799004ac81SGuenter Roeck 			     DIV_FROM_REG(data->fan_div[nr])));
5808d5d45fbSJean Delvare }
fan_div_show(struct device * dev,struct device_attribute * da,char * buf)5819d5bc090SGuenter Roeck static ssize_t fan_div_show(struct device *dev, struct device_attribute *da,
5821e71a5a2SJean Delvare 			    char *buf) {
5838d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5841e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5851e71a5a2SJean Delvare 	int nr = attr->index;
5868d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
5878d5d45fbSJean Delvare }
fan_min_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)5889d5bc090SGuenter Roeck static ssize_t fan_min_store(struct device *dev, struct device_attribute *da,
5891e71a5a2SJean Delvare 			     const char *buf, size_t count) {
5902ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
5911e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5921e71a5a2SJean Delvare 	int nr = attr->index;
5939004ac81SGuenter Roeck 	unsigned long val;
5949004ac81SGuenter Roeck 	int err;
5959004ac81SGuenter Roeck 
5969004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
5979004ac81SGuenter Roeck 	if (err)
5989004ac81SGuenter Roeck 		return err;
5998d5d45fbSJean Delvare 
6009a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
6018d5d45fbSJean Delvare 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
6022ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
6039a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
6048d5d45fbSJean Delvare 	return count;
6058d5d45fbSJean Delvare }
fan_div_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)6069d5bc090SGuenter Roeck static ssize_t fan_div_store(struct device *dev, struct device_attribute *da,
6071e71a5a2SJean Delvare 			     const char *buf, size_t count) {
6082ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
6091e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
6101e71a5a2SJean Delvare 	int nr = attr->index;
6118d5d45fbSJean Delvare 	int old;
6129004ac81SGuenter Roeck 	unsigned long val;
6139004ac81SGuenter Roeck 	int err;
6149004ac81SGuenter Roeck 
6159004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
6169004ac81SGuenter Roeck 	if (err)
6179004ac81SGuenter Roeck 		return err;
6188d5d45fbSJean Delvare 
6199a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
6202ec342e6SJean Delvare 	old = via686a_read_value(data, VIA686A_REG_FANDIV);
6218d5d45fbSJean Delvare 	data->fan_div[nr] = DIV_TO_REG(val);
6228d5d45fbSJean Delvare 	old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
6232ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_FANDIV, old);
6249a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
6258d5d45fbSJean Delvare 	return count;
6268d5d45fbSJean Delvare }
6278d5d45fbSJean Delvare 
6289d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
6299d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0);
6309d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_div, fan_div, 0);
6319d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
6329d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1);
6339d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1);
6348d5d45fbSJean Delvare 
6358d5d45fbSJean Delvare /* Alarms */
alarms_show(struct device * dev,struct device_attribute * attr,char * buf)6368b2bd7aeSJulia Lawall static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
6379004ac81SGuenter Roeck 			   char *buf)
6389004ac81SGuenter Roeck {
6398d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
6408d5d45fbSJean Delvare 	return sprintf(buf, "%u\n", data->alarms);
6418d5d45fbSJean Delvare }
6429004ac81SGuenter Roeck 
6438b2bd7aeSJulia Lawall static DEVICE_ATTR_RO(alarms);
6448d5d45fbSJean Delvare 
alarm_show(struct device * dev,struct device_attribute * attr,char * buf)6459d5bc090SGuenter Roeck static ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
64613ff05e9SJean Delvare 			  char *buf)
64713ff05e9SJean Delvare {
64813ff05e9SJean Delvare 	int bitnr = to_sensor_dev_attr(attr)->index;
64913ff05e9SJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
65013ff05e9SJean Delvare 	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
65113ff05e9SJean Delvare }
6529d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0);
6539d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in1_alarm, alarm, 1);
6549d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in2_alarm, alarm, 2);
6559d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in3_alarm, alarm, 3);
6569d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in4_alarm, alarm, 8);
6579d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 4);
6589d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_alarm, alarm, 11);
6599d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_alarm, alarm, 15);
6609d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 6);
6619d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 7);
66213ff05e9SJean Delvare 
name_show(struct device * dev,struct device_attribute * devattr,char * buf)6638b2bd7aeSJulia Lawall static ssize_t name_show(struct device *dev, struct device_attribute
6642ec342e6SJean Delvare 			 *devattr, char *buf)
6652ec342e6SJean Delvare {
6662ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
6672ec342e6SJean Delvare 	return sprintf(buf, "%s\n", data->name);
6682ec342e6SJean Delvare }
6698b2bd7aeSJulia Lawall static DEVICE_ATTR_RO(name);
6702ec342e6SJean Delvare 
671a5ebe668SJean Delvare static struct attribute *via686a_attributes[] = {
6721e71a5a2SJean Delvare 	&sensor_dev_attr_in0_input.dev_attr.attr,
6731e71a5a2SJean Delvare 	&sensor_dev_attr_in1_input.dev_attr.attr,
6741e71a5a2SJean Delvare 	&sensor_dev_attr_in2_input.dev_attr.attr,
6751e71a5a2SJean Delvare 	&sensor_dev_attr_in3_input.dev_attr.attr,
6761e71a5a2SJean Delvare 	&sensor_dev_attr_in4_input.dev_attr.attr,
6771e71a5a2SJean Delvare 	&sensor_dev_attr_in0_min.dev_attr.attr,
6781e71a5a2SJean Delvare 	&sensor_dev_attr_in1_min.dev_attr.attr,
6791e71a5a2SJean Delvare 	&sensor_dev_attr_in2_min.dev_attr.attr,
6801e71a5a2SJean Delvare 	&sensor_dev_attr_in3_min.dev_attr.attr,
6811e71a5a2SJean Delvare 	&sensor_dev_attr_in4_min.dev_attr.attr,
6821e71a5a2SJean Delvare 	&sensor_dev_attr_in0_max.dev_attr.attr,
6831e71a5a2SJean Delvare 	&sensor_dev_attr_in1_max.dev_attr.attr,
6841e71a5a2SJean Delvare 	&sensor_dev_attr_in2_max.dev_attr.attr,
6851e71a5a2SJean Delvare 	&sensor_dev_attr_in3_max.dev_attr.attr,
6861e71a5a2SJean Delvare 	&sensor_dev_attr_in4_max.dev_attr.attr,
68713ff05e9SJean Delvare 	&sensor_dev_attr_in0_alarm.dev_attr.attr,
68813ff05e9SJean Delvare 	&sensor_dev_attr_in1_alarm.dev_attr.attr,
68913ff05e9SJean Delvare 	&sensor_dev_attr_in2_alarm.dev_attr.attr,
69013ff05e9SJean Delvare 	&sensor_dev_attr_in3_alarm.dev_attr.attr,
69113ff05e9SJean Delvare 	&sensor_dev_attr_in4_alarm.dev_attr.attr,
692a5ebe668SJean Delvare 
6931e71a5a2SJean Delvare 	&sensor_dev_attr_temp1_input.dev_attr.attr,
6941e71a5a2SJean Delvare 	&sensor_dev_attr_temp2_input.dev_attr.attr,
6951e71a5a2SJean Delvare 	&sensor_dev_attr_temp3_input.dev_attr.attr,
6961e71a5a2SJean Delvare 	&sensor_dev_attr_temp1_max.dev_attr.attr,
6971e71a5a2SJean Delvare 	&sensor_dev_attr_temp2_max.dev_attr.attr,
6981e71a5a2SJean Delvare 	&sensor_dev_attr_temp3_max.dev_attr.attr,
6991e71a5a2SJean Delvare 	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
7001e71a5a2SJean Delvare 	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
7011e71a5a2SJean Delvare 	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
70213ff05e9SJean Delvare 	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
70313ff05e9SJean Delvare 	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
70413ff05e9SJean Delvare 	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
705a5ebe668SJean Delvare 
7061e71a5a2SJean Delvare 	&sensor_dev_attr_fan1_input.dev_attr.attr,
7071e71a5a2SJean Delvare 	&sensor_dev_attr_fan2_input.dev_attr.attr,
7081e71a5a2SJean Delvare 	&sensor_dev_attr_fan1_min.dev_attr.attr,
7091e71a5a2SJean Delvare 	&sensor_dev_attr_fan2_min.dev_attr.attr,
7101e71a5a2SJean Delvare 	&sensor_dev_attr_fan1_div.dev_attr.attr,
7111e71a5a2SJean Delvare 	&sensor_dev_attr_fan2_div.dev_attr.attr,
71213ff05e9SJean Delvare 	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
71313ff05e9SJean Delvare 	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
714a5ebe668SJean Delvare 
715a5ebe668SJean Delvare 	&dev_attr_alarms.attr,
7162ec342e6SJean Delvare 	&dev_attr_name.attr,
717a5ebe668SJean Delvare 	NULL
718a5ebe668SJean Delvare };
719a5ebe668SJean Delvare 
720a5ebe668SJean Delvare static const struct attribute_group via686a_group = {
721a5ebe668SJean Delvare 	.attrs = via686a_attributes,
722a5ebe668SJean Delvare };
723a5ebe668SJean Delvare 
via686a_init_device(struct via686a_data * data)724984fed56SUwe Kleine-König static void via686a_init_device(struct via686a_data *data)
725984fed56SUwe Kleine-König {
726984fed56SUwe Kleine-König 	u8 reg;
727984fed56SUwe Kleine-König 
728984fed56SUwe Kleine-König 	/* Start monitoring */
729984fed56SUwe Kleine-König 	reg = via686a_read_value(data, VIA686A_REG_CONFIG);
730984fed56SUwe Kleine-König 	via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
731984fed56SUwe Kleine-König 
732984fed56SUwe Kleine-König 	/* Configure temp interrupt mode for continuous-interrupt operation */
733984fed56SUwe Kleine-König 	reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
734984fed56SUwe Kleine-König 	via686a_write_value(data, VIA686A_REG_TEMP_MODE,
735984fed56SUwe Kleine-König 			    (reg & ~VIA686A_TEMP_MODE_MASK)
736984fed56SUwe Kleine-König 			    | VIA686A_TEMP_MODE_CONTINUOUS);
737984fed56SUwe Kleine-König 
738984fed56SUwe Kleine-König 	/* Pre-read fan clock divisor values */
739984fed56SUwe Kleine-König 	via686a_update_fan_div(data);
740984fed56SUwe Kleine-König }
7418d5d45fbSJean Delvare 
7428d5d45fbSJean Delvare /* This is called when the module is loaded */
via686a_probe(struct platform_device * pdev)7436c931ae1SBill Pemberton static int via686a_probe(struct platform_device *pdev)
7448d5d45fbSJean Delvare {
7458d5d45fbSJean Delvare 	struct via686a_data *data;
7462ec342e6SJean Delvare 	struct resource *res;
7472ec342e6SJean Delvare 	int err;
7488d5d45fbSJean Delvare 
7498d5d45fbSJean Delvare 	/* Reserve the ISA region */
7502ec342e6SJean Delvare 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
751fd55bc00SGuenter Roeck 	if (!devm_request_region(&pdev->dev, res->start, VIA686A_EXTENT,
75250e52c1fSUwe Kleine-König 				 DRIVER_NAME)) {
7532ec342e6SJean Delvare 		dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
7542ec342e6SJean Delvare 			(unsigned long)res->start, (unsigned long)res->end);
7558d5d45fbSJean Delvare 		return -ENODEV;
7568d5d45fbSJean Delvare 	}
7578d5d45fbSJean Delvare 
758fd55bc00SGuenter Roeck 	data = devm_kzalloc(&pdev->dev, sizeof(struct via686a_data),
759fd55bc00SGuenter Roeck 			    GFP_KERNEL);
760fd55bc00SGuenter Roeck 	if (!data)
761fd55bc00SGuenter Roeck 		return -ENOMEM;
7628d5d45fbSJean Delvare 
7632ec342e6SJean Delvare 	platform_set_drvdata(pdev, data);
7642ec342e6SJean Delvare 	data->addr = res->start;
76550e52c1fSUwe Kleine-König 	data->name = DRIVER_NAME;
7669a61bf63SIngo Molnar 	mutex_init(&data->update_lock);
7678d5d45fbSJean Delvare 
7688d5d45fbSJean Delvare 	/* Initialize the VIA686A chip */
7692ec342e6SJean Delvare 	via686a_init_device(data);
7708d5d45fbSJean Delvare 
7718d5d45fbSJean Delvare 	/* Register sysfs hooks */
7729004ac81SGuenter Roeck 	err = sysfs_create_group(&pdev->dev.kobj, &via686a_group);
7739004ac81SGuenter Roeck 	if (err)
774fd55bc00SGuenter Roeck 		return err;
775a5ebe668SJean Delvare 
7761beeffe4STony Jones 	data->hwmon_dev = hwmon_device_register(&pdev->dev);
7771beeffe4STony Jones 	if (IS_ERR(data->hwmon_dev)) {
7781beeffe4STony Jones 		err = PTR_ERR(data->hwmon_dev);
779a5ebe668SJean Delvare 		goto exit_remove_files;
780943b0830SMark M. Hoffman 	}
781943b0830SMark M. Hoffman 
7828d5d45fbSJean Delvare 	return 0;
7838d5d45fbSJean Delvare 
784a5ebe668SJean Delvare exit_remove_files:
7852ec342e6SJean Delvare 	sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
7868d5d45fbSJean Delvare 	return err;
7878d5d45fbSJean Delvare }
7888d5d45fbSJean Delvare 
via686a_remove(struct platform_device * pdev)789*680a1b08SUwe Kleine-König static void via686a_remove(struct platform_device *pdev)
7908d5d45fbSJean Delvare {
7912ec342e6SJean Delvare 	struct via686a_data *data = platform_get_drvdata(pdev);
7928d5d45fbSJean Delvare 
7931beeffe4STony Jones 	hwmon_device_unregister(data->hwmon_dev);
7942ec342e6SJean Delvare 	sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
7958d5d45fbSJean Delvare }
7968d5d45fbSJean Delvare 
797984fed56SUwe Kleine-König static struct platform_driver via686a_driver = {
798984fed56SUwe Kleine-König 	.driver = {
799984fed56SUwe Kleine-König 		.name	= DRIVER_NAME,
800984fed56SUwe Kleine-König 	},
801984fed56SUwe Kleine-König 	.probe		= via686a_probe,
802*680a1b08SUwe Kleine-König 	.remove_new	= via686a_remove,
803984fed56SUwe Kleine-König };
8048d5d45fbSJean Delvare 
805cd9bb056SJingoo Han static const struct pci_device_id via686a_pci_ids[] = {
8068d5d45fbSJean Delvare 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
8079004ac81SGuenter Roeck 	{ }
8088d5d45fbSJean Delvare };
8098d5d45fbSJean Delvare MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
8108d5d45fbSJean Delvare 
via686a_device_add(unsigned short address)8116c931ae1SBill Pemberton static int via686a_device_add(unsigned short address)
8122ec342e6SJean Delvare {
8132ec342e6SJean Delvare 	struct resource res = {
8142ec342e6SJean Delvare 		.start	= address,
8152ec342e6SJean Delvare 		.end	= address + VIA686A_EXTENT - 1,
81650e52c1fSUwe Kleine-König 		.name	= DRIVER_NAME,
8172ec342e6SJean Delvare 		.flags	= IORESOURCE_IO,
8182ec342e6SJean Delvare 	};
8192ec342e6SJean Delvare 	int err;
8202ec342e6SJean Delvare 
821b9acb64aSJean Delvare 	err = acpi_check_resource_conflict(&res);
822b9acb64aSJean Delvare 	if (err)
823b9acb64aSJean Delvare 		goto exit;
824b9acb64aSJean Delvare 
82550e52c1fSUwe Kleine-König 	pdev = platform_device_alloc(DRIVER_NAME, address);
8262ec342e6SJean Delvare 	if (!pdev) {
8272ec342e6SJean Delvare 		err = -ENOMEM;
828774f7827SJoe Perches 		pr_err("Device allocation failed\n");
8292ec342e6SJean Delvare 		goto exit;
8302ec342e6SJean Delvare 	}
8312ec342e6SJean Delvare 
8322ec342e6SJean Delvare 	err = platform_device_add_resources(pdev, &res, 1);
8332ec342e6SJean Delvare 	if (err) {
834774f7827SJoe Perches 		pr_err("Device resource addition failed (%d)\n", err);
8352ec342e6SJean Delvare 		goto exit_device_put;
8362ec342e6SJean Delvare 	}
8372ec342e6SJean Delvare 
8382ec342e6SJean Delvare 	err = platform_device_add(pdev);
8392ec342e6SJean Delvare 	if (err) {
840774f7827SJoe Perches 		pr_err("Device addition failed (%d)\n", err);
8412ec342e6SJean Delvare 		goto exit_device_put;
8422ec342e6SJean Delvare 	}
8432ec342e6SJean Delvare 
8442ec342e6SJean Delvare 	return 0;
8452ec342e6SJean Delvare 
8462ec342e6SJean Delvare exit_device_put:
8472ec342e6SJean Delvare 	platform_device_put(pdev);
8482ec342e6SJean Delvare exit:
8492ec342e6SJean Delvare 	return err;
8502ec342e6SJean Delvare }
8512ec342e6SJean Delvare 
via686a_pci_probe(struct pci_dev * dev,const struct pci_device_id * id)8526c931ae1SBill Pemberton static int via686a_pci_probe(struct pci_dev *dev,
8538d5d45fbSJean Delvare 				       const struct pci_device_id *id)
8548d5d45fbSJean Delvare {
8552ec342e6SJean Delvare 	u16 address, val;
85670332ec7SIlpo Järvinen 	int ret;
8578d5d45fbSJean Delvare 
8582ec342e6SJean Delvare 	if (force_addr) {
8592ec342e6SJean Delvare 		address = force_addr & ~(VIA686A_EXTENT - 1);
8602ec342e6SJean Delvare 		dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
86170332ec7SIlpo Järvinen 		ret = pci_write_config_word(dev, VIA686A_BASE_REG, address | 1);
86270332ec7SIlpo Järvinen 		if (ret != PCIBIOS_SUCCESSFUL)
8632ec342e6SJean Delvare 			return -ENODEV;
8642ec342e6SJean Delvare 	}
86570332ec7SIlpo Järvinen 	ret = pci_read_config_word(dev, VIA686A_BASE_REG, &val);
86670332ec7SIlpo Järvinen 	if (ret != PCIBIOS_SUCCESSFUL)
8678d5d45fbSJean Delvare 		return -ENODEV;
8688d5d45fbSJean Delvare 
8692d8672c5SJean Delvare 	address = val & ~(VIA686A_EXTENT - 1);
8702ec342e6SJean Delvare 	if (address == 0) {
871b55f3757SGuenter Roeck 		dev_err(&dev->dev,
872b55f3757SGuenter Roeck 			"base address not set - upgrade BIOS or use force_addr=0xaddr\n");
8738d5d45fbSJean Delvare 		return -ENODEV;
8748d5d45fbSJean Delvare 	}
8758d5d45fbSJean Delvare 
87670332ec7SIlpo Järvinen 	ret = pci_read_config_word(dev, VIA686A_ENABLE_REG, &val);
87770332ec7SIlpo Järvinen 	if (ret != PCIBIOS_SUCCESSFUL)
8782ec342e6SJean Delvare 		return -ENODEV;
8792ec342e6SJean Delvare 	if (!(val & 0x0001)) {
8802ec342e6SJean Delvare 		if (!force_addr) {
881b55f3757SGuenter Roeck 			dev_warn(&dev->dev,
882b55f3757SGuenter Roeck 				 "Sensors disabled, enable with force_addr=0x%x\n",
883b55f3757SGuenter Roeck 				 address);
8842ec342e6SJean Delvare 			return -ENODEV;
8858d5d45fbSJean Delvare 		}
8868d5d45fbSJean Delvare 
8872ec342e6SJean Delvare 		dev_warn(&dev->dev, "Enabling sensors\n");
88870332ec7SIlpo Järvinen 		ret = pci_write_config_word(dev, VIA686A_ENABLE_REG, val | 0x1);
88970332ec7SIlpo Järvinen 		if (ret != PCIBIOS_SUCCESSFUL)
8902ec342e6SJean Delvare 			return -ENODEV;
8912ec342e6SJean Delvare 	}
8922ec342e6SJean Delvare 
8932ec342e6SJean Delvare 	if (platform_driver_register(&via686a_driver))
8942ec342e6SJean Delvare 		goto exit;
8952ec342e6SJean Delvare 
8962ec342e6SJean Delvare 	/* Sets global pdev as a side effect */
8972ec342e6SJean Delvare 	if (via686a_device_add(address))
8982ec342e6SJean Delvare 		goto exit_unregister;
8992ec342e6SJean Delvare 
9009004ac81SGuenter Roeck 	/*
9019004ac81SGuenter Roeck 	 * Always return failure here.  This is to allow other drivers to bind
9028d5d45fbSJean Delvare 	 * to this pci device.  We don't really want to have control over the
9038d5d45fbSJean Delvare 	 * pci device, we only wanted to read as few register values from it.
9048d5d45fbSJean Delvare 	 */
9052ec342e6SJean Delvare 	s_bridge = pci_dev_get(dev);
9062ec342e6SJean Delvare 	return -ENODEV;
9072ec342e6SJean Delvare 
9082ec342e6SJean Delvare exit_unregister:
9092ec342e6SJean Delvare 	platform_driver_unregister(&via686a_driver);
9102ec342e6SJean Delvare exit:
9118d5d45fbSJean Delvare 	return -ENODEV;
9128d5d45fbSJean Delvare }
9138d5d45fbSJean Delvare 
9148d5d45fbSJean Delvare static struct pci_driver via686a_pci_driver = {
91550e52c1fSUwe Kleine-König 	.name		= DRIVER_NAME,
9168d5d45fbSJean Delvare 	.id_table	= via686a_pci_ids,
9178d5d45fbSJean Delvare 	.probe		= via686a_pci_probe,
9188d5d45fbSJean Delvare };
9198d5d45fbSJean Delvare 
sm_via686a_init(void)9208d5d45fbSJean Delvare static int __init sm_via686a_init(void)
9218d5d45fbSJean Delvare {
9228d5d45fbSJean Delvare 	return pci_register_driver(&via686a_pci_driver);
9238d5d45fbSJean Delvare }
9248d5d45fbSJean Delvare 
sm_via686a_exit(void)9258d5d45fbSJean Delvare static void __exit sm_via686a_exit(void)
9268d5d45fbSJean Delvare {
9278d5d45fbSJean Delvare 	pci_unregister_driver(&via686a_pci_driver);
9288d5d45fbSJean Delvare 	if (s_bridge != NULL) {
9292ec342e6SJean Delvare 		platform_device_unregister(pdev);
9302ec342e6SJean Delvare 		platform_driver_unregister(&via686a_driver);
9318d5d45fbSJean Delvare 		pci_dev_put(s_bridge);
9328d5d45fbSJean Delvare 		s_bridge = NULL;
9338d5d45fbSJean Delvare 	}
9348d5d45fbSJean Delvare }
9358d5d45fbSJean Delvare 
93696de0e25SJan Engelhardt MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, "
9378d5d45fbSJean Delvare 	      "Mark Studebaker <mdsxyz123@yahoo.com> "
9388d5d45fbSJean Delvare 	      "and Bob Dougherty <bobd@stanford.edu>");
9398d5d45fbSJean Delvare MODULE_DESCRIPTION("VIA 686A Sensor device");
9408d5d45fbSJean Delvare MODULE_LICENSE("GPL");
9418d5d45fbSJean Delvare 
9428d5d45fbSJean Delvare module_init(sm_via686a_init);
9438d5d45fbSJean Delvare module_exit(sm_via686a_exit);
944