18d5d45fbSJean Delvare /* 28d5d45fbSJean Delvare via686a.c - Part of lm_sensors, Linux kernel modules 38d5d45fbSJean Delvare for hardware monitoring 48d5d45fbSJean Delvare 58d5d45fbSJean Delvare Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, 696de0e25SJan Engelhardt Kyösti Mälkki <kmalkki@cc.hut.fi>, 78d5d45fbSJean Delvare Mark Studebaker <mdsxyz123@yahoo.com>, 88d5d45fbSJean Delvare and Bob Dougherty <bobd@stanford.edu> 98d5d45fbSJean Delvare (Some conversion-factor data were contributed by Jonathan Teh Soon Yew 108d5d45fbSJean Delvare <j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.) 118d5d45fbSJean Delvare 128d5d45fbSJean Delvare This program is free software; you can redistribute it and/or modify 138d5d45fbSJean Delvare it under the terms of the GNU General Public License as published by 148d5d45fbSJean Delvare the Free Software Foundation; either version 2 of the License, or 158d5d45fbSJean Delvare (at your option) any later version. 168d5d45fbSJean Delvare 178d5d45fbSJean Delvare This program is distributed in the hope that it will be useful, 188d5d45fbSJean Delvare but WITHOUT ANY WARRANTY; without even the implied warranty of 198d5d45fbSJean Delvare MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 208d5d45fbSJean Delvare GNU General Public License for more details. 218d5d45fbSJean Delvare 228d5d45fbSJean Delvare You should have received a copy of the GNU General Public License 238d5d45fbSJean Delvare along with this program; if not, write to the Free Software 248d5d45fbSJean Delvare Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 258d5d45fbSJean Delvare */ 268d5d45fbSJean Delvare 278d5d45fbSJean Delvare /* 288d5d45fbSJean Delvare Supports the Via VT82C686A, VT82C686B south bridges. 298d5d45fbSJean Delvare Reports all as a 686A. 308d5d45fbSJean Delvare Warning - only supports a single device. 318d5d45fbSJean Delvare */ 328d5d45fbSJean Delvare 338d5d45fbSJean Delvare #include <linux/module.h> 348d5d45fbSJean Delvare #include <linux/slab.h> 358d5d45fbSJean Delvare #include <linux/pci.h> 368d5d45fbSJean Delvare #include <linux/jiffies.h> 372ec342e6SJean Delvare #include <linux/platform_device.h> 38943b0830SMark M. Hoffman #include <linux/hwmon.h> 391e71a5a2SJean Delvare #include <linux/hwmon-sysfs.h> 40943b0830SMark M. Hoffman #include <linux/err.h> 418d5d45fbSJean Delvare #include <linux/init.h> 429a61bf63SIngo Molnar #include <linux/mutex.h> 43a5ebe668SJean Delvare #include <linux/sysfs.h> 448d5d45fbSJean Delvare #include <asm/io.h> 458d5d45fbSJean Delvare 468d5d45fbSJean Delvare 478d5d45fbSJean Delvare /* If force_addr is set to anything different from 0, we forcibly enable 488d5d45fbSJean Delvare the device at the given address. */ 4902002963SJean Delvare static unsigned short force_addr; 508d5d45fbSJean Delvare module_param(force_addr, ushort, 0); 518d5d45fbSJean Delvare MODULE_PARM_DESC(force_addr, 528d5d45fbSJean Delvare "Initialize the base address of the sensors"); 538d5d45fbSJean Delvare 542ec342e6SJean Delvare static struct platform_device *pdev; 558d5d45fbSJean Delvare 568d5d45fbSJean Delvare /* 578d5d45fbSJean Delvare The Via 686a southbridge has a LM78-like chip integrated on the same IC. 588d5d45fbSJean Delvare This driver is a customized copy of lm78.c 598d5d45fbSJean Delvare */ 608d5d45fbSJean Delvare 618d5d45fbSJean Delvare /* Many VIA686A constants specified below */ 628d5d45fbSJean Delvare 638d5d45fbSJean Delvare /* Length of ISA address segment */ 648d5d45fbSJean Delvare #define VIA686A_EXTENT 0x80 658d5d45fbSJean Delvare #define VIA686A_BASE_REG 0x70 668d5d45fbSJean Delvare #define VIA686A_ENABLE_REG 0x74 678d5d45fbSJean Delvare 688d5d45fbSJean Delvare /* The VIA686A registers */ 698d5d45fbSJean Delvare /* ins numbered 0-4 */ 708d5d45fbSJean Delvare #define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) 718d5d45fbSJean Delvare #define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) 728d5d45fbSJean Delvare #define VIA686A_REG_IN(nr) (0x22 + (nr)) 738d5d45fbSJean Delvare 748d5d45fbSJean Delvare /* fans numbered 1-2 */ 758d5d45fbSJean Delvare #define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) 768d5d45fbSJean Delvare #define VIA686A_REG_FAN(nr) (0x28 + (nr)) 778d5d45fbSJean Delvare 788d5d45fbSJean Delvare /* temps numbered 1-3 */ 798d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP[] = { 0x20, 0x21, 0x1f }; 808d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_OVER[] = { 0x39, 0x3d, 0x1d }; 818d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e }; 828d5d45fbSJean Delvare /* bits 7-6 */ 838d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW1 0x4b 848d5d45fbSJean Delvare /* 2 = bits 5-4, 3 = bits 7-6 */ 858d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW23 0x49 868d5d45fbSJean Delvare 878d5d45fbSJean Delvare #define VIA686A_REG_ALARM1 0x41 888d5d45fbSJean Delvare #define VIA686A_REG_ALARM2 0x42 898d5d45fbSJean Delvare #define VIA686A_REG_FANDIV 0x47 908d5d45fbSJean Delvare #define VIA686A_REG_CONFIG 0x40 918d5d45fbSJean Delvare /* The following register sets temp interrupt mode (bits 1-0 for temp1, 928d5d45fbSJean Delvare 3-2 for temp2, 5-4 for temp3). Modes are: 938d5d45fbSJean Delvare 00 interrupt stays as long as value is out-of-range 948d5d45fbSJean Delvare 01 interrupt is cleared once register is read (default) 958d5d45fbSJean Delvare 10 comparator mode- like 00, but ignores hysteresis 968d5d45fbSJean Delvare 11 same as 00 */ 978d5d45fbSJean Delvare #define VIA686A_REG_TEMP_MODE 0x4b 988d5d45fbSJean Delvare /* We'll just assume that you want to set all 3 simultaneously: */ 998d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_MASK 0x3F 1008d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_CONTINUOUS 0x00 1018d5d45fbSJean Delvare 1028d5d45fbSJean Delvare /* Conversions. Limit checking is only done on the TO_REG 1038d5d45fbSJean Delvare variants. 1048d5d45fbSJean Delvare 1058d5d45fbSJean Delvare ********* VOLTAGE CONVERSIONS (Bob Dougherty) ******** 1068d5d45fbSJean Delvare From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): 1078d5d45fbSJean Delvare voltagefactor[0]=1.25/2628; (2628/1.25=2102.4) // Vccp 1088d5d45fbSJean Delvare voltagefactor[1]=1.25/2628; (2628/1.25=2102.4) // +2.5V 1098d5d45fbSJean Delvare voltagefactor[2]=1.67/2628; (2628/1.67=1573.7) // +3.3V 1108d5d45fbSJean Delvare voltagefactor[3]=2.6/2628; (2628/2.60=1010.8) // +5V 1118d5d45fbSJean Delvare voltagefactor[4]=6.3/2628; (2628/6.30=417.14) // +12V 1128d5d45fbSJean Delvare in[i]=(data[i+2]*25.0+133)*voltagefactor[i]; 1138d5d45fbSJean Delvare That is: 1148d5d45fbSJean Delvare volts = (25*regVal+133)*factor 1158d5d45fbSJean Delvare regVal = (volts/factor-133)/25 1168d5d45fbSJean Delvare (These conversions were contributed by Jonathan Teh Soon Yew 1178d5d45fbSJean Delvare <j.teh@iname.com>) */ 1188d5d45fbSJean Delvare static inline u8 IN_TO_REG(long val, int inNum) 1198d5d45fbSJean Delvare { 1208d5d45fbSJean Delvare /* To avoid floating point, we multiply constants by 10 (100 for +12V). 1218d5d45fbSJean Delvare Rounding is done (120500 is actually 133000 - 12500). 1228d5d45fbSJean Delvare Remember that val is expressed in 0.001V/bit, which is why we divide 1238d5d45fbSJean Delvare by an additional 10000 (100000 for +12V): 1000 for val and 10 (100) 1248d5d45fbSJean Delvare for the constants. */ 1258d5d45fbSJean Delvare if (inNum <= 1) 1268d5d45fbSJean Delvare return (u8) 1278d5d45fbSJean Delvare SENSORS_LIMIT((val * 21024 - 1205000) / 250000, 0, 255); 1288d5d45fbSJean Delvare else if (inNum == 2) 1298d5d45fbSJean Delvare return (u8) 1308d5d45fbSJean Delvare SENSORS_LIMIT((val * 15737 - 1205000) / 250000, 0, 255); 1318d5d45fbSJean Delvare else if (inNum == 3) 1328d5d45fbSJean Delvare return (u8) 1338d5d45fbSJean Delvare SENSORS_LIMIT((val * 10108 - 1205000) / 250000, 0, 255); 1348d5d45fbSJean Delvare else 1358d5d45fbSJean Delvare return (u8) 1368d5d45fbSJean Delvare SENSORS_LIMIT((val * 41714 - 12050000) / 2500000, 0, 255); 1378d5d45fbSJean Delvare } 1388d5d45fbSJean Delvare 1398d5d45fbSJean Delvare static inline long IN_FROM_REG(u8 val, int inNum) 1408d5d45fbSJean Delvare { 1418d5d45fbSJean Delvare /* To avoid floating point, we multiply constants by 10 (100 for +12V). 1428d5d45fbSJean Delvare We also multiply them by 1000 because we want 0.001V/bit for the 1438d5d45fbSJean Delvare output value. Rounding is done. */ 1448d5d45fbSJean Delvare if (inNum <= 1) 1458d5d45fbSJean Delvare return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024); 1468d5d45fbSJean Delvare else if (inNum == 2) 1478d5d45fbSJean Delvare return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737); 1488d5d45fbSJean Delvare else if (inNum == 3) 1498d5d45fbSJean Delvare return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108); 1508d5d45fbSJean Delvare else 1518d5d45fbSJean Delvare return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714); 1528d5d45fbSJean Delvare } 1538d5d45fbSJean Delvare 1548d5d45fbSJean Delvare /********* FAN RPM CONVERSIONS ********/ 1558d5d45fbSJean Delvare /* Higher register values = slower fans (the fan's strobe gates a counter). 1568d5d45fbSJean Delvare But this chip saturates back at 0, not at 255 like all the other chips. 1578d5d45fbSJean Delvare So, 0 means 0 RPM */ 1588d5d45fbSJean Delvare static inline u8 FAN_TO_REG(long rpm, int div) 1598d5d45fbSJean Delvare { 1608d5d45fbSJean Delvare if (rpm == 0) 1618d5d45fbSJean Delvare return 0; 1628d5d45fbSJean Delvare rpm = SENSORS_LIMIT(rpm, 1, 1000000); 1638d5d45fbSJean Delvare return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255); 1648d5d45fbSJean Delvare } 1658d5d45fbSJean Delvare 1668d5d45fbSJean Delvare #define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div))) 1678d5d45fbSJean Delvare 1688d5d45fbSJean Delvare /******** TEMP CONVERSIONS (Bob Dougherty) *********/ 1698d5d45fbSJean Delvare /* linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew) 1708d5d45fbSJean Delvare if(temp<169) 1718d5d45fbSJean Delvare return double(temp)*0.427-32.08; 1728d5d45fbSJean Delvare else if(temp>=169 && temp<=202) 1738d5d45fbSJean Delvare return double(temp)*0.582-58.16; 1748d5d45fbSJean Delvare else 1758d5d45fbSJean Delvare return double(temp)*0.924-127.33; 1768d5d45fbSJean Delvare 1778d5d45fbSJean Delvare A fifth-order polynomial fits the unofficial data (provided by Alex van 1788d5d45fbSJean Delvare Kaam <darkside@chello.nl>) a bit better. It also give more reasonable 1798d5d45fbSJean Delvare numbers on my machine (ie. they agree with what my BIOS tells me). 1808d5d45fbSJean Delvare Here's the fifth-order fit to the 8-bit data: 1818d5d45fbSJean Delvare temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - 1828d5d45fbSJean Delvare 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. 1838d5d45fbSJean Delvare 1848d5d45fbSJean Delvare (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for 1858d5d45fbSJean Delvare finding my typos in this formula!) 1868d5d45fbSJean Delvare 1878d5d45fbSJean Delvare Alas, none of the elegant function-fit solutions will work because we 1888d5d45fbSJean Delvare aren't allowed to use floating point in the kernel and doing it with 1898d5d45fbSJean Delvare integers doesn't provide enough precision. So we'll do boring old 1908d5d45fbSJean Delvare look-up table stuff. The unofficial data (see below) have effectively 1918d5d45fbSJean Delvare 7-bit resolution (they are rounded to the nearest degree). I'm assuming 1928d5d45fbSJean Delvare that the transfer function of the device is monotonic and smooth, so a 1938d5d45fbSJean Delvare smooth function fit to the data will allow us to get better precision. 1948d5d45fbSJean Delvare I used the 5th-order poly fit described above and solved for 1958d5d45fbSJean Delvare VIA register values 0-255. I *10 before rounding, so we get tenth-degree 1968d5d45fbSJean Delvare precision. (I could have done all 1024 values for our 10-bit readings, 1978d5d45fbSJean Delvare but the function is very linear in the useful range (0-80 deg C), so 1988d5d45fbSJean Delvare we'll just use linear interpolation for 10-bit readings.) So, tempLUT 1998d5d45fbSJean Delvare is the temp at via register values 0-255: */ 200088341bdSJean Delvare static const s16 tempLUT[] = 2018d5d45fbSJean Delvare { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, 2028d5d45fbSJean Delvare -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, 2038d5d45fbSJean Delvare -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, 2048d5d45fbSJean Delvare -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, 2058d5d45fbSJean Delvare -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, 2068d5d45fbSJean Delvare -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, 2078d5d45fbSJean Delvare -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, 2088d5d45fbSJean Delvare 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, 2098d5d45fbSJean Delvare 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, 2108d5d45fbSJean Delvare 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, 2118d5d45fbSJean Delvare 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, 2128d5d45fbSJean Delvare 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, 2138d5d45fbSJean Delvare 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, 2148d5d45fbSJean Delvare 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, 2158d5d45fbSJean Delvare 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, 2168d5d45fbSJean Delvare 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, 2178d5d45fbSJean Delvare 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, 2188d5d45fbSJean Delvare 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, 2198d5d45fbSJean Delvare 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, 2208d5d45fbSJean Delvare 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, 2218d5d45fbSJean Delvare 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, 2228d5d45fbSJean Delvare 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 2238d5d45fbSJean Delvare }; 2248d5d45fbSJean Delvare 2258d5d45fbSJean Delvare /* the original LUT values from Alex van Kaam <darkside@chello.nl> 2268d5d45fbSJean Delvare (for via register values 12-240): 2278d5d45fbSJean Delvare {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, 2288d5d45fbSJean Delvare -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, 2298d5d45fbSJean Delvare -15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3, 2308d5d45fbSJean Delvare -3,-2,-2,-1,-1,0,0,1,1,1,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,9,10,10,11,11,12, 2318d5d45fbSJean Delvare 12,12,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,20,20,21,21,21,22,22, 2328d5d45fbSJean Delvare 22,23,23,24,24,25,25,26,26,26,27,27,27,28,28,29,29,30,30,30,31,31,32,32,33, 2338d5d45fbSJean Delvare 33,34,34,35,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45, 2348d5d45fbSJean Delvare 45,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,59,59,60, 2358d5d45fbSJean Delvare 61,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84, 2368d5d45fbSJean Delvare 85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110}; 2378d5d45fbSJean Delvare 2388d5d45fbSJean Delvare 2398d5d45fbSJean Delvare Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed 2408d5d45fbSJean Delvare an extra term for a good fit to these inverse data!) and then 2418d5d45fbSJean Delvare solving for each temp value from -50 to 110 (the useable range for 2428d5d45fbSJean Delvare this chip). Here's the fit: 2438d5d45fbSJean Delvare viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 2448d5d45fbSJean Delvare - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) 2458d5d45fbSJean Delvare Note that n=161: */ 2468d5d45fbSJean Delvare static const u8 viaLUT[] = 2478d5d45fbSJean Delvare { 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, 2488d5d45fbSJean Delvare 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, 2498d5d45fbSJean Delvare 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, 2508d5d45fbSJean Delvare 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, 2518d5d45fbSJean Delvare 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, 2528d5d45fbSJean Delvare 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, 2538d5d45fbSJean Delvare 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 2548d5d45fbSJean Delvare 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, 2558d5d45fbSJean Delvare 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, 2568d5d45fbSJean Delvare 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, 2578d5d45fbSJean Delvare 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, 2588d5d45fbSJean Delvare 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 2598d5d45fbSJean Delvare 239, 240 2608d5d45fbSJean Delvare }; 2618d5d45fbSJean Delvare 2628d5d45fbSJean Delvare /* Converting temps to (8-bit) hyst and over registers 2638d5d45fbSJean Delvare No interpolation here. 2648d5d45fbSJean Delvare The +50 is because the temps start at -50 */ 2658d5d45fbSJean Delvare static inline u8 TEMP_TO_REG(long val) 2668d5d45fbSJean Delvare { 2678d5d45fbSJean Delvare return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 : 2688d5d45fbSJean Delvare (val < 0 ? val - 500 : val + 500) / 1000 + 50]; 2698d5d45fbSJean Delvare } 2708d5d45fbSJean Delvare 2718d5d45fbSJean Delvare /* for 8-bit temperature hyst and over registers */ 272088341bdSJean Delvare #define TEMP_FROM_REG(val) ((long)tempLUT[val] * 100) 2738d5d45fbSJean Delvare 2748d5d45fbSJean Delvare /* for 10-bit temperature readings */ 2758d5d45fbSJean Delvare static inline long TEMP_FROM_REG10(u16 val) 2768d5d45fbSJean Delvare { 2778d5d45fbSJean Delvare u16 eightBits = val >> 2; 2788d5d45fbSJean Delvare u16 twoBits = val & 3; 2798d5d45fbSJean Delvare 2808d5d45fbSJean Delvare /* no interpolation for these */ 2818d5d45fbSJean Delvare if (twoBits == 0 || eightBits == 255) 2828d5d45fbSJean Delvare return TEMP_FROM_REG(eightBits); 2838d5d45fbSJean Delvare 2848d5d45fbSJean Delvare /* do some linear interpolation */ 2858d5d45fbSJean Delvare return (tempLUT[eightBits] * (4 - twoBits) + 2868d5d45fbSJean Delvare tempLUT[eightBits + 1] * twoBits) * 25; 2878d5d45fbSJean Delvare } 2888d5d45fbSJean Delvare 2898d5d45fbSJean Delvare #define DIV_FROM_REG(val) (1 << (val)) 2908d5d45fbSJean Delvare #define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) 2918d5d45fbSJean Delvare 292ed6bafbfSJean Delvare /* For each registered chip, we need to keep some data in memory. 293ed6bafbfSJean Delvare The structure is dynamically allocated. */ 2948d5d45fbSJean Delvare struct via686a_data { 2952ec342e6SJean Delvare unsigned short addr; 2962ec342e6SJean Delvare const char *name; 2971beeffe4STony Jones struct device *hwmon_dev; 2989a61bf63SIngo Molnar struct mutex update_lock; 2998d5d45fbSJean Delvare char valid; /* !=0 if following fields are valid */ 3008d5d45fbSJean Delvare unsigned long last_updated; /* In jiffies */ 3018d5d45fbSJean Delvare 3028d5d45fbSJean Delvare u8 in[5]; /* Register value */ 3038d5d45fbSJean Delvare u8 in_max[5]; /* Register value */ 3048d5d45fbSJean Delvare u8 in_min[5]; /* Register value */ 3058d5d45fbSJean Delvare u8 fan[2]; /* Register value */ 3068d5d45fbSJean Delvare u8 fan_min[2]; /* Register value */ 3078d5d45fbSJean Delvare u16 temp[3]; /* Register value 10 bit */ 3088d5d45fbSJean Delvare u8 temp_over[3]; /* Register value */ 3098d5d45fbSJean Delvare u8 temp_hyst[3]; /* Register value */ 3108d5d45fbSJean Delvare u8 fan_div[2]; /* Register encoding, shifted right */ 3118d5d45fbSJean Delvare u16 alarms; /* Register encoding, combined */ 3128d5d45fbSJean Delvare }; 3138d5d45fbSJean Delvare 3148d5d45fbSJean Delvare static struct pci_dev *s_bridge; /* pointer to the (only) via686a */ 3158d5d45fbSJean Delvare 3162ec342e6SJean Delvare static int via686a_probe(struct platform_device *pdev); 317d0546128SJean Delvare static int __devexit via686a_remove(struct platform_device *pdev); 3188d5d45fbSJean Delvare 3192ec342e6SJean Delvare static inline int via686a_read_value(struct via686a_data *data, u8 reg) 3208d5d45fbSJean Delvare { 3212ec342e6SJean Delvare return inb_p(data->addr + reg); 3228d5d45fbSJean Delvare } 3238d5d45fbSJean Delvare 3242ec342e6SJean Delvare static inline void via686a_write_value(struct via686a_data *data, u8 reg, 3258d5d45fbSJean Delvare u8 value) 3268d5d45fbSJean Delvare { 3272ec342e6SJean Delvare outb_p(value, data->addr + reg); 3288d5d45fbSJean Delvare } 3298d5d45fbSJean Delvare 3308d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev); 3312ec342e6SJean Delvare static void via686a_init_device(struct via686a_data *data); 3328d5d45fbSJean Delvare 3338d5d45fbSJean Delvare /* following are the sysfs callback functions */ 3348d5d45fbSJean Delvare 3358d5d45fbSJean Delvare /* 7 voltage sensors */ 3361e71a5a2SJean Delvare static ssize_t show_in(struct device *dev, struct device_attribute *da, 3371e71a5a2SJean Delvare char *buf) { 3388d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 3391e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 3401e71a5a2SJean Delvare int nr = attr->index; 3418d5d45fbSJean Delvare return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr)); 3428d5d45fbSJean Delvare } 3438d5d45fbSJean Delvare 3441e71a5a2SJean Delvare static ssize_t show_in_min(struct device *dev, struct device_attribute *da, 3451e71a5a2SJean Delvare char *buf) { 3468d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 3471e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 3481e71a5a2SJean Delvare int nr = attr->index; 3498d5d45fbSJean Delvare return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr)); 3508d5d45fbSJean Delvare } 3518d5d45fbSJean Delvare 3521e71a5a2SJean Delvare static ssize_t show_in_max(struct device *dev, struct device_attribute *da, 3531e71a5a2SJean Delvare char *buf) { 3548d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 3551e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 3561e71a5a2SJean Delvare int nr = attr->index; 3578d5d45fbSJean Delvare return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr)); 3588d5d45fbSJean Delvare } 3598d5d45fbSJean Delvare 3601e71a5a2SJean Delvare static ssize_t set_in_min(struct device *dev, struct device_attribute *da, 3611e71a5a2SJean Delvare const char *buf, size_t count) { 3622ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 3631e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 3641e71a5a2SJean Delvare int nr = attr->index; 3658d5d45fbSJean Delvare unsigned long val = simple_strtoul(buf, NULL, 10); 3668d5d45fbSJean Delvare 3679a61bf63SIngo Molnar mutex_lock(&data->update_lock); 3688d5d45fbSJean Delvare data->in_min[nr] = IN_TO_REG(val, nr); 3692ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_IN_MIN(nr), 3708d5d45fbSJean Delvare data->in_min[nr]); 3719a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 3728d5d45fbSJean Delvare return count; 3738d5d45fbSJean Delvare } 3741e71a5a2SJean Delvare static ssize_t set_in_max(struct device *dev, struct device_attribute *da, 3751e71a5a2SJean Delvare const char *buf, size_t count) { 3762ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 3771e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 3781e71a5a2SJean Delvare int nr = attr->index; 3798d5d45fbSJean Delvare unsigned long val = simple_strtoul(buf, NULL, 10); 3808d5d45fbSJean Delvare 3819a61bf63SIngo Molnar mutex_lock(&data->update_lock); 3828d5d45fbSJean Delvare data->in_max[nr] = IN_TO_REG(val, nr); 3832ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_IN_MAX(nr), 3848d5d45fbSJean Delvare data->in_max[nr]); 3859a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 3868d5d45fbSJean Delvare return count; 3878d5d45fbSJean Delvare } 3888d5d45fbSJean Delvare #define show_in_offset(offset) \ 3891e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ 3901e71a5a2SJean Delvare show_in, NULL, offset); \ 3911e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ 3921e71a5a2SJean Delvare show_in_min, set_in_min, offset); \ 3931e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ 3941e71a5a2SJean Delvare show_in_max, set_in_max, offset); 3958d5d45fbSJean Delvare 3968d5d45fbSJean Delvare show_in_offset(0); 3978d5d45fbSJean Delvare show_in_offset(1); 3988d5d45fbSJean Delvare show_in_offset(2); 3998d5d45fbSJean Delvare show_in_offset(3); 4008d5d45fbSJean Delvare show_in_offset(4); 4018d5d45fbSJean Delvare 4028d5d45fbSJean Delvare /* 3 temperatures */ 4031e71a5a2SJean Delvare static ssize_t show_temp(struct device *dev, struct device_attribute *da, 4041e71a5a2SJean Delvare char *buf) { 4058d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 4061e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 4071e71a5a2SJean Delvare int nr = attr->index; 4088d5d45fbSJean Delvare return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr])); 4098d5d45fbSJean Delvare } 4101e71a5a2SJean Delvare static ssize_t show_temp_over(struct device *dev, struct device_attribute *da, 4111e71a5a2SJean Delvare char *buf) { 4128d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 4131e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 4141e71a5a2SJean Delvare int nr = attr->index; 4158d5d45fbSJean Delvare return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr])); 4168d5d45fbSJean Delvare } 4171e71a5a2SJean Delvare static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da, 4181e71a5a2SJean Delvare char *buf) { 4198d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 4201e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 4211e71a5a2SJean Delvare int nr = attr->index; 4228d5d45fbSJean Delvare return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr])); 4238d5d45fbSJean Delvare } 4241e71a5a2SJean Delvare static ssize_t set_temp_over(struct device *dev, struct device_attribute *da, 4251e71a5a2SJean Delvare const char *buf, size_t count) { 4262ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 4271e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 4281e71a5a2SJean Delvare int nr = attr->index; 4298d5d45fbSJean Delvare int val = simple_strtol(buf, NULL, 10); 4308d5d45fbSJean Delvare 4319a61bf63SIngo Molnar mutex_lock(&data->update_lock); 4328d5d45fbSJean Delvare data->temp_over[nr] = TEMP_TO_REG(val); 4332ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr], 4348d5d45fbSJean Delvare data->temp_over[nr]); 4359a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 4368d5d45fbSJean Delvare return count; 4378d5d45fbSJean Delvare } 4381e71a5a2SJean Delvare static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da, 4391e71a5a2SJean Delvare const char *buf, size_t count) { 4402ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 4411e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 4421e71a5a2SJean Delvare int nr = attr->index; 4438d5d45fbSJean Delvare int val = simple_strtol(buf, NULL, 10); 4448d5d45fbSJean Delvare 4459a61bf63SIngo Molnar mutex_lock(&data->update_lock); 4468d5d45fbSJean Delvare data->temp_hyst[nr] = TEMP_TO_REG(val); 4472ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr], 4488d5d45fbSJean Delvare data->temp_hyst[nr]); 4499a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 4508d5d45fbSJean Delvare return count; 4518d5d45fbSJean Delvare } 4528d5d45fbSJean Delvare #define show_temp_offset(offset) \ 4531e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ 4541e71a5a2SJean Delvare show_temp, NULL, offset - 1); \ 4551e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ 4561e71a5a2SJean Delvare show_temp_over, set_temp_over, offset - 1); \ 4571e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ 4581e71a5a2SJean Delvare show_temp_hyst, set_temp_hyst, offset - 1); 4598d5d45fbSJean Delvare 4608d5d45fbSJean Delvare show_temp_offset(1); 4618d5d45fbSJean Delvare show_temp_offset(2); 4628d5d45fbSJean Delvare show_temp_offset(3); 4638d5d45fbSJean Delvare 4648d5d45fbSJean Delvare /* 2 Fans */ 4651e71a5a2SJean Delvare static ssize_t show_fan(struct device *dev, struct device_attribute *da, 4661e71a5a2SJean Delvare char *buf) { 4678d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 4681e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 4691e71a5a2SJean Delvare int nr = attr->index; 4708d5d45fbSJean Delvare return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], 4718d5d45fbSJean Delvare DIV_FROM_REG(data->fan_div[nr])) ); 4728d5d45fbSJean Delvare } 4731e71a5a2SJean Delvare static ssize_t show_fan_min(struct device *dev, struct device_attribute *da, 4741e71a5a2SJean Delvare char *buf) { 4758d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 4761e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 4771e71a5a2SJean Delvare int nr = attr->index; 4788d5d45fbSJean Delvare return sprintf(buf, "%d\n", 4798d5d45fbSJean Delvare FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) ); 4808d5d45fbSJean Delvare } 4811e71a5a2SJean Delvare static ssize_t show_fan_div(struct device *dev, struct device_attribute *da, 4821e71a5a2SJean Delvare char *buf) { 4838d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 4841e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 4851e71a5a2SJean Delvare int nr = attr->index; 4868d5d45fbSJean Delvare return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); 4878d5d45fbSJean Delvare } 4881e71a5a2SJean Delvare static ssize_t set_fan_min(struct device *dev, struct device_attribute *da, 4891e71a5a2SJean Delvare const char *buf, size_t count) { 4902ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 4911e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 4921e71a5a2SJean Delvare int nr = attr->index; 4938d5d45fbSJean Delvare int val = simple_strtol(buf, NULL, 10); 4948d5d45fbSJean Delvare 4959a61bf63SIngo Molnar mutex_lock(&data->update_lock); 4968d5d45fbSJean Delvare data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); 4972ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]); 4989a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 4998d5d45fbSJean Delvare return count; 5008d5d45fbSJean Delvare } 5011e71a5a2SJean Delvare static ssize_t set_fan_div(struct device *dev, struct device_attribute *da, 5021e71a5a2SJean Delvare const char *buf, size_t count) { 5032ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 5041e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 5051e71a5a2SJean Delvare int nr = attr->index; 5068d5d45fbSJean Delvare int val = simple_strtol(buf, NULL, 10); 5078d5d45fbSJean Delvare int old; 5088d5d45fbSJean Delvare 5099a61bf63SIngo Molnar mutex_lock(&data->update_lock); 5102ec342e6SJean Delvare old = via686a_read_value(data, VIA686A_REG_FANDIV); 5118d5d45fbSJean Delvare data->fan_div[nr] = DIV_TO_REG(val); 5128d5d45fbSJean Delvare old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4); 5132ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_FANDIV, old); 5149a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 5158d5d45fbSJean Delvare return count; 5168d5d45fbSJean Delvare } 5178d5d45fbSJean Delvare 5188d5d45fbSJean Delvare #define show_fan_offset(offset) \ 5191e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ 5201e71a5a2SJean Delvare show_fan, NULL, offset - 1); \ 5211e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ 5221e71a5a2SJean Delvare show_fan_min, set_fan_min, offset - 1); \ 5231e71a5a2SJean Delvare static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ 5241e71a5a2SJean Delvare show_fan_div, set_fan_div, offset - 1); 5258d5d45fbSJean Delvare 5268d5d45fbSJean Delvare show_fan_offset(1); 5278d5d45fbSJean Delvare show_fan_offset(2); 5288d5d45fbSJean Delvare 5298d5d45fbSJean Delvare /* Alarms */ 5308d5d45fbSJean Delvare static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { 5318d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 5328d5d45fbSJean Delvare return sprintf(buf, "%u\n", data->alarms); 5338d5d45fbSJean Delvare } 5348d5d45fbSJean Delvare static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); 5358d5d45fbSJean Delvare 536*13ff05e9SJean Delvare static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, 537*13ff05e9SJean Delvare char *buf) 538*13ff05e9SJean Delvare { 539*13ff05e9SJean Delvare int bitnr = to_sensor_dev_attr(attr)->index; 540*13ff05e9SJean Delvare struct via686a_data *data = via686a_update_device(dev); 541*13ff05e9SJean Delvare return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); 542*13ff05e9SJean Delvare } 543*13ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); 544*13ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); 545*13ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); 546*13ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); 547*13ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); 548*13ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); 549*13ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 11); 550*13ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 15); 551*13ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); 552*13ff05e9SJean Delvare static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); 553*13ff05e9SJean Delvare 5542ec342e6SJean Delvare static ssize_t show_name(struct device *dev, struct device_attribute 5552ec342e6SJean Delvare *devattr, char *buf) 5562ec342e6SJean Delvare { 5572ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 5582ec342e6SJean Delvare return sprintf(buf, "%s\n", data->name); 5592ec342e6SJean Delvare } 5602ec342e6SJean Delvare static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); 5612ec342e6SJean Delvare 562a5ebe668SJean Delvare static struct attribute *via686a_attributes[] = { 5631e71a5a2SJean Delvare &sensor_dev_attr_in0_input.dev_attr.attr, 5641e71a5a2SJean Delvare &sensor_dev_attr_in1_input.dev_attr.attr, 5651e71a5a2SJean Delvare &sensor_dev_attr_in2_input.dev_attr.attr, 5661e71a5a2SJean Delvare &sensor_dev_attr_in3_input.dev_attr.attr, 5671e71a5a2SJean Delvare &sensor_dev_attr_in4_input.dev_attr.attr, 5681e71a5a2SJean Delvare &sensor_dev_attr_in0_min.dev_attr.attr, 5691e71a5a2SJean Delvare &sensor_dev_attr_in1_min.dev_attr.attr, 5701e71a5a2SJean Delvare &sensor_dev_attr_in2_min.dev_attr.attr, 5711e71a5a2SJean Delvare &sensor_dev_attr_in3_min.dev_attr.attr, 5721e71a5a2SJean Delvare &sensor_dev_attr_in4_min.dev_attr.attr, 5731e71a5a2SJean Delvare &sensor_dev_attr_in0_max.dev_attr.attr, 5741e71a5a2SJean Delvare &sensor_dev_attr_in1_max.dev_attr.attr, 5751e71a5a2SJean Delvare &sensor_dev_attr_in2_max.dev_attr.attr, 5761e71a5a2SJean Delvare &sensor_dev_attr_in3_max.dev_attr.attr, 5771e71a5a2SJean Delvare &sensor_dev_attr_in4_max.dev_attr.attr, 578*13ff05e9SJean Delvare &sensor_dev_attr_in0_alarm.dev_attr.attr, 579*13ff05e9SJean Delvare &sensor_dev_attr_in1_alarm.dev_attr.attr, 580*13ff05e9SJean Delvare &sensor_dev_attr_in2_alarm.dev_attr.attr, 581*13ff05e9SJean Delvare &sensor_dev_attr_in3_alarm.dev_attr.attr, 582*13ff05e9SJean Delvare &sensor_dev_attr_in4_alarm.dev_attr.attr, 583a5ebe668SJean Delvare 5841e71a5a2SJean Delvare &sensor_dev_attr_temp1_input.dev_attr.attr, 5851e71a5a2SJean Delvare &sensor_dev_attr_temp2_input.dev_attr.attr, 5861e71a5a2SJean Delvare &sensor_dev_attr_temp3_input.dev_attr.attr, 5871e71a5a2SJean Delvare &sensor_dev_attr_temp1_max.dev_attr.attr, 5881e71a5a2SJean Delvare &sensor_dev_attr_temp2_max.dev_attr.attr, 5891e71a5a2SJean Delvare &sensor_dev_attr_temp3_max.dev_attr.attr, 5901e71a5a2SJean Delvare &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, 5911e71a5a2SJean Delvare &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, 5921e71a5a2SJean Delvare &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, 593*13ff05e9SJean Delvare &sensor_dev_attr_temp1_alarm.dev_attr.attr, 594*13ff05e9SJean Delvare &sensor_dev_attr_temp2_alarm.dev_attr.attr, 595*13ff05e9SJean Delvare &sensor_dev_attr_temp3_alarm.dev_attr.attr, 596a5ebe668SJean Delvare 5971e71a5a2SJean Delvare &sensor_dev_attr_fan1_input.dev_attr.attr, 5981e71a5a2SJean Delvare &sensor_dev_attr_fan2_input.dev_attr.attr, 5991e71a5a2SJean Delvare &sensor_dev_attr_fan1_min.dev_attr.attr, 6001e71a5a2SJean Delvare &sensor_dev_attr_fan2_min.dev_attr.attr, 6011e71a5a2SJean Delvare &sensor_dev_attr_fan1_div.dev_attr.attr, 6021e71a5a2SJean Delvare &sensor_dev_attr_fan2_div.dev_attr.attr, 603*13ff05e9SJean Delvare &sensor_dev_attr_fan1_alarm.dev_attr.attr, 604*13ff05e9SJean Delvare &sensor_dev_attr_fan2_alarm.dev_attr.attr, 605a5ebe668SJean Delvare 606a5ebe668SJean Delvare &dev_attr_alarms.attr, 6072ec342e6SJean Delvare &dev_attr_name.attr, 608a5ebe668SJean Delvare NULL 609a5ebe668SJean Delvare }; 610a5ebe668SJean Delvare 611a5ebe668SJean Delvare static const struct attribute_group via686a_group = { 612a5ebe668SJean Delvare .attrs = via686a_attributes, 613a5ebe668SJean Delvare }; 614a5ebe668SJean Delvare 6152ec342e6SJean Delvare static struct platform_driver via686a_driver = { 616cdaf7934SLaurent Riffard .driver = { 61787218842SJean Delvare .owner = THIS_MODULE, 6188d5d45fbSJean Delvare .name = "via686a", 619cdaf7934SLaurent Riffard }, 6202ec342e6SJean Delvare .probe = via686a_probe, 6212ec342e6SJean Delvare .remove = __devexit_p(via686a_remove), 6228d5d45fbSJean Delvare }; 6238d5d45fbSJean Delvare 6248d5d45fbSJean Delvare 6258d5d45fbSJean Delvare /* This is called when the module is loaded */ 6262ec342e6SJean Delvare static int __devinit via686a_probe(struct platform_device *pdev) 6278d5d45fbSJean Delvare { 6288d5d45fbSJean Delvare struct via686a_data *data; 6292ec342e6SJean Delvare struct resource *res; 6302ec342e6SJean Delvare int err; 6318d5d45fbSJean Delvare 6328d5d45fbSJean Delvare /* Reserve the ISA region */ 6332ec342e6SJean Delvare res = platform_get_resource(pdev, IORESOURCE_IO, 0); 6342ec342e6SJean Delvare if (!request_region(res->start, VIA686A_EXTENT, 635cdaf7934SLaurent Riffard via686a_driver.driver.name)) { 6362ec342e6SJean Delvare dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n", 6372ec342e6SJean Delvare (unsigned long)res->start, (unsigned long)res->end); 6388d5d45fbSJean Delvare return -ENODEV; 6398d5d45fbSJean Delvare } 6408d5d45fbSJean Delvare 641ba9c2e8dSDeepak Saxena if (!(data = kzalloc(sizeof(struct via686a_data), GFP_KERNEL))) { 6428d5d45fbSJean Delvare err = -ENOMEM; 643943b0830SMark M. Hoffman goto exit_release; 6448d5d45fbSJean Delvare } 6458d5d45fbSJean Delvare 6462ec342e6SJean Delvare platform_set_drvdata(pdev, data); 6472ec342e6SJean Delvare data->addr = res->start; 6482ec342e6SJean Delvare data->name = "via686a"; 6499a61bf63SIngo Molnar mutex_init(&data->update_lock); 6508d5d45fbSJean Delvare 6518d5d45fbSJean Delvare /* Initialize the VIA686A chip */ 6522ec342e6SJean Delvare via686a_init_device(data); 6538d5d45fbSJean Delvare 6548d5d45fbSJean Delvare /* Register sysfs hooks */ 6552ec342e6SJean Delvare if ((err = sysfs_create_group(&pdev->dev.kobj, &via686a_group))) 6562ec342e6SJean Delvare goto exit_free; 657a5ebe668SJean Delvare 6581beeffe4STony Jones data->hwmon_dev = hwmon_device_register(&pdev->dev); 6591beeffe4STony Jones if (IS_ERR(data->hwmon_dev)) { 6601beeffe4STony Jones err = PTR_ERR(data->hwmon_dev); 661a5ebe668SJean Delvare goto exit_remove_files; 662943b0830SMark M. Hoffman } 663943b0830SMark M. Hoffman 6648d5d45fbSJean Delvare return 0; 6658d5d45fbSJean Delvare 666a5ebe668SJean Delvare exit_remove_files: 6672ec342e6SJean Delvare sysfs_remove_group(&pdev->dev.kobj, &via686a_group); 668943b0830SMark M. Hoffman exit_free: 6698d5d45fbSJean Delvare kfree(data); 670943b0830SMark M. Hoffman exit_release: 6712ec342e6SJean Delvare release_region(res->start, VIA686A_EXTENT); 6728d5d45fbSJean Delvare return err; 6738d5d45fbSJean Delvare } 6748d5d45fbSJean Delvare 6752ec342e6SJean Delvare static int __devexit via686a_remove(struct platform_device *pdev) 6768d5d45fbSJean Delvare { 6772ec342e6SJean Delvare struct via686a_data *data = platform_get_drvdata(pdev); 6788d5d45fbSJean Delvare 6791beeffe4STony Jones hwmon_device_unregister(data->hwmon_dev); 6802ec342e6SJean Delvare sysfs_remove_group(&pdev->dev.kobj, &via686a_group); 681943b0830SMark M. Hoffman 6822ec342e6SJean Delvare release_region(data->addr, VIA686A_EXTENT); 6832ec342e6SJean Delvare platform_set_drvdata(pdev, NULL); 684943b0830SMark M. Hoffman kfree(data); 6858d5d45fbSJean Delvare 6868d5d45fbSJean Delvare return 0; 6878d5d45fbSJean Delvare } 6888d5d45fbSJean Delvare 6892ec342e6SJean Delvare static void __devinit via686a_init_device(struct via686a_data *data) 6908d5d45fbSJean Delvare { 6918d5d45fbSJean Delvare u8 reg; 6928d5d45fbSJean Delvare 6938d5d45fbSJean Delvare /* Start monitoring */ 6942ec342e6SJean Delvare reg = via686a_read_value(data, VIA686A_REG_CONFIG); 6952ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F); 6968d5d45fbSJean Delvare 6978d5d45fbSJean Delvare /* Configure temp interrupt mode for continuous-interrupt operation */ 6982ec342e6SJean Delvare reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE); 6992ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_TEMP_MODE, 70058fe0809SJean Delvare (reg & ~VIA686A_TEMP_MODE_MASK) 70158fe0809SJean Delvare | VIA686A_TEMP_MODE_CONTINUOUS); 7028d5d45fbSJean Delvare } 7038d5d45fbSJean Delvare 7048d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev) 7058d5d45fbSJean Delvare { 7062ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 7078d5d45fbSJean Delvare int i; 7088d5d45fbSJean Delvare 7099a61bf63SIngo Molnar mutex_lock(&data->update_lock); 7108d5d45fbSJean Delvare 7118d5d45fbSJean Delvare if (time_after(jiffies, data->last_updated + HZ + HZ / 2) 7128d5d45fbSJean Delvare || !data->valid) { 7138d5d45fbSJean Delvare for (i = 0; i <= 4; i++) { 7148d5d45fbSJean Delvare data->in[i] = 7152ec342e6SJean Delvare via686a_read_value(data, VIA686A_REG_IN(i)); 7162ec342e6SJean Delvare data->in_min[i] = via686a_read_value(data, 7178d5d45fbSJean Delvare VIA686A_REG_IN_MIN 7188d5d45fbSJean Delvare (i)); 7198d5d45fbSJean Delvare data->in_max[i] = 7202ec342e6SJean Delvare via686a_read_value(data, VIA686A_REG_IN_MAX(i)); 7218d5d45fbSJean Delvare } 7228d5d45fbSJean Delvare for (i = 1; i <= 2; i++) { 7238d5d45fbSJean Delvare data->fan[i - 1] = 7242ec342e6SJean Delvare via686a_read_value(data, VIA686A_REG_FAN(i)); 7252ec342e6SJean Delvare data->fan_min[i - 1] = via686a_read_value(data, 7268d5d45fbSJean Delvare VIA686A_REG_FAN_MIN(i)); 7278d5d45fbSJean Delvare } 7288d5d45fbSJean Delvare for (i = 0; i <= 2; i++) { 7292ec342e6SJean Delvare data->temp[i] = via686a_read_value(data, 7308d5d45fbSJean Delvare VIA686A_REG_TEMP[i]) << 2; 7318d5d45fbSJean Delvare data->temp_over[i] = 7322ec342e6SJean Delvare via686a_read_value(data, 7338d5d45fbSJean Delvare VIA686A_REG_TEMP_OVER[i]); 7348d5d45fbSJean Delvare data->temp_hyst[i] = 7352ec342e6SJean Delvare via686a_read_value(data, 7368d5d45fbSJean Delvare VIA686A_REG_TEMP_HYST[i]); 7378d5d45fbSJean Delvare } 7388d5d45fbSJean Delvare /* add in lower 2 bits 7398d5d45fbSJean Delvare temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 7408d5d45fbSJean Delvare temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 7418d5d45fbSJean Delvare temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 7428d5d45fbSJean Delvare */ 7432ec342e6SJean Delvare data->temp[0] |= (via686a_read_value(data, 7448d5d45fbSJean Delvare VIA686A_REG_TEMP_LOW1) 7458d5d45fbSJean Delvare & 0xc0) >> 6; 7468d5d45fbSJean Delvare data->temp[1] |= 7472ec342e6SJean Delvare (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) & 7488d5d45fbSJean Delvare 0x30) >> 4; 7498d5d45fbSJean Delvare data->temp[2] |= 7502ec342e6SJean Delvare (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) & 7518d5d45fbSJean Delvare 0xc0) >> 6; 7528d5d45fbSJean Delvare 7532ec342e6SJean Delvare i = via686a_read_value(data, VIA686A_REG_FANDIV); 7548d5d45fbSJean Delvare data->fan_div[0] = (i >> 4) & 0x03; 7558d5d45fbSJean Delvare data->fan_div[1] = i >> 6; 7568d5d45fbSJean Delvare data->alarms = 7572ec342e6SJean Delvare via686a_read_value(data, 7588d5d45fbSJean Delvare VIA686A_REG_ALARM1) | 7592ec342e6SJean Delvare (via686a_read_value(data, VIA686A_REG_ALARM2) << 8); 7608d5d45fbSJean Delvare data->last_updated = jiffies; 7618d5d45fbSJean Delvare data->valid = 1; 7628d5d45fbSJean Delvare } 7638d5d45fbSJean Delvare 7649a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 7658d5d45fbSJean Delvare 7668d5d45fbSJean Delvare return data; 7678d5d45fbSJean Delvare } 7688d5d45fbSJean Delvare 7698d5d45fbSJean Delvare static struct pci_device_id via686a_pci_ids[] = { 7708d5d45fbSJean Delvare { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, 7718d5d45fbSJean Delvare { 0, } 7728d5d45fbSJean Delvare }; 7738d5d45fbSJean Delvare 7748d5d45fbSJean Delvare MODULE_DEVICE_TABLE(pci, via686a_pci_ids); 7758d5d45fbSJean Delvare 7762ec342e6SJean Delvare static int __devinit via686a_device_add(unsigned short address) 7772ec342e6SJean Delvare { 7782ec342e6SJean Delvare struct resource res = { 7792ec342e6SJean Delvare .start = address, 7802ec342e6SJean Delvare .end = address + VIA686A_EXTENT - 1, 7812ec342e6SJean Delvare .name = "via686a", 7822ec342e6SJean Delvare .flags = IORESOURCE_IO, 7832ec342e6SJean Delvare }; 7842ec342e6SJean Delvare int err; 7852ec342e6SJean Delvare 7862ec342e6SJean Delvare pdev = platform_device_alloc("via686a", address); 7872ec342e6SJean Delvare if (!pdev) { 7882ec342e6SJean Delvare err = -ENOMEM; 7892ec342e6SJean Delvare printk(KERN_ERR "via686a: Device allocation failed\n"); 7902ec342e6SJean Delvare goto exit; 7912ec342e6SJean Delvare } 7922ec342e6SJean Delvare 7932ec342e6SJean Delvare err = platform_device_add_resources(pdev, &res, 1); 7942ec342e6SJean Delvare if (err) { 7952ec342e6SJean Delvare printk(KERN_ERR "via686a: Device resource addition failed " 7962ec342e6SJean Delvare "(%d)\n", err); 7972ec342e6SJean Delvare goto exit_device_put; 7982ec342e6SJean Delvare } 7992ec342e6SJean Delvare 8002ec342e6SJean Delvare err = platform_device_add(pdev); 8012ec342e6SJean Delvare if (err) { 8022ec342e6SJean Delvare printk(KERN_ERR "via686a: Device addition failed (%d)\n", 8032ec342e6SJean Delvare err); 8042ec342e6SJean Delvare goto exit_device_put; 8052ec342e6SJean Delvare } 8062ec342e6SJean Delvare 8072ec342e6SJean Delvare return 0; 8082ec342e6SJean Delvare 8092ec342e6SJean Delvare exit_device_put: 8102ec342e6SJean Delvare platform_device_put(pdev); 8112ec342e6SJean Delvare exit: 8122ec342e6SJean Delvare return err; 8132ec342e6SJean Delvare } 8142ec342e6SJean Delvare 8158d5d45fbSJean Delvare static int __devinit via686a_pci_probe(struct pci_dev *dev, 8168d5d45fbSJean Delvare const struct pci_device_id *id) 8178d5d45fbSJean Delvare { 8182ec342e6SJean Delvare u16 address, val; 8198d5d45fbSJean Delvare 8202ec342e6SJean Delvare if (force_addr) { 8212ec342e6SJean Delvare address = force_addr & ~(VIA686A_EXTENT - 1); 8222ec342e6SJean Delvare dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address); 8232ec342e6SJean Delvare if (PCIBIOS_SUCCESSFUL != 8242ec342e6SJean Delvare pci_write_config_word(dev, VIA686A_BASE_REG, address | 1)) 8252ec342e6SJean Delvare return -ENODEV; 8262ec342e6SJean Delvare } 8278d5d45fbSJean Delvare if (PCIBIOS_SUCCESSFUL != 8288d5d45fbSJean Delvare pci_read_config_word(dev, VIA686A_BASE_REG, &val)) 8298d5d45fbSJean Delvare return -ENODEV; 8308d5d45fbSJean Delvare 8312d8672c5SJean Delvare address = val & ~(VIA686A_EXTENT - 1); 8322ec342e6SJean Delvare if (address == 0) { 8338d5d45fbSJean Delvare dev_err(&dev->dev, "base address not set - upgrade BIOS " 8348d5d45fbSJean Delvare "or use force_addr=0xaddr\n"); 8358d5d45fbSJean Delvare return -ENODEV; 8368d5d45fbSJean Delvare } 8378d5d45fbSJean Delvare 8382ec342e6SJean Delvare if (PCIBIOS_SUCCESSFUL != 8392ec342e6SJean Delvare pci_read_config_word(dev, VIA686A_ENABLE_REG, &val)) 8402ec342e6SJean Delvare return -ENODEV; 8412ec342e6SJean Delvare if (!(val & 0x0001)) { 8422ec342e6SJean Delvare if (!force_addr) { 8432ec342e6SJean Delvare dev_warn(&dev->dev, "Sensors disabled, enable " 8442ec342e6SJean Delvare "with force_addr=0x%x\n", address); 8452ec342e6SJean Delvare return -ENODEV; 8468d5d45fbSJean Delvare } 8478d5d45fbSJean Delvare 8482ec342e6SJean Delvare dev_warn(&dev->dev, "Enabling sensors\n"); 8492ec342e6SJean Delvare if (PCIBIOS_SUCCESSFUL != 8502ec342e6SJean Delvare pci_write_config_word(dev, VIA686A_ENABLE_REG, 8512ec342e6SJean Delvare val | 0x0001)) 8522ec342e6SJean Delvare return -ENODEV; 8532ec342e6SJean Delvare } 8542ec342e6SJean Delvare 8552ec342e6SJean Delvare if (platform_driver_register(&via686a_driver)) 8562ec342e6SJean Delvare goto exit; 8572ec342e6SJean Delvare 8582ec342e6SJean Delvare /* Sets global pdev as a side effect */ 8592ec342e6SJean Delvare if (via686a_device_add(address)) 8602ec342e6SJean Delvare goto exit_unregister; 8612ec342e6SJean Delvare 8628d5d45fbSJean Delvare /* Always return failure here. This is to allow other drivers to bind 8638d5d45fbSJean Delvare * to this pci device. We don't really want to have control over the 8648d5d45fbSJean Delvare * pci device, we only wanted to read as few register values from it. 8658d5d45fbSJean Delvare */ 8662ec342e6SJean Delvare s_bridge = pci_dev_get(dev); 8672ec342e6SJean Delvare return -ENODEV; 8682ec342e6SJean Delvare 8692ec342e6SJean Delvare exit_unregister: 8702ec342e6SJean Delvare platform_driver_unregister(&via686a_driver); 8712ec342e6SJean Delvare exit: 8728d5d45fbSJean Delvare return -ENODEV; 8738d5d45fbSJean Delvare } 8748d5d45fbSJean Delvare 8758d5d45fbSJean Delvare static struct pci_driver via686a_pci_driver = { 8768d5d45fbSJean Delvare .name = "via686a", 8778d5d45fbSJean Delvare .id_table = via686a_pci_ids, 8788d5d45fbSJean Delvare .probe = via686a_pci_probe, 8798d5d45fbSJean Delvare }; 8808d5d45fbSJean Delvare 8818d5d45fbSJean Delvare static int __init sm_via686a_init(void) 8828d5d45fbSJean Delvare { 8838d5d45fbSJean Delvare return pci_register_driver(&via686a_pci_driver); 8848d5d45fbSJean Delvare } 8858d5d45fbSJean Delvare 8868d5d45fbSJean Delvare static void __exit sm_via686a_exit(void) 8878d5d45fbSJean Delvare { 8888d5d45fbSJean Delvare pci_unregister_driver(&via686a_pci_driver); 8898d5d45fbSJean Delvare if (s_bridge != NULL) { 8902ec342e6SJean Delvare platform_device_unregister(pdev); 8912ec342e6SJean Delvare platform_driver_unregister(&via686a_driver); 8928d5d45fbSJean Delvare pci_dev_put(s_bridge); 8938d5d45fbSJean Delvare s_bridge = NULL; 8948d5d45fbSJean Delvare } 8958d5d45fbSJean Delvare } 8968d5d45fbSJean Delvare 89796de0e25SJan Engelhardt MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, " 8988d5d45fbSJean Delvare "Mark Studebaker <mdsxyz123@yahoo.com> " 8998d5d45fbSJean Delvare "and Bob Dougherty <bobd@stanford.edu>"); 9008d5d45fbSJean Delvare MODULE_DESCRIPTION("VIA 686A Sensor device"); 9018d5d45fbSJean Delvare MODULE_LICENSE("GPL"); 9028d5d45fbSJean Delvare 9038d5d45fbSJean Delvare module_init(sm_via686a_init); 9048d5d45fbSJean Delvare module_exit(sm_via686a_exit); 905