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