xref: /openbmc/linux/drivers/hwmon/via686a.c (revision 9d5bc0906cc1dc816f5b26e179b6cf764a2ef259)
18d5d45fbSJean Delvare /*
29004ac81SGuenter Roeck  * via686a.c - Part of lm_sensors, Linux kernel modules
39004ac81SGuenter Roeck  *	       for hardware monitoring
49004ac81SGuenter Roeck  *
59004ac81SGuenter Roeck  * Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
69004ac81SGuenter Roeck  *			      Kyösti Mälkki <kmalkki@cc.hut.fi>,
79004ac81SGuenter Roeck  *			      Mark Studebaker <mdsxyz123@yahoo.com>,
89004ac81SGuenter Roeck  *			      and Bob Dougherty <bobd@stanford.edu>
99004ac81SGuenter Roeck  *
109004ac81SGuenter Roeck  * (Some conversion-factor data were contributed by Jonathan Teh Soon Yew
119004ac81SGuenter Roeck  * <j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.)
129004ac81SGuenter Roeck  *
139004ac81SGuenter Roeck  * This program is free software; you can redistribute it and/or modify
149004ac81SGuenter Roeck  * it under the terms of the GNU General Public License as published by
159004ac81SGuenter Roeck  * the Free Software Foundation; either version 2 of the License, or
169004ac81SGuenter Roeck  * (at your option) any later version.
179004ac81SGuenter Roeck  *
189004ac81SGuenter Roeck  * This program is distributed in the hope that it will be useful,
199004ac81SGuenter Roeck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
209004ac81SGuenter Roeck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
219004ac81SGuenter Roeck  * GNU General Public License for more details.
229004ac81SGuenter Roeck  *
239004ac81SGuenter Roeck  * You should have received a copy of the GNU General Public License
249004ac81SGuenter Roeck  * along with this program; if not, write to the Free Software
259004ac81SGuenter Roeck  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
268d5d45fbSJean Delvare  */
278d5d45fbSJean Delvare 
288d5d45fbSJean Delvare /*
299004ac81SGuenter Roeck  * Supports the Via VT82C686A, VT82C686B south bridges.
309004ac81SGuenter Roeck  * Reports all as a 686A.
319004ac81SGuenter Roeck  * Warning - only supports a single device.
328d5d45fbSJean Delvare  */
338d5d45fbSJean Delvare 
34774f7827SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
35774f7827SJoe Perches 
368d5d45fbSJean Delvare #include <linux/module.h>
378d5d45fbSJean Delvare #include <linux/slab.h>
388d5d45fbSJean Delvare #include <linux/pci.h>
398d5d45fbSJean Delvare #include <linux/jiffies.h>
402ec342e6SJean Delvare #include <linux/platform_device.h>
41943b0830SMark M. Hoffman #include <linux/hwmon.h>
421e71a5a2SJean Delvare #include <linux/hwmon-sysfs.h>
43943b0830SMark M. Hoffman #include <linux/err.h>
448d5d45fbSJean Delvare #include <linux/init.h>
459a61bf63SIngo Molnar #include <linux/mutex.h>
46a5ebe668SJean Delvare #include <linux/sysfs.h>
47b9acb64aSJean Delvare #include <linux/acpi.h>
486055fae8SH Hartley Sweeten #include <linux/io.h>
498d5d45fbSJean Delvare 
509004ac81SGuenter Roeck /*
519004ac81SGuenter Roeck  * If force_addr is set to anything different from 0, we forcibly enable
529004ac81SGuenter Roeck  * the device at the given address.
539004ac81SGuenter Roeck  */
5402002963SJean Delvare static unsigned short force_addr;
558d5d45fbSJean Delvare module_param(force_addr, ushort, 0);
568d5d45fbSJean Delvare MODULE_PARM_DESC(force_addr,
578d5d45fbSJean Delvare 		 "Initialize the base address of the sensors");
588d5d45fbSJean Delvare 
592ec342e6SJean Delvare static struct platform_device *pdev;
608d5d45fbSJean Delvare 
618d5d45fbSJean Delvare /*
629004ac81SGuenter Roeck  * The Via 686a southbridge has a LM78-like chip integrated on the same IC.
639004ac81SGuenter Roeck  * This driver is a customized copy of lm78.c
648d5d45fbSJean Delvare  */
658d5d45fbSJean Delvare 
668d5d45fbSJean Delvare /* Many VIA686A constants specified below */
678d5d45fbSJean Delvare 
688d5d45fbSJean Delvare /* Length of ISA address segment */
698d5d45fbSJean Delvare #define VIA686A_EXTENT		0x80
708d5d45fbSJean Delvare #define VIA686A_BASE_REG	0x70
718d5d45fbSJean Delvare #define VIA686A_ENABLE_REG	0x74
728d5d45fbSJean Delvare 
738d5d45fbSJean Delvare /* The VIA686A registers */
748d5d45fbSJean Delvare /* ins numbered 0-4 */
758d5d45fbSJean Delvare #define VIA686A_REG_IN_MAX(nr)	(0x2b + ((nr) * 2))
768d5d45fbSJean Delvare #define VIA686A_REG_IN_MIN(nr)	(0x2c + ((nr) * 2))
778d5d45fbSJean Delvare #define VIA686A_REG_IN(nr)	(0x22 + (nr))
788d5d45fbSJean Delvare 
798d5d45fbSJean Delvare /* fans numbered 1-2 */
808d5d45fbSJean Delvare #define VIA686A_REG_FAN_MIN(nr)	(0x3a + (nr))
818d5d45fbSJean Delvare #define VIA686A_REG_FAN(nr)	(0x28 + (nr))
828d5d45fbSJean Delvare 
838d5d45fbSJean Delvare /* temps numbered 1-3 */
848d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP[]	= { 0x20, 0x21, 0x1f };
858d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_OVER[]	= { 0x39, 0x3d, 0x1d };
868d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_HYST[]	= { 0x3a, 0x3e, 0x1e };
878d5d45fbSJean Delvare /* bits 7-6 */
888d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW1	0x4b
898d5d45fbSJean Delvare /* 2 = bits 5-4, 3 = bits 7-6 */
908d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW23	0x49
918d5d45fbSJean Delvare 
928d5d45fbSJean Delvare #define VIA686A_REG_ALARM1	0x41
938d5d45fbSJean Delvare #define VIA686A_REG_ALARM2	0x42
948d5d45fbSJean Delvare #define VIA686A_REG_FANDIV	0x47
958d5d45fbSJean Delvare #define VIA686A_REG_CONFIG	0x40
969004ac81SGuenter Roeck /*
979004ac81SGuenter Roeck  * The following register sets temp interrupt mode (bits 1-0 for temp1,
989004ac81SGuenter Roeck  * 3-2 for temp2, 5-4 for temp3).  Modes are:
999004ac81SGuenter Roeck  * 00 interrupt stays as long as value is out-of-range
1009004ac81SGuenter Roeck  * 01 interrupt is cleared once register is read (default)
1019004ac81SGuenter Roeck  * 10 comparator mode- like 00, but ignores hysteresis
1029004ac81SGuenter Roeck  * 11 same as 00
1039004ac81SGuenter Roeck  */
1048d5d45fbSJean Delvare #define VIA686A_REG_TEMP_MODE		0x4b
1058d5d45fbSJean Delvare /* We'll just assume that you want to set all 3 simultaneously: */
1068d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_MASK		0x3F
1078d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_CONTINUOUS	0x00
1088d5d45fbSJean Delvare 
1099004ac81SGuenter Roeck /*
1109004ac81SGuenter Roeck  * Conversions. Limit checking is only done on the TO_REG
1119004ac81SGuenter Roeck  * variants.
1129004ac81SGuenter Roeck  *
1139004ac81SGuenter Roeck  ******** VOLTAGE CONVERSIONS (Bob Dougherty) ********
1149004ac81SGuenter Roeck  * From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew):
1159004ac81SGuenter Roeck  * voltagefactor[0]=1.25/2628; (2628/1.25=2102.4)   // Vccp
1169004ac81SGuenter Roeck  * voltagefactor[1]=1.25/2628; (2628/1.25=2102.4)   // +2.5V
1179004ac81SGuenter Roeck  * voltagefactor[2]=1.67/2628; (2628/1.67=1573.7)   // +3.3V
1189004ac81SGuenter Roeck  * voltagefactor[3]=2.6/2628;  (2628/2.60=1010.8)   // +5V
1199004ac81SGuenter Roeck  * voltagefactor[4]=6.3/2628;  (2628/6.30=417.14)   // +12V
1209004ac81SGuenter Roeck  * in[i]=(data[i+2]*25.0+133)*voltagefactor[i];
1219004ac81SGuenter Roeck  * That is:
1229004ac81SGuenter Roeck  * volts = (25*regVal+133)*factor
1239004ac81SGuenter Roeck  * regVal = (volts/factor-133)/25
1249004ac81SGuenter Roeck  * (These conversions were contributed by Jonathan Teh Soon Yew
1259004ac81SGuenter Roeck  * <j.teh@iname.com>)
1269004ac81SGuenter Roeck  */
127088ce2acSGuenter Roeck static inline u8 IN_TO_REG(long val, int in_num)
1288d5d45fbSJean Delvare {
1299004ac81SGuenter Roeck 	/*
1309004ac81SGuenter Roeck 	 * To avoid floating point, we multiply constants by 10 (100 for +12V).
1319004ac81SGuenter Roeck 	 * Rounding is done (120500 is actually 133000 - 12500).
1329004ac81SGuenter Roeck 	 * Remember that val is expressed in 0.001V/bit, which is why we divide
1339004ac81SGuenter Roeck 	 * by an additional 10000 (100000 for +12V): 1000 for val and 10 (100)
1349004ac81SGuenter Roeck 	 * for the constants.
1359004ac81SGuenter Roeck 	 */
136088ce2acSGuenter Roeck 	if (in_num <= 1)
1372a844c14SGuenter Roeck 		return (u8) clamp_val((val * 21024 - 1205000) / 250000, 0, 255);
138088ce2acSGuenter Roeck 	else if (in_num == 2)
1392a844c14SGuenter Roeck 		return (u8) clamp_val((val * 15737 - 1205000) / 250000, 0, 255);
140088ce2acSGuenter Roeck 	else if (in_num == 3)
1412a844c14SGuenter Roeck 		return (u8) clamp_val((val * 10108 - 1205000) / 250000, 0, 255);
1428d5d45fbSJean Delvare 	else
1432a844c14SGuenter Roeck 		return (u8) clamp_val((val * 41714 - 12050000) / 2500000, 0,
1442a844c14SGuenter Roeck 				      255);
1458d5d45fbSJean Delvare }
1468d5d45fbSJean Delvare 
147088ce2acSGuenter Roeck static inline long IN_FROM_REG(u8 val, int in_num)
1488d5d45fbSJean Delvare {
1499004ac81SGuenter Roeck 	/*
1509004ac81SGuenter Roeck 	 * To avoid floating point, we multiply constants by 10 (100 for +12V).
1519004ac81SGuenter Roeck 	 * We also multiply them by 1000 because we want 0.001V/bit for the
1529004ac81SGuenter Roeck 	 * output value. Rounding is done.
1539004ac81SGuenter Roeck 	 */
154088ce2acSGuenter Roeck 	if (in_num <= 1)
1558d5d45fbSJean Delvare 		return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024);
156088ce2acSGuenter Roeck 	else if (in_num == 2)
1578d5d45fbSJean Delvare 		return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737);
158088ce2acSGuenter Roeck 	else if (in_num == 3)
1598d5d45fbSJean Delvare 		return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108);
1608d5d45fbSJean Delvare 	else
1618d5d45fbSJean Delvare 		return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714);
1628d5d45fbSJean Delvare }
1638d5d45fbSJean Delvare 
1648d5d45fbSJean Delvare /********* FAN RPM CONVERSIONS ********/
1659004ac81SGuenter Roeck /*
1669004ac81SGuenter Roeck  * Higher register values = slower fans (the fan's strobe gates a counter).
1679004ac81SGuenter Roeck  * But this chip saturates back at 0, not at 255 like all the other chips.
1689004ac81SGuenter Roeck  * So, 0 means 0 RPM
1699004ac81SGuenter Roeck  */
1708d5d45fbSJean Delvare static inline u8 FAN_TO_REG(long rpm, int div)
1718d5d45fbSJean Delvare {
1728d5d45fbSJean Delvare 	if (rpm == 0)
1738d5d45fbSJean Delvare 		return 0;
1742a844c14SGuenter Roeck 	rpm = clamp_val(rpm, 1, 1000000);
1752a844c14SGuenter Roeck 	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 255);
1768d5d45fbSJean Delvare }
1778d5d45fbSJean Delvare 
1789004ac81SGuenter Roeck #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (val) == 255 ? 0 : 1350000 / \
1799004ac81SGuenter Roeck 				((val) * (div)))
1808d5d45fbSJean Delvare 
1818d5d45fbSJean Delvare /******** TEMP CONVERSIONS (Bob Dougherty) *********/
1829004ac81SGuenter Roeck /*
1839004ac81SGuenter Roeck  * linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew)
1849004ac81SGuenter Roeck  *	if(temp<169)
1859004ac81SGuenter Roeck  *		return double(temp)*0.427-32.08;
1869004ac81SGuenter Roeck  *	else if(temp>=169 && temp<=202)
1879004ac81SGuenter Roeck  *		return double(temp)*0.582-58.16;
1889004ac81SGuenter Roeck  *	else
1899004ac81SGuenter Roeck  *		return double(temp)*0.924-127.33;
1909004ac81SGuenter Roeck  *
1919004ac81SGuenter Roeck  * A fifth-order polynomial fits the unofficial data (provided by Alex van
1929004ac81SGuenter Roeck  * Kaam <darkside@chello.nl>) a bit better.  It also give more reasonable
1939004ac81SGuenter Roeck  * numbers on my machine (ie. they agree with what my BIOS tells me).
1949004ac81SGuenter Roeck  * Here's the fifth-order fit to the 8-bit data:
1959004ac81SGuenter Roeck  * temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 -
1969004ac81SGuenter Roeck  *	2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0.
1979004ac81SGuenter Roeck  *
1989004ac81SGuenter Roeck  * (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for
1999004ac81SGuenter Roeck  * finding my typos in this formula!)
2009004ac81SGuenter Roeck  *
2019004ac81SGuenter Roeck  * Alas, none of the elegant function-fit solutions will work because we
2029004ac81SGuenter Roeck  * aren't allowed to use floating point in the kernel and doing it with
2039004ac81SGuenter Roeck  * integers doesn't provide enough precision.  So we'll do boring old
2049004ac81SGuenter Roeck  * look-up table stuff.  The unofficial data (see below) have effectively
2059004ac81SGuenter Roeck  * 7-bit resolution (they are rounded to the nearest degree).  I'm assuming
2069004ac81SGuenter Roeck  * that the transfer function of the device is monotonic and smooth, so a
2079004ac81SGuenter Roeck  * smooth function fit to the data will allow us to get better precision.
2089004ac81SGuenter Roeck  * I used the 5th-order poly fit described above and solved for
2099004ac81SGuenter Roeck  * VIA register values 0-255.  I *10 before rounding, so we get tenth-degree
2109004ac81SGuenter Roeck  * precision.  (I could have done all 1024 values for our 10-bit readings,
2119004ac81SGuenter Roeck  * but the function is very linear in the useful range (0-80 deg C), so
212088ce2acSGuenter Roeck  * we'll just use linear interpolation for 10-bit readings.)  So, temp_lut
2139004ac81SGuenter Roeck  * is the temp at via register values 0-255:
2149004ac81SGuenter Roeck  */
215088ce2acSGuenter Roeck static const s16 temp_lut[] = {
2169004ac81SGuenter Roeck 	-709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
2178d5d45fbSJean Delvare 	-503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
2188d5d45fbSJean Delvare 	-362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
2198d5d45fbSJean Delvare 	-255, -246, -237, -229, -220, -212, -204, -196, -188, -180,
2208d5d45fbSJean Delvare 	-173, -166, -159, -152, -145, -139, -132, -126, -120, -114,
2218d5d45fbSJean Delvare 	-108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49,
2228d5d45fbSJean Delvare 	-44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16,
2238d5d45fbSJean Delvare 	20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84,
2248d5d45fbSJean Delvare 	88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138,
2258d5d45fbSJean Delvare 	142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189,
2268d5d45fbSJean Delvare 	193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241,
2278d5d45fbSJean Delvare 	245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294,
2288d5d45fbSJean Delvare 	299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348,
2298d5d45fbSJean Delvare 	353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404,
2308d5d45fbSJean Delvare 	409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464,
2318d5d45fbSJean Delvare 	469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532,
2328d5d45fbSJean Delvare 	538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614,
2338d5d45fbSJean Delvare 	621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718,
2348d5d45fbSJean Delvare 	728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856,
2358d5d45fbSJean Delvare 	870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044,
2368d5d45fbSJean Delvare 	1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252,
2378d5d45fbSJean Delvare 	1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462
2388d5d45fbSJean Delvare };
2398d5d45fbSJean Delvare 
2409004ac81SGuenter Roeck /*
2419004ac81SGuenter Roeck  * the original LUT values from Alex van Kaam <darkside@chello.nl>
2429004ac81SGuenter Roeck  * (for via register values 12-240):
2439004ac81SGuenter Roeck  * {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31,
2449004ac81SGuenter Roeck  * -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15,
2459004ac81SGuenter Roeck  * -15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3,
2469004ac81SGuenter 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,
2479004ac81SGuenter 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,
2489004ac81SGuenter 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,
2499004ac81SGuenter 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,
2509004ac81SGuenter 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,
2519004ac81SGuenter 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,
2529004ac81SGuenter Roeck  * 85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110};
2539004ac81SGuenter Roeck  *
2549004ac81SGuenter Roeck  *
2559004ac81SGuenter Roeck  * Here's the reverse LUT.  I got it by doing a 6-th order poly fit (needed
2569004ac81SGuenter Roeck  * an extra term for a good fit to these inverse data!) and then
2579004ac81SGuenter Roeck  * solving for each temp value from -50 to 110 (the useable range for
2589004ac81SGuenter Roeck  * this chip).  Here's the fit:
2599004ac81SGuenter Roeck  * viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4
2609004ac81SGuenter Roeck  * - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
2619004ac81SGuenter Roeck  * Note that n=161:
2629004ac81SGuenter Roeck  */
263088ce2acSGuenter Roeck static const u8 via_lut[] = {
2649004ac81SGuenter Roeck 	12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
2658d5d45fbSJean Delvare 	23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
2668d5d45fbSJean Delvare 	41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
2678d5d45fbSJean Delvare 	69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100,
2688d5d45fbSJean Delvare 	103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129,
2698d5d45fbSJean Delvare 	131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156,
2708d5d45fbSJean Delvare 	158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
2718d5d45fbSJean Delvare 	182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199,
2728d5d45fbSJean Delvare 	200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213,
2738d5d45fbSJean Delvare 	214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224,
2748d5d45fbSJean Delvare 	225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232,
2758d5d45fbSJean Delvare 	233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
2768d5d45fbSJean Delvare 	239, 240
2778d5d45fbSJean Delvare };
2788d5d45fbSJean Delvare 
2799004ac81SGuenter Roeck /*
2809004ac81SGuenter Roeck  * Converting temps to (8-bit) hyst and over registers
2819004ac81SGuenter Roeck  * No interpolation here.
2829004ac81SGuenter Roeck  * The +50 is because the temps start at -50
2839004ac81SGuenter Roeck  */
2848d5d45fbSJean Delvare static inline u8 TEMP_TO_REG(long val)
2858d5d45fbSJean Delvare {
286088ce2acSGuenter Roeck 	return via_lut[val <= -50000 ? 0 : val >= 110000 ? 160 :
2878d5d45fbSJean Delvare 		      (val < 0 ? val - 500 : val + 500) / 1000 + 50];
2888d5d45fbSJean Delvare }
2898d5d45fbSJean Delvare 
2908d5d45fbSJean Delvare /* for 8-bit temperature hyst and over registers */
291088ce2acSGuenter Roeck #define TEMP_FROM_REG(val)	((long)temp_lut[val] * 100)
2928d5d45fbSJean Delvare 
2938d5d45fbSJean Delvare /* for 10-bit temperature readings */
2948d5d45fbSJean Delvare static inline long TEMP_FROM_REG10(u16 val)
2958d5d45fbSJean Delvare {
296088ce2acSGuenter Roeck 	u16 eight_bits = val >> 2;
297088ce2acSGuenter Roeck 	u16 two_bits = val & 3;
2988d5d45fbSJean Delvare 
2998d5d45fbSJean Delvare 	/* no interpolation for these */
300088ce2acSGuenter Roeck 	if (two_bits == 0 || eight_bits == 255)
301088ce2acSGuenter Roeck 		return TEMP_FROM_REG(eight_bits);
3028d5d45fbSJean Delvare 
3038d5d45fbSJean Delvare 	/* do some linear interpolation */
304088ce2acSGuenter Roeck 	return (temp_lut[eight_bits] * (4 - two_bits) +
305088ce2acSGuenter Roeck 		temp_lut[eight_bits + 1] * two_bits) * 25;
3068d5d45fbSJean Delvare }
3078d5d45fbSJean Delvare 
3088d5d45fbSJean Delvare #define DIV_FROM_REG(val) (1 << (val))
3098d5d45fbSJean Delvare #define DIV_TO_REG(val) ((val) == 8 ? 3 : (val) == 4 ? 2 : (val) == 1 ? 0 : 1)
3108d5d45fbSJean Delvare 
3119004ac81SGuenter Roeck /*
3129004ac81SGuenter Roeck  * For each registered chip, we need to keep some data in memory.
3139004ac81SGuenter Roeck  * The structure is dynamically allocated.
3149004ac81SGuenter Roeck  */
3158d5d45fbSJean Delvare struct via686a_data {
3162ec342e6SJean Delvare 	unsigned short addr;
3172ec342e6SJean Delvare 	const char *name;
3181beeffe4STony Jones 	struct device *hwmon_dev;
3199a61bf63SIngo Molnar 	struct mutex update_lock;
3208d5d45fbSJean Delvare 	char valid;		/* !=0 if following fields are valid */
3218d5d45fbSJean Delvare 	unsigned long last_updated;	/* In jiffies */
3228d5d45fbSJean Delvare 
3238d5d45fbSJean Delvare 	u8 in[5];		/* Register value */
3248d5d45fbSJean Delvare 	u8 in_max[5];		/* Register value */
3258d5d45fbSJean Delvare 	u8 in_min[5];		/* Register value */
3268d5d45fbSJean Delvare 	u8 fan[2];		/* Register value */
3278d5d45fbSJean Delvare 	u8 fan_min[2];		/* Register value */
3288d5d45fbSJean Delvare 	u16 temp[3];		/* Register value 10 bit */
3298d5d45fbSJean Delvare 	u8 temp_over[3];	/* Register value */
3308d5d45fbSJean Delvare 	u8 temp_hyst[3];	/* Register value */
3318d5d45fbSJean Delvare 	u8 fan_div[2];		/* Register encoding, shifted right */
3328d5d45fbSJean Delvare 	u16 alarms;		/* Register encoding, combined */
3338d5d45fbSJean Delvare };
3348d5d45fbSJean Delvare 
3358d5d45fbSJean Delvare static struct pci_dev *s_bridge;	/* pointer to the (only) via686a */
3368d5d45fbSJean Delvare 
3372ec342e6SJean Delvare static int via686a_probe(struct platform_device *pdev);
338281dfd0bSBill Pemberton static int via686a_remove(struct platform_device *pdev);
3398d5d45fbSJean Delvare 
3402ec342e6SJean Delvare static inline int via686a_read_value(struct via686a_data *data, u8 reg)
3418d5d45fbSJean Delvare {
3422ec342e6SJean Delvare 	return inb_p(data->addr + reg);
3438d5d45fbSJean Delvare }
3448d5d45fbSJean Delvare 
3452ec342e6SJean Delvare static inline void via686a_write_value(struct via686a_data *data, u8 reg,
3468d5d45fbSJean Delvare 				       u8 value)
3478d5d45fbSJean Delvare {
3482ec342e6SJean Delvare 	outb_p(value, data->addr + reg);
3498d5d45fbSJean Delvare }
3508d5d45fbSJean Delvare 
3518d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev);
3522ec342e6SJean Delvare static void via686a_init_device(struct via686a_data *data);
3538d5d45fbSJean Delvare 
3548d5d45fbSJean Delvare /* following are the sysfs callback functions */
3558d5d45fbSJean Delvare 
3568d5d45fbSJean Delvare /* 7 voltage sensors */
357*9d5bc090SGuenter Roeck static ssize_t in_show(struct device *dev, struct device_attribute *da,
3581e71a5a2SJean Delvare 		       char *buf) {
3598d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
3601e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3611e71a5a2SJean Delvare 	int nr = attr->index;
3628d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr));
3638d5d45fbSJean Delvare }
3648d5d45fbSJean Delvare 
365*9d5bc090SGuenter Roeck static ssize_t in_min_show(struct device *dev, struct device_attribute *da,
3661e71a5a2SJean Delvare 			   char *buf) {
3678d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
3681e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3691e71a5a2SJean Delvare 	int nr = attr->index;
3708d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr));
3718d5d45fbSJean Delvare }
3728d5d45fbSJean Delvare 
373*9d5bc090SGuenter Roeck static ssize_t in_max_show(struct device *dev, struct device_attribute *da,
3741e71a5a2SJean Delvare 			   char *buf) {
3758d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
3761e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3771e71a5a2SJean Delvare 	int nr = attr->index;
3788d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
3798d5d45fbSJean Delvare }
3808d5d45fbSJean Delvare 
381*9d5bc090SGuenter Roeck static ssize_t in_min_store(struct device *dev, struct device_attribute *da,
3821e71a5a2SJean Delvare 			    const char *buf, size_t count) {
3832ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
3841e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3851e71a5a2SJean Delvare 	int nr = attr->index;
3869004ac81SGuenter Roeck 	unsigned long val;
3879004ac81SGuenter Roeck 	int err;
3889004ac81SGuenter Roeck 
3899004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
3909004ac81SGuenter Roeck 	if (err)
3919004ac81SGuenter Roeck 		return err;
3928d5d45fbSJean Delvare 
3939a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
3948d5d45fbSJean Delvare 	data->in_min[nr] = IN_TO_REG(val, nr);
3952ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_IN_MIN(nr),
3968d5d45fbSJean Delvare 			data->in_min[nr]);
3979a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
3988d5d45fbSJean Delvare 	return count;
3998d5d45fbSJean Delvare }
400*9d5bc090SGuenter Roeck static ssize_t in_max_store(struct device *dev, struct device_attribute *da,
4011e71a5a2SJean Delvare 			    const char *buf, size_t count) {
4022ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
4031e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4041e71a5a2SJean Delvare 	int nr = attr->index;
4059004ac81SGuenter Roeck 	unsigned long val;
4069004ac81SGuenter Roeck 	int err;
4079004ac81SGuenter Roeck 
4089004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
4099004ac81SGuenter Roeck 	if (err)
4109004ac81SGuenter Roeck 		return err;
4118d5d45fbSJean Delvare 
4129a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4138d5d45fbSJean Delvare 	data->in_max[nr] = IN_TO_REG(val, nr);
4142ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_IN_MAX(nr),
4158d5d45fbSJean Delvare 			data->in_max[nr]);
4169a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4178d5d45fbSJean Delvare 	return count;
4188d5d45fbSJean Delvare }
4198d5d45fbSJean Delvare 
420*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in0_input, in, 0);
421*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in0_min, in_min, 0);
422*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in0_max, in_max, 0);
423*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in1_input, in, 1);
424*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 1);
425*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 1);
426*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in2_input, in, 2);
427*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 2);
428*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 2);
429*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in3_input, in, 3);
430*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 3);
431*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 3);
432*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in4_input, in, 4);
433*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 4);
434*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 4);
4358d5d45fbSJean Delvare 
4368d5d45fbSJean Delvare /* 3 temperatures */
437*9d5bc090SGuenter Roeck static ssize_t temp_show(struct device *dev, struct device_attribute *da,
4381e71a5a2SJean Delvare 			 char *buf) {
4398d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4401e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4411e71a5a2SJean Delvare 	int nr = attr->index;
4428d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
4438d5d45fbSJean Delvare }
444*9d5bc090SGuenter Roeck static ssize_t temp_over_show(struct device *dev, struct device_attribute *da,
4451e71a5a2SJean Delvare 			      char *buf) {
4468d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4471e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4481e71a5a2SJean Delvare 	int nr = attr->index;
4498d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
4508d5d45fbSJean Delvare }
451*9d5bc090SGuenter Roeck static ssize_t temp_hyst_show(struct device *dev, struct device_attribute *da,
4521e71a5a2SJean Delvare 			      char *buf) {
4538d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
4541e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4551e71a5a2SJean Delvare 	int nr = attr->index;
4568d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
4578d5d45fbSJean Delvare }
458*9d5bc090SGuenter Roeck static ssize_t temp_over_store(struct device *dev,
459*9d5bc090SGuenter Roeck 			       struct device_attribute *da, const char *buf,
460*9d5bc090SGuenter Roeck 			       size_t count) {
4612ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
4621e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4631e71a5a2SJean Delvare 	int nr = attr->index;
4649004ac81SGuenter Roeck 	long val;
4659004ac81SGuenter Roeck 	int err;
4669004ac81SGuenter Roeck 
4679004ac81SGuenter Roeck 	err = kstrtol(buf, 10, &val);
4689004ac81SGuenter Roeck 	if (err)
4699004ac81SGuenter Roeck 		return err;
4708d5d45fbSJean Delvare 
4719a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4728d5d45fbSJean Delvare 	data->temp_over[nr] = TEMP_TO_REG(val);
4732ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr],
4748d5d45fbSJean Delvare 			    data->temp_over[nr]);
4759a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4768d5d45fbSJean Delvare 	return count;
4778d5d45fbSJean Delvare }
478*9d5bc090SGuenter Roeck static ssize_t temp_hyst_store(struct device *dev,
479*9d5bc090SGuenter Roeck 			       struct device_attribute *da, const char *buf,
480*9d5bc090SGuenter Roeck 			       size_t count) {
4812ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
4821e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
4831e71a5a2SJean Delvare 	int nr = attr->index;
4849004ac81SGuenter Roeck 	long val;
4859004ac81SGuenter Roeck 	int err;
4869004ac81SGuenter Roeck 
4879004ac81SGuenter Roeck 	err = kstrtol(buf, 10, &val);
4889004ac81SGuenter Roeck 	if (err)
4899004ac81SGuenter Roeck 		return err;
4908d5d45fbSJean Delvare 
4919a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4928d5d45fbSJean Delvare 	data->temp_hyst[nr] = TEMP_TO_REG(val);
4932ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr],
4948d5d45fbSJean Delvare 			    data->temp_hyst[nr]);
4959a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4968d5d45fbSJean Delvare 	return count;
4978d5d45fbSJean Delvare }
4988d5d45fbSJean Delvare 
499*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
500*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_over, 0);
501*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, temp_hyst, 0);
502*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1);
503*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_over, 1);
504*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_max_hyst, temp_hyst, 1);
505*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2);
506*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_max, temp_over, 2);
507*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_max_hyst, temp_hyst, 2);
5088d5d45fbSJean Delvare 
5098d5d45fbSJean Delvare /* 2 Fans */
510*9d5bc090SGuenter Roeck static ssize_t fan_show(struct device *dev, struct device_attribute *da,
5111e71a5a2SJean Delvare 			char *buf) {
5128d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5131e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5141e71a5a2SJean Delvare 	int nr = attr->index;
5158d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
5168d5d45fbSJean Delvare 				DIV_FROM_REG(data->fan_div[nr])));
5178d5d45fbSJean Delvare }
518*9d5bc090SGuenter Roeck static ssize_t fan_min_show(struct device *dev, struct device_attribute *da,
5191e71a5a2SJean Delvare 			    char *buf) {
5208d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5211e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5221e71a5a2SJean Delvare 	int nr = attr->index;
5238d5d45fbSJean Delvare 	return sprintf(buf, "%d\n",
5249004ac81SGuenter Roeck 		FAN_FROM_REG(data->fan_min[nr],
5259004ac81SGuenter Roeck 			     DIV_FROM_REG(data->fan_div[nr])));
5268d5d45fbSJean Delvare }
527*9d5bc090SGuenter Roeck static ssize_t fan_div_show(struct device *dev, struct device_attribute *da,
5281e71a5a2SJean Delvare 			    char *buf) {
5298d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5301e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5311e71a5a2SJean Delvare 	int nr = attr->index;
5328d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
5338d5d45fbSJean Delvare }
534*9d5bc090SGuenter Roeck static ssize_t fan_min_store(struct device *dev, struct device_attribute *da,
5351e71a5a2SJean Delvare 			     const char *buf, size_t count) {
5362ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
5371e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5381e71a5a2SJean Delvare 	int nr = attr->index;
5399004ac81SGuenter Roeck 	unsigned long val;
5409004ac81SGuenter Roeck 	int err;
5419004ac81SGuenter Roeck 
5429004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
5439004ac81SGuenter Roeck 	if (err)
5449004ac81SGuenter Roeck 		return err;
5458d5d45fbSJean Delvare 
5469a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
5478d5d45fbSJean Delvare 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
5482ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
5499a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
5508d5d45fbSJean Delvare 	return count;
5518d5d45fbSJean Delvare }
552*9d5bc090SGuenter Roeck static ssize_t fan_div_store(struct device *dev, struct device_attribute *da,
5531e71a5a2SJean Delvare 			     const char *buf, size_t count) {
5542ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
5551e71a5a2SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
5561e71a5a2SJean Delvare 	int nr = attr->index;
5578d5d45fbSJean Delvare 	int old;
5589004ac81SGuenter Roeck 	unsigned long val;
5599004ac81SGuenter Roeck 	int err;
5609004ac81SGuenter Roeck 
5619004ac81SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
5629004ac81SGuenter Roeck 	if (err)
5639004ac81SGuenter Roeck 		return err;
5648d5d45fbSJean Delvare 
5659a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
5662ec342e6SJean Delvare 	old = via686a_read_value(data, VIA686A_REG_FANDIV);
5678d5d45fbSJean Delvare 	data->fan_div[nr] = DIV_TO_REG(val);
5688d5d45fbSJean Delvare 	old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
5692ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_FANDIV, old);
5709a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
5718d5d45fbSJean Delvare 	return count;
5728d5d45fbSJean Delvare }
5738d5d45fbSJean Delvare 
574*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
575*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0);
576*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_div, fan_div, 0);
577*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
578*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1);
579*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1);
5808d5d45fbSJean Delvare 
5818d5d45fbSJean Delvare /* Alarms */
5828b2bd7aeSJulia Lawall static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
5839004ac81SGuenter Roeck 			   char *buf)
5849004ac81SGuenter Roeck {
5858d5d45fbSJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
5868d5d45fbSJean Delvare 	return sprintf(buf, "%u\n", data->alarms);
5878d5d45fbSJean Delvare }
5889004ac81SGuenter Roeck 
5898b2bd7aeSJulia Lawall static DEVICE_ATTR_RO(alarms);
5908d5d45fbSJean Delvare 
591*9d5bc090SGuenter Roeck static ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
59213ff05e9SJean Delvare 			  char *buf)
59313ff05e9SJean Delvare {
59413ff05e9SJean Delvare 	int bitnr = to_sensor_dev_attr(attr)->index;
59513ff05e9SJean Delvare 	struct via686a_data *data = via686a_update_device(dev);
59613ff05e9SJean Delvare 	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
59713ff05e9SJean Delvare }
598*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0);
599*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in1_alarm, alarm, 1);
600*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in2_alarm, alarm, 2);
601*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in3_alarm, alarm, 3);
602*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in4_alarm, alarm, 8);
603*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 4);
604*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_alarm, alarm, 11);
605*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_alarm, alarm, 15);
606*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 6);
607*9d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 7);
60813ff05e9SJean Delvare 
6098b2bd7aeSJulia Lawall static ssize_t name_show(struct device *dev, struct device_attribute
6102ec342e6SJean Delvare 			 *devattr, char *buf)
6112ec342e6SJean Delvare {
6122ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
6132ec342e6SJean Delvare 	return sprintf(buf, "%s\n", data->name);
6142ec342e6SJean Delvare }
6158b2bd7aeSJulia Lawall static DEVICE_ATTR_RO(name);
6162ec342e6SJean Delvare 
617a5ebe668SJean Delvare static struct attribute *via686a_attributes[] = {
6181e71a5a2SJean Delvare 	&sensor_dev_attr_in0_input.dev_attr.attr,
6191e71a5a2SJean Delvare 	&sensor_dev_attr_in1_input.dev_attr.attr,
6201e71a5a2SJean Delvare 	&sensor_dev_attr_in2_input.dev_attr.attr,
6211e71a5a2SJean Delvare 	&sensor_dev_attr_in3_input.dev_attr.attr,
6221e71a5a2SJean Delvare 	&sensor_dev_attr_in4_input.dev_attr.attr,
6231e71a5a2SJean Delvare 	&sensor_dev_attr_in0_min.dev_attr.attr,
6241e71a5a2SJean Delvare 	&sensor_dev_attr_in1_min.dev_attr.attr,
6251e71a5a2SJean Delvare 	&sensor_dev_attr_in2_min.dev_attr.attr,
6261e71a5a2SJean Delvare 	&sensor_dev_attr_in3_min.dev_attr.attr,
6271e71a5a2SJean Delvare 	&sensor_dev_attr_in4_min.dev_attr.attr,
6281e71a5a2SJean Delvare 	&sensor_dev_attr_in0_max.dev_attr.attr,
6291e71a5a2SJean Delvare 	&sensor_dev_attr_in1_max.dev_attr.attr,
6301e71a5a2SJean Delvare 	&sensor_dev_attr_in2_max.dev_attr.attr,
6311e71a5a2SJean Delvare 	&sensor_dev_attr_in3_max.dev_attr.attr,
6321e71a5a2SJean Delvare 	&sensor_dev_attr_in4_max.dev_attr.attr,
63313ff05e9SJean Delvare 	&sensor_dev_attr_in0_alarm.dev_attr.attr,
63413ff05e9SJean Delvare 	&sensor_dev_attr_in1_alarm.dev_attr.attr,
63513ff05e9SJean Delvare 	&sensor_dev_attr_in2_alarm.dev_attr.attr,
63613ff05e9SJean Delvare 	&sensor_dev_attr_in3_alarm.dev_attr.attr,
63713ff05e9SJean Delvare 	&sensor_dev_attr_in4_alarm.dev_attr.attr,
638a5ebe668SJean Delvare 
6391e71a5a2SJean Delvare 	&sensor_dev_attr_temp1_input.dev_attr.attr,
6401e71a5a2SJean Delvare 	&sensor_dev_attr_temp2_input.dev_attr.attr,
6411e71a5a2SJean Delvare 	&sensor_dev_attr_temp3_input.dev_attr.attr,
6421e71a5a2SJean Delvare 	&sensor_dev_attr_temp1_max.dev_attr.attr,
6431e71a5a2SJean Delvare 	&sensor_dev_attr_temp2_max.dev_attr.attr,
6441e71a5a2SJean Delvare 	&sensor_dev_attr_temp3_max.dev_attr.attr,
6451e71a5a2SJean Delvare 	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
6461e71a5a2SJean Delvare 	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
6471e71a5a2SJean Delvare 	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
64813ff05e9SJean Delvare 	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
64913ff05e9SJean Delvare 	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
65013ff05e9SJean Delvare 	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
651a5ebe668SJean Delvare 
6521e71a5a2SJean Delvare 	&sensor_dev_attr_fan1_input.dev_attr.attr,
6531e71a5a2SJean Delvare 	&sensor_dev_attr_fan2_input.dev_attr.attr,
6541e71a5a2SJean Delvare 	&sensor_dev_attr_fan1_min.dev_attr.attr,
6551e71a5a2SJean Delvare 	&sensor_dev_attr_fan2_min.dev_attr.attr,
6561e71a5a2SJean Delvare 	&sensor_dev_attr_fan1_div.dev_attr.attr,
6571e71a5a2SJean Delvare 	&sensor_dev_attr_fan2_div.dev_attr.attr,
65813ff05e9SJean Delvare 	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
65913ff05e9SJean Delvare 	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
660a5ebe668SJean Delvare 
661a5ebe668SJean Delvare 	&dev_attr_alarms.attr,
6622ec342e6SJean Delvare 	&dev_attr_name.attr,
663a5ebe668SJean Delvare 	NULL
664a5ebe668SJean Delvare };
665a5ebe668SJean Delvare 
666a5ebe668SJean Delvare static const struct attribute_group via686a_group = {
667a5ebe668SJean Delvare 	.attrs = via686a_attributes,
668a5ebe668SJean Delvare };
669a5ebe668SJean Delvare 
6702ec342e6SJean Delvare static struct platform_driver via686a_driver = {
671cdaf7934SLaurent Riffard 	.driver = {
6728d5d45fbSJean Delvare 		.name	= "via686a",
673cdaf7934SLaurent Riffard 	},
6742ec342e6SJean Delvare 	.probe		= via686a_probe,
6759e5e9b7aSBill Pemberton 	.remove		= via686a_remove,
6768d5d45fbSJean Delvare };
6778d5d45fbSJean Delvare 
6788d5d45fbSJean Delvare /* This is called when the module is loaded */
6796c931ae1SBill Pemberton static int via686a_probe(struct platform_device *pdev)
6808d5d45fbSJean Delvare {
6818d5d45fbSJean Delvare 	struct via686a_data *data;
6822ec342e6SJean Delvare 	struct resource *res;
6832ec342e6SJean Delvare 	int err;
6848d5d45fbSJean Delvare 
6858d5d45fbSJean Delvare 	/* Reserve the ISA region */
6862ec342e6SJean Delvare 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
687fd55bc00SGuenter Roeck 	if (!devm_request_region(&pdev->dev, res->start, VIA686A_EXTENT,
688cdaf7934SLaurent Riffard 				 via686a_driver.driver.name)) {
6892ec342e6SJean Delvare 		dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
6902ec342e6SJean Delvare 			(unsigned long)res->start, (unsigned long)res->end);
6918d5d45fbSJean Delvare 		return -ENODEV;
6928d5d45fbSJean Delvare 	}
6938d5d45fbSJean Delvare 
694fd55bc00SGuenter Roeck 	data = devm_kzalloc(&pdev->dev, sizeof(struct via686a_data),
695fd55bc00SGuenter Roeck 			    GFP_KERNEL);
696fd55bc00SGuenter Roeck 	if (!data)
697fd55bc00SGuenter Roeck 		return -ENOMEM;
6988d5d45fbSJean Delvare 
6992ec342e6SJean Delvare 	platform_set_drvdata(pdev, data);
7002ec342e6SJean Delvare 	data->addr = res->start;
7012ec342e6SJean Delvare 	data->name = "via686a";
7029a61bf63SIngo Molnar 	mutex_init(&data->update_lock);
7038d5d45fbSJean Delvare 
7048d5d45fbSJean Delvare 	/* Initialize the VIA686A chip */
7052ec342e6SJean Delvare 	via686a_init_device(data);
7068d5d45fbSJean Delvare 
7078d5d45fbSJean Delvare 	/* Register sysfs hooks */
7089004ac81SGuenter Roeck 	err = sysfs_create_group(&pdev->dev.kobj, &via686a_group);
7099004ac81SGuenter Roeck 	if (err)
710fd55bc00SGuenter Roeck 		return err;
711a5ebe668SJean Delvare 
7121beeffe4STony Jones 	data->hwmon_dev = hwmon_device_register(&pdev->dev);
7131beeffe4STony Jones 	if (IS_ERR(data->hwmon_dev)) {
7141beeffe4STony Jones 		err = PTR_ERR(data->hwmon_dev);
715a5ebe668SJean Delvare 		goto exit_remove_files;
716943b0830SMark M. Hoffman 	}
717943b0830SMark M. Hoffman 
7188d5d45fbSJean Delvare 	return 0;
7198d5d45fbSJean Delvare 
720a5ebe668SJean Delvare exit_remove_files:
7212ec342e6SJean Delvare 	sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
7228d5d45fbSJean Delvare 	return err;
7238d5d45fbSJean Delvare }
7248d5d45fbSJean Delvare 
725281dfd0bSBill Pemberton static int via686a_remove(struct platform_device *pdev)
7268d5d45fbSJean Delvare {
7272ec342e6SJean Delvare 	struct via686a_data *data = platform_get_drvdata(pdev);
7288d5d45fbSJean Delvare 
7291beeffe4STony Jones 	hwmon_device_unregister(data->hwmon_dev);
7302ec342e6SJean Delvare 	sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
731943b0830SMark M. Hoffman 
7328d5d45fbSJean Delvare 	return 0;
7338d5d45fbSJean Delvare }
7348d5d45fbSJean Delvare 
735f790674dSJean Delvare static void via686a_update_fan_div(struct via686a_data *data)
736f790674dSJean Delvare {
737f790674dSJean Delvare 	int reg = via686a_read_value(data, VIA686A_REG_FANDIV);
738f790674dSJean Delvare 	data->fan_div[0] = (reg >> 4) & 0x03;
739f790674dSJean Delvare 	data->fan_div[1] = reg >> 6;
740f790674dSJean Delvare }
741f790674dSJean Delvare 
7426c931ae1SBill Pemberton static void via686a_init_device(struct via686a_data *data)
7438d5d45fbSJean Delvare {
7448d5d45fbSJean Delvare 	u8 reg;
7458d5d45fbSJean Delvare 
7468d5d45fbSJean Delvare 	/* Start monitoring */
7472ec342e6SJean Delvare 	reg = via686a_read_value(data, VIA686A_REG_CONFIG);
7482ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
7498d5d45fbSJean Delvare 
7508d5d45fbSJean Delvare 	/* Configure temp interrupt mode for continuous-interrupt operation */
7512ec342e6SJean Delvare 	reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
7522ec342e6SJean Delvare 	via686a_write_value(data, VIA686A_REG_TEMP_MODE,
75358fe0809SJean Delvare 			    (reg & ~VIA686A_TEMP_MODE_MASK)
75458fe0809SJean Delvare 			    | VIA686A_TEMP_MODE_CONTINUOUS);
755f790674dSJean Delvare 
756f790674dSJean Delvare 	/* Pre-read fan clock divisor values */
757f790674dSJean Delvare 	via686a_update_fan_div(data);
7588d5d45fbSJean Delvare }
7598d5d45fbSJean Delvare 
7608d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev)
7618d5d45fbSJean Delvare {
7622ec342e6SJean Delvare 	struct via686a_data *data = dev_get_drvdata(dev);
7638d5d45fbSJean Delvare 	int i;
7648d5d45fbSJean Delvare 
7659a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
7668d5d45fbSJean Delvare 
7678d5d45fbSJean Delvare 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
7688d5d45fbSJean Delvare 	    || !data->valid) {
7698d5d45fbSJean Delvare 		for (i = 0; i <= 4; i++) {
7708d5d45fbSJean Delvare 			data->in[i] =
7712ec342e6SJean Delvare 			    via686a_read_value(data, VIA686A_REG_IN(i));
7722ec342e6SJean Delvare 			data->in_min[i] = via686a_read_value(data,
7738d5d45fbSJean Delvare 							     VIA686A_REG_IN_MIN
7748d5d45fbSJean Delvare 							     (i));
7758d5d45fbSJean Delvare 			data->in_max[i] =
7762ec342e6SJean Delvare 			    via686a_read_value(data, VIA686A_REG_IN_MAX(i));
7778d5d45fbSJean Delvare 		}
7788d5d45fbSJean Delvare 		for (i = 1; i <= 2; i++) {
7798d5d45fbSJean Delvare 			data->fan[i - 1] =
7802ec342e6SJean Delvare 			    via686a_read_value(data, VIA686A_REG_FAN(i));
7812ec342e6SJean Delvare 			data->fan_min[i - 1] = via686a_read_value(data,
7828d5d45fbSJean Delvare 						     VIA686A_REG_FAN_MIN(i));
7838d5d45fbSJean Delvare 		}
7848d5d45fbSJean Delvare 		for (i = 0; i <= 2; i++) {
7852ec342e6SJean Delvare 			data->temp[i] = via686a_read_value(data,
7868d5d45fbSJean Delvare 						 VIA686A_REG_TEMP[i]) << 2;
7878d5d45fbSJean Delvare 			data->temp_over[i] =
7882ec342e6SJean Delvare 			    via686a_read_value(data,
7898d5d45fbSJean Delvare 					       VIA686A_REG_TEMP_OVER[i]);
7908d5d45fbSJean Delvare 			data->temp_hyst[i] =
7912ec342e6SJean Delvare 			    via686a_read_value(data,
7928d5d45fbSJean Delvare 					       VIA686A_REG_TEMP_HYST[i]);
7938d5d45fbSJean Delvare 		}
7949004ac81SGuenter Roeck 		/*
7959004ac81SGuenter Roeck 		 * add in lower 2 bits
7969004ac81SGuenter Roeck 		 * temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1
7979004ac81SGuenter Roeck 		 * temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
7989004ac81SGuenter Roeck 		 * temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
7998d5d45fbSJean Delvare 		 */
8002ec342e6SJean Delvare 		data->temp[0] |= (via686a_read_value(data,
8018d5d45fbSJean Delvare 						     VIA686A_REG_TEMP_LOW1)
8028d5d45fbSJean Delvare 				  & 0xc0) >> 6;
8038d5d45fbSJean Delvare 		data->temp[1] |=
8042ec342e6SJean Delvare 		    (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
8058d5d45fbSJean Delvare 		     0x30) >> 4;
8068d5d45fbSJean Delvare 		data->temp[2] |=
8072ec342e6SJean Delvare 		    (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
8088d5d45fbSJean Delvare 		     0xc0) >> 6;
8098d5d45fbSJean Delvare 
810f790674dSJean Delvare 		via686a_update_fan_div(data);
8118d5d45fbSJean Delvare 		data->alarms =
8122ec342e6SJean Delvare 		    via686a_read_value(data,
8138d5d45fbSJean Delvare 				       VIA686A_REG_ALARM1) |
8142ec342e6SJean Delvare 		    (via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
8158d5d45fbSJean Delvare 		data->last_updated = jiffies;
8168d5d45fbSJean Delvare 		data->valid = 1;
8178d5d45fbSJean Delvare 	}
8188d5d45fbSJean Delvare 
8199a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
8208d5d45fbSJean Delvare 
8218d5d45fbSJean Delvare 	return data;
8228d5d45fbSJean Delvare }
8238d5d45fbSJean Delvare 
824cd9bb056SJingoo Han static const struct pci_device_id via686a_pci_ids[] = {
8258d5d45fbSJean Delvare 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
8269004ac81SGuenter Roeck 	{ }
8278d5d45fbSJean Delvare };
8288d5d45fbSJean Delvare MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
8298d5d45fbSJean Delvare 
8306c931ae1SBill Pemberton static int via686a_device_add(unsigned short address)
8312ec342e6SJean Delvare {
8322ec342e6SJean Delvare 	struct resource res = {
8332ec342e6SJean Delvare 		.start	= address,
8342ec342e6SJean Delvare 		.end	= address + VIA686A_EXTENT - 1,
8352ec342e6SJean Delvare 		.name	= "via686a",
8362ec342e6SJean Delvare 		.flags	= IORESOURCE_IO,
8372ec342e6SJean Delvare 	};
8382ec342e6SJean Delvare 	int err;
8392ec342e6SJean Delvare 
840b9acb64aSJean Delvare 	err = acpi_check_resource_conflict(&res);
841b9acb64aSJean Delvare 	if (err)
842b9acb64aSJean Delvare 		goto exit;
843b9acb64aSJean Delvare 
8442ec342e6SJean Delvare 	pdev = platform_device_alloc("via686a", address);
8452ec342e6SJean Delvare 	if (!pdev) {
8462ec342e6SJean Delvare 		err = -ENOMEM;
847774f7827SJoe Perches 		pr_err("Device allocation failed\n");
8482ec342e6SJean Delvare 		goto exit;
8492ec342e6SJean Delvare 	}
8502ec342e6SJean Delvare 
8512ec342e6SJean Delvare 	err = platform_device_add_resources(pdev, &res, 1);
8522ec342e6SJean Delvare 	if (err) {
853774f7827SJoe Perches 		pr_err("Device resource addition failed (%d)\n", err);
8542ec342e6SJean Delvare 		goto exit_device_put;
8552ec342e6SJean Delvare 	}
8562ec342e6SJean Delvare 
8572ec342e6SJean Delvare 	err = platform_device_add(pdev);
8582ec342e6SJean Delvare 	if (err) {
859774f7827SJoe Perches 		pr_err("Device addition failed (%d)\n", err);
8602ec342e6SJean Delvare 		goto exit_device_put;
8612ec342e6SJean Delvare 	}
8622ec342e6SJean Delvare 
8632ec342e6SJean Delvare 	return 0;
8642ec342e6SJean Delvare 
8652ec342e6SJean Delvare exit_device_put:
8662ec342e6SJean Delvare 	platform_device_put(pdev);
8672ec342e6SJean Delvare exit:
8682ec342e6SJean Delvare 	return err;
8692ec342e6SJean Delvare }
8702ec342e6SJean Delvare 
8716c931ae1SBill Pemberton static int via686a_pci_probe(struct pci_dev *dev,
8728d5d45fbSJean Delvare 				       const struct pci_device_id *id)
8738d5d45fbSJean Delvare {
8742ec342e6SJean Delvare 	u16 address, val;
8758d5d45fbSJean Delvare 
8762ec342e6SJean Delvare 	if (force_addr) {
8772ec342e6SJean Delvare 		address = force_addr & ~(VIA686A_EXTENT - 1);
8782ec342e6SJean Delvare 		dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
8792ec342e6SJean Delvare 		if (PCIBIOS_SUCCESSFUL !=
8802ec342e6SJean Delvare 		    pci_write_config_word(dev, VIA686A_BASE_REG, address | 1))
8812ec342e6SJean Delvare 			return -ENODEV;
8822ec342e6SJean Delvare 	}
8838d5d45fbSJean Delvare 	if (PCIBIOS_SUCCESSFUL !=
8848d5d45fbSJean Delvare 	    pci_read_config_word(dev, VIA686A_BASE_REG, &val))
8858d5d45fbSJean Delvare 		return -ENODEV;
8868d5d45fbSJean Delvare 
8872d8672c5SJean Delvare 	address = val & ~(VIA686A_EXTENT - 1);
8882ec342e6SJean Delvare 	if (address == 0) {
889b55f3757SGuenter Roeck 		dev_err(&dev->dev,
890b55f3757SGuenter Roeck 			"base address not set - upgrade BIOS or use force_addr=0xaddr\n");
8918d5d45fbSJean Delvare 		return -ENODEV;
8928d5d45fbSJean Delvare 	}
8938d5d45fbSJean Delvare 
8942ec342e6SJean Delvare 	if (PCIBIOS_SUCCESSFUL !=
8952ec342e6SJean Delvare 	    pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
8962ec342e6SJean Delvare 		return -ENODEV;
8972ec342e6SJean Delvare 	if (!(val & 0x0001)) {
8982ec342e6SJean Delvare 		if (!force_addr) {
899b55f3757SGuenter Roeck 			dev_warn(&dev->dev,
900b55f3757SGuenter Roeck 				 "Sensors disabled, enable with force_addr=0x%x\n",
901b55f3757SGuenter Roeck 				 address);
9022ec342e6SJean Delvare 			return -ENODEV;
9038d5d45fbSJean Delvare 		}
9048d5d45fbSJean Delvare 
9052ec342e6SJean Delvare 		dev_warn(&dev->dev, "Enabling sensors\n");
9062ec342e6SJean Delvare 		if (PCIBIOS_SUCCESSFUL !=
9072ec342e6SJean Delvare 		    pci_write_config_word(dev, VIA686A_ENABLE_REG,
9082ec342e6SJean Delvare 					  val | 0x0001))
9092ec342e6SJean Delvare 			return -ENODEV;
9102ec342e6SJean Delvare 	}
9112ec342e6SJean Delvare 
9122ec342e6SJean Delvare 	if (platform_driver_register(&via686a_driver))
9132ec342e6SJean Delvare 		goto exit;
9142ec342e6SJean Delvare 
9152ec342e6SJean Delvare 	/* Sets global pdev as a side effect */
9162ec342e6SJean Delvare 	if (via686a_device_add(address))
9172ec342e6SJean Delvare 		goto exit_unregister;
9182ec342e6SJean Delvare 
9199004ac81SGuenter Roeck 	/*
9209004ac81SGuenter Roeck 	 * Always return failure here.  This is to allow other drivers to bind
9218d5d45fbSJean Delvare 	 * to this pci device.  We don't really want to have control over the
9228d5d45fbSJean Delvare 	 * pci device, we only wanted to read as few register values from it.
9238d5d45fbSJean Delvare 	 */
9242ec342e6SJean Delvare 	s_bridge = pci_dev_get(dev);
9252ec342e6SJean Delvare 	return -ENODEV;
9262ec342e6SJean Delvare 
9272ec342e6SJean Delvare exit_unregister:
9282ec342e6SJean Delvare 	platform_driver_unregister(&via686a_driver);
9292ec342e6SJean Delvare exit:
9308d5d45fbSJean Delvare 	return -ENODEV;
9318d5d45fbSJean Delvare }
9328d5d45fbSJean Delvare 
9338d5d45fbSJean Delvare static struct pci_driver via686a_pci_driver = {
9348d5d45fbSJean Delvare 	.name		= "via686a",
9358d5d45fbSJean Delvare 	.id_table	= via686a_pci_ids,
9368d5d45fbSJean Delvare 	.probe		= via686a_pci_probe,
9378d5d45fbSJean Delvare };
9388d5d45fbSJean Delvare 
9398d5d45fbSJean Delvare static int __init sm_via686a_init(void)
9408d5d45fbSJean Delvare {
9418d5d45fbSJean Delvare 	return pci_register_driver(&via686a_pci_driver);
9428d5d45fbSJean Delvare }
9438d5d45fbSJean Delvare 
9448d5d45fbSJean Delvare static void __exit sm_via686a_exit(void)
9458d5d45fbSJean Delvare {
9468d5d45fbSJean Delvare 	pci_unregister_driver(&via686a_pci_driver);
9478d5d45fbSJean Delvare 	if (s_bridge != NULL) {
9482ec342e6SJean Delvare 		platform_device_unregister(pdev);
9492ec342e6SJean Delvare 		platform_driver_unregister(&via686a_driver);
9508d5d45fbSJean Delvare 		pci_dev_put(s_bridge);
9518d5d45fbSJean Delvare 		s_bridge = NULL;
9528d5d45fbSJean Delvare 	}
9538d5d45fbSJean Delvare }
9548d5d45fbSJean Delvare 
95596de0e25SJan Engelhardt MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, "
9568d5d45fbSJean Delvare 	      "Mark Studebaker <mdsxyz123@yahoo.com> "
9578d5d45fbSJean Delvare 	      "and Bob Dougherty <bobd@stanford.edu>");
9588d5d45fbSJean Delvare MODULE_DESCRIPTION("VIA 686A Sensor device");
9598d5d45fbSJean Delvare MODULE_LICENSE("GPL");
9608d5d45fbSJean Delvare 
9618d5d45fbSJean Delvare module_init(sm_via686a_init);
9628d5d45fbSJean Delvare module_exit(sm_via686a_exit);
963