xref: /openbmc/linux/drivers/hwmon/via686a.c (revision 50e52c1fc5cecfac52287a2227d8883b32963876)
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 
37*50e52c1fSUwe Kleine-König #define DRIVER_NAME "via686a"
38*50e52c1fSUwe 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  */
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 
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  */
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  */
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 */
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 
3262ec342e6SJean Delvare static int via686a_probe(struct platform_device *pdev);
327281dfd0bSBill Pemberton static int via686a_remove(struct platform_device *pdev);
3288d5d45fbSJean Delvare 
3292ec342e6SJean Delvare static inline int via686a_read_value(struct via686a_data *data, u8 reg)
3308d5d45fbSJean Delvare {
3312ec342e6SJean Delvare 	return inb_p(data->addr + reg);
3328d5d45fbSJean Delvare }
3338d5d45fbSJean Delvare 
3342ec342e6SJean Delvare static inline void via686a_write_value(struct via686a_data *data, u8 reg,
3358d5d45fbSJean Delvare 				       u8 value)
3368d5d45fbSJean Delvare {
3372ec342e6SJean Delvare 	outb_p(value, data->addr + reg);
3388d5d45fbSJean Delvare }
3398d5d45fbSJean Delvare 
3408d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev);
3412ec342e6SJean Delvare static void via686a_init_device(struct via686a_data *data);
3428d5d45fbSJean Delvare 
3438d5d45fbSJean Delvare /* following are the sysfs callback functions */
3448d5d45fbSJean Delvare 
3458d5d45fbSJean Delvare /* 7 voltage sensors */
3469d5bc090SGuenter Roeck static ssize_t in_show(struct device *dev, struct device_attribute *da,
3471e71a5a2SJean Delvare 		       char *buf) {
3488d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
3491e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3501e71a5a2SJean Delvare 	int nr = attr->index;
3518d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr));
3528d5d45fbSJean Delvare }
3538d5d45fbSJean Delvare 
3549d5bc090SGuenter Roeck static ssize_t in_min_show(struct device *dev, struct device_attribute *da,
3551e71a5a2SJean Delvare 			   char *buf) {
3568d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
3571e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3581e71a5a2SJean Delvare 	int nr = attr->index;
3598d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr));
3608d5d45fbSJean Delvare }
3618d5d45fbSJean Delvare 
3629d5bc090SGuenter Roeck static ssize_t in_max_show(struct device *dev, struct device_attribute *da,
3631e71a5a2SJean Delvare 			   char *buf) {
3648d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
3651e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3661e71a5a2SJean Delvare 	int nr = attr->index;
3678d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
3688d5d45fbSJean Delvare }
3698d5d45fbSJean Delvare 
3709d5bc090SGuenter Roeck static ssize_t in_min_store(struct device *dev, struct device_attribute *da,
3711e71a5a2SJean Delvare 			    const char *buf, size_t count) {
3722ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
3731e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3741e71a5a2SJean Delvare 	int nr = attr->index;
3759004ac81SGuenter Roeck 	unsigned long val;
3769004ac81SGuenter Roeck 	int err;
3779004ac81SGuenter Roeck 
3789004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
3799004ac81SGuenter Roeck 	if (err)
3809004ac81SGuenter Roeck 		return err;
3818d5d45fbSJean Delvare 
3829a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
3838d5d45fbSJean Delvare 	data->in_min[nr] = IN_TO_REG(val, nr);
3842ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_IN_MIN(nr),
3858d5d45fbSJean Delvare 			data->in_min[nr]);
3869a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
3878d5d45fbSJean Delvare 	return count;
3888d5d45fbSJean Delvare }
3899d5bc090SGuenter Roeck static ssize_t in_max_store(struct device *dev, struct device_attribute *da,
3901e71a5a2SJean Delvare 			    const char *buf, size_t count) {
3912ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
3921e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3931e71a5a2SJean Delvare 	int nr = attr->index;
3949004ac81SGuenter Roeck 	unsigned long val;
3959004ac81SGuenter Roeck 	int err;
3969004ac81SGuenter Roeck 
3979004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
3989004ac81SGuenter Roeck 	if (err)
3999004ac81SGuenter Roeck 		return err;
4008d5d45fbSJean Delvare 
4019a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4028d5d45fbSJean Delvare 	data->in_max[nr] = IN_TO_REG(val, nr);
4032ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_IN_MAX(nr),
4048d5d45fbSJean Delvare 			data->in_max[nr]);
4059a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4068d5d45fbSJean Delvare 	return count;
4078d5d45fbSJean Delvare }
4088d5d45fbSJean Delvare 
4099d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in0_input, in, 0);
4109d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in0_min, in_min, 0);
4119d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in0_max, in_max, 0);
4129d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in1_input, in, 1);
4139d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 1);
4149d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 1);
4159d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in2_input, in, 2);
4169d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 2);
4179d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 2);
4189d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in3_input, in, 3);
4199d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 3);
4209d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 3);
4219d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in4_input, in, 4);
4229d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 4);
4239d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 4);
4248d5d45fbSJean Delvare 
4258d5d45fbSJean Delvare /* 3 temperatures */
4269d5bc090SGuenter Roeck static ssize_t temp_show(struct device *dev, struct device_attribute *da,
4271e71a5a2SJean Delvare 			 char *buf) {
4288d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4291e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4301e71a5a2SJean Delvare 	int nr = attr->index;
4318d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
4328d5d45fbSJean Delvare }
4339d5bc090SGuenter Roeck static ssize_t temp_over_show(struct device *dev, struct device_attribute *da,
4341e71a5a2SJean Delvare 			      char *buf) {
4358d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4361e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4371e71a5a2SJean Delvare 	int nr = attr->index;
4388d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
4398d5d45fbSJean Delvare }
4409d5bc090SGuenter Roeck static ssize_t temp_hyst_show(struct device *dev, struct device_attribute *da,
4411e71a5a2SJean Delvare 			      char *buf) {
4428d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4431e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4441e71a5a2SJean Delvare 	int nr = attr->index;
4458d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
4468d5d45fbSJean Delvare }
4479d5bc090SGuenter Roeck static ssize_t temp_over_store(struct device *dev,
4489d5bc090SGuenter Roeck 			       struct device_attribute *da, const char *buf,
4499d5bc090SGuenter Roeck 			       size_t count) {
4502ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
4511e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4521e71a5a2SJean Delvare 	int nr = attr->index;
4539004ac81SGuenter Roeck 	long val;
4549004ac81SGuenter Roeck 	int err;
4559004ac81SGuenter Roeck 
4569004ac81SGuenter Roeck 	err = kstrtol(buf, 10, &val);
4579004ac81SGuenter Roeck 	if (err)
4589004ac81SGuenter Roeck 		return err;
4598d5d45fbSJean Delvare 
4609a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4618d5d45fbSJean Delvare 	data->temp_over[nr] = TEMP_TO_REG(val);
4622ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr],
4638d5d45fbSJean Delvare 			    data->temp_over[nr]);
4649a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4658d5d45fbSJean Delvare 	return count;
4668d5d45fbSJean Delvare }
4679d5bc090SGuenter Roeck static ssize_t temp_hyst_store(struct device *dev,
4689d5bc090SGuenter Roeck 			       struct device_attribute *da, const char *buf,
4699d5bc090SGuenter Roeck 			       size_t count) {
4702ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
4711e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4721e71a5a2SJean Delvare 	int nr = attr->index;
4739004ac81SGuenter Roeck 	long val;
4749004ac81SGuenter Roeck 	int err;
4759004ac81SGuenter Roeck 
4769004ac81SGuenter Roeck 	err = kstrtol(buf, 10, &val);
4779004ac81SGuenter Roeck 	if (err)
4789004ac81SGuenter Roeck 		return err;
4798d5d45fbSJean Delvare 
4809a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4818d5d45fbSJean Delvare 	data->temp_hyst[nr] = TEMP_TO_REG(val);
4822ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr],
4838d5d45fbSJean Delvare 			    data->temp_hyst[nr]);
4849a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4858d5d45fbSJean Delvare 	return count;
4868d5d45fbSJean Delvare }
4878d5d45fbSJean Delvare 
4889d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
4899d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_over, 0);
4909d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, temp_hyst, 0);
4919d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1);
4929d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_over, 1);
4939d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_max_hyst, temp_hyst, 1);
4949d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2);
4959d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_max, temp_over, 2);
4969d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_max_hyst, temp_hyst, 2);
4978d5d45fbSJean Delvare 
4988d5d45fbSJean Delvare /* 2 Fans */
4999d5bc090SGuenter Roeck static ssize_t fan_show(struct device *dev, struct device_attribute *da,
5001e71a5a2SJean Delvare 			char *buf) {
5018d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5021e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5031e71a5a2SJean Delvare 	int nr = attr->index;
5048d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
5058d5d45fbSJean Delvare 				DIV_FROM_REG(data->fan_div[nr])));
5068d5d45fbSJean Delvare }
5079d5bc090SGuenter Roeck static ssize_t fan_min_show(struct device *dev, struct device_attribute *da,
5081e71a5a2SJean Delvare 			    char *buf) {
5098d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5101e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5111e71a5a2SJean Delvare 	int nr = attr->index;
5128d5d45fbSJean Delvare 	return sprintf(buf, "%d\n",
5139004ac81SGuenter Roeck 		FAN_FROM_REG(data->fan_min[nr],
5149004ac81SGuenter Roeck 			     DIV_FROM_REG(data->fan_div[nr])));
5158d5d45fbSJean Delvare }
5169d5bc090SGuenter Roeck static ssize_t fan_div_show(struct device *dev, struct device_attribute *da,
5171e71a5a2SJean Delvare 			    char *buf) {
5188d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5191e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5201e71a5a2SJean Delvare 	int nr = attr->index;
5218d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
5228d5d45fbSJean Delvare }
5239d5bc090SGuenter Roeck static ssize_t fan_min_store(struct device *dev, struct device_attribute *da,
5241e71a5a2SJean Delvare 			     const char *buf, size_t count) {
5252ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
5261e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5271e71a5a2SJean Delvare 	int nr = attr->index;
5289004ac81SGuenter Roeck 	unsigned long val;
5299004ac81SGuenter Roeck 	int err;
5309004ac81SGuenter Roeck 
5319004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
5329004ac81SGuenter Roeck 	if (err)
5339004ac81SGuenter Roeck 		return err;
5348d5d45fbSJean Delvare 
5359a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
5368d5d45fbSJean Delvare 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
5372ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
5389a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
5398d5d45fbSJean Delvare 	return count;
5408d5d45fbSJean Delvare }
5419d5bc090SGuenter Roeck static ssize_t fan_div_store(struct device *dev, struct device_attribute *da,
5421e71a5a2SJean Delvare 			     const char *buf, size_t count) {
5432ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
5441e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5451e71a5a2SJean Delvare 	int nr = attr->index;
5468d5d45fbSJean Delvare 	int old;
5479004ac81SGuenter Roeck 	unsigned long val;
5489004ac81SGuenter Roeck 	int err;
5499004ac81SGuenter Roeck 
5509004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
5519004ac81SGuenter Roeck 	if (err)
5529004ac81SGuenter Roeck 		return err;
5538d5d45fbSJean Delvare 
5549a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
5552ec342e6SJean Delvare 	old = via686a_read_value(data, VIA686A_REG_FANDIV);
5568d5d45fbSJean Delvare 	data->fan_div[nr] = DIV_TO_REG(val);
5578d5d45fbSJean Delvare 	old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
5582ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_FANDIV, old);
5599a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
5608d5d45fbSJean Delvare 	return count;
5618d5d45fbSJean Delvare }
5628d5d45fbSJean Delvare 
5639d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
5649d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0);
5659d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_div, fan_div, 0);
5669d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
5679d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1);
5689d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1);
5698d5d45fbSJean Delvare 
5708d5d45fbSJean Delvare /* Alarms */
5718b2bd7aeSJulia Lawall static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
5729004ac81SGuenter Roeck 			   char *buf)
5739004ac81SGuenter Roeck {
5748d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5758d5d45fbSJean Delvare 	return sprintf(buf, "%u\n", data->alarms);
5768d5d45fbSJean Delvare }
5779004ac81SGuenter Roeck 
5788b2bd7aeSJulia Lawall static DEVICE_ATTR_RO(alarms);
5798d5d45fbSJean Delvare 
5809d5bc090SGuenter Roeck static ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
58113ff05e9SJean Delvare 			  char *buf)
58213ff05e9SJean Delvare {
58313ff05e9SJean Delvare 	int bitnr = to_sensor_dev_attr(attr)->index;
58413ff05e9SJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
58513ff05e9SJean Delvare 	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
58613ff05e9SJean Delvare }
5879d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0);
5889d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in1_alarm, alarm, 1);
5899d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in2_alarm, alarm, 2);
5909d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in3_alarm, alarm, 3);
5919d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in4_alarm, alarm, 8);
5929d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 4);
5939d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_alarm, alarm, 11);
5949d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_alarm, alarm, 15);
5959d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 6);
5969d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 7);
59713ff05e9SJean Delvare 
5988b2bd7aeSJulia Lawall static ssize_t name_show(struct device *dev, struct device_attribute
5992ec342e6SJean Delvare 			 *devattr, char *buf)
6002ec342e6SJean Delvare {
6012ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
6022ec342e6SJean Delvare 	return sprintf(buf, "%s\n", data->name);
6032ec342e6SJean Delvare }
6048b2bd7aeSJulia Lawall static DEVICE_ATTR_RO(name);
6052ec342e6SJean Delvare 
606a5ebe668SJean Delvare static struct attribute *via686a_attributes[] = {
6071e71a5a2SJean Delvare 	&sensor_dev_attr_in0_input.dev_attr.attr,
6081e71a5a2SJean Delvare 	&sensor_dev_attr_in1_input.dev_attr.attr,
6091e71a5a2SJean Delvare 	&sensor_dev_attr_in2_input.dev_attr.attr,
6101e71a5a2SJean Delvare 	&sensor_dev_attr_in3_input.dev_attr.attr,
6111e71a5a2SJean Delvare 	&sensor_dev_attr_in4_input.dev_attr.attr,
6121e71a5a2SJean Delvare 	&sensor_dev_attr_in0_min.dev_attr.attr,
6131e71a5a2SJean Delvare 	&sensor_dev_attr_in1_min.dev_attr.attr,
6141e71a5a2SJean Delvare 	&sensor_dev_attr_in2_min.dev_attr.attr,
6151e71a5a2SJean Delvare 	&sensor_dev_attr_in3_min.dev_attr.attr,
6161e71a5a2SJean Delvare 	&sensor_dev_attr_in4_min.dev_attr.attr,
6171e71a5a2SJean Delvare 	&sensor_dev_attr_in0_max.dev_attr.attr,
6181e71a5a2SJean Delvare 	&sensor_dev_attr_in1_max.dev_attr.attr,
6191e71a5a2SJean Delvare 	&sensor_dev_attr_in2_max.dev_attr.attr,
6201e71a5a2SJean Delvare 	&sensor_dev_attr_in3_max.dev_attr.attr,
6211e71a5a2SJean Delvare 	&sensor_dev_attr_in4_max.dev_attr.attr,
62213ff05e9SJean Delvare 	&sensor_dev_attr_in0_alarm.dev_attr.attr,
62313ff05e9SJean Delvare 	&sensor_dev_attr_in1_alarm.dev_attr.attr,
62413ff05e9SJean Delvare 	&sensor_dev_attr_in2_alarm.dev_attr.attr,
62513ff05e9SJean Delvare 	&sensor_dev_attr_in3_alarm.dev_attr.attr,
62613ff05e9SJean Delvare 	&sensor_dev_attr_in4_alarm.dev_attr.attr,
627a5ebe668SJean Delvare 
6281e71a5a2SJean Delvare 	&sensor_dev_attr_temp1_input.dev_attr.attr,
6291e71a5a2SJean Delvare 	&sensor_dev_attr_temp2_input.dev_attr.attr,
6301e71a5a2SJean Delvare 	&sensor_dev_attr_temp3_input.dev_attr.attr,
6311e71a5a2SJean Delvare 	&sensor_dev_attr_temp1_max.dev_attr.attr,
6321e71a5a2SJean Delvare 	&sensor_dev_attr_temp2_max.dev_attr.attr,
6331e71a5a2SJean Delvare 	&sensor_dev_attr_temp3_max.dev_attr.attr,
6341e71a5a2SJean Delvare 	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
6351e71a5a2SJean Delvare 	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
6361e71a5a2SJean Delvare 	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
63713ff05e9SJean Delvare 	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
63813ff05e9SJean Delvare 	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
63913ff05e9SJean Delvare 	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
640a5ebe668SJean Delvare 
6411e71a5a2SJean Delvare 	&sensor_dev_attr_fan1_input.dev_attr.attr,
6421e71a5a2SJean Delvare 	&sensor_dev_attr_fan2_input.dev_attr.attr,
6431e71a5a2SJean Delvare 	&sensor_dev_attr_fan1_min.dev_attr.attr,
6441e71a5a2SJean Delvare 	&sensor_dev_attr_fan2_min.dev_attr.attr,
6451e71a5a2SJean Delvare 	&sensor_dev_attr_fan1_div.dev_attr.attr,
6461e71a5a2SJean Delvare 	&sensor_dev_attr_fan2_div.dev_attr.attr,
64713ff05e9SJean Delvare 	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
64813ff05e9SJean Delvare 	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
649a5ebe668SJean Delvare 
650a5ebe668SJean Delvare 	&dev_attr_alarms.attr,
6512ec342e6SJean Delvare 	&dev_attr_name.attr,
652a5ebe668SJean Delvare 	NULL
653a5ebe668SJean Delvare };
654a5ebe668SJean Delvare 
655a5ebe668SJean Delvare static const struct attribute_group via686a_group = {
656a5ebe668SJean Delvare 	.attrs = via686a_attributes,
657a5ebe668SJean Delvare };
658a5ebe668SJean Delvare 
6592ec342e6SJean Delvare static struct platform_driver via686a_driver = {
660cdaf7934SLaurent Riffard 	.driver = {
661*50e52c1fSUwe Kleine-König 		.name	= DRIVER_NAME,
662cdaf7934SLaurent Riffard 	},
6632ec342e6SJean Delvare 	.probe		= via686a_probe,
6649e5e9b7aSBill Pemberton 	.remove		= via686a_remove,
6658d5d45fbSJean Delvare };
6668d5d45fbSJean Delvare 
6678d5d45fbSJean Delvare /* This is called when the module is loaded */
6686c931ae1SBill Pemberton static int via686a_probe(struct platform_device *pdev)
6698d5d45fbSJean Delvare {
6708d5d45fbSJean Delvare 	struct via686a_data *data;
6712ec342e6SJean Delvare 	struct resource *res;
6722ec342e6SJean Delvare 	int err;
6738d5d45fbSJean Delvare 
6748d5d45fbSJean Delvare 	/* Reserve the ISA region */
6752ec342e6SJean Delvare 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
676fd55bc00SGuenter Roeck 	if (!devm_request_region(&pdev->dev, res->start, VIA686A_EXTENT,
677*50e52c1fSUwe Kleine-König 				 DRIVER_NAME)) {
6782ec342e6SJean Delvare 		dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
6792ec342e6SJean Delvare 			(unsigned long)res->start, (unsigned long)res->end);
6808d5d45fbSJean Delvare 		return -ENODEV;
6818d5d45fbSJean Delvare 	}
6828d5d45fbSJean Delvare 
683fd55bc00SGuenter Roeck 	data = devm_kzalloc(&pdev->dev, sizeof(struct via686a_data),
684fd55bc00SGuenter Roeck 			    GFP_KERNEL);
685fd55bc00SGuenter Roeck 	if (!data)
686fd55bc00SGuenter Roeck 		return -ENOMEM;
6878d5d45fbSJean Delvare 
6882ec342e6SJean Delvare 	platform_set_drvdata(pdev, data);
6892ec342e6SJean Delvare 	data->addr = res->start;
690*50e52c1fSUwe Kleine-König 	data->name = DRIVER_NAME;
6919a61bf63SIngo Molnar 	mutex_init(&data->update_lock);
6928d5d45fbSJean Delvare 
6938d5d45fbSJean Delvare 	/* Initialize the VIA686A chip */
6942ec342e6SJean Delvare 	via686a_init_device(data);
6958d5d45fbSJean Delvare 
6968d5d45fbSJean Delvare 	/* Register sysfs hooks */
6979004ac81SGuenter Roeck 	err = sysfs_create_group(&pdev->dev.kobj, &via686a_group);
6989004ac81SGuenter Roeck 	if (err)
699fd55bc00SGuenter Roeck 		return err;
700a5ebe668SJean Delvare 
7011beeffe4STony Jones 	data->hwmon_dev = hwmon_device_register(&pdev->dev);
7021beeffe4STony Jones 	if (IS_ERR(data->hwmon_dev)) {
7031beeffe4STony Jones 		err = PTR_ERR(data->hwmon_dev);
704a5ebe668SJean Delvare 		goto exit_remove_files;
705943b0830SMark M. Hoffman 	}
706943b0830SMark M. Hoffman 
7078d5d45fbSJean Delvare 	return 0;
7088d5d45fbSJean Delvare 
709a5ebe668SJean Delvare exit_remove_files:
7102ec342e6SJean Delvare 	sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
7118d5d45fbSJean Delvare 	return err;
7128d5d45fbSJean Delvare }
7138d5d45fbSJean Delvare 
714281dfd0bSBill Pemberton static int via686a_remove(struct platform_device *pdev)
7158d5d45fbSJean Delvare {
7162ec342e6SJean Delvare 	struct via686a_data *data = platform_get_drvdata(pdev);
7178d5d45fbSJean Delvare 
7181beeffe4STony Jones 	hwmon_device_unregister(data->hwmon_dev);
7192ec342e6SJean Delvare 	sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
720943b0830SMark M. Hoffman 
7218d5d45fbSJean Delvare 	return 0;
7228d5d45fbSJean Delvare }
7238d5d45fbSJean Delvare 
724f790674dSJean Delvare static void via686a_update_fan_div(struct via686a_data *data)
725f790674dSJean Delvare {
726f790674dSJean Delvare 	int reg = via686a_read_value(data, VIA686A_REG_FANDIV);
727f790674dSJean Delvare 	data->fan_div[0] = (reg >> 4) & 0x03;
728f790674dSJean Delvare 	data->fan_div[1] = reg >> 6;
729f790674dSJean Delvare }
730f790674dSJean Delvare 
7316c931ae1SBill Pemberton static void via686a_init_device(struct via686a_data *data)
7328d5d45fbSJean Delvare {
7338d5d45fbSJean Delvare 	u8 reg;
7348d5d45fbSJean Delvare 
7358d5d45fbSJean Delvare 	/* Start monitoring */
7362ec342e6SJean Delvare 	reg = via686a_read_value(data, VIA686A_REG_CONFIG);
7372ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
7388d5d45fbSJean Delvare 
7398d5d45fbSJean Delvare 	/* Configure temp interrupt mode for continuous-interrupt operation */
7402ec342e6SJean Delvare 	reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
7412ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_TEMP_MODE,
74258fe0809SJean Delvare 			    (reg & ~VIA686A_TEMP_MODE_MASK)
74358fe0809SJean Delvare 			    | VIA686A_TEMP_MODE_CONTINUOUS);
744f790674dSJean Delvare 
745f790674dSJean Delvare 	/* Pre-read fan clock divisor values */
746f790674dSJean Delvare 	via686a_update_fan_div(data);
7478d5d45fbSJean Delvare }
7488d5d45fbSJean Delvare 
7498d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev)
7508d5d45fbSJean Delvare {
7512ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
7528d5d45fbSJean Delvare 	int i;
7538d5d45fbSJean Delvare 
7549a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
7558d5d45fbSJean Delvare 
7568d5d45fbSJean Delvare 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
7578d5d45fbSJean Delvare 	    || !data->valid) {
7588d5d45fbSJean Delvare 		for (i = 0; i <= 4; i++) {
7598d5d45fbSJean Delvare 			data->in[i] =
7602ec342e6SJean Delvare 			    via686a_read_value(data, VIA686A_REG_IN(i));
7612ec342e6SJean Delvare 			data->in_min[i] = via686a_read_value(data,
7628d5d45fbSJean Delvare 							     VIA686A_REG_IN_MIN
7638d5d45fbSJean Delvare 							     (i));
7648d5d45fbSJean Delvare 			data->in_max[i] =
7652ec342e6SJean Delvare 			    via686a_read_value(data, VIA686A_REG_IN_MAX(i));
7668d5d45fbSJean Delvare 		}
7678d5d45fbSJean Delvare 		for (i = 1; i <= 2; i++) {
7688d5d45fbSJean Delvare 			data->fan[i - 1] =
7692ec342e6SJean Delvare 			    via686a_read_value(data, VIA686A_REG_FAN(i));
7702ec342e6SJean Delvare 			data->fan_min[i - 1] = via686a_read_value(data,
7718d5d45fbSJean Delvare 						     VIA686A_REG_FAN_MIN(i));
7728d5d45fbSJean Delvare 		}
7738d5d45fbSJean Delvare 		for (i = 0; i <= 2; i++) {
7742ec342e6SJean Delvare 			data->temp[i] = via686a_read_value(data,
7758d5d45fbSJean Delvare 						 VIA686A_REG_TEMP[i]) << 2;
7768d5d45fbSJean Delvare 			data->temp_over[i] =
7772ec342e6SJean Delvare 			    via686a_read_value(data,
7788d5d45fbSJean Delvare 					       VIA686A_REG_TEMP_OVER[i]);
7798d5d45fbSJean Delvare 			data->temp_hyst[i] =
7802ec342e6SJean Delvare 			    via686a_read_value(data,
7818d5d45fbSJean Delvare 					       VIA686A_REG_TEMP_HYST[i]);
7828d5d45fbSJean Delvare 		}
7839004ac81SGuenter Roeck 		/*
7849004ac81SGuenter Roeck 		 * add in lower 2 bits
7859004ac81SGuenter Roeck 		 * temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1
7869004ac81SGuenter Roeck 		 * temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
7879004ac81SGuenter Roeck 		 * temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
7888d5d45fbSJean Delvare 		 */
7892ec342e6SJean Delvare 		data->temp[0] |= (via686a_read_value(data,
7908d5d45fbSJean Delvare 						     VIA686A_REG_TEMP_LOW1)
7918d5d45fbSJean Delvare 				  & 0xc0) >> 6;
7928d5d45fbSJean Delvare 		data->temp[1] |=
7932ec342e6SJean Delvare 		    (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
7948d5d45fbSJean Delvare 		     0x30) >> 4;
7958d5d45fbSJean Delvare 		data->temp[2] |=
7962ec342e6SJean Delvare 		    (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
7978d5d45fbSJean Delvare 		     0xc0) >> 6;
7988d5d45fbSJean Delvare 
799f790674dSJean Delvare 		via686a_update_fan_div(data);
8008d5d45fbSJean Delvare 		data->alarms =
8012ec342e6SJean Delvare 		    via686a_read_value(data,
8028d5d45fbSJean Delvare 				       VIA686A_REG_ALARM1) |
8032ec342e6SJean Delvare 		    (via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
8048d5d45fbSJean Delvare 		data->last_updated = jiffies;
805952a11caSPaul Fertser 		data->valid = true;
8068d5d45fbSJean Delvare 	}
8078d5d45fbSJean Delvare 
8089a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
8098d5d45fbSJean Delvare 
8108d5d45fbSJean Delvare 	return data;
8118d5d45fbSJean Delvare }
8128d5d45fbSJean Delvare 
813cd9bb056SJingoo Han static const struct pci_device_id via686a_pci_ids[] = {
8148d5d45fbSJean Delvare 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
8159004ac81SGuenter Roeck 	{ }
8168d5d45fbSJean Delvare };
8178d5d45fbSJean Delvare MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
8188d5d45fbSJean Delvare 
8196c931ae1SBill Pemberton static int via686a_device_add(unsigned short address)
8202ec342e6SJean Delvare {
8212ec342e6SJean Delvare 	struct resource res = {
8222ec342e6SJean Delvare 		.start	= address,
8232ec342e6SJean Delvare 		.end	= address + VIA686A_EXTENT - 1,
824*50e52c1fSUwe Kleine-König 		.name	= DRIVER_NAME,
8252ec342e6SJean Delvare 		.flags	= IORESOURCE_IO,
8262ec342e6SJean Delvare 	};
8272ec342e6SJean Delvare 	int err;
8282ec342e6SJean Delvare 
829b9acb64aSJean Delvare 	err = acpi_check_resource_conflict(&res);
830b9acb64aSJean Delvare 	if (err)
831b9acb64aSJean Delvare 		goto exit;
832b9acb64aSJean Delvare 
833*50e52c1fSUwe Kleine-König 	pdev = platform_device_alloc(DRIVER_NAME, address);
8342ec342e6SJean Delvare 	if (!pdev) {
8352ec342e6SJean Delvare 		err = -ENOMEM;
836774f7827SJoe Perches 		pr_err("Device allocation failed\n");
8372ec342e6SJean Delvare 		goto exit;
8382ec342e6SJean Delvare 	}
8392ec342e6SJean Delvare 
8402ec342e6SJean Delvare 	err = platform_device_add_resources(pdev, &res, 1);
8412ec342e6SJean Delvare 	if (err) {
842774f7827SJoe Perches 		pr_err("Device resource addition failed (%d)\n", err);
8432ec342e6SJean Delvare 		goto exit_device_put;
8442ec342e6SJean Delvare 	}
8452ec342e6SJean Delvare 
8462ec342e6SJean Delvare 	err = platform_device_add(pdev);
8472ec342e6SJean Delvare 	if (err) {
848774f7827SJoe Perches 		pr_err("Device addition failed (%d)\n", err);
8492ec342e6SJean Delvare 		goto exit_device_put;
8502ec342e6SJean Delvare 	}
8512ec342e6SJean Delvare 
8522ec342e6SJean Delvare 	return 0;
8532ec342e6SJean Delvare 
8542ec342e6SJean Delvare exit_device_put:
8552ec342e6SJean Delvare 	platform_device_put(pdev);
8562ec342e6SJean Delvare exit:
8572ec342e6SJean Delvare 	return err;
8582ec342e6SJean Delvare }
8592ec342e6SJean Delvare 
8606c931ae1SBill Pemberton static int via686a_pci_probe(struct pci_dev *dev,
8618d5d45fbSJean Delvare 				       const struct pci_device_id *id)
8628d5d45fbSJean Delvare {
8632ec342e6SJean Delvare 	u16 address, val;
8648d5d45fbSJean Delvare 
8652ec342e6SJean Delvare 	if (force_addr) {
8662ec342e6SJean Delvare 		address = force_addr & ~(VIA686A_EXTENT - 1);
8672ec342e6SJean Delvare 		dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
8682ec342e6SJean Delvare 		if (PCIBIOS_SUCCESSFUL !=
8692ec342e6SJean Delvare 		    pci_write_config_word(dev, VIA686A_BASE_REG, address | 1))
8702ec342e6SJean Delvare 			return -ENODEV;
8712ec342e6SJean Delvare 	}
8728d5d45fbSJean Delvare 	if (PCIBIOS_SUCCESSFUL !=
8738d5d45fbSJean Delvare 	    pci_read_config_word(dev, VIA686A_BASE_REG, &val))
8748d5d45fbSJean Delvare 		return -ENODEV;
8758d5d45fbSJean Delvare 
8762d8672c5SJean Delvare 	address = val & ~(VIA686A_EXTENT - 1);
8772ec342e6SJean Delvare 	if (address == 0) {
878b55f3757SGuenter Roeck 		dev_err(&dev->dev,
879b55f3757SGuenter Roeck 			"base address not set - upgrade BIOS or use force_addr=0xaddr\n");
8808d5d45fbSJean Delvare 		return -ENODEV;
8818d5d45fbSJean Delvare 	}
8828d5d45fbSJean Delvare 
8832ec342e6SJean Delvare 	if (PCIBIOS_SUCCESSFUL !=
8842ec342e6SJean Delvare 	    pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
8852ec342e6SJean Delvare 		return -ENODEV;
8862ec342e6SJean Delvare 	if (!(val & 0x0001)) {
8872ec342e6SJean Delvare 		if (!force_addr) {
888b55f3757SGuenter Roeck 			dev_warn(&dev->dev,
889b55f3757SGuenter Roeck 				 "Sensors disabled, enable with force_addr=0x%x\n",
890b55f3757SGuenter Roeck 				 address);
8912ec342e6SJean Delvare 			return -ENODEV;
8928d5d45fbSJean Delvare 		}
8938d5d45fbSJean Delvare 
8942ec342e6SJean Delvare 		dev_warn(&dev->dev, "Enabling sensors\n");
8952ec342e6SJean Delvare 		if (PCIBIOS_SUCCESSFUL !=
8962ec342e6SJean Delvare 		    pci_write_config_word(dev, VIA686A_ENABLE_REG,
8972ec342e6SJean Delvare 					  val | 0x0001))
8982ec342e6SJean Delvare 			return -ENODEV;
8992ec342e6SJean Delvare 	}
9002ec342e6SJean Delvare 
9012ec342e6SJean Delvare 	if (platform_driver_register(&via686a_driver))
9022ec342e6SJean Delvare 		goto exit;
9032ec342e6SJean Delvare 
9042ec342e6SJean Delvare 	/* Sets global pdev as a side effect */
9052ec342e6SJean Delvare 	if (via686a_device_add(address))
9062ec342e6SJean Delvare 		goto exit_unregister;
9072ec342e6SJean Delvare 
9089004ac81SGuenter Roeck 	/*
9099004ac81SGuenter Roeck 	 * Always return failure here.  This is to allow other drivers to bind
9108d5d45fbSJean Delvare 	 * to this pci device.  We don't really want to have control over the
9118d5d45fbSJean Delvare 	 * pci device, we only wanted to read as few register values from it.
9128d5d45fbSJean Delvare 	 */
9132ec342e6SJean Delvare 	s_bridge = pci_dev_get(dev);
9142ec342e6SJean Delvare 	return -ENODEV;
9152ec342e6SJean Delvare 
9162ec342e6SJean Delvare exit_unregister:
9172ec342e6SJean Delvare 	platform_driver_unregister(&via686a_driver);
9182ec342e6SJean Delvare exit:
9198d5d45fbSJean Delvare 	return -ENODEV;
9208d5d45fbSJean Delvare }
9218d5d45fbSJean Delvare 
9228d5d45fbSJean Delvare static struct pci_driver via686a_pci_driver = {
923*50e52c1fSUwe Kleine-König 	.name		= DRIVER_NAME,
9248d5d45fbSJean Delvare 	.id_table	= via686a_pci_ids,
9258d5d45fbSJean Delvare 	.probe		= via686a_pci_probe,
9268d5d45fbSJean Delvare };
9278d5d45fbSJean Delvare 
9288d5d45fbSJean Delvare static int __init sm_via686a_init(void)
9298d5d45fbSJean Delvare {
9308d5d45fbSJean Delvare 	return pci_register_driver(&via686a_pci_driver);
9318d5d45fbSJean Delvare }
9328d5d45fbSJean Delvare 
9338d5d45fbSJean Delvare static void __exit sm_via686a_exit(void)
9348d5d45fbSJean Delvare {
9358d5d45fbSJean Delvare 	pci_unregister_driver(&via686a_pci_driver);
9368d5d45fbSJean Delvare 	if (s_bridge != NULL) {
9372ec342e6SJean Delvare 		platform_device_unregister(pdev);
9382ec342e6SJean Delvare 		platform_driver_unregister(&via686a_driver);
9398d5d45fbSJean Delvare 		pci_dev_put(s_bridge);
9408d5d45fbSJean Delvare 		s_bridge = NULL;
9418d5d45fbSJean Delvare 	}
9428d5d45fbSJean Delvare }
9438d5d45fbSJean Delvare 
94496de0e25SJan Engelhardt MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, "
9458d5d45fbSJean Delvare 	      "Mark Studebaker <mdsxyz123@yahoo.com> "
9468d5d45fbSJean Delvare 	      "and Bob Dougherty <bobd@stanford.edu>");
9478d5d45fbSJean Delvare MODULE_DESCRIPTION("VIA 686A Sensor device");
9488d5d45fbSJean Delvare MODULE_LICENSE("GPL");
9498d5d45fbSJean Delvare 
9508d5d45fbSJean Delvare module_init(sm_via686a_init);
9518d5d45fbSJean Delvare module_exit(sm_via686a_exit);
952