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>, 68d5d45fbSJean Delvare 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> 378d5d45fbSJean Delvare #include <linux/i2c.h> 38*fde09509SJean Delvare #include <linux/i2c-isa.h> 398d5d45fbSJean Delvare #include <linux/i2c-sensor.h> 40943b0830SMark M. Hoffman #include <linux/hwmon.h> 41943b0830SMark M. Hoffman #include <linux/err.h> 428d5d45fbSJean Delvare #include <linux/init.h> 438d5d45fbSJean Delvare #include <asm/io.h> 448d5d45fbSJean Delvare 458d5d45fbSJean Delvare 468d5d45fbSJean Delvare /* If force_addr is set to anything different from 0, we forcibly enable 478d5d45fbSJean Delvare the device at the given address. */ 488d5d45fbSJean Delvare static unsigned short force_addr = 0; 498d5d45fbSJean Delvare module_param(force_addr, ushort, 0); 508d5d45fbSJean Delvare MODULE_PARM_DESC(force_addr, 518d5d45fbSJean Delvare "Initialize the base address of the sensors"); 528d5d45fbSJean Delvare 538d5d45fbSJean Delvare /* Addresses to scan. 548d5d45fbSJean Delvare Note that we can't determine the ISA address until we have initialized 558d5d45fbSJean Delvare our module */ 568d5d45fbSJean Delvare static unsigned short normal_i2c[] = { I2C_CLIENT_END }; 578d5d45fbSJean Delvare static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; 588d5d45fbSJean Delvare 598d5d45fbSJean Delvare /* Insmod parameters */ 608d5d45fbSJean Delvare SENSORS_INSMOD_1(via686a); 618d5d45fbSJean Delvare 628d5d45fbSJean Delvare /* 638d5d45fbSJean Delvare The Via 686a southbridge has a LM78-like chip integrated on the same IC. 648d5d45fbSJean Delvare This driver is a customized copy of lm78.c 658d5d45fbSJean Delvare */ 668d5d45fbSJean Delvare 678d5d45fbSJean Delvare /* Many VIA686A constants specified below */ 688d5d45fbSJean Delvare 698d5d45fbSJean Delvare /* Length of ISA address segment */ 708d5d45fbSJean Delvare #define VIA686A_EXTENT 0x80 718d5d45fbSJean Delvare #define VIA686A_BASE_REG 0x70 728d5d45fbSJean Delvare #define VIA686A_ENABLE_REG 0x74 738d5d45fbSJean Delvare 748d5d45fbSJean Delvare /* The VIA686A registers */ 758d5d45fbSJean Delvare /* ins numbered 0-4 */ 768d5d45fbSJean Delvare #define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) 778d5d45fbSJean Delvare #define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) 788d5d45fbSJean Delvare #define VIA686A_REG_IN(nr) (0x22 + (nr)) 798d5d45fbSJean Delvare 808d5d45fbSJean Delvare /* fans numbered 1-2 */ 818d5d45fbSJean Delvare #define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) 828d5d45fbSJean Delvare #define VIA686A_REG_FAN(nr) (0x28 + (nr)) 838d5d45fbSJean Delvare 848d5d45fbSJean Delvare /* temps numbered 1-3 */ 858d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP[] = { 0x20, 0x21, 0x1f }; 868d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_OVER[] = { 0x39, 0x3d, 0x1d }; 878d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e }; 888d5d45fbSJean Delvare /* bits 7-6 */ 898d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW1 0x4b 908d5d45fbSJean Delvare /* 2 = bits 5-4, 3 = bits 7-6 */ 918d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW23 0x49 928d5d45fbSJean Delvare 938d5d45fbSJean Delvare #define VIA686A_REG_ALARM1 0x41 948d5d45fbSJean Delvare #define VIA686A_REG_ALARM2 0x42 958d5d45fbSJean Delvare #define VIA686A_REG_FANDIV 0x47 968d5d45fbSJean Delvare #define VIA686A_REG_CONFIG 0x40 978d5d45fbSJean Delvare /* The following register sets temp interrupt mode (bits 1-0 for temp1, 988d5d45fbSJean Delvare 3-2 for temp2, 5-4 for temp3). Modes are: 998d5d45fbSJean Delvare 00 interrupt stays as long as value is out-of-range 1008d5d45fbSJean Delvare 01 interrupt is cleared once register is read (default) 1018d5d45fbSJean Delvare 10 comparator mode- like 00, but ignores hysteresis 1028d5d45fbSJean Delvare 11 same as 00 */ 1038d5d45fbSJean Delvare #define VIA686A_REG_TEMP_MODE 0x4b 1048d5d45fbSJean Delvare /* We'll just assume that you want to set all 3 simultaneously: */ 1058d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_MASK 0x3F 1068d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_CONTINUOUS 0x00 1078d5d45fbSJean Delvare 1088d5d45fbSJean Delvare /* Conversions. Limit checking is only done on the TO_REG 1098d5d45fbSJean Delvare variants. 1108d5d45fbSJean Delvare 1118d5d45fbSJean Delvare ********* VOLTAGE CONVERSIONS (Bob Dougherty) ******** 1128d5d45fbSJean Delvare From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): 1138d5d45fbSJean Delvare voltagefactor[0]=1.25/2628; (2628/1.25=2102.4) // Vccp 1148d5d45fbSJean Delvare voltagefactor[1]=1.25/2628; (2628/1.25=2102.4) // +2.5V 1158d5d45fbSJean Delvare voltagefactor[2]=1.67/2628; (2628/1.67=1573.7) // +3.3V 1168d5d45fbSJean Delvare voltagefactor[3]=2.6/2628; (2628/2.60=1010.8) // +5V 1178d5d45fbSJean Delvare voltagefactor[4]=6.3/2628; (2628/6.30=417.14) // +12V 1188d5d45fbSJean Delvare in[i]=(data[i+2]*25.0+133)*voltagefactor[i]; 1198d5d45fbSJean Delvare That is: 1208d5d45fbSJean Delvare volts = (25*regVal+133)*factor 1218d5d45fbSJean Delvare regVal = (volts/factor-133)/25 1228d5d45fbSJean Delvare (These conversions were contributed by Jonathan Teh Soon Yew 1238d5d45fbSJean Delvare <j.teh@iname.com>) */ 1248d5d45fbSJean Delvare static inline u8 IN_TO_REG(long val, int inNum) 1258d5d45fbSJean Delvare { 1268d5d45fbSJean Delvare /* To avoid floating point, we multiply constants by 10 (100 for +12V). 1278d5d45fbSJean Delvare Rounding is done (120500 is actually 133000 - 12500). 1288d5d45fbSJean Delvare Remember that val is expressed in 0.001V/bit, which is why we divide 1298d5d45fbSJean Delvare by an additional 10000 (100000 for +12V): 1000 for val and 10 (100) 1308d5d45fbSJean Delvare for the constants. */ 1318d5d45fbSJean Delvare if (inNum <= 1) 1328d5d45fbSJean Delvare return (u8) 1338d5d45fbSJean Delvare SENSORS_LIMIT((val * 21024 - 1205000) / 250000, 0, 255); 1348d5d45fbSJean Delvare else if (inNum == 2) 1358d5d45fbSJean Delvare return (u8) 1368d5d45fbSJean Delvare SENSORS_LIMIT((val * 15737 - 1205000) / 250000, 0, 255); 1378d5d45fbSJean Delvare else if (inNum == 3) 1388d5d45fbSJean Delvare return (u8) 1398d5d45fbSJean Delvare SENSORS_LIMIT((val * 10108 - 1205000) / 250000, 0, 255); 1408d5d45fbSJean Delvare else 1418d5d45fbSJean Delvare return (u8) 1428d5d45fbSJean Delvare SENSORS_LIMIT((val * 41714 - 12050000) / 2500000, 0, 255); 1438d5d45fbSJean Delvare } 1448d5d45fbSJean Delvare 1458d5d45fbSJean Delvare static inline long IN_FROM_REG(u8 val, int inNum) 1468d5d45fbSJean Delvare { 1478d5d45fbSJean Delvare /* To avoid floating point, we multiply constants by 10 (100 for +12V). 1488d5d45fbSJean Delvare We also multiply them by 1000 because we want 0.001V/bit for the 1498d5d45fbSJean Delvare output value. Rounding is done. */ 1508d5d45fbSJean Delvare if (inNum <= 1) 1518d5d45fbSJean Delvare return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024); 1528d5d45fbSJean Delvare else if (inNum == 2) 1538d5d45fbSJean Delvare return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737); 1548d5d45fbSJean Delvare else if (inNum == 3) 1558d5d45fbSJean Delvare return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108); 1568d5d45fbSJean Delvare else 1578d5d45fbSJean Delvare return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714); 1588d5d45fbSJean Delvare } 1598d5d45fbSJean Delvare 1608d5d45fbSJean Delvare /********* FAN RPM CONVERSIONS ********/ 1618d5d45fbSJean Delvare /* Higher register values = slower fans (the fan's strobe gates a counter). 1628d5d45fbSJean Delvare But this chip saturates back at 0, not at 255 like all the other chips. 1638d5d45fbSJean Delvare So, 0 means 0 RPM */ 1648d5d45fbSJean Delvare static inline u8 FAN_TO_REG(long rpm, int div) 1658d5d45fbSJean Delvare { 1668d5d45fbSJean Delvare if (rpm == 0) 1678d5d45fbSJean Delvare return 0; 1688d5d45fbSJean Delvare rpm = SENSORS_LIMIT(rpm, 1, 1000000); 1698d5d45fbSJean Delvare return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255); 1708d5d45fbSJean Delvare } 1718d5d45fbSJean Delvare 1728d5d45fbSJean Delvare #define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div))) 1738d5d45fbSJean Delvare 1748d5d45fbSJean Delvare /******** TEMP CONVERSIONS (Bob Dougherty) *********/ 1758d5d45fbSJean Delvare /* linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew) 1768d5d45fbSJean Delvare if(temp<169) 1778d5d45fbSJean Delvare return double(temp)*0.427-32.08; 1788d5d45fbSJean Delvare else if(temp>=169 && temp<=202) 1798d5d45fbSJean Delvare return double(temp)*0.582-58.16; 1808d5d45fbSJean Delvare else 1818d5d45fbSJean Delvare return double(temp)*0.924-127.33; 1828d5d45fbSJean Delvare 1838d5d45fbSJean Delvare A fifth-order polynomial fits the unofficial data (provided by Alex van 1848d5d45fbSJean Delvare Kaam <darkside@chello.nl>) a bit better. It also give more reasonable 1858d5d45fbSJean Delvare numbers on my machine (ie. they agree with what my BIOS tells me). 1868d5d45fbSJean Delvare Here's the fifth-order fit to the 8-bit data: 1878d5d45fbSJean Delvare temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - 1888d5d45fbSJean Delvare 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. 1898d5d45fbSJean Delvare 1908d5d45fbSJean Delvare (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for 1918d5d45fbSJean Delvare finding my typos in this formula!) 1928d5d45fbSJean Delvare 1938d5d45fbSJean Delvare Alas, none of the elegant function-fit solutions will work because we 1948d5d45fbSJean Delvare aren't allowed to use floating point in the kernel and doing it with 1958d5d45fbSJean Delvare integers doesn't provide enough precision. So we'll do boring old 1968d5d45fbSJean Delvare look-up table stuff. The unofficial data (see below) have effectively 1978d5d45fbSJean Delvare 7-bit resolution (they are rounded to the nearest degree). I'm assuming 1988d5d45fbSJean Delvare that the transfer function of the device is monotonic and smooth, so a 1998d5d45fbSJean Delvare smooth function fit to the data will allow us to get better precision. 2008d5d45fbSJean Delvare I used the 5th-order poly fit described above and solved for 2018d5d45fbSJean Delvare VIA register values 0-255. I *10 before rounding, so we get tenth-degree 2028d5d45fbSJean Delvare precision. (I could have done all 1024 values for our 10-bit readings, 2038d5d45fbSJean Delvare but the function is very linear in the useful range (0-80 deg C), so 2048d5d45fbSJean Delvare we'll just use linear interpolation for 10-bit readings.) So, tempLUT 2058d5d45fbSJean Delvare is the temp at via register values 0-255: */ 2068d5d45fbSJean Delvare static const long tempLUT[] = 2078d5d45fbSJean Delvare { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, 2088d5d45fbSJean Delvare -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, 2098d5d45fbSJean Delvare -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, 2108d5d45fbSJean Delvare -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, 2118d5d45fbSJean Delvare -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, 2128d5d45fbSJean Delvare -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, 2138d5d45fbSJean Delvare -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, 2148d5d45fbSJean Delvare 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, 2158d5d45fbSJean Delvare 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, 2168d5d45fbSJean Delvare 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, 2178d5d45fbSJean Delvare 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, 2188d5d45fbSJean Delvare 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, 2198d5d45fbSJean Delvare 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, 2208d5d45fbSJean Delvare 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, 2218d5d45fbSJean Delvare 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, 2228d5d45fbSJean Delvare 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, 2238d5d45fbSJean Delvare 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, 2248d5d45fbSJean Delvare 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, 2258d5d45fbSJean Delvare 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, 2268d5d45fbSJean Delvare 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, 2278d5d45fbSJean Delvare 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, 2288d5d45fbSJean Delvare 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 2298d5d45fbSJean Delvare }; 2308d5d45fbSJean Delvare 2318d5d45fbSJean Delvare /* the original LUT values from Alex van Kaam <darkside@chello.nl> 2328d5d45fbSJean Delvare (for via register values 12-240): 2338d5d45fbSJean Delvare {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, 2348d5d45fbSJean Delvare -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, 2358d5d45fbSJean Delvare -15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3, 2368d5d45fbSJean 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, 2378d5d45fbSJean 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, 2388d5d45fbSJean 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, 2398d5d45fbSJean 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, 2408d5d45fbSJean 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, 2418d5d45fbSJean 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, 2428d5d45fbSJean Delvare 85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110}; 2438d5d45fbSJean Delvare 2448d5d45fbSJean Delvare 2458d5d45fbSJean Delvare Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed 2468d5d45fbSJean Delvare an extra term for a good fit to these inverse data!) and then 2478d5d45fbSJean Delvare solving for each temp value from -50 to 110 (the useable range for 2488d5d45fbSJean Delvare this chip). Here's the fit: 2498d5d45fbSJean Delvare viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 2508d5d45fbSJean Delvare - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) 2518d5d45fbSJean Delvare Note that n=161: */ 2528d5d45fbSJean Delvare static const u8 viaLUT[] = 2538d5d45fbSJean Delvare { 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, 2548d5d45fbSJean Delvare 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, 2558d5d45fbSJean Delvare 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, 2568d5d45fbSJean Delvare 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, 2578d5d45fbSJean Delvare 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, 2588d5d45fbSJean Delvare 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, 2598d5d45fbSJean Delvare 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 2608d5d45fbSJean Delvare 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, 2618d5d45fbSJean Delvare 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, 2628d5d45fbSJean Delvare 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, 2638d5d45fbSJean Delvare 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, 2648d5d45fbSJean Delvare 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 2658d5d45fbSJean Delvare 239, 240 2668d5d45fbSJean Delvare }; 2678d5d45fbSJean Delvare 2688d5d45fbSJean Delvare /* Converting temps to (8-bit) hyst and over registers 2698d5d45fbSJean Delvare No interpolation here. 2708d5d45fbSJean Delvare The +50 is because the temps start at -50 */ 2718d5d45fbSJean Delvare static inline u8 TEMP_TO_REG(long val) 2728d5d45fbSJean Delvare { 2738d5d45fbSJean Delvare return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 : 2748d5d45fbSJean Delvare (val < 0 ? val - 500 : val + 500) / 1000 + 50]; 2758d5d45fbSJean Delvare } 2768d5d45fbSJean Delvare 2778d5d45fbSJean Delvare /* for 8-bit temperature hyst and over registers */ 2788d5d45fbSJean Delvare #define TEMP_FROM_REG(val) (tempLUT[(val)] * 100) 2798d5d45fbSJean Delvare 2808d5d45fbSJean Delvare /* for 10-bit temperature readings */ 2818d5d45fbSJean Delvare static inline long TEMP_FROM_REG10(u16 val) 2828d5d45fbSJean Delvare { 2838d5d45fbSJean Delvare u16 eightBits = val >> 2; 2848d5d45fbSJean Delvare u16 twoBits = val & 3; 2858d5d45fbSJean Delvare 2868d5d45fbSJean Delvare /* no interpolation for these */ 2878d5d45fbSJean Delvare if (twoBits == 0 || eightBits == 255) 2888d5d45fbSJean Delvare return TEMP_FROM_REG(eightBits); 2898d5d45fbSJean Delvare 2908d5d45fbSJean Delvare /* do some linear interpolation */ 2918d5d45fbSJean Delvare return (tempLUT[eightBits] * (4 - twoBits) + 2928d5d45fbSJean Delvare tempLUT[eightBits + 1] * twoBits) * 25; 2938d5d45fbSJean Delvare } 2948d5d45fbSJean Delvare 2958d5d45fbSJean Delvare #define DIV_FROM_REG(val) (1 << (val)) 2968d5d45fbSJean Delvare #define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) 2978d5d45fbSJean Delvare 2988d5d45fbSJean Delvare /* For the VIA686A, we need to keep some data in memory. 2998d5d45fbSJean Delvare The structure is dynamically allocated, at the same time when a new 3008d5d45fbSJean Delvare via686a client is allocated. */ 3018d5d45fbSJean Delvare struct via686a_data { 3028d5d45fbSJean Delvare struct i2c_client client; 303943b0830SMark M. Hoffman struct class_device *class_dev; 3048d5d45fbSJean Delvare struct semaphore update_lock; 3058d5d45fbSJean Delvare char valid; /* !=0 if following fields are valid */ 3068d5d45fbSJean Delvare unsigned long last_updated; /* In jiffies */ 3078d5d45fbSJean Delvare 3088d5d45fbSJean Delvare u8 in[5]; /* Register value */ 3098d5d45fbSJean Delvare u8 in_max[5]; /* Register value */ 3108d5d45fbSJean Delvare u8 in_min[5]; /* Register value */ 3118d5d45fbSJean Delvare u8 fan[2]; /* Register value */ 3128d5d45fbSJean Delvare u8 fan_min[2]; /* Register value */ 3138d5d45fbSJean Delvare u16 temp[3]; /* Register value 10 bit */ 3148d5d45fbSJean Delvare u8 temp_over[3]; /* Register value */ 3158d5d45fbSJean Delvare u8 temp_hyst[3]; /* Register value */ 3168d5d45fbSJean Delvare u8 fan_div[2]; /* Register encoding, shifted right */ 3178d5d45fbSJean Delvare u16 alarms; /* Register encoding, combined */ 3188d5d45fbSJean Delvare }; 3198d5d45fbSJean Delvare 3208d5d45fbSJean Delvare static struct pci_dev *s_bridge; /* pointer to the (only) via686a */ 3218d5d45fbSJean Delvare 3228d5d45fbSJean Delvare static int via686a_attach_adapter(struct i2c_adapter *adapter); 3238d5d45fbSJean Delvare static int via686a_detect(struct i2c_adapter *adapter, int address, int kind); 3248d5d45fbSJean Delvare static int via686a_detach_client(struct i2c_client *client); 3258d5d45fbSJean Delvare 3268d5d45fbSJean Delvare static inline int via686a_read_value(struct i2c_client *client, u8 reg) 3278d5d45fbSJean Delvare { 3288d5d45fbSJean Delvare return (inb_p(client->addr + reg)); 3298d5d45fbSJean Delvare } 3308d5d45fbSJean Delvare 3318d5d45fbSJean Delvare static inline void via686a_write_value(struct i2c_client *client, u8 reg, 3328d5d45fbSJean Delvare u8 value) 3338d5d45fbSJean Delvare { 3348d5d45fbSJean Delvare outb_p(value, client->addr + reg); 3358d5d45fbSJean Delvare } 3368d5d45fbSJean Delvare 3378d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev); 3388d5d45fbSJean Delvare static void via686a_init_client(struct i2c_client *client); 3398d5d45fbSJean Delvare 3408d5d45fbSJean Delvare /* following are the sysfs callback functions */ 3418d5d45fbSJean Delvare 3428d5d45fbSJean Delvare /* 7 voltage sensors */ 3438d5d45fbSJean Delvare static ssize_t show_in(struct device *dev, char *buf, int nr) { 3448d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 3458d5d45fbSJean Delvare return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr)); 3468d5d45fbSJean Delvare } 3478d5d45fbSJean Delvare 3488d5d45fbSJean Delvare static ssize_t show_in_min(struct device *dev, char *buf, int nr) { 3498d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 3508d5d45fbSJean Delvare return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr)); 3518d5d45fbSJean Delvare } 3528d5d45fbSJean Delvare 3538d5d45fbSJean Delvare static ssize_t show_in_max(struct device *dev, char *buf, int nr) { 3548d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 3558d5d45fbSJean Delvare return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr)); 3568d5d45fbSJean Delvare } 3578d5d45fbSJean Delvare 3588d5d45fbSJean Delvare static ssize_t set_in_min(struct device *dev, const char *buf, 3598d5d45fbSJean Delvare size_t count, int nr) { 3608d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 3618d5d45fbSJean Delvare struct via686a_data *data = i2c_get_clientdata(client); 3628d5d45fbSJean Delvare unsigned long val = simple_strtoul(buf, NULL, 10); 3638d5d45fbSJean Delvare 3648d5d45fbSJean Delvare down(&data->update_lock); 3658d5d45fbSJean Delvare data->in_min[nr] = IN_TO_REG(val, nr); 3668d5d45fbSJean Delvare via686a_write_value(client, VIA686A_REG_IN_MIN(nr), 3678d5d45fbSJean Delvare data->in_min[nr]); 3688d5d45fbSJean Delvare up(&data->update_lock); 3698d5d45fbSJean Delvare return count; 3708d5d45fbSJean Delvare } 3718d5d45fbSJean Delvare static ssize_t set_in_max(struct device *dev, const char *buf, 3728d5d45fbSJean Delvare size_t count, int nr) { 3738d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 3748d5d45fbSJean Delvare struct via686a_data *data = i2c_get_clientdata(client); 3758d5d45fbSJean Delvare unsigned long val = simple_strtoul(buf, NULL, 10); 3768d5d45fbSJean Delvare 3778d5d45fbSJean Delvare down(&data->update_lock); 3788d5d45fbSJean Delvare data->in_max[nr] = IN_TO_REG(val, nr); 3798d5d45fbSJean Delvare via686a_write_value(client, VIA686A_REG_IN_MAX(nr), 3808d5d45fbSJean Delvare data->in_max[nr]); 3818d5d45fbSJean Delvare up(&data->update_lock); 3828d5d45fbSJean Delvare return count; 3838d5d45fbSJean Delvare } 3848d5d45fbSJean Delvare #define show_in_offset(offset) \ 3858d5d45fbSJean Delvare static ssize_t \ 3868d5d45fbSJean Delvare show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 3878d5d45fbSJean Delvare { \ 3888d5d45fbSJean Delvare return show_in(dev, buf, offset); \ 3898d5d45fbSJean Delvare } \ 3908d5d45fbSJean Delvare static ssize_t \ 3918d5d45fbSJean Delvare show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ 3928d5d45fbSJean Delvare { \ 3938d5d45fbSJean Delvare return show_in_min(dev, buf, offset); \ 3948d5d45fbSJean Delvare } \ 3958d5d45fbSJean Delvare static ssize_t \ 3968d5d45fbSJean Delvare show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ 3978d5d45fbSJean Delvare { \ 3988d5d45fbSJean Delvare return show_in_max(dev, buf, offset); \ 3998d5d45fbSJean Delvare } \ 4008d5d45fbSJean Delvare static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ 4018d5d45fbSJean Delvare const char *buf, size_t count) \ 4028d5d45fbSJean Delvare { \ 4038d5d45fbSJean Delvare return set_in_min(dev, buf, count, offset); \ 4048d5d45fbSJean Delvare } \ 4058d5d45fbSJean Delvare static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ 4068d5d45fbSJean Delvare const char *buf, size_t count) \ 4078d5d45fbSJean Delvare { \ 4088d5d45fbSJean Delvare return set_in_max(dev, buf, count, offset); \ 4098d5d45fbSJean Delvare } \ 4108d5d45fbSJean Delvare static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);\ 4118d5d45fbSJean Delvare static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ 4128d5d45fbSJean Delvare show_in##offset##_min, set_in##offset##_min); \ 4138d5d45fbSJean Delvare static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ 4148d5d45fbSJean Delvare show_in##offset##_max, set_in##offset##_max); 4158d5d45fbSJean Delvare 4168d5d45fbSJean Delvare show_in_offset(0); 4178d5d45fbSJean Delvare show_in_offset(1); 4188d5d45fbSJean Delvare show_in_offset(2); 4198d5d45fbSJean Delvare show_in_offset(3); 4208d5d45fbSJean Delvare show_in_offset(4); 4218d5d45fbSJean Delvare 4228d5d45fbSJean Delvare /* 3 temperatures */ 4238d5d45fbSJean Delvare static ssize_t show_temp(struct device *dev, char *buf, int nr) { 4248d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 4258d5d45fbSJean Delvare return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr])); 4268d5d45fbSJean Delvare } 4278d5d45fbSJean Delvare static ssize_t show_temp_over(struct device *dev, char *buf, int nr) { 4288d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 4298d5d45fbSJean Delvare return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr])); 4308d5d45fbSJean Delvare } 4318d5d45fbSJean Delvare static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) { 4328d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 4338d5d45fbSJean Delvare return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr])); 4348d5d45fbSJean Delvare } 4358d5d45fbSJean Delvare static ssize_t set_temp_over(struct device *dev, const char *buf, 4368d5d45fbSJean Delvare size_t count, int nr) { 4378d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 4388d5d45fbSJean Delvare struct via686a_data *data = i2c_get_clientdata(client); 4398d5d45fbSJean Delvare int val = simple_strtol(buf, NULL, 10); 4408d5d45fbSJean Delvare 4418d5d45fbSJean Delvare down(&data->update_lock); 4428d5d45fbSJean Delvare data->temp_over[nr] = TEMP_TO_REG(val); 4438d5d45fbSJean Delvare via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr], 4448d5d45fbSJean Delvare data->temp_over[nr]); 4458d5d45fbSJean Delvare up(&data->update_lock); 4468d5d45fbSJean Delvare return count; 4478d5d45fbSJean Delvare } 4488d5d45fbSJean Delvare static ssize_t set_temp_hyst(struct device *dev, const char *buf, 4498d5d45fbSJean Delvare size_t count, int nr) { 4508d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 4518d5d45fbSJean Delvare struct via686a_data *data = i2c_get_clientdata(client); 4528d5d45fbSJean Delvare int val = simple_strtol(buf, NULL, 10); 4538d5d45fbSJean Delvare 4548d5d45fbSJean Delvare down(&data->update_lock); 4558d5d45fbSJean Delvare data->temp_hyst[nr] = TEMP_TO_REG(val); 4568d5d45fbSJean Delvare via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr], 4578d5d45fbSJean Delvare data->temp_hyst[nr]); 4588d5d45fbSJean Delvare up(&data->update_lock); 4598d5d45fbSJean Delvare return count; 4608d5d45fbSJean Delvare } 4618d5d45fbSJean Delvare #define show_temp_offset(offset) \ 4628d5d45fbSJean Delvare static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 4638d5d45fbSJean Delvare { \ 4648d5d45fbSJean Delvare return show_temp(dev, buf, offset - 1); \ 4658d5d45fbSJean Delvare } \ 4668d5d45fbSJean Delvare static ssize_t \ 4678d5d45fbSJean Delvare show_temp_##offset##_over (struct device *dev, struct device_attribute *attr, char *buf) \ 4688d5d45fbSJean Delvare { \ 4698d5d45fbSJean Delvare return show_temp_over(dev, buf, offset - 1); \ 4708d5d45fbSJean Delvare } \ 4718d5d45fbSJean Delvare static ssize_t \ 4728d5d45fbSJean Delvare show_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, char *buf) \ 4738d5d45fbSJean Delvare { \ 4748d5d45fbSJean Delvare return show_temp_hyst(dev, buf, offset - 1); \ 4758d5d45fbSJean Delvare } \ 4768d5d45fbSJean Delvare static ssize_t set_temp_##offset##_over (struct device *dev, struct device_attribute *attr, \ 4778d5d45fbSJean Delvare const char *buf, size_t count) \ 4788d5d45fbSJean Delvare { \ 4798d5d45fbSJean Delvare return set_temp_over(dev, buf, count, offset - 1); \ 4808d5d45fbSJean Delvare } \ 4818d5d45fbSJean Delvare static ssize_t set_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, \ 4828d5d45fbSJean Delvare const char *buf, size_t count) \ 4838d5d45fbSJean Delvare { \ 4848d5d45fbSJean Delvare return set_temp_hyst(dev, buf, count, offset - 1); \ 4858d5d45fbSJean Delvare } \ 4868d5d45fbSJean Delvare static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\ 4878d5d45fbSJean Delvare static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ 4888d5d45fbSJean Delvare show_temp_##offset##_over, set_temp_##offset##_over); \ 4898d5d45fbSJean Delvare static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ 4908d5d45fbSJean Delvare show_temp_##offset##_hyst, set_temp_##offset##_hyst); 4918d5d45fbSJean Delvare 4928d5d45fbSJean Delvare show_temp_offset(1); 4938d5d45fbSJean Delvare show_temp_offset(2); 4948d5d45fbSJean Delvare show_temp_offset(3); 4958d5d45fbSJean Delvare 4968d5d45fbSJean Delvare /* 2 Fans */ 4978d5d45fbSJean Delvare static ssize_t show_fan(struct device *dev, char *buf, int nr) { 4988d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 4998d5d45fbSJean Delvare return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], 5008d5d45fbSJean Delvare DIV_FROM_REG(data->fan_div[nr])) ); 5018d5d45fbSJean Delvare } 5028d5d45fbSJean Delvare static ssize_t show_fan_min(struct device *dev, char *buf, int nr) { 5038d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 5048d5d45fbSJean Delvare return sprintf(buf, "%d\n", 5058d5d45fbSJean Delvare FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) ); 5068d5d45fbSJean Delvare } 5078d5d45fbSJean Delvare static ssize_t show_fan_div(struct device *dev, char *buf, int nr) { 5088d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 5098d5d45fbSJean Delvare return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); 5108d5d45fbSJean Delvare } 5118d5d45fbSJean Delvare static ssize_t set_fan_min(struct device *dev, const char *buf, 5128d5d45fbSJean Delvare size_t count, int nr) { 5138d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 5148d5d45fbSJean Delvare struct via686a_data *data = i2c_get_clientdata(client); 5158d5d45fbSJean Delvare int val = simple_strtol(buf, NULL, 10); 5168d5d45fbSJean Delvare 5178d5d45fbSJean Delvare down(&data->update_lock); 5188d5d45fbSJean Delvare data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); 5198d5d45fbSJean Delvare via686a_write_value(client, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]); 5208d5d45fbSJean Delvare up(&data->update_lock); 5218d5d45fbSJean Delvare return count; 5228d5d45fbSJean Delvare } 5238d5d45fbSJean Delvare static ssize_t set_fan_div(struct device *dev, const char *buf, 5248d5d45fbSJean Delvare size_t count, int nr) { 5258d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 5268d5d45fbSJean Delvare struct via686a_data *data = i2c_get_clientdata(client); 5278d5d45fbSJean Delvare int val = simple_strtol(buf, NULL, 10); 5288d5d45fbSJean Delvare int old; 5298d5d45fbSJean Delvare 5308d5d45fbSJean Delvare down(&data->update_lock); 5318d5d45fbSJean Delvare old = via686a_read_value(client, VIA686A_REG_FANDIV); 5328d5d45fbSJean Delvare data->fan_div[nr] = DIV_TO_REG(val); 5338d5d45fbSJean Delvare old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4); 5348d5d45fbSJean Delvare via686a_write_value(client, VIA686A_REG_FANDIV, old); 5358d5d45fbSJean Delvare up(&data->update_lock); 5368d5d45fbSJean Delvare return count; 5378d5d45fbSJean Delvare } 5388d5d45fbSJean Delvare 5398d5d45fbSJean Delvare #define show_fan_offset(offset) \ 5408d5d45fbSJean Delvare static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 5418d5d45fbSJean Delvare { \ 5428d5d45fbSJean Delvare return show_fan(dev, buf, offset - 1); \ 5438d5d45fbSJean Delvare } \ 5448d5d45fbSJean Delvare static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ 5458d5d45fbSJean Delvare { \ 5468d5d45fbSJean Delvare return show_fan_min(dev, buf, offset - 1); \ 5478d5d45fbSJean Delvare } \ 5488d5d45fbSJean Delvare static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ 5498d5d45fbSJean Delvare { \ 5508d5d45fbSJean Delvare return show_fan_div(dev, buf, offset - 1); \ 5518d5d45fbSJean Delvare } \ 5528d5d45fbSJean Delvare static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ 5538d5d45fbSJean Delvare const char *buf, size_t count) \ 5548d5d45fbSJean Delvare { \ 5558d5d45fbSJean Delvare return set_fan_min(dev, buf, count, offset - 1); \ 5568d5d45fbSJean Delvare } \ 5578d5d45fbSJean Delvare static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ 5588d5d45fbSJean Delvare const char *buf, size_t count) \ 5598d5d45fbSJean Delvare { \ 5608d5d45fbSJean Delvare return set_fan_div(dev, buf, count, offset - 1); \ 5618d5d45fbSJean Delvare } \ 5628d5d45fbSJean Delvare static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ 5638d5d45fbSJean Delvare static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ 5648d5d45fbSJean Delvare show_fan_##offset##_min, set_fan_##offset##_min); \ 5658d5d45fbSJean Delvare static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ 5668d5d45fbSJean Delvare show_fan_##offset##_div, set_fan_##offset##_div); 5678d5d45fbSJean Delvare 5688d5d45fbSJean Delvare show_fan_offset(1); 5698d5d45fbSJean Delvare show_fan_offset(2); 5708d5d45fbSJean Delvare 5718d5d45fbSJean Delvare /* Alarms */ 5728d5d45fbSJean Delvare static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { 5738d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 5748d5d45fbSJean Delvare return sprintf(buf, "%u\n", data->alarms); 5758d5d45fbSJean Delvare } 5768d5d45fbSJean Delvare static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); 5778d5d45fbSJean Delvare 5788d5d45fbSJean Delvare /* The driver. I choose to use type i2c_driver, as at is identical to both 5798d5d45fbSJean Delvare smbus_driver and isa_driver, and clients could be of either kind */ 5808d5d45fbSJean Delvare static struct i2c_driver via686a_driver = { 5818d5d45fbSJean Delvare .owner = THIS_MODULE, 5828d5d45fbSJean Delvare .name = "via686a", 5838d5d45fbSJean Delvare .id = I2C_DRIVERID_VIA686A, 5848d5d45fbSJean Delvare .flags = I2C_DF_NOTIFY, 5858d5d45fbSJean Delvare .attach_adapter = via686a_attach_adapter, 5868d5d45fbSJean Delvare .detach_client = via686a_detach_client, 5878d5d45fbSJean Delvare }; 5888d5d45fbSJean Delvare 5898d5d45fbSJean Delvare 5908d5d45fbSJean Delvare /* This is called when the module is loaded */ 5918d5d45fbSJean Delvare static int via686a_attach_adapter(struct i2c_adapter *adapter) 5928d5d45fbSJean Delvare { 5938d5d45fbSJean Delvare if (!(adapter->class & I2C_CLASS_HWMON)) 5948d5d45fbSJean Delvare return 0; 5958d5d45fbSJean Delvare return i2c_detect(adapter, &addr_data, via686a_detect); 5968d5d45fbSJean Delvare } 5978d5d45fbSJean Delvare 5988d5d45fbSJean Delvare static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) 5998d5d45fbSJean Delvare { 6008d5d45fbSJean Delvare struct i2c_client *new_client; 6018d5d45fbSJean Delvare struct via686a_data *data; 6028d5d45fbSJean Delvare int err = 0; 6038d5d45fbSJean Delvare const char client_name[] = "via686a"; 6048d5d45fbSJean Delvare u16 val; 6058d5d45fbSJean Delvare 6068d5d45fbSJean Delvare /* Make sure we are probing the ISA bus!! */ 6078d5d45fbSJean Delvare if (!i2c_is_isa_adapter(adapter)) { 6088d5d45fbSJean Delvare dev_err(&adapter->dev, 6098d5d45fbSJean Delvare "via686a_detect called for an I2C bus adapter?!?\n"); 6108d5d45fbSJean Delvare return 0; 6118d5d45fbSJean Delvare } 6128d5d45fbSJean Delvare 6138d5d45fbSJean Delvare /* 8231 requires multiple of 256, we enforce that on 686 as well */ 6148d5d45fbSJean Delvare if (force_addr) 6158d5d45fbSJean Delvare address = force_addr & 0xFF00; 6168d5d45fbSJean Delvare 6178d5d45fbSJean Delvare if (force_addr) { 6188d5d45fbSJean Delvare dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", 6198d5d45fbSJean Delvare address); 6208d5d45fbSJean Delvare if (PCIBIOS_SUCCESSFUL != 6218d5d45fbSJean Delvare pci_write_config_word(s_bridge, VIA686A_BASE_REG, address)) 6228d5d45fbSJean Delvare return -ENODEV; 6238d5d45fbSJean Delvare } 6248d5d45fbSJean Delvare if (PCIBIOS_SUCCESSFUL != 6258d5d45fbSJean Delvare pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) 6268d5d45fbSJean Delvare return -ENODEV; 6278d5d45fbSJean Delvare if (!(val & 0x0001)) { 6288d5d45fbSJean Delvare dev_warn(&adapter->dev, "enabling sensors\n"); 6298d5d45fbSJean Delvare if (PCIBIOS_SUCCESSFUL != 6308d5d45fbSJean Delvare pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, 6318d5d45fbSJean Delvare val | 0x0001)) 6328d5d45fbSJean Delvare return -ENODEV; 6338d5d45fbSJean Delvare } 6348d5d45fbSJean Delvare 6358d5d45fbSJean Delvare /* Reserve the ISA region */ 6368d5d45fbSJean Delvare if (!request_region(address, VIA686A_EXTENT, via686a_driver.name)) { 6378d5d45fbSJean Delvare dev_err(&adapter->dev, "region 0x%x already in use!\n", 6388d5d45fbSJean Delvare address); 6398d5d45fbSJean Delvare return -ENODEV; 6408d5d45fbSJean Delvare } 6418d5d45fbSJean Delvare 6428d5d45fbSJean Delvare if (!(data = kmalloc(sizeof(struct via686a_data), GFP_KERNEL))) { 6438d5d45fbSJean Delvare err = -ENOMEM; 644943b0830SMark M. Hoffman goto exit_release; 6458d5d45fbSJean Delvare } 6468d5d45fbSJean Delvare memset(data, 0, sizeof(struct via686a_data)); 6478d5d45fbSJean Delvare 6488d5d45fbSJean Delvare new_client = &data->client; 6498d5d45fbSJean Delvare i2c_set_clientdata(new_client, data); 6508d5d45fbSJean Delvare new_client->addr = address; 6518d5d45fbSJean Delvare new_client->adapter = adapter; 6528d5d45fbSJean Delvare new_client->driver = &via686a_driver; 6538d5d45fbSJean Delvare new_client->flags = 0; 6548d5d45fbSJean Delvare 6558d5d45fbSJean Delvare /* Fill in the remaining client fields and put into the global list */ 6568d5d45fbSJean Delvare strlcpy(new_client->name, client_name, I2C_NAME_SIZE); 6578d5d45fbSJean Delvare 6588d5d45fbSJean Delvare data->valid = 0; 6598d5d45fbSJean Delvare init_MUTEX(&data->update_lock); 6608d5d45fbSJean Delvare /* Tell the I2C layer a new client has arrived */ 6618d5d45fbSJean Delvare if ((err = i2c_attach_client(new_client))) 662943b0830SMark M. Hoffman goto exit_free; 6638d5d45fbSJean Delvare 6648d5d45fbSJean Delvare /* Initialize the VIA686A chip */ 6658d5d45fbSJean Delvare via686a_init_client(new_client); 6668d5d45fbSJean Delvare 6678d5d45fbSJean Delvare /* Register sysfs hooks */ 668943b0830SMark M. Hoffman data->class_dev = hwmon_device_register(&new_client->dev); 669943b0830SMark M. Hoffman if (IS_ERR(data->class_dev)) { 670943b0830SMark M. Hoffman err = PTR_ERR(data->class_dev); 671943b0830SMark M. Hoffman goto exit_detach; 672943b0830SMark M. Hoffman } 673943b0830SMark M. Hoffman 6748d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_in0_input); 6758d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_in1_input); 6768d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_in2_input); 6778d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_in3_input); 6788d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_in4_input); 6798d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_in0_min); 6808d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_in1_min); 6818d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_in2_min); 6828d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_in3_min); 6838d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_in4_min); 6848d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_in0_max); 6858d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_in1_max); 6868d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_in2_max); 6878d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_in3_max); 6888d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_in4_max); 6898d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_temp1_input); 6908d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_temp2_input); 6918d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_temp3_input); 6928d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_temp1_max); 6938d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_temp2_max); 6948d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_temp3_max); 6958d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); 6968d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_temp2_max_hyst); 6978d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_temp3_max_hyst); 6988d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_fan1_input); 6998d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_fan2_input); 7008d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_fan1_min); 7018d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_fan2_min); 7028d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_fan1_div); 7038d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_fan2_div); 7048d5d45fbSJean Delvare device_create_file(&new_client->dev, &dev_attr_alarms); 7058d5d45fbSJean Delvare 7068d5d45fbSJean Delvare return 0; 7078d5d45fbSJean Delvare 708943b0830SMark M. Hoffman exit_detach: 709943b0830SMark M. Hoffman i2c_detach_client(new_client); 710943b0830SMark M. Hoffman exit_free: 7118d5d45fbSJean Delvare kfree(data); 712943b0830SMark M. Hoffman exit_release: 7138d5d45fbSJean Delvare release_region(address, VIA686A_EXTENT); 7148d5d45fbSJean Delvare return err; 7158d5d45fbSJean Delvare } 7168d5d45fbSJean Delvare 7178d5d45fbSJean Delvare static int via686a_detach_client(struct i2c_client *client) 7188d5d45fbSJean Delvare { 719943b0830SMark M. Hoffman struct via686a_data *data = i2c_get_clientdata(client); 7208d5d45fbSJean Delvare int err; 7218d5d45fbSJean Delvare 722943b0830SMark M. Hoffman hwmon_device_unregister(data->class_dev); 723943b0830SMark M. Hoffman 7248d5d45fbSJean Delvare if ((err = i2c_detach_client(client))) { 7258d5d45fbSJean Delvare dev_err(&client->dev, 7268d5d45fbSJean Delvare "Client deregistration failed, client not detached.\n"); 7278d5d45fbSJean Delvare return err; 7288d5d45fbSJean Delvare } 7298d5d45fbSJean Delvare 7308d5d45fbSJean Delvare release_region(client->addr, VIA686A_EXTENT); 731943b0830SMark M. Hoffman kfree(data); 7328d5d45fbSJean Delvare 7338d5d45fbSJean Delvare return 0; 7348d5d45fbSJean Delvare } 7358d5d45fbSJean Delvare 7368d5d45fbSJean Delvare /* Called when we have found a new VIA686A. Set limits, etc. */ 7378d5d45fbSJean Delvare static void via686a_init_client(struct i2c_client *client) 7388d5d45fbSJean Delvare { 7398d5d45fbSJean Delvare u8 reg; 7408d5d45fbSJean Delvare 7418d5d45fbSJean Delvare /* Start monitoring */ 7428d5d45fbSJean Delvare reg = via686a_read_value(client, VIA686A_REG_CONFIG); 7438d5d45fbSJean Delvare via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F); 7448d5d45fbSJean Delvare 7458d5d45fbSJean Delvare /* Configure temp interrupt mode for continuous-interrupt operation */ 7468d5d45fbSJean Delvare via686a_write_value(client, VIA686A_REG_TEMP_MODE, 7478d5d45fbSJean Delvare via686a_read_value(client, VIA686A_REG_TEMP_MODE) & 7488d5d45fbSJean Delvare !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS)); 7498d5d45fbSJean Delvare } 7508d5d45fbSJean Delvare 7518d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev) 7528d5d45fbSJean Delvare { 7538d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 7548d5d45fbSJean Delvare struct via686a_data *data = i2c_get_clientdata(client); 7558d5d45fbSJean Delvare int i; 7568d5d45fbSJean Delvare 7578d5d45fbSJean Delvare down(&data->update_lock); 7588d5d45fbSJean Delvare 7598d5d45fbSJean Delvare if (time_after(jiffies, data->last_updated + HZ + HZ / 2) 7608d5d45fbSJean Delvare || !data->valid) { 7618d5d45fbSJean Delvare for (i = 0; i <= 4; i++) { 7628d5d45fbSJean Delvare data->in[i] = 7638d5d45fbSJean Delvare via686a_read_value(client, VIA686A_REG_IN(i)); 7648d5d45fbSJean Delvare data->in_min[i] = via686a_read_value(client, 7658d5d45fbSJean Delvare VIA686A_REG_IN_MIN 7668d5d45fbSJean Delvare (i)); 7678d5d45fbSJean Delvare data->in_max[i] = 7688d5d45fbSJean Delvare via686a_read_value(client, VIA686A_REG_IN_MAX(i)); 7698d5d45fbSJean Delvare } 7708d5d45fbSJean Delvare for (i = 1; i <= 2; i++) { 7718d5d45fbSJean Delvare data->fan[i - 1] = 7728d5d45fbSJean Delvare via686a_read_value(client, VIA686A_REG_FAN(i)); 7738d5d45fbSJean Delvare data->fan_min[i - 1] = via686a_read_value(client, 7748d5d45fbSJean Delvare VIA686A_REG_FAN_MIN(i)); 7758d5d45fbSJean Delvare } 7768d5d45fbSJean Delvare for (i = 0; i <= 2; i++) { 7778d5d45fbSJean Delvare data->temp[i] = via686a_read_value(client, 7788d5d45fbSJean Delvare VIA686A_REG_TEMP[i]) << 2; 7798d5d45fbSJean Delvare data->temp_over[i] = 7808d5d45fbSJean Delvare via686a_read_value(client, 7818d5d45fbSJean Delvare VIA686A_REG_TEMP_OVER[i]); 7828d5d45fbSJean Delvare data->temp_hyst[i] = 7838d5d45fbSJean Delvare via686a_read_value(client, 7848d5d45fbSJean Delvare VIA686A_REG_TEMP_HYST[i]); 7858d5d45fbSJean Delvare } 7868d5d45fbSJean Delvare /* add in lower 2 bits 7878d5d45fbSJean Delvare temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 7888d5d45fbSJean Delvare temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 7898d5d45fbSJean Delvare temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 7908d5d45fbSJean Delvare */ 7918d5d45fbSJean Delvare data->temp[0] |= (via686a_read_value(client, 7928d5d45fbSJean Delvare VIA686A_REG_TEMP_LOW1) 7938d5d45fbSJean Delvare & 0xc0) >> 6; 7948d5d45fbSJean Delvare data->temp[1] |= 7958d5d45fbSJean Delvare (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & 7968d5d45fbSJean Delvare 0x30) >> 4; 7978d5d45fbSJean Delvare data->temp[2] |= 7988d5d45fbSJean Delvare (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & 7998d5d45fbSJean Delvare 0xc0) >> 6; 8008d5d45fbSJean Delvare 8018d5d45fbSJean Delvare i = via686a_read_value(client, VIA686A_REG_FANDIV); 8028d5d45fbSJean Delvare data->fan_div[0] = (i >> 4) & 0x03; 8038d5d45fbSJean Delvare data->fan_div[1] = i >> 6; 8048d5d45fbSJean Delvare data->alarms = 8058d5d45fbSJean Delvare via686a_read_value(client, 8068d5d45fbSJean Delvare VIA686A_REG_ALARM1) | 8078d5d45fbSJean Delvare (via686a_read_value(client, VIA686A_REG_ALARM2) << 8); 8088d5d45fbSJean Delvare data->last_updated = jiffies; 8098d5d45fbSJean Delvare data->valid = 1; 8108d5d45fbSJean Delvare } 8118d5d45fbSJean Delvare 8128d5d45fbSJean Delvare up(&data->update_lock); 8138d5d45fbSJean Delvare 8148d5d45fbSJean Delvare return data; 8158d5d45fbSJean Delvare } 8168d5d45fbSJean Delvare 8178d5d45fbSJean Delvare static struct pci_device_id via686a_pci_ids[] = { 8188d5d45fbSJean Delvare { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, 8198d5d45fbSJean Delvare { 0, } 8208d5d45fbSJean Delvare }; 8218d5d45fbSJean Delvare 8228d5d45fbSJean Delvare MODULE_DEVICE_TABLE(pci, via686a_pci_ids); 8238d5d45fbSJean Delvare 8248d5d45fbSJean Delvare static int __devinit via686a_pci_probe(struct pci_dev *dev, 8258d5d45fbSJean Delvare const struct pci_device_id *id) 8268d5d45fbSJean Delvare { 8278d5d45fbSJean Delvare u16 val; 8288d5d45fbSJean Delvare int addr = 0; 8298d5d45fbSJean Delvare 8308d5d45fbSJean Delvare if (PCIBIOS_SUCCESSFUL != 8318d5d45fbSJean Delvare pci_read_config_word(dev, VIA686A_BASE_REG, &val)) 8328d5d45fbSJean Delvare return -ENODEV; 8338d5d45fbSJean Delvare 8348d5d45fbSJean Delvare addr = val & ~(VIA686A_EXTENT - 1); 8358d5d45fbSJean Delvare if (addr == 0 && force_addr == 0) { 8368d5d45fbSJean Delvare dev_err(&dev->dev, "base address not set - upgrade BIOS " 8378d5d45fbSJean Delvare "or use force_addr=0xaddr\n"); 8388d5d45fbSJean Delvare return -ENODEV; 8398d5d45fbSJean Delvare } 8408d5d45fbSJean Delvare if (force_addr) 8418d5d45fbSJean Delvare addr = force_addr; /* so detect will get called */ 8428d5d45fbSJean Delvare 8438d5d45fbSJean Delvare if (!addr) { 8448d5d45fbSJean Delvare dev_err(&dev->dev, "No Via 686A sensors found.\n"); 8458d5d45fbSJean Delvare return -ENODEV; 8468d5d45fbSJean Delvare } 8478d5d45fbSJean Delvare normal_isa[0] = addr; 8488d5d45fbSJean Delvare 8498d5d45fbSJean Delvare s_bridge = pci_dev_get(dev); 850*fde09509SJean Delvare if (i2c_isa_add_driver(&via686a_driver)) { 8518d5d45fbSJean Delvare pci_dev_put(s_bridge); 8528d5d45fbSJean Delvare s_bridge = NULL; 8538d5d45fbSJean Delvare } 8548d5d45fbSJean Delvare 8558d5d45fbSJean Delvare /* Always return failure here. This is to allow other drivers to bind 8568d5d45fbSJean Delvare * to this pci device. We don't really want to have control over the 8578d5d45fbSJean Delvare * pci device, we only wanted to read as few register values from it. 8588d5d45fbSJean Delvare */ 8598d5d45fbSJean Delvare return -ENODEV; 8608d5d45fbSJean Delvare } 8618d5d45fbSJean Delvare 8628d5d45fbSJean Delvare static struct pci_driver via686a_pci_driver = { 8638d5d45fbSJean Delvare .name = "via686a", 8648d5d45fbSJean Delvare .id_table = via686a_pci_ids, 8658d5d45fbSJean Delvare .probe = via686a_pci_probe, 8668d5d45fbSJean Delvare }; 8678d5d45fbSJean Delvare 8688d5d45fbSJean Delvare static int __init sm_via686a_init(void) 8698d5d45fbSJean Delvare { 8708d5d45fbSJean Delvare return pci_register_driver(&via686a_pci_driver); 8718d5d45fbSJean Delvare } 8728d5d45fbSJean Delvare 8738d5d45fbSJean Delvare static void __exit sm_via686a_exit(void) 8748d5d45fbSJean Delvare { 8758d5d45fbSJean Delvare pci_unregister_driver(&via686a_pci_driver); 8768d5d45fbSJean Delvare if (s_bridge != NULL) { 877*fde09509SJean Delvare i2c_isa_del_driver(&via686a_driver); 8788d5d45fbSJean Delvare pci_dev_put(s_bridge); 8798d5d45fbSJean Delvare s_bridge = NULL; 8808d5d45fbSJean Delvare } 8818d5d45fbSJean Delvare } 8828d5d45fbSJean Delvare 8838d5d45fbSJean Delvare MODULE_AUTHOR("Ky�sti M�lkki <kmalkki@cc.hut.fi>, " 8848d5d45fbSJean Delvare "Mark Studebaker <mdsxyz123@yahoo.com> " 8858d5d45fbSJean Delvare "and Bob Dougherty <bobd@stanford.edu>"); 8868d5d45fbSJean Delvare MODULE_DESCRIPTION("VIA 686A Sensor device"); 8878d5d45fbSJean Delvare MODULE_LICENSE("GPL"); 8888d5d45fbSJean Delvare 8898d5d45fbSJean Delvare module_init(sm_via686a_init); 8908d5d45fbSJean Delvare module_exit(sm_via686a_exit); 891