1*74ba9207SThomas 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 379004ac81SGuenter Roeck /* 389004ac81SGuenter Roeck * If force_addr is set to anything different from 0, we forcibly enable 399004ac81SGuenter Roeck * the device at the given address. 409004ac81SGuenter Roeck */ 4102002963SJean Delvare static unsigned short force_addr; 428d5d45fbSJean Delvare module_param(force_addr, ushort, 0); 438d5d45fbSJean Delvare MODULE_PARM_DESC(force_addr, 448d5d45fbSJean Delvare "Initialize the base address of the sensors"); 458d5d45fbSJean Delvare 462ec342e6SJean Delvare static struct platform_device *pdev; 478d5d45fbSJean Delvare 488d5d45fbSJean Delvare /* 499004ac81SGuenter Roeck * The Via 686a southbridge has a LM78-like chip integrated on the same IC. 509004ac81SGuenter Roeck * This driver is a customized copy of lm78.c 518d5d45fbSJean Delvare */ 528d5d45fbSJean Delvare 538d5d45fbSJean Delvare /* Many VIA686A constants specified below */ 548d5d45fbSJean Delvare 558d5d45fbSJean Delvare /* Length of ISA address segment */ 568d5d45fbSJean Delvare #define VIA686A_EXTENT 0x80 578d5d45fbSJean Delvare #define VIA686A_BASE_REG 0x70 588d5d45fbSJean Delvare #define VIA686A_ENABLE_REG 0x74 598d5d45fbSJean Delvare 608d5d45fbSJean Delvare /* The VIA686A registers */ 618d5d45fbSJean Delvare /* ins numbered 0-4 */ 628d5d45fbSJean Delvare #define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) 638d5d45fbSJean Delvare #define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) 648d5d45fbSJean Delvare #define VIA686A_REG_IN(nr) (0x22 + (nr)) 658d5d45fbSJean Delvare 668d5d45fbSJean Delvare /* fans numbered 1-2 */ 678d5d45fbSJean Delvare #define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) 688d5d45fbSJean Delvare #define VIA686A_REG_FAN(nr) (0x28 + (nr)) 698d5d45fbSJean Delvare 708d5d45fbSJean Delvare /* temps numbered 1-3 */ 718d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP[] = { 0x20, 0x21, 0x1f }; 728d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_OVER[] = { 0x39, 0x3d, 0x1d }; 738d5d45fbSJean Delvare static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e }; 748d5d45fbSJean Delvare /* bits 7-6 */ 758d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW1 0x4b 768d5d45fbSJean Delvare /* 2 = bits 5-4, 3 = bits 7-6 */ 778d5d45fbSJean Delvare #define VIA686A_REG_TEMP_LOW23 0x49 788d5d45fbSJean Delvare 798d5d45fbSJean Delvare #define VIA686A_REG_ALARM1 0x41 808d5d45fbSJean Delvare #define VIA686A_REG_ALARM2 0x42 818d5d45fbSJean Delvare #define VIA686A_REG_FANDIV 0x47 828d5d45fbSJean Delvare #define VIA686A_REG_CONFIG 0x40 839004ac81SGuenter Roeck /* 849004ac81SGuenter Roeck * The following register sets temp interrupt mode (bits 1-0 for temp1, 859004ac81SGuenter Roeck * 3-2 for temp2, 5-4 for temp3). Modes are: 869004ac81SGuenter Roeck * 00 interrupt stays as long as value is out-of-range 879004ac81SGuenter Roeck * 01 interrupt is cleared once register is read (default) 889004ac81SGuenter Roeck * 10 comparator mode- like 00, but ignores hysteresis 899004ac81SGuenter Roeck * 11 same as 00 909004ac81SGuenter Roeck */ 918d5d45fbSJean Delvare #define VIA686A_REG_TEMP_MODE 0x4b 928d5d45fbSJean Delvare /* We'll just assume that you want to set all 3 simultaneously: */ 938d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_MASK 0x3F 948d5d45fbSJean Delvare #define VIA686A_TEMP_MODE_CONTINUOUS 0x00 958d5d45fbSJean Delvare 969004ac81SGuenter Roeck /* 979004ac81SGuenter Roeck * Conversions. Limit checking is only done on the TO_REG 989004ac81SGuenter Roeck * variants. 999004ac81SGuenter Roeck * 1009004ac81SGuenter Roeck ******** VOLTAGE CONVERSIONS (Bob Dougherty) ******** 1019004ac81SGuenter Roeck * From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): 1029004ac81SGuenter Roeck * voltagefactor[0]=1.25/2628; (2628/1.25=2102.4) // Vccp 1039004ac81SGuenter Roeck * voltagefactor[1]=1.25/2628; (2628/1.25=2102.4) // +2.5V 1049004ac81SGuenter Roeck * voltagefactor[2]=1.67/2628; (2628/1.67=1573.7) // +3.3V 1059004ac81SGuenter Roeck * voltagefactor[3]=2.6/2628; (2628/2.60=1010.8) // +5V 1069004ac81SGuenter Roeck * voltagefactor[4]=6.3/2628; (2628/6.30=417.14) // +12V 1079004ac81SGuenter Roeck * in[i]=(data[i+2]*25.0+133)*voltagefactor[i]; 1089004ac81SGuenter Roeck * That is: 1099004ac81SGuenter Roeck * volts = (25*regVal+133)*factor 1109004ac81SGuenter Roeck * regVal = (volts/factor-133)/25 1119004ac81SGuenter Roeck * (These conversions were contributed by Jonathan Teh Soon Yew 1129004ac81SGuenter Roeck * <j.teh@iname.com>) 1139004ac81SGuenter Roeck */ 114088ce2acSGuenter Roeck static inline u8 IN_TO_REG(long val, int in_num) 1158d5d45fbSJean Delvare { 1169004ac81SGuenter Roeck /* 1179004ac81SGuenter Roeck * To avoid floating point, we multiply constants by 10 (100 for +12V). 1189004ac81SGuenter Roeck * Rounding is done (120500 is actually 133000 - 12500). 1199004ac81SGuenter Roeck * Remember that val is expressed in 0.001V/bit, which is why we divide 1209004ac81SGuenter Roeck * by an additional 10000 (100000 for +12V): 1000 for val and 10 (100) 1219004ac81SGuenter Roeck * for the constants. 1229004ac81SGuenter Roeck */ 123088ce2acSGuenter Roeck if (in_num <= 1) 1242a844c14SGuenter Roeck return (u8) clamp_val((val * 21024 - 1205000) / 250000, 0, 255); 125088ce2acSGuenter Roeck else if (in_num == 2) 1262a844c14SGuenter Roeck return (u8) clamp_val((val * 15737 - 1205000) / 250000, 0, 255); 127088ce2acSGuenter Roeck else if (in_num == 3) 1282a844c14SGuenter Roeck return (u8) clamp_val((val * 10108 - 1205000) / 250000, 0, 255); 1298d5d45fbSJean Delvare else 1302a844c14SGuenter Roeck return (u8) clamp_val((val * 41714 - 12050000) / 2500000, 0, 1312a844c14SGuenter Roeck 255); 1328d5d45fbSJean Delvare } 1338d5d45fbSJean Delvare 134088ce2acSGuenter Roeck static inline long IN_FROM_REG(u8 val, int in_num) 1358d5d45fbSJean Delvare { 1369004ac81SGuenter Roeck /* 1379004ac81SGuenter Roeck * To avoid floating point, we multiply constants by 10 (100 for +12V). 1389004ac81SGuenter Roeck * We also multiply them by 1000 because we want 0.001V/bit for the 1399004ac81SGuenter Roeck * output value. Rounding is done. 1409004ac81SGuenter Roeck */ 141088ce2acSGuenter Roeck if (in_num <= 1) 1428d5d45fbSJean Delvare return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024); 143088ce2acSGuenter Roeck else if (in_num == 2) 1448d5d45fbSJean Delvare return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737); 145088ce2acSGuenter Roeck else if (in_num == 3) 1468d5d45fbSJean Delvare return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108); 1478d5d45fbSJean Delvare else 1488d5d45fbSJean Delvare return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714); 1498d5d45fbSJean Delvare } 1508d5d45fbSJean Delvare 1518d5d45fbSJean Delvare /********* FAN RPM CONVERSIONS ********/ 1529004ac81SGuenter Roeck /* 1539004ac81SGuenter Roeck * Higher register values = slower fans (the fan's strobe gates a counter). 1549004ac81SGuenter Roeck * But this chip saturates back at 0, not at 255 like all the other chips. 1559004ac81SGuenter Roeck * So, 0 means 0 RPM 1569004ac81SGuenter Roeck */ 1578d5d45fbSJean Delvare static inline u8 FAN_TO_REG(long rpm, int div) 1588d5d45fbSJean Delvare { 1598d5d45fbSJean Delvare if (rpm == 0) 1608d5d45fbSJean Delvare return 0; 1612a844c14SGuenter Roeck rpm = clamp_val(rpm, 1, 1000000); 1622a844c14SGuenter Roeck return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 255); 1638d5d45fbSJean Delvare } 1648d5d45fbSJean Delvare 1659004ac81SGuenter Roeck #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (val) == 255 ? 0 : 1350000 / \ 1669004ac81SGuenter Roeck ((val) * (div))) 1678d5d45fbSJean Delvare 1688d5d45fbSJean Delvare /******** TEMP CONVERSIONS (Bob Dougherty) *********/ 1699004ac81SGuenter Roeck /* 1709004ac81SGuenter Roeck * linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew) 1719004ac81SGuenter Roeck * if(temp<169) 1729004ac81SGuenter Roeck * return double(temp)*0.427-32.08; 1739004ac81SGuenter Roeck * else if(temp>=169 && temp<=202) 1749004ac81SGuenter Roeck * return double(temp)*0.582-58.16; 1759004ac81SGuenter Roeck * else 1769004ac81SGuenter Roeck * return double(temp)*0.924-127.33; 1779004ac81SGuenter Roeck * 1789004ac81SGuenter Roeck * A fifth-order polynomial fits the unofficial data (provided by Alex van 1799004ac81SGuenter Roeck * Kaam <darkside@chello.nl>) a bit better. It also give more reasonable 1809004ac81SGuenter Roeck * numbers on my machine (ie. they agree with what my BIOS tells me). 1819004ac81SGuenter Roeck * Here's the fifth-order fit to the 8-bit data: 1829004ac81SGuenter Roeck * temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - 1839004ac81SGuenter Roeck * 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. 1849004ac81SGuenter Roeck * 1859004ac81SGuenter Roeck * (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for 1869004ac81SGuenter Roeck * finding my typos in this formula!) 1879004ac81SGuenter Roeck * 1889004ac81SGuenter Roeck * Alas, none of the elegant function-fit solutions will work because we 1899004ac81SGuenter Roeck * aren't allowed to use floating point in the kernel and doing it with 1909004ac81SGuenter Roeck * integers doesn't provide enough precision. So we'll do boring old 1919004ac81SGuenter Roeck * look-up table stuff. The unofficial data (see below) have effectively 1929004ac81SGuenter Roeck * 7-bit resolution (they are rounded to the nearest degree). I'm assuming 1939004ac81SGuenter Roeck * that the transfer function of the device is monotonic and smooth, so a 1949004ac81SGuenter Roeck * smooth function fit to the data will allow us to get better precision. 1959004ac81SGuenter Roeck * I used the 5th-order poly fit described above and solved for 1969004ac81SGuenter Roeck * VIA register values 0-255. I *10 before rounding, so we get tenth-degree 1979004ac81SGuenter Roeck * precision. (I could have done all 1024 values for our 10-bit readings, 1989004ac81SGuenter Roeck * but the function is very linear in the useful range (0-80 deg C), so 199088ce2acSGuenter Roeck * we'll just use linear interpolation for 10-bit readings.) So, temp_lut 2009004ac81SGuenter Roeck * is the temp at via register values 0-255: 2019004ac81SGuenter Roeck */ 202088ce2acSGuenter Roeck static const s16 temp_lut[] = { 2039004ac81SGuenter Roeck -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, 2048d5d45fbSJean Delvare -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, 2058d5d45fbSJean Delvare -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, 2068d5d45fbSJean Delvare -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, 2078d5d45fbSJean Delvare -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, 2088d5d45fbSJean Delvare -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, 2098d5d45fbSJean Delvare -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, 2108d5d45fbSJean Delvare 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, 2118d5d45fbSJean Delvare 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, 2128d5d45fbSJean Delvare 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, 2138d5d45fbSJean Delvare 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, 2148d5d45fbSJean Delvare 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, 2158d5d45fbSJean Delvare 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, 2168d5d45fbSJean Delvare 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, 2178d5d45fbSJean Delvare 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, 2188d5d45fbSJean Delvare 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, 2198d5d45fbSJean Delvare 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, 2208d5d45fbSJean Delvare 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, 2218d5d45fbSJean Delvare 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, 2228d5d45fbSJean Delvare 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, 2238d5d45fbSJean Delvare 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, 2248d5d45fbSJean Delvare 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 2258d5d45fbSJean Delvare }; 2268d5d45fbSJean Delvare 2279004ac81SGuenter Roeck /* 2289004ac81SGuenter Roeck * the original LUT values from Alex van Kaam <darkside@chello.nl> 2299004ac81SGuenter Roeck * (for via register values 12-240): 2309004ac81SGuenter Roeck * {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, 2319004ac81SGuenter Roeck * -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, 2329004ac81SGuenter Roeck * -15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3, 2339004ac81SGuenter 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, 2349004ac81SGuenter 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, 2359004ac81SGuenter 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, 2369004ac81SGuenter 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, 2379004ac81SGuenter 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, 2389004ac81SGuenter 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, 2399004ac81SGuenter Roeck * 85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110}; 2409004ac81SGuenter Roeck * 2419004ac81SGuenter Roeck * 2429004ac81SGuenter Roeck * Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed 2439004ac81SGuenter Roeck * an extra term for a good fit to these inverse data!) and then 2449004ac81SGuenter Roeck * solving for each temp value from -50 to 110 (the useable range for 2459004ac81SGuenter Roeck * this chip). Here's the fit: 2469004ac81SGuenter Roeck * viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 2479004ac81SGuenter Roeck * - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) 2489004ac81SGuenter Roeck * Note that n=161: 2499004ac81SGuenter Roeck */ 250088ce2acSGuenter Roeck static const u8 via_lut[] = { 2519004ac81SGuenter Roeck 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, 2528d5d45fbSJean Delvare 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, 2538d5d45fbSJean Delvare 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, 2548d5d45fbSJean Delvare 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, 2558d5d45fbSJean Delvare 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, 2568d5d45fbSJean Delvare 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, 2578d5d45fbSJean Delvare 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 2588d5d45fbSJean Delvare 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, 2598d5d45fbSJean Delvare 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, 2608d5d45fbSJean Delvare 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, 2618d5d45fbSJean Delvare 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, 2628d5d45fbSJean Delvare 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 2638d5d45fbSJean Delvare 239, 240 2648d5d45fbSJean Delvare }; 2658d5d45fbSJean Delvare 2669004ac81SGuenter Roeck /* 2679004ac81SGuenter Roeck * Converting temps to (8-bit) hyst and over registers 2689004ac81SGuenter Roeck * No interpolation here. 2699004ac81SGuenter Roeck * The +50 is because the temps start at -50 2709004ac81SGuenter Roeck */ 2718d5d45fbSJean Delvare static inline u8 TEMP_TO_REG(long val) 2728d5d45fbSJean Delvare { 273088ce2acSGuenter Roeck return via_lut[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 */ 278088ce2acSGuenter Roeck #define TEMP_FROM_REG(val) ((long)temp_lut[val] * 100) 2798d5d45fbSJean Delvare 2808d5d45fbSJean Delvare /* for 10-bit temperature readings */ 2818d5d45fbSJean Delvare static inline long TEMP_FROM_REG10(u16 val) 2828d5d45fbSJean Delvare { 283088ce2acSGuenter Roeck u16 eight_bits = val >> 2; 284088ce2acSGuenter Roeck u16 two_bits = val & 3; 2858d5d45fbSJean Delvare 2868d5d45fbSJean Delvare /* no interpolation for these */ 287088ce2acSGuenter Roeck if (two_bits == 0 || eight_bits == 255) 288088ce2acSGuenter Roeck return TEMP_FROM_REG(eight_bits); 2898d5d45fbSJean Delvare 2908d5d45fbSJean Delvare /* do some linear interpolation */ 291088ce2acSGuenter Roeck return (temp_lut[eight_bits] * (4 - two_bits) + 292088ce2acSGuenter Roeck temp_lut[eight_bits + 1] * two_bits) * 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 2989004ac81SGuenter Roeck /* 2999004ac81SGuenter Roeck * For each registered chip, we need to keep some data in memory. 3009004ac81SGuenter Roeck * The structure is dynamically allocated. 3019004ac81SGuenter Roeck */ 3028d5d45fbSJean Delvare struct via686a_data { 3032ec342e6SJean Delvare unsigned short addr; 3042ec342e6SJean Delvare const char *name; 3051beeffe4STony Jones struct device *hwmon_dev; 3069a61bf63SIngo Molnar struct mutex update_lock; 3078d5d45fbSJean Delvare char valid; /* !=0 if following fields are valid */ 3088d5d45fbSJean Delvare unsigned long last_updated; /* In jiffies */ 3098d5d45fbSJean Delvare 3108d5d45fbSJean Delvare u8 in[5]; /* Register value */ 3118d5d45fbSJean Delvare u8 in_max[5]; /* Register value */ 3128d5d45fbSJean Delvare u8 in_min[5]; /* Register value */ 3138d5d45fbSJean Delvare u8 fan[2]; /* Register value */ 3148d5d45fbSJean Delvare u8 fan_min[2]; /* Register value */ 3158d5d45fbSJean Delvare u16 temp[3]; /* Register value 10 bit */ 3168d5d45fbSJean Delvare u8 temp_over[3]; /* Register value */ 3178d5d45fbSJean Delvare u8 temp_hyst[3]; /* Register value */ 3188d5d45fbSJean Delvare u8 fan_div[2]; /* Register encoding, shifted right */ 3198d5d45fbSJean Delvare u16 alarms; /* Register encoding, combined */ 3208d5d45fbSJean Delvare }; 3218d5d45fbSJean Delvare 3228d5d45fbSJean Delvare static struct pci_dev *s_bridge; /* pointer to the (only) via686a */ 3238d5d45fbSJean Delvare 3242ec342e6SJean Delvare static int via686a_probe(struct platform_device *pdev); 325281dfd0bSBill Pemberton static int via686a_remove(struct platform_device *pdev); 3268d5d45fbSJean Delvare 3272ec342e6SJean Delvare static inline int via686a_read_value(struct via686a_data *data, u8 reg) 3288d5d45fbSJean Delvare { 3292ec342e6SJean Delvare return inb_p(data->addr + reg); 3308d5d45fbSJean Delvare } 3318d5d45fbSJean Delvare 3322ec342e6SJean Delvare static inline void via686a_write_value(struct via686a_data *data, u8 reg, 3338d5d45fbSJean Delvare u8 value) 3348d5d45fbSJean Delvare { 3352ec342e6SJean Delvare outb_p(value, data->addr + reg); 3368d5d45fbSJean Delvare } 3378d5d45fbSJean Delvare 3388d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev); 3392ec342e6SJean Delvare static void via686a_init_device(struct via686a_data *data); 3408d5d45fbSJean Delvare 3418d5d45fbSJean Delvare /* following are the sysfs callback functions */ 3428d5d45fbSJean Delvare 3438d5d45fbSJean Delvare /* 7 voltage sensors */ 3449d5bc090SGuenter Roeck static ssize_t in_show(struct device *dev, struct device_attribute *da, 3451e71a5a2SJean Delvare char *buf) { 3468d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 3471e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 3481e71a5a2SJean Delvare int nr = attr->index; 3498d5d45fbSJean Delvare return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr)); 3508d5d45fbSJean Delvare } 3518d5d45fbSJean Delvare 3529d5bc090SGuenter Roeck static ssize_t in_min_show(struct device *dev, struct device_attribute *da, 3531e71a5a2SJean Delvare char *buf) { 3548d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 3551e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 3561e71a5a2SJean Delvare int nr = attr->index; 3578d5d45fbSJean Delvare return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr)); 3588d5d45fbSJean Delvare } 3598d5d45fbSJean Delvare 3609d5bc090SGuenter Roeck static ssize_t in_max_show(struct device *dev, struct device_attribute *da, 3611e71a5a2SJean Delvare char *buf) { 3628d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 3631e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 3641e71a5a2SJean Delvare int nr = attr->index; 3658d5d45fbSJean Delvare return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr)); 3668d5d45fbSJean Delvare } 3678d5d45fbSJean Delvare 3689d5bc090SGuenter Roeck static ssize_t in_min_store(struct device *dev, struct device_attribute *da, 3691e71a5a2SJean Delvare const char *buf, size_t count) { 3702ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 3711e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 3721e71a5a2SJean Delvare int nr = attr->index; 3739004ac81SGuenter Roeck unsigned long val; 3749004ac81SGuenter Roeck int err; 3759004ac81SGuenter Roeck 3769004ac81SGuenter Roeck err = kstrtoul(buf, 10, &val); 3779004ac81SGuenter Roeck if (err) 3789004ac81SGuenter Roeck return err; 3798d5d45fbSJean Delvare 3809a61bf63SIngo Molnar mutex_lock(&data->update_lock); 3818d5d45fbSJean Delvare data->in_min[nr] = IN_TO_REG(val, nr); 3822ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_IN_MIN(nr), 3838d5d45fbSJean Delvare data->in_min[nr]); 3849a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 3858d5d45fbSJean Delvare return count; 3868d5d45fbSJean Delvare } 3879d5bc090SGuenter Roeck static ssize_t in_max_store(struct device *dev, struct device_attribute *da, 3881e71a5a2SJean Delvare const char *buf, size_t count) { 3892ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 3901e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 3911e71a5a2SJean Delvare int nr = attr->index; 3929004ac81SGuenter Roeck unsigned long val; 3939004ac81SGuenter Roeck int err; 3949004ac81SGuenter Roeck 3959004ac81SGuenter Roeck err = kstrtoul(buf, 10, &val); 3969004ac81SGuenter Roeck if (err) 3979004ac81SGuenter Roeck return err; 3988d5d45fbSJean Delvare 3999a61bf63SIngo Molnar mutex_lock(&data->update_lock); 4008d5d45fbSJean Delvare data->in_max[nr] = IN_TO_REG(val, nr); 4012ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_IN_MAX(nr), 4028d5d45fbSJean Delvare data->in_max[nr]); 4039a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 4048d5d45fbSJean Delvare return count; 4058d5d45fbSJean Delvare } 4068d5d45fbSJean Delvare 4079d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in0_input, in, 0); 4089d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in0_min, in_min, 0); 4099d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in0_max, in_max, 0); 4109d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in1_input, in, 1); 4119d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 1); 4129d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 1); 4139d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in2_input, in, 2); 4149d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 2); 4159d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 2); 4169d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in3_input, in, 3); 4179d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 3); 4189d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 3); 4199d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in4_input, in, 4); 4209d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 4); 4219d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 4); 4228d5d45fbSJean Delvare 4238d5d45fbSJean Delvare /* 3 temperatures */ 4249d5bc090SGuenter Roeck static ssize_t temp_show(struct device *dev, struct device_attribute *da, 4251e71a5a2SJean Delvare char *buf) { 4268d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 4271e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 4281e71a5a2SJean Delvare int nr = attr->index; 4298d5d45fbSJean Delvare return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr])); 4308d5d45fbSJean Delvare } 4319d5bc090SGuenter Roeck static ssize_t temp_over_show(struct device *dev, struct device_attribute *da, 4321e71a5a2SJean Delvare char *buf) { 4338d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 4341e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 4351e71a5a2SJean Delvare int nr = attr->index; 4368d5d45fbSJean Delvare return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr])); 4378d5d45fbSJean Delvare } 4389d5bc090SGuenter Roeck static ssize_t temp_hyst_show(struct device *dev, struct device_attribute *da, 4391e71a5a2SJean Delvare char *buf) { 4408d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 4411e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 4421e71a5a2SJean Delvare int nr = attr->index; 4438d5d45fbSJean Delvare return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr])); 4448d5d45fbSJean Delvare } 4459d5bc090SGuenter Roeck static ssize_t temp_over_store(struct device *dev, 4469d5bc090SGuenter Roeck struct device_attribute *da, const char *buf, 4479d5bc090SGuenter Roeck size_t count) { 4482ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 4491e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 4501e71a5a2SJean Delvare int nr = attr->index; 4519004ac81SGuenter Roeck long val; 4529004ac81SGuenter Roeck int err; 4539004ac81SGuenter Roeck 4549004ac81SGuenter Roeck err = kstrtol(buf, 10, &val); 4559004ac81SGuenter Roeck if (err) 4569004ac81SGuenter Roeck return err; 4578d5d45fbSJean Delvare 4589a61bf63SIngo Molnar mutex_lock(&data->update_lock); 4598d5d45fbSJean Delvare data->temp_over[nr] = TEMP_TO_REG(val); 4602ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr], 4618d5d45fbSJean Delvare data->temp_over[nr]); 4629a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 4638d5d45fbSJean Delvare return count; 4648d5d45fbSJean Delvare } 4659d5bc090SGuenter Roeck static ssize_t temp_hyst_store(struct device *dev, 4669d5bc090SGuenter Roeck struct device_attribute *da, const char *buf, 4679d5bc090SGuenter Roeck size_t count) { 4682ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 4691e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 4701e71a5a2SJean Delvare int nr = attr->index; 4719004ac81SGuenter Roeck long val; 4729004ac81SGuenter Roeck int err; 4739004ac81SGuenter Roeck 4749004ac81SGuenter Roeck err = kstrtol(buf, 10, &val); 4759004ac81SGuenter Roeck if (err) 4769004ac81SGuenter Roeck return err; 4778d5d45fbSJean Delvare 4789a61bf63SIngo Molnar mutex_lock(&data->update_lock); 4798d5d45fbSJean Delvare data->temp_hyst[nr] = TEMP_TO_REG(val); 4802ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr], 4818d5d45fbSJean Delvare data->temp_hyst[nr]); 4829a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 4838d5d45fbSJean Delvare return count; 4848d5d45fbSJean Delvare } 4858d5d45fbSJean Delvare 4869d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0); 4879d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_over, 0); 4889d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, temp_hyst, 0); 4899d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1); 4909d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_over, 1); 4919d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_max_hyst, temp_hyst, 1); 4929d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2); 4939d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_max, temp_over, 2); 4949d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_max_hyst, temp_hyst, 2); 4958d5d45fbSJean Delvare 4968d5d45fbSJean Delvare /* 2 Fans */ 4979d5bc090SGuenter Roeck static ssize_t fan_show(struct device *dev, struct device_attribute *da, 4981e71a5a2SJean Delvare char *buf) { 4998d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 5001e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 5011e71a5a2SJean Delvare int nr = attr->index; 5028d5d45fbSJean Delvare return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], 5038d5d45fbSJean Delvare DIV_FROM_REG(data->fan_div[nr]))); 5048d5d45fbSJean Delvare } 5059d5bc090SGuenter Roeck static ssize_t fan_min_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, "%d\n", 5119004ac81SGuenter Roeck FAN_FROM_REG(data->fan_min[nr], 5129004ac81SGuenter Roeck DIV_FROM_REG(data->fan_div[nr]))); 5138d5d45fbSJean Delvare } 5149d5bc090SGuenter Roeck static ssize_t fan_div_show(struct device *dev, struct device_attribute *da, 5151e71a5a2SJean Delvare char *buf) { 5168d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 5171e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 5181e71a5a2SJean Delvare int nr = attr->index; 5198d5d45fbSJean Delvare return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); 5208d5d45fbSJean Delvare } 5219d5bc090SGuenter Roeck static ssize_t fan_min_store(struct device *dev, struct device_attribute *da, 5221e71a5a2SJean Delvare const char *buf, size_t count) { 5232ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 5241e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 5251e71a5a2SJean Delvare int nr = attr->index; 5269004ac81SGuenter Roeck unsigned long val; 5279004ac81SGuenter Roeck int err; 5289004ac81SGuenter Roeck 5299004ac81SGuenter Roeck err = kstrtoul(buf, 10, &val); 5309004ac81SGuenter Roeck if (err) 5319004ac81SGuenter Roeck return err; 5328d5d45fbSJean Delvare 5339a61bf63SIngo Molnar mutex_lock(&data->update_lock); 5348d5d45fbSJean Delvare data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); 5352ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]); 5369a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 5378d5d45fbSJean Delvare return count; 5388d5d45fbSJean Delvare } 5399d5bc090SGuenter Roeck static ssize_t fan_div_store(struct device *dev, struct device_attribute *da, 5401e71a5a2SJean Delvare const char *buf, size_t count) { 5412ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 5421e71a5a2SJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 5431e71a5a2SJean Delvare int nr = attr->index; 5448d5d45fbSJean Delvare int old; 5459004ac81SGuenter Roeck unsigned long val; 5469004ac81SGuenter Roeck int err; 5479004ac81SGuenter Roeck 5489004ac81SGuenter Roeck err = kstrtoul(buf, 10, &val); 5499004ac81SGuenter Roeck if (err) 5509004ac81SGuenter Roeck return err; 5518d5d45fbSJean Delvare 5529a61bf63SIngo Molnar mutex_lock(&data->update_lock); 5532ec342e6SJean Delvare old = via686a_read_value(data, VIA686A_REG_FANDIV); 5548d5d45fbSJean Delvare data->fan_div[nr] = DIV_TO_REG(val); 5558d5d45fbSJean Delvare old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4); 5562ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_FANDIV, old); 5579a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 5588d5d45fbSJean Delvare return count; 5598d5d45fbSJean Delvare } 5608d5d45fbSJean Delvare 5619d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0); 5629d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0); 5639d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_div, fan_div, 0); 5649d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1); 5659d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1); 5669d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1); 5678d5d45fbSJean Delvare 5688d5d45fbSJean Delvare /* Alarms */ 5698b2bd7aeSJulia Lawall static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, 5709004ac81SGuenter Roeck char *buf) 5719004ac81SGuenter Roeck { 5728d5d45fbSJean Delvare struct via686a_data *data = via686a_update_device(dev); 5738d5d45fbSJean Delvare return sprintf(buf, "%u\n", data->alarms); 5748d5d45fbSJean Delvare } 5759004ac81SGuenter Roeck 5768b2bd7aeSJulia Lawall static DEVICE_ATTR_RO(alarms); 5778d5d45fbSJean Delvare 5789d5bc090SGuenter Roeck static ssize_t alarm_show(struct device *dev, struct device_attribute *attr, 57913ff05e9SJean Delvare char *buf) 58013ff05e9SJean Delvare { 58113ff05e9SJean Delvare int bitnr = to_sensor_dev_attr(attr)->index; 58213ff05e9SJean Delvare struct via686a_data *data = via686a_update_device(dev); 58313ff05e9SJean Delvare return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); 58413ff05e9SJean Delvare } 5859d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0); 5869d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in1_alarm, alarm, 1); 5879d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in2_alarm, alarm, 2); 5889d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in3_alarm, alarm, 3); 5899d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in4_alarm, alarm, 8); 5909d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 4); 5919d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_alarm, alarm, 11); 5929d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_alarm, alarm, 15); 5939d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 6); 5949d5bc090SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 7); 59513ff05e9SJean Delvare 5968b2bd7aeSJulia Lawall static ssize_t name_show(struct device *dev, struct device_attribute 5972ec342e6SJean Delvare *devattr, char *buf) 5982ec342e6SJean Delvare { 5992ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 6002ec342e6SJean Delvare return sprintf(buf, "%s\n", data->name); 6012ec342e6SJean Delvare } 6028b2bd7aeSJulia Lawall static DEVICE_ATTR_RO(name); 6032ec342e6SJean Delvare 604a5ebe668SJean Delvare static struct attribute *via686a_attributes[] = { 6051e71a5a2SJean Delvare &sensor_dev_attr_in0_input.dev_attr.attr, 6061e71a5a2SJean Delvare &sensor_dev_attr_in1_input.dev_attr.attr, 6071e71a5a2SJean Delvare &sensor_dev_attr_in2_input.dev_attr.attr, 6081e71a5a2SJean Delvare &sensor_dev_attr_in3_input.dev_attr.attr, 6091e71a5a2SJean Delvare &sensor_dev_attr_in4_input.dev_attr.attr, 6101e71a5a2SJean Delvare &sensor_dev_attr_in0_min.dev_attr.attr, 6111e71a5a2SJean Delvare &sensor_dev_attr_in1_min.dev_attr.attr, 6121e71a5a2SJean Delvare &sensor_dev_attr_in2_min.dev_attr.attr, 6131e71a5a2SJean Delvare &sensor_dev_attr_in3_min.dev_attr.attr, 6141e71a5a2SJean Delvare &sensor_dev_attr_in4_min.dev_attr.attr, 6151e71a5a2SJean Delvare &sensor_dev_attr_in0_max.dev_attr.attr, 6161e71a5a2SJean Delvare &sensor_dev_attr_in1_max.dev_attr.attr, 6171e71a5a2SJean Delvare &sensor_dev_attr_in2_max.dev_attr.attr, 6181e71a5a2SJean Delvare &sensor_dev_attr_in3_max.dev_attr.attr, 6191e71a5a2SJean Delvare &sensor_dev_attr_in4_max.dev_attr.attr, 62013ff05e9SJean Delvare &sensor_dev_attr_in0_alarm.dev_attr.attr, 62113ff05e9SJean Delvare &sensor_dev_attr_in1_alarm.dev_attr.attr, 62213ff05e9SJean Delvare &sensor_dev_attr_in2_alarm.dev_attr.attr, 62313ff05e9SJean Delvare &sensor_dev_attr_in3_alarm.dev_attr.attr, 62413ff05e9SJean Delvare &sensor_dev_attr_in4_alarm.dev_attr.attr, 625a5ebe668SJean Delvare 6261e71a5a2SJean Delvare &sensor_dev_attr_temp1_input.dev_attr.attr, 6271e71a5a2SJean Delvare &sensor_dev_attr_temp2_input.dev_attr.attr, 6281e71a5a2SJean Delvare &sensor_dev_attr_temp3_input.dev_attr.attr, 6291e71a5a2SJean Delvare &sensor_dev_attr_temp1_max.dev_attr.attr, 6301e71a5a2SJean Delvare &sensor_dev_attr_temp2_max.dev_attr.attr, 6311e71a5a2SJean Delvare &sensor_dev_attr_temp3_max.dev_attr.attr, 6321e71a5a2SJean Delvare &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, 6331e71a5a2SJean Delvare &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, 6341e71a5a2SJean Delvare &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, 63513ff05e9SJean Delvare &sensor_dev_attr_temp1_alarm.dev_attr.attr, 63613ff05e9SJean Delvare &sensor_dev_attr_temp2_alarm.dev_attr.attr, 63713ff05e9SJean Delvare &sensor_dev_attr_temp3_alarm.dev_attr.attr, 638a5ebe668SJean Delvare 6391e71a5a2SJean Delvare &sensor_dev_attr_fan1_input.dev_attr.attr, 6401e71a5a2SJean Delvare &sensor_dev_attr_fan2_input.dev_attr.attr, 6411e71a5a2SJean Delvare &sensor_dev_attr_fan1_min.dev_attr.attr, 6421e71a5a2SJean Delvare &sensor_dev_attr_fan2_min.dev_attr.attr, 6431e71a5a2SJean Delvare &sensor_dev_attr_fan1_div.dev_attr.attr, 6441e71a5a2SJean Delvare &sensor_dev_attr_fan2_div.dev_attr.attr, 64513ff05e9SJean Delvare &sensor_dev_attr_fan1_alarm.dev_attr.attr, 64613ff05e9SJean Delvare &sensor_dev_attr_fan2_alarm.dev_attr.attr, 647a5ebe668SJean Delvare 648a5ebe668SJean Delvare &dev_attr_alarms.attr, 6492ec342e6SJean Delvare &dev_attr_name.attr, 650a5ebe668SJean Delvare NULL 651a5ebe668SJean Delvare }; 652a5ebe668SJean Delvare 653a5ebe668SJean Delvare static const struct attribute_group via686a_group = { 654a5ebe668SJean Delvare .attrs = via686a_attributes, 655a5ebe668SJean Delvare }; 656a5ebe668SJean Delvare 6572ec342e6SJean Delvare static struct platform_driver via686a_driver = { 658cdaf7934SLaurent Riffard .driver = { 6598d5d45fbSJean Delvare .name = "via686a", 660cdaf7934SLaurent Riffard }, 6612ec342e6SJean Delvare .probe = via686a_probe, 6629e5e9b7aSBill Pemberton .remove = via686a_remove, 6638d5d45fbSJean Delvare }; 6648d5d45fbSJean Delvare 6658d5d45fbSJean Delvare /* This is called when the module is loaded */ 6666c931ae1SBill Pemberton static int via686a_probe(struct platform_device *pdev) 6678d5d45fbSJean Delvare { 6688d5d45fbSJean Delvare struct via686a_data *data; 6692ec342e6SJean Delvare struct resource *res; 6702ec342e6SJean Delvare int err; 6718d5d45fbSJean Delvare 6728d5d45fbSJean Delvare /* Reserve the ISA region */ 6732ec342e6SJean Delvare res = platform_get_resource(pdev, IORESOURCE_IO, 0); 674fd55bc00SGuenter Roeck if (!devm_request_region(&pdev->dev, res->start, VIA686A_EXTENT, 675cdaf7934SLaurent Riffard via686a_driver.driver.name)) { 6762ec342e6SJean Delvare dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n", 6772ec342e6SJean Delvare (unsigned long)res->start, (unsigned long)res->end); 6788d5d45fbSJean Delvare return -ENODEV; 6798d5d45fbSJean Delvare } 6808d5d45fbSJean Delvare 681fd55bc00SGuenter Roeck data = devm_kzalloc(&pdev->dev, sizeof(struct via686a_data), 682fd55bc00SGuenter Roeck GFP_KERNEL); 683fd55bc00SGuenter Roeck if (!data) 684fd55bc00SGuenter Roeck return -ENOMEM; 6858d5d45fbSJean Delvare 6862ec342e6SJean Delvare platform_set_drvdata(pdev, data); 6872ec342e6SJean Delvare data->addr = res->start; 6882ec342e6SJean Delvare data->name = "via686a"; 6899a61bf63SIngo Molnar mutex_init(&data->update_lock); 6908d5d45fbSJean Delvare 6918d5d45fbSJean Delvare /* Initialize the VIA686A chip */ 6922ec342e6SJean Delvare via686a_init_device(data); 6938d5d45fbSJean Delvare 6948d5d45fbSJean Delvare /* Register sysfs hooks */ 6959004ac81SGuenter Roeck err = sysfs_create_group(&pdev->dev.kobj, &via686a_group); 6969004ac81SGuenter Roeck if (err) 697fd55bc00SGuenter Roeck return err; 698a5ebe668SJean Delvare 6991beeffe4STony Jones data->hwmon_dev = hwmon_device_register(&pdev->dev); 7001beeffe4STony Jones if (IS_ERR(data->hwmon_dev)) { 7011beeffe4STony Jones err = PTR_ERR(data->hwmon_dev); 702a5ebe668SJean Delvare goto exit_remove_files; 703943b0830SMark M. Hoffman } 704943b0830SMark M. Hoffman 7058d5d45fbSJean Delvare return 0; 7068d5d45fbSJean Delvare 707a5ebe668SJean Delvare exit_remove_files: 7082ec342e6SJean Delvare sysfs_remove_group(&pdev->dev.kobj, &via686a_group); 7098d5d45fbSJean Delvare return err; 7108d5d45fbSJean Delvare } 7118d5d45fbSJean Delvare 712281dfd0bSBill Pemberton static int via686a_remove(struct platform_device *pdev) 7138d5d45fbSJean Delvare { 7142ec342e6SJean Delvare struct via686a_data *data = platform_get_drvdata(pdev); 7158d5d45fbSJean Delvare 7161beeffe4STony Jones hwmon_device_unregister(data->hwmon_dev); 7172ec342e6SJean Delvare sysfs_remove_group(&pdev->dev.kobj, &via686a_group); 718943b0830SMark M. Hoffman 7198d5d45fbSJean Delvare return 0; 7208d5d45fbSJean Delvare } 7218d5d45fbSJean Delvare 722f790674dSJean Delvare static void via686a_update_fan_div(struct via686a_data *data) 723f790674dSJean Delvare { 724f790674dSJean Delvare int reg = via686a_read_value(data, VIA686A_REG_FANDIV); 725f790674dSJean Delvare data->fan_div[0] = (reg >> 4) & 0x03; 726f790674dSJean Delvare data->fan_div[1] = reg >> 6; 727f790674dSJean Delvare } 728f790674dSJean Delvare 7296c931ae1SBill Pemberton static void via686a_init_device(struct via686a_data *data) 7308d5d45fbSJean Delvare { 7318d5d45fbSJean Delvare u8 reg; 7328d5d45fbSJean Delvare 7338d5d45fbSJean Delvare /* Start monitoring */ 7342ec342e6SJean Delvare reg = via686a_read_value(data, VIA686A_REG_CONFIG); 7352ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F); 7368d5d45fbSJean Delvare 7378d5d45fbSJean Delvare /* Configure temp interrupt mode for continuous-interrupt operation */ 7382ec342e6SJean Delvare reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE); 7392ec342e6SJean Delvare via686a_write_value(data, VIA686A_REG_TEMP_MODE, 74058fe0809SJean Delvare (reg & ~VIA686A_TEMP_MODE_MASK) 74158fe0809SJean Delvare | VIA686A_TEMP_MODE_CONTINUOUS); 742f790674dSJean Delvare 743f790674dSJean Delvare /* Pre-read fan clock divisor values */ 744f790674dSJean Delvare via686a_update_fan_div(data); 7458d5d45fbSJean Delvare } 7468d5d45fbSJean Delvare 7478d5d45fbSJean Delvare static struct via686a_data *via686a_update_device(struct device *dev) 7488d5d45fbSJean Delvare { 7492ec342e6SJean Delvare struct via686a_data *data = dev_get_drvdata(dev); 7508d5d45fbSJean Delvare int i; 7518d5d45fbSJean Delvare 7529a61bf63SIngo Molnar mutex_lock(&data->update_lock); 7538d5d45fbSJean Delvare 7548d5d45fbSJean Delvare if (time_after(jiffies, data->last_updated + HZ + HZ / 2) 7558d5d45fbSJean Delvare || !data->valid) { 7568d5d45fbSJean Delvare for (i = 0; i <= 4; i++) { 7578d5d45fbSJean Delvare data->in[i] = 7582ec342e6SJean Delvare via686a_read_value(data, VIA686A_REG_IN(i)); 7592ec342e6SJean Delvare data->in_min[i] = via686a_read_value(data, 7608d5d45fbSJean Delvare VIA686A_REG_IN_MIN 7618d5d45fbSJean Delvare (i)); 7628d5d45fbSJean Delvare data->in_max[i] = 7632ec342e6SJean Delvare via686a_read_value(data, VIA686A_REG_IN_MAX(i)); 7648d5d45fbSJean Delvare } 7658d5d45fbSJean Delvare for (i = 1; i <= 2; i++) { 7668d5d45fbSJean Delvare data->fan[i - 1] = 7672ec342e6SJean Delvare via686a_read_value(data, VIA686A_REG_FAN(i)); 7682ec342e6SJean Delvare data->fan_min[i - 1] = via686a_read_value(data, 7698d5d45fbSJean Delvare VIA686A_REG_FAN_MIN(i)); 7708d5d45fbSJean Delvare } 7718d5d45fbSJean Delvare for (i = 0; i <= 2; i++) { 7722ec342e6SJean Delvare data->temp[i] = via686a_read_value(data, 7738d5d45fbSJean Delvare VIA686A_REG_TEMP[i]) << 2; 7748d5d45fbSJean Delvare data->temp_over[i] = 7752ec342e6SJean Delvare via686a_read_value(data, 7768d5d45fbSJean Delvare VIA686A_REG_TEMP_OVER[i]); 7778d5d45fbSJean Delvare data->temp_hyst[i] = 7782ec342e6SJean Delvare via686a_read_value(data, 7798d5d45fbSJean Delvare VIA686A_REG_TEMP_HYST[i]); 7808d5d45fbSJean Delvare } 7819004ac81SGuenter Roeck /* 7829004ac81SGuenter Roeck * add in lower 2 bits 7839004ac81SGuenter Roeck * temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 7849004ac81SGuenter Roeck * temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 7859004ac81SGuenter Roeck * temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 7868d5d45fbSJean Delvare */ 7872ec342e6SJean Delvare data->temp[0] |= (via686a_read_value(data, 7888d5d45fbSJean Delvare VIA686A_REG_TEMP_LOW1) 7898d5d45fbSJean Delvare & 0xc0) >> 6; 7908d5d45fbSJean Delvare data->temp[1] |= 7912ec342e6SJean Delvare (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) & 7928d5d45fbSJean Delvare 0x30) >> 4; 7938d5d45fbSJean Delvare data->temp[2] |= 7942ec342e6SJean Delvare (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) & 7958d5d45fbSJean Delvare 0xc0) >> 6; 7968d5d45fbSJean Delvare 797f790674dSJean Delvare via686a_update_fan_div(data); 7988d5d45fbSJean Delvare data->alarms = 7992ec342e6SJean Delvare via686a_read_value(data, 8008d5d45fbSJean Delvare VIA686A_REG_ALARM1) | 8012ec342e6SJean Delvare (via686a_read_value(data, VIA686A_REG_ALARM2) << 8); 8028d5d45fbSJean Delvare data->last_updated = jiffies; 8038d5d45fbSJean Delvare data->valid = 1; 8048d5d45fbSJean Delvare } 8058d5d45fbSJean Delvare 8069a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 8078d5d45fbSJean Delvare 8088d5d45fbSJean Delvare return data; 8098d5d45fbSJean Delvare } 8108d5d45fbSJean Delvare 811cd9bb056SJingoo Han static const struct pci_device_id via686a_pci_ids[] = { 8128d5d45fbSJean Delvare { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, 8139004ac81SGuenter Roeck { } 8148d5d45fbSJean Delvare }; 8158d5d45fbSJean Delvare MODULE_DEVICE_TABLE(pci, via686a_pci_ids); 8168d5d45fbSJean Delvare 8176c931ae1SBill Pemberton static int via686a_device_add(unsigned short address) 8182ec342e6SJean Delvare { 8192ec342e6SJean Delvare struct resource res = { 8202ec342e6SJean Delvare .start = address, 8212ec342e6SJean Delvare .end = address + VIA686A_EXTENT - 1, 8222ec342e6SJean Delvare .name = "via686a", 8232ec342e6SJean Delvare .flags = IORESOURCE_IO, 8242ec342e6SJean Delvare }; 8252ec342e6SJean Delvare int err; 8262ec342e6SJean Delvare 827b9acb64aSJean Delvare err = acpi_check_resource_conflict(&res); 828b9acb64aSJean Delvare if (err) 829b9acb64aSJean Delvare goto exit; 830b9acb64aSJean Delvare 8312ec342e6SJean Delvare pdev = platform_device_alloc("via686a", address); 8322ec342e6SJean Delvare if (!pdev) { 8332ec342e6SJean Delvare err = -ENOMEM; 834774f7827SJoe Perches pr_err("Device allocation failed\n"); 8352ec342e6SJean Delvare goto exit; 8362ec342e6SJean Delvare } 8372ec342e6SJean Delvare 8382ec342e6SJean Delvare err = platform_device_add_resources(pdev, &res, 1); 8392ec342e6SJean Delvare if (err) { 840774f7827SJoe Perches pr_err("Device resource addition failed (%d)\n", err); 8412ec342e6SJean Delvare goto exit_device_put; 8422ec342e6SJean Delvare } 8432ec342e6SJean Delvare 8442ec342e6SJean Delvare err = platform_device_add(pdev); 8452ec342e6SJean Delvare if (err) { 846774f7827SJoe Perches pr_err("Device addition failed (%d)\n", err); 8472ec342e6SJean Delvare goto exit_device_put; 8482ec342e6SJean Delvare } 8492ec342e6SJean Delvare 8502ec342e6SJean Delvare return 0; 8512ec342e6SJean Delvare 8522ec342e6SJean Delvare exit_device_put: 8532ec342e6SJean Delvare platform_device_put(pdev); 8542ec342e6SJean Delvare exit: 8552ec342e6SJean Delvare return err; 8562ec342e6SJean Delvare } 8572ec342e6SJean Delvare 8586c931ae1SBill Pemberton static int via686a_pci_probe(struct pci_dev *dev, 8598d5d45fbSJean Delvare const struct pci_device_id *id) 8608d5d45fbSJean Delvare { 8612ec342e6SJean Delvare u16 address, val; 8628d5d45fbSJean Delvare 8632ec342e6SJean Delvare if (force_addr) { 8642ec342e6SJean Delvare address = force_addr & ~(VIA686A_EXTENT - 1); 8652ec342e6SJean Delvare dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address); 8662ec342e6SJean Delvare if (PCIBIOS_SUCCESSFUL != 8672ec342e6SJean Delvare pci_write_config_word(dev, VIA686A_BASE_REG, address | 1)) 8682ec342e6SJean Delvare return -ENODEV; 8692ec342e6SJean Delvare } 8708d5d45fbSJean Delvare if (PCIBIOS_SUCCESSFUL != 8718d5d45fbSJean Delvare pci_read_config_word(dev, VIA686A_BASE_REG, &val)) 8728d5d45fbSJean Delvare return -ENODEV; 8738d5d45fbSJean Delvare 8742d8672c5SJean Delvare address = val & ~(VIA686A_EXTENT - 1); 8752ec342e6SJean Delvare if (address == 0) { 876b55f3757SGuenter Roeck dev_err(&dev->dev, 877b55f3757SGuenter Roeck "base address not set - upgrade BIOS or use force_addr=0xaddr\n"); 8788d5d45fbSJean Delvare return -ENODEV; 8798d5d45fbSJean Delvare } 8808d5d45fbSJean Delvare 8812ec342e6SJean Delvare if (PCIBIOS_SUCCESSFUL != 8822ec342e6SJean Delvare pci_read_config_word(dev, VIA686A_ENABLE_REG, &val)) 8832ec342e6SJean Delvare return -ENODEV; 8842ec342e6SJean Delvare if (!(val & 0x0001)) { 8852ec342e6SJean Delvare if (!force_addr) { 886b55f3757SGuenter Roeck dev_warn(&dev->dev, 887b55f3757SGuenter Roeck "Sensors disabled, enable with force_addr=0x%x\n", 888b55f3757SGuenter Roeck address); 8892ec342e6SJean Delvare return -ENODEV; 8908d5d45fbSJean Delvare } 8918d5d45fbSJean Delvare 8922ec342e6SJean Delvare dev_warn(&dev->dev, "Enabling sensors\n"); 8932ec342e6SJean Delvare if (PCIBIOS_SUCCESSFUL != 8942ec342e6SJean Delvare pci_write_config_word(dev, VIA686A_ENABLE_REG, 8952ec342e6SJean Delvare val | 0x0001)) 8962ec342e6SJean Delvare return -ENODEV; 8972ec342e6SJean Delvare } 8982ec342e6SJean Delvare 8992ec342e6SJean Delvare if (platform_driver_register(&via686a_driver)) 9002ec342e6SJean Delvare goto exit; 9012ec342e6SJean Delvare 9022ec342e6SJean Delvare /* Sets global pdev as a side effect */ 9032ec342e6SJean Delvare if (via686a_device_add(address)) 9042ec342e6SJean Delvare goto exit_unregister; 9052ec342e6SJean Delvare 9069004ac81SGuenter Roeck /* 9079004ac81SGuenter Roeck * Always return failure here. This is to allow other drivers to bind 9088d5d45fbSJean Delvare * to this pci device. We don't really want to have control over the 9098d5d45fbSJean Delvare * pci device, we only wanted to read as few register values from it. 9108d5d45fbSJean Delvare */ 9112ec342e6SJean Delvare s_bridge = pci_dev_get(dev); 9122ec342e6SJean Delvare return -ENODEV; 9132ec342e6SJean Delvare 9142ec342e6SJean Delvare exit_unregister: 9152ec342e6SJean Delvare platform_driver_unregister(&via686a_driver); 9162ec342e6SJean Delvare exit: 9178d5d45fbSJean Delvare return -ENODEV; 9188d5d45fbSJean Delvare } 9198d5d45fbSJean Delvare 9208d5d45fbSJean Delvare static struct pci_driver via686a_pci_driver = { 9218d5d45fbSJean Delvare .name = "via686a", 9228d5d45fbSJean Delvare .id_table = via686a_pci_ids, 9238d5d45fbSJean Delvare .probe = via686a_pci_probe, 9248d5d45fbSJean Delvare }; 9258d5d45fbSJean Delvare 9268d5d45fbSJean Delvare static int __init sm_via686a_init(void) 9278d5d45fbSJean Delvare { 9288d5d45fbSJean Delvare return pci_register_driver(&via686a_pci_driver); 9298d5d45fbSJean Delvare } 9308d5d45fbSJean Delvare 9318d5d45fbSJean Delvare static void __exit sm_via686a_exit(void) 9328d5d45fbSJean Delvare { 9338d5d45fbSJean Delvare pci_unregister_driver(&via686a_pci_driver); 9348d5d45fbSJean Delvare if (s_bridge != NULL) { 9352ec342e6SJean Delvare platform_device_unregister(pdev); 9362ec342e6SJean Delvare platform_driver_unregister(&via686a_driver); 9378d5d45fbSJean Delvare pci_dev_put(s_bridge); 9388d5d45fbSJean Delvare s_bridge = NULL; 9398d5d45fbSJean Delvare } 9408d5d45fbSJean Delvare } 9418d5d45fbSJean Delvare 94296de0e25SJan Engelhardt MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, " 9438d5d45fbSJean Delvare "Mark Studebaker <mdsxyz123@yahoo.com> " 9448d5d45fbSJean Delvare "and Bob Dougherty <bobd@stanford.edu>"); 9458d5d45fbSJean Delvare MODULE_DESCRIPTION("VIA 686A Sensor device"); 9468d5d45fbSJean Delvare MODULE_LICENSE("GPL"); 9478d5d45fbSJean Delvare 9488d5d45fbSJean Delvare module_init(sm_via686a_init); 9498d5d45fbSJean Delvare module_exit(sm_via686a_exit); 950